diff --git a/.github/workflows/post-release.yaml b/.github/workflows/post-release.yaml index d04e66d573acd..05e12675db625 100644 --- a/.github/workflows/post-release.yaml +++ b/.github/workflows/post-release.yaml @@ -104,7 +104,8 @@ jobs: .variables.teleport.latest_oss_docker_image |= sub(":.*";":")+$version | .variables.teleport.latest_oss_debug_docker_image |= sub(":.*";":")+$version | .variables.teleport.latest_ent_docker_image |= sub(":.*";":")+$version | - .variables.teleport.latest_ent_debug_docker_image |= sub(":.*";":")+$version' \ + .variables.teleport.latest_ent_debug_docker_image |= sub(":.*";":")+$version | + .variables.teleport.teleport_install_script_url |= sub("install-v.*.sh"; "install-v"+$version+".sh")' \ docs/config.json > docs/confignew.json cat docs/confignew.json mv docs/confignew.json docs/config.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 44907c3e89ff1..ea59df8af87c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,73 @@ # Changelog +## 16.1.4 (08/07/24) + +* Improved `tsh ssh` performance for concurrent execs. [#45162](https://github.com/gravitational/teleport/pull/45162) +* Fixed issue with loading cluster features when agents are upgraded prior to auth. [#45226](https://github.com/gravitational/teleport/pull/45226) +* Updated Go to `1.22.6`. [#45194](https://github.com/gravitational/teleport/pull/45194) + +## 16.1.3 (08/06/24) + +* Fixed an issue where `tsh aws` may display extra text in addition to the original command output. [#45168](https://github.com/gravitational/teleport/pull/45168) +* Fixed regression that denied access to launch some Apps. [#45149](https://github.com/gravitational/teleport/pull/45149) +* Bot resources now honor their `metadata.expires` field. [#45130](https://github.com/gravitational/teleport/pull/45130) +* Teleport Connect now sets `TERM_PROGRAM: Teleport_Connect` and `TERM_PROGRAM_VERSION: ` environment variables in the integrated terminal. [#45063](https://github.com/gravitational/teleport/pull/45063) +* Fixed a panic in the Microsoft Teams plugin when it receives an error. [#45011](https://github.com/gravitational/teleport/pull/45011) +* Added a background item for VNet in Teleport Connect; VNet now prompts for a password only during the first launch. [#44994](https://github.com/gravitational/teleport/pull/44994) +* Added warning on `tbot` startup when the requested certificate TTL exceeds the maximum allowed value. [#44989](https://github.com/gravitational/teleport/pull/44989) +* Fixed a race condition between session recording uploads and session recording upload cleanup. [#44978](https://github.com/gravitational/teleport/pull/44978) +* Prevented Kubernetes per-Resource RBAC from blocking access to namespaces when denying access to a single resource kind in every namespace. [#44974](https://github.com/gravitational/teleport/pull/44974) +* SSO login flows can now authorize web sessions with Device Trust. [#44906](https://github.com/gravitational/teleport/pull/44906) +* Added support for Kubernetes Workload Attestation into Teleport Workload Identity to allow the authentication of pods running within Kubernetes without secrets. [#44883](https://github.com/gravitational/teleport/pull/44883) + +Enterprise: +* Fixed a redirection issue with the SAML IdP authentication middleware which prevented users from signing into the service provider when an SAML authentication request was made with an HTTP-POST binding protocol, and user's didn't already have an active session with Teleport. [#4806](https://github.com/gravitational/teleport.e/pull/4806) +* SAML applications can now be deleted from the Web UI. [#4778](https://github.com/gravitational/teleport.e/pull/4778) +* Fixed an issue introduced in v16.0.3 and v15.4.6 where `tbot` FIPS builds fail to start due to a missing boringcrypto dependency. [#4757](https://github.com/gravitational/teleport.e/pull/4757) + +## 16.1.1 (07/31/24) + +* Added option to allow client redirects from IPs in specified CIDR ranges in SSO client logins. [#44846](https://github.com/gravitational/teleport/pull/44846) +* Machine ID can now be configured to use Kubernetes Secret destinations from the command line using the `kubernetes-secret` schema. [#44801](https://github.com/gravitational/teleport/pull/44801) +* Prevent discovery service from overwriting Teleport dynamic resources that have the same name as discovered resources. [#44785](https://github.com/gravitational/teleport/pull/44785) +* Reduced the probability that the event-handler deadlocks when encountering errors processing session recordings. [#44771](https://github.com/gravitational/teleport/pull/44771) +* Improved event-handler diagnostics by providing a way to capture profiles dynamically via `SIGUSR1`. [#44758](https://github.com/gravitational/teleport/pull/44758) +* Teleport Connect now uses ConPTY for better terminal resizing and accurate color rendering on Windows, with an option to disable it in the app config. [#44742](https://github.com/gravitational/teleport/pull/44742) +* Fixed event-handler Helm charts using the wrong command when starting the event-handler container. [#44697](https://github.com/gravitational/teleport/pull/44697) +* Improved stability of very large Teleport clusters during temporary backend disruption/degradation. [#44694](https://github.com/gravitational/teleport/pull/44694) +* Resolved compatibility issue with Paramiko and Machine ID's SSH multiplexer SSH agent. [#44673](https://github.com/gravitational/teleport/pull/44673) +* Teleport no longer creates invalid SAML Connectors when calling `tctl get saml/ | tctl create -f` without the `--with-secrets` flag. [#44666](https://github.com/gravitational/teleport/pull/44666) +* Fixed a fatal error in `tbot` when unable to lookup the user from a given UID in containerized environments for checking ACL configuration. [#44645](https://github.com/gravitational/teleport/pull/44645) +* Fixed Application Access regression where an HTTP header wasn't set in forwarded requests. [#44628](https://github.com/gravitational/teleport/pull/44628) +* Added Server auto-discovery support for Rocky and AlmaLinux distros. [#44612](https://github.com/gravitational/teleport/pull/44612) +* Use the registered port of the target host when `tsh puttyconfig` is invoked without `--port`. [#44572](https://github.com/gravitational/teleport/pull/44572) +* Added more icons for guessing application icon by name or by label `teleport.icon` in the web UI. [#44566](https://github.com/gravitational/teleport/pull/44566) +* Remove deprecated S3 bucket option when creating or editing AWS OIDC integration in the web UI. [#44485](https://github.com/gravitational/teleport/pull/44485) +* Fixed terminal sessions with a database CLI client in Teleport Connect hanging indefinitely if the client cannot be found. [#44465](https://github.com/gravitational/teleport/pull/44465) +* Added `application-tunnel` service to Machine ID for establishing a long-lived tunnel to a HTTP or TCP application for Machine to Machine access. [#44443](https://github.com/gravitational/teleport/pull/44443) +* Fixed a regression that caused Teleport Connect to fail to start on Intel Macs. [#44435](https://github.com/gravitational/teleport/pull/44435) +* Improved auto-discovery resiliency by recreating Teleport configuration when the node fails to join the cluster. [#44432](https://github.com/gravitational/teleport/pull/44432) +* Fixed a low-probability panic in audit event upload logic. [#44425](https://github.com/gravitational/teleport/pull/44425) +* Fixed Teleport Connect binaries not being signed correctly. [#44419](https://github.com/gravitational/teleport/pull/44419) +* Prevented DoSing the cluster during a mass failed join event by agents. [#44414](https://github.com/gravitational/teleport/pull/44414) +* The availability filter is now a toggle to show (or hide) requestable resources. [#44413](https://github.com/gravitational/teleport/pull/44413) +* Moved PostgreSQL auto provisioning users procedures to `pg_temp` schema. [#44409](https://github.com/gravitational/teleport/pull/44409) +* Added audit events for AWS and Azure integration resource actions. [#44403](https://github.com/gravitational/teleport/pull/44403) +* Fixed automatic updates with previous versions of the `teleport.yaml` config. [#44379](https://github.com/gravitational/teleport/pull/44379) +* Added support for Rocky and AlmaLinux when enrolling a new server from the UI. [#44332](https://github.com/gravitational/teleport/pull/44332) +* Fixed PostgreSQL session playback not rendering queries line breaks correctly. [#44315](https://github.com/gravitational/teleport/pull/44315) +* Fixed Teleport access plugin tarballs containing a `build` directory, which was accidentally added upon v16.0.0 release. [#44300](https://github.com/gravitational/teleport/pull/44300) +* Prevented an infinite loop in DynamoDB event querying by advancing the cursor to the next day when the limit is reached at the end of a day with an empty iterator. This ensures the cursor does not reset to the beginning of the day. [#44275](https://github.com/gravitational/teleport/pull/44275) +* The clipboard sharing tooltip for desktop sessions now indicates why clipboard sharing is disabled. [#44237](https://github.com/gravitational/teleport/pull/44237) +* Prevented redirects to arbitrary URLs when launching an app. [#44188](https://github.com/gravitational/teleport/pull/44188) +* Added a `--skip-idle-time` flag to `tsh play`. [#44013](https://github.com/gravitational/teleport/pull/44013) +* Added audit events for discovery config actions. [#43793](https://github.com/gravitational/teleport/pull/43793) +* Enabled Access Monitoring Rules routing with Mattermost plugin. [#43601](https://github.com/gravitational/teleport/pull/43601) +* SAML application can now be deleted from the Web UI. [#4778](https://github.com/gravitational/teleport.e/pull/4778) +* Fixed an Access List permission bug where an access list owner, who is also a member, was not able to add/remove access list member. [#4744](https://github.com/gravitational/teleport.e/pull/4744) +* Fixed a bug in Web UI where clicking SAML GCP Workforce Identity Federation discover tile would throw an error, preventing from using the guided enrollment feature. [#4720](https://github.com/gravitational/teleport.e/pull/4720) +* Fixed an issue with incorrect yum/zypper updater packages being installed. [#4684](https://github.com/gravitational/teleport.e/pull/4684) + ## 16.1.0 (07/15/24) ### New logo @@ -336,6 +404,137 @@ follow the manual setup guide. All Teleport Assist functionality and OpenAI integration has been removed from Teleport. +## 15.4.10 (07/29/24) + +* Fixed an issue that could cause auth servers to panic when their backend connectivity was interrupted. [#44787](https://github.com/gravitational/teleport/pull/44787) +* Reduced the probability that the event-handler deadlocks when encountering errors processing session recordings. [#44772](https://github.com/gravitational/teleport/pull/44772) +* Improved event-handler diagnostics by providing a way to capture profiles dynamically via `SIGUSR1`. [#44759](https://github.com/gravitational/teleport/pull/44759) +* Added support for Teams to Opsgenie plugin alert creation. [#44330](https://github.com/gravitational/teleport/pull/44330) +* Improved stability of very large teleport clusters during temporary backend disruption/degradation. [#44695](https://github.com/gravitational/teleport/pull/44695) +* Resolved compatibility issue with Paramiko and Machine ID's SSH multiplexer SSH agent. [#44672](https://github.com/gravitational/teleport/pull/44672) +* Fixed a fatal error in `tbot` when unable to lookup the user from a given UID in containerized environments for checking ACL configuration. [#44646](https://github.com/gravitational/teleport/pull/44646) +* Fixed Application Access regression where an HTTP header wasn't set in forwarded requests. [#44629](https://github.com/gravitational/teleport/pull/44629) +* Use the registered port of the target host when `tsh puttyconfig` is invoked without `--port`. [#44573](https://github.com/gravitational/teleport/pull/44573) +* Added more icons for guessing application icon by name or by label `teleport.icon` in the web UI. [#44568](https://github.com/gravitational/teleport/pull/44568) +* Removed deprecated S3 bucket option when creating or editing AWS OIDC integration in the web UI. [#44487](https://github.com/gravitational/teleport/pull/44487) +* Fixed terminal sessions with a database CLI client in Teleport Connect hanging indefinitely if the client cannot be found. [#44466](https://github.com/gravitational/teleport/pull/44466) +* Added application-tunnel service to Machine ID for establishing a long-lived tunnel to a HTTP or TCP application for Machine to Machine access. [#44446](https://github.com/gravitational/teleport/pull/44446) +* Fixed a low-probability panic in audit event upload logic. [#44424](https://github.com/gravitational/teleport/pull/44424) +* Fixed Teleport Connect binaries not being signed correctly. [#44420](https://github.com/gravitational/teleport/pull/44420) +* Prevented DoSing the cluster during a mass failed join event by agents. [#44415](https://github.com/gravitational/teleport/pull/44415) +* Added audit events for AWS and Azure integration resource actions. [#44404](https://github.com/gravitational/teleport/pull/44404) +* Fixed automatic updates with previous versions of the `teleport.yaml` config. [#44378](https://github.com/gravitational/teleport/pull/44378) +* Added support for Rocky and AlmaLinux when enrolling a new server from the UI. [#44331](https://github.com/gravitational/teleport/pull/44331) +* Fixed Teleport access plugin tarballs containing a `build` directory, which was accidentally added upon v15.4.5 release. [#44301](https://github.com/gravitational/teleport/pull/44301) +* Prevented an infinite loop in DynamoDB event querying by advancing the cursor to the next day when the limit is reached at the end of a day with an empty iterator. This ensures the cursor does not reset to the beginning of the day. [#44274](https://github.com/gravitational/teleport/pull/44274) +* The clipboard sharing tooltip for desktop sessions now indicates why clipboard sharing is disabled. [#44238](https://github.com/gravitational/teleport/pull/44238) +* Fixed a `kube-agent-updater` bug affecting resolutions of private images. [#44192](https://github.com/gravitational/teleport/pull/44192) +* Prevented redirects to arbitrary URLs when launching an app. [#44189](https://github.com/gravitational/teleport/pull/44189) +* Added audit event field describing if the "MFA for admin actions" requirement changed. [#44185](https://github.com/gravitational/teleport/pull/44185) +* The `teleport-cluster` chart can now use existing ingresses instead of creating its own. [#44147](https://github.com/gravitational/teleport/pull/44147) +* Ensured that `tsh login` outputs accurate status information for the new session. [#44144](https://github.com/gravitational/teleport/pull/44144) +* Fixed "device trust mode _x_ requires Teleport Enterprise" errors on `tctl`. [#44134](https://github.com/gravitational/teleport/pull/44134) +* Added a `--skip-idle-time` flag to `tsh play`. [#44095](https://github.com/gravitational/teleport/pull/44095) +* Added the `tbot install systemd` command for installing tbot as a service on Linux systems. [#44082](https://github.com/gravitational/teleport/pull/44082) +* Added ability to list access list members in json format in `tctl` cli tool. [#44072](https://github.com/gravitational/teleport/pull/44072) +* Made `tbot` compilable on Windows. [#44070](https://github.com/gravitational/teleport/pull/44070) +* For slack integration, Access List reminders are batched into 1 message and provides link out to the web UI. [#44035](https://github.com/gravitational/teleport/pull/44035) +* Fixed denying access despite access being configured for Notification Routing Rules in the web UI. [#44028](https://github.com/gravitational/teleport/pull/44028) +* Fixed eBPF error occurring during startup on Linux RHEL 9. [#44024](https://github.com/gravitational/teleport/pull/44024) +* Lowered latency of detecting Kubernetes cluster becoming online. [#43971](https://github.com/gravitational/teleport/pull/43971) +* Enabled Access Monitoring Rules routing with Mattermost plugin. [#43600](https://github.com/gravitational/teleport/pull/43600) + +Enterprise: +* Fixed an Access List permission bug where an access list owner, who is also a member, was not able to add/rm access list member. +* Fixed an issue with incorrect yum/zypper updater packages being installed. +* Fixed empty condition from unquoted string with yaml editor for Notification Routing Rules in the Web UI. + +## 15.4.9 (07/11/24) + +* Honor proxy templates in tsh ssh. [#44027](https://github.com/gravitational/teleport/pull/44027) +* Fixed Redshift auto-user deactivation/deletion failure that occurs when a user is created or deleted and another user is deactivated concurrently. [#43975](https://github.com/gravitational/teleport/pull/43975) +* Teleport AMIs now optionally source environment variables from `/etc/default/teleport` as regular Teleport package installations do. [#43961](https://github.com/gravitational/teleport/pull/43961) +* Enabled setting event types to forward, skip events, skip session types in event-handler helm chart. [#43939](https://github.com/gravitational/teleport/pull/43939) +* Correctly propagate `extraLabels` configured in teleport-kube-agent chart values to post-delete hooks. A new `extraLabels.job` object has been added for labels which should only apply to the post-delete job. [#43931](https://github.com/gravitational/teleport/pull/43931) +* Machine ID outputs now execute individually and concurrently, meaning that one failing output does not disrupt other outputs, and that performance when generating a large number of outputs is improved. [#43883](https://github.com/gravitational/teleport/pull/43883) +* Omit control plane services from the inventory list output for Cloud-Hosted instances. [#43778](https://github.com/gravitational/teleport/pull/43778) +* Fixed session recordings getting overwritten or not uploaded. [#42164](https://github.com/gravitational/teleport/pull/42164) + +Enterprise: +* Fixed inaccurately notifying user that access list reviews are due in the web UI. + +## 15.4.7 (07/03/24) + +* Added audit events for discovery config actions. [#43794](https://github.com/gravitational/teleport/pull/43794) +* Updated Go toolchain to v1.22.5. [#43769](https://github.com/gravitational/teleport/pull/43769) +* Reduced CPU usage in auth servers experiencing very high concurrent request load. [#43760](https://github.com/gravitational/teleport/pull/43760) +* Machine ID defaults to disabling the use of the Kubernetes exec plugin when writing a Kubeconfig to a directory destination. This removes the need to manually configure `disable_exec_plugin`. [#43656](https://github.com/gravitational/teleport/pull/43656) +* Fixed startup crash of Teleport Connect on Ubuntu 24.04 by adding an AppArmor profile. [#43652](https://github.com/gravitational/teleport/pull/43652) +* Added support for dialling leaf clusters to the tbot SSH multiplexer. [#43635](https://github.com/gravitational/teleport/pull/43635) +* Extend Teleport ability to use non-default cluster domains in Kubernetes, avoiding the assumption of `cluster.local`. [#43632](https://github.com/gravitational/teleport/pull/43632) +* Wait for user MFA input when reissuing expired certificates for a kube proxy. [#43613](https://github.com/gravitational/teleport/pull/43613) +* Improved error diagnostics when using Machine ID's SSH multiplexer. [#43587](https://github.com/gravitational/teleport/pull/43587) + +Enterprise: +* Increased Access Monitoring refresh interval to 24h. +* Teleport Enterprise now supports the `TELEPORT_REPORTING_HTTP(S)_PROXY` environment variable to specify the URL of the HTTP(S) proxy used for connections to our usage reporting ingest service. + +## 15.4.6 (06/27/24) + +This release of Teleport contains a fix for medium-level security issue impacting +Teleport Enterprise, as well as various other updates and improvements + +### Security Fixes + +* **[Medium]** Fixes issue where a SCIM client could potentially overwrite. + Teleport system Roles using specially crafted groups. This issue impacts + Teleport Enterprise deployments using the Okta integration with SCIM support + enabled. + +We strongly recommend all customers upgrade to the latest releases of Teleport. + +### Other updates and improvements + +* Fixed Discover setup access error when updating user. [#43561](https://github.com/gravitational/teleport/pull/43561) +* Updated Go toolchain to 1.22. [#43550](https://github.com/gravitational/teleport/pull/43550) +* Fixed remote port forwarding validation error. [#43517](https://github.com/gravitational/teleport/pull/43517) +* Added support to trust system CAs for self-hosted databases. [#43500](https://github.com/gravitational/teleport/pull/43500) +* Added error display in the Web UI for SSH and Kubernetes sessions. [#43491](https://github.com/gravitational/teleport/pull/43491) +* Update `go-retryablehttp` to v0.7.7 (fixes CVE-2024-6104). [#43475](https://github.com/gravitational/teleport/pull/43475) +* Fixed accurate inventory reporting of the updater after it is removed.. [#43453](https://github.com/gravitational/teleport/pull/43453) +* `tctl alerts ls` now displays remaining alert ttl. [#43435](https://github.com/gravitational/teleport/pull/43435) +* Fixed input search for Teleport Connect's access request listing. [#43430](https://github.com/gravitational/teleport/pull/43430) +* Added `Debug` setting for event-handler. [#43409](https://github.com/gravitational/teleport/pull/43409) +* Fixed Headless auth for sso users, including when local auth is disabled. [#43362](https://github.com/gravitational/teleport/pull/43362) +* Added configuration for custom CAs in the event-handler helm chart. [#43341](https://github.com/gravitational/teleport/pull/43341) +* Fixed an issue with Database Access Controls preventing users from making additional database connections depending on their permissions. [#43302](https://github.com/gravitational/teleport/pull/43302) +* Fixed Connect My Computer in Teleport Connect failing with "bind: invalid argument". [#43288](https://github.com/gravitational/teleport/pull/43288) + +### Enterprise only updates and improvements + +* The teleport updater will no longer default to using the global version channel, avoiding incompatible updates. [#4476](https://github.com/gravitational/teleport.e/pull/4476) + +## 15.4.5 (06/20/24) + +* Added a missing `[Install]` section to the `teleport-acm` systemd unit file as used by Teleport AMIs. [#43256](https://github.com/gravitational/teleport/pull/43256) +* Patched timing variability in curve25519-dalek. [#43249](https://github.com/gravitational/teleport/pull/43249) +* Updated `tctl` to ignore a configuration file if the `auth_service` section is disabled, and prefer loading credentials from a given identity file or tsh profile instead. [#43203](https://github.com/gravitational/teleport/pull/43203) +* Fixed setting request reason for automatic ssh access requests. [#43180](https://github.com/gravitational/teleport/pull/43180) +* Updated `teleport` to skip `jamf_service` validation when the Jamf service is not enabled. [#43169](https://github.com/gravitational/teleport/pull/43169) +* Improved log rotation logic in Teleport Connect; now the non-numbered files always contain recent logs. [#43162](https://github.com/gravitational/teleport/pull/43162) +* Made `tsh` and Teleport Connect return early during login if ping to proxy service was not successful. [#43086](https://github.com/gravitational/teleport/pull/43086) +* Added ability to edit user traits from the Web UI. [#43068](https://github.com/gravitational/teleport/pull/43068) +* Enforce limits when reading events from Firestore to prevent OOM events. [#42967](https://github.com/gravitational/teleport/pull/42967) +* Fixed updating groups for Teleport-created host users. [#42884](https://github.com/gravitational/teleport/pull/42884) +* Added support for `crown_jewel` resource. [#42866](https://github.com/gravitational/teleport/pull/42866) +* Added ability to edit user traits from the Web UI. [#43068](https://github.com/gravitational/teleport/pull/43068) +* Fixed gRPC disconnection on certificate expiry even though DisconnectCertExpiry was false. [#43291](https://github.com/gravitational/teleport/pull/43291) +* Fixed issue where a Teleport instance running only Jamf or Discovery service would never have a healthy `/readyz` endpoint. [#43284](https://github.com/gravitational/teleport/pull/43284) + +### Enterprise-only changes + +* Fixed sync error in Okta SCIM integration. + ## 15.4.4 (06/13/24) * Improve search and predicate/label based dialing performance in large clusters under very high load. [#42941](https://github.com/gravitational/teleport/pull/42941) @@ -1358,6 +1557,337 @@ characters. The account lockout interval has been increased from 20 to 30 minutes. +## 14.3.21 (06/20/24) + +* Fixed bug that caused gRPC connections to be disconnected when their certificate expired even though DisconnectCertExpiry was false. [#43292](https://github.com/gravitational/teleport/pull/43292) +* Fixed bug where a Teleport instance running only Jamf or Discovery service would never have a healthy `/readyz` endpoint. [#43285](https://github.com/gravitational/teleport/pull/43285) +* Added a missing `[Install]` section to the `teleport-acm` systemd unit file as used by Teleport AMIs. [#43258](https://github.com/gravitational/teleport/pull/43258) +* Updated `teleport` to skip `jamf_service` validation when the Jamf is not enabled. [#43170](https://github.com/gravitational/teleport/pull/43170) +* Improved log rotation logic in Teleport Connect; now the non-numbered files always contain recent logs. [#43163](https://github.com/gravitational/teleport/pull/43163) +* Made tsh and Teleport Connect return early during login if ping to proxy service was not successful. [#43087](https://github.com/gravitational/teleport/pull/43087) +* Added ability to edit user traits from the Web UI. [#43070](https://github.com/gravitational/teleport/pull/43070) +* Enforce limits when reading events from Firestore to prevent OOM events. [#42968](https://github.com/gravitational/teleport/pull/42968) +* Fixed an issue Oracle access failed through trusted cluster. [#42929](https://github.com/gravitational/teleport/pull/42929) +* Fixes errors caused by `dynamoevents` query `StartKey` not being within the [From, To] window. [#42914](https://github.com/gravitational/teleport/pull/42914) +* Fixed updating groups for Teleport-created host users. [#42883](https://github.com/gravitational/teleport/pull/42883) +* Update azidentity to v1.6.0 (patches CVE-2024-35255). [#42860](https://github.com/gravitational/teleport/pull/42860) +* Remote rate limits on endpoints used extensively to connect to the cluster. [#42836](https://github.com/gravitational/teleport/pull/42836) +* Improved the performance of the Athena audit log and S3 session storage backends. [#42796](https://github.com/gravitational/teleport/pull/42796) +* Prevented a panic in the Proxy when accessing an offline application. [#42787](https://github.com/gravitational/teleport/pull/42787) +* Improve backoff of session recording uploads by teleport agents. [#42775](https://github.com/gravitational/teleport/pull/42775) +* Reduced backend writes incurred by tracking status of non-recorded sessions. [#42695](https://github.com/gravitational/teleport/pull/42695) +* Fixed listing available DB users in Teleport Connect for databases from leaf clusters obtained through access requests. [#42681](https://github.com/gravitational/teleport/pull/42681) +* Fixed not being able to logout from the web UI when session invalidation errors. [#42654](https://github.com/gravitational/teleport/pull/42654) +* Updated OpenSSL to 3.0.14. [#42643](https://github.com/gravitational/teleport/pull/42643) +* Teleport Connect binaries for Windows are now signed. [#42473](https://github.com/gravitational/teleport/pull/42473) +* Updated Go to 1.21.11. [#42416](https://github.com/gravitational/teleport/pull/42416) +* Fix web UI notification dropdown menu height from growing too long from many notifications. [#42338](https://github.com/gravitational/teleport/pull/42338) +* Disabled session recordings for non-interactive sessions when enhanced recording is disabled. [#42321](https://github.com/gravitational/teleport/pull/42321) +* Fixed issue where removing an app could make teleport app agents incorrectly report as unhealthy for a short time. [#42269](https://github.com/gravitational/teleport/pull/42269) +* Fixed a panic in the DynamoDB audit log backend when the cursor fell outside of the [From,To] interval. [#42266](https://github.com/gravitational/teleport/pull/42266) +* The `teleport configure` command now supports a `--node-name` flag for overriding the node's hostname. [#42249](https://github.com/gravitational/teleport/pull/42249) +* Fixed an issue where mix-and-match of join tokens could interfere with some services appearing correctly in heartbeats. [#42188](https://github.com/gravitational/teleport/pull/42188) +* Improved temporary disk space usage for session recording processing. [#42175](https://github.com/gravitational/teleport/pull/42175) +* Fixed a regression where Kubernetes Exec audit events were not properly populated and lacked error details. [#42146](https://github.com/gravitational/teleport/pull/42146) +* Fix Azure join method when using Resource Groups in the allow section. [#42140](https://github.com/gravitational/teleport/pull/42140) +* Fixed resource leak in session recording cleanup. [#42069](https://github.com/gravitational/teleport/pull/42069) +* Reduced memory and cpu usage after control plane restarts in clusters with a high number of roles. [#42064](https://github.com/gravitational/teleport/pull/42064) +* Fixed the field `allowed_https_hostnames` in the Teleport Operator resources: SAML, OIDC, and GitHub Connector. [#42056](https://github.com/gravitational/teleport/pull/42056) +* Enhanced error messaging for clients using `kubectl exec` v1.30+ to include warnings about a breaking change in Kubernetes. [#41989](https://github.com/gravitational/teleport/pull/41989) + +### Enterprise-Only changes: +* Improved memory usage when reconciling Access Lists members to prevent Out of Memory events when reconciling a large number of Access Lists members. +* Prevented Access Monitoring reports from crashing when large datasets are returned. +* Ensured graceful restart of `teleport.service` after an upgrade. + +## 14.3.20 (05/23/24) + +This release contains fixes for several high-severity security issues, as well +as numerous other bug fixes and improvements. + +### Security Fixes + +#### **[High]** Unrestricted redirect in SSO Authentication + +Teleport didn’t sufficiently validate the client redirect URL. This could allow +an attacker to trick Teleport users into performing an SSO authentication and +redirect to an attacker-controlled URL allowing them to steal the credentials. +[#41834](https://github.com/gravitational/teleport/pull/41834). + +Warning: Teleport will now disallow non-localhost callback URLs for SSO logins +unless otherwise configured. Users of the `tsh login --callback` feature should +modify their auth connector configuration as follows: + +```yaml +version: vX +kind: (saml|oidc|github) +metadata: + name: ... +spec: + ... + client_redirect_settings: + allowed_https_hostnames: + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + ``` + +The `allowed_https_hostnames` field is an array containing allowed hostnames, +supporting glob matching and, if the string begins and ends with `^` and `$` +respectively, full regular expression syntax. Custom callback URLs are required +to be HTTPS on the standard port (443). + +#### **[High]** CockroachDB authorization bypass + +When connecting to CockroachDB using Database Access, Teleport did not properly +consider the username case when running RBAC checks. As such, it was possible to +establish a connection using an explicitly denied username when using a +different case. [#41823](https://github.com/gravitational/teleport/pull/41823). + +#### **[High]** Long-lived connection persistence issue with expired certificates + +Teleport did not terminate some long-running mTLS-authenticated connections past +the expiry of client certificates for users with the `disconnect_expired_cert` +option. This could allow such users to perform some API actions after their +certificate has expired. +[#41827](https://github.com/gravitational/teleport/pull/41827). + +#### **[High]** PagerDuty integration privilege escalation + +When creating a role access request, Teleport would include PagerDuty +annotations from the entire user’s role set rather than a specific role being +requested. For users who run multiple PagerDuty access plugins with +auto-approval, this could result in a request for a different role being +inadvertently auto-approved than the one which corresponds to the user’s active +on-call schedule. +[#41837](https://github.com/gravitational/teleport/pull/41837). + +#### **[High]** SAML IdP session privilege escalation + +When using Teleport as SAML IdP, authorization wasn’t properly enforced on the +SAML IdP session creation. As such, authenticated users could use an internal +API to escalate their own privileges by crafting a malicious program. +[#41846](https://github.com/gravitational/teleport/pull/41846). + +We strongly recommend all customers upgrade to the latest releases of Teleport. + +### Other fixes and improvements + +* Fixed session upload completion in situations where there's a large number of in-flight session uploads. [#41853](https://github.com/gravitational/teleport/pull/41853) +* Debug symbols are now stripped from Windows builds, resulting in smaller tsh and tctl binaries. [#41839](https://github.com/gravitational/teleport/pull/41839) +* Fixed an issue that the server version of the registered MySQL databases is not automatically updated upon new connections. [#41820](https://github.com/gravitational/teleport/pull/41820) +* Add read-only permissions for cluster maintenance config. [#41791](https://github.com/gravitational/teleport/pull/41791) +* Simplified how Bots are shown on the Users list page. [#41739](https://github.com/gravitational/teleport/pull/41739) +* Fix missing variable and script options in Default Agentless Installer script. [#41722](https://github.com/gravitational/teleport/pull/41722) +* Improved reliability of aggregated usage reporting with some cluster state storage backends (Teleport Enterprise only). [#41703](https://github.com/gravitational/teleport/pull/41703) +* Adds the remote address to audit log events emitted when a join for a Bot or Instance fails or succeeds. [#41699](https://github.com/gravitational/teleport/pull/41699) +* Allow the application service to heartbeat on behalf of more than 1000 dynamic applications. [#41627](https://github.com/gravitational/teleport/pull/41627) +* Ensure responses to Kubernetes watch requests are written sequentially. [#41625](https://github.com/gravitational/teleport/pull/41625) +* Install Script used in discover wizard now supports Ubuntu 24.04. [#41588](https://github.com/gravitational/teleport/pull/41588) +* Ensured that systemd always restarts Teleport on any failure unless explicitly stopped. [#41582](https://github.com/gravitational/teleport/pull/41582) +* Teleport service config is now reloaded on upgrades. [#41548](https://github.com/gravitational/teleport/pull/41548) +* Fix AccessList reconciler comparison causing audit events noise. [#41541](https://github.com/gravitational/teleport/pull/41541) +* Prevent SSH connections opened in the UI from leaking if the browser tab is closed while the SSH connection is being established. [#41519](https://github.com/gravitational/teleport/pull/41519) +* Emit login login failed audit events for invalid passwords on password+webauthn local authentication. [#41433](https://github.com/gravitational/teleport/pull/41433) +* Allow setting Kubernetes Cluster name when using non-default addresses. [#41355](https://github.com/gravitational/teleport/pull/41355) +* Added support to automatically download CA for MongoDB Atlas databases. [#41339](https://github.com/gravitational/teleport/pull/41339) +* Fix broken finish web page for SSO user's on auto discover. [#41336](https://github.com/gravitational/teleport/pull/41336) +* Add fallback on GetAccessList cache miss call. [#41327](https://github.com/gravitational/teleport/pull/41327) +* Validate application URL extracted from the web application launcher request route. [#41305](https://github.com/gravitational/teleport/pull/41305) +* Allow defining custom database names and users when selecting wildcard during test connection when enrolling a database through the web UI. [#41302](https://github.com/gravitational/teleport/pull/41302) +* Updated Go to v1.21.10. [#41282](https://github.com/gravitational/teleport/pull/41282) +* Forbid SSO users from local logins or password changes. [#41271](https://github.com/gravitational/teleport/pull/41271) +* Prevents Cloud tenants from updating `cluster_networking_config` fields `keep_alive_count_max`, `keep_alive_interval`, `tunnel_strategy`, or `proxy_listener_mode`. [#41248](https://github.com/gravitational/teleport/pull/41248) + +## 14.3.18 (05/07/24) + +* Ensure that the active sessions page shows up in the web UI for users with permissions to join sessions. [#41222](https://github.com/gravitational/teleport/pull/41222) +* Fix a bug that was preventing tsh proxy kube certificate renewal from working when accessing a leaf kubernetes cluster via the root. [#41157](https://github.com/gravitational/teleport/pull/41157) +* Add lock target to lock deletion audit events. [#41111](https://github.com/gravitational/teleport/pull/41111) +* Improve the reliability of the upload completer. [#41104](https://github.com/gravitational/teleport/pull/41104) +* Allows the listener for the tbot database-tunnel service to be set to a unix socket. [#41042](https://github.com/gravitational/teleport/pull/41042) + +## 14.3.17 (04/30/24) + +* Fixed user SSO bypass by performing a local passwordless login. [#41071](https://github.com/gravitational/teleport/pull/41071) +* Enforce allow_passwordless server-side. [#41058](https://github.com/gravitational/teleport/pull/41058) +* Fixed a memory leak caused by incorrectly passing the offset when paginating all Access Lists' members when there are more than the default pagesize (200) Access Lists. [#41044](https://github.com/gravitational/teleport/pull/41044) +* Fixed a regression causing roles filtering to not work. [#41000](https://github.com/gravitational/teleport/pull/41000) +* Allow AWS integration to be used for global services without specifying a valid region. [#40990](https://github.com/gravitational/teleport/pull/40990) +* Fixed access requests lingering in the UI and tctl after expiry. [#40965](https://github.com/gravitational/teleport/pull/40965) +* Made `podSecurityContext` configurable in the `teleport-cluster` Helm chart. [#40950](https://github.com/gravitational/teleport/pull/40950) +* Allow mounting extra volumes in the updater pod deployed by the `teleport-kube-agent`chart. [#40949](https://github.com/gravitational/teleport/pull/40949) +* Improved error message when performing an SSO login with a hardware key. [#40924](https://github.com/gravitational/teleport/pull/40924) +* Fixed a bug in the `teleport-cluster` Helm chart that happened when `sessionRecording` was `off`. [#40920](https://github.com/gravitational/teleport/pull/40920) +* Allows setting additional Kubernetes labels on resources created by the `teleport-cluster` Helm chart. [#40916](https://github.com/gravitational/teleport/pull/40916) +* Fixed audit event failures when using DynamoDB event storage. [#40912](https://github.com/gravitational/teleport/pull/40912) +* Properly enforce session moderation requirements when starting Kubernetes ephemeral containers. [#40907](https://github.com/gravitational/teleport/pull/40907) +* Introduced the tpm join method, which allows for secure joining in on-prem environments without the need for a shared secret. [#40875](https://github.com/gravitational/teleport/pull/40875) +* Issue cert.create events during device authentication. [#40873](https://github.com/gravitational/teleport/pull/40873) +* Add the ability to control `ssh_config` generation in Machine ID's Identity Outputs. This allows the generation of the `ssh_config` to be disabled if unnecessary, improving performance and removing the dependency on the Proxy being online. [#40862](https://github.com/gravitational/teleport/pull/40862) +* Prevented deleting AWS OIDC integration used by External Audit Storage. [#40853](https://github.com/gravitational/teleport/pull/40853) +* Reduced parallelism when polling AWS resources to prevent API throttling when exporting them to Teleport Access Graph. [#40812](https://github.com/gravitational/teleport/pull/40812) +* Added hardware key support for agentless connections [#40929](https://github.com/gravitational/teleport/pull/40929) + +## 14.3.16 (04/23/24) + +* Fixed a deprecation warning being shown when `tbot` is used with OpenSSH. [#40838](https://github.com/gravitational/teleport/pull/40838) +* Added a new Audit log event that is emitted when an Agent or Bot request to join the cluster is denied. [#40815](https://github.com/gravitational/teleport/pull/40815) +* Added a new Prometheus metric to track requests initiated by Teleport against the control plane API. [#40755](https://github.com/gravitational/teleport/pull/40755) +* Fixed uploading zip files larger than 10MiB when updating an AWS Lambda function via tsh app access. [#40738](https://github.com/gravitational/teleport/pull/40738) +* Fixed possible data race that could lead to concurrent map read and map write while proxying Kubernetes requests. [#40721](https://github.com/gravitational/teleport/pull/40721) +* Fixed access request promotion of windows_desktop resources. [#40711](https://github.com/gravitational/teleport/pull/40711) +* Fixed spurious ambiguous host errors in ssh routing. [#40709](https://github.com/gravitational/teleport/pull/40709) +* Patched CVE-2023-45288 and CVE-2024-32473. [#40696](https://github.com/gravitational/teleport/pull/40696) +* Generic "not found" errors are returned whether a remote cluster can't be found or access is denied. [#40682](https://github.com/gravitational/teleport/pull/40682) +* Fixed a resource leak in the Teleport proxy server when using proxy peering. [#40675](https://github.com/gravitational/teleport/pull/40675) +* Allow other issue types when configuring JIRA plugin. [#40645](https://github.com/gravitational/teleport/pull/40645) +* Added the ability to configure labels that should be set on the Kubernetes secret when using the `kubernetes_secret` destination in `tbot`. [#40551](https://github.com/gravitational/teleport/pull/40551) +* Updated cosign to address CVE-2024-29902 and CVE-2024-29903. [#40498](https://github.com/gravitational/teleport/pull/40498) +* The Web UI now supports large number of roles by paginating them. [#40464](https://github.com/gravitational/teleport/pull/40464) + +## 14.3.15 (04/12/24) + +* Fixed accidental passkey "downgrades" to MFA. [#40410](https://github.com/gravitational/teleport/pull/40410) +* Added `tsh proxy kube --exec` mode that spawns kube proxy in the background, which re-executes the user shell with the appropriate kubeconfig. [#40394](https://github.com/gravitational/teleport/pull/40394) +* Made Amazon S3 fields optional when creating or editing AWS OIDC integration on the web UI. [#40372](https://github.com/gravitational/teleport/pull/40372) +* Changed Teleport Connect to hide cluster name in the connection list if there is only a single cluster available. [#40357](https://github.com/gravitational/teleport/pull/40357) +* Changed Teleport Connect to now show all recent connections instead of capping them at 10. [#40251](https://github.com/gravitational/teleport/pull/40251) +* Fixed an issue that prevents the Teleport service from restarting. [#40230](https://github.com/gravitational/teleport/pull/40230) +* Added a new resource filtering predicates to allow exact matches on a single item of a delimited list stored in a label value. For example, if given the following label containing a string separated list of values `foo=bar,baz,bang`, it is now possible to match on any resources with a label `foo` that contains the element `bar` via `contains(split(labels[foo], ","), bar)`. [#40184](https://github.com/gravitational/teleport/pull/40184) +* Updated Go to 1.21.9. [#40177](https://github.com/gravitational/teleport/pull/40177) +* Added `disable_exec_plugin` option to the Machine ID Kubernetes Output to remove the dependency on `tbot` existing in the target environment. [#40163](https://github.com/gravitational/teleport/pull/40163) +* Added the database-tunnel service to `tbot` which allows an authenticated database tunnel to be opened by `tbot`. This is an improvement over the original technique of using `tbot proxy db`. [#40160](https://github.com/gravitational/teleport/pull/40160) +* Enabled diagnostic endpoints access behind a PROXY protocol enabled loadbalancer/proxy. [#40139](https://github.com/gravitational/teleport/pull/40139) +* Added system annotations to audit event entries for access requests. [#40122](https://github.com/gravitational/teleport/pull/40122) +* Fixed "Invalid URI" error in Teleport Connect when starting MongoDB `mongosh` from the database connection tab. [#40105](https://github.com/gravitational/teleport/pull/40105) +* Improved the performance of filtering resources via predicate expressions. [#39975](https://github.com/gravitational/teleport/pull/39975) +* Fixed a verbosity issue that caused the `teleport-kube-agent-updater` to output debug logs by default. [#39954](https://github.com/gravitational/teleport/pull/39954) +* Reduced default Jamf inventory page size, and added support for custom values. [#39934](https://github.com/gravitational/teleport/pull/39934) +* Added support to the `teleport-cluster` Helm chart for using an Amazon Athena event backend. [#39908](https://github.com/gravitational/teleport/pull/39908) +* Improved the performance of resource filtering via labels and fuzzy search. [#39792](https://github.com/gravitational/teleport/pull/39792) + +## 14.3.14 (03/27/24) + +* Fixed possible phishing links which could result in code execution with install and join scripts. [#39838](https://github.com/gravitational/teleport/pull/39838) +* Fixed MFA checks not being prompted when joining a session. [#39815](https://github.com/gravitational/teleport/pull/39815) +* Fixed potential issue with some resources expiry being set to 01/01/1970 instead of never. [#39774](https://github.com/gravitational/teleport/pull/39774) +* Added support for Kubernetes websocket streaming subprotocol v5 connections. [#39771](https://github.com/gravitational/teleport/pull/39771) +* Fixed broken SSO login landing page on certain versions of Google Chrome. [#39722](https://github.com/gravitational/teleport/pull/39722) +* Updated Electron to v29 in Teleport Connect. [#39658](https://github.com/gravitational/teleport/pull/39658) +* Fixed a bug in Teleport Cloud causing the hosted ServiceNow plugin to crash when setting up the integration. [#39604](https://github.com/gravitational/teleport/pull/39604) +* Fixed Teleport updater metrics for AWS OIDC deployments. [#39531](https://github.com/gravitational/teleport/pull/39531) +* Fixed allowing invalid access request start time date to be set. [#39324](https://github.com/gravitational/teleport/pull/39324) + +## 14.3.13 (03/20/24) + +* Fixed the discovery script failing when `jq` was not installed. [#39600](https://github.com/gravitational/teleport/pull/39600) +* Improve performance when listing nodes with tsh or tctl. [#39568](https://github.com/gravitational/teleport/pull/39568) +* Require AWS S3 bucket fields when creating/editing AWS OIDC integration in the web UI. [#39513](https://github.com/gravitational/teleport/pull/39513) +* Removed implicit AccessList membership and ownership modes. All AccessList owners and members must be explicitly specified. [#39388](https://github.com/gravitational/teleport/pull/39388) + +## 14.3.11 (03/18/24) + +* Fixed an issue with AWS IAM permissions that may prevent AWS database access when discovery_service is enabled in the same Teleport config as the db_service, namely AWS RDS, Redshift, Elasticache, and MemoryDB. [#39487](https://github.com/gravitational/teleport/pull/39487) + +## 14.3.10 (03/16/24) + +* Fixed issue with Teleport auth server panicking when Access Graph is enabled in discovery service. [#39456](https://github.com/gravitational/teleport/pull/39456) + +## 14.3.8 (03/15/24) + +* Improve error messaging when creating resources fails because they already exist or updating resources fails because they were removed. [#39396](https://github.com/gravitational/teleport/pull/39396) +* Support logging in with an identity file with `tsh login -i identity.pem`. This allows running `tsh app login` in CI environments where MachineID is impossible. [#39374](https://github.com/gravitational/teleport/pull/39374) +* Only allow necessary operations during moderated file transfers and limit in-flight file transfer requests to one per session. [#39352](https://github.com/gravitational/teleport/pull/39352) +* Make the Jira access plugin log Jira errors properly. [#39347](https://github.com/gravitational/teleport/pull/39347) +* Teleport Enterprise now attempts to load the license file from the configured data directory if not otherwise specified. [#39313](https://github.com/gravitational/teleport/pull/39313) +* Patched CVE-2024-27304 (Postgres driver). [#39259](https://github.com/gravitational/teleport/pull/39259) +* Raised concurrent connection limits between Teleport Cloud regions and in clusters that use proxy peering. [#39232](https://github.com/gravitational/teleport/pull/39232) +* Improved clean up of system resources during a fast shutdown of Teleport. [#39213](https://github.com/gravitational/teleport/pull/39213) +* Fixed an issue where it was possible to skip providing old password when setting a new one. [#39126](https://github.com/gravitational/teleport/pull/39126) + +## 14.3.7 (03/11/24) + +* Resolved sporadic errors caused by requests fail to comply with Kubernetes API spec by not specifying resource identifiers. [#39167](https://github.com/gravitational/teleport/pull/39167) +* Fixed a bug when using automatic updates and the discovery service. The default install script now installs the correct Teleport version by querying the version server. [#39100](https://github.com/gravitational/teleport/pull/39100) +* Teleport Proxy Service now runs a version server by default serving its own version. [#39096](https://github.com/gravitational/teleport/pull/39096) +* Fixed a regression where `tsh kube credentials` fails to re-login when credentials expire. [#39074](https://github.com/gravitational/teleport/pull/39074) +* TBot now supports `--proxy-server` for explicitly configuring the Proxy address. We recommend switching to this if you currently specify the address of your Teleport proxy to `--auth-server`. [#39056](https://github.com/gravitational/teleport/pull/39056) +* Expanded the EC2 joining process to include newly created AWS regions. [#39052](https://github.com/gravitational/teleport/pull/39052) +* Added GCP MySQL access IAM Authentication support. [#39041](https://github.com/gravitational/teleport/pull/39041) +* Fixed an issue in SAML IdP entity descriptor generator process, which would fail to generate entity descriptor if the configured Entity ID endpoint would return HTTP status code above `200` and below `400`. [#38988](https://github.com/gravitational/teleport/pull/38988) +* Updated Go to 1.21.8. [#38985](https://github.com/gravitational/teleport/pull/38985) +* Updated electron-builder dependency to address possible arbitrary code execution in the Windows installer of Teleport Connect (CVE-2024-27303). [#38966](https://github.com/gravitational/teleport/pull/38966) +* Improved reliability and performance of `tbot`. [#38929](https://github.com/gravitational/teleport/pull/38929) +* Filtered terminated sessions from the `tsh sessions ls` output. [#38886](https://github.com/gravitational/teleport/pull/38886) +* Prevented panic when AccessList's status field is not set. [#38862](https://github.com/gravitational/teleport/pull/38862) +* Fixed an issue with over counting of reported Teleport updater metrics. [#38832](https://github.com/gravitational/teleport/pull/38832) +* Fixed a bug that caused `tsh` to return "private key policy not met" errors instead of automatically initiating re-login to satisfy the private key policy. [#38818](https://github.com/gravitational/teleport/pull/38818) +* Fixed application access events being overwritten when using DynamoDB as event storage. [#38816](https://github.com/gravitational/teleport/pull/38816) +* Fixed issue where DynamoDB writes could fail when recording too many records. [#38762](https://github.com/gravitational/teleport/pull/38762) +* Added a tbot-only `tbot-distroless` container image, bringing an 80% size reduction over the Teleport `teleport` image. [#38719](https://github.com/gravitational/teleport/pull/38719) +* Fixed a Postgres v16.x compatibility issue preventing multiple connections for auto-provisioned users. [#38542](https://github.com/gravitational/teleport/pull/38542) +* Tsh will now show access list review deadlines in dates rather than remaining hours.. [#38526](https://github.com/gravitational/teleport/pull/38526) +* Fixed an issue where tsh would not function if one of its profiles is invalid. [#38513](https://github.com/gravitational/teleport/pull/38513) +* Fixed an issue where `teleport configure` command logs would not use the configured logger. [#38509](https://github.com/gravitational/teleport/pull/38509) +* Removed `telnet` from legacy Ubuntu images due to CVE-2021-40491. Netcat `nc` can be used instead. [#38506](https://github.com/gravitational/teleport/pull/38506) +* Fixed a tsh WebAuthn.dll panic on Windows Server 2019. [#38489](https://github.com/gravitational/teleport/pull/38489) +* Added `ssh_service.enhanced_recording.root_path` configuration option to change the cgroup slice path used by the agent. [#38395](https://github.com/gravitational/teleport/pull/38395) +* Fixed a bug which allowed the operator to delete resources it does not own. [#37751](https://github.com/gravitational/teleport/pull/37751) + +## 14.3.6 (02/16/24) + +* Fixed a potential panic in the `tsh status` command. [#38304](https://github.com/gravitational/teleport/pull/38304) +* Fixed locking SSO user in the setup access step of the RDS auto discover flow in the web UI. [#38284](https://github.com/gravitational/teleport/pull/38284) +* Optionally permit the auth server to terminate client connections from unsupported versions. [#38186](https://github.com/gravitational/teleport/pull/38186) +* Removed access tokens from URL parameters, preventing them from being leaked to intermediary systems that may log them in plaintext. [#38070](https://github.com/gravitational/teleport/pull/38070) +* Added option to validate hardware key serial numbers with hardware key support. [#38069](https://github.com/gravitational/teleport/pull/38069) +* Forced agents to terminate Auth connections if joining fails. [#38004](https://github.com/gravitational/teleport/pull/38004) +* Added a tsh sessions ls command to list active sessions. [#37970](https://github.com/gravitational/teleport/pull/37970) +* Improved error handling when idle desktop connections are terminated. [#37956](https://github.com/gravitational/teleport/pull/37956) +* Updated Go to 1.21.7. [#37848](https://github.com/gravitational/teleport/pull/37848) +* Discover flow now starts two instances of DatabaseServices when setting up access to Amazon RDS. [#37804](https://github.com/gravitational/teleport/pull/37804) +* Fixed incorrect resizing of CLI apps in Teleport Connect on Windows. [#37799](https://github.com/gravitational/teleport/pull/37799) +* Fixed handling of non-registered U2F keys. [#37722](https://github.com/gravitational/teleport/pull/37722) +* Fixed memory leak in tbot caused by never closing reverse tunnel address resolvers. [#37719](https://github.com/gravitational/teleport/pull/37719) +* Fixed app redirection loop on browser's incognito mode and 3rd party cookie block. [#37692](https://github.com/gravitational/teleport/pull/37692) + +## 14.3.4 (02/01/24) + +* Skip `tsh` AppID pre-flight check whenever possible. [#37643](https://github.com/gravitational/teleport/pull/37643) +* Update OpenSSL to `3.0.13`. [#37552](https://github.com/gravitational/teleport/pull/37552) +* `tsh` FIDO2 backend re-written for improved responsiveness and reliability. [#37538](https://github.com/gravitational/teleport/pull/37538) +* Do not add alphabetically first Kube cluster's name to a user certificate on login. [#37501](https://github.com/gravitational/teleport/pull/37501) +* Allow to replicate proxy pods when using an ingress in the `teleport-cluster` Helm chart. [#37480](https://github.com/gravitational/teleport/pull/37480) +* Fix an issue `tsh` uses wrong default username for auto-user provisioning enabled databases in remote clusters [#37418](https://github.com/gravitational/teleport/pull/37418) +* Prevent backend throttling caused by a large number of app sessions. [#37391](https://github.com/gravitational/teleport/pull/37391) +* Emit audit events when SFTP or SCP commands are blocked. [#37385](https://github.com/gravitational/teleport/pull/37385) +* Fix goroutine leak on PostgreSQL access. [#37342](https://github.com/gravitational/teleport/pull/37342) +* Fixed incompatibility between leaf clusters and ProxyJump. [#37319](https://github.com/gravitational/teleport/pull/37319) +* Fixed a potential crash when setting up the Connect My Computer role in Teleport Connect. [#37314](https://github.com/gravitational/teleport/pull/37314) +* Fixed CA key generation when two auth servers share a single YubiHSM2. [#37296](https://github.com/gravitational/teleport/pull/37296) +* Add support for cancelling CockroachDB requests. [#37282](https://github.com/gravitational/teleport/pull/37282) +* Fix Terraform provider creating AccessLists with next audit date set to Epoch. [#37262](https://github.com/gravitational/teleport/pull/37262) +* Fix an issue selecting MySQL database is not reflected in the audit logs. [#37257](https://github.com/gravitational/teleport/pull/37257) +* The login screen will no longer be rendered for authenticated users. [#37230](https://github.com/gravitational/teleport/pull/37230) +* Fixed missing proxy address in GCP and Azure VM auto-discovery. [#37215](https://github.com/gravitational/teleport/pull/37215) +* Teleport namespace label prefixes are now sorted toward the end of the labels list in the web UI. [#37191](https://github.com/gravitational/teleport/pull/37191) +* Adds `tbot proxy kube` to support connecting to Kubernetes clusters using Machine ID when the Proxy is behind a L7 LB. [#37157](https://github.com/gravitational/teleport/pull/37157) +* Fix a bug that was breaking web UI if automatic upgrades are misconfigured. [#37130](https://github.com/gravitational/teleport/pull/37130) +* Fix an issue AWS Redshift auto-provisioned user not deleted in drop mode. [#37036](https://github.com/gravitational/teleport/pull/37036) +* Fix an issue database auto-user provisioning fails to connect a second session on MariaDB older than 10.7. [#37028](https://github.com/gravitational/teleport/pull/37028) +* Improved styling of the login form in Connect and Web UI. [#37003](https://github.com/gravitational/teleport/pull/37003) +* Ensure that moderated sessions do not get stuck in the event of an unexpected drop in the moderator's connection. [#36917](https://github.com/gravitational/teleport/pull/36917) +* The web terminal now properly displays underscores on Linux. [#36890](https://github.com/gravitational/teleport/pull/36890) +* Fix `tsh` panic on Windows if `WebAuthn.dll` is missing. [#36868](https://github.com/gravitational/teleport/pull/36868) +* Increased timeout when waiting for response from Jira API and webhook to reconcile. [#36818](https://github.com/gravitational/teleport/pull/36818) +* Ensure `connect_to_node_attempts_total` is always incremented when dialing hosts. [#36739](https://github.com/gravitational/teleport/pull/36739) +* Fixed a potential crash in Teleport Connect after downgrading the app from v15+. [#36730](https://github.com/gravitational/teleport/pull/36730) +* Prevent a goroutine leak caused by app sessions not cleaning up resources properly. [#36668](https://github.com/gravitational/teleport/pull/36668) +* Added `tctl idp saml test-attribute-mapping` command to test SAML IdP attribute mapping. [#36662](https://github.com/gravitational/teleport/pull/36662) +* Fixed an issue where valid SAML entity descriptors could be rejected. [#36485](https://github.com/gravitational/teleport/pull/36485) +* Updated SAML IdP UI to display entity ID, SSO URL and X.509 certificate. [#3322](https://github.com/gravitational/teleport.e/pull/3322) +* Updated access request creation dialog to pre-select suggested reviewers. [#3325](https://github.com/gravitational/teleport.e/pull/3325) + ## 14.3.3 (01/12/24) * Fixed routing to nodes by their public addresses. [#36624](https://github.com/gravitational/teleport/pull/36624) @@ -1793,8 +2323,7 @@ Teleport 14 adds database access support for ClickHouse HTTP and native (TCP) protocols. When using HTTP protocol, the user's query activity is captured in the Teleport audit log. -See how to connect ClickHouse to Teleport -[here](docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/clickhouse-self-hosted.mdx). +See how to connect ClickHouse to Teleport [here](docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/clickhouse-self-hosted.mdx). #### Oracle database access audit logging support @@ -4388,10 +4917,10 @@ CentOS 6 support was deprecated in Teleport 8 and has now been removed. #### Desktop access -desktop access now authenticates to LDAP using X.509 client certificates. +Desktop access now authenticates to LDAP using X.509 client certificates. Support for the `password_file` configuration option has been removed. -## 8.0.0 +## 8.0.0 Teleport 8.0 is a major release of Teleport that contains new features, improvements, and bug fixes. @@ -4620,7 +5149,7 @@ Kubernetes access will no longer automatically register a cluster named after th `tsh login` has been updated to no longer change the current Kubernetes context. While `tsh login` will write credentials to `kubeconfig` it will only update your context if `tsh login --kube-cluster` or `tsh kube login ` is used. [#6045](https://github.com/gravitational/teleport/issues/6045) -## 6.2 +## 6.2.0 Teleport 6.2 contains new features, improvements, and bug fixes. @@ -4916,15 +5445,15 @@ This release of Teleport contains multiple bug fixes. * Fixes streaming k8s responses (`kubectl logs -f`, `kubectl run -it`, etc) [#5009](https://github.com/gravitational/teleport/pull/5009) * Multiple fixes for the k8s forwarder [#5038](https://github.com/gravitational/teleport/pull/5038) -## 5.0.0 +## 5.0.0 Teleport 5.0 is a major release with new features, functionality, and bug fixes. Users can review [5.0 closed issues](https://github.com/gravitational/teleport/milestone/39?closed=1) on Github for details of all items. -#### New Features +### New Features Teleport 5.0 introduces two distinct features: Teleport application access and significant Kubernetes access improvements - multi-cluster support. -##### Teleport application access +#### Teleport application access Teleport can now be used to provide secure access to web applications. This new feature was built with the express intention of securing internal apps which might have once lived on a VPN or had a simple authorization and authentication mechanism with little to no audit trail. application access works with everything from dashboards to single page Javascript applications (SPA). @@ -5008,7 +5537,7 @@ proxy_service: You can learn more in the [Application Access introduction](./docs/pages/enroll-resources/application-access/introduction.mdx). -##### Teleport Kubernetes access +#### Teleport Kubernetes access Teleport 5.0 also introduces two highly requested features for Kubernetes. @@ -5160,7 +5689,7 @@ Please follow our [standard upgrade procedure](./docs/pages/upgrading.mdx). * Optional: Consider updating `https_key_file` & `https_cert_file` to our new `https_keypairs:` format. * Optional: Consider migrating Kubernetes access from `proxy_service` to `kubernetes_service` after the upgrade. -### 4.4.6 +## 4.4.6 This release of teleport contains a security fix and a bug fix. @@ -5171,13 +5700,13 @@ Any Enterprise SSO users using Okta, Active Directory, OneLogin or custom SAML c * Fix an issue where `tsh login` would fail with an `AccessDenied` error if the user was perviously logged into a leaf cluster. [#5105](https://github.com/gravitational/teleport/pull/5105) -### 4.4.5 +## 4.4.5 This release of Teleport contains a bug fix. * Fixed an issue where a slow or unresponsive Teleport auth service could hang client connections in async recording mode. [#4696](https://github.com/gravitational/teleport/pull/4696) -### 4.4.4 +## 4.4.4 This release of Teleport adds enhancements to the Access Workflows API. @@ -5196,25 +5725,25 @@ identity providers to determine which roles a user can request. manage and audit, including support for human-readable request/approve/deny reasons and structured annotations. -### 4.4.2 +## 4.4.2 This release of Teleport adds support for a new build architecture. * Added automatic arm64 builds of Teleport to the download portal. -### 4.4.1 +## 4.4.1 This release of Teleport contains a bug fix. * Fixed an issue where defining multiple logging configurations would cause Teleport to crash. [#4598](https://github.com/gravitational/teleport/issues/4598) -### 4.4.0 +## 4.4.0 This is a major Teleport release with a focus on new features, functionality, and bug fixes. It’s a substantial release and users can review [4.4 closed issues](https://github.com/gravitational/teleport/milestone/40?closed=1) on Github for details of all items. -#### New Features +### New Features -##### Concurrent Session Control +#### Concurrent Session Control This addition to Teleport helps customers obtain AC-10 control. We now provide two new optional configuration values: `max_connections` and `max_sessions`. @@ -5272,7 +5801,7 @@ auth_service: session_recording: "node-sync" ``` -#### Improvements +### Improvements * Added session streaming. [#4045](https://github.com/gravitational/teleport/pull/4045) * Added concurrent session control. [#4138](https://github.com/gravitational/teleport/pull/4138) @@ -5281,7 +5810,7 @@ auth_service: * Added node ID to heartbeat debug log [#4291](https://github.com/gravitational/teleport/pull/4291) * Added the option to trigger `pam_authenticate` on login [#3966](https://github.com/gravitational/teleport/pull/3966) -#### Fixes +### Fixes * Fixed issue that caused some idle `kubectl exec` sessions to terminate. [#4377](https://github.com/gravitational/teleport/pull/4377) * Fixed symlink issued when using `tsh` on Windows. [#4347](https://github.com/gravitational/teleport/pull/4347) @@ -5289,19 +5818,19 @@ auth_service: * Fixed issue that caused DynamoDB not to respect HTTP CONNECT proxies. [#4271](https://github.com/gravitational/teleport/pull/4271) * Fixed `/readyz` endpoint to recover much quicker. [#4223](https://github.com/gravitational/teleport/pull/4223) -#### Documentation +### Documentation * Updated Google Workspace documentation to add clarification on supported account types. [#4394](https://github.com/gravitational/teleport/pull/4394) * Updated IoT instructions on necessary ports. [#4398](https://github.com/gravitational/teleport/pull/4398) * Updated Trusted Cluster documentation on how to remove trust from root and leaf clusters. [#4358](https://github.com/gravitational/teleport/pull/4358) * Updated the PAM documentation with PAM authentication usage information. [#4352](https://github.com/gravitational/teleport/pull/4352) -#### Upgrade Notes +### Upgrade Notes Please follow our [standard upgrade procedure](docs/pages/upgrading.mdx). -## 4.3.9 +## 4.3.9 This release of Teleport contains a security fix. @@ -5309,13 +5838,13 @@ This release of Teleport contains a security fix. Any Enterprise SSO users using Okta, Active Directory, OneLogin or custom SAML connectors should upgrade their auth servers to version 4.3.9 and restart Teleport. If you are unable to upgrade immediately, we suggest disabling SAML connectors for all clusters until the updates can be applied. -## 4.3.8 +## 4.3.8 This release of Teleport adds support for a new build architecture. * Added automatic arm64 builds of Teleport to the download portal. -## 4.3.7 +## 4.3.7 This release of Teleport contains a security fix and a bug fix. @@ -5334,7 +5863,7 @@ If you are unable to upgrade immediately, we suggest deleting SAML connectors fo * Fixed an issue where DynamoDB connections made by Teleport would not respect the `HTTP_PROXY` or `HTTPS_PROXY` environment variables. [#4271](https://github.com/gravitational/teleport/pull/4271) -## 4.3.6 +## 4.3.6 This release of Teleport contains multiple bug fixes. @@ -5343,13 +5872,13 @@ This release of Teleport contains multiple bug fixes. * Updated `/readyz` endpoint to recover faster after node goes into degraded state. [#4223](https://github.com/gravitational/teleport/pull/4223) * Added node UUID to debug logs to allow correlation between TCP connections and nodes. [#4291](https://github.com/gravitational/teleport/pull/4291) -## 4.3.5 +## 4.3.5 This release of Teleport contains a bug fix. * Fixed issue that caused Teleport Docker images to be built incorrectly. [#4201](https://github.com/gravitational/teleport/pull/4201) -## 4.3.4 +## 4.3.4 This release of Teleport contains multiple bug fixes. @@ -5597,7 +6126,13 @@ This is a minor Teleport release with a focus on new features and bug fixes. * Adopting root/leaf terminology for trusted clusters. [Trusted cluster documentation](./docs/pages/management/admin/trustedclusters.mdx). * Documented Teleport FedRAMP & FIPS Support. [FedRAMP & FIPS documentation](./docs/pages/access-controls/compliance-frameworks/fedramp.mdx). -## 4.1.11 +## 4.1.13 + +This release of Teleport contains a bug fix. + +* Fixed issue where the port forwarding option in a role was ignored. [#3208](https://github.com/gravitational/teleport/pull/3208) + +## 4.1.11 This release of Teleport contains a security fix. @@ -5614,7 +6149,7 @@ Active Directory, OneLogin or custom SAML connectors should upgrade their auth s If you are unable to upgrade immediately, we suggest deleting SAML connectors for all clusters until the updates can be applied. -## 4.1.10 +## 4.1.10 As part of a routine security audit of Teleport, a security vulnerability was discovered that affects all recent releases of Teleport. We strongly suggest upgrading to the latest patched release to mitigate this vulnerability. @@ -5630,43 +6165,43 @@ Command line programs like `tsh` (or `ssh`) are not affected by this vulnerabili To mitigate this issue, upgrade and restart all Teleport proxy processes. -## 4.1.9 +## 4.1.9 This release of Teleport contains a security fix. * Mitigated [CVE-2020-9283](https://groups.google.com/forum/#!msg/golang-announce/3L45YRc91SY/ywEPcKLnGQAJ) by updating golang.org/x/crypto. -## 4.1.8 +## 4.1.8 This release of Teleport contains a bug fix. * Fixed a regression in role mapping between trusted clusters. [#3252](https://github.com/gravitational/teleport/issues/3252) -## 4.1.7 +## 4.1.7 This release of Teleport contains a bug fix. * Fixed issue where the port forwarding option in a role was ignored. [#3208](https://github.com/gravitational/teleport/pull/3208) -## 4.1.6 +## 4.1.6 This release of Teleport contains a bug fix. * Fixed an issue that caused Teleport not to start with certain OIDC claims. [#3053](https://github.com/gravitational/teleport/issues/3053) -## 4.1.5 +## 4.1.5 This release of Teleport adds support for an older version of Linux. * Added RHEL/CentOS 6.x builds to the build pipeline. [#3175](https://github.com/gravitational/teleport/pull/3175) -## 4.1.4 +## 4.1.4 This release of Teleport contains a bug fix. * Fixed GSuite integration by adding support for service accounts. [#3122](https://github.com/gravitational/teleport/pull/3122) -## 4.1.3 +## 4.1.3 This release of Teleport contains multiple bug fixes. @@ -5674,20 +6209,20 @@ This release of Teleport contains multiple bug fixes. * Fixed issues with `local_auth` for FIPS builds. [#3100](https://github.com/gravitational/teleport/pull/3100) * Upgraded Go runtime to 1.13.2 to mitigate [CVE-2019-16276](https://github.com/golang/go/issues/34540) and [CVE-2019-17596](https://github.com/golang/go/issues/34960). -## 4.1.2 +## 4.1.2 This release of Teleport contains improvements to the build code. * Added support for building Docker images using the FIPS-compliant version of Teleport. The first of these images is quay.io/gravitational/teleport-ent:4.1.2-fips * In future, these images will be automatically built for use by Teleport Enterprise customers. -## 4.1.1 +## 4.1.1 This release of Teleport contains a bug fix. * Fixed an issue with multi-cluster EKS when the Teleport proxy runs outside EKS. [#3070](https://github.com/gravitational/teleport/pull/3070) -## 4.1.0 +## 4.1.0 This is a major Teleport release with a focus on stability and bug fixes. @@ -5710,7 +6245,7 @@ This is a major Teleport release with a focus on stability and bug fixes. * Teleport truncates MOTD with PAM. [#2477](https://github.com/gravitational/teleport/issues/2477) * Miscellaneous fixes around error handling and reporting. -## 4.0.16 +## 4.0.16 As part of a routine security audit of Teleport, a security vulnerability was discovered that affects all recent releases of Teleport. We strongly suggest upgrading to the latest patched release to mitigate this vulnerability. @@ -5738,13 +6273,7 @@ This release of Teleport contains a bug fix. * Fixed a regression in role mapping between trusted clusters. [#3252](https://github.com/gravitational/teleport/issues/3252) -## 4.1.13 - -This release of Teleport contains a bug fix. - -* Fixed issue where the port forwarding option in a role was ignored. [#3208](https://github.com/gravitational/teleport/pull/3208) - -## 4.0.12 +## 4.0.12 This release of Teleport contains a bug fix. @@ -5911,7 +6440,7 @@ This release of Teleport contains a new feature. * Added `--bind-addr` to force `tsh` to bind to a specific port during SSO login. [#2620](https://github.com/gravitational/teleport/issues/2620) -## 3.2 +## 3.2.0 This version brings support for Amazon's managed Kubernetes offering (EKS). @@ -6017,7 +6546,7 @@ Teleport 3.1.1 contains a security fix. We strongly encourage anyone running Tel * Upgraded Go to 1.11.4 to mitigate CVE-2018-16875: [CPU denial of service in chain validation](https://golang.org/issue/29233) Go. For customers using the RHEL5.x compatible release of Teleport, we've backported this fix to Go 1.9.7, before releasing RHEL 5.x compatible binaries. -## 3.1 +## 3.1.0 This is a major Teleport release with a focus on backwards compatibility, stability, and bug fixes. Some of the improvements: @@ -6056,19 +6585,19 @@ Teleport 3.0.3 contains a security fix. We strongly encourage anyone running Tel * Due to the flaw in internal RBAC verification logic, a compromised node, trusted cluster or authenticated non-privileged user can craft special request to Teleport's internal auth server API to gain access to the private key material of the cluster's internal certificate authorities and elevate their privileges to gain full administrative access to the Teleport cluster. This vulnerability only affects authenticated clients, there is no known way to exploit this vulnerability outside the cluster for unauthenticated clients. -## 3.0.2 +## 3.0.2 Teleport 3.0.2 contains a security fix. We strongly encourage anyone running Teleport 3.0.1 to upgrade. * Upgraded Go to 1.11.4 to mitigate CVE-2018-16875: [CPU denial of service in chain validation](https://golang.org/issue/29233) Go. For customers using the RHEL5.x compatible release of Teleport, we've backported this fix to Go 1.9.7, before releasing RHEL 5.x compatible binaries. -## 3.0.1 +## 3.0.1 This release of Teleport contains the following bug fix: * Fix regression that marked ADFS claims as invalid. [#2293](https://github.com/gravitational/teleport/pull/2293) -## 3.0 +## 3.0.0 This is a major Teleport release which introduces support for Kubernetes clusters. In addition to this new feature this release includes several @@ -6783,7 +7312,7 @@ The most pressing issues (a phishing attack which can potentially be used to ext * Fixed Regressions. [#874](https://github.com/gravitational/teleport/pull/874), [#876](https://github.com/gravitational/teleport/pull/876), [#883](https://github.com/gravitational/teleport/pull/883), [#892](https://github.com/gravitational/teleport/pull/892), and [#906](https://github.com/gravitational/teleport/pull/906) -## 2.0 +## 2.0.0 This is a major new release of Teleport. @@ -6832,7 +7361,7 @@ v1.3.1 is a maintenance release which fixes a few issues found in 1.3 * U2F documentation has been improved -## 1.3 +## 1.3.0 This release includes several major new features and it's recommended for production use. @@ -6896,6 +7425,6 @@ to OSS Teleport users. * Guessing `advertise_ip` chooses IPv6 address space. #486 -## 1.0 +## 1.0.0 The first official release of Teleport! diff --git a/Makefile b/Makefile index 273e2738649cd..c74c36486c161 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ # Stable releases: "1.0.0" # Pre-releases: "1.0.0-alpha.1", "1.0.0-beta.2", "1.0.0-rc.3" # Master/dev branch: "1.0.0-dev" -VERSION=16.1.0 +VERSION=16.1.4 DOCKER_IMAGE ?= teleport diff --git a/api/client/proto/authservice.pb.go b/api/client/proto/authservice.pb.go index 7b0da9c93095c..84ff715ffe6de 100644 --- a/api/client/proto/authservice.pb.go +++ b/api/client/proto/authservice.pb.go @@ -8,6 +8,7 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" v1 "github.com/gravitational/teleport/api/gen/proto/go/attestation/v1" v11 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" @@ -22,7 +23,6 @@ import ( codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" emptypb "google.golang.org/protobuf/types/known/emptypb" - _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" @@ -450,7 +450,7 @@ func (x DatabaseCertRequest_Requester) String() string { } func (DatabaseCertRequest_Requester) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{75, 0} + return fileDescriptor_0ffcffcda38ae159, []int{76, 0} } // Extensions are the extensions to add to the certificate. @@ -478,7 +478,7 @@ func (x DatabaseCertRequest_Extensions) String() string { } func (DatabaseCertRequest_Extensions) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{75, 1} + return fileDescriptor_0ffcffcda38ae159, []int{76, 1} } // Watch specifies watch parameters @@ -1255,7 +1255,9 @@ type RouteToApp struct { // AzureIdentity is the Azure identity to assume when accessing Azure API. AzureIdentity string `protobuf:"bytes,6,opt,name=AzureIdentity,proto3" json:"azure_identity,omitempty"` // GCPServiceAccount is the GCP service account to assume when accessing GCP API. - GCPServiceAccount string `protobuf:"bytes,7,opt,name=GCPServiceAccount,proto3" json:"gcp_service_account,omitempty"` + GCPServiceAccount string `protobuf:"bytes,7,opt,name=GCPServiceAccount,proto3" json:"gcp_service_account,omitempty"` + // URI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + URI string `protobuf:"bytes,8,opt,name=URI,proto3" json:"uri,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1344,6 +1346,13 @@ func (m *RouteToApp) GetGCPServiceAccount() string { return "" } +func (m *RouteToApp) GetURI() string { + if m != nil { + return m.URI + } + return "" +} + // GetUserRequest specifies parameters for the GetUser method. type GetUserRequest struct { // Name is the name of the desired user. @@ -2052,34 +2061,31 @@ func (m *PingResponse) GetLoadAllCAs() bool { // Features are auth server features. type Features struct { // Kubernetes enables Kubernetes Access product + // Deprecated remove in v18; leverage entitlements Kubernetes bool `protobuf:"varint,1,opt,name=Kubernetes,proto3" json:"kubernetes"` // App enables Application Access product + // Deprecated remove in v18; leverage entitlements App bool `protobuf:"varint,2,opt,name=App,proto3" json:"app"` // DB enables database access product + // Deprecated remove in v18; leverage entitlements DB bool `protobuf:"varint,3,opt,name=DB,proto3" json:"db"` // OIDC enables OIDC connectors + // Deprecated remove in v18; leverage entitlements OIDC bool `protobuf:"varint,4,opt,name=OIDC,proto3" json:"oidc"` // SAML enables SAML connectors + // Deprecated remove in v18; leverage entitlements SAML bool `protobuf:"varint,5,opt,name=SAML,proto3" json:"saml"` // AccessControls enables FIPS access controls AccessControls bool `protobuf:"varint,6,opt,name=AccessControls,proto3" json:"access_controls"` - // Currently this flag is to gate actions from OSS clusters. - // - // Determining support for access request is currently determined by: - // 1) Enterprise + [Features.IdentityGovernanceSecurity] == true, new flag - // introduced with Enterprise Usage Based (EUB) product. - // 2) Enterprise + [Features.IsUsageBasedBilling] == false, legacy support - // where before EUB, it was unlimited. - // - // AdvancedAccessWorkflows is currently set to true for all - // enterprise editions (team, cloud, on-prem). Historically, access request - // was only available for enterprise cloud and enterprise on-prem. + // AdvancedAccessWorkflows is currently set to the value of the Cloud AccessRequests entitlement AdvancedAccessWorkflows bool `protobuf:"varint,7,opt,name=AdvancedAccessWorkflows,proto3" json:"advanced_access_workflows"` // Cloud enables some cloud-related features Cloud bool `protobuf:"varint,8,opt,name=Cloud,proto3" json:"cloud"` // HSM enables PKCS#11 HSM support + // Deprecated remove in v18; leverage entitlements HSM bool `protobuf:"varint,9,opt,name=HSM,proto3" json:"hsm"` // Desktop enables desktop access product + // Deprecated remove in v18; leverage entitlements Desktop bool `protobuf:"varint,10,opt,name=Desktop,proto3" json:"desktop"` // RecoveryCodes enables recovery codes RecoveryCodes bool `protobuf:"varint,14,opt,name=RecoveryCodes,proto3" json:"recovery_codes"` @@ -2090,17 +2096,22 @@ type Features struct { // IsUsageBased enables some usage-based billing features IsUsageBased bool `protobuf:"varint,17,opt,name=IsUsageBased,proto3" json:"is_usage_based"` // Assist enables the Assistant feature + // Deprecated remove in v18; leverage entitlements Assist bool `protobuf:"varint,18,opt,name=Assist,proto3" json:"assist"` // DeviceTrust holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements DeviceTrust *DeviceTrustFeature `protobuf:"bytes,19,opt,name=DeviceTrust,proto3" json:"device_trust,omitempty"` // FeatureHiding enables hiding features from being discoverable for users who don't have the necessary permissions. + // Deprecated remove in v18; leverage entitlements FeatureHiding bool `protobuf:"varint,20,opt,name=FeatureHiding,proto3" json:"feature_hiding,omitempty"` // AccessRequests holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements AccessRequests *AccessRequestsFeature `protobuf:"bytes,21,opt,name=AccessRequests,proto3" json:"access_requests,omitempty"` // CustomTheme holds the name of WebUI custom theme. CustomTheme string `protobuf:"bytes,22,opt,name=CustomTheme,proto3" json:"custom_theme,omitempty"` // IdentityGovernance indicates whether IGS related features are enabled: // access list, access request, access monitoring, device trust. + // Deprecated remove in v18; leverage entitlements IdentityGovernance bool `protobuf:"varint,23,opt,name=IdentityGovernance,proto3" json:"identity_governance,omitempty"` // AccessGraph enables the usage of access graph. // NOTE: this is a legacy flag that is currently used to signal @@ -2109,29 +2120,41 @@ type Features struct { // TODO(justinas): remove this field once "TAG enabled" status is moved to a resource in the backend. AccessGraph bool `protobuf:"varint,24,opt,name=AccessGraph,proto3" json:"access_graph,omitempty"` // AccessListFeature holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements AccessList *AccessListFeature `protobuf:"bytes,25,opt,name=AccessList,proto3" json:"access_list,omitempty"` // AccessMonitoringFeature holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements for access and AccessMonitoringConfigured for enabled AccessMonitoring *AccessMonitoringFeature `protobuf:"bytes,26,opt,name=AccessMonitoring,proto3" json:"access_monitoring,omitempty"` // ProductType describes the product being used. ProductType ProductType `protobuf:"varint,27,opt,name=ProductType,proto3,enum=proto.ProductType" json:"product_type,omitempty"` // Policy enables the Teleport Policy feature set. // At the time of writing, this includes Teleport Access Graph (TAG). + // Deprecated remove in v18; leverage entitlements Policy *PolicyFeature `protobuf:"bytes,28,opt,name=Policy,proto3" json:"policy,omitempty"` // Questionnaire indicates whether cluster users should get an onboarding questionnaire Questionnaire bool `protobuf:"varint,29,opt,name=Questionnaire,proto3" json:"questionnaire,omitempty"` // IsStripeManaged indicates if the cluster billing is managed via Stripe IsStripeManaged bool `protobuf:"varint,30,opt,name=IsStripeManaged,proto3" json:"is_stripe_managed,omitempty"` // ExternalAuditStorage indicates whether the EAS feature is enabled in the cluster. + // Deprecated remove in v18; leverage entitlements ExternalAuditStorage bool `protobuf:"varint,31,opt,name=ExternalAuditStorage,proto3" json:"external_audit_storage,omitempty"` // SupportType indicates the type of the customer's support SupportType SupportType `protobuf:"varint,32,opt,name=SupportType,proto3,enum=proto.SupportType" json:"support_type,omitempty"` // JoinActiveSessions indicates whether joining active sessions via web UI is enabled + // Deprecated remove in v18; leverage entitlements JoinActiveSessions bool `protobuf:"varint,33,opt,name=JoinActiveSessions,proto3" json:"join_active_sessions,omitempty"` // MobileDeviceManagement indicates whether endpoint management (like Jamf Plugin) can be used in the cluster - MobileDeviceManagement bool `protobuf:"varint,34,opt,name=MobileDeviceManagement,proto3" json:"mobile_device_management,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + // Deprecated remove in v18; leverage entitlements + MobileDeviceManagement bool `protobuf:"varint,34,opt,name=MobileDeviceManagement,proto3" json:"mobile_device_management,omitempty"` + // entitlements define a customer’s access to a specific features + Entitlements map[string]*EntitlementInfo `protobuf:"bytes,35,rep,name=entitlements,proto3" json:"entitlements,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // AccessMonitoringConfigured contributes to the enablement of access monitoring. + // NOTE: this flag is used to signal that Access Monitoring is *enabled* on a cluster. + // *Access* to the feature is gated on the `AccessMonitoring` entitlement. + AccessMonitoringConfigured bool `protobuf:"varint,36,opt,name=AccessMonitoringConfigured,proto3" json:"AccessMonitoringConfigured,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Features) Reset() { *m = Features{} } @@ -2384,6 +2407,78 @@ func (m *Features) GetMobileDeviceManagement() bool { return false } +func (m *Features) GetEntitlements() map[string]*EntitlementInfo { + if m != nil { + return m.Entitlements + } + return nil +} + +func (m *Features) GetAccessMonitoringConfigured() bool { + if m != nil { + return m.AccessMonitoringConfigured + } + return false +} + +// EntitlementInfo is the state and limits of a particular entitlement +type EntitlementInfo struct { + // enabled indicates the feature is 'on' if true + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + // limit indicates the allotted amount of use when limited + Limit int32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *EntitlementInfo) Reset() { *m = EntitlementInfo{} } +func (m *EntitlementInfo) String() string { return proto.CompactTextString(m) } +func (*EntitlementInfo) ProtoMessage() {} +func (*EntitlementInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_0ffcffcda38ae159, []int{20} +} +func (m *EntitlementInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EntitlementInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EntitlementInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *EntitlementInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_EntitlementInfo.Merge(m, src) +} +func (m *EntitlementInfo) XXX_Size() int { + return m.Size() +} +func (m *EntitlementInfo) XXX_DiscardUnknown() { + xxx_messageInfo_EntitlementInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_EntitlementInfo proto.InternalMessageInfo + +func (m *EntitlementInfo) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +func (m *EntitlementInfo) GetLimit() int32 { + if m != nil { + return m.Limit + } + return 0 +} + // DeviceTrustFeature holds the Device Trust feature general and usage-based // settings. // Limits have no affect if [Features.IdentityGovernance] is enabled. @@ -2408,7 +2503,7 @@ func (m *DeviceTrustFeature) Reset() { *m = DeviceTrustFeature{} } func (m *DeviceTrustFeature) String() string { return proto.CompactTextString(m) } func (*DeviceTrustFeature) ProtoMessage() {} func (*DeviceTrustFeature) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{20} + return fileDescriptor_0ffcffcda38ae159, []int{21} } func (m *DeviceTrustFeature) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2467,7 +2562,7 @@ func (m *AccessRequestsFeature) Reset() { *m = AccessRequestsFeature{} } func (m *AccessRequestsFeature) String() string { return proto.CompactTextString(m) } func (*AccessRequestsFeature) ProtoMessage() {} func (*AccessRequestsFeature) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{21} + return fileDescriptor_0ffcffcda38ae159, []int{22} } func (m *AccessRequestsFeature) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2518,7 +2613,7 @@ func (m *AccessListFeature) Reset() { *m = AccessListFeature{} } func (m *AccessListFeature) String() string { return proto.CompactTextString(m) } func (*AccessListFeature) ProtoMessage() {} func (*AccessListFeature) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{22} + return fileDescriptor_0ffcffcda38ae159, []int{23} } func (m *AccessListFeature) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2570,7 +2665,7 @@ func (m *AccessMonitoringFeature) Reset() { *m = AccessMonitoringFeature func (m *AccessMonitoringFeature) String() string { return proto.CompactTextString(m) } func (*AccessMonitoringFeature) ProtoMessage() {} func (*AccessMonitoringFeature) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{23} + return fileDescriptor_0ffcffcda38ae159, []int{24} } func (m *AccessMonitoringFeature) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2626,7 +2721,7 @@ func (m *PolicyFeature) Reset() { *m = PolicyFeature{} } func (m *PolicyFeature) String() string { return proto.CompactTextString(m) } func (*PolicyFeature) ProtoMessage() {} func (*PolicyFeature) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{24} + return fileDescriptor_0ffcffcda38ae159, []int{25} } func (m *PolicyFeature) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2675,7 +2770,7 @@ func (m *DeleteUserRequest) Reset() { *m = DeleteUserRequest{} } func (m *DeleteUserRequest) String() string { return proto.CompactTextString(m) } func (*DeleteUserRequest) ProtoMessage() {} func (*DeleteUserRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{25} + return fileDescriptor_0ffcffcda38ae159, []int{26} } func (m *DeleteUserRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2723,7 +2818,7 @@ func (m *Semaphores) Reset() { *m = Semaphores{} } func (m *Semaphores) String() string { return proto.CompactTextString(m) } func (*Semaphores) ProtoMessage() {} func (*Semaphores) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{26} + return fileDescriptor_0ffcffcda38ae159, []int{27} } func (m *Semaphores) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2780,7 +2875,7 @@ func (m *AuditStreamRequest) Reset() { *m = AuditStreamRequest{} } func (m *AuditStreamRequest) String() string { return proto.CompactTextString(m) } func (*AuditStreamRequest) ProtoMessage() {} func (*AuditStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{27} + return fileDescriptor_0ffcffcda38ae159, []int{28} } func (m *AuditStreamRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2905,7 +3000,7 @@ func (m *AuditStreamStatus) Reset() { *m = AuditStreamStatus{} } func (m *AuditStreamStatus) String() string { return proto.CompactTextString(m) } func (*AuditStreamStatus) ProtoMessage() {} func (*AuditStreamStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{28} + return fileDescriptor_0ffcffcda38ae159, []int{29} } func (m *AuditStreamStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2953,7 +3048,7 @@ func (m *CreateStream) Reset() { *m = CreateStream{} } func (m *CreateStream) String() string { return proto.CompactTextString(m) } func (*CreateStream) ProtoMessage() {} func (*CreateStream) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{29} + return fileDescriptor_0ffcffcda38ae159, []int{30} } func (m *CreateStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3004,7 +3099,7 @@ func (m *ResumeStream) Reset() { *m = ResumeStream{} } func (m *ResumeStream) String() string { return proto.CompactTextString(m) } func (*ResumeStream) ProtoMessage() {} func (*ResumeStream) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{30} + return fileDescriptor_0ffcffcda38ae159, []int{31} } func (m *ResumeStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3059,7 +3154,7 @@ func (m *CompleteStream) Reset() { *m = CompleteStream{} } func (m *CompleteStream) String() string { return proto.CompactTextString(m) } func (*CompleteStream) ProtoMessage() {} func (*CompleteStream) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{31} + return fileDescriptor_0ffcffcda38ae159, []int{32} } func (m *CompleteStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3099,7 +3194,7 @@ func (m *FlushAndCloseStream) Reset() { *m = FlushAndCloseStream{} } func (m *FlushAndCloseStream) String() string { return proto.CompactTextString(m) } func (*FlushAndCloseStream) ProtoMessage() {} func (*FlushAndCloseStream) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{32} + return fileDescriptor_0ffcffcda38ae159, []int{33} } func (m *FlushAndCloseStream) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3141,7 +3236,7 @@ func (m *UpsertApplicationServerRequest) Reset() { *m = UpsertApplicatio func (m *UpsertApplicationServerRequest) String() string { return proto.CompactTextString(m) } func (*UpsertApplicationServerRequest) ProtoMessage() {} func (*UpsertApplicationServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{33} + return fileDescriptor_0ffcffcda38ae159, []int{34} } func (m *UpsertApplicationServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3194,7 +3289,7 @@ func (m *DeleteApplicationServerRequest) Reset() { *m = DeleteApplicatio func (m *DeleteApplicationServerRequest) String() string { return proto.CompactTextString(m) } func (*DeleteApplicationServerRequest) ProtoMessage() {} func (*DeleteApplicationServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{34} + return fileDescriptor_0ffcffcda38ae159, []int{35} } func (m *DeleteApplicationServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3257,7 +3352,7 @@ func (m *DeleteAllApplicationServersRequest) Reset() { *m = DeleteAllApp func (m *DeleteAllApplicationServersRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllApplicationServersRequest) ProtoMessage() {} func (*DeleteAllApplicationServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{35} + return fileDescriptor_0ffcffcda38ae159, []int{36} } func (m *DeleteAllApplicationServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3315,7 +3410,7 @@ func (m *GenerateAppTokenRequest) Reset() { *m = GenerateAppTokenRequest func (m *GenerateAppTokenRequest) String() string { return proto.CompactTextString(m) } func (*GenerateAppTokenRequest) ProtoMessage() {} func (*GenerateAppTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{36} + return fileDescriptor_0ffcffcda38ae159, []int{37} } func (m *GenerateAppTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3391,7 +3486,7 @@ func (m *GenerateAppTokenResponse) Reset() { *m = GenerateAppTokenRespon func (m *GenerateAppTokenResponse) String() string { return proto.CompactTextString(m) } func (*GenerateAppTokenResponse) ProtoMessage() {} func (*GenerateAppTokenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{37} + return fileDescriptor_0ffcffcda38ae159, []int{38} } func (m *GenerateAppTokenResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3440,7 +3535,7 @@ func (m *GetAppSessionRequest) Reset() { *m = GetAppSessionRequest{} } func (m *GetAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*GetAppSessionRequest) ProtoMessage() {} func (*GetAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{38} + return fileDescriptor_0ffcffcda38ae159, []int{39} } func (m *GetAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3489,7 +3584,7 @@ func (m *GetAppSessionResponse) Reset() { *m = GetAppSessionResponse{} } func (m *GetAppSessionResponse) String() string { return proto.CompactTextString(m) } func (*GetAppSessionResponse) ProtoMessage() {} func (*GetAppSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{39} + return fileDescriptor_0ffcffcda38ae159, []int{40} } func (m *GetAppSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3547,7 +3642,7 @@ func (m *ListAppSessionsRequest) Reset() { *m = ListAppSessionsRequest{} func (m *ListAppSessionsRequest) String() string { return proto.CompactTextString(m) } func (*ListAppSessionsRequest) ProtoMessage() {} func (*ListAppSessionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{40} + return fileDescriptor_0ffcffcda38ae159, []int{41} } func (m *ListAppSessionsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3613,7 +3708,7 @@ func (m *ListAppSessionsResponse) Reset() { *m = ListAppSessionsResponse func (m *ListAppSessionsResponse) String() string { return proto.CompactTextString(m) } func (*ListAppSessionsResponse) ProtoMessage() {} func (*ListAppSessionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{41} + return fileDescriptor_0ffcffcda38ae159, []int{42} } func (m *ListAppSessionsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3669,7 +3764,7 @@ func (m *GetSnowflakeSessionsResponse) Reset() { *m = GetSnowflakeSessio func (m *GetSnowflakeSessionsResponse) String() string { return proto.CompactTextString(m) } func (*GetSnowflakeSessionsResponse) ProtoMessage() {} func (*GetSnowflakeSessionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{42} + return fileDescriptor_0ffcffcda38ae159, []int{43} } func (m *GetSnowflakeSessionsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3727,7 +3822,7 @@ func (m *ListSAMLIdPSessionsRequest) Reset() { *m = ListSAMLIdPSessionsR func (m *ListSAMLIdPSessionsRequest) String() string { return proto.CompactTextString(m) } func (*ListSAMLIdPSessionsRequest) ProtoMessage() {} func (*ListSAMLIdPSessionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{43} + return fileDescriptor_0ffcffcda38ae159, []int{44} } func (m *ListSAMLIdPSessionsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3793,7 +3888,7 @@ func (m *ListSAMLIdPSessionsResponse) Reset() { *m = ListSAMLIdPSessions func (m *ListSAMLIdPSessionsResponse) String() string { return proto.CompactTextString(m) } func (*ListSAMLIdPSessionsResponse) ProtoMessage() {} func (*ListSAMLIdPSessionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{44} + return fileDescriptor_0ffcffcda38ae159, []int{45} } func (m *ListSAMLIdPSessionsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3853,17 +3948,23 @@ type CreateAppSessionRequest struct { // MFAResponse is a response to a challenge from a user's MFA device. // An optional field, that when provided, the response will be validated and // the ID of the validated MFA device will be stored in session's certificate. - MFAResponse *MFAAuthenticateResponse `protobuf:"bytes,8,opt,name=MFAResponse,proto3" json:"mfa_response,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + MFAResponse *MFAAuthenticateResponse `protobuf:"bytes,8,opt,name=MFAResponse,proto3" json:"mfa_response,omitempty"` + // AppName is the name of the application. + AppName string `protobuf:"bytes,9,opt,name=AppName,proto3" json:"app_name"` + // URI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + URI string `protobuf:"bytes,10,opt,name=URI,proto3" json:"uri"` + // ClientAddr is a client (user's) address. + ClientAddr string `protobuf:"bytes,11,opt,name=ClientAddr,proto3" json:"client_addr,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *CreateAppSessionRequest) Reset() { *m = CreateAppSessionRequest{} } func (m *CreateAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*CreateAppSessionRequest) ProtoMessage() {} func (*CreateAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{45} + return fileDescriptor_0ffcffcda38ae159, []int{46} } func (m *CreateAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3941,6 +4042,27 @@ func (m *CreateAppSessionRequest) GetMFAResponse() *MFAAuthenticateResponse { return nil } +func (m *CreateAppSessionRequest) GetAppName() string { + if m != nil { + return m.AppName + } + return "" +} + +func (m *CreateAppSessionRequest) GetURI() string { + if m != nil { + return m.URI + } + return "" +} + +func (m *CreateAppSessionRequest) GetClientAddr() string { + if m != nil { + return m.ClientAddr + } + return "" +} + // CreateAppSessionResponse contains the requested application web session. type CreateAppSessionResponse struct { // Session is the application web session. @@ -3954,7 +4076,7 @@ func (m *CreateAppSessionResponse) Reset() { *m = CreateAppSessionRespon func (m *CreateAppSessionResponse) String() string { return proto.CompactTextString(m) } func (*CreateAppSessionResponse) ProtoMessage() {} func (*CreateAppSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{46} + return fileDescriptor_0ffcffcda38ae159, []int{47} } func (m *CreateAppSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4007,7 +4129,7 @@ func (m *CreateSnowflakeSessionRequest) Reset() { *m = CreateSnowflakeSe func (m *CreateSnowflakeSessionRequest) String() string { return proto.CompactTextString(m) } func (*CreateSnowflakeSessionRequest) ProtoMessage() {} func (*CreateSnowflakeSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{47} + return fileDescriptor_0ffcffcda38ae159, []int{48} } func (m *CreateSnowflakeSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4069,7 +4191,7 @@ func (m *CreateSnowflakeSessionResponse) Reset() { *m = CreateSnowflakeS func (m *CreateSnowflakeSessionResponse) String() string { return proto.CompactTextString(m) } func (*CreateSnowflakeSessionResponse) ProtoMessage() {} func (*CreateSnowflakeSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{48} + return fileDescriptor_0ffcffcda38ae159, []int{49} } func (m *CreateSnowflakeSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4122,7 +4244,7 @@ func (m *CreateSAMLIdPSessionRequest) Reset() { *m = CreateSAMLIdPSessio func (m *CreateSAMLIdPSessionRequest) String() string { return proto.CompactTextString(m) } func (*CreateSAMLIdPSessionRequest) ProtoMessage() {} func (*CreateSAMLIdPSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{49} + return fileDescriptor_0ffcffcda38ae159, []int{50} } func (m *CreateSAMLIdPSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4184,7 +4306,7 @@ func (m *CreateSAMLIdPSessionResponse) Reset() { *m = CreateSAMLIdPSessi func (m *CreateSAMLIdPSessionResponse) String() string { return proto.CompactTextString(m) } func (*CreateSAMLIdPSessionResponse) ProtoMessage() {} func (*CreateSAMLIdPSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{50} + return fileDescriptor_0ffcffcda38ae159, []int{51} } func (m *CreateSAMLIdPSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4233,7 +4355,7 @@ func (m *GetSnowflakeSessionRequest) Reset() { *m = GetSnowflakeSessionR func (m *GetSnowflakeSessionRequest) String() string { return proto.CompactTextString(m) } func (*GetSnowflakeSessionRequest) ProtoMessage() {} func (*GetSnowflakeSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{51} + return fileDescriptor_0ffcffcda38ae159, []int{52} } func (m *GetSnowflakeSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4282,7 +4404,7 @@ func (m *GetSnowflakeSessionResponse) Reset() { *m = GetSnowflakeSession func (m *GetSnowflakeSessionResponse) String() string { return proto.CompactTextString(m) } func (*GetSnowflakeSessionResponse) ProtoMessage() {} func (*GetSnowflakeSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{52} + return fileDescriptor_0ffcffcda38ae159, []int{53} } func (m *GetSnowflakeSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4331,7 +4453,7 @@ func (m *GetSAMLIdPSessionRequest) Reset() { *m = GetSAMLIdPSessionReque func (m *GetSAMLIdPSessionRequest) String() string { return proto.CompactTextString(m) } func (*GetSAMLIdPSessionRequest) ProtoMessage() {} func (*GetSAMLIdPSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{53} + return fileDescriptor_0ffcffcda38ae159, []int{54} } func (m *GetSAMLIdPSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4380,7 +4502,7 @@ func (m *GetSAMLIdPSessionResponse) Reset() { *m = GetSAMLIdPSessionResp func (m *GetSAMLIdPSessionResponse) String() string { return proto.CompactTextString(m) } func (*GetSAMLIdPSessionResponse) ProtoMessage() {} func (*GetSAMLIdPSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{54} + return fileDescriptor_0ffcffcda38ae159, []int{55} } func (m *GetSAMLIdPSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4428,7 +4550,7 @@ func (m *DeleteAppSessionRequest) Reset() { *m = DeleteAppSessionRequest func (m *DeleteAppSessionRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAppSessionRequest) ProtoMessage() {} func (*DeleteAppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{55} + return fileDescriptor_0ffcffcda38ae159, []int{56} } func (m *DeleteAppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4476,7 +4598,7 @@ func (m *DeleteSnowflakeSessionRequest) Reset() { *m = DeleteSnowflakeSe func (m *DeleteSnowflakeSessionRequest) String() string { return proto.CompactTextString(m) } func (*DeleteSnowflakeSessionRequest) ProtoMessage() {} func (*DeleteSnowflakeSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{56} + return fileDescriptor_0ffcffcda38ae159, []int{57} } func (m *DeleteSnowflakeSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4524,7 +4646,7 @@ func (m *DeleteSAMLIdPSessionRequest) Reset() { *m = DeleteSAMLIdPSessio func (m *DeleteSAMLIdPSessionRequest) String() string { return proto.CompactTextString(m) } func (*DeleteSAMLIdPSessionRequest) ProtoMessage() {} func (*DeleteSAMLIdPSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{57} + return fileDescriptor_0ffcffcda38ae159, []int{58} } func (m *DeleteSAMLIdPSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4573,7 +4695,7 @@ func (m *DeleteUserAppSessionsRequest) Reset() { *m = DeleteUserAppSessi func (m *DeleteUserAppSessionsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteUserAppSessionsRequest) ProtoMessage() {} func (*DeleteUserAppSessionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{58} + return fileDescriptor_0ffcffcda38ae159, []int{59} } func (m *DeleteUserAppSessionsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4622,7 +4744,7 @@ func (m *DeleteUserSAMLIdPSessionsRequest) Reset() { *m = DeleteUserSAML func (m *DeleteUserSAMLIdPSessionsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteUserSAMLIdPSessionsRequest) ProtoMessage() {} func (*DeleteUserSAMLIdPSessionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{59} + return fileDescriptor_0ffcffcda38ae159, []int{60} } func (m *DeleteUserSAMLIdPSessionsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4671,7 +4793,7 @@ func (m *GetWebSessionResponse) Reset() { *m = GetWebSessionResponse{} } func (m *GetWebSessionResponse) String() string { return proto.CompactTextString(m) } func (*GetWebSessionResponse) ProtoMessage() {} func (*GetWebSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{60} + return fileDescriptor_0ffcffcda38ae159, []int{61} } func (m *GetWebSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4720,7 +4842,7 @@ func (m *GetWebSessionsResponse) Reset() { *m = GetWebSessionsResponse{} func (m *GetWebSessionsResponse) String() string { return proto.CompactTextString(m) } func (*GetWebSessionsResponse) ProtoMessage() {} func (*GetWebSessionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{61} + return fileDescriptor_0ffcffcda38ae159, []int{62} } func (m *GetWebSessionsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4769,7 +4891,7 @@ func (m *GetWebTokenResponse) Reset() { *m = GetWebTokenResponse{} } func (m *GetWebTokenResponse) String() string { return proto.CompactTextString(m) } func (*GetWebTokenResponse) ProtoMessage() {} func (*GetWebTokenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{62} + return fileDescriptor_0ffcffcda38ae159, []int{63} } func (m *GetWebTokenResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4818,7 +4940,7 @@ func (m *GetWebTokensResponse) Reset() { *m = GetWebTokensResponse{} } func (m *GetWebTokensResponse) String() string { return proto.CompactTextString(m) } func (*GetWebTokensResponse) ProtoMessage() {} func (*GetWebTokensResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{63} + return fileDescriptor_0ffcffcda38ae159, []int{64} } func (m *GetWebTokensResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4867,7 +4989,7 @@ func (m *UpsertKubernetesServerRequest) Reset() { *m = UpsertKubernetesS func (m *UpsertKubernetesServerRequest) String() string { return proto.CompactTextString(m) } func (*UpsertKubernetesServerRequest) ProtoMessage() {} func (*UpsertKubernetesServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{64} + return fileDescriptor_0ffcffcda38ae159, []int{65} } func (m *UpsertKubernetesServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4918,7 +5040,7 @@ func (m *DeleteKubernetesServerRequest) Reset() { *m = DeleteKubernetesS func (m *DeleteKubernetesServerRequest) String() string { return proto.CompactTextString(m) } func (*DeleteKubernetesServerRequest) ProtoMessage() {} func (*DeleteKubernetesServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{65} + return fileDescriptor_0ffcffcda38ae159, []int{66} } func (m *DeleteKubernetesServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4972,7 +5094,7 @@ func (m *DeleteAllKubernetesServersRequest) Reset() { *m = DeleteAllKube func (m *DeleteAllKubernetesServersRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllKubernetesServersRequest) ProtoMessage() {} func (*DeleteAllKubernetesServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{66} + return fileDescriptor_0ffcffcda38ae159, []int{67} } func (m *DeleteAllKubernetesServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5014,7 +5136,7 @@ func (m *UpsertDatabaseServerRequest) Reset() { *m = UpsertDatabaseServe func (m *UpsertDatabaseServerRequest) String() string { return proto.CompactTextString(m) } func (*UpsertDatabaseServerRequest) ProtoMessage() {} func (*UpsertDatabaseServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{67} + return fileDescriptor_0ffcffcda38ae159, []int{68} } func (m *UpsertDatabaseServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5067,7 +5189,7 @@ func (m *DeleteDatabaseServerRequest) Reset() { *m = DeleteDatabaseServe func (m *DeleteDatabaseServerRequest) String() string { return proto.CompactTextString(m) } func (*DeleteDatabaseServerRequest) ProtoMessage() {} func (*DeleteDatabaseServerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{68} + return fileDescriptor_0ffcffcda38ae159, []int{69} } func (m *DeleteDatabaseServerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5130,7 +5252,7 @@ func (m *DeleteAllDatabaseServersRequest) Reset() { *m = DeleteAllDataba func (m *DeleteAllDatabaseServersRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllDatabaseServersRequest) ProtoMessage() {} func (*DeleteAllDatabaseServersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{69} + return fileDescriptor_0ffcffcda38ae159, []int{70} } func (m *DeleteAllDatabaseServersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5179,7 +5301,7 @@ func (m *DatabaseServiceV1List) Reset() { *m = DatabaseServiceV1List{} } func (m *DatabaseServiceV1List) String() string { return proto.CompactTextString(m) } func (*DatabaseServiceV1List) ProtoMessage() {} func (*DatabaseServiceV1List) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{70} + return fileDescriptor_0ffcffcda38ae159, []int{71} } func (m *DatabaseServiceV1List) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5228,7 +5350,7 @@ func (m *UpsertDatabaseServiceRequest) Reset() { *m = UpsertDatabaseServ func (m *UpsertDatabaseServiceRequest) String() string { return proto.CompactTextString(m) } func (*UpsertDatabaseServiceRequest) ProtoMessage() {} func (*UpsertDatabaseServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{71} + return fileDescriptor_0ffcffcda38ae159, []int{72} } func (m *UpsertDatabaseServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5275,7 +5397,7 @@ func (m *DeleteAllDatabaseServicesRequest) Reset() { *m = DeleteAllDatab func (m *DeleteAllDatabaseServicesRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllDatabaseServicesRequest) ProtoMessage() {} func (*DeleteAllDatabaseServicesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{72} + return fileDescriptor_0ffcffcda38ae159, []int{73} } func (m *DeleteAllDatabaseServicesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5320,7 +5442,7 @@ func (m *DatabaseCSRRequest) Reset() { *m = DatabaseCSRRequest{} } func (m *DatabaseCSRRequest) String() string { return proto.CompactTextString(m) } func (*DatabaseCSRRequest) ProtoMessage() {} func (*DatabaseCSRRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{73} + return fileDescriptor_0ffcffcda38ae159, []int{74} } func (m *DatabaseCSRRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5378,7 +5500,7 @@ func (m *DatabaseCSRResponse) Reset() { *m = DatabaseCSRResponse{} } func (m *DatabaseCSRResponse) String() string { return proto.CompactTextString(m) } func (*DatabaseCSRResponse) ProtoMessage() {} func (*DatabaseCSRResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{74} + return fileDescriptor_0ffcffcda38ae159, []int{75} } func (m *DatabaseCSRResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5448,7 +5570,7 @@ func (m *DatabaseCertRequest) Reset() { *m = DatabaseCertRequest{} } func (m *DatabaseCertRequest) String() string { return proto.CompactTextString(m) } func (*DatabaseCertRequest) ProtoMessage() {} func (*DatabaseCertRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{75} + return fileDescriptor_0ffcffcda38ae159, []int{76} } func (m *DatabaseCertRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5542,7 +5664,7 @@ func (m *DatabaseCertResponse) Reset() { *m = DatabaseCertResponse{} } func (m *DatabaseCertResponse) String() string { return proto.CompactTextString(m) } func (*DatabaseCertResponse) ProtoMessage() {} func (*DatabaseCertResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{76} + return fileDescriptor_0ffcffcda38ae159, []int{77} } func (m *DatabaseCertResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5598,7 +5720,7 @@ func (m *SnowflakeJWTRequest) Reset() { *m = SnowflakeJWTRequest{} } func (m *SnowflakeJWTRequest) String() string { return proto.CompactTextString(m) } func (*SnowflakeJWTRequest) ProtoMessage() {} func (*SnowflakeJWTRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{77} + return fileDescriptor_0ffcffcda38ae159, []int{78} } func (m *SnowflakeJWTRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5653,7 +5775,7 @@ func (m *SnowflakeJWTResponse) Reset() { *m = SnowflakeJWTResponse{} } func (m *SnowflakeJWTResponse) String() string { return proto.CompactTextString(m) } func (*SnowflakeJWTResponse) ProtoMessage() {} func (*SnowflakeJWTResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{78} + return fileDescriptor_0ffcffcda38ae159, []int{79} } func (m *SnowflakeJWTResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5702,7 +5824,7 @@ func (m *GetRoleRequest) Reset() { *m = GetRoleRequest{} } func (m *GetRoleRequest) String() string { return proto.CompactTextString(m) } func (*GetRoleRequest) ProtoMessage() {} func (*GetRoleRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{79} + return fileDescriptor_0ffcffcda38ae159, []int{80} } func (m *GetRoleRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5751,7 +5873,7 @@ func (m *GetRolesResponse) Reset() { *m = GetRolesResponse{} } func (m *GetRolesResponse) String() string { return proto.CompactTextString(m) } func (*GetRolesResponse) ProtoMessage() {} func (*GetRolesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{80} + return fileDescriptor_0ffcffcda38ae159, []int{81} } func (m *GetRolesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5806,7 +5928,7 @@ func (m *ListRolesRequest) Reset() { *m = ListRolesRequest{} } func (m *ListRolesRequest) String() string { return proto.CompactTextString(m) } func (*ListRolesRequest) ProtoMessage() {} func (*ListRolesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{81} + return fileDescriptor_0ffcffcda38ae159, []int{82} } func (m *ListRolesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5871,7 +5993,7 @@ func (m *ListRolesResponse) Reset() { *m = ListRolesResponse{} } func (m *ListRolesResponse) String() string { return proto.CompactTextString(m) } func (*ListRolesResponse) ProtoMessage() {} func (*ListRolesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{82} + return fileDescriptor_0ffcffcda38ae159, []int{83} } func (m *ListRolesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5927,7 +6049,7 @@ func (m *CreateRoleRequest) Reset() { *m = CreateRoleRequest{} } func (m *CreateRoleRequest) String() string { return proto.CompactTextString(m) } func (*CreateRoleRequest) ProtoMessage() {} func (*CreateRoleRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{83} + return fileDescriptor_0ffcffcda38ae159, []int{84} } func (m *CreateRoleRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5976,7 +6098,7 @@ func (m *UpdateRoleRequest) Reset() { *m = UpdateRoleRequest{} } func (m *UpdateRoleRequest) String() string { return proto.CompactTextString(m) } func (*UpdateRoleRequest) ProtoMessage() {} func (*UpdateRoleRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{84} + return fileDescriptor_0ffcffcda38ae159, []int{85} } func (m *UpdateRoleRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6025,7 +6147,7 @@ func (m *UpsertRoleRequest) Reset() { *m = UpsertRoleRequest{} } func (m *UpsertRoleRequest) String() string { return proto.CompactTextString(m) } func (*UpsertRoleRequest) ProtoMessage() {} func (*UpsertRoleRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{85} + return fileDescriptor_0ffcffcda38ae159, []int{86} } func (m *UpsertRoleRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6074,7 +6196,7 @@ func (m *DeleteRoleRequest) Reset() { *m = DeleteRoleRequest{} } func (m *DeleteRoleRequest) String() string { return proto.CompactTextString(m) } func (*DeleteRoleRequest) ProtoMessage() {} func (*DeleteRoleRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{86} + return fileDescriptor_0ffcffcda38ae159, []int{87} } func (m *DeleteRoleRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6139,7 +6261,7 @@ func (m *MFAAuthenticateChallenge) Reset() { *m = MFAAuthenticateChallen func (m *MFAAuthenticateChallenge) String() string { return proto.CompactTextString(m) } func (*MFAAuthenticateChallenge) ProtoMessage() {} func (*MFAAuthenticateChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{87} + return fileDescriptor_0ffcffcda38ae159, []int{88} } func (m *MFAAuthenticateChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6205,7 +6327,7 @@ func (m *MFAAuthenticateResponse) Reset() { *m = MFAAuthenticateResponse func (m *MFAAuthenticateResponse) String() string { return proto.CompactTextString(m) } func (*MFAAuthenticateResponse) ProtoMessage() {} func (*MFAAuthenticateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{88} + return fileDescriptor_0ffcffcda38ae159, []int{89} } func (m *MFAAuthenticateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6290,7 +6412,7 @@ func (m *TOTPChallenge) Reset() { *m = TOTPChallenge{} } func (m *TOTPChallenge) String() string { return proto.CompactTextString(m) } func (*TOTPChallenge) ProtoMessage() {} func (*TOTPChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{89} + return fileDescriptor_0ffcffcda38ae159, []int{90} } func (m *TOTPChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6331,7 +6453,7 @@ func (m *TOTPResponse) Reset() { *m = TOTPResponse{} } func (m *TOTPResponse) String() string { return proto.CompactTextString(m) } func (*TOTPResponse) ProtoMessage() {} func (*TOTPResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{90} + return fileDescriptor_0ffcffcda38ae159, []int{91} } func (m *TOTPResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6384,7 +6506,7 @@ func (m *MFARegisterChallenge) Reset() { *m = MFARegisterChallenge{} } func (m *MFARegisterChallenge) String() string { return proto.CompactTextString(m) } func (*MFARegisterChallenge) ProtoMessage() {} func (*MFARegisterChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{91} + return fileDescriptor_0ffcffcda38ae159, []int{92} } func (m *MFARegisterChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6473,7 +6595,7 @@ func (m *MFARegisterResponse) Reset() { *m = MFARegisterResponse{} } func (m *MFARegisterResponse) String() string { return proto.CompactTextString(m) } func (*MFARegisterResponse) ProtoMessage() {} func (*MFARegisterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{92} + return fileDescriptor_0ffcffcda38ae159, []int{93} } func (m *MFARegisterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6576,7 +6698,7 @@ func (m *TOTPRegisterChallenge) Reset() { *m = TOTPRegisterChallenge{} } func (m *TOTPRegisterChallenge) String() string { return proto.CompactTextString(m) } func (*TOTPRegisterChallenge) ProtoMessage() {} func (*TOTPRegisterChallenge) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{93} + return fileDescriptor_0ffcffcda38ae159, []int{94} } func (m *TOTPRegisterChallenge) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6675,7 +6797,7 @@ func (m *TOTPRegisterResponse) Reset() { *m = TOTPRegisterResponse{} } func (m *TOTPRegisterResponse) String() string { return proto.CompactTextString(m) } func (*TOTPRegisterResponse) ProtoMessage() {} func (*TOTPRegisterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{94} + return fileDescriptor_0ffcffcda38ae159, []int{95} } func (m *TOTPRegisterResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6729,7 +6851,7 @@ func (m *AddMFADeviceRequest) Reset() { *m = AddMFADeviceRequest{} } func (m *AddMFADeviceRequest) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceRequest) ProtoMessage() {} func (*AddMFADeviceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{95} + return fileDescriptor_0ffcffcda38ae159, []int{96} } func (m *AddMFADeviceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6769,7 +6891,7 @@ func (m *AddMFADeviceResponse) Reset() { *m = AddMFADeviceResponse{} } func (m *AddMFADeviceResponse) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceResponse) ProtoMessage() {} func (*AddMFADeviceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{96} + return fileDescriptor_0ffcffcda38ae159, []int{97} } func (m *AddMFADeviceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6809,7 +6931,7 @@ func (m *DeleteMFADeviceRequest) Reset() { *m = DeleteMFADeviceRequest{} func (m *DeleteMFADeviceRequest) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceRequest) ProtoMessage() {} func (*DeleteMFADeviceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{97} + return fileDescriptor_0ffcffcda38ae159, []int{98} } func (m *DeleteMFADeviceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6849,7 +6971,7 @@ func (m *DeleteMFADeviceResponse) Reset() { *m = DeleteMFADeviceResponse func (m *DeleteMFADeviceResponse) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceResponse) ProtoMessage() {} func (*DeleteMFADeviceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{98} + return fileDescriptor_0ffcffcda38ae159, []int{99} } func (m *DeleteMFADeviceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6904,7 +7026,7 @@ func (m *DeleteMFADeviceSyncRequest) Reset() { *m = DeleteMFADeviceSyncR func (m *DeleteMFADeviceSyncRequest) String() string { return proto.CompactTextString(m) } func (*DeleteMFADeviceSyncRequest) ProtoMessage() {} func (*DeleteMFADeviceSyncRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{99} + return fileDescriptor_0ffcffcda38ae159, []int{100} } func (m *DeleteMFADeviceSyncRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6984,7 +7106,7 @@ func (m *AddMFADeviceSyncRequest) Reset() { *m = AddMFADeviceSyncRequest func (m *AddMFADeviceSyncRequest) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceSyncRequest) ProtoMessage() {} func (*AddMFADeviceSyncRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{100} + return fileDescriptor_0ffcffcda38ae159, []int{101} } func (m *AddMFADeviceSyncRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7060,7 +7182,7 @@ func (m *AddMFADeviceSyncResponse) Reset() { *m = AddMFADeviceSyncRespon func (m *AddMFADeviceSyncResponse) String() string { return proto.CompactTextString(m) } func (*AddMFADeviceSyncResponse) ProtoMessage() {} func (*AddMFADeviceSyncResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{101} + return fileDescriptor_0ffcffcda38ae159, []int{102} } func (m *AddMFADeviceSyncResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7115,7 +7237,7 @@ func (m *GetMFADevicesRequest) Reset() { *m = GetMFADevicesRequest{} } func (m *GetMFADevicesRequest) String() string { return proto.CompactTextString(m) } func (*GetMFADevicesRequest) ProtoMessage() {} func (*GetMFADevicesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{102} + return fileDescriptor_0ffcffcda38ae159, []int{103} } func (m *GetMFADevicesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7163,7 +7285,7 @@ func (m *GetMFADevicesResponse) Reset() { *m = GetMFADevicesResponse{} } func (m *GetMFADevicesResponse) String() string { return proto.CompactTextString(m) } func (*GetMFADevicesResponse) ProtoMessage() {} func (*GetMFADevicesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{103} + return fileDescriptor_0ffcffcda38ae159, []int{104} } func (m *GetMFADevicesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7210,7 +7332,7 @@ func (m *UserSingleUseCertsRequest) Reset() { *m = UserSingleUseCertsReq func (m *UserSingleUseCertsRequest) String() string { return proto.CompactTextString(m) } func (*UserSingleUseCertsRequest) ProtoMessage() {} func (*UserSingleUseCertsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{104} + return fileDescriptor_0ffcffcda38ae159, []int{105} } func (m *UserSingleUseCertsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7250,7 +7372,7 @@ func (m *UserSingleUseCertsResponse) Reset() { *m = UserSingleUseCertsRe func (m *UserSingleUseCertsResponse) String() string { return proto.CompactTextString(m) } func (*UserSingleUseCertsResponse) ProtoMessage() {} func (*UserSingleUseCertsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{105} + return fileDescriptor_0ffcffcda38ae159, []int{106} } func (m *UserSingleUseCertsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7299,7 +7421,7 @@ func (m *IsMFARequiredRequest) Reset() { *m = IsMFARequiredRequest{} } func (m *IsMFARequiredRequest) String() string { return proto.CompactTextString(m) } func (*IsMFARequiredRequest) ProtoMessage() {} func (*IsMFARequiredRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{106} + return fileDescriptor_0ffcffcda38ae159, []int{107} } func (m *IsMFARequiredRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7437,7 +7559,7 @@ func (m *StreamSessionEventsRequest) Reset() { *m = StreamSessionEventsR func (m *StreamSessionEventsRequest) String() string { return proto.CompactTextString(m) } func (*StreamSessionEventsRequest) ProtoMessage() {} func (*StreamSessionEventsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{107} + return fileDescriptor_0ffcffcda38ae159, []int{108} } func (m *StreamSessionEventsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7495,7 +7617,7 @@ func (m *NodeLogin) Reset() { *m = NodeLogin{} } func (m *NodeLogin) String() string { return proto.CompactTextString(m) } func (*NodeLogin) ProtoMessage() {} func (*NodeLogin) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{108} + return fileDescriptor_0ffcffcda38ae159, []int{109} } func (m *NodeLogin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7549,7 +7671,7 @@ func (m *AdminAction) Reset() { *m = AdminAction{} } func (m *AdminAction) String() string { return proto.CompactTextString(m) } func (*AdminAction) ProtoMessage() {} func (*AdminAction) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{109} + return fileDescriptor_0ffcffcda38ae159, []int{110} } func (m *AdminAction) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7594,7 +7716,7 @@ func (m *IsMFARequiredResponse) Reset() { *m = IsMFARequiredResponse{} } func (m *IsMFARequiredResponse) String() string { return proto.CompactTextString(m) } func (*IsMFARequiredResponse) ProtoMessage() {} func (*IsMFARequiredResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{110} + return fileDescriptor_0ffcffcda38ae159, []int{111} } func (m *IsMFARequiredResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7664,7 +7786,7 @@ func (m *GetEventsRequest) Reset() { *m = GetEventsRequest{} } func (m *GetEventsRequest) String() string { return proto.CompactTextString(m) } func (*GetEventsRequest) ProtoMessage() {} func (*GetEventsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{111} + return fileDescriptor_0ffcffcda38ae159, []int{112} } func (m *GetEventsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7765,7 +7887,7 @@ func (m *GetSessionEventsRequest) Reset() { *m = GetSessionEventsRequest func (m *GetSessionEventsRequest) String() string { return proto.CompactTextString(m) } func (*GetSessionEventsRequest) ProtoMessage() {} func (*GetSessionEventsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{112} + return fileDescriptor_0ffcffcda38ae159, []int{113} } func (m *GetSessionEventsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7845,7 +7967,7 @@ func (m *Events) Reset() { *m = Events{} } func (m *Events) String() string { return proto.CompactTextString(m) } func (*Events) ProtoMessage() {} func (*Events) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{113} + return fileDescriptor_0ffcffcda38ae159, []int{114} } func (m *Events) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7903,7 +8025,7 @@ func (m *GetLocksRequest) Reset() { *m = GetLocksRequest{} } func (m *GetLocksRequest) String() string { return proto.CompactTextString(m) } func (*GetLocksRequest) ProtoMessage() {} func (*GetLocksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{114} + return fileDescriptor_0ffcffcda38ae159, []int{115} } func (m *GetLocksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -7958,7 +8080,7 @@ func (m *GetLocksResponse) Reset() { *m = GetLocksResponse{} } func (m *GetLocksResponse) String() string { return proto.CompactTextString(m) } func (*GetLocksResponse) ProtoMessage() {} func (*GetLocksResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{115} + return fileDescriptor_0ffcffcda38ae159, []int{116} } func (m *GetLocksResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8006,7 +8128,7 @@ func (m *GetLockRequest) Reset() { *m = GetLockRequest{} } func (m *GetLockRequest) String() string { return proto.CompactTextString(m) } func (*GetLockRequest) ProtoMessage() {} func (*GetLockRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{116} + return fileDescriptor_0ffcffcda38ae159, []int{117} } func (m *GetLockRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8054,7 +8176,7 @@ func (m *DeleteLockRequest) Reset() { *m = DeleteLockRequest{} } func (m *DeleteLockRequest) String() string { return proto.CompactTextString(m) } func (*DeleteLockRequest) ProtoMessage() {} func (*DeleteLockRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{117} + return fileDescriptor_0ffcffcda38ae159, []int{118} } func (m *DeleteLockRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8104,7 +8226,7 @@ func (m *ReplaceRemoteLocksRequest) Reset() { *m = ReplaceRemoteLocksReq func (m *ReplaceRemoteLocksRequest) String() string { return proto.CompactTextString(m) } func (*ReplaceRemoteLocksRequest) ProtoMessage() {} func (*ReplaceRemoteLocksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{118} + return fileDescriptor_0ffcffcda38ae159, []int{119} } func (m *ReplaceRemoteLocksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8160,7 +8282,7 @@ func (m *GetWindowsDesktopServicesResponse) Reset() { *m = GetWindowsDes func (m *GetWindowsDesktopServicesResponse) String() string { return proto.CompactTextString(m) } func (*GetWindowsDesktopServicesResponse) ProtoMessage() {} func (*GetWindowsDesktopServicesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{119} + return fileDescriptor_0ffcffcda38ae159, []int{120} } func (m *GetWindowsDesktopServicesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8209,7 +8331,7 @@ func (m *GetWindowsDesktopServiceRequest) Reset() { *m = GetWindowsDeskt func (m *GetWindowsDesktopServiceRequest) String() string { return proto.CompactTextString(m) } func (*GetWindowsDesktopServiceRequest) ProtoMessage() {} func (*GetWindowsDesktopServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{120} + return fileDescriptor_0ffcffcda38ae159, []int{121} } func (m *GetWindowsDesktopServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8258,7 +8380,7 @@ func (m *GetWindowsDesktopServiceResponse) Reset() { *m = GetWindowsDesk func (m *GetWindowsDesktopServiceResponse) String() string { return proto.CompactTextString(m) } func (*GetWindowsDesktopServiceResponse) ProtoMessage() {} func (*GetWindowsDesktopServiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{121} + return fileDescriptor_0ffcffcda38ae159, []int{122} } func (m *GetWindowsDesktopServiceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8307,7 +8429,7 @@ func (m *DeleteWindowsDesktopServiceRequest) Reset() { *m = DeleteWindow func (m *DeleteWindowsDesktopServiceRequest) String() string { return proto.CompactTextString(m) } func (*DeleteWindowsDesktopServiceRequest) ProtoMessage() {} func (*DeleteWindowsDesktopServiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{122} + return fileDescriptor_0ffcffcda38ae159, []int{123} } func (m *DeleteWindowsDesktopServiceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8356,7 +8478,7 @@ func (m *GetWindowsDesktopsResponse) Reset() { *m = GetWindowsDesktopsRe func (m *GetWindowsDesktopsResponse) String() string { return proto.CompactTextString(m) } func (*GetWindowsDesktopsResponse) ProtoMessage() {} func (*GetWindowsDesktopsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{123} + return fileDescriptor_0ffcffcda38ae159, []int{124} } func (m *GetWindowsDesktopsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8409,7 +8531,7 @@ func (m *DeleteWindowsDesktopRequest) Reset() { *m = DeleteWindowsDeskto func (m *DeleteWindowsDesktopRequest) String() string { return proto.CompactTextString(m) } func (*DeleteWindowsDesktopRequest) ProtoMessage() {} func (*DeleteWindowsDesktopRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{124} + return fileDescriptor_0ffcffcda38ae159, []int{125} } func (m *DeleteWindowsDesktopRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8470,7 +8592,7 @@ func (m *WindowsDesktopCertRequest) Reset() { *m = WindowsDesktopCertReq func (m *WindowsDesktopCertRequest) String() string { return proto.CompactTextString(m) } func (*WindowsDesktopCertRequest) ProtoMessage() {} func (*WindowsDesktopCertRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{125} + return fileDescriptor_0ffcffcda38ae159, []int{126} } func (m *WindowsDesktopCertRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8533,7 +8655,7 @@ func (m *WindowsDesktopCertResponse) Reset() { *m = WindowsDesktopCertRe func (m *WindowsDesktopCertResponse) String() string { return proto.CompactTextString(m) } func (*WindowsDesktopCertResponse) ProtoMessage() {} func (*WindowsDesktopCertResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{126} + return fileDescriptor_0ffcffcda38ae159, []int{127} } func (m *WindowsDesktopCertResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8582,7 +8704,7 @@ func (m *DesktopBootstrapScriptResponse) Reset() { *m = DesktopBootstrap func (m *DesktopBootstrapScriptResponse) String() string { return proto.CompactTextString(m) } func (*DesktopBootstrapScriptResponse) ProtoMessage() {} func (*DesktopBootstrapScriptResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{127} + return fileDescriptor_0ffcffcda38ae159, []int{128} } func (m *DesktopBootstrapScriptResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8633,7 +8755,7 @@ func (m *ListSAMLIdPServiceProvidersRequest) Reset() { *m = ListSAMLIdPS func (m *ListSAMLIdPServiceProvidersRequest) String() string { return proto.CompactTextString(m) } func (*ListSAMLIdPServiceProvidersRequest) ProtoMessage() {} func (*ListSAMLIdPServiceProvidersRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{128} + return fileDescriptor_0ffcffcda38ae159, []int{129} } func (m *ListSAMLIdPServiceProvidersRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8693,7 +8815,7 @@ func (m *ListSAMLIdPServiceProvidersResponse) Reset() { *m = ListSAMLIdP func (m *ListSAMLIdPServiceProvidersResponse) String() string { return proto.CompactTextString(m) } func (*ListSAMLIdPServiceProvidersResponse) ProtoMessage() {} func (*ListSAMLIdPServiceProvidersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{129} + return fileDescriptor_0ffcffcda38ae159, []int{130} } func (m *ListSAMLIdPServiceProvidersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8756,7 +8878,7 @@ func (m *GetSAMLIdPServiceProviderRequest) Reset() { *m = GetSAMLIdPServ func (m *GetSAMLIdPServiceProviderRequest) String() string { return proto.CompactTextString(m) } func (*GetSAMLIdPServiceProviderRequest) ProtoMessage() {} func (*GetSAMLIdPServiceProviderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{130} + return fileDescriptor_0ffcffcda38ae159, []int{131} } func (m *GetSAMLIdPServiceProviderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8805,7 +8927,7 @@ func (m *DeleteSAMLIdPServiceProviderRequest) Reset() { *m = DeleteSAMLI func (m *DeleteSAMLIdPServiceProviderRequest) String() string { return proto.CompactTextString(m) } func (*DeleteSAMLIdPServiceProviderRequest) ProtoMessage() {} func (*DeleteSAMLIdPServiceProviderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{131} + return fileDescriptor_0ffcffcda38ae159, []int{132} } func (m *DeleteSAMLIdPServiceProviderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8856,7 +8978,7 @@ func (m *ListUserGroupsRequest) Reset() { *m = ListUserGroupsRequest{} } func (m *ListUserGroupsRequest) String() string { return proto.CompactTextString(m) } func (*ListUserGroupsRequest) ProtoMessage() {} func (*ListUserGroupsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{132} + return fileDescriptor_0ffcffcda38ae159, []int{133} } func (m *ListUserGroupsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8916,7 +9038,7 @@ func (m *ListUserGroupsResponse) Reset() { *m = ListUserGroupsResponse{} func (m *ListUserGroupsResponse) String() string { return proto.CompactTextString(m) } func (*ListUserGroupsResponse) ProtoMessage() {} func (*ListUserGroupsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{133} + return fileDescriptor_0ffcffcda38ae159, []int{134} } func (m *ListUserGroupsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -8979,7 +9101,7 @@ func (m *GetUserGroupRequest) Reset() { *m = GetUserGroupRequest{} } func (m *GetUserGroupRequest) String() string { return proto.CompactTextString(m) } func (*GetUserGroupRequest) ProtoMessage() {} func (*GetUserGroupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{134} + return fileDescriptor_0ffcffcda38ae159, []int{135} } func (m *GetUserGroupRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9028,7 +9150,7 @@ func (m *DeleteUserGroupRequest) Reset() { *m = DeleteUserGroupRequest{} func (m *DeleteUserGroupRequest) String() string { return proto.CompactTextString(m) } func (*DeleteUserGroupRequest) ProtoMessage() {} func (*DeleteUserGroupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{135} + return fileDescriptor_0ffcffcda38ae159, []int{136} } func (m *DeleteUserGroupRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9077,7 +9199,7 @@ func (m *CertAuthorityRequest) Reset() { *m = CertAuthorityRequest{} } func (m *CertAuthorityRequest) String() string { return proto.CompactTextString(m) } func (*CertAuthorityRequest) ProtoMessage() {} func (*CertAuthorityRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{136} + return fileDescriptor_0ffcffcda38ae159, []int{137} } func (m *CertAuthorityRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9126,7 +9248,7 @@ func (m *CRL) Reset() { *m = CRL{} } func (m *CRL) String() string { return proto.CompactTextString(m) } func (*CRL) ProtoMessage() {} func (*CRL) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{137} + return fileDescriptor_0ffcffcda38ae159, []int{138} } func (m *CRL) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9196,7 +9318,7 @@ func (m *ChangeUserAuthenticationRequest) Reset() { *m = ChangeUserAuthe func (m *ChangeUserAuthenticationRequest) String() string { return proto.CompactTextString(m) } func (*ChangeUserAuthenticationRequest) ProtoMessage() {} func (*ChangeUserAuthenticationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{138} + return fileDescriptor_0ffcffcda38ae159, []int{139} } func (m *ChangeUserAuthenticationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9282,7 +9404,7 @@ func (m *ChangeUserAuthenticationResponse) Reset() { *m = ChangeUserAuth func (m *ChangeUserAuthenticationResponse) String() string { return proto.CompactTextString(m) } func (*ChangeUserAuthenticationResponse) ProtoMessage() {} func (*ChangeUserAuthenticationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{139} + return fileDescriptor_0ffcffcda38ae159, []int{140} } func (m *ChangeUserAuthenticationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9355,7 +9477,7 @@ func (m *StartAccountRecoveryRequest) Reset() { *m = StartAccountRecover func (m *StartAccountRecoveryRequest) String() string { return proto.CompactTextString(m) } func (*StartAccountRecoveryRequest) ProtoMessage() {} func (*StartAccountRecoveryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{140} + return fileDescriptor_0ffcffcda38ae159, []int{141} } func (m *StartAccountRecoveryRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9430,7 +9552,7 @@ func (m *VerifyAccountRecoveryRequest) Reset() { *m = VerifyAccountRecov func (m *VerifyAccountRecoveryRequest) String() string { return proto.CompactTextString(m) } func (*VerifyAccountRecoveryRequest) ProtoMessage() {} func (*VerifyAccountRecoveryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{141} + return fileDescriptor_0ffcffcda38ae159, []int{142} } func (m *VerifyAccountRecoveryRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9545,7 +9667,7 @@ func (m *CompleteAccountRecoveryRequest) Reset() { *m = CompleteAccountR func (m *CompleteAccountRecoveryRequest) String() string { return proto.CompactTextString(m) } func (*CompleteAccountRecoveryRequest) ProtoMessage() {} func (*CompleteAccountRecoveryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{142} + return fileDescriptor_0ffcffcda38ae159, []int{143} } func (m *CompleteAccountRecoveryRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9651,7 +9773,7 @@ func (m *RecoveryCodes) Reset() { *m = RecoveryCodes{} } func (m *RecoveryCodes) String() string { return proto.CompactTextString(m) } func (*RecoveryCodes) ProtoMessage() {} func (*RecoveryCodes) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{143} + return fileDescriptor_0ffcffcda38ae159, []int{144} } func (m *RecoveryCodes) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9714,7 +9836,7 @@ func (m *CreateAccountRecoveryCodesRequest) Reset() { *m = CreateAccount func (m *CreateAccountRecoveryCodesRequest) String() string { return proto.CompactTextString(m) } func (*CreateAccountRecoveryCodesRequest) ProtoMessage() {} func (*CreateAccountRecoveryCodesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{144} + return fileDescriptor_0ffcffcda38ae159, []int{145} } func (m *CreateAccountRecoveryCodesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9765,7 +9887,7 @@ func (m *GetAccountRecoveryTokenRequest) Reset() { *m = GetAccountRecove func (m *GetAccountRecoveryTokenRequest) String() string { return proto.CompactTextString(m) } func (*GetAccountRecoveryTokenRequest) ProtoMessage() {} func (*GetAccountRecoveryTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{145} + return fileDescriptor_0ffcffcda38ae159, []int{146} } func (m *GetAccountRecoveryTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9813,7 +9935,7 @@ func (m *GetAccountRecoveryCodesRequest) Reset() { *m = GetAccountRecove func (m *GetAccountRecoveryCodesRequest) String() string { return proto.CompactTextString(m) } func (*GetAccountRecoveryCodesRequest) ProtoMessage() {} func (*GetAccountRecoveryCodesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{146} + return fileDescriptor_0ffcffcda38ae159, []int{147} } func (m *GetAccountRecoveryCodesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9855,7 +9977,7 @@ func (m *UserCredentials) Reset() { *m = UserCredentials{} } func (m *UserCredentials) String() string { return proto.CompactTextString(m) } func (*UserCredentials) ProtoMessage() {} func (*UserCredentials) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{147} + return fileDescriptor_0ffcffcda38ae159, []int{148} } func (m *UserCredentials) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9909,7 +10031,7 @@ func (m *ContextUser) Reset() { *m = ContextUser{} } func (m *ContextUser) String() string { return proto.CompactTextString(m) } func (*ContextUser) ProtoMessage() {} func (*ContextUser) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{148} + return fileDescriptor_0ffcffcda38ae159, []int{149} } func (m *ContextUser) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -9949,7 +10071,7 @@ func (m *Passwordless) Reset() { *m = Passwordless{} } func (m *Passwordless) String() string { return proto.CompactTextString(m) } func (*Passwordless) ProtoMessage() {} func (*Passwordless) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{149} + return fileDescriptor_0ffcffcda38ae159, []int{150} } func (m *Passwordless) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10013,7 +10135,7 @@ func (m *CreateAuthenticateChallengeRequest) Reset() { *m = CreateAuthen func (m *CreateAuthenticateChallengeRequest) String() string { return proto.CompactTextString(m) } func (*CreateAuthenticateChallengeRequest) ProtoMessage() {} func (*CreateAuthenticateChallengeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{150} + return fileDescriptor_0ffcffcda38ae159, []int{151} } func (m *CreateAuthenticateChallengeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10147,7 +10269,7 @@ func (m *CreatePrivilegeTokenRequest) Reset() { *m = CreatePrivilegeToke func (m *CreatePrivilegeTokenRequest) String() string { return proto.CompactTextString(m) } func (*CreatePrivilegeTokenRequest) ProtoMessage() {} func (*CreatePrivilegeTokenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{151} + return fileDescriptor_0ffcffcda38ae159, []int{152} } func (m *CreatePrivilegeTokenRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10216,7 +10338,7 @@ func (m *CreateRegisterChallengeRequest) Reset() { *m = CreateRegisterCh func (m *CreateRegisterChallengeRequest) String() string { return proto.CompactTextString(m) } func (*CreateRegisterChallengeRequest) ProtoMessage() {} func (*CreateRegisterChallengeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{152} + return fileDescriptor_0ffcffcda38ae159, []int{153} } func (m *CreateRegisterChallengeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10304,7 +10426,7 @@ func (m *PaginatedResource) Reset() { *m = PaginatedResource{} } func (m *PaginatedResource) String() string { return proto.CompactTextString(m) } func (*PaginatedResource) ProtoMessage() {} func (*PaginatedResource) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{153} + return fileDescriptor_0ffcffcda38ae159, []int{154} } func (m *PaginatedResource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10545,7 +10667,7 @@ func (m *ListUnifiedResourcesRequest) Reset() { *m = ListUnifiedResource func (m *ListUnifiedResourcesRequest) String() string { return proto.CompactTextString(m) } func (*ListUnifiedResourcesRequest) ProtoMessage() {} func (*ListUnifiedResourcesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{154} + return fileDescriptor_0ffcffcda38ae159, []int{155} } func (m *ListUnifiedResourcesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10682,7 +10804,7 @@ func (m *ListUnifiedResourcesResponse) Reset() { *m = ListUnifiedResourc func (m *ListUnifiedResourcesResponse) String() string { return proto.CompactTextString(m) } func (*ListUnifiedResourcesResponse) ProtoMessage() {} func (*ListUnifiedResourcesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{155} + return fileDescriptor_0ffcffcda38ae159, []int{156} } func (m *ListUnifiedResourcesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10778,7 +10900,7 @@ func (m *ListResourcesRequest) Reset() { *m = ListResourcesRequest{} } func (m *ListResourcesRequest) String() string { return proto.CompactTextString(m) } func (*ListResourcesRequest) ProtoMessage() {} func (*ListResourcesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{156} + return fileDescriptor_0ffcffcda38ae159, []int{157} } func (m *ListResourcesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10914,7 +11036,7 @@ func (m *GetSSHTargetsRequest) Reset() { *m = GetSSHTargetsRequest{} } func (m *GetSSHTargetsRequest) String() string { return proto.CompactTextString(m) } func (*GetSSHTargetsRequest) ProtoMessage() {} func (*GetSSHTargetsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{157} + return fileDescriptor_0ffcffcda38ae159, []int{158} } func (m *GetSSHTargetsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -10970,7 +11092,7 @@ func (m *GetSSHTargetsResponse) Reset() { *m = GetSSHTargetsResponse{} } func (m *GetSSHTargetsResponse) String() string { return proto.CompactTextString(m) } func (*GetSSHTargetsResponse) ProtoMessage() {} func (*GetSSHTargetsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{158} + return fileDescriptor_0ffcffcda38ae159, []int{159} } func (m *GetSSHTargetsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11025,7 +11147,7 @@ func (m *ListResourcesResponse) Reset() { *m = ListResourcesResponse{} } func (m *ListResourcesResponse) String() string { return proto.CompactTextString(m) } func (*ListResourcesResponse) ProtoMessage() {} func (*ListResourcesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{159} + return fileDescriptor_0ffcffcda38ae159, []int{160} } func (m *ListResourcesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11090,7 +11212,7 @@ func (m *CreateSessionTrackerRequest) Reset() { *m = CreateSessionTracke func (m *CreateSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*CreateSessionTrackerRequest) ProtoMessage() {} func (*CreateSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{160} + return fileDescriptor_0ffcffcda38ae159, []int{161} } func (m *CreateSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11139,7 +11261,7 @@ func (m *GetSessionTrackerRequest) Reset() { *m = GetSessionTrackerReque func (m *GetSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*GetSessionTrackerRequest) ProtoMessage() {} func (*GetSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{161} + return fileDescriptor_0ffcffcda38ae159, []int{162} } func (m *GetSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11188,7 +11310,7 @@ func (m *RemoveSessionTrackerRequest) Reset() { *m = RemoveSessionTracke func (m *RemoveSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*RemoveSessionTrackerRequest) ProtoMessage() {} func (*RemoveSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{162} + return fileDescriptor_0ffcffcda38ae159, []int{163} } func (m *RemoveSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11236,7 +11358,7 @@ func (m *SessionTrackerUpdateState) Reset() { *m = SessionTrackerUpdateS func (m *SessionTrackerUpdateState) String() string { return proto.CompactTextString(m) } func (*SessionTrackerUpdateState) ProtoMessage() {} func (*SessionTrackerUpdateState) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{163} + return fileDescriptor_0ffcffcda38ae159, []int{164} } func (m *SessionTrackerUpdateState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11284,7 +11406,7 @@ func (m *SessionTrackerAddParticipant) Reset() { *m = SessionTrackerAddP func (m *SessionTrackerAddParticipant) String() string { return proto.CompactTextString(m) } func (*SessionTrackerAddParticipant) ProtoMessage() {} func (*SessionTrackerAddParticipant) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{164} + return fileDescriptor_0ffcffcda38ae159, []int{165} } func (m *SessionTrackerAddParticipant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11332,7 +11454,7 @@ func (m *SessionTrackerRemoveParticipant) Reset() { *m = SessionTrackerR func (m *SessionTrackerRemoveParticipant) String() string { return proto.CompactTextString(m) } func (*SessionTrackerRemoveParticipant) ProtoMessage() {} func (*SessionTrackerRemoveParticipant) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{165} + return fileDescriptor_0ffcffcda38ae159, []int{166} } func (m *SessionTrackerRemoveParticipant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11381,7 +11503,7 @@ func (m *SessionTrackerUpdateExpiry) Reset() { *m = SessionTrackerUpdate func (m *SessionTrackerUpdateExpiry) String() string { return proto.CompactTextString(m) } func (*SessionTrackerUpdateExpiry) ProtoMessage() {} func (*SessionTrackerUpdateExpiry) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{166} + return fileDescriptor_0ffcffcda38ae159, []int{167} } func (m *SessionTrackerUpdateExpiry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11436,7 +11558,7 @@ func (m *UpdateSessionTrackerRequest) Reset() { *m = UpdateSessionTracke func (m *UpdateSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*UpdateSessionTrackerRequest) ProtoMessage() {} func (*UpdateSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{167} + return fileDescriptor_0ffcffcda38ae159, []int{168} } func (m *UpdateSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11554,7 +11676,7 @@ func (m *PresenceMFAChallengeRequest) Reset() { *m = PresenceMFAChalleng func (m *PresenceMFAChallengeRequest) String() string { return proto.CompactTextString(m) } func (*PresenceMFAChallengeRequest) ProtoMessage() {} func (*PresenceMFAChallengeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{168} + return fileDescriptor_0ffcffcda38ae159, []int{169} } func (m *PresenceMFAChallengeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11605,7 +11727,7 @@ func (m *PresenceMFAChallengeSend) Reset() { *m = PresenceMFAChallengeSe func (m *PresenceMFAChallengeSend) String() string { return proto.CompactTextString(m) } func (*PresenceMFAChallengeSend) ProtoMessage() {} func (*PresenceMFAChallengeSend) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{169} + return fileDescriptor_0ffcffcda38ae159, []int{170} } func (m *PresenceMFAChallengeSend) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11692,7 +11814,7 @@ func (m *GetDomainNameResponse) Reset() { *m = GetDomainNameResponse{} } func (m *GetDomainNameResponse) String() string { return proto.CompactTextString(m) } func (*GetDomainNameResponse) ProtoMessage() {} func (*GetDomainNameResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{170} + return fileDescriptor_0ffcffcda38ae159, []int{171} } func (m *GetDomainNameResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11741,7 +11863,7 @@ func (m *GetClusterCACertResponse) Reset() { *m = GetClusterCACertRespon func (m *GetClusterCACertResponse) String() string { return proto.CompactTextString(m) } func (*GetClusterCACertResponse) ProtoMessage() {} func (*GetClusterCACertResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{171} + return fileDescriptor_0ffcffcda38ae159, []int{172} } func (m *GetClusterCACertResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11789,7 +11911,7 @@ func (m *GetLicenseResponse) Reset() { *m = GetLicenseResponse{} } func (m *GetLicenseResponse) String() string { return proto.CompactTextString(m) } func (*GetLicenseResponse) ProtoMessage() {} func (*GetLicenseResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{172} + return fileDescriptor_0ffcffcda38ae159, []int{173} } func (m *GetLicenseResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11837,7 +11959,7 @@ func (m *ListReleasesResponse) Reset() { *m = ListReleasesResponse{} } func (m *ListReleasesResponse) String() string { return proto.CompactTextString(m) } func (*ListReleasesResponse) ProtoMessage() {} func (*ListReleasesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{173} + return fileDescriptor_0ffcffcda38ae159, []int{174} } func (m *ListReleasesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11886,7 +12008,7 @@ func (m *GetOIDCAuthRequestRequest) Reset() { *m = GetOIDCAuthRequestReq func (m *GetOIDCAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetOIDCAuthRequestRequest) ProtoMessage() {} func (*GetOIDCAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{174} + return fileDescriptor_0ffcffcda38ae159, []int{175} } func (m *GetOIDCAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11935,7 +12057,7 @@ func (m *GetSAMLAuthRequestRequest) Reset() { *m = GetSAMLAuthRequestReq func (m *GetSAMLAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetSAMLAuthRequestRequest) ProtoMessage() {} func (*GetSAMLAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{175} + return fileDescriptor_0ffcffcda38ae159, []int{176} } func (m *GetSAMLAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11984,7 +12106,7 @@ func (m *GetGithubAuthRequestRequest) Reset() { *m = GetGithubAuthReques func (m *GetGithubAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetGithubAuthRequestRequest) ProtoMessage() {} func (*GetGithubAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{176} + return fileDescriptor_0ffcffcda38ae159, []int{177} } func (m *GetGithubAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12033,7 +12155,7 @@ func (m *CreateOIDCConnectorRequest) Reset() { *m = CreateOIDCConnectorR func (m *CreateOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateOIDCConnectorRequest) ProtoMessage() {} func (*CreateOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{177} + return fileDescriptor_0ffcffcda38ae159, []int{178} } func (m *CreateOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12082,7 +12204,7 @@ func (m *UpdateOIDCConnectorRequest) Reset() { *m = UpdateOIDCConnectorR func (m *UpdateOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateOIDCConnectorRequest) ProtoMessage() {} func (*UpdateOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{178} + return fileDescriptor_0ffcffcda38ae159, []int{179} } func (m *UpdateOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12131,7 +12253,7 @@ func (m *UpsertOIDCConnectorRequest) Reset() { *m = UpsertOIDCConnectorR func (m *UpsertOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertOIDCConnectorRequest) ProtoMessage() {} func (*UpsertOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{179} + return fileDescriptor_0ffcffcda38ae159, []int{180} } func (m *UpsertOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12180,7 +12302,7 @@ func (m *CreateSAMLConnectorRequest) Reset() { *m = CreateSAMLConnectorR func (m *CreateSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateSAMLConnectorRequest) ProtoMessage() {} func (*CreateSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{180} + return fileDescriptor_0ffcffcda38ae159, []int{181} } func (m *CreateSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12229,7 +12351,7 @@ func (m *UpdateSAMLConnectorRequest) Reset() { *m = UpdateSAMLConnectorR func (m *UpdateSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateSAMLConnectorRequest) ProtoMessage() {} func (*UpdateSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{181} + return fileDescriptor_0ffcffcda38ae159, []int{182} } func (m *UpdateSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12278,7 +12400,7 @@ func (m *UpsertSAMLConnectorRequest) Reset() { *m = UpsertSAMLConnectorR func (m *UpsertSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertSAMLConnectorRequest) ProtoMessage() {} func (*UpsertSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{182} + return fileDescriptor_0ffcffcda38ae159, []int{183} } func (m *UpsertSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12327,7 +12449,7 @@ func (m *CreateGithubConnectorRequest) Reset() { *m = CreateGithubConnec func (m *CreateGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateGithubConnectorRequest) ProtoMessage() {} func (*CreateGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{183} + return fileDescriptor_0ffcffcda38ae159, []int{184} } func (m *CreateGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12376,7 +12498,7 @@ func (m *UpdateGithubConnectorRequest) Reset() { *m = UpdateGithubConnec func (m *UpdateGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateGithubConnectorRequest) ProtoMessage() {} func (*UpdateGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{184} + return fileDescriptor_0ffcffcda38ae159, []int{185} } func (m *UpdateGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12425,7 +12547,7 @@ func (m *UpsertGithubConnectorRequest) Reset() { *m = UpsertGithubConnec func (m *UpsertGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertGithubConnectorRequest) ProtoMessage() {} func (*UpsertGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{185} + return fileDescriptor_0ffcffcda38ae159, []int{186} } func (m *UpsertGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12476,7 +12598,7 @@ func (m *GetSSODiagnosticInfoRequest) Reset() { *m = GetSSODiagnosticInf func (m *GetSSODiagnosticInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetSSODiagnosticInfoRequest) ProtoMessage() {} func (*GetSSODiagnosticInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{186} + return fileDescriptor_0ffcffcda38ae159, []int{187} } func (m *GetSSODiagnosticInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12542,7 +12664,7 @@ func (m *SystemRoleAssertion) Reset() { *m = SystemRoleAssertion{} } func (m *SystemRoleAssertion) String() string { return proto.CompactTextString(m) } func (*SystemRoleAssertion) ProtoMessage() {} func (*SystemRoleAssertion) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{187} + return fileDescriptor_0ffcffcda38ae159, []int{188} } func (m *SystemRoleAssertion) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12612,7 +12734,7 @@ func (m *SystemRoleAssertionSet) Reset() { *m = SystemRoleAssertionSet{} func (m *SystemRoleAssertionSet) String() string { return proto.CompactTextString(m) } func (*SystemRoleAssertionSet) ProtoMessage() {} func (*SystemRoleAssertionSet) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{188} + return fileDescriptor_0ffcffcda38ae159, []int{189} } func (m *SystemRoleAssertionSet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12681,7 +12803,7 @@ func (m *UpstreamInventoryOneOf) Reset() { *m = UpstreamInventoryOneOf{} func (m *UpstreamInventoryOneOf) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryOneOf) ProtoMessage() {} func (*UpstreamInventoryOneOf) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{189} + return fileDescriptor_0ffcffcda38ae159, []int{190} } func (m *UpstreamInventoryOneOf) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12808,7 +12930,7 @@ func (m *DownstreamInventoryOneOf) Reset() { *m = DownstreamInventoryOne func (m *DownstreamInventoryOneOf) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryOneOf) ProtoMessage() {} func (*DownstreamInventoryOneOf) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{190} + return fileDescriptor_0ffcffcda38ae159, []int{191} } func (m *DownstreamInventoryOneOf) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12907,7 +13029,7 @@ func (m *DownstreamInventoryPing) Reset() { *m = DownstreamInventoryPing func (m *DownstreamInventoryPing) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryPing) ProtoMessage() {} func (*DownstreamInventoryPing) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{191} + return fileDescriptor_0ffcffcda38ae159, []int{192} } func (m *DownstreamInventoryPing) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12956,7 +13078,7 @@ func (m *UpstreamInventoryPong) Reset() { *m = UpstreamInventoryPong{} } func (m *UpstreamInventoryPong) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryPong) ProtoMessage() {} func (*UpstreamInventoryPong) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{192} + return fileDescriptor_0ffcffcda38ae159, []int{193} } func (m *UpstreamInventoryPong) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13023,7 +13145,7 @@ func (m *UpstreamInventoryHello) Reset() { *m = UpstreamInventoryHello{} func (m *UpstreamInventoryHello) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryHello) ProtoMessage() {} func (*UpstreamInventoryHello) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{193} + return fileDescriptor_0ffcffcda38ae159, []int{194} } func (m *UpstreamInventoryHello) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13123,7 +13245,7 @@ func (m *UpstreamInventoryAgentMetadata) Reset() { *m = UpstreamInventor func (m *UpstreamInventoryAgentMetadata) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryAgentMetadata) ProtoMessage() {} func (*UpstreamInventoryAgentMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{194} + return fileDescriptor_0ffcffcda38ae159, []int{195} } func (m *UpstreamInventoryAgentMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13225,7 +13347,7 @@ func (m *DownstreamInventoryHello) Reset() { *m = DownstreamInventoryHel func (m *DownstreamInventoryHello) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryHello) ProtoMessage() {} func (*DownstreamInventoryHello) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{195} + return fileDescriptor_0ffcffcda38ae159, []int{196} } func (m *DownstreamInventoryHello) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13328,7 +13450,7 @@ func (m *DownstreamInventoryHello_SupportedCapabilities) String() string { } func (*DownstreamInventoryHello_SupportedCapabilities) ProtoMessage() {} func (*DownstreamInventoryHello_SupportedCapabilities) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{195, 0} + return fileDescriptor_0ffcffcda38ae159, []int{196, 0} } func (m *DownstreamInventoryHello_SupportedCapabilities) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13501,7 +13623,7 @@ func (m *InventoryUpdateLabelsRequest) Reset() { *m = InventoryUpdateLab func (m *InventoryUpdateLabelsRequest) String() string { return proto.CompactTextString(m) } func (*InventoryUpdateLabelsRequest) ProtoMessage() {} func (*InventoryUpdateLabelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{196} + return fileDescriptor_0ffcffcda38ae159, []int{197} } func (m *InventoryUpdateLabelsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13567,7 +13689,7 @@ func (m *DownstreamInventoryUpdateLabels) Reset() { *m = DownstreamInven func (m *DownstreamInventoryUpdateLabels) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryUpdateLabels) ProtoMessage() {} func (*DownstreamInventoryUpdateLabels) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{197} + return fileDescriptor_0ffcffcda38ae159, []int{198} } func (m *DownstreamInventoryUpdateLabels) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13628,7 +13750,7 @@ func (m *InventoryHeartbeat) Reset() { *m = InventoryHeartbeat{} } func (m *InventoryHeartbeat) String() string { return proto.CompactTextString(m) } func (*InventoryHeartbeat) ProtoMessage() {} func (*InventoryHeartbeat) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{198} + return fileDescriptor_0ffcffcda38ae159, []int{199} } func (m *InventoryHeartbeat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13686,7 +13808,7 @@ func (m *UpstreamInventoryGoodbye) Reset() { *m = UpstreamInventoryGoodb func (m *UpstreamInventoryGoodbye) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryGoodbye) ProtoMessage() {} func (*UpstreamInventoryGoodbye) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{199} + return fileDescriptor_0ffcffcda38ae159, []int{200} } func (m *UpstreamInventoryGoodbye) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13736,7 +13858,7 @@ func (m *InventoryStatusRequest) Reset() { *m = InventoryStatusRequest{} func (m *InventoryStatusRequest) String() string { return proto.CompactTextString(m) } func (*InventoryStatusRequest) ProtoMessage() {} func (*InventoryStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{200} + return fileDescriptor_0ffcffcda38ae159, []int{201} } func (m *InventoryStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13794,7 +13916,7 @@ func (m *InventoryStatusSummary) Reset() { *m = InventoryStatusSummary{} func (m *InventoryStatusSummary) String() string { return proto.CompactTextString(m) } func (*InventoryStatusSummary) ProtoMessage() {} func (*InventoryStatusSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{201} + return fileDescriptor_0ffcffcda38ae159, []int{202} } func (m *InventoryStatusSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13871,7 +13993,7 @@ func (m *InventoryConnectedServiceCountsRequest) Reset() { func (m *InventoryConnectedServiceCountsRequest) String() string { return proto.CompactTextString(m) } func (*InventoryConnectedServiceCountsRequest) ProtoMessage() {} func (*InventoryConnectedServiceCountsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{202} + return fileDescriptor_0ffcffcda38ae159, []int{203} } func (m *InventoryConnectedServiceCountsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13913,7 +14035,7 @@ func (m *InventoryConnectedServiceCounts) Reset() { *m = InventoryConnec func (m *InventoryConnectedServiceCounts) String() string { return proto.CompactTextString(m) } func (*InventoryConnectedServiceCounts) ProtoMessage() {} func (*InventoryConnectedServiceCounts) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{203} + return fileDescriptor_0ffcffcda38ae159, []int{204} } func (m *InventoryConnectedServiceCounts) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13967,7 +14089,7 @@ func (m *InventoryPingRequest) Reset() { *m = InventoryPingRequest{} } func (m *InventoryPingRequest) String() string { return proto.CompactTextString(m) } func (*InventoryPingRequest) ProtoMessage() {} func (*InventoryPingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{204} + return fileDescriptor_0ffcffcda38ae159, []int{205} } func (m *InventoryPingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14023,7 +14145,7 @@ func (m *InventoryPingResponse) Reset() { *m = InventoryPingResponse{} } func (m *InventoryPingResponse) String() string { return proto.CompactTextString(m) } func (*InventoryPingResponse) ProtoMessage() {} func (*InventoryPingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{205} + return fileDescriptor_0ffcffcda38ae159, []int{206} } func (m *InventoryPingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14072,7 +14194,7 @@ func (m *GetClusterAlertsResponse) Reset() { *m = GetClusterAlertsRespon func (m *GetClusterAlertsResponse) String() string { return proto.CompactTextString(m) } func (*GetClusterAlertsResponse) ProtoMessage() {} func (*GetClusterAlertsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{206} + return fileDescriptor_0ffcffcda38ae159, []int{207} } func (m *GetClusterAlertsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14119,7 +14241,7 @@ func (m *GetAlertAcksRequest) Reset() { *m = GetAlertAcksRequest{} } func (m *GetAlertAcksRequest) String() string { return proto.CompactTextString(m) } func (*GetAlertAcksRequest) ProtoMessage() {} func (*GetAlertAcksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{207} + return fileDescriptor_0ffcffcda38ae159, []int{208} } func (m *GetAlertAcksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14161,7 +14283,7 @@ func (m *GetAlertAcksResponse) Reset() { *m = GetAlertAcksResponse{} } func (m *GetAlertAcksResponse) String() string { return proto.CompactTextString(m) } func (*GetAlertAcksResponse) ProtoMessage() {} func (*GetAlertAcksResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{208} + return fileDescriptor_0ffcffcda38ae159, []int{209} } func (m *GetAlertAcksResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14211,7 +14333,7 @@ func (m *ClearAlertAcksRequest) Reset() { *m = ClearAlertAcksRequest{} } func (m *ClearAlertAcksRequest) String() string { return proto.CompactTextString(m) } func (*ClearAlertAcksRequest) ProtoMessage() {} func (*ClearAlertAcksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{209} + return fileDescriptor_0ffcffcda38ae159, []int{210} } func (m *ClearAlertAcksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14260,7 +14382,7 @@ func (m *UpsertClusterAlertRequest) Reset() { *m = UpsertClusterAlertReq func (m *UpsertClusterAlertRequest) String() string { return proto.CompactTextString(m) } func (*UpsertClusterAlertRequest) ProtoMessage() {} func (*UpsertClusterAlertRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{210} + return fileDescriptor_0ffcffcda38ae159, []int{211} } func (m *UpsertClusterAlertRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14309,7 +14431,7 @@ func (m *GetConnectionDiagnosticRequest) Reset() { *m = GetConnectionDia func (m *GetConnectionDiagnosticRequest) String() string { return proto.CompactTextString(m) } func (*GetConnectionDiagnosticRequest) ProtoMessage() {} func (*GetConnectionDiagnosticRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{211} + return fileDescriptor_0ffcffcda38ae159, []int{212} } func (m *GetConnectionDiagnosticRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14360,7 +14482,7 @@ func (m *AppendDiagnosticTraceRequest) Reset() { *m = AppendDiagnosticTr func (m *AppendDiagnosticTraceRequest) String() string { return proto.CompactTextString(m) } func (*AppendDiagnosticTraceRequest) ProtoMessage() {} func (*AppendDiagnosticTraceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{212} + return fileDescriptor_0ffcffcda38ae159, []int{213} } func (m *AppendDiagnosticTraceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14415,7 +14537,7 @@ func (m *SubmitUsageEventRequest) Reset() { *m = SubmitUsageEventRequest func (m *SubmitUsageEventRequest) String() string { return proto.CompactTextString(m) } func (*SubmitUsageEventRequest) ProtoMessage() {} func (*SubmitUsageEventRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{213} + return fileDescriptor_0ffcffcda38ae159, []int{214} } func (m *SubmitUsageEventRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14462,7 +14584,7 @@ func (m *GetLicenseRequest) Reset() { *m = GetLicenseRequest{} } func (m *GetLicenseRequest) String() string { return proto.CompactTextString(m) } func (*GetLicenseRequest) ProtoMessage() {} func (*GetLicenseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{214} + return fileDescriptor_0ffcffcda38ae159, []int{215} } func (m *GetLicenseRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14502,7 +14624,7 @@ func (m *ListReleasesRequest) Reset() { *m = ListReleasesRequest{} } func (m *ListReleasesRequest) String() string { return proto.CompactTextString(m) } func (*ListReleasesRequest) ProtoMessage() {} func (*ListReleasesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{215} + return fileDescriptor_0ffcffcda38ae159, []int{216} } func (m *ListReleasesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14546,7 +14668,7 @@ func (m *CreateTokenV2Request) Reset() { *m = CreateTokenV2Request{} } func (m *CreateTokenV2Request) String() string { return proto.CompactTextString(m) } func (*CreateTokenV2Request) ProtoMessage() {} func (*CreateTokenV2Request) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{216} + return fileDescriptor_0ffcffcda38ae159, []int{217} } func (m *CreateTokenV2Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14623,7 +14745,7 @@ func (m *UpsertTokenV2Request) Reset() { *m = UpsertTokenV2Request{} } func (m *UpsertTokenV2Request) String() string { return proto.CompactTextString(m) } func (*UpsertTokenV2Request) ProtoMessage() {} func (*UpsertTokenV2Request) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{217} + return fileDescriptor_0ffcffcda38ae159, []int{218} } func (m *UpsertTokenV2Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14698,7 +14820,7 @@ func (m *GetHeadlessAuthenticationRequest) Reset() { *m = GetHeadlessAut func (m *GetHeadlessAuthenticationRequest) String() string { return proto.CompactTextString(m) } func (*GetHeadlessAuthenticationRequest) ProtoMessage() {} func (*GetHeadlessAuthenticationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{218} + return fileDescriptor_0ffcffcda38ae159, []int{219} } func (m *GetHeadlessAuthenticationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14756,7 +14878,7 @@ func (m *UpdateHeadlessAuthenticationStateRequest) Reset() { func (m *UpdateHeadlessAuthenticationStateRequest) String() string { return proto.CompactTextString(m) } func (*UpdateHeadlessAuthenticationStateRequest) ProtoMessage() {} func (*UpdateHeadlessAuthenticationStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{219} + return fileDescriptor_0ffcffcda38ae159, []int{220} } func (m *UpdateHeadlessAuthenticationStateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14822,7 +14944,7 @@ func (m *ExportUpgradeWindowsRequest) Reset() { *m = ExportUpgradeWindow func (m *ExportUpgradeWindowsRequest) String() string { return proto.CompactTextString(m) } func (*ExportUpgradeWindowsRequest) ProtoMessage() {} func (*ExportUpgradeWindowsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{220} + return fileDescriptor_0ffcffcda38ae159, []int{221} } func (m *ExportUpgradeWindowsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14888,7 +15010,7 @@ func (m *ExportUpgradeWindowsResponse) Reset() { *m = ExportUpgradeWindo func (m *ExportUpgradeWindowsResponse) String() string { return proto.CompactTextString(m) } func (*ExportUpgradeWindowsResponse) ProtoMessage() {} func (*ExportUpgradeWindowsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{221} + return fileDescriptor_0ffcffcda38ae159, []int{222} } func (m *ExportUpgradeWindowsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14963,7 +15085,7 @@ func (m *ListAccessRequestsRequest) Reset() { *m = ListAccessRequestsReq func (m *ListAccessRequestsRequest) String() string { return proto.CompactTextString(m) } func (*ListAccessRequestsRequest) ProtoMessage() {} func (*ListAccessRequestsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{222} + return fileDescriptor_0ffcffcda38ae159, []int{223} } func (m *ListAccessRequestsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15042,7 +15164,7 @@ func (m *ListAccessRequestsResponse) Reset() { *m = ListAccessRequestsRe func (m *ListAccessRequestsResponse) String() string { return proto.CompactTextString(m) } func (*ListAccessRequestsResponse) ProtoMessage() {} func (*ListAccessRequestsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{223} + return fileDescriptor_0ffcffcda38ae159, []int{224} } func (m *ListAccessRequestsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15098,7 +15220,7 @@ func (m *AccessRequestAllowedPromotionRequest) Reset() { *m = AccessRequ func (m *AccessRequestAllowedPromotionRequest) String() string { return proto.CompactTextString(m) } func (*AccessRequestAllowedPromotionRequest) ProtoMessage() {} func (*AccessRequestAllowedPromotionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{224} + return fileDescriptor_0ffcffcda38ae159, []int{225} } func (m *AccessRequestAllowedPromotionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15147,7 +15269,7 @@ func (m *AccessRequestAllowedPromotionResponse) Reset() { *m = AccessReq func (m *AccessRequestAllowedPromotionResponse) String() string { return proto.CompactTextString(m) } func (*AccessRequestAllowedPromotionResponse) ProtoMessage() {} func (*AccessRequestAllowedPromotionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{225} + return fileDescriptor_0ffcffcda38ae159, []int{226} } func (m *AccessRequestAllowedPromotionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15217,6 +15339,8 @@ func init() { proto.RegisterType((*PingRequest)(nil), "proto.PingRequest") proto.RegisterType((*PingResponse)(nil), "proto.PingResponse") proto.RegisterType((*Features)(nil), "proto.Features") + proto.RegisterMapType((map[string]*EntitlementInfo)(nil), "proto.Features.EntitlementsEntry") + proto.RegisterType((*EntitlementInfo)(nil), "proto.EntitlementInfo") proto.RegisterType((*DeviceTrustFeature)(nil), "proto.DeviceTrustFeature") proto.RegisterType((*AccessRequestsFeature)(nil), "proto.AccessRequestsFeature") proto.RegisterType((*AccessListFeature)(nil), "proto.AccessListFeature") @@ -15440,920 +15564,929 @@ func init() { } var fileDescriptor_0ffcffcda38ae159 = []byte{ - // 14607 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x5b, 0x6c, 0x5c, 0x49, - 0x76, 0x20, 0xc8, 0xe4, 0x9b, 0x87, 0x0f, 0xa5, 0x82, 0xa4, 0x48, 0x51, 0x94, 0x52, 0xba, 0xf5, - 0x52, 0xa9, 0xab, 0xf5, 0xa0, 0xaa, 0xaa, 0xeb, 0xd5, 0x55, 0x9d, 0x7c, 0x48, 0xa4, 0xc4, 0x57, - 0xdd, 0x24, 0xa9, 0xaa, 0xea, 0x72, 0x67, 0x5f, 0x66, 0x86, 0xc8, 0x6b, 0x25, 0xef, 0xcd, 0xbe, - 0xf7, 0xa6, 0x54, 0x6a, 0xaf, 0xbd, 0x70, 0x7b, 0x17, 0xeb, 0x9f, 0xdd, 0xb5, 0x81, 0xf5, 0xc2, - 0x0b, 0x7f, 0x18, 0x0b, 0x8c, 0x81, 0xc1, 0x7c, 0xf9, 0x67, 0xc6, 0x3f, 0x03, 0x0c, 0xe6, 0x6b, - 0x7a, 0x0c, 0x78, 0x1e, 0xb0, 0xfd, 0x33, 0x1f, 0xf4, 0x4c, 0x03, 0xf3, 0x43, 0xcc, 0x7c, 0x18, - 0x83, 0x19, 0x60, 0x1a, 0x30, 0x30, 0x88, 0x13, 0x8f, 0x1b, 0x71, 0x5f, 0x49, 0x4a, 0xaa, 0xf6, - 0xfc, 0x48, 0xcc, 0x13, 0xe7, 0x9c, 0x88, 0x38, 0x11, 0x37, 0xe2, 0xc4, 0x89, 0x13, 0xe7, 0xc0, - 0xcd, 0x88, 0xb6, 0x68, 0xdb, 0x0f, 0xa2, 0x5b, 0x2d, 0x7a, 0xe0, 0x34, 0x9e, 0xdf, 0x6a, 0xb4, - 0x5c, 0xea, 0x45, 0xb7, 0xda, 0x81, 0x1f, 0xf9, 0xb7, 0x9c, 0x4e, 0x74, 0x18, 0xd2, 0xe0, 0xa9, - 0xdb, 0xa0, 0x37, 0x11, 0x42, 0x06, 0xf0, 0xbf, 0xb9, 0xa9, 0x03, 0xff, 0xc0, 0xe7, 0x38, 0xec, - 0x2f, 0x5e, 0x38, 0x77, 0xe9, 0xc0, 0xf7, 0x0f, 0x5a, 0x94, 0x13, 0xef, 0x77, 0x1e, 0xdf, 0xa2, - 0x47, 0xed, 0xe8, 0xb9, 0x28, 0xac, 0x24, 0x0b, 0x23, 0xf7, 0x88, 0x86, 0x91, 0x73, 0xd4, 0x16, - 0x08, 0x6f, 0xab, 0xa6, 0x38, 0x51, 0xc4, 0x4a, 0x22, 0xd7, 0xf7, 0x6e, 0x3d, 0xbd, 0xa3, 0xff, - 0x14, 0xa8, 0xd7, 0x0b, 0x5b, 0xdd, 0xa0, 0x41, 0x14, 0x9e, 0x0a, 0x93, 0x3e, 0xa5, 0x5e, 0x94, - 0xaa, 0x5e, 0x60, 0x46, 0xcf, 0xdb, 0x34, 0xe4, 0x28, 0xf2, 0x3f, 0x81, 0x7a, 0x2d, 0x1b, 0x15, - 0xff, 0x15, 0x28, 0xdf, 0xcd, 0x46, 0x79, 0x46, 0xf7, 0x99, 0x4c, 0x3d, 0xf5, 0x47, 0x17, 0xf4, - 0xc0, 0x69, 0xb7, 0x69, 0x10, 0xff, 0x21, 0xd0, 0x2f, 0x2a, 0xf4, 0xa3, 0xc7, 0x0e, 0x13, 0xd1, - 0xd1, 0x63, 0x27, 0xd5, 0x8d, 0x4e, 0xe8, 0x1c, 0x50, 0xd1, 0xfc, 0xa7, 0x77, 0xf4, 0x9f, 0x1c, - 0xd5, 0xfa, 0xe3, 0x12, 0x0c, 0x3c, 0x72, 0xa2, 0xc6, 0x21, 0xf9, 0x0c, 0x06, 0x1e, 0xba, 0x5e, - 0x33, 0x9c, 0x2d, 0x5d, 0xed, 0xbb, 0x3e, 0xba, 0x50, 0xbe, 0xc9, 0xbb, 0x82, 0x85, 0xac, 0x60, - 0x71, 0xe6, 0xe7, 0xc7, 0x95, 0x9e, 0x93, 0xe3, 0xca, 0xb9, 0x27, 0x0c, 0xed, 0x1d, 0xff, 0xc8, - 0x8d, 0x70, 0x6c, 0x6d, 0x4e, 0x47, 0x76, 0x61, 0xb2, 0xda, 0x6a, 0xf9, 0xcf, 0xb6, 0x9d, 0x20, - 0x72, 0x9d, 0x56, 0xad, 0xd3, 0x68, 0xd0, 0x30, 0x9c, 0xed, 0xbd, 0x5a, 0xba, 0x3e, 0xbc, 0xf8, - 0xda, 0xc9, 0x71, 0xa5, 0xe2, 0xb0, 0xe2, 0x7a, 0x9b, 0x97, 0xd7, 0x43, 0x8e, 0xa0, 0x31, 0xca, - 0xa2, 0xb7, 0xfe, 0x7c, 0x10, 0xca, 0xab, 0x7e, 0x18, 0x2d, 0xb1, 0x11, 0xb5, 0xe9, 0x4f, 0x3a, - 0x34, 0x8c, 0xc8, 0x6b, 0x30, 0xc8, 0x60, 0x6b, 0xcb, 0xb3, 0xa5, 0xab, 0xa5, 0xeb, 0x23, 0x8b, - 0xa3, 0x27, 0xc7, 0x95, 0xa1, 0x43, 0x3f, 0x8c, 0xea, 0x6e, 0xd3, 0x16, 0x45, 0xe4, 0x6d, 0x18, - 0xde, 0xf4, 0x9b, 0x74, 0xd3, 0x39, 0xa2, 0xd8, 0x8a, 0x91, 0xc5, 0xf1, 0x93, 0xe3, 0xca, 0x88, - 0xe7, 0x37, 0x69, 0xdd, 0x73, 0x8e, 0xa8, 0xad, 0x8a, 0xc9, 0x1e, 0xf4, 0xdb, 0x7e, 0x8b, 0xce, - 0xf6, 0x21, 0xda, 0xe2, 0xc9, 0x71, 0xa5, 0x3f, 0xf0, 0x5b, 0xf4, 0x97, 0xc7, 0x95, 0xf7, 0x0f, - 0xdc, 0xe8, 0xb0, 0xb3, 0x7f, 0xb3, 0xe1, 0x1f, 0xdd, 0x3a, 0x08, 0x9c, 0xa7, 0x2e, 0x9f, 0x84, - 0x4e, 0xeb, 0x56, 0x3c, 0x55, 0xdb, 0xae, 0x18, 0xf7, 0xda, 0xf3, 0x30, 0xa2, 0x47, 0x8c, 0x93, - 0x8d, 0xfc, 0xc8, 0x23, 0x98, 0xaa, 0x36, 0x9b, 0x2e, 0xa7, 0xd8, 0x0e, 0x5c, 0xaf, 0xe1, 0xb6, - 0x9d, 0x56, 0x38, 0xdb, 0x7f, 0xb5, 0xef, 0xfa, 0x88, 0x10, 0x8a, 0x2a, 0xaf, 0xb7, 0x15, 0x82, - 0x26, 0x94, 0x4c, 0x06, 0xe4, 0x2e, 0x0c, 0x2f, 0x6f, 0xd6, 0x58, 0xdb, 0xc3, 0xd9, 0x01, 0x64, - 0x36, 0x73, 0x72, 0x5c, 0x99, 0x6c, 0x7a, 0x21, 0x76, 0x4d, 0x67, 0xa0, 0x10, 0xc9, 0xfb, 0x30, - 0xb6, 0xdd, 0xd9, 0x6f, 0xb9, 0x8d, 0x9d, 0xf5, 0xda, 0x43, 0xfa, 0x7c, 0x76, 0xf0, 0x6a, 0xe9, - 0xfa, 0xd8, 0x22, 0x39, 0x39, 0xae, 0x4c, 0xb4, 0x11, 0x5e, 0x8f, 0x5a, 0x61, 0xfd, 0x09, 0x7d, - 0x6e, 0x1b, 0x78, 0x31, 0x5d, 0xad, 0xb6, 0xca, 0xe8, 0x86, 0x52, 0x74, 0x61, 0x78, 0xa8, 0xd3, - 0x71, 0x3c, 0x72, 0x0b, 0xc0, 0xa6, 0x47, 0x7e, 0x44, 0xab, 0xcd, 0x66, 0x30, 0x3b, 0x8c, 0xb2, - 0x3d, 0x77, 0x72, 0x5c, 0x19, 0x0d, 0x10, 0x5a, 0x77, 0x9a, 0xcd, 0xc0, 0xd6, 0x50, 0xc8, 0x12, - 0x0c, 0xdb, 0x3e, 0x17, 0xf0, 0xec, 0xc8, 0xd5, 0xd2, 0xf5, 0xd1, 0x85, 0x73, 0x62, 0x1a, 0x4a, - 0xf0, 0xe2, 0x85, 0x93, 0xe3, 0x0a, 0x09, 0xc4, 0x2f, 0xbd, 0x97, 0x12, 0x83, 0x54, 0x60, 0x68, - 0xd3, 0x5f, 0x72, 0x1a, 0x87, 0x74, 0x16, 0x70, 0xee, 0x0d, 0x9c, 0x1c, 0x57, 0x4a, 0xdf, 0xb5, - 0x25, 0x94, 0x3c, 0x85, 0xd1, 0x78, 0xa0, 0xc2, 0xd9, 0x51, 0x14, 0xdf, 0xce, 0xc9, 0x71, 0xe5, - 0x42, 0x88, 0xe0, 0x3a, 0x1b, 0x7a, 0x4d, 0x82, 0x2f, 0x31, 0x0b, 0xf4, 0x8a, 0xc8, 0xd7, 0x30, - 0x1d, 0xff, 0xac, 0x86, 0x21, 0x0d, 0x18, 0x8f, 0xb5, 0xe5, 0xd9, 0x71, 0x94, 0xcc, 0x9b, 0x27, - 0xc7, 0x15, 0x4b, 0x6b, 0x41, 0xdd, 0x91, 0x28, 0x75, 0xb7, 0xa9, 0xf5, 0x34, 0x9b, 0xc9, 0x83, - 0xfe, 0xe1, 0xb1, 0xf2, 0xb8, 0x7d, 0x79, 0xd7, 0x0b, 0x23, 0x67, 0xbf, 0x45, 0x33, 0x91, 0xac, - 0xbf, 0x2b, 0x01, 0xd9, 0x6a, 0x53, 0xaf, 0x56, 0x5b, 0x65, 0xdf, 0x93, 0xfc, 0x9c, 0xde, 0x81, - 0x11, 0x3e, 0x70, 0x6c, 0x74, 0x7b, 0x71, 0x74, 0x27, 0x4e, 0x8e, 0x2b, 0x20, 0x46, 0x97, 0x8d, - 0x6c, 0x8c, 0x40, 0xde, 0x80, 0xbe, 0x9d, 0x9d, 0x75, 0xfc, 0x56, 0xfa, 0x16, 0x27, 0x4f, 0x8e, - 0x2b, 0x7d, 0x51, 0xd4, 0xfa, 0xe5, 0x71, 0x65, 0x78, 0xb9, 0x13, 0xa0, 0x58, 0x6c, 0x56, 0x4e, - 0xde, 0x80, 0xa1, 0xa5, 0x56, 0x27, 0x8c, 0x68, 0x30, 0xdb, 0x1f, 0x7f, 0xa4, 0x0d, 0x0e, 0xb2, - 0x65, 0x19, 0xf9, 0x0e, 0xf4, 0xef, 0x86, 0x34, 0x98, 0x1d, 0xc0, 0xf1, 0x1e, 0x17, 0xe3, 0xcd, - 0x40, 0x7b, 0x0b, 0x8b, 0xc3, 0xec, 0x4b, 0xec, 0x84, 0x34, 0xb0, 0x11, 0x89, 0xdc, 0x84, 0x01, - 0x3e, 0x68, 0x83, 0xb8, 0x48, 0x8d, 0xab, 0xd9, 0xd1, 0xa2, 0x7b, 0xef, 0x2f, 0x8e, 0x9c, 0x1c, - 0x57, 0x06, 0x70, 0xf0, 0x6c, 0x8e, 0xf6, 0xa0, 0x7f, 0xb8, 0x54, 0xee, 0xb5, 0x87, 0x19, 0x2d, - 0xfb, 0x2c, 0xac, 0xef, 0xc0, 0xa8, 0xd6, 0x7d, 0x32, 0x0f, 0xfd, 0xec, 0x7f, 0x5c, 0x44, 0xc6, - 0x78, 0x65, 0x6c, 0xe3, 0xb0, 0x11, 0x6a, 0xfd, 0x93, 0x73, 0x50, 0x66, 0x94, 0xc6, 0xca, 0x63, - 0x88, 0xaa, 0xd4, 0x4d, 0x54, 0xd7, 0x41, 0xd5, 0x2d, 0x96, 0xa0, 0xb1, 0x93, 0xe3, 0xca, 0x70, - 0x47, 0xc0, 0xe2, 0x96, 0x91, 0x1a, 0x0c, 0xad, 0x7c, 0xd3, 0x76, 0x03, 0x1a, 0xa2, 0x60, 0x47, - 0x17, 0xe6, 0x6e, 0xf2, 0xcd, 0xf2, 0xa6, 0xdc, 0x2c, 0x6f, 0xee, 0xc8, 0xcd, 0x72, 0xf1, 0xb2, - 0x58, 0x8a, 0xcf, 0x53, 0x4e, 0x12, 0xcf, 0x8e, 0xdf, 0xfb, 0x9b, 0x4a, 0xc9, 0x96, 0x9c, 0xc8, - 0x3b, 0x30, 0x78, 0xcf, 0x0f, 0x8e, 0x9c, 0x48, 0x8c, 0xc0, 0xd4, 0xc9, 0x71, 0xa5, 0xfc, 0x18, - 0x21, 0xda, 0x84, 0x12, 0x38, 0xe4, 0x1e, 0x4c, 0xd8, 0x7e, 0x27, 0xa2, 0x3b, 0xbe, 0x1c, 0xb7, - 0x01, 0xa4, 0xba, 0x72, 0x72, 0x5c, 0x99, 0x0b, 0x58, 0x49, 0x3d, 0xf2, 0xeb, 0x62, 0x00, 0x35, - 0xfa, 0x04, 0x15, 0x59, 0x81, 0x89, 0x2a, 0xae, 0xdd, 0x42, 0x66, 0x7c, 0xb4, 0x46, 0x16, 0x2f, - 0x9f, 0x1c, 0x57, 0x2e, 0x3a, 0x58, 0x52, 0x0f, 0x44, 0x91, 0xce, 0xc6, 0x24, 0x22, 0x9b, 0x70, - 0xfe, 0x61, 0x67, 0x9f, 0x06, 0x1e, 0x8d, 0x68, 0x28, 0x5b, 0x34, 0x84, 0x2d, 0xba, 0x7a, 0x72, - 0x5c, 0x99, 0x7f, 0xa2, 0x0a, 0x33, 0xda, 0x94, 0x26, 0x25, 0x14, 0xce, 0x89, 0x86, 0x2e, 0x3b, - 0x91, 0xb3, 0xef, 0x84, 0x14, 0x97, 0xa4, 0xd1, 0x85, 0x0b, 0x5c, 0xc4, 0x37, 0x13, 0xa5, 0x8b, - 0xaf, 0x09, 0x29, 0x5f, 0x52, 0x7d, 0x6f, 0x8a, 0x22, 0xad, 0xa2, 0x24, 0x4f, 0xb6, 0x32, 0xab, - 0x5d, 0x67, 0x04, 0x5b, 0x8b, 0x2b, 0xb3, 0xda, 0x75, 0xf4, 0x35, 0x4b, 0xed, 0x3f, 0xeb, 0x30, - 0xb0, 0xcb, 0xf6, 0x66, 0x5c, 0xb1, 0x26, 0x16, 0xae, 0x89, 0x16, 0x25, 0x67, 0xdf, 0x4d, 0xf6, - 0x03, 0x11, 0xf1, 0xbb, 0x3b, 0x87, 0xfb, 0xb9, 0xbe, 0x13, 0x63, 0x19, 0xf9, 0x1c, 0x40, 0xb4, - 0xaa, 0xda, 0x6e, 0xcf, 0x8e, 0x62, 0x27, 0xcf, 0x9b, 0x9d, 0xac, 0xb6, 0xdb, 0x8b, 0x57, 0x44, - 0xff, 0x2e, 0xa8, 0xfe, 0x39, 0xed, 0xb6, 0xc6, 0x4d, 0x63, 0x42, 0x3e, 0x83, 0x31, 0x5c, 0xd0, - 0xe4, 0x88, 0x8e, 0xe1, 0x88, 0x5e, 0x3a, 0x39, 0xae, 0xcc, 0xe0, 0x5a, 0x95, 0x31, 0x9e, 0x06, - 0x01, 0xf9, 0x2d, 0x98, 0x16, 0xec, 0x1e, 0xb9, 0x5e, 0xd3, 0x7f, 0x16, 0x2e, 0xd3, 0xf0, 0x49, - 0xe4, 0xb7, 0x71, 0xf1, 0x1b, 0x5d, 0x98, 0x37, 0x9b, 0x67, 0xe2, 0x2c, 0xde, 0x10, 0x2d, 0xb5, - 0x54, 0x4b, 0x9f, 0x71, 0x84, 0x7a, 0x93, 0x63, 0xe8, 0xcb, 0x63, 0x26, 0x0b, 0xb2, 0x06, 0xe7, - 0x76, 0x43, 0x6a, 0xf4, 0x61, 0x02, 0x77, 0x87, 0x0a, 0x1b, 0xe1, 0x4e, 0x48, 0xeb, 0x79, 0xfd, - 0x48, 0xd2, 0x11, 0x1b, 0xc8, 0x72, 0xe0, 0xb7, 0x13, 0x73, 0xfc, 0x1c, 0x4a, 0xc4, 0x3a, 0x39, - 0xae, 0x5c, 0x69, 0x06, 0x7e, 0xbb, 0x9e, 0x3f, 0xd1, 0x33, 0xa8, 0xc9, 0x8f, 0xe0, 0xc2, 0x92, - 0xef, 0x79, 0xb4, 0xc1, 0xd6, 0xcf, 0x65, 0xd7, 0x39, 0xf0, 0xfc, 0x30, 0x72, 0x1b, 0x6b, 0xcb, - 0xb3, 0xe5, 0x78, 0x73, 0x68, 0x28, 0x8c, 0x7a, 0x53, 0xa1, 0x98, 0x9b, 0x43, 0x0e, 0x17, 0xf2, - 0x43, 0x18, 0x17, 0x75, 0xd1, 0x00, 0xa7, 0xe6, 0xf9, 0xe2, 0x89, 0xa6, 0x90, 0xf9, 0x36, 0x1f, - 0xc8, 0x9f, 0x5c, 0x71, 0x32, 0x79, 0x91, 0xaf, 0x61, 0x74, 0xe3, 0x5e, 0xd5, 0xa6, 0x61, 0xdb, - 0xf7, 0x42, 0x3a, 0x4b, 0x70, 0x44, 0xaf, 0x08, 0xd6, 0x1b, 0xf7, 0xaa, 0xd5, 0x4e, 0x74, 0x48, - 0xbd, 0xc8, 0x6d, 0x38, 0x11, 0x95, 0x58, 0x8b, 0x73, 0x6c, 0xe6, 0x1d, 0x3d, 0x76, 0xea, 0x81, - 0x80, 0x68, 0xbd, 0xd0, 0xd9, 0x91, 0x39, 0x18, 0xae, 0xd5, 0x56, 0xd7, 0xfd, 0x03, 0xd7, 0x9b, - 0x9d, 0x64, 0xc2, 0xb0, 0xd5, 0x6f, 0xb2, 0x0f, 0xd3, 0xda, 0xc9, 0xa0, 0xce, 0xfe, 0xa7, 0x47, - 0xd4, 0x8b, 0x66, 0xa7, 0xb0, 0x0d, 0xdf, 0x55, 0x47, 0x9b, 0x9b, 0xfa, 0x01, 0xe2, 0xe9, 0x9d, - 0x9b, 0xd5, 0xf8, 0x67, 0x4d, 0x12, 0xd9, 0x53, 0x4e, 0x06, 0x94, 0xec, 0xc0, 0xd0, 0x76, 0x27, - 0x68, 0xfb, 0x21, 0x9d, 0x9d, 0x46, 0xa1, 0xbd, 0x56, 0xf4, 0x75, 0x0a, 0xd4, 0xc5, 0x69, 0xb6, - 0x3c, 0xb7, 0xf9, 0x0f, 0xad, 0x67, 0x92, 0x95, 0xf5, 0x05, 0x8c, 0xa8, 0x8f, 0x99, 0x0c, 0x41, - 0x5f, 0xb5, 0xd5, 0x2a, 0xf7, 0xb0, 0x3f, 0x6a, 0xb5, 0xd5, 0x72, 0x89, 0x4c, 0x00, 0xc4, 0x2b, - 0x58, 0xb9, 0x97, 0x8c, 0xc1, 0xb0, 0x5c, 0x61, 0xca, 0x7d, 0x88, 0xdf, 0x6e, 0x97, 0xfb, 0x09, - 0x81, 0x09, 0x73, 0x9e, 0x97, 0x07, 0xac, 0xdf, 0x2f, 0xc1, 0x88, 0x1a, 0x1f, 0x72, 0x0e, 0x46, - 0x77, 0x37, 0x6b, 0xdb, 0x2b, 0x4b, 0x6b, 0xf7, 0xd6, 0x56, 0x96, 0xcb, 0x3d, 0xe4, 0x32, 0x5c, - 0xdc, 0xa9, 0xad, 0xd6, 0x97, 0x17, 0xeb, 0xeb, 0x5b, 0x4b, 0xd5, 0xf5, 0xfa, 0xb6, 0xbd, 0xf5, - 0xc5, 0x97, 0xf5, 0x9d, 0xdd, 0xcd, 0xcd, 0x95, 0xf5, 0x72, 0x89, 0xcc, 0xc2, 0x14, 0x2b, 0x7e, - 0xb8, 0xbb, 0xb8, 0xa2, 0x23, 0x94, 0x7b, 0xc9, 0x35, 0xb8, 0x9c, 0x55, 0x52, 0x5f, 0x5d, 0xa9, - 0x2e, 0xaf, 0xaf, 0xd4, 0x6a, 0xe5, 0x3e, 0x32, 0x03, 0x93, 0x0c, 0xa5, 0xba, 0xbd, 0x6d, 0xd0, - 0xf6, 0x5b, 0x2d, 0x18, 0xd5, 0x84, 0x43, 0xe6, 0x61, 0x76, 0x69, 0xc5, 0xde, 0xa9, 0x6f, 0xef, - 0xda, 0xdb, 0x5b, 0xb5, 0x95, 0xba, 0xd9, 0xc2, 0x64, 0xe9, 0xfa, 0xd6, 0xfd, 0xb5, 0xcd, 0x3a, - 0x03, 0xd5, 0xca, 0x25, 0xd6, 0x0c, 0xa3, 0xb4, 0xb6, 0xb6, 0x79, 0x7f, 0x7d, 0xa5, 0xbe, 0x5b, - 0x5b, 0x11, 0x28, 0xbd, 0xd6, 0xcf, 0x7a, 0x53, 0x4b, 0x3d, 0x59, 0x80, 0xd1, 0x1a, 0x3f, 0xc5, - 0xe2, 0xf4, 0xe7, 0xc7, 0x86, 0xf2, 0xc9, 0x71, 0x65, 0x4c, 0x1c, 0x6e, 0xf9, 0xcc, 0xd6, 0x91, - 0xd8, 0xee, 0xbd, 0xcd, 0x46, 0xba, 0xe1, 0xb7, 0xf4, 0xdd, 0xbb, 0x2d, 0x60, 0xb6, 0x2a, 0x25, - 0x0b, 0xda, 0x3e, 0xcf, 0xcf, 0x10, 0xa8, 0xa7, 0xca, 0x7d, 0x5e, 0x5f, 0xf3, 0xd5, 0x8e, 0xbf, - 0x10, 0x0f, 0xa9, 0xd8, 0x9e, 0x91, 0x26, 0x63, 0x8f, 0x51, 0x78, 0xe4, 0x6d, 0xa9, 0xff, 0x70, - 0x9d, 0x1f, 0x37, 0x81, 0x84, 0xb6, 0x2a, 0x54, 0x1f, 0xab, 0x93, 0xb3, 0xe0, 0x92, 0x8f, 0x93, - 0x73, 0x46, 0x08, 0x03, 0x99, 0x25, 0xd6, 0x55, 0x3b, 0x81, 0x4a, 0x2a, 0x30, 0xc0, 0xbf, 0x44, - 0x2e, 0x0f, 0xd4, 0xb8, 0x5a, 0x0c, 0x60, 0x73, 0xb8, 0xf5, 0x7b, 0x7d, 0xfa, 0xe6, 0xc3, 0x34, - 0x2c, 0x4d, 0xde, 0xa8, 0x61, 0xa1, 0x9c, 0x11, 0x4a, 0x6e, 0xc2, 0x48, 0x8d, 0x86, 0x21, 0xd7, - 0x82, 0x7b, 0xd5, 0x90, 0x40, 0xc8, 0x81, 0x75, 0xb7, 0x39, 0x5b, 0xb2, 0x63, 0x14, 0x76, 0xa0, - 0xe0, 0xba, 0x15, 0x1e, 0x28, 0xfa, 0xe2, 0x03, 0x85, 0xd0, 0xbe, 0xf8, 0x81, 0x22, 0x46, 0x61, - 0xa3, 0x2e, 0xb6, 0x7f, 0x6c, 0x45, 0x7f, 0x3c, 0xea, 0x42, 0x65, 0x10, 0xa3, 0xae, 0x21, 0x91, - 0x8f, 0x00, 0xaa, 0x8f, 0x6a, 0xa8, 0x39, 0xdb, 0x9b, 0x42, 0x05, 0xc2, 0xc5, 0xca, 0x79, 0x16, - 0x0a, 0xc5, 0x3c, 0xd0, 0x4f, 0x1e, 0x1a, 0x36, 0x59, 0x84, 0xf1, 0xea, 0x4f, 0x3b, 0x01, 0x5d, - 0x6b, 0xb2, 0xf5, 0x2e, 0xe2, 0x47, 0xac, 0x91, 0xc5, 0xf9, 0x93, 0xe3, 0xca, 0xac, 0xc3, 0x0a, - 0xea, 0xae, 0x28, 0xd1, 0x18, 0x98, 0x24, 0x64, 0x0b, 0xce, 0xdf, 0x5f, 0xda, 0x16, 0xf3, 0xb0, - 0xda, 0x68, 0xf8, 0x1d, 0x2f, 0x12, 0x7a, 0xcf, 0xb5, 0x93, 0xe3, 0xca, 0xe5, 0x83, 0x46, 0xbb, - 0x2e, 0xe7, 0xac, 0xc3, 0x8b, 0x75, 0xc5, 0x27, 0x45, 0x6b, 0xb5, 0x60, 0xe2, 0x3e, 0x8d, 0xd8, - 0xbc, 0x93, 0x4a, 0x6c, 0xf1, 0xa8, 0x7c, 0x02, 0xa3, 0x8f, 0xdc, 0xe8, 0xb0, 0x46, 0x1b, 0x01, - 0x8d, 0xe4, 0x01, 0x1e, 0x25, 0xf0, 0xcc, 0x8d, 0x0e, 0xeb, 0x21, 0x87, 0xeb, 0xcb, 0xb5, 0x86, - 0x6e, 0xad, 0xc0, 0x39, 0x51, 0x9b, 0xd2, 0x99, 0x17, 0x4c, 0x86, 0x25, 0x64, 0x88, 0xa3, 0xa0, - 0x33, 0x34, 0xd9, 0xfc, 0xe3, 0x5e, 0x98, 0x5e, 0x3a, 0x74, 0xbc, 0x03, 0xba, 0xed, 0x84, 0xe1, - 0x33, 0x3f, 0x68, 0x6a, 0x8d, 0xc7, 0x03, 0x43, 0xaa, 0xf1, 0x78, 0x42, 0x58, 0x80, 0xd1, 0xad, - 0x56, 0x53, 0xd2, 0x88, 0xc3, 0x0c, 0xd6, 0xe5, 0xb7, 0x9a, 0xf5, 0xb6, 0xe4, 0xa5, 0x23, 0x31, - 0x9a, 0x4d, 0xfa, 0x4c, 0xd1, 0xf4, 0xc5, 0x34, 0x1e, 0x7d, 0xa6, 0xd1, 0x68, 0x48, 0x64, 0x05, - 0xce, 0xd7, 0x68, 0xc3, 0xf7, 0x9a, 0xf7, 0x9c, 0x46, 0xe4, 0x07, 0x3b, 0xfe, 0x13, 0xea, 0x89, - 0xf9, 0x85, 0xfa, 0x5e, 0x88, 0x85, 0xf5, 0xc7, 0x58, 0x5a, 0x8f, 0x58, 0xb1, 0x9d, 0xa6, 0x20, - 0x5b, 0x30, 0xfc, 0x48, 0x98, 0x81, 0xc4, 0x09, 0xe8, 0x8d, 0x9b, 0xca, 0x2e, 0xb4, 0x14, 0x50, - 0x9c, 0x14, 0x4e, 0x4b, 0x9d, 0xe1, 0xd4, 0xf6, 0x89, 0x2b, 0x91, 0xc4, 0xb4, 0x15, 0x13, 0x6b, - 0x17, 0xc6, 0xb7, 0x5b, 0x9d, 0x03, 0xd7, 0x63, 0x6b, 0x46, 0x8d, 0xfe, 0x84, 0x2c, 0x03, 0xc4, - 0x00, 0x61, 0xdc, 0x99, 0x14, 0xe7, 0xa6, 0xb8, 0x60, 0xef, 0xae, 0xf8, 0x90, 0x10, 0x82, 0x8a, - 0xae, 0xad, 0xd1, 0x59, 0xff, 0xbd, 0x0f, 0x88, 0x18, 0x00, 0xdc, 0x19, 0x6b, 0x34, 0x62, 0xbb, - 0xcb, 0x05, 0xe8, 0x55, 0x36, 0x98, 0xc1, 0x93, 0xe3, 0x4a, 0xaf, 0xdb, 0xb4, 0x7b, 0xd7, 0x96, - 0xc9, 0xbb, 0x30, 0x80, 0x68, 0x28, 0xff, 0x09, 0x55, 0x9f, 0xce, 0x81, 0xaf, 0x1d, 0xb8, 0x63, - 0xdb, 0x1c, 0x99, 0xbc, 0x07, 0x23, 0xcb, 0xb4, 0x45, 0x0f, 0x9c, 0xc8, 0x97, 0x5f, 0x37, 0xb7, - 0x6a, 0x48, 0xa0, 0x36, 0xe7, 0x62, 0x4c, 0x76, 0xca, 0xb1, 0xa9, 0x13, 0xfa, 0x9e, 0x7e, 0xca, - 0x09, 0x10, 0xa2, 0x9f, 0x72, 0x38, 0x0e, 0xf9, 0x83, 0x12, 0x8c, 0x56, 0x3d, 0x4f, 0x58, 0x0b, - 0x42, 0x21, 0xf5, 0xe9, 0x9b, 0xca, 0xbc, 0xb6, 0xee, 0xec, 0xd3, 0xd6, 0x9e, 0xd3, 0xea, 0xd0, - 0x70, 0xf1, 0x6b, 0xa6, 0x78, 0xfe, 0xbb, 0xe3, 0xca, 0xc7, 0x67, 0x38, 0xff, 0xc7, 0x86, 0xba, - 0x9d, 0xc0, 0x71, 0xa3, 0xf0, 0xe4, 0xb8, 0x32, 0xed, 0xc4, 0x15, 0xea, 0xdf, 0x8d, 0xd6, 0x8e, - 0x78, 0x69, 0x1f, 0xec, 0xb6, 0xb4, 0x93, 0x23, 0x38, 0x57, 0x0d, 0xc3, 0xce, 0x11, 0xad, 0x45, - 0x4e, 0x10, 0xb1, 0x63, 0x21, 0xae, 0x0f, 0xc5, 0x67, 0xc6, 0xb7, 0x7e, 0x7e, 0x5c, 0x29, 0x31, - 0x5d, 0xd7, 0x41, 0x52, 0xa6, 0x2b, 0x05, 0x51, 0x3d, 0x72, 0xf5, 0xdd, 0x09, 0x4f, 0x8f, 0x49, - 0xde, 0xd6, 0x6b, 0x4a, 0x9f, 0x58, 0x5b, 0xce, 0x1b, 0x71, 0x6b, 0x09, 0xe6, 0xef, 0xd3, 0xc8, - 0xa6, 0x21, 0x8d, 0xe4, 0x37, 0x82, 0x33, 0x3c, 0xb6, 0xd8, 0x0d, 0xe1, 0x6f, 0x45, 0x8c, 0xc3, - 0xcf, 0xbf, 0x0b, 0x59, 0x62, 0xfd, 0x6f, 0x25, 0xa8, 0x2c, 0x05, 0x94, 0xab, 0x89, 0x39, 0x8c, - 0x8a, 0xd7, 0xae, 0x79, 0xe8, 0xdf, 0x79, 0xde, 0x96, 0x87, 0x6d, 0x2c, 0x65, 0x83, 0x62, 0x23, - 0xf4, 0x94, 0x96, 0x0b, 0xeb, 0x31, 0x4c, 0xdb, 0xd4, 0xa3, 0xcf, 0x9c, 0xfd, 0x16, 0x35, 0x0e, - 0xff, 0x15, 0x18, 0xe0, 0x1f, 0x7a, 0xaa, 0x0b, 0x1c, 0x7e, 0x36, 0x43, 0x8a, 0x35, 0x0e, 0xa3, - 0xdb, 0xae, 0x77, 0x20, 0xb8, 0x5b, 0x7f, 0xda, 0x07, 0x63, 0xfc, 0xb7, 0xd0, 0x7c, 0x13, 0xbb, - 0x57, 0xe9, 0x34, 0xbb, 0xd7, 0x07, 0x30, 0xce, 0x96, 0x7f, 0x1a, 0xec, 0xd1, 0x80, 0xed, 0x9a, - 0x42, 0x12, 0xa8, 0xc5, 0x87, 0x58, 0x50, 0x7f, 0xca, 0x4b, 0x6c, 0x13, 0x91, 0xac, 0xc3, 0x04, - 0x07, 0xdc, 0xa3, 0x4e, 0xd4, 0x89, 0x0d, 0x11, 0xe7, 0x84, 0xba, 0x2b, 0xc1, 0x7c, 0x6a, 0x0a, - 0x5e, 0x8f, 0x05, 0xd0, 0x4e, 0xd0, 0x92, 0xcf, 0xe0, 0xdc, 0x76, 0xe0, 0x7f, 0xf3, 0x5c, 0xdb, - 0xaf, 0xf9, 0xd7, 0xc9, 0x15, 0x63, 0x56, 0x54, 0xd7, 0x77, 0xed, 0x24, 0x36, 0x79, 0x1b, 0x86, - 0xd7, 0xc2, 0x45, 0x3f, 0x70, 0xbd, 0x03, 0xfc, 0x46, 0x87, 0xb9, 0xf5, 0xd6, 0x0d, 0xeb, 0xfb, - 0x08, 0xb4, 0x55, 0x71, 0xc2, 0xce, 0x38, 0xd4, 0xdd, 0xce, 0x78, 0x1b, 0x60, 0xdd, 0x77, 0x9a, - 0xd5, 0x56, 0x6b, 0xa9, 0x1a, 0xa2, 0x15, 0x40, 0xec, 0x47, 0x2d, 0xdf, 0x69, 0xd6, 0x9d, 0x56, - 0xab, 0xde, 0x70, 0x42, 0x5b, 0xc3, 0x79, 0xd0, 0x3f, 0x3c, 0x58, 0x1e, 0xb2, 0xcf, 0xad, 0xbb, - 0x0d, 0xea, 0x85, 0xf4, 0x91, 0x13, 0x78, 0xae, 0x77, 0x10, 0x5a, 0xff, 0xea, 0x1c, 0x0c, 0xab, - 0x2e, 0xdf, 0xd4, 0x75, 0x76, 0xb1, 0xcb, 0xe1, 0xe8, 0xc7, 0x96, 0x0a, 0x5b, 0xc3, 0x20, 0x17, - 0x51, 0x8b, 0x17, 0xfb, 0xeb, 0x10, 0x9b, 0x8d, 0x4e, 0xbb, 0x6d, 0x33, 0x18, 0xfb, 0xca, 0x96, - 0x17, 0x51, 0xfe, 0xc3, 0xfc, 0x2b, 0x6b, 0xee, 0xdb, 0xbd, 0xcb, 0x8b, 0x6c, 0x7a, 0x6f, 0xad, - 0x2d, 0x2f, 0xa1, 0x28, 0x87, 0xf9, 0xf4, 0xf6, 0xdd, 0x66, 0xc3, 0x46, 0x28, 0x2b, 0xad, 0x55, - 0x37, 0xd6, 0x85, 0xb8, 0xb0, 0x34, 0x74, 0x8e, 0x5a, 0x36, 0x42, 0x99, 0xde, 0xc7, 0x0f, 0x9d, - 0x4b, 0xbe, 0x17, 0x05, 0x7e, 0x2b, 0x44, 0xe5, 0x64, 0x98, 0x0f, 0xa7, 0x38, 0xad, 0x36, 0x44, - 0x91, 0x9d, 0x40, 0x25, 0x8f, 0x60, 0xa6, 0xda, 0x7c, 0xea, 0x78, 0x0d, 0xda, 0xe4, 0x25, 0x8f, - 0xfc, 0xe0, 0xc9, 0xe3, 0x96, 0xff, 0x2c, 0x44, 0x79, 0x0f, 0x0b, 0xe3, 0x8e, 0x40, 0x91, 0x87, - 0xdf, 0x67, 0x12, 0xc9, 0xce, 0xa3, 0x66, 0x9f, 0xd4, 0x52, 0xcb, 0xef, 0x34, 0xc5, 0x28, 0xe0, - 0x27, 0xd5, 0x60, 0x00, 0x9b, 0xc3, 0x99, 0x94, 0x56, 0x6b, 0x1b, 0x68, 0x4a, 0x11, 0x52, 0x3a, - 0x0c, 0x8f, 0x6c, 0x06, 0x23, 0x6f, 0xc0, 0x90, 0x54, 0x61, 0xb9, 0xa5, 0x17, 0x2d, 0x8c, 0x52, - 0x75, 0x95, 0x65, 0xec, 0x93, 0xb0, 0x69, 0xc3, 0x7f, 0x4a, 0x83, 0xe7, 0x4b, 0x7e, 0x93, 0xca, - 0x83, 0xbf, 0x38, 0xd8, 0xf2, 0x82, 0x7a, 0x83, 0x95, 0xd8, 0x26, 0x22, 0xab, 0x80, 0xef, 0x81, - 0xec, 0x78, 0xaf, 0x2a, 0xe0, 0x7b, 0x64, 0x68, 0xcb, 0x32, 0xb2, 0x0c, 0xe7, 0xab, 0x9d, 0xc8, - 0x3f, 0x72, 0x22, 0xb7, 0xb1, 0xdb, 0x3e, 0x08, 0x1c, 0x56, 0x49, 0x19, 0x09, 0x50, 0xa5, 0x77, - 0x64, 0x61, 0xbd, 0x23, 0x4a, 0xed, 0x34, 0x01, 0x79, 0x1f, 0xc6, 0xd6, 0x42, 0x6e, 0xdc, 0x71, - 0x42, 0xda, 0xc4, 0x13, 0xba, 0x68, 0xa5, 0x1b, 0xd6, 0xd1, 0xd4, 0x53, 0x67, 0x87, 0x80, 0xa6, - 0x6d, 0xe0, 0x11, 0x0b, 0x06, 0xab, 0x61, 0xe8, 0x86, 0x11, 0x1e, 0xbc, 0x87, 0x17, 0xe1, 0xe4, - 0xb8, 0x32, 0xe8, 0x20, 0xc4, 0x16, 0x25, 0xe4, 0x11, 0x8c, 0x2e, 0x53, 0xa6, 0x13, 0xee, 0x04, - 0x9d, 0x30, 0xc2, 0x63, 0xf4, 0xe8, 0xc2, 0x45, 0xf1, 0x61, 0x6b, 0x25, 0x62, 0x2e, 0x73, 0x6d, - 0xaf, 0x89, 0xf0, 0x7a, 0xc4, 0x0a, 0xf4, 0x5d, 0x4b, 0xc3, 0x67, 0x0a, 0xaf, 0xa0, 0x59, 0x75, - 0x9b, 0xec, 0x53, 0x9d, 0xc2, 0x36, 0xa0, 0xc2, 0x2b, 0xd6, 0x86, 0xfa, 0x21, 0x96, 0xe8, 0x0a, - 0xaf, 0x41, 0x42, 0x1a, 0x29, 0x7b, 0xe1, 0xb4, 0x61, 0x13, 0x32, 0x0b, 0x65, 0x13, 0xcf, 0x68, - 0x4d, 0xfc, 0x04, 0x46, 0x97, 0x3a, 0x61, 0xe4, 0x1f, 0xed, 0x1c, 0xd2, 0x23, 0x3a, 0x7b, 0x21, - 0x56, 0xeb, 0x1b, 0x08, 0xae, 0x47, 0x0c, 0xae, 0x77, 0x53, 0x43, 0x27, 0x9f, 0x03, 0x91, 0xfa, - 0xf9, 0x7d, 0x36, 0x3f, 0x3c, 0x36, 0x97, 0x67, 0x67, 0xb0, 0xaf, 0xa8, 0x94, 0x4b, 0xb5, 0xbe, - 0x7e, 0xa0, 0x8a, 0x75, 0x8b, 0x4f, 0x9a, 0x98, 0x35, 0x88, 0x37, 0xf1, 0x7e, 0xe0, 0xb4, 0x0f, - 0x67, 0x67, 0x63, 0x2d, 0x5b, 0x74, 0xea, 0x80, 0xc1, 0x0d, 0x6d, 0x21, 0x46, 0x27, 0x35, 0x00, - 0xfe, 0x73, 0x9d, 0x0d, 0xfc, 0x45, 0x94, 0xd7, 0xac, 0x21, 0x2f, 0x56, 0x20, 0x65, 0x75, 0x11, - 0x75, 0x10, 0xce, 0xb6, 0xe5, 0x1a, 0xa3, 0xa9, 0xb1, 0x21, 0x4f, 0xa0, 0xcc, 0x7f, 0x6d, 0xf8, - 0x9e, 0x1b, 0xf1, 0xa5, 0x77, 0xce, 0x30, 0xe6, 0x24, 0x8b, 0x65, 0x05, 0x68, 0x44, 0x13, 0x15, - 0x1c, 0xa9, 0x52, 0xad, 0x9a, 0x14, 0x63, 0xb2, 0x0d, 0xa3, 0xdb, 0x81, 0xdf, 0xec, 0x34, 0x22, - 0xdc, 0xb0, 0x2f, 0xa1, 0xa2, 0x48, 0x44, 0x3d, 0x5a, 0x09, 0x97, 0x49, 0x9b, 0x03, 0xea, 0x6c, - 0x33, 0xd7, 0x65, 0xa2, 0x21, 0x92, 0x45, 0x18, 0xdc, 0xf6, 0x5b, 0x6e, 0xe3, 0xf9, 0xec, 0x3c, - 0x36, 0x7a, 0x4a, 0x32, 0x43, 0xa0, 0x6c, 0x2a, 0x6a, 0x87, 0x6d, 0x04, 0xe9, 0xda, 0x21, 0x47, - 0x22, 0x55, 0x18, 0xff, 0x9c, 0x4d, 0x18, 0xd7, 0xf7, 0x3c, 0xc7, 0x0d, 0xe8, 0xec, 0x65, 0x1c, - 0x17, 0x34, 0x74, 0xfe, 0x44, 0x2f, 0xd0, 0xa7, 0xb3, 0x41, 0x41, 0xd6, 0xe0, 0xdc, 0x5a, 0x58, - 0x8b, 0x02, 0xb7, 0x4d, 0x37, 0x1c, 0xcf, 0x39, 0xa0, 0xcd, 0xd9, 0x2b, 0xb1, 0xa5, 0xd1, 0x0d, - 0xeb, 0x21, 0x96, 0xd5, 0x8f, 0x78, 0xa1, 0x6e, 0x69, 0x4c, 0xd0, 0x91, 0x2f, 0x60, 0x6a, 0xe5, - 0x9b, 0x88, 0xcd, 0x98, 0x56, 0xb5, 0xd3, 0x74, 0xa3, 0x5a, 0xe4, 0x07, 0xce, 0x01, 0x9d, 0xad, - 0x20, 0xbf, 0xd7, 0x4f, 0x8e, 0x2b, 0x57, 0xa9, 0x28, 0xaf, 0x3b, 0x0c, 0xa1, 0x1e, 0x72, 0x0c, - 0xfd, 0xfe, 0x30, 0x8b, 0x03, 0x93, 0x7e, 0xad, 0xd3, 0x66, 0x8a, 0x2b, 0x4a, 0xff, 0xaa, 0x21, - 0x7d, 0xad, 0x84, 0x4b, 0x3f, 0xe4, 0x80, 0x94, 0xf4, 0x35, 0x44, 0x62, 0x03, 0x79, 0xe0, 0xbb, - 0x5e, 0xb5, 0x11, 0xb9, 0x4f, 0xa9, 0x38, 0xb2, 0x87, 0xb3, 0xd7, 0xb0, 0xa5, 0x68, 0x15, 0xfd, - 0x75, 0xdf, 0xf5, 0xea, 0x0e, 0x16, 0xd7, 0xc5, 0x01, 0xdf, 0xb0, 0x8a, 0xa6, 0xa9, 0xc9, 0x8f, - 0xe0, 0xc2, 0x86, 0xbf, 0xef, 0xb6, 0x28, 0x5f, 0x72, 0xb8, 0x58, 0xd0, 0xbe, 0x67, 0x21, 0x5f, - 0xb4, 0x8a, 0x1e, 0x21, 0x46, 0x5d, 0xac, 0x56, 0x47, 0x0a, 0x47, 0xb7, 0x8a, 0x66, 0x73, 0x79, - 0xd0, 0x3f, 0x3c, 0x5a, 0x1e, 0xe3, 0x37, 0x67, 0x0f, 0xfa, 0x87, 0xc7, 0xcb, 0x13, 0xd6, 0x1f, - 0x96, 0x80, 0xa4, 0xd7, 0x43, 0x72, 0x0b, 0x86, 0xa8, 0xc7, 0xd4, 0xc1, 0xa6, 0xd8, 0xd7, 0x51, - 0x8b, 0x11, 0x20, 0xdd, 0xbc, 0x27, 0x40, 0xe4, 0x73, 0x98, 0xe4, 0x0d, 0x92, 0x2b, 0x77, 0xcb, - 0x3d, 0x72, 0x23, 0xdc, 0xeb, 0x07, 0xf8, 0x8a, 0x91, 0x51, 0xac, 0x1f, 0xe3, 0x45, 0x31, 0xae, - 0xf3, 0xeb, 0xac, 0xd0, 0xea, 0xc0, 0x74, 0xe6, 0x4a, 0x48, 0x36, 0x60, 0xfa, 0xc8, 0xf7, 0xa2, - 0xc3, 0xd6, 0x73, 0xb9, 0x10, 0x8a, 0xda, 0x4a, 0x58, 0x1b, 0x7e, 0xfc, 0x99, 0x08, 0xf6, 0xa4, - 0x00, 0x0b, 0x8e, 0x58, 0xcf, 0x83, 0xfe, 0xe1, 0xde, 0x72, 0x9f, 0xea, 0x89, 0x65, 0xc3, 0xf9, - 0xd4, 0x82, 0x42, 0xbe, 0x0f, 0x63, 0x0d, 0xd4, 0xd3, 0x8d, 0x9a, 0xf8, 0x72, 0xaa, 0xc1, 0xf5, - 0xb9, 0xc2, 0xe1, 0xbc, 0x2b, 0x7f, 0x52, 0x82, 0x99, 0x9c, 0xa5, 0xe4, 0xec, 0xa2, 0xfe, 0x12, - 0x2e, 0x1c, 0x39, 0xdf, 0xd4, 0x03, 0x3c, 0x86, 0xd5, 0x03, 0xc7, 0x4b, 0x48, 0x1b, 0x3f, 0x93, - 0x6c, 0x0c, 0xdd, 0xf7, 0xe0, 0xc8, 0xf9, 0xc6, 0x46, 0x04, 0x9b, 0x95, 0xf3, 0x76, 0xfe, 0x00, - 0xc6, 0x8d, 0xc5, 0xe3, 0xcc, 0x8d, 0xb3, 0xee, 0xc0, 0x79, 0x76, 0x50, 0x8d, 0xe8, 0xa9, 0xcd, - 0x2f, 0xd6, 0x36, 0x40, 0x8d, 0x1e, 0x39, 0xed, 0x43, 0x9f, 0x29, 0x95, 0x8b, 0xfa, 0x2f, 0x71, - 0x7c, 0x27, 0xe2, 0x38, 0xad, 0x0a, 0xf6, 0xee, 0x72, 0x45, 0x33, 0x54, 0x98, 0xb6, 0x46, 0x65, - 0xfd, 0x45, 0x2f, 0x10, 0xf1, 0xf5, 0x07, 0xd4, 0x39, 0x92, 0xcd, 0xf8, 0x10, 0xc6, 0xf8, 0x61, - 0x8b, 0x83, 0xb1, 0x39, 0xa3, 0x0b, 0x93, 0x62, 0x11, 0xd0, 0x8b, 0x56, 0x7b, 0x6c, 0x03, 0x95, - 0x91, 0xda, 0x94, 0x9f, 0x12, 0x91, 0xb4, 0xd7, 0x20, 0xd5, 0x8b, 0x18, 0xa9, 0xfe, 0x9b, 0x7c, - 0x06, 0x13, 0x4b, 0xfe, 0x51, 0x9b, 0xc9, 0x44, 0x10, 0xf7, 0x89, 0x13, 0xb8, 0xa8, 0xd7, 0x28, - 0x5c, 0xed, 0xb1, 0x13, 0xe8, 0x64, 0x13, 0x26, 0xef, 0xb5, 0x3a, 0xe1, 0x61, 0xd5, 0x6b, 0x2e, - 0xb5, 0xfc, 0x50, 0x72, 0xe9, 0x17, 0x27, 0x60, 0x71, 0x58, 0x49, 0x63, 0xac, 0xf6, 0xd8, 0x59, - 0x84, 0xe4, 0x0d, 0x18, 0x58, 0x79, 0xca, 0xd6, 0x14, 0x79, 0x03, 0x2d, 0x1c, 0x64, 0xb6, 0x3c, - 0xba, 0xf5, 0x78, 0xb5, 0xc7, 0xe6, 0xa5, 0x8b, 0x23, 0x30, 0x24, 0x0f, 0x6a, 0xb7, 0x98, 0xbe, - 0xa7, 0xc4, 0x59, 0x8b, 0x9c, 0xa8, 0x13, 0x92, 0x39, 0x18, 0xde, 0x6d, 0xb3, 0xf3, 0x83, 0x3c, - 0xe1, 0xda, 0xea, 0xb7, 0xf5, 0x8e, 0x29, 0x69, 0x32, 0xaf, 0xdb, 0x3d, 0x39, 0x72, 0x0c, 0xb0, - 0x56, 0x4d, 0xe1, 0x16, 0x63, 0x1b, 0xf5, 0xf6, 0x26, 0xea, 0x2d, 0x27, 0x65, 0x6d, 0x4d, 0x67, - 0x0a, 0xcf, 0xfa, 0x02, 0xae, 0xec, 0xb6, 0x43, 0x1a, 0x44, 0xd5, 0x76, 0xbb, 0xe5, 0x36, 0xf8, - 0x0d, 0x08, 0x1e, 0xe8, 0xe4, 0x64, 0x79, 0x1f, 0x06, 0x39, 0x40, 0x4c, 0x13, 0x39, 0x07, 0xab, - 0xed, 0xb6, 0x38, 0x46, 0xde, 0xe5, 0x9a, 0x27, 0x3f, 0x18, 0xda, 0x02, 0xdb, 0xfa, 0xbd, 0x12, - 0x5c, 0xe1, 0x5f, 0x40, 0x2e, 0xeb, 0xef, 0xc0, 0x08, 0xfa, 0xa7, 0xb4, 0x9d, 0x86, 0xfc, 0x26, - 0xb8, 0xa3, 0x8e, 0x04, 0xda, 0x71, 0xb9, 0xe6, 0xf9, 0xd3, 0x9b, 0xef, 0xf9, 0x23, 0x3f, 0xb0, - 0xbe, 0xcc, 0x0f, 0xec, 0x73, 0xb0, 0x44, 0x8b, 0x5a, 0xad, 0x54, 0xa3, 0xc2, 0x17, 0x69, 0x95, - 0xf5, 0x9f, 0x7b, 0x61, 0xe6, 0x3e, 0xf5, 0x68, 0xe0, 0x60, 0x3f, 0x0d, 0x83, 0x85, 0xee, 0x03, - 0x50, 0x2a, 0xf4, 0x01, 0xa8, 0x48, 0x13, 0x50, 0x2f, 0x9a, 0x80, 0x52, 0xee, 0x0c, 0xec, 0x2c, - 0xb4, 0x6b, 0xaf, 0x89, 0x6e, 0xe1, 0x59, 0xa8, 0x13, 0xb8, 0x36, 0x83, 0x91, 0xb5, 0xd8, 0x7f, - 0xa0, 0xbf, 0xab, 0x2d, 0x68, 0x52, 0xdc, 0xa7, 0x0e, 0x09, 0xff, 0x01, 0xd3, 0x6b, 0x60, 0x13, - 0x06, 0xb9, 0xe5, 0x0a, 0x6f, 0x19, 0x46, 0x17, 0x6e, 0x88, 0x6f, 0x2a, 0xa7, 0x83, 0xc2, 0xcc, - 0xb5, 0xe2, 0x45, 0xc1, 0x73, 0x3e, 0x05, 0x22, 0x04, 0xd8, 0x82, 0xcb, 0xdc, 0xe7, 0x30, 0xaa, - 0xa1, 0x90, 0x32, 0xf4, 0x3d, 0x11, 0xbe, 0x13, 0x23, 0x36, 0xfb, 0x93, 0xbc, 0x03, 0x03, 0x4f, - 0x9d, 0x56, 0x87, 0x8a, 0x65, 0xe4, 0x42, 0x6c, 0x8b, 0x63, 0xea, 0x90, 0x77, 0xc0, 0x8d, 0x71, - 0x36, 0x47, 0xfa, 0xa8, 0xf7, 0x83, 0x92, 0xf5, 0x31, 0xcc, 0xa6, 0x5b, 0x23, 0xac, 0x26, 0xdd, - 0x8c, 0x34, 0xd6, 0x32, 0x4c, 0xdd, 0xa7, 0x11, 0x4e, 0x5c, 0xfc, 0x88, 0x34, 0xd7, 0x8e, 0xc4, - 0x77, 0x26, 0x57, 0x55, 0x79, 0x1b, 0xa1, 0x7f, 0xa5, 0x35, 0x98, 0x4e, 0x70, 0x11, 0xf5, 0x7f, - 0x04, 0x43, 0x02, 0xa4, 0x56, 0x54, 0xe1, 0x4a, 0x47, 0xf7, 0x45, 0xc1, 0xde, 0x02, 0x9f, 0xb7, - 0x82, 0xb3, 0x2d, 0x09, 0xac, 0x43, 0xb8, 0xc0, 0xb6, 0xd9, 0x98, 0xab, 0x9a, 0x8e, 0x97, 0x60, - 0xa4, 0xcd, 0x14, 0x85, 0xd0, 0xfd, 0x29, 0x9f, 0x46, 0x03, 0xf6, 0x30, 0x03, 0xd4, 0xdc, 0x9f, - 0x52, 0x72, 0x19, 0x00, 0x0b, 0xb1, 0x9b, 0x62, 0x15, 0x40, 0x74, 0x6e, 0x95, 0x22, 0x80, 0x3e, - 0x34, 0x7c, 0xde, 0xd8, 0xf8, 0xb7, 0x15, 0xc0, 0x4c, 0xaa, 0x26, 0xd1, 0x81, 0x5b, 0x30, 0x2c, - 0xf5, 0xb3, 0x84, 0xbd, 0x58, 0xef, 0x81, 0xad, 0x90, 0xc8, 0x9b, 0x70, 0xce, 0xa3, 0xdf, 0x44, - 0xf5, 0x54, 0x1b, 0xc6, 0x19, 0x78, 0x5b, 0xb6, 0xc3, 0xfa, 0x35, 0xb4, 0x11, 0xd6, 0x3c, 0xff, - 0xd9, 0xe3, 0x96, 0xf3, 0x84, 0xa6, 0x2a, 0xfe, 0x3e, 0x0c, 0xd7, 0xba, 0x57, 0xcc, 0x3f, 0x1f, - 0x59, 0xb9, 0xad, 0x48, 0xac, 0x16, 0xcc, 0xb1, 0x2e, 0xd5, 0xaa, 0x1b, 0xeb, 0x6b, 0xcd, 0xed, - 0x6f, 0x5b, 0x80, 0x4f, 0xe1, 0x52, 0x66, 0x6d, 0xdf, 0xb6, 0x10, 0xff, 0x59, 0x1f, 0xcc, 0xf0, - 0xcd, 0x24, 0x3d, 0x83, 0x4f, 0xbf, 0xd4, 0xfc, 0x4a, 0x6e, 0xd2, 0x6e, 0x67, 0xdc, 0xa4, 0x21, - 0x89, 0x7e, 0x93, 0x66, 0xdc, 0x9f, 0x7d, 0x90, 0x7d, 0x7f, 0x86, 0x46, 0x10, 0xf3, 0xfe, 0x2c, - 0x79, 0x6b, 0xb6, 0x92, 0x7f, 0x6b, 0x86, 0x77, 0x08, 0x19, 0xb7, 0x66, 0x19, 0x77, 0x65, 0x49, - 0x57, 0x86, 0xe1, 0x57, 0xea, 0xca, 0xc0, 0x55, 0x6b, 0x6b, 0x0f, 0x66, 0xd3, 0x03, 0xf8, 0x0a, - 0x16, 0x8f, 0x3f, 0x2b, 0xc1, 0x65, 0xa1, 0x66, 0x24, 0x3e, 0xb1, 0xb3, 0xcf, 0x8f, 0xf7, 0x60, - 0x4c, 0xd0, 0xee, 0xc4, 0x53, 0x71, 0xf1, 0xfc, 0xc9, 0x71, 0x65, 0x5c, 0x2e, 0x87, 0x7c, 0x4d, - 0x35, 0xd0, 0xc8, 0x7b, 0x30, 0x8c, 0x7f, 0xc4, 0x56, 0x76, 0x76, 0xfa, 0x18, 0x41, 0xd4, 0x7a, - 0xd2, 0xd6, 0xae, 0x50, 0xad, 0xaf, 0xe1, 0x4a, 0x5e, 0xc3, 0x5f, 0x81, 0x5c, 0xfe, 0x79, 0x09, - 0x2e, 0x09, 0xf6, 0xc6, 0xc7, 0xfa, 0x42, 0xeb, 0xfe, 0x19, 0x5c, 0xfa, 0x1e, 0xc0, 0x28, 0xab, - 0x50, 0xb6, 0xbb, 0x4f, 0x6c, 0x6e, 0x42, 0x77, 0x8f, 0x4b, 0x96, 0x9d, 0xc8, 0x11, 0xae, 0x08, - 0xce, 0x51, 0x4b, 0x9e, 0x8d, 0x6d, 0x9d, 0xd8, 0xfa, 0x0a, 0xe6, 0xb3, 0xbb, 0xf0, 0x0a, 0xe4, - 0xf3, 0x00, 0xe6, 0x32, 0x96, 0xe5, 0x17, 0xdb, 0x15, 0xbf, 0x84, 0x4b, 0x99, 0xbc, 0x5e, 0x41, - 0x33, 0x57, 0xd9, 0x9e, 0x1f, 0xbd, 0x82, 0x21, 0xb4, 0x1e, 0xc1, 0xc5, 0x0c, 0x4e, 0xaf, 0xa0, - 0x89, 0xf7, 0x61, 0x46, 0xe9, 0xba, 0x2f, 0xd5, 0xc2, 0x0d, 0xb8, 0xcc, 0x19, 0xbd, 0x9a, 0x51, - 0x79, 0x08, 0x97, 0x04, 0xbb, 0x57, 0x20, 0xbd, 0x55, 0x98, 0x8f, 0x8f, 0xb4, 0x19, 0x9a, 0xca, - 0xa9, 0x17, 0x19, 0x6b, 0x1d, 0xae, 0xc6, 0x9c, 0x72, 0xb6, 0xed, 0xd3, 0x73, 0xe3, 0x0a, 0x59, - 0x3c, 0x4a, 0xaf, 0x64, 0x44, 0x1f, 0xc1, 0x05, 0x83, 0xe9, 0x2b, 0x53, 0x56, 0xd6, 0x60, 0x92, - 0x33, 0x36, 0x95, 0xd7, 0x05, 0x5d, 0x79, 0x1d, 0x5d, 0x38, 0x1f, 0xb3, 0x44, 0xf0, 0xde, 0xdd, - 0x0c, 0x7d, 0x76, 0x03, 0xf5, 0x59, 0x89, 0x12, 0xb7, 0xf0, 0x3d, 0x18, 0xe4, 0x10, 0xd1, 0xbe, - 0x0c, 0x66, 0x5c, 0x5d, 0xe7, 0x64, 0x02, 0xd9, 0xfa, 0x11, 0x5c, 0xe6, 0x67, 0xc1, 0xf8, 0xaa, - 0xca, 0x3c, 0xaf, 0x7d, 0x3f, 0x71, 0x14, 0xbc, 0x28, 0xf8, 0x26, 0xf1, 0x73, 0x4e, 0x84, 0xfb, - 0x72, 0x6e, 0xe7, 0xf1, 0x3f, 0xd5, 0xe3, 0x0e, 0x79, 0xc4, 0xeb, 0xcd, 0x3c, 0xe2, 0xbd, 0x06, - 0xd7, 0xd4, 0x11, 0x2f, 0x59, 0x8d, 0x9c, 0x5a, 0xd6, 0x57, 0x70, 0x89, 0x77, 0x54, 0xba, 0x57, - 0x99, 0xcd, 0xf8, 0x38, 0xd1, 0xcd, 0x19, 0xd1, 0x4d, 0x13, 0x3b, 0xa7, 0x93, 0xff, 0x67, 0x49, - 0x7e, 0x72, 0xd9, 0xcc, 0x7f, 0xd5, 0x67, 0xde, 0x4d, 0xa8, 0x28, 0x81, 0x98, 0x2d, 0x7a, 0xb1, - 0x03, 0xef, 0x06, 0x4c, 0xeb, 0x6c, 0xdc, 0x06, 0xdd, 0xbb, 0x83, 0x77, 0x08, 0xef, 0xb2, 0xcf, - 0x02, 0x01, 0x72, 0xda, 0xcd, 0x66, 0xc8, 0x0d, 0xf1, 0x6d, 0x85, 0x69, 0xd5, 0x61, 0x3e, 0x3d, - 0x14, 0x6e, 0x43, 0xfa, 0xdc, 0x92, 0xcf, 0xd8, 0x27, 0x8c, 0x10, 0x31, 0x18, 0xb9, 0x4c, 0xe5, - 0x77, 0xcc, 0xc9, 0x25, 0x95, 0x65, 0xc9, 0xa5, 0x26, 0xd1, 0x7f, 0x56, 0xbb, 0x9c, 0x0f, 0xbf, - 0x09, 0x44, 0x16, 0x2d, 0xd5, 0x6c, 0x59, 0xf5, 0x45, 0xe8, 0x5b, 0xaa, 0xd9, 0xc2, 0xd5, 0x1f, - 0xcf, 0xdc, 0x8d, 0x30, 0xb0, 0x19, 0x2c, 0xa9, 0x13, 0xf7, 0x9e, 0x42, 0x27, 0x7e, 0xd0, 0x3f, - 0xdc, 0x57, 0xee, 0xb7, 0x49, 0xcd, 0x3d, 0xf0, 0x1e, 0xb9, 0xd1, 0xa1, 0xaa, 0xb0, 0x6a, 0xfd, - 0x10, 0x26, 0x8d, 0xea, 0xc5, 0x57, 0x5c, 0xf8, 0x46, 0x81, 0xbc, 0x09, 0x43, 0x4b, 0x55, 0xf4, - 0x51, 0x40, 0xa3, 0xc1, 0x18, 0x5f, 0x6f, 0x1a, 0x4e, 0x1d, 0x1f, 0xc0, 0xd9, 0xb2, 0xd0, 0xfa, - 0x07, 0xfd, 0x1a, 0x77, 0xed, 0xe5, 0x47, 0x41, 0xef, 0xee, 0x00, 0xf0, 0x19, 0xa2, 0x75, 0x8e, - 0x29, 0x80, 0xa3, 0xe2, 0xea, 0x9f, 0x2f, 0xc9, 0xb6, 0x86, 0x74, 0xda, 0x97, 0x21, 0xc2, 0x17, - 0x93, 0x13, 0xc9, 0xc7, 0x50, 0xca, 0x17, 0x53, 0xb0, 0x0e, 0x6d, 0x1d, 0x89, 0xfc, 0x28, 0xe9, - 0xc0, 0x3c, 0x80, 0x57, 0x16, 0xaf, 0xcb, 0x3b, 0xcc, 0x74, 0xdf, 0xce, 0xe6, 0xc3, 0xfc, 0x0c, - 0xa6, 0x19, 0xad, 0xfb, 0x18, 0x55, 0xfb, 0x95, 0x6f, 0x22, 0xea, 0xf1, 0xb5, 0x7d, 0x10, 0xeb, - 0x79, 0xa3, 0xa0, 0x9e, 0x18, 0x59, 0x58, 0xc0, 0x63, 0x3e, 0x75, 0xaa, 0xca, 0xec, 0x6c, 0xfe, - 0x38, 0x89, 0xec, 0xf5, 0x15, 0xaf, 0xd9, 0xf6, 0x5d, 0x75, 0x64, 0xe1, 0x93, 0x28, 0x68, 0xd5, - 0xa9, 0x80, 0xdb, 0x3a, 0x92, 0xf5, 0x66, 0xa1, 0x87, 0xef, 0x30, 0xf4, 0xef, 0x2c, 0xed, 0xac, - 0x97, 0x4b, 0xd6, 0x2d, 0x00, 0xad, 0x26, 0x80, 0xc1, 0xcd, 0x2d, 0x7b, 0xa3, 0xba, 0x5e, 0xee, - 0x21, 0xd3, 0x70, 0xfe, 0xd1, 0xda, 0xe6, 0xf2, 0xd6, 0xa3, 0x5a, 0xbd, 0xb6, 0x51, 0xb5, 0x77, - 0x96, 0xaa, 0xf6, 0x72, 0xb9, 0x64, 0x7d, 0x0d, 0x53, 0x66, 0x0f, 0x5f, 0xe9, 0x24, 0x8c, 0x60, - 0x52, 0xe9, 0x33, 0x0f, 0x1e, 0xed, 0x68, 0xee, 0x81, 0xe2, 0xf8, 0x95, 0x74, 0x73, 0x11, 0x07, - 0x35, 0xf1, 0x19, 0x69, 0x48, 0xe4, 0x6d, 0xae, 0x16, 0x24, 0xdf, 0xf6, 0x31, 0xb5, 0xa0, 0x1e, - 0xeb, 0x05, 0xb8, 0xf4, 0x7d, 0x0f, 0xa6, 0xcc, 0x5a, 0x4f, 0x6b, 0x27, 0x7a, 0x1d, 0xfd, 0x26, - 0x35, 0xd7, 0x7f, 0x42, 0x74, 0xc3, 0xbd, 0x58, 0x59, 0xbf, 0x07, 0x65, 0x81, 0x15, 0xef, 0xbc, - 0xaf, 0x49, 0x43, 0x5e, 0x29, 0xe3, 0x99, 0x92, 0x74, 0xd0, 0xf5, 0xa1, 0xcc, 0x56, 0x4c, 0x41, - 0xc9, 0x2b, 0x98, 0x82, 0x81, 0xf5, 0xf8, 0x42, 0xc5, 0xe6, 0x3f, 0xd0, 0x03, 0x3e, 0x72, 0x82, - 0x48, 0x3a, 0x15, 0x8d, 0xd8, 0xea, 0x37, 0x79, 0x1b, 0x06, 0xef, 0xb9, 0xad, 0x48, 0x18, 0x27, - 0xe2, 0x4d, 0x9e, 0xb1, 0xe5, 0x05, 0xb6, 0x40, 0xb0, 0x6c, 0x38, 0xaf, 0x55, 0x78, 0x86, 0xa6, - 0x92, 0x59, 0x18, 0xda, 0xa4, 0xdf, 0x68, 0xf5, 0xcb, 0x9f, 0xd6, 0xfb, 0x70, 0x5e, 0x38, 0x6c, - 0x69, 0x62, 0xba, 0x26, 0x5e, 0x53, 0x96, 0x8c, 0x27, 0x5d, 0x82, 0x25, 0x16, 0x31, 0xba, 0xdd, - 0x76, 0xf3, 0x05, 0xe9, 0xd8, 0x46, 0x71, 0x46, 0xba, 0xb7, 0xe4, 0x3d, 0x4c, 0xb7, 0xe1, 0xfc, - 0x8b, 0x12, 0xcc, 0x26, 0xce, 0xf9, 0x4b, 0x87, 0x4e, 0xab, 0x45, 0xbd, 0x03, 0x4a, 0xae, 0x43, - 0xff, 0xce, 0xd6, 0xce, 0xb6, 0xb0, 0x53, 0xca, 0xfb, 0x65, 0x06, 0x52, 0x38, 0x36, 0x62, 0x90, - 0x87, 0x70, 0x5e, 0xba, 0x64, 0xaa, 0x22, 0x31, 0x42, 0x97, 0x8b, 0x1d, 0x3c, 0xd3, 0x74, 0xe4, - 0x5d, 0x61, 0x94, 0xf8, 0x49, 0xc7, 0x0d, 0x68, 0x13, 0x6d, 0x2f, 0xf1, 0x65, 0xad, 0x56, 0x62, - 0xeb, 0x68, 0xfc, 0xed, 0x9b, 0xf5, 0x07, 0x25, 0x98, 0xc9, 0xb1, 0x5b, 0x90, 0xb7, 0x8d, 0xee, - 0x4c, 0x6a, 0xdd, 0x91, 0x28, 0xab, 0x3d, 0xa2, 0x3f, 0x4b, 0x9a, 0x9f, 0x6a, 0xdf, 0x19, 0xfc, - 0x54, 0x57, 0x7b, 0x62, 0xdf, 0xd4, 0x45, 0x80, 0x61, 0x09, 0xb7, 0xce, 0xc1, 0xb8, 0x21, 0x37, - 0xcb, 0x82, 0x31, 0xbd, 0x66, 0x36, 0x38, 0x4b, 0x7e, 0x53, 0x0d, 0x0e, 0xfb, 0xdb, 0xfa, 0xfd, - 0x12, 0x4c, 0x61, 0x17, 0x0f, 0x5c, 0xb6, 0xf4, 0xc5, 0x12, 0x5a, 0x30, 0x7a, 0x32, 0x6f, 0xf4, - 0x24, 0x81, 0xab, 0xba, 0xf4, 0x51, 0xaa, 0x4b, 0xf3, 0x59, 0x5d, 0xc2, 0xe9, 0xed, 0xfa, 0x9e, - 0xd1, 0x13, 0xed, 0x32, 0xe8, 0x0f, 0x4b, 0x30, 0xa9, 0xb5, 0x49, 0xb5, 0xff, 0x8e, 0xd1, 0xa4, - 0x4b, 0x19, 0x4d, 0x4a, 0x09, 0x79, 0x31, 0xd5, 0xa2, 0xd7, 0x8b, 0x5a, 0xd4, 0x55, 0xc6, 0xff, - 0xb1, 0x04, 0xd3, 0x99, 0x32, 0x20, 0x17, 0x98, 0x6e, 0xdb, 0x08, 0x68, 0x24, 0xc4, 0x2b, 0x7e, - 0x31, 0xf8, 0x5a, 0x18, 0x76, 0x68, 0x20, 0xbe, 0x73, 0xf1, 0x8b, 0xbc, 0x0e, 0xe3, 0xdb, 0x34, - 0x70, 0xfd, 0x26, 0xf7, 0x60, 0xe6, 0xae, 0x81, 0xe3, 0xb6, 0x09, 0x24, 0xf3, 0x30, 0x52, 0x6d, - 0x1d, 0xf8, 0x81, 0x1b, 0x1d, 0xf2, 0xfb, 0xb8, 0x11, 0x3b, 0x06, 0x30, 0xde, 0xcb, 0xee, 0x01, - 0xbf, 0x56, 0x60, 0xc4, 0xe2, 0x17, 0x5b, 0x5c, 0xa4, 0xbd, 0x6e, 0x90, 0x2f, 0x2e, 0xd2, 0x18, - 0x77, 0x01, 0x06, 0x3f, 0xb7, 0x71, 0x12, 0xe0, 0x8b, 0x63, 0x5b, 0xfc, 0x22, 0x13, 0xe8, 0x83, - 0x8a, 0xef, 0x89, 0xd1, 0xf7, 0xf4, 0x23, 0x98, 0xca, 0x92, 0x6b, 0xd6, 0x14, 0x12, 0xb4, 0xbd, - 0x8a, 0xf6, 0x2b, 0x98, 0xac, 0x36, 0x9b, 0x1b, 0xf7, 0xaa, 0xfc, 0xd6, 0x5f, 0x8c, 0x2a, 0xff, - 0x78, 0xb8, 0xbd, 0x4e, 0xa8, 0x6c, 0xfd, 0x6b, 0x9e, 0x1b, 0xd9, 0x93, 0x2b, 0xdf, 0xb8, 0x61, - 0xe4, 0x7a, 0x07, 0x9a, 0x59, 0xcf, 0xbe, 0xb0, 0x49, 0x9f, 0x65, 0x4c, 0x01, 0xb6, 0x9b, 0x9a, - 0xbc, 0x95, 0x19, 0x30, 0xc9, 0x7c, 0x4a, 0x63, 0x1b, 0x2f, 0x25, 0x33, 0x26, 0xdf, 0xb8, 0xa0, - 0xaf, 0xda, 0x78, 0x62, 0x7d, 0x0f, 0x2e, 0xf0, 0x25, 0xad, 0xa8, 0xf1, 0xa2, 0xd9, 0xba, 0x15, - 0xd2, 0xfa, 0x40, 0x5a, 0x29, 0x0a, 0x5b, 0x66, 0x8f, 0x19, 0x6d, 0xc1, 0x2a, 0xff, 0x53, 0x09, - 0xe6, 0x12, 0xa4, 0xb5, 0xe7, 0x5e, 0x43, 0xae, 0xa7, 0x6f, 0x26, 0x7d, 0x7c, 0x51, 0x0f, 0xe0, - 0xc6, 0x3f, 0xb7, 0xa9, 0xdc, 0x7c, 0xc9, 0x2d, 0x00, 0x4e, 0xac, 0x6d, 0xdf, 0x68, 0x7c, 0x16, - 0x3e, 0x1c, 0xb8, 0x81, 0x6b, 0x28, 0xa4, 0x03, 0x59, 0x72, 0x17, 0xdf, 0x48, 0x37, 0xeb, 0x2c, - 0xbe, 0xb2, 0xa7, 0x82, 0xbc, 0x9e, 0x63, 0xa6, 0xcd, 0xe2, 0x6f, 0xfd, 0x5f, 0x7d, 0x30, 0xa3, - 0x0f, 0xe0, 0x8b, 0xf4, 0x75, 0x1b, 0x46, 0x97, 0x7c, 0x2f, 0xa2, 0xdf, 0x44, 0xda, 0x2b, 0x67, - 0xa2, 0xee, 0xba, 0x55, 0x89, 0x50, 0x1d, 0x39, 0xa0, 0xce, 0xf4, 0x18, 0xc3, 0x17, 0x2d, 0x46, - 0x24, 0x4b, 0x30, 0xbe, 0x49, 0x9f, 0xa5, 0x04, 0x88, 0xfe, 0x70, 0x1e, 0x7d, 0x56, 0xd7, 0x84, - 0xa8, 0x3b, 0x29, 0x19, 0x34, 0x64, 0x1f, 0x26, 0xe4, 0xe4, 0x32, 0x84, 0x39, 0xa7, 0xef, 0x2a, - 0xe6, 0x74, 0xe6, 0xef, 0x80, 0x59, 0x0d, 0x39, 0x32, 0x4c, 0x70, 0x64, 0x5d, 0xe7, 0x35, 0xf2, - 0xa7, 0xad, 0xe6, 0xb6, 0xa5, 0x95, 0x18, 0xde, 0x86, 0xc9, 0x27, 0xad, 0x3a, 0x0b, 0x6b, 0x1b, - 0x66, 0xd3, 0xe3, 0x21, 0x6a, 0x7b, 0x17, 0x06, 0x39, 0x54, 0xa8, 0x01, 0x32, 0x80, 0x85, 0xc2, - 0xe6, 0xe7, 0x74, 0x5e, 0x8d, 0x2d, 0x70, 0xad, 0x55, 0xb4, 0x9d, 0x28, 0x1c, 0xa5, 0x88, 0xdd, - 0x4e, 0x0e, 0x2f, 0x3a, 0x72, 0xca, 0xe1, 0xd5, 0x3d, 0x3d, 0xa4, 0xef, 0xfa, 0x12, 0x9a, 0x9f, - 0x74, 0x4e, 0xa2, 0x61, 0x37, 0x60, 0x48, 0x80, 0x12, 0xa1, 0x35, 0xe2, 0xcf, 0x4f, 0x22, 0x58, - 0x1f, 0xc1, 0x45, 0xb4, 0x85, 0xb9, 0xde, 0x41, 0x8b, 0xee, 0x86, 0x86, 0xf7, 0x79, 0xb7, 0xcf, - 0xfa, 0x13, 0x98, 0xcb, 0xa2, 0xed, 0xfa, 0x65, 0xf3, 0xc7, 0xee, 0x7f, 0xdd, 0x0b, 0x53, 0x6b, - 0xa1, 0xae, 0x4c, 0x08, 0x49, 0xdc, 0xcc, 0x7a, 0x86, 0x8d, 0x32, 0x59, 0xed, 0xc9, 0x7a, 0x66, - 0xfd, 0xae, 0xf6, 0xac, 0xad, 0xb7, 0xe8, 0x7d, 0x35, 0xdb, 0xb6, 0xd4, 0xc3, 0xb6, 0x37, 0xa1, - 0x7f, 0x93, 0x2d, 0xd5, 0x7d, 0x62, 0xec, 0x38, 0x05, 0x03, 0xe1, 0xb3, 0x32, 0xb6, 0x45, 0xb2, - 0x1f, 0xe4, 0x5e, 0xea, 0xf1, 0x5a, 0x7f, 0xf7, 0xf7, 0xc3, 0xab, 0x3d, 0xa9, 0x77, 0x6c, 0xef, - 0xc3, 0x68, 0xb5, 0x79, 0xc4, 0x1d, 0xce, 0x7c, 0x2f, 0xf1, 0x59, 0x6a, 0x25, 0xab, 0x3d, 0xb6, - 0x8e, 0xc8, 0x4e, 0xb8, 0xd5, 0x76, 0x1b, 0x37, 0xaa, 0xac, 0x37, 0xd5, 0xab, 0x3d, 0xe8, 0xbf, - 0xbd, 0x38, 0x0c, 0x83, 0x3b, 0x4e, 0x70, 0x40, 0x23, 0xeb, 0x2b, 0x98, 0x13, 0x6e, 0x22, 0xdc, - 0xf2, 0x87, 0xce, 0x24, 0x61, 0xec, 0x09, 0x54, 0xe4, 0xda, 0x71, 0x05, 0x00, 0xf5, 0xfc, 0x35, - 0xaf, 0x49, 0xbf, 0xe1, 0xde, 0x4c, 0xb6, 0x06, 0xb1, 0xde, 0x83, 0x11, 0x25, 0x21, 0x54, 0x66, - 0xb5, 0xcd, 0x0e, 0xa5, 0x35, 0x65, 0xbc, 0xd6, 0x93, 0x4f, 0xf4, 0x2e, 0x1a, 0x7d, 0x17, 0x31, - 0x12, 0xb8, 0xf6, 0xeb, 0xc2, 0x74, 0x62, 0x12, 0xc4, 0x8f, 0x70, 0x95, 0xfe, 0x89, 0x9e, 0x4f, - 0xb6, 0xfa, 0x9d, 0x54, 0x4f, 0x7b, 0x4f, 0xa5, 0x9e, 0x5a, 0xff, 0xa8, 0x17, 0x0f, 0x4e, 0x29, - 0x79, 0x24, 0x6c, 0x50, 0xba, 0x1d, 0x6c, 0x11, 0x46, 0xb0, 0xf7, 0xcb, 0xf2, 0x65, 0x51, 0xb1, - 0x97, 0xc3, 0xf0, 0xcf, 0x8f, 0x2b, 0x3d, 0xe8, 0xda, 0x10, 0x93, 0x91, 0x4f, 0x61, 0x68, 0xc5, - 0x6b, 0x22, 0x87, 0xbe, 0x33, 0x70, 0x90, 0x44, 0x6c, 0x4c, 0xb0, 0xc9, 0x3b, 0xec, 0x13, 0xe6, - 0xa6, 0x0b, 0x5b, 0x83, 0xc4, 0x27, 0xb8, 0x81, 0xbc, 0x13, 0xdc, 0x60, 0xe2, 0x04, 0x67, 0xc1, - 0xc0, 0x56, 0xd0, 0x14, 0xb1, 0x0d, 0x26, 0x16, 0xc6, 0x84, 0xe0, 0x10, 0x66, 0xf3, 0x22, 0xeb, - 0xbf, 0x94, 0x60, 0xe6, 0x3e, 0x8d, 0x32, 0xe7, 0x90, 0x21, 0x95, 0xd2, 0x4b, 0x4b, 0xa5, 0xf7, - 0x45, 0xa4, 0xa2, 0x7a, 0xdd, 0x97, 0xd7, 0xeb, 0xfe, 0xbc, 0x5e, 0x0f, 0xe4, 0xf7, 0xfa, 0x3e, - 0x0c, 0xf2, 0xae, 0xb2, 0x53, 0xea, 0x5a, 0x44, 0x8f, 0xe2, 0x53, 0xaa, 0xee, 0xa3, 0x65, 0xf3, - 0x32, 0xa6, 0x48, 0xae, 0x3b, 0xa1, 0x7e, 0x4a, 0x15, 0x3f, 0xad, 0x1f, 0xe3, 0x9b, 0xc4, 0x75, - 0xbf, 0xf1, 0x44, 0xb3, 0x76, 0x0e, 0xf1, 0x2f, 0x34, 0x69, 0x1d, 0x67, 0x58, 0xbc, 0xc4, 0x96, - 0x18, 0xe4, 0x2a, 0x8c, 0xae, 0x79, 0xf7, 0xfc, 0xa0, 0x41, 0xb7, 0xbc, 0x16, 0xe7, 0x3e, 0x6c, - 0xeb, 0x20, 0x61, 0x05, 0x10, 0x35, 0xc4, 0x47, 0x6b, 0x04, 0x24, 0x8e, 0xd6, 0x0c, 0xb6, 0xb7, - 0x60, 0xf3, 0x32, 0x61, 0x64, 0x60, 0x7f, 0x17, 0x9d, 0x4a, 0xd5, 0xf1, 0xb5, 0x1b, 0xe2, 0x3e, - 0x5c, 0xb4, 0x69, 0xbb, 0xe5, 0x30, 0x9d, 0xee, 0xc8, 0xe7, 0xf8, 0xaa, 0xcf, 0x57, 0x33, 0xde, - 0x13, 0x99, 0x37, 0xf6, 0xaa, 0xc9, 0xbd, 0x05, 0x4d, 0x3e, 0x82, 0x6b, 0xf7, 0x69, 0x64, 0x2e, - 0xa8, 0xb1, 0x2d, 0x55, 0x74, 0x7e, 0x15, 0x86, 0x43, 0xd3, 0x0e, 0x7c, 0x45, 0x5e, 0x3f, 0x64, - 0x11, 0xee, 0xdd, 0x95, 0x37, 0x25, 0x82, 0x8f, 0xfa, 0xcb, 0xfa, 0x0c, 0x2a, 0x79, 0xd5, 0x9d, - 0xce, 0xa1, 0xd2, 0x85, 0xab, 0xf9, 0x0c, 0x44, 0x73, 0x57, 0x40, 0xda, 0x8c, 0xc5, 0x27, 0xd4, - 0xad, 0xb5, 0xa6, 0x99, 0x59, 0xfc, 0x61, 0x2d, 0x4a, 0xd7, 0xb2, 0x97, 0x68, 0x6e, 0x1d, 0xaf, - 0x63, 0x4d, 0x06, 0xb1, 0x5c, 0xab, 0x30, 0x2c, 0x61, 0x42, 0xae, 0x33, 0x99, 0x2d, 0x95, 0x02, - 0x6d, 0x4a, 0x06, 0x8a, 0xcc, 0xfa, 0xb1, 0xbc, 0x9a, 0x30, 0x29, 0x4e, 0xf7, 0xc0, 0xee, 0x34, - 0x77, 0x11, 0x96, 0x0f, 0x17, 0x4d, 0xde, 0xba, 0xc9, 0xb9, 0xac, 0x99, 0x9c, 0xb9, 0xa5, 0xf9, - 0xaa, 0x69, 0x02, 0xed, 0x15, 0xf3, 0x32, 0x06, 0x91, 0x2b, 0xba, 0x61, 0x79, 0x2c, 0xfd, 0x62, - 0xef, 0x36, 0xcc, 0x65, 0x55, 0xa8, 0x9d, 0x03, 0x95, 0xf5, 0x52, 0xe8, 0x3b, 0xcb, 0x70, 0x45, - 0x46, 0x17, 0xf1, 0xfd, 0x28, 0x8c, 0x02, 0xa7, 0x5d, 0x6b, 0x04, 0x6e, 0x3b, 0xa6, 0xb2, 0x60, - 0x90, 0x43, 0x84, 0x24, 0xf8, 0x35, 0x0f, 0xc7, 0x11, 0x25, 0xd6, 0x6f, 0x97, 0xc0, 0x32, 0xbc, - 0x80, 0x70, 0x9c, 0xb7, 0x03, 0xff, 0xa9, 0xdb, 0xd4, 0xae, 0x56, 0xde, 0x36, 0xcc, 0x7a, 0xfc, - 0xc5, 0x55, 0xd2, 0x01, 0x59, 0xac, 0x99, 0xb7, 0x13, 0xa6, 0x36, 0xae, 0x78, 0xa2, 0x67, 0xd0, - 0x13, 0xaa, 0xbf, 0x58, 0x50, 0x26, 0xb8, 0xff, 0x56, 0x82, 0xd7, 0x0a, 0xdb, 0x20, 0xfa, 0xb3, - 0x0f, 0xe5, 0x64, 0x99, 0x98, 0x41, 0x15, 0xcd, 0x27, 0x21, 0xcd, 0x61, 0xef, 0x0e, 0xf7, 0x72, - 0x96, 0xde, 0x33, 0x6d, 0xc5, 0x39, 0xc5, 0xef, 0xec, 0xad, 0x27, 0x1f, 0x02, 0xec, 0xf8, 0x91, - 0xd3, 0x5a, 0x42, 0x03, 0x40, 0x5f, 0xec, 0xb1, 0x1e, 0x31, 0x68, 0x3d, 0xf9, 0xbc, 0x5d, 0x43, - 0xb6, 0x7e, 0x80, 0xdf, 0x75, 0x76, 0xa3, 0x4f, 0xf7, 0xa9, 0x2d, 0xc1, 0x6b, 0x89, 0x7b, 0xf1, - 0x17, 0x60, 0x12, 0xc1, 0x34, 0x13, 0x3f, 0xd3, 0xbd, 0xef, 0x07, 0x7e, 0xa7, 0xfd, 0xab, 0x19, - 0xf5, 0x3f, 0x2f, 0x71, 0x57, 0x41, 0xbd, 0x5a, 0x31, 0xd0, 0x4b, 0x00, 0x31, 0x34, 0xe1, 0x32, - 0xae, 0x0a, 0xf6, 0xee, 0xf0, 0x23, 0x37, 0x5a, 0xcc, 0x0f, 0x38, 0x03, 0x8d, 0xec, 0x57, 0x3b, - 0x92, 0x77, 0xf1, 0x32, 0x5c, 0xd5, 0x7e, 0x3a, 0xb9, 0xbf, 0x2f, 0xed, 0x1f, 0x67, 0xa4, 0x3b, - 0x84, 0x29, 0xb6, 0x02, 0x54, 0x3b, 0xd1, 0xa1, 0x1f, 0xb8, 0x91, 0x7c, 0xfc, 0x40, 0xb6, 0xc5, - 0xd3, 0x61, 0x4e, 0xf5, 0xc9, 0x2f, 0x8f, 0x2b, 0x1f, 0x9c, 0x25, 0xea, 0x9b, 0xe4, 0xb9, 0xa3, - 0x9e, 0x1b, 0x5b, 0x33, 0xd0, 0xb7, 0x64, 0xaf, 0xe3, 0x82, 0x67, 0xaf, 0xab, 0x05, 0xcf, 0x5e, - 0xb7, 0xfe, 0xb6, 0x17, 0x2a, 0x3c, 0xb8, 0x01, 0xfa, 0x50, 0xc4, 0x56, 0x0b, 0xcd, 0x29, 0xe3, - 0xb4, 0x06, 0x86, 0x44, 0xf0, 0x82, 0xde, 0xd3, 0x04, 0x2f, 0xf8, 0x0d, 0xc8, 0x31, 0x59, 0x9d, - 0xc2, 0x0a, 0xf0, 0xd6, 0xc9, 0x71, 0xe5, 0xb5, 0xd8, 0x0a, 0xc0, 0x4b, 0xb3, 0xcc, 0x01, 0x39, - 0x55, 0xa4, 0xed, 0x17, 0xfd, 0x2f, 0x60, 0xbf, 0xb8, 0x0d, 0x43, 0x78, 0x98, 0x59, 0xdb, 0x16, - 0x7e, 0x85, 0x38, 0x3d, 0x31, 0x12, 0x49, 0xdd, 0xd5, 0xc3, 0x41, 0x49, 0x34, 0xeb, 0xff, 0xed, - 0x85, 0xab, 0xf9, 0x32, 0x17, 0x6d, 0x5b, 0x06, 0x88, 0xbd, 0x37, 0x8a, 0xbc, 0x45, 0xf0, 0xdb, - 0x79, 0x46, 0xf7, 0x95, 0xb7, 0x96, 0x46, 0xc7, 0x74, 0x1f, 0xf9, 0x8e, 0x34, 0x71, 0x55, 0x60, - 0x3c, 0x2f, 0x15, 0xb1, 0x0c, 0x05, 0xc8, 0x88, 0x65, 0x28, 0x60, 0x64, 0x1f, 0x66, 0xb6, 0x03, - 0xf7, 0xa9, 0x13, 0xd1, 0x87, 0xf4, 0x39, 0x7f, 0x8a, 0xb2, 0x22, 0xde, 0x9f, 0xf0, 0xc7, 0xc1, - 0xd7, 0x4f, 0x8e, 0x2b, 0xaf, 0xb7, 0x39, 0x0a, 0xfb, 0x30, 0xeb, 0xfc, 0x65, 0x5b, 0x3d, 0xfd, - 0x24, 0x25, 0x8f, 0x91, 0xf5, 0x2f, 0x4b, 0x70, 0x09, 0xd5, 0x72, 0x61, 0x76, 0x95, 0x95, 0xbf, - 0x90, 0xd3, 0xa0, 0xde, 0x41, 0x31, 0x17, 0xd1, 0x69, 0xd0, 0x78, 0x67, 0x6b, 0x1b, 0x68, 0x64, - 0x0d, 0x46, 0xc5, 0x6f, 0xfc, 0xfe, 0xfa, 0xf0, 0x40, 0x30, 0xad, 0x2d, 0x58, 0x38, 0xd5, 0xb9, - 0xa9, 0x08, 0x27, 0xb6, 0x60, 0x86, 0xcf, 0xd1, 0x6c, 0x9d, 0xd6, 0xfa, 0x45, 0x2f, 0xcc, 0xef, - 0xd1, 0xc0, 0x7d, 0xfc, 0x3c, 0xa7, 0x33, 0x5b, 0x30, 0x25, 0x41, 0x3c, 0xc0, 0x81, 0xf1, 0x89, - 0xf1, 0x78, 0x66, 0xb2, 0xa9, 0x22, 0x42, 0x82, 0xfc, 0xe2, 0x32, 0x09, 0xcf, 0xe0, 0x0e, 0xf8, - 0x2e, 0x0c, 0x27, 0x42, 0x8c, 0xe0, 0xf8, 0xcb, 0x2f, 0x34, 0x1e, 0xaa, 0xd5, 0x1e, 0x5b, 0x61, - 0x92, 0xdf, 0xc9, 0xbf, 0xbf, 0x11, 0xa6, 0x8f, 0x6e, 0xf6, 0x4f, 0xfc, 0x60, 0xd9, 0xc7, 0xea, - 0x68, 0xa5, 0x19, 0x1f, 0xec, 0x6a, 0x8f, 0x9d, 0x57, 0xd3, 0xe2, 0x28, 0x8c, 0x54, 0xf1, 0x4e, - 0x8a, 0x9d, 0xdc, 0xff, 0x6b, 0x2f, 0x5c, 0x91, 0xcf, 0x4a, 0x72, 0xc4, 0xfc, 0x05, 0xcc, 0x48, - 0x50, 0xb5, 0xcd, 0x14, 0x06, 0xda, 0x34, 0x25, 0xcd, 0x63, 0x0a, 0x4a, 0x49, 0x3b, 0x02, 0x27, - 0x16, 0x76, 0x1e, 0xf9, 0xab, 0xb1, 0x7e, 0x7e, 0x9a, 0x15, 0xf0, 0x05, 0xad, 0x90, 0xfa, 0x9a, - 0x69, 0x88, 0xc6, 0x58, 0x3f, 0x9b, 0x29, 0xeb, 0x69, 0xff, 0xcb, 0x5a, 0x4f, 0x57, 0x7b, 0x92, - 0xf6, 0xd3, 0xc5, 0x09, 0x18, 0xdb, 0xa4, 0xcf, 0x62, 0xb9, 0xff, 0xef, 0xa5, 0xc4, 0x43, 0x76, - 0xa6, 0x61, 0xf0, 0x17, 0xed, 0xa5, 0x38, 0x66, 0x08, 0x3e, 0x64, 0xd7, 0x35, 0x0c, 0x8e, 0xba, - 0x06, 0x43, 0xfc, 0xa2, 0xb6, 0x79, 0x8a, 0x13, 0xbe, 0x7a, 0x1f, 0xc2, 0x1f, 0xed, 0x35, 0xf9, - 0x61, 0x5f, 0xd0, 0x5b, 0x0f, 0xe1, 0x9a, 0xf0, 0x5f, 0x36, 0x07, 0x1f, 0x2b, 0x3a, 0xe3, 0xf6, - 0x65, 0x39, 0x70, 0xe5, 0x3e, 0x4d, 0x2e, 0x3d, 0xc6, 0xfb, 0x99, 0xcf, 0xe0, 0x9c, 0x01, 0x57, - 0x1c, 0x51, 0x2b, 0x55, 0x73, 0x48, 0xb1, 0x4e, 0x62, 0x5b, 0x57, 0xb3, 0xaa, 0xd0, 0x1b, 0x6b, - 0x51, 0x0c, 0x0e, 0x18, 0xc4, 0x57, 0x6c, 0xe1, 0x19, 0x56, 0xbd, 0xeb, 0xda, 0x77, 0xcd, 0x57, - 0x3c, 0x1e, 0x25, 0x4c, 0xee, 0xbc, 0xaa, 0xd4, 0x1a, 0x37, 0xee, 0x02, 0xac, 0x09, 0x18, 0x93, - 0x45, 0x2d, 0x1a, 0x86, 0xd6, 0xcf, 0x06, 0xc0, 0x12, 0x82, 0xcd, 0xba, 0x7d, 0x96, 0xf2, 0xd8, - 0x4f, 0x35, 0x56, 0x6c, 0x54, 0x17, 0xf4, 0xb8, 0x74, 0x71, 0x29, 0x9f, 0x79, 0xa8, 0xe7, 0x35, - 0x62, 0xa8, 0x31, 0xf3, 0x52, 0xbd, 0xff, 0x61, 0xce, 0x32, 0xc9, 0x3f, 0xb6, 0x37, 0x4e, 0x8e, - 0x2b, 0xd7, 0x72, 0x96, 0x49, 0x83, 0x6f, 0xf6, 0x92, 0x69, 0x9b, 0x57, 0x22, 0x7d, 0x2f, 0x72, - 0x25, 0xc2, 0xbe, 0x48, 0xfd, 0x52, 0x64, 0xd7, 0x94, 0xa5, 0xf8, 0x1e, 0xe5, 0x95, 0xb6, 0x5e, - 0x24, 0xde, 0x93, 0x6b, 0x10, 0x83, 0xab, 0xc1, 0x86, 0xb8, 0x50, 0xd6, 0x6c, 0x96, 0x4b, 0x87, - 0xb4, 0xf1, 0x44, 0xd8, 0x8a, 0xe5, 0x85, 0x6e, 0x96, 0xcd, 0x9c, 0xc7, 0x27, 0xe5, 0xdf, 0x39, - 0x2f, 0xa8, 0x37, 0x18, 0xa9, 0xfe, 0x1e, 0x3e, 0xc9, 0x96, 0xfc, 0x14, 0x26, 0xd5, 0x50, 0x27, - 0xdc, 0x8f, 0x46, 0x17, 0x5e, 0x8f, 0x03, 0x19, 0x1e, 0x3d, 0x76, 0x6e, 0x3e, 0xbd, 0x73, 0x33, - 0x03, 0x97, 0x3f, 0xb3, 0x6e, 0xc8, 0x02, 0xcd, 0xf7, 0x48, 0xbf, 0xe8, 0xca, 0x22, 0xd4, 0xae, - 0xb3, 0xff, 0x1f, 0xe5, 0x2c, 0xcf, 0xf4, 0x05, 0xb7, 0x45, 0xc5, 0xbb, 0x13, 0x39, 0xfb, 0x72, - 0xae, 0xe2, 0x4a, 0xdf, 0xf2, 0x55, 0xdc, 0x9f, 0xf6, 0xca, 0x27, 0x02, 0xe9, 0xdb, 0xd0, 0x33, - 0xdf, 0xc8, 0x65, 0xf6, 0xe0, 0x54, 0x9b, 0x69, 0x66, 0xe3, 0xc8, 0xa2, 0xbc, 0xcf, 0x54, 0xa1, - 0x87, 0x26, 0xd4, 0xdd, 0x40, 0x5c, 0x60, 0x5c, 0x71, 0xa2, 0xea, 0xa2, 0x51, 0x25, 0x2f, 0xcb, - 0xfa, 0x5e, 0xfe, 0xb2, 0xec, 0x9f, 0x8e, 0xc0, 0xf9, 0x6d, 0xe7, 0xc0, 0xf5, 0xd8, 0xa2, 0x6d, - 0xd3, 0xd0, 0xef, 0x04, 0x0d, 0x4a, 0xaa, 0x30, 0x61, 0xfa, 0x7f, 0x76, 0xf1, 0x6e, 0x65, 0xfb, - 0x92, 0x09, 0x23, 0x0b, 0x30, 0xa2, 0x5e, 0x7d, 0x8a, 0xcd, 0x24, 0xe3, 0x35, 0xe8, 0x6a, 0x8f, - 0x1d, 0xa3, 0x91, 0x0f, 0x8d, 0xfb, 0x9d, 0x73, 0xea, 0x01, 0x33, 0xe2, 0x2e, 0x70, 0x07, 0x3d, - 0xcf, 0x6f, 0x9a, 0x1b, 0x22, 0xbf, 0xc4, 0xf8, 0x71, 0xea, 0xca, 0x67, 0xc0, 0x68, 0x71, 0xca, - 0xee, 0x85, 0xba, 0x40, 0x6e, 0x80, 0xd8, 0x8c, 0xcb, 0xa0, 0xaf, 0x60, 0xf4, 0x61, 0x67, 0x9f, - 0xca, 0xcb, 0xad, 0x41, 0xb1, 0x3f, 0x26, 0xbd, 0x9a, 0x45, 0xf9, 0xde, 0x5d, 0x3e, 0x06, 0x4f, - 0x3a, 0xfb, 0x34, 0x1d, 0x79, 0x98, 0x2d, 0x4c, 0x1a, 0x33, 0x72, 0x08, 0xe5, 0xa4, 0x03, 0xb2, - 0x08, 0xd6, 0x55, 0xe0, 0x36, 0x8d, 0x91, 0x22, 0xb4, 0xf8, 0xc6, 0xdc, 0x2d, 0xd2, 0xa8, 0x24, - 0xc5, 0x95, 0xfc, 0x26, 0x4c, 0x67, 0x5a, 0x1d, 0xd5, 0x23, 0xa6, 0x62, 0x83, 0x26, 0x2e, 0xea, - 0x09, 0xa9, 0xc9, 0x17, 0x53, 0x46, 0xcd, 0xd9, 0xb5, 0x90, 0x26, 0x9c, 0x4b, 0x38, 0xd6, 0x8a, - 0x10, 0xee, 0xf9, 0xae, 0xba, 0xb8, 0x31, 0xc9, 0x78, 0x97, 0x99, 0x75, 0x25, 0x59, 0x92, 0x75, - 0x18, 0x51, 0xc7, 0x7d, 0x0c, 0xfa, 0x93, 0x6d, 0xda, 0x98, 0x3d, 0x39, 0xae, 0x4c, 0xc5, 0xa6, - 0x0d, 0x83, 0x67, 0xcc, 0x80, 0xfc, 0x16, 0x5c, 0x53, 0x53, 0x74, 0x2b, 0xc8, 0x36, 0x02, 0x89, - 0xf8, 0xc9, 0x37, 0x92, 0x33, 0x3c, 0x0f, 0x7f, 0xef, 0xce, 0x62, 0xef, 0x6c, 0x69, 0xb5, 0xc7, - 0xee, 0xce, 0x9a, 0xfc, 0xac, 0x04, 0x17, 0x72, 0x6a, 0x1d, 0xc3, 0x5a, 0xbb, 0x5a, 0xe6, 0x50, - 0xb9, 0xc7, 0x67, 0x43, 0x6e, 0x33, 0x7e, 0xe0, 0x26, 0x4d, 0x74, 0x46, 0xbf, 0x73, 0x6a, 0x22, - 0xef, 0xc0, 0x20, 0x9e, 0x91, 0xc3, 0xd9, 0x71, 0xd4, 0x22, 0x31, 0x40, 0x0a, 0x9e, 0xa4, 0xf5, - 0x7d, 0x43, 0xe0, 0x90, 0x55, 0xa6, 0x8d, 0xe1, 0xbe, 0x25, 0xb5, 0x27, 0x11, 0x4e, 0x49, 0x68, - 0xf4, 0xbc, 0x48, 0xc6, 0x99, 0x30, 0x02, 0x65, 0x9b, 0x64, 0x8b, 0x00, 0xc3, 0x81, 0x58, 0x95, - 0x1e, 0xf4, 0x0f, 0xf7, 0x97, 0x07, 0xf8, 0x87, 0x23, 0x3d, 0xb6, 0x7f, 0x77, 0x98, 0x3f, 0xb0, - 0xdc, 0xf5, 0xdc, 0xc7, 0x6e, 0xbc, 0x80, 0xe9, 0xd6, 0xb5, 0x38, 0x5f, 0x85, 0xd0, 0x7d, 0x73, - 0x32, 0x53, 0x28, 0x43, 0x5c, 0x6f, 0x57, 0x43, 0xdc, 0x5d, 0xed, 0xca, 0x4a, 0x8b, 0x40, 0xc8, - 0x75, 0x1c, 0xd3, 0xf0, 0x15, 0xdf, 0x65, 0x7d, 0x0d, 0x83, 0x18, 0x34, 0x90, 0xdf, 0x07, 0x8e, - 0x2e, 0xdc, 0x14, 0xcb, 0x76, 0x41, 0xf3, 0x79, 0x94, 0x41, 0xf1, 0x68, 0x9a, 0x4b, 0x1c, 0x01, - 0x86, 0xc4, 0x11, 0x42, 0x76, 0x60, 0x72, 0x3b, 0xa0, 0x4d, 0xe1, 0x37, 0xdc, 0x0e, 0x84, 0x71, - 0x82, 0x9b, 0x3d, 0x70, 0xcb, 0x6f, 0xcb, 0xe2, 0x3a, 0x55, 0xe5, 0xfa, 0x86, 0x9a, 0x41, 0x4e, - 0x56, 0x60, 0xa2, 0x46, 0x9d, 0xa0, 0x71, 0xf8, 0x90, 0x3e, 0x67, 0xea, 0x8e, 0x11, 0xa4, 0x3d, - 0xc4, 0x12, 0xd6, 0x5f, 0x2c, 0xd2, 0x7d, 0x3c, 0x4c, 0x22, 0xf2, 0x03, 0x18, 0xac, 0xf9, 0x41, - 0xb4, 0xf8, 0x5c, 0x2c, 0x6a, 0xf2, 0xc6, 0x88, 0x03, 0x17, 0x2f, 0xca, 0x40, 0xf5, 0xa1, 0x1f, - 0x44, 0xf5, 0x7d, 0x23, 0xe2, 0x0e, 0x47, 0x21, 0xcf, 0x61, 0xca, 0x5c, 0x50, 0x84, 0x3b, 0xeb, - 0xb0, 0x50, 0xb3, 0xb2, 0x56, 0x2d, 0x8e, 0xb2, 0x78, 0x5d, 0x70, 0xbf, 0x9a, 0x5c, 0xb6, 0x1e, - 0x63, 0xb9, 0x1e, 0x04, 0x27, 0x8b, 0x9e, 0x6c, 0x60, 0x7c, 0x7f, 0xde, 0xa3, 0x6a, 0xc8, 0xdd, - 0x60, 0x47, 0xe2, 0x98, 0x4e, 0x1d, 0x5c, 0x94, 0x50, 0x12, 0x4e, 0x98, 0x4c, 0x0a, 0x61, 0xa7, - 0x48, 0xc9, 0x36, 0x9c, 0xdf, 0x0d, 0xe9, 0x76, 0x40, 0x9f, 0xba, 0xf4, 0x99, 0xe4, 0x07, 0x71, - 0x00, 0x1c, 0xc6, 0xaf, 0xcd, 0x4b, 0xb3, 0x18, 0xa6, 0x89, 0xc9, 0x87, 0x00, 0xdb, 0xae, 0xe7, - 0xd1, 0x26, 0x5e, 0x3b, 0x8e, 0x22, 0x2b, 0x34, 0xa9, 0xb6, 0x11, 0x5a, 0xf7, 0xbd, 0x96, 0x2e, - 0x52, 0x0d, 0x99, 0x2c, 0xc2, 0xf8, 0x9a, 0xd7, 0x68, 0x75, 0x84, 0x7b, 0x40, 0x88, 0x0b, 0x8a, - 0x08, 0xcc, 0xe5, 0xf2, 0x82, 0x7a, 0xea, 0x23, 0x37, 0x49, 0xc8, 0x43, 0x20, 0x02, 0x20, 0x66, - 0xad, 0xb3, 0xdf, 0xa2, 0xe2, 0x73, 0x47, 0x53, 0x89, 0x64, 0x84, 0xd3, 0xdd, 0x88, 0x77, 0x95, - 0x22, 0x9b, 0xfb, 0x10, 0x46, 0xb5, 0x39, 0x9f, 0x11, 0x05, 0x60, 0x4a, 0x8f, 0x02, 0x30, 0xa2, - 0xbf, 0xf6, 0xff, 0xff, 0x4b, 0x30, 0x9f, 0xfd, 0x2d, 0x09, 0x05, 0x6c, 0x0b, 0x46, 0x14, 0x50, - 0xbd, 0x3a, 0x91, 0xaa, 0x7f, 0x42, 0x03, 0xe2, 0x1f, 0xb4, 0x5c, 0x79, 0xf4, 0xde, 0xc7, 0x3c, - 0x5e, 0xc0, 0x1e, 0xff, 0x7f, 0x0c, 0xc3, 0x14, 0x7a, 0x57, 0x27, 0xd7, 0xa9, 0xcf, 0x30, 0x9a, - 0x07, 0xc2, 0x34, 0xf3, 0xb2, 0xb0, 0x34, 0x71, 0x78, 0x32, 0xae, 0x92, 0x41, 0x40, 0xde, 0xd3, - 0x7d, 0x22, 0x7a, 0xb5, 0x8c, 0x02, 0x12, 0xa8, 0x77, 0x21, 0x76, 0x96, 0x78, 0xdb, 0xb8, 0x92, - 0x3f, 0xf5, 0xa2, 0xd7, 0x7f, 0xda, 0x45, 0x6f, 0x57, 0x2d, 0x7a, 0x3c, 0x4a, 0xc4, 0x5b, 0xda, - 0xa2, 0xf7, 0xea, 0x57, 0xbb, 0xc1, 0x57, 0xbd, 0xda, 0x0d, 0xbd, 0xdc, 0x6a, 0x37, 0xfc, 0x82, - 0xab, 0xdd, 0x3d, 0x98, 0xd8, 0xa4, 0xb4, 0xa9, 0x5d, 0x94, 0x8c, 0xc4, 0xbb, 0xa7, 0x47, 0xd1, - 0x04, 0x96, 0x75, 0x5b, 0x92, 0xa0, 0xca, 0x5d, 0x35, 0xe1, 0xef, 0x67, 0xd5, 0x1c, 0x7d, 0xc5, - 0xab, 0xe6, 0xd8, 0xcb, 0xac, 0x9a, 0xa9, 0xa5, 0x6f, 0xfc, 0xcc, 0x4b, 0xdf, 0xcb, 0xac, 0x56, - 0x9f, 0xa2, 0x4b, 0x61, 0xad, 0xb6, 0x2a, 0xbc, 0x47, 0x34, 0x77, 0x8d, 0x55, 0x3f, 0x94, 0x1e, - 0xd7, 0xf8, 0x37, 0x83, 0x6d, 0xfb, 0x81, 0xbc, 0xf2, 0xc6, 0xbf, 0xad, 0x45, 0x74, 0x24, 0xd4, - 0xe9, 0x95, 0xbb, 0xfe, 0x90, 0x78, 0xb2, 0x27, 0xd6, 0xb8, 0xe4, 0x31, 0xca, 0x96, 0xe5, 0xd6, - 0x5f, 0x97, 0xf8, 0xa5, 0xe4, 0xff, 0x8c, 0x4b, 0xe5, 0xcb, 0x5c, 0x14, 0xfe, 0x4e, 0xfc, 0x94, - 0x5f, 0x84, 0x1d, 0x08, 0x9c, 0xc6, 0x93, 0xf8, 0xa6, 0xf6, 0x47, 0xec, 0x3b, 0xd7, 0x0b, 0x30, - 0x6e, 0x67, 0x7c, 0x56, 0x34, 0x0b, 0xf7, 0xee, 0xc8, 0x05, 0x40, 0x44, 0x34, 0xe0, 0x60, 0x73, - 0x01, 0xd0, 0x09, 0xd0, 0x57, 0xee, 0x9c, 0x65, 0xf3, 0x97, 0xe8, 0x99, 0x2d, 0x78, 0x3f, 0xfd, - 0x96, 0x1a, 0x0f, 0x23, 0xf1, 0x5b, 0x6a, 0x5d, 0x8c, 0xf1, 0xab, 0xea, 0x5d, 0xb8, 0x64, 0xd3, - 0x23, 0xff, 0x29, 0x7d, 0xb5, 0x6c, 0x7f, 0x08, 0x17, 0x4d, 0x86, 0xfc, 0xd5, 0x0d, 0x8f, 0xb7, - 0xfd, 0x69, 0x76, 0x94, 0x6e, 0x41, 0xc0, 0xa3, 0x74, 0xf3, 0x60, 0xbf, 0xec, 0x4f, 0x7d, 0xdf, - 0xc0, 0x32, 0xcb, 0x87, 0x79, 0x93, 0x79, 0xb5, 0xd9, 0xc4, 0xec, 0x6d, 0x0d, 0xb7, 0xed, 0x78, - 0x11, 0xd9, 0x82, 0x51, 0xed, 0x67, 0xc2, 0x54, 0xa0, 0x95, 0x08, 0x9d, 0x26, 0x06, 0x18, 0x11, - 0x1e, 0x63, 0xb0, 0x45, 0xa1, 0x92, 0x14, 0x0f, 0x13, 0x99, 0x5e, 0xe7, 0x22, 0x8c, 0x6b, 0x3f, - 0x95, 0xc9, 0x12, 0x3f, 0x7e, 0xad, 0x06, 0x53, 0x60, 0x26, 0x89, 0xd5, 0x80, 0xb9, 0x2c, 0xa1, - 0x61, 0x7c, 0xa4, 0xe7, 0x64, 0x25, 0x8e, 0xb4, 0xd4, 0xdd, 0xdb, 0xee, 0x5c, 0x5e, 0x94, 0x25, - 0xeb, 0xff, 0xee, 0x87, 0x4b, 0x62, 0x30, 0x5e, 0xe5, 0x88, 0x93, 0x1f, 0xc3, 0xa8, 0x36, 0xc6, - 0x42, 0xe8, 0x57, 0x65, 0x64, 0xc7, 0xbc, 0xb9, 0xc0, 0x4d, 0x1a, 0x1d, 0x04, 0xd4, 0x13, 0xc3, - 0xbd, 0xda, 0x63, 0xeb, 0x2c, 0x49, 0x0b, 0x26, 0xcc, 0x81, 0x16, 0x56, 0x9d, 0xd7, 0x32, 0x2b, - 0x31, 0x51, 0x65, 0x9c, 0xe0, 0x66, 0x3d, 0x73, 0xb8, 0x57, 0x7b, 0xec, 0x04, 0x6f, 0xf2, 0x0d, - 0x9c, 0x4f, 0x8d, 0xb2, 0x30, 0xd6, 0xbd, 0x99, 0x59, 0x61, 0x0a, 0x9b, 0x9b, 0x63, 0x03, 0x04, - 0xe7, 0x56, 0x9b, 0xae, 0x84, 0x34, 0x61, 0x4c, 0x1f, 0x78, 0x61, 0x76, 0xba, 0x56, 0x20, 0x4a, - 0x8e, 0xc8, 0x95, 0x3b, 0x21, 0x4b, 0x1c, 0xfb, 0xe7, 0xa6, 0x89, 0xd9, 0x40, 0x1e, 0x86, 0x41, - 0xfe, 0x9b, 0x2d, 0x01, 0xdb, 0x01, 0x0d, 0xa9, 0xd7, 0xa0, 0x86, 0x83, 0xf6, 0x4b, 0x2e, 0x01, - 0xff, 0xa2, 0x04, 0xb3, 0x59, 0x7c, 0x6b, 0xd4, 0x6b, 0x92, 0x6d, 0x28, 0x27, 0x2b, 0x12, 0xb3, - 0xda, 0x52, 0xa1, 0x58, 0x73, 0x9b, 0xb4, 0xda, 0x63, 0xa7, 0xa8, 0xc9, 0x26, 0x9c, 0xd7, 0x60, - 0xc2, 0xb8, 0xda, 0x7b, 0x1a, 0xe3, 0x2a, 0x1b, 0x85, 0x14, 0xa9, 0x6e, 0x9b, 0x5e, 0xc5, 0x9d, - 0x71, 0xd9, 0x3f, 0x72, 0x5c, 0x8f, 0x29, 0xba, 0x5a, 0xb0, 0x25, 0x88, 0xa1, 0x42, 0x36, 0xdc, - 0xda, 0x8a, 0x50, 0xf9, 0xa0, 0x44, 0xa1, 0x58, 0x9f, 0xe0, 0x0a, 0x2e, 0x6c, 0x74, 0xfc, 0x79, - 0xaa, 0x62, 0x76, 0x15, 0x06, 0x76, 0xd6, 0x6b, 0x4b, 0x55, 0xf1, 0xd8, 0x95, 0x87, 0x48, 0x68, - 0x85, 0xf5, 0x86, 0x63, 0xf3, 0x02, 0xeb, 0x63, 0x20, 0xf7, 0x69, 0x24, 0x62, 0x81, 0x2b, 0xba, - 0x37, 0x60, 0x48, 0x80, 0x04, 0x25, 0xba, 0xc6, 0xb5, 0x04, 0x96, 0x2c, 0xb3, 0xb6, 0xe5, 0x39, - 0xa1, 0x45, 0x9d, 0x50, 0xdb, 0x98, 0x3f, 0x80, 0xe1, 0x40, 0xc0, 0xc4, 0xbe, 0x3c, 0xa1, 0xb2, - 0x26, 0x20, 0x98, 0xdb, 0xb3, 0x25, 0x8e, 0xad, 0xfe, 0xb2, 0xd6, 0x31, 0x9c, 0xc9, 0xd6, 0xda, - 0xf2, 0x12, 0x93, 0xaa, 0x10, 0x96, 0x1c, 0x8e, 0x5b, 0xe8, 0x43, 0x1e, 0x51, 0xfd, 0xa9, 0x2b, - 0x8a, 0x06, 0x3f, 0x72, 0x11, 0xc4, 0x47, 0x43, 0xb1, 0xee, 0xaa, 0xe0, 0x28, 0x19, 0xdc, 0xf2, - 0xa2, 0xff, 0x6f, 0x62, 0xd8, 0x97, 0xfb, 0xe8, 0x2e, 0xf3, 0x2a, 0x1a, 0xe1, 0xc0, 0x1c, 0xdf, - 0xe6, 0x59, 0xaf, 0x44, 0x4a, 0x2b, 0x5f, 0x2d, 0x8d, 0x4b, 0x30, 0xa2, 0x60, 0xea, 0xee, 0x8b, - 0xcb, 0xca, 0xc0, 0xdf, 0xbb, 0xcb, 0x5f, 0x05, 0x37, 0x14, 0x83, 0x98, 0x8e, 0x55, 0xc1, 0xbf, - 0xbb, 0x6f, 0xb9, 0x8a, 0x90, 0x06, 0xd1, 0xb7, 0x5a, 0x45, 0x1c, 0x17, 0xe8, 0x2c, 0x55, 0x18, - 0xf8, 0x7b, 0x0b, 0xa7, 0x11, 0xd4, 0xb7, 0x5c, 0x05, 0x13, 0xd4, 0xb7, 0x57, 0x05, 0x95, 0x01, - 0x94, 0xf8, 0x24, 0x4d, 0x55, 0xb2, 0x92, 0xae, 0x44, 0x1a, 0xae, 0x13, 0x14, 0x85, 0xe3, 0x41, - 0x61, 0x9e, 0x0b, 0xeb, 0x57, 0x50, 0x0d, 0x13, 0xd8, 0xb7, 0x5b, 0xcd, 0xff, 0x57, 0xe2, 0xe1, - 0x9c, 0x6a, 0x5b, 0x5a, 0x32, 0x39, 0xef, 0xb1, 0xaf, 0x5d, 0xcd, 0x6b, 0x5f, 0xfb, 0x43, 0xd7, - 0x6b, 0xea, 0x57, 0xf3, 0x4e, 0x27, 0x3a, 0x54, 0x01, 0x87, 0x9f, 0xb8, 0x5e, 0xd3, 0x4e, 0x62, - 0x93, 0x0f, 0x61, 0x5c, 0x03, 0x29, 0x6d, 0x8d, 0xa7, 0x24, 0xd0, 0xc9, 0xdd, 0xa6, 0x6d, 0x62, - 0x5a, 0x7f, 0x57, 0x82, 0xc9, 0x8c, 0x24, 0xa7, 0x68, 0xcc, 0xc0, 0x53, 0x90, 0x5a, 0xa8, 0x44, - 0x3e, 0x1e, 0x8c, 0x2c, 0x61, 0x6c, 0x92, 0x0a, 0x11, 0x83, 0xb1, 0x6b, 0x09, 0x59, 0x7b, 0xb5, - 0xa4, 0x4f, 0xd9, 0x49, 0x58, 0x75, 0x74, 0x12, 0x02, 0xc4, 0x2d, 0x11, 0x66, 0xe3, 0x1a, 0x53, - 0x69, 0xb5, 0x6c, 0xae, 0xaf, 0x24, 0x9d, 0xac, 0x56, 0x8d, 0xf5, 0x3b, 0xbd, 0x70, 0x21, 0xa3, - 0xff, 0x35, 0x1a, 0xfd, 0x7d, 0x88, 0x20, 0x91, 0x53, 0xb7, 0xef, 0x57, 0x94, 0x53, 0xd7, 0xfa, - 0xb7, 0xbd, 0x70, 0x61, 0xb7, 0x1d, 0xe2, 0x0b, 0xab, 0x35, 0xef, 0x29, 0xf5, 0x22, 0x3f, 0x78, - 0x8e, 0xaf, 0x42, 0xc8, 0x7b, 0x30, 0xb0, 0x4a, 0x5b, 0x2d, 0x5f, 0xcc, 0xff, 0xcb, 0xd2, 0x3b, - 0x22, 0x89, 0x8d, 0x48, 0xab, 0x3d, 0x36, 0xc7, 0x26, 0x1f, 0xc2, 0xc8, 0x2a, 0x75, 0x82, 0x68, - 0x9f, 0x3a, 0xf2, 0xc8, 0x22, 0x13, 0x25, 0x68, 0x24, 0x02, 0x61, 0xb5, 0xc7, 0x8e, 0xb1, 0xc9, - 0x02, 0x3b, 0xcd, 0x7b, 0x07, 0xea, 0x35, 0x79, 0x4e, 0x85, 0x0c, 0x67, 0xb5, 0xc7, 0x46, 0x5c, - 0xb2, 0x01, 0xe3, 0xd5, 0x03, 0xea, 0x45, 0x1b, 0x34, 0x72, 0x9a, 0x4e, 0xe4, 0x08, 0xd5, 0xf6, - 0x8d, 0x3c, 0x62, 0x03, 0x79, 0xb5, 0xc7, 0x36, 0xa9, 0xc9, 0xc7, 0x30, 0x74, 0xdf, 0xf7, 0x9b, - 0xfb, 0xcf, 0xa9, 0x50, 0x57, 0x2b, 0x79, 0x8c, 0x04, 0xda, 0x6a, 0x8f, 0x2d, 0x29, 0x16, 0x07, - 0xa0, 0x6f, 0x23, 0x3c, 0xb0, 0x8e, 0x4b, 0x30, 0xbb, 0xec, 0x3f, 0xf3, 0x32, 0xa5, 0xfa, 0x3d, - 0x53, 0xaa, 0x92, 0x7d, 0x06, 0x7e, 0x42, 0xae, 0xef, 0x42, 0xff, 0xb6, 0xeb, 0x1d, 0x24, 0x54, - 0xc1, 0x0c, 0x3a, 0x86, 0x85, 0xe2, 0x71, 0xbd, 0x03, 0xb2, 0x2e, 0x75, 0x70, 0x61, 0x6b, 0xec, - 0x33, 0x14, 0xff, 0x0c, 0x6a, 0x1d, 0x3b, 0xd6, 0xb5, 0xf9, 0x6f, 0xd9, 0xc1, 0xb7, 0x61, 0x26, - 0xa7, 0x5e, 0xf1, 0x3c, 0x9c, 0xf5, 0xad, 0x1f, 0x15, 0x9b, 0xb7, 0x60, 0x3a, 0x73, 0xfc, 0x52, - 0x88, 0xff, 0x30, 0x6b, 0x22, 0xf2, 0x9e, 0xcf, 0xc2, 0x90, 0x4c, 0xc6, 0xc3, 0x6d, 0x3f, 0xf2, - 0x27, 0x3e, 0x90, 0x92, 0x1f, 0xaa, 0x0c, 0xec, 0x21, 0xbf, 0xc7, 0x3d, 0x2d, 0x90, 0x12, 0xff, - 0x9c, 0x3e, 0x7a, 0x89, 0x8f, 0x46, 0xf1, 0x62, 0x75, 0xae, 0xfa, 0x61, 0xe4, 0x29, 0xcf, 0x5b, - 0x5b, 0xfd, 0x26, 0x37, 0xa0, 0x2c, 0xb3, 0x05, 0x88, 0xb4, 0x24, 0x22, 0x07, 0xb0, 0x9d, 0x82, - 0x93, 0x0f, 0x60, 0x26, 0x09, 0x93, 0xbd, 0xe4, 0x2f, 0xdc, 0xf2, 0x8a, 0xad, 0xbf, 0xea, 0xc5, - 0x68, 0xd3, 0x05, 0xf3, 0x9a, 0x49, 0x77, 0xab, 0x26, 0xa4, 0xd5, 0xbb, 0x55, 0x23, 0xf3, 0x30, - 0xb2, 0x55, 0x33, 0x32, 0x1a, 0xd9, 0x31, 0x80, 0x35, 0x9b, 0x75, 0xa1, 0x1a, 0x34, 0x0e, 0xdd, - 0x88, 0x36, 0xa2, 0x4e, 0x20, 0x56, 0x61, 0x3b, 0x05, 0x27, 0x16, 0x8c, 0xdd, 0x6f, 0xb9, 0xfb, - 0x0d, 0xc9, 0x8c, 0x8b, 0xc0, 0x80, 0x91, 0x37, 0x61, 0x62, 0xcd, 0x0b, 0x23, 0xa7, 0xd5, 0xda, - 0xa0, 0xd1, 0xa1, 0xdf, 0x14, 0xe9, 0x16, 0xed, 0x04, 0x94, 0xd5, 0xbb, 0xe4, 0x7b, 0x91, 0xe3, - 0x7a, 0x34, 0xb0, 0x3b, 0x5e, 0xe4, 0x1e, 0x51, 0xd1, 0xf7, 0x14, 0x9c, 0xbc, 0x0b, 0xd3, 0x0a, - 0xb6, 0x15, 0x34, 0x0e, 0x69, 0x18, 0x05, 0x98, 0xe7, 0x0c, 0x03, 0xfe, 0xd8, 0xd9, 0x85, 0x58, - 0x43, 0xcb, 0xef, 0x34, 0x57, 0xbc, 0xa7, 0x6e, 0xe0, 0x7b, 0x98, 0xfa, 0x60, 0x58, 0xd4, 0x90, - 0x80, 0x5b, 0x7f, 0x3c, 0x9c, 0xf9, 0xd9, 0xbe, 0xcc, 0x1c, 0xfc, 0x12, 0xc6, 0x96, 0x9c, 0xb6, - 0xb3, 0xef, 0xb6, 0xdc, 0xc8, 0x55, 0x09, 0xa1, 0xde, 0xeb, 0xf2, 0xcd, 0xcb, 0xfc, 0x11, 0xb4, - 0xa9, 0x13, 0xdb, 0x06, 0xab, 0xb9, 0xbf, 0x1d, 0x84, 0xe9, 0x4c, 0x3c, 0x72, 0x5d, 0x64, 0x8e, - 0x52, 0xeb, 0xaa, 0xc8, 0xa5, 0x64, 0x27, 0xc1, 0x6c, 0x2c, 0x11, 0xb4, 0xd4, 0xa2, 0x8e, 0xd7, - 0x11, 0x99, 0x94, 0x6c, 0x03, 0xc6, 0xc6, 0x92, 0xe9, 0x0d, 0x1a, 0x33, 0x74, 0x9c, 0xb6, 0x13, - 0x50, 0x72, 0x15, 0x46, 0x19, 0x44, 0xb2, 0xea, 0xe7, 0x4f, 0xfc, 0x34, 0x10, 0xe3, 0xb4, 0xe9, - 0x37, 0xa9, 0xc6, 0x69, 0x80, 0x73, 0x32, 0xa1, 0x8c, 0x13, 0x83, 0x48, 0x4e, 0x83, 0x9c, 0x93, - 0x06, 0x22, 0xaf, 0xc3, 0x78, 0xb5, 0xdd, 0xd6, 0x18, 0x61, 0x0a, 0x25, 0xdb, 0x04, 0x92, 0x2b, - 0x00, 0xd5, 0x76, 0x5b, 0xb2, 0xc1, 0xf4, 0x48, 0xb6, 0x06, 0x21, 0x37, 0xe3, 0x70, 0x65, 0x1a, - 0x2b, 0xbc, 0x4e, 0xb0, 0x33, 0x4a, 0x98, 0x5c, 0x55, 0x6c, 0x27, 0xc1, 0x14, 0xb8, 0x5c, 0x13, - 0x60, 0xf2, 0x09, 0x5c, 0x4c, 0xf8, 0x5d, 0x68, 0x15, 0xa0, 0xa9, 0xdf, 0xce, 0x47, 0x20, 0xef, - 0xc3, 0x85, 0x44, 0xa1, 0xac, 0x0e, 0xad, 0xfa, 0x76, 0x4e, 0x29, 0xf9, 0x08, 0x66, 0x13, 0xcf, - 0xb6, 0xe3, 0x4a, 0xd1, 0x82, 0x6f, 0xe7, 0x96, 0xb3, 0xaf, 0x2b, 0xf1, 0xfe, 0x4b, 0x54, 0x89, - 0x97, 0x95, 0x76, 0x76, 0x21, 0x59, 0x85, 0x4a, 0xa6, 0x2f, 0x8b, 0x56, 0x31, 0xa6, 0x7d, 0xb2, - 0xbb, 0xa1, 0x91, 0x45, 0x98, 0xcf, 0x44, 0x91, 0xcd, 0xc0, 0x64, 0x50, 0x76, 0x21, 0x0e, 0x59, - 0x80, 0xa9, 0xd8, 0xa7, 0x47, 0x6b, 0x02, 0xe6, 0x81, 0xb2, 0x33, 0xcb, 0xc8, 0x3b, 0xe6, 0xe3, - 0x7c, 0x5e, 0x19, 0xa6, 0x81, 0xb2, 0xd3, 0x05, 0xd6, 0x49, 0x09, 0xe6, 0x33, 0x37, 0x4a, 0xa9, - 0xcf, 0xcf, 0x25, 0x15, 0x47, 0x6d, 0x2d, 0xb8, 0x01, 0xfd, 0xa8, 0xe0, 0x73, 0x5b, 0xb1, 0xf4, - 0x35, 0x45, 0x7a, 0xce, 0x8a, 0x95, 0xda, 0x88, 0x43, 0xee, 0xab, 0xbb, 0xc1, 0x3e, 0xb4, 0x64, - 0xdc, 0x4a, 0x2a, 0x50, 0x19, 0x95, 0xeb, 0x77, 0x84, 0xf2, 0x36, 0xf0, 0x65, 0xae, 0x61, 0xfe, - 0xaa, 0x04, 0x95, 0x2e, 0xfa, 0x81, 0xea, 0x53, 0xe9, 0x14, 0x7d, 0x7a, 0xa0, 0xfa, 0xc4, 0xdf, - 0xc6, 0x2e, 0x9c, 0x4e, 0x07, 0x79, 0xd5, 0xdd, 0xea, 0x00, 0x49, 0xab, 0xa1, 0xe4, 0xbb, 0x30, - 0x52, 0xab, 0xad, 0x1a, 0x0e, 0x7d, 0xa9, 0xcb, 0xa1, 0x18, 0x83, 0xdc, 0x3e, 0x95, 0x07, 0x9f, - 0xe6, 0xbf, 0x67, 0x2d, 0xc3, 0x6c, 0x9e, 0x06, 0x89, 0x0b, 0x0b, 0x8f, 0xad, 0xa5, 0x5d, 0x2c, - 0xf1, 0x85, 0xc5, 0x04, 0x5b, 0xef, 0xc3, 0x05, 0x45, 0xcd, 0xd3, 0x66, 0x68, 0x0f, 0xff, 0xc5, - 0xb1, 0x53, 0x05, 0x18, 0x88, 0x01, 0xd6, 0x5f, 0xf6, 0xa7, 0x08, 0x6b, 0x9d, 0xa3, 0x23, 0x27, - 0x78, 0x4e, 0xaa, 0x26, 0x61, 0x5f, 0x57, 0x4d, 0x7f, 0xb1, 0xff, 0xe7, 0xc7, 0x95, 0x1e, 0x8d, - 0x3b, 0x5b, 0x8e, 0x71, 0x63, 0xf7, 0x1a, 0x94, 0x5f, 0x49, 0xf5, 0xf2, 0xe0, 0x46, 0x06, 0x90, - 0xec, 0xc1, 0xb8, 0xd8, 0x32, 0xf1, 0xb7, 0x9c, 0xda, 0xb7, 0x93, 0x53, 0xdb, 0x68, 0xde, 0x4d, - 0x83, 0x84, 0x4f, 0x02, 0x93, 0x0d, 0xf9, 0x12, 0x26, 0xa4, 0x82, 0x24, 0x18, 0x73, 0x27, 0xa2, - 0x3b, 0xc5, 0x8c, 0x4d, 0x1a, 0xce, 0x39, 0xc1, 0x88, 0x35, 0x59, 0xae, 0x31, 0x9c, 0xf3, 0xc0, - 0x69, 0x9a, 0x6c, 0x90, 0x88, 0x26, 0x1b, 0xb0, 0xb9, 0x1f, 0x00, 0x49, 0xf7, 0xab, 0xdb, 0x2c, - 0x1e, 0xd7, 0x66, 0xf1, 0x5c, 0x15, 0x26, 0x33, 0x3a, 0x70, 0x26, 0x16, 0x3f, 0x00, 0x92, 0x6e, - 0xe9, 0x59, 0x38, 0x58, 0xd7, 0xe1, 0x4d, 0x25, 0x02, 0x35, 0x1b, 0x0c, 0x9e, 0xd2, 0xf0, 0xfc, - 0xdb, 0xbd, 0x50, 0xe9, 0x82, 0x4a, 0xfe, 0xa8, 0x94, 0x94, 0x36, 0x9f, 0x8d, 0x1f, 0x26, 0xa5, - 0x9d, 0x4d, 0x9f, 0x21, 0xf6, 0xc5, 0x8f, 0x7e, 0xf6, 0x37, 0x2f, 0xac, 0xf0, 0xa7, 0x87, 0xec, - 0xec, 0xd2, 0xea, 0xd7, 0xa5, 0x65, 0xc3, 0x94, 0x71, 0x54, 0x3a, 0xcd, 0x9e, 0x71, 0x05, 0x40, - 0x64, 0x90, 0x5c, 0xf7, 0x0f, 0x84, 0x7a, 0xa6, 0x41, 0xac, 0x7b, 0x30, 0x9d, 0xe0, 0x29, 0x8c, - 0xe1, 0xdf, 0x05, 0xf5, 0xc0, 0x1b, 0x99, 0xf6, 0x2d, 0x9e, 0xff, 0xe5, 0x71, 0x65, 0x9c, 0x69, - 0xd2, 0x37, 0xe3, 0xf8, 0xf1, 0xf2, 0x2f, 0x6b, 0x43, 0x37, 0xe7, 0x57, 0x5b, 0x7a, 0xe0, 0x1b, - 0x72, 0x07, 0x06, 0x39, 0x24, 0x11, 0xa5, 0x59, 0xc7, 0x16, 0x6b, 0x82, 0x40, 0xb4, 0xa6, 0xf1, - 0x39, 0x2a, 0xfe, 0xa8, 0xc6, 0xe1, 0x13, 0xac, 0x5d, 0x9e, 0x37, 0x24, 0x06, 0xab, 0x48, 0xd0, - 0xfd, 0xd5, 0x38, 0xcc, 0x83, 0xf4, 0xbd, 0x90, 0x78, 0x9e, 0xff, 0xac, 0x45, 0x9b, 0x3c, 0xe1, - 0xd8, 0xe2, 0x98, 0xf0, 0xbd, 0xe8, 0x77, 0x18, 0x03, 0x24, 0xb3, 0x3e, 0x83, 0x69, 0xb6, 0x41, - 0x07, 0xc9, 0xfa, 0xc8, 0x9b, 0x30, 0x84, 0x30, 0xd3, 0xa1, 0xdd, 0x61, 0x20, 0x74, 0x68, 0x17, - 0x85, 0xd6, 0x3a, 0x5c, 0xe4, 0xc6, 0x40, 0xbd, 0x4b, 0xb1, 0xe9, 0x7d, 0x00, 0x7f, 0x27, 0x1e, - 0x33, 0x66, 0xf4, 0x9e, 0xe3, 0x59, 0x9f, 0xe2, 0x6b, 0x19, 0x31, 0x49, 0x5d, 0xdf, 0x8b, 0x2d, - 0x7f, 0xa7, 0x7b, 0x5e, 0xfb, 0xbf, 0xc2, 0x7c, 0xb5, 0xdd, 0xa6, 0x5e, 0x33, 0x26, 0xdc, 0x09, - 0x9c, 0x53, 0x06, 0x3f, 0x20, 0x55, 0x18, 0x40, 0x6c, 0x75, 0x6f, 0x29, 0x9a, 0x9b, 0xd1, 0x1c, - 0xc4, 0x13, 0x61, 0x3b, 0xb1, 0x02, 0x4e, 0x69, 0x35, 0x61, 0xa6, 0xd6, 0xd9, 0x3f, 0x72, 0x23, - 0x74, 0x83, 0xc7, 0x00, 0x22, 0xb2, 0xee, 0x35, 0x99, 0xea, 0x89, 0x0b, 0xe3, 0x7a, 0xfc, 0xaa, - 0x02, 0x3d, 0xe9, 0x45, 0x50, 0x91, 0xa7, 0x77, 0x6e, 0xc6, 0xa4, 0x68, 0xf5, 0xe0, 0xb5, 0x60, - 0xb1, 0x48, 0x07, 0x65, 0x4d, 0xc2, 0x79, 0xfd, 0x0e, 0x88, 0xcf, 0x90, 0x69, 0x98, 0x34, 0xef, - 0x76, 0x38, 0xf8, 0x6b, 0x98, 0xe2, 0xb6, 0x67, 0x1e, 0x76, 0x7b, 0x21, 0x8e, 0x30, 0xdd, 0xbb, - 0xb7, 0x90, 0xf0, 0xbf, 0x47, 0xb7, 0x5c, 0x95, 0x50, 0x61, 0x6f, 0x81, 0xbf, 0x78, 0x7c, 0xba, - 0x60, 0xdc, 0x20, 0xf6, 0xee, 0x2d, 0x2c, 0x0e, 0x89, 0xf0, 0xa5, 0x8c, 0x3b, 0x1f, 0xfe, 0x6f, - 0x85, 0xfb, 0x02, 0x3e, 0xb2, 0x5f, 0xa5, 0x0e, 0x3e, 0x88, 0xc9, 0x7e, 0xaa, 0x3c, 0x01, 0xbd, - 0x6e, 0x53, 0x9e, 0xd6, 0xdd, 0xa6, 0xf5, 0x67, 0x25, 0xb8, 0xce, 0x75, 0xa0, 0x6c, 0x3a, 0xbc, - 0xe8, 0xc9, 0x21, 0x26, 0x1f, 0x00, 0x4f, 0x0a, 0x2e, 0x14, 0x4d, 0x4b, 0xb4, 0xbc, 0x88, 0x13, - 0x27, 0x20, 0x55, 0x18, 0xd3, 0x9f, 0x94, 0x9c, 0x2e, 0x3c, 0x9c, 0x3d, 0x7a, 0xf4, 0xd8, 0x51, - 0xcf, 0x4c, 0x9e, 0xc0, 0xa5, 0x95, 0x6f, 0xd8, 0x84, 0x10, 0xbb, 0x93, 0x50, 0xd8, 0xe3, 0xa7, - 0xb0, 0xe7, 0x76, 0xc4, 0x8c, 0x31, 0x4f, 0xd3, 0x49, 0x30, 0x3b, 0x9a, 0xca, 0x0d, 0x4e, 0x69, - 0xcd, 0x23, 0xb6, 0x01, 0xb3, 0xfe, 0xb2, 0x04, 0xf3, 0xd9, 0xb5, 0x89, 0x85, 0x65, 0x0d, 0xce, - 0x2f, 0x39, 0x9e, 0xef, 0xb9, 0x0d, 0xa7, 0x55, 0x6b, 0x1c, 0xd2, 0x66, 0x47, 0x05, 0x39, 0x55, - 0xab, 0xcc, 0x01, 0xf5, 0x24, 0xb9, 0x44, 0xb1, 0xd3, 0x54, 0xec, 0x50, 0x86, 0xaf, 0x12, 0xf8, - 0xda, 0xdb, 0xa2, 0x81, 0xe2, 0xc7, 0x5b, 0x96, 0x53, 0x4a, 0x6e, 0x4b, 0x23, 0x7b, 0x73, 0xd7, - 0x73, 0x23, 0x45, 0xc4, 0xad, 0x2b, 0x59, 0x45, 0xd6, 0xbf, 0x2e, 0xc1, 0x45, 0xcc, 0x2c, 0x64, - 0xe4, 0x2a, 0x8c, 0x63, 0xfd, 0xca, 0x70, 0xb5, 0x25, 0xe3, 0x95, 0x85, 0x81, 0x6d, 0xc6, 0xad, - 0x25, 0xef, 0x40, 0x7f, 0x4d, 0x3a, 0x49, 0x4d, 0x24, 0xb2, 0x9c, 0xca, 0x8c, 0xf2, 0x7e, 0x10, - 0xd9, 0x88, 0xc5, 0xf6, 0x9c, 0x65, 0x1a, 0x36, 0xa8, 0x87, 0xe9, 0x68, 0xf9, 0x61, 0x5f, 0x83, - 0xc4, 0xa1, 0x8a, 0xfa, 0xf3, 0x42, 0x15, 0x0d, 0x98, 0xa1, 0x8a, 0xac, 0xa7, 0x3c, 0xaf, 0x50, - 0xb2, 0x43, 0x62, 0x90, 0x3e, 0x4d, 0x65, 0xaf, 0xe5, 0xfb, 0xc0, 0x85, 0xac, 0x9e, 0xed, 0xdd, - 0x4d, 0x25, 0xa6, 0xcd, 0x8f, 0xad, 0xbb, 0x0d, 0xaf, 0x1b, 0xb8, 0xd5, 0x56, 0xcb, 0x7f, 0x46, - 0x9b, 0xdb, 0x81, 0x7f, 0xe4, 0x47, 0x46, 0x56, 0x17, 0x91, 0xbe, 0x39, 0xbe, 0x46, 0x11, 0xb3, - 0x32, 0x01, 0xb6, 0xfe, 0x17, 0x78, 0xa3, 0x0b, 0x47, 0xd1, 0xa9, 0x1a, 0x9c, 0x77, 0x12, 0x65, - 0xd2, 0xdb, 0xe5, 0x8d, 0xac, 0x7e, 0x25, 0x19, 0x85, 0x76, 0x9a, 0xfe, 0xc6, 0x8e, 0x91, 0xf1, - 0x95, 0xcc, 0xc2, 0xd4, 0xb6, 0xbd, 0xb5, 0xbc, 0xbb, 0xb4, 0x53, 0xdf, 0xf9, 0x72, 0x7b, 0xa5, - 0xbe, 0xbb, 0xf9, 0x70, 0x73, 0xeb, 0xd1, 0x26, 0x0f, 0x4e, 0x6d, 0x94, 0xec, 0xac, 0x54, 0x37, - 0xca, 0x25, 0x32, 0x05, 0x65, 0x03, 0xbc, 0xb2, 0xbb, 0x58, 0xee, 0xbd, 0xf1, 0xb5, 0x91, 0xc9, - 0x94, 0xcc, 0xc3, 0x6c, 0x6d, 0x77, 0x7b, 0x7b, 0xcb, 0x56, 0x5c, 0xf5, 0xd0, 0xd8, 0xd3, 0x70, - 0xde, 0x28, 0xbd, 0x67, 0xaf, 0xac, 0x94, 0x4b, 0xac, 0x29, 0x06, 0x78, 0xdb, 0x5e, 0xd9, 0x58, - 0xdb, 0xdd, 0x28, 0xf7, 0xde, 0xa8, 0xeb, 0x4f, 0xbb, 0xc8, 0x25, 0x98, 0x59, 0x5e, 0xd9, 0x5b, - 0x5b, 0x5a, 0xc9, 0xe2, 0x3d, 0x05, 0x65, 0xbd, 0x70, 0x67, 0x6b, 0x67, 0x9b, 0xb3, 0xd6, 0xa1, - 0x8f, 0x56, 0x16, 0xab, 0xbb, 0x3b, 0xab, 0x9b, 0xe5, 0x3e, 0xab, 0x7f, 0xb8, 0xb7, 0xdc, 0x7b, - 0xe3, 0xc7, 0xc6, 0xbb, 0x2f, 0xd6, 0x7c, 0x81, 0xbe, 0x5b, 0xab, 0xde, 0xcf, 0xaf, 0x82, 0x97, - 0x6e, 0xdc, 0xab, 0x96, 0x4b, 0xe4, 0x32, 0x5c, 0x34, 0xa0, 0xdb, 0xd5, 0x5a, 0xed, 0xd1, 0x96, - 0xbd, 0xbc, 0xbe, 0x52, 0xab, 0x95, 0x7b, 0x6f, 0xec, 0x19, 0xe1, 0xd9, 0x58, 0x0d, 0x1b, 0xf7, - 0xaa, 0x75, 0x7b, 0xe5, 0xf3, 0xdd, 0x35, 0x7b, 0x65, 0x39, 0x5d, 0x83, 0x51, 0xfa, 0xe5, 0x4a, - 0xad, 0x5c, 0x22, 0x93, 0x70, 0xce, 0x80, 0x6e, 0x6e, 0x95, 0x7b, 0x6f, 0xbc, 0x29, 0x22, 0x78, - 0x91, 0x09, 0x80, 0xe5, 0x95, 0xda, 0xd2, 0xca, 0xe6, 0xf2, 0xda, 0xe6, 0xfd, 0x72, 0x0f, 0x19, - 0x87, 0x91, 0xaa, 0xfa, 0x59, 0xba, 0xf1, 0x11, 0x9c, 0x4b, 0x9c, 0xa8, 0x19, 0x86, 0x3a, 0x8c, - 0x96, 0x7b, 0x50, 0xfc, 0xf2, 0x27, 0x9a, 0x35, 0xf9, 0xe1, 0xb8, 0x5c, 0xba, 0xb1, 0x28, 0x93, - 0x8f, 0x6a, 0xdf, 0x39, 0x19, 0x85, 0xa1, 0xe5, 0x95, 0x7b, 0xd5, 0xdd, 0xf5, 0x9d, 0x72, 0x0f, - 0xfb, 0xb1, 0x64, 0xaf, 0x54, 0x77, 0x56, 0x96, 0xcb, 0x25, 0x32, 0x02, 0x03, 0xb5, 0x9d, 0xea, - 0xce, 0x4a, 0xb9, 0x97, 0x0c, 0x43, 0xff, 0x6e, 0x6d, 0xc5, 0x2e, 0xf7, 0x2d, 0xfc, 0xc9, 0x1f, - 0x95, 0xb8, 0x6d, 0x4f, 0xbe, 0x21, 0xfa, 0x5a, 0x3b, 0x4c, 0x8a, 0x25, 0x4f, 0x64, 0x5a, 0xcc, - 0x3d, 0x39, 0xa2, 0x16, 0x30, 0x57, 0x70, 0xd9, 0x81, 0x08, 0xd7, 0x4b, 0xb7, 0x4b, 0xc4, 0x46, - 0xe7, 0x90, 0xc4, 0xd9, 0x4a, 0x71, 0xce, 0x3e, 0xfe, 0xce, 0x5d, 0x2e, 0x3c, 0x92, 0x91, 0xdf, - 0x00, 0x4b, 0xe7, 0x99, 0x73, 0x02, 0xf9, 0xee, 0xe9, 0x4e, 0x1a, 0xb2, 0xce, 0x37, 0x4f, 0x87, - 0x4e, 0x1e, 0xc0, 0x38, 0xd3, 0xcd, 0x15, 0x1a, 0xb9, 0x94, 0x24, 0xd4, 0x8e, 0x03, 0x73, 0xf3, - 0xd9, 0x85, 0x2a, 0x15, 0xcb, 0x18, 0x76, 0x84, 0x1f, 0xac, 0x43, 0x22, 0xa3, 0x3c, 0x48, 0x08, - 0x5f, 0xf1, 0xe7, 0xce, 0x27, 0xc0, 0x7b, 0x77, 0x6e, 0x97, 0x48, 0x0d, 0x43, 0xac, 0x19, 0x4a, - 0x3e, 0x91, 0x8f, 0xda, 0xd2, 0xda, 0x3f, 0x6f, 0x4d, 0x45, 0xa5, 0x2e, 0xcc, 0x39, 0x1d, 0x6c, - 0x02, 0x49, 0xeb, 0xce, 0xe4, 0x6a, 0x3c, 0x0f, 0xb2, 0xd5, 0xea, 0xb9, 0x0b, 0x29, 0x9f, 0xbf, - 0x15, 0xa6, 0x3d, 0x91, 0x15, 0x98, 0x10, 0x4f, 0xb8, 0x85, 0x36, 0x4f, 0x8a, 0xce, 0x03, 0xb9, - 0x6c, 0xee, 0xa3, 0x9c, 0xd4, 0x89, 0x80, 0xcc, 0xc5, 0xfd, 0x48, 0x1e, 0x13, 0xe6, 0x2e, 0x65, - 0x96, 0x89, 0xfe, 0xdd, 0x83, 0x09, 0xf3, 0x70, 0x41, 0xe4, 0x00, 0x65, 0x9e, 0x39, 0x72, 0x1b, - 0x54, 0x87, 0x99, 0x0d, 0xc7, 0xc5, 0x2b, 0x0a, 0xe1, 0x59, 0x26, 0xfd, 0xc2, 0x48, 0xa5, 0xc0, - 0x51, 0xac, 0x46, 0xbd, 0xa6, 0x1a, 0x84, 0xbc, 0xb0, 0xea, 0xf8, 0xd9, 0xd4, 0xa4, 0x8e, 0x6c, - 0xfa, 0xd5, 0x11, 0xcb, 0x4c, 0x47, 0x9b, 0xe5, 0x2a, 0x39, 0x97, 0xe7, 0xdd, 0x4b, 0x36, 0x50, - 0x49, 0x4f, 0x70, 0xd4, 0xe6, 0xc4, 0x99, 0xd9, 0xcd, 0x62, 0x20, 0x01, 0x2d, 0x47, 0xb5, 0x28, - 0x0c, 0x49, 0x8e, 0xe0, 0x72, 0x99, 0xdd, 0x2e, 0x91, 0xaf, 0xf1, 0xab, 0xce, 0x64, 0xf7, 0xc8, - 0x8d, 0x0e, 0x85, 0xf6, 0x73, 0x29, 0x93, 0x81, 0xf8, 0x50, 0x0a, 0xb8, 0xdb, 0x30, 0x95, 0xe5, - 0x50, 0xac, 0x04, 0x5a, 0xe0, 0x6d, 0x9c, 0x3b, 0x0b, 0x6c, 0x76, 0xd4, 0x68, 0xe6, 0x0f, 0x52, - 0x81, 0x3f, 0x6b, 0x2e, 0xcf, 0x4f, 0x60, 0x82, 0xcd, 0x92, 0x87, 0x94, 0xb6, 0xab, 0x2d, 0xf7, - 0x29, 0x0d, 0x89, 0x8c, 0x8f, 0xab, 0x40, 0x79, 0xb4, 0xd7, 0x4b, 0xe4, 0x3b, 0x30, 0xfa, 0xc8, - 0x89, 0x1a, 0x87, 0x22, 0x4e, 0xa4, 0x0c, 0x23, 0x89, 0xb0, 0x39, 0xf9, 0x0b, 0x0b, 0x6f, 0x97, - 0xc8, 0xf7, 0x61, 0xe8, 0x3e, 0x8d, 0xf0, 0x51, 0xf1, 0x35, 0xe5, 0x5b, 0xc7, 0x6d, 0x93, 0x6b, - 0x9e, 0x7a, 0x39, 0x23, 0x1b, 0x9c, 0x34, 0xa0, 0x92, 0x5b, 0x00, 0x7c, 0x41, 0x40, 0x0e, 0xc9, - 0xe2, 0xb9, 0x54, 0xb3, 0xc9, 0x7d, 0xa6, 0x3c, 0xb4, 0x68, 0x44, 0x4f, 0x5b, 0x65, 0x9e, 0x8c, - 0xd6, 0x61, 0x42, 0x65, 0xaf, 0xd9, 0xc4, 0x70, 0x1e, 0x56, 0x82, 0x59, 0x78, 0x06, 0x6e, 0x1f, - 0xb1, 0xaf, 0x82, 0x27, 0x4f, 0xc5, 0xb8, 0x0f, 0xb8, 0x92, 0xce, 0xe8, 0xc1, 0x23, 0xf4, 0x25, - 0x54, 0x0a, 0x91, 0xa3, 0x69, 0xb4, 0xab, 0x7e, 0x18, 0x99, 0xb4, 0x0a, 0x92, 0x4d, 0xfb, 0xeb, - 0x30, 0xa7, 0xd7, 0x6b, 0x06, 0x2a, 0x8e, 0xd7, 0xdc, 0xbc, 0xf8, 0xc7, 0x73, 0xd7, 0x0a, 0x30, - 0xc4, 0xf9, 0xad, 0xef, 0x77, 0x7b, 0x4b, 0xb8, 0x9c, 0x2c, 0xc3, 0xa4, 0xac, 0x6b, 0xab, 0x4d, - 0xbd, 0x5a, 0x6d, 0x15, 0x33, 0x95, 0x48, 0x4f, 0x0e, 0x0d, 0x26, 0xb9, 0x93, 0x74, 0x11, 0xdb, - 0xfa, 0x8c, 0xf8, 0x0e, 0xa4, 0x28, 0xea, 0x43, 0xbc, 0xf5, 0x65, 0x46, 0xd0, 0x7d, 0xc8, 0x8d, - 0x4a, 0x86, 0xf2, 0xbf, 0xb7, 0x40, 0x0a, 0x0e, 0x40, 0x73, 0x39, 0x47, 0x88, 0xdb, 0x25, 0xf2, - 0x25, 0x90, 0xf4, 0x91, 0x44, 0x89, 0x30, 0xf7, 0xf8, 0xa5, 0x44, 0x58, 0x70, 0x9e, 0x59, 0x81, - 0x49, 0x15, 0xdd, 0x25, 0x2e, 0x27, 0x39, 0x6d, 0x29, 0xd8, 0xc1, 0xa6, 0x33, 0xd8, 0xec, 0x2d, - 0x14, 0x30, 0xca, 0x84, 0x93, 0xcf, 0x60, 0x52, 0xcc, 0x7d, 0xa3, 0x3d, 0x65, 0xb5, 0x8c, 0x89, - 0xc3, 0x4d, 0x6e, 0x4b, 0x1e, 0xc0, 0x74, 0x2d, 0x21, 0x78, 0xee, 0xc7, 0x7e, 0xd1, 0x64, 0x81, - 0xc0, 0x1a, 0x8d, 0xb8, 0xe4, 0xb3, 0x79, 0x3d, 0x04, 0xc2, 0x6d, 0x4b, 0x92, 0xdd, 0x53, 0x97, - 0x3e, 0x23, 0x97, 0x13, 0x4d, 0x67, 0x40, 0x44, 0xc3, 0x75, 0x30, 0xb7, 0x67, 0x3b, 0x3c, 0x83, - 0x30, 0x42, 0x8d, 0x1b, 0xf0, 0xab, 0x06, 0x81, 0x71, 0x89, 0x2e, 0xc6, 0xf1, 0x62, 0x2e, 0x06, - 0xf9, 0x2d, 0x8c, 0xce, 0x5a, 0x7c, 0x3a, 0x23, 0xdf, 0xc9, 0x3a, 0x44, 0xe7, 0x9c, 0x2f, 0xe7, - 0xde, 0x39, 0x1d, 0xb2, 0x3a, 0x0f, 0x8f, 0xdf, 0xa7, 0xd1, 0x76, 0xab, 0x73, 0xe0, 0x62, 0x66, - 0x4b, 0xa2, 0x6c, 0x4f, 0x0a, 0x24, 0xa6, 0xb7, 0x0c, 0x8a, 0x16, 0x17, 0xd4, 0xe8, 0x4f, 0xc8, - 0x1a, 0x94, 0xf9, 0x36, 0xa2, 0xb1, 0xb8, 0x9c, 0x62, 0x21, 0x50, 0x9c, 0xc0, 0x39, 0x0a, 0x73, - 0x47, 0xeb, 0x16, 0x77, 0x39, 0x22, 0xf2, 0xd3, 0xd6, 0xf5, 0xd4, 0x49, 0x03, 0xa6, 0x22, 0xd6, - 0xb3, 0x11, 0xb1, 0x69, 0x48, 0x23, 0x19, 0x06, 0x86, 0xe7, 0x35, 0x7d, 0x2d, 0xd6, 0x19, 0xd2, - 0xa5, 0xf1, 0x0a, 0x92, 0x08, 0x59, 0xb6, 0x77, 0x97, 0xa8, 0x5c, 0xaf, 0x19, 0x4c, 0xdf, 0x34, - 0x54, 0x9b, 0xb3, 0xf1, 0x7d, 0x17, 0xb7, 0x32, 0x0c, 0x7d, 0x33, 0x1d, 0xb7, 0x8d, 0xfd, 0x96, - 0x54, 0xe3, 0x1a, 0xd5, 0xde, 0x02, 0xae, 0x8c, 0x6c, 0xaf, 0x65, 0x9a, 0x70, 0x27, 0x08, 0xa8, - 0xc7, 0x89, 0xf3, 0xd4, 0x96, 0x2c, 0xea, 0x4f, 0x71, 0x05, 0xd3, 0xa8, 0xf9, 0x73, 0xbb, 0x6e, - 0x2c, 0x78, 0x1e, 0x9e, 0xdb, 0x25, 0xf2, 0x01, 0x0c, 0x8b, 0x36, 0x32, 0x22, 0xa3, 0xd1, 0x61, - 0x41, 0xab, 0x91, 0x12, 0xb8, 0x90, 0xb0, 0xcd, 0x26, 0x4e, 0xde, 0xe8, 0xf3, 0x36, 0x7f, 0xc0, - 0xf6, 0xec, 0xe6, 0x8b, 0x50, 0x2e, 0xc9, 0xcd, 0x1b, 0x29, 0x67, 0x55, 0x24, 0x16, 0x09, 0xea, - 0xb2, 0xcb, 0x72, 0x26, 0x4c, 0xfd, 0xc6, 0x98, 0x83, 0x2a, 0x74, 0x98, 0x52, 0xbf, 0x0d, 0x70, - 0xb7, 0x2d, 0x7b, 0x0d, 0xca, 0xd5, 0x06, 0x6e, 0x28, 0x35, 0x7a, 0xe4, 0xb4, 0x0f, 0xfd, 0x80, - 0xaa, 0xb3, 0x4f, 0xb2, 0x40, 0xf2, 0x9a, 0x56, 0x0a, 0x8a, 0x28, 0x58, 0xa7, 0x0e, 0x06, 0x66, - 0x9e, 0x51, 0x1a, 0x4a, 0xa2, 0x28, 0x9b, 0xa2, 0xe0, 0xac, 0x33, 0xb5, 0xc4, 0x4e, 0x67, 0xad, - 0x97, 0x63, 0xf3, 0x11, 0x2e, 0x18, 0x0a, 0x39, 0x54, 0x3b, 0x84, 0x02, 0xa9, 0x53, 0xa1, 0x7c, - 0x79, 0xa3, 0x50, 0xab, 0xf2, 0xea, 0x39, 0x16, 0x4b, 0x1e, 0x75, 0x5e, 0xf5, 0xdf, 0x83, 0x89, - 0x15, 0xb6, 0xa0, 0x77, 0x9a, 0x2e, 0x0f, 0x46, 0x4f, 0xcc, 0xe8, 0xe2, 0xb9, 0x84, 0xab, 0x32, - 0xf5, 0x15, 0x92, 0x0a, 0x0b, 0x82, 0xdc, 0x53, 0x34, 0x98, 0x1c, 0x8f, 0x29, 0xc9, 0x56, 0xe4, - 0x03, 0xc0, 0x13, 0xbe, 0x30, 0x19, 0xcc, 0x70, 0xc5, 0xb2, 0xda, 0x6e, 0xb7, 0xa4, 0x65, 0x9b, - 0xdf, 0xd4, 0xbf, 0x61, 0x9c, 0x44, 0x53, 0xe5, 0x92, 0x77, 0x5a, 0xf7, 0xfc, 0x42, 0x4b, 0x45, - 0x9b, 0xc3, 0x33, 0xa7, 0xbc, 0xdb, 0x5c, 0x54, 0xe1, 0xa3, 0xab, 0xad, 0x56, 0x8a, 0x38, 0x24, - 0x6f, 0x9b, 0xdc, 0xb3, 0x70, 0xba, 0xd5, 0x80, 0x27, 0x7d, 0x33, 0xbb, 0x3f, 0xb9, 0xa2, 0x16, - 0x8c, 0x64, 0xda, 0xff, 0xe4, 0x49, 0x3f, 0x59, 0x2e, 0xd6, 0xf6, 0x07, 0x38, 0xcd, 0xe2, 0x7c, - 0xb5, 0x44, 0x3f, 0x37, 0x27, 0xd3, 0xf5, 0x2a, 0x5d, 0x2e, 0x3b, 0xc5, 0xff, 0x36, 0x9c, 0x4b, - 0x24, 0xcf, 0x57, 0x06, 0x9e, 0xec, 0xf4, 0xfd, 0x73, 0x57, 0xf2, 0x8a, 0x95, 0xc1, 0xb5, 0x9c, - 0xcc, 0x09, 0xae, 0xba, 0x9c, 0x93, 0xed, 0x5d, 0x75, 0x39, 0x37, 0x99, 0xf8, 0x03, 0x28, 0x27, - 0xd3, 0x11, 0x2b, 0xa6, 0x39, 0x79, 0x8a, 0x73, 0xc7, 0xe4, 0x1e, 0x4c, 0xe9, 0x23, 0xaa, 0xfa, - 0x9d, 0xb7, 0xfa, 0xe7, 0xf1, 0xd9, 0x81, 0xe9, 0xcc, 0xec, 0xc1, 0x6a, 0x8b, 0x2d, 0xca, 0x2d, - 0x9c, 0xcb, 0x95, 0xc2, 0x85, 0xec, 0x04, 0xe2, 0xe4, 0x75, 0xd3, 0x7e, 0x90, 0x9d, 0x4e, 0x79, - 0xee, 0x8d, 0x2e, 0x58, 0x42, 0xa0, 0x5f, 0xe3, 0x0e, 0x98, 0xaa, 0xe3, 0x9a, 0x66, 0x51, 0xc8, - 0xa9, 0xc0, 0x2a, 0x42, 0x51, 0x73, 0x60, 0x2a, 0xa3, 0x38, 0x5f, 0xc4, 0xaf, 0xe5, 0xf3, 0x8c, - 0x27, 0xd6, 0x9e, 0x8c, 0x92, 0x9c, 0x2b, 0x99, 0xc2, 0x44, 0xd3, 0x05, 0x47, 0xd2, 0x39, 0x35, - 0x1f, 0x4e, 0xdf, 0xe4, 0x7c, 0xf3, 0xd2, 0x54, 0x56, 0x7a, 0xf3, 0xa4, 0xf5, 0x27, 0x2b, 0x7b, - 0xb5, 0x12, 0x43, 0x61, 0x7e, 0xf4, 0x3d, 0x6e, 0x09, 0x32, 0xb9, 0xeb, 0x96, 0xa0, 0x4c, 0xd6, - 0x57, 0xf3, 0x11, 0xe2, 0x19, 0x61, 0xc4, 0x5e, 0x17, 0xfd, 0xd7, 0xcf, 0x59, 0xd9, 0x89, 0xad, - 0xd5, 0x8c, 0xc8, 0x44, 0x11, 0xdc, 0x6d, 0xf9, 0xd1, 0xe5, 0x88, 0xa5, 0x20, 0xa9, 0x77, 0xc1, - 0x71, 0x68, 0x36, 0x1e, 0xb8, 0x44, 0xb3, 0xcf, 0x3a, 0x6c, 0x5f, 0xc3, 0xc5, 0xdc, 0x04, 0xde, - 0xe4, 0xad, 0xd4, 0x07, 0x9d, 0x23, 0x89, 0xfc, 0x96, 0x8e, 0x1b, 0xb9, 0xb7, 0x95, 0x29, 0x2c, - 0x91, 0xe6, 0x3b, 0xb5, 0x62, 0x67, 0xe4, 0x00, 0xbf, 0x8f, 0x9a, 0xaf, 0x96, 0xc7, 0x3b, 0xb7, - 0xaf, 0x97, 0xb3, 0xf8, 0x84, 0xe9, 0x35, 0x55, 0x6b, 0x97, 0xd4, 0xc4, 0x92, 0x05, 0x67, 0x59, - 0x53, 0x4f, 0xd3, 0xb4, 0x3c, 0x3e, 0xcb, 0x30, 0xaa, 0x25, 0x00, 0x27, 0x17, 0x0d, 0x31, 0x19, - 0xbb, 0xe4, 0x9c, 0xd1, 0x39, 0x73, 0x83, 0x5c, 0x42, 0x9b, 0xb3, 0x4a, 0x23, 0x9e, 0xdb, 0x8a, - 0x4b, 0x69, 0x1e, 0x86, 0xbd, 0x59, 0x49, 0x81, 0xb7, 0x66, 0x3e, 0x29, 0x1c, 0xa3, 0x41, 0xf9, - 0x5d, 0x22, 0xba, 0x68, 0xba, 0x34, 0x29, 0x5f, 0x43, 0x9d, 0x14, 0x59, 0x46, 0x31, 0x19, 0x8a, - 0x8c, 0xc9, 0x77, 0x41, 0x19, 0xcf, 0x34, 0x68, 0x81, 0x2d, 0x63, 0x1b, 0x9f, 0x76, 0x64, 0x64, - 0x44, 0x57, 0x6b, 0x68, 0x61, 0xc2, 0xf4, 0x0c, 0xed, 0x4c, 0xad, 0xca, 0xb9, 0x1c, 0x0b, 0x53, - 0xa4, 0xe7, 0xb6, 0xf4, 0x47, 0xda, 0xaa, 0x9c, 0xca, 0x7b, 0x4e, 0xae, 0x27, 0x55, 0xb3, 0xbc, - 0xd4, 0xe8, 0x05, 0xab, 0xfe, 0x54, 0x56, 0xca, 0x74, 0xcd, 0x00, 0x9c, 0x9b, 0x4f, 0x3d, 0x43, - 0x0a, 0x6a, 0x79, 0xcb, 0xe1, 0x56, 0x90, 0x40, 0x3d, 0xb7, 0x85, 0x5f, 0x69, 0xcb, 0x5b, 0x22, - 0xd1, 0xb9, 0x3a, 0x70, 0x77, 0xc9, 0x84, 0x9e, 0xcb, 0x7b, 0x13, 0x1f, 0x03, 0xa5, 0xb3, 0x94, - 0x2b, 0xdd, 0xa5, 0x28, 0x87, 0x79, 0xa6, 0x7d, 0x78, 0x3a, 0xdd, 0x45, 0xc6, 0xef, 0x42, 0xc2, - 0xba, 0xdb, 0xad, 0x61, 0x6a, 0x1d, 0xce, 0xc8, 0x6e, 0x9e, 0x58, 0x87, 0xf3, 0xf3, 0x9f, 0x17, - 0x1c, 0x74, 0xce, 0xd5, 0xdc, 0x03, 0x4f, 0x4b, 0x4e, 0xae, 0x8e, 0x39, 0xe9, 0x7c, 0xe9, 0x6a, - 0x89, 0xc9, 0xca, 0x65, 0xbe, 0xc5, 0x34, 0x1c, 0xae, 0x9f, 0xeb, 0x69, 0xa6, 0xc9, 0x5c, 0x7e, - 0x76, 0x6d, 0xb5, 0xdc, 0x64, 0xe6, 0xa5, 0xd6, 0x18, 0xea, 0x39, 0x9e, 0x15, 0xc3, 0x8c, 0x74, - 0xd3, 0x8a, 0x61, 0x66, 0x52, 0xe8, 0x5b, 0x68, 0x57, 0xb1, 0xfd, 0x16, 0xd5, 0xed, 0x2a, 0x5a, - 0xd2, 0xe0, 0x84, 0x59, 0x83, 0x7c, 0x8c, 0x46, 0x8d, 0x62, 0x4b, 0xc8, 0x8c, 0xc9, 0x49, 0xf7, - 0x1d, 0x19, 0x51, 0x19, 0x99, 0x95, 0x15, 0x3d, 0x99, 0x14, 0x7a, 0x6e, 0x36, 0x5d, 0x20, 0xe8, - 0xdf, 0x93, 0x76, 0x11, 0x6c, 0xf0, 0xac, 0x69, 0x4f, 0xca, 0x6f, 0xf3, 0x7b, 0xd2, 0x28, 0x62, - 0x90, 0xa5, 0xf2, 0x31, 0x27, 0xc9, 0xbe, 0x07, 0x63, 0x71, 0xee, 0xe5, 0xbd, 0x05, 0x8d, 0x30, - 0x91, 0x90, 0x39, 0x49, 0xf8, 0x81, 0xbc, 0x38, 0xc1, 0xfa, 0xcc, 0xc2, 0x62, 0xfb, 0xc9, 0xa7, - 0xd2, 0x08, 0x63, 0xb4, 0x34, 0x95, 0xc9, 0xb9, 0x60, 0xe5, 0x1e, 0xd3, 0x13, 0x46, 0xaa, 0x79, - 0x91, 0x91, 0xf2, 0x55, 0xcd, 0x8b, 0xac, 0x94, 0xad, 0xf1, 0xc5, 0xc2, 0x97, 0xd2, 0xe2, 0x10, - 0x33, 0xbd, 0x6c, 0x34, 0x2b, 0xc5, 0xf7, 0x4a, 0x5e, 0x71, 0x92, 0x75, 0x0d, 0xca, 0xc9, 0xec, - 0x96, 0xea, 0xb8, 0x96, 0x93, 0x86, 0x54, 0x9d, 0x01, 0x73, 0xd3, 0x62, 0x6e, 0x4b, 0xf3, 0xb9, - 0xc9, 0xf7, 0x5a, 0x76, 0xa3, 0x74, 0xd6, 0xc5, 0x6a, 0x59, 0x9c, 0xe8, 0x52, 0x3f, 0x48, 0xa7, - 0x12, 0x69, 0xea, 0x6a, 0x59, 0x46, 0x6e, 0x4c, 0x57, 0x86, 0x73, 0xca, 0xce, 0xb7, 0xfd, 0xb6, - 0x79, 0xc2, 0x2d, 0x88, 0x8a, 0xde, 0xf5, 0x92, 0x99, 0xfc, 0x1a, 0xcc, 0xe4, 0x04, 0x90, 0x26, - 0x6f, 0x24, 0x0c, 0xb1, 0xd9, 0x01, 0xa6, 0xd5, 0x04, 0xc9, 0xcc, 0x40, 0xbd, 0x81, 0xde, 0x09, - 0x46, 0xe0, 0x86, 0xd4, 0x8d, 0xdf, 0x23, 0x37, 0x3a, 0xe4, 0x89, 0x96, 0xb5, 0x35, 0x37, 0x33, - 0xe2, 0x03, 0xa9, 0xe1, 0x79, 0xc5, 0x80, 0x66, 0x5c, 0xfa, 0x65, 0x30, 0x9c, 0xcb, 0x66, 0xc8, - 0xd6, 0x0e, 0x36, 0x17, 0x32, 0xa2, 0x6a, 0xa8, 0xb9, 0x90, 0x1f, 0x71, 0x23, 0xb7, 0x99, 0xdb, - 0x52, 0xc1, 0xca, 0xe6, 0x98, 0x1f, 0x60, 0x23, 0x97, 0xe3, 0x03, 0xc6, 0x31, 0x15, 0x33, 0x83, - 0xe4, 0xa0, 0x17, 0xaf, 0x1e, 0xb6, 0xdc, 0xaf, 0x4d, 0xaa, 0x05, 0xad, 0x7d, 0x79, 0xd1, 0x39, - 0x72, 0xdb, 0xb7, 0x22, 0xbf, 0xa7, 0xec, 0xf6, 0x9d, 0x76, 0xc7, 0x56, 0xd7, 0x63, 0x89, 0xb0, - 0x2d, 0x46, 0x47, 0x35, 0xf8, 0x5c, 0x0e, 0x9c, 0x6c, 0xa2, 0xbb, 0x51, 0x12, 0xaa, 0x1d, 0x5c, - 0xb3, 0xe3, 0xc2, 0xe4, 0xf2, 0xe3, 0xf3, 0xd8, 0x88, 0xab, 0x71, 0x96, 0x79, 0x9c, 0x08, 0xc8, - 0x21, 0xe6, 0xb1, 0x01, 0x3d, 0xdb, 0x3c, 0x4e, 0x30, 0x34, 0xe7, 0x71, 0xb2, 0x99, 0x49, 0x43, - 0x40, 0xee, 0xa8, 0x26, 0x9b, 0xa9, 0xe6, 0x71, 0x36, 0xc7, 0xfc, 0xf8, 0x27, 0xb9, 0x1c, 0xd5, - 0x3c, 0x36, 0x39, 0xe6, 0xa0, 0x9f, 0x72, 0x1e, 0x27, 0x2b, 0x31, 0xe7, 0xf1, 0x99, 0xda, 0xa7, - 0xe6, 0x71, 0x76, 0xfb, 0xce, 0x3c, 0x8f, 0x13, 0x01, 0x83, 0x8c, 0x8e, 0x66, 0xcd, 0xe3, 0x24, - 0x3e, 0x9f, 0xc7, 0x49, 0x68, 0xc2, 0x00, 0x53, 0x30, 0x8f, 0x93, 0x94, 0x9f, 0x23, 0xbf, 0x44, - 0xb0, 0x93, 0xd3, 0xcc, 0xe4, 0xdc, 0x38, 0x29, 0xe4, 0x11, 0x5a, 0xff, 0x12, 0xf0, 0xd3, 0xcd, - 0xe6, 0xf9, 0x3c, 0xa6, 0x38, 0x9f, 0xf7, 0xa4, 0x10, 0x93, 0xcd, 0x35, 0x4d, 0x5b, 0xd9, 0xb1, - 0x5e, 0x0a, 0x1a, 0xbc, 0xc7, 0xe6, 0x4d, 0xb3, 0x80, 0x6f, 0x51, 0xa8, 0x9a, 0x02, 0xbe, 0xea, - 0x1c, 0x94, 0xe4, 0x9b, 0x4b, 0x52, 0x3c, 0xbf, 0xbf, 0x90, 0xf7, 0x1f, 0x49, 0xba, 0x85, 0xc4, - 0xc9, 0xea, 0xcc, 0x2d, 0x55, 0x27, 0xac, 0x64, 0x4b, 0xcf, 0x3a, 0xcf, 0x37, 0xa4, 0xf6, 0x90, - 0x8a, 0x71, 0x95, 0xe8, 0xb4, 0x3e, 0xd7, 0x73, 0x4b, 0xc8, 0x0e, 0x9a, 0x7a, 0xd3, 0x70, 0xcd, - 0x4c, 0x9c, 0x17, 0x4c, 0xab, 0x2b, 0xd7, 0x54, 0xb4, 0x1e, 0x9d, 0x6b, 0x5e, 0x28, 0x1f, 0xc5, - 0x35, 0x4d, 0xfd, 0x19, 0x9a, 0xce, 0xc4, 0x9b, 0x2e, 0xef, 0xb1, 0x9f, 0x7f, 0xce, 0x99, 0x34, - 0x5c, 0xa2, 0x18, 0x2e, 0x7a, 0xa2, 0x7d, 0x22, 0x2e, 0xf8, 0x24, 0x30, 0x57, 0xf8, 0x59, 0xf4, - 0xe4, 0x33, 0x28, 0x8b, 0xe5, 0x2d, 0x66, 0x90, 0x85, 0x98, 0x3b, 0x74, 0x8b, 0xd2, 0x62, 0x77, - 0x8a, 0x16, 0x9c, 0xc6, 0x52, 0x77, 0x1a, 0x49, 0xe4, 0x9b, 0xb5, 0xd8, 0x76, 0xb8, 0x13, 0x74, - 0xc2, 0x88, 0x36, 0xd3, 0xe6, 0x28, 0xb3, 0x31, 0xd2, 0x71, 0xc2, 0x44, 0xdf, 0x5b, 0x20, 0x6b, - 0xb8, 0xb6, 0x99, 0xe0, 0x22, 0x7b, 0x5d, 0x36, 0x1b, 0x5c, 0x7a, 0x56, 0xd5, 0xe3, 0x21, 0xb3, - 0x4d, 0x79, 0x75, 0xe7, 0x37, 0x4a, 0x89, 0xe8, 0x94, 0xbd, 0xcb, 0x13, 0x11, 0x3f, 0x50, 0x73, - 0xdb, 0x61, 0x37, 0xc9, 0x24, 0x9f, 0x33, 0x91, 0x1f, 0xc0, 0x88, 0x24, 0xee, 0x2e, 0x90, 0x24, - 0x35, 0x0a, 0x64, 0x19, 0xc6, 0x8d, 0xb7, 0x5a, 0xea, 0x74, 0x93, 0xf5, 0x82, 0xab, 0x60, 0x9c, - 0xc7, 0x8d, 0x37, 0x59, 0x8a, 0x4b, 0xd6, 0x4b, 0xad, 0x5c, 0x2e, 0xdf, 0x87, 0x51, 0x21, 0xd2, - 0x42, 0x69, 0xe4, 0x1b, 0xeb, 0xa6, 0x35, 0xbf, 0xe7, 0x4e, 0xd3, 0x8d, 0x96, 0x7c, 0xef, 0xb1, - 0x7b, 0xd0, 0x55, 0x30, 0x69, 0x92, 0xbd, 0x05, 0xf2, 0x43, 0x4c, 0x4b, 0x2c, 0x93, 0x45, 0xd3, - 0xe8, 0x99, 0x1f, 0x3c, 0x71, 0xbd, 0x83, 0x2e, 0x2c, 0xaf, 0x9a, 0x2c, 0x93, 0x74, 0xd2, 0xb5, - 0xe4, 0x87, 0x30, 0x57, 0xcb, 0x67, 0xde, 0x95, 0x49, 0xf1, 0xf6, 0x52, 0x83, 0x79, 0x74, 0xae, - 0x39, 0x6b, 0xdb, 0x0b, 0x99, 0x7e, 0xc9, 0xc3, 0x24, 0x4a, 0x43, 0x7f, 0xc3, 0x0f, 0x9a, 0xdd, - 0x39, 0x56, 0x4c, 0x77, 0xdd, 0x04, 0x99, 0x14, 0xc6, 0x97, 0x70, 0xb1, 0x96, 0xcb, 0xba, 0x1b, - 0x8b, 0x6e, 0x9a, 0xe4, 0x25, 0x14, 0xc5, 0x19, 0xdb, 0x5d, 0xc8, 0x73, 0x0d, 0xd7, 0x34, 0xb6, - 0x0f, 0x6d, 0x07, 0xf4, 0x31, 0x0d, 0xd0, 0x29, 0xbc, 0x9b, 0x3b, 0xb4, 0x89, 0x2e, 0x7b, 0xbe, - 0x06, 0xe7, 0x6b, 0x29, 0x56, 0x79, 0x24, 0xc5, 0xad, 0x7a, 0x00, 0x93, 0xd8, 0xd3, 0x53, 0xb6, - 0xab, 0x8b, 0x13, 0xd1, 0xe8, 0x7d, 0x1a, 0xed, 0xae, 0x75, 0x91, 0x92, 0x7c, 0xb5, 0x20, 0x11, - 0xf7, 0xee, 0x30, 0xca, 0x9a, 0x46, 0x99, 0xc6, 0xc8, 0xfd, 0x78, 0x7f, 0x20, 0x2f, 0x52, 0xba, - 0x56, 0x9b, 0xc7, 0xe1, 0x2e, 0xae, 0x85, 0xc2, 0x31, 0x5a, 0x33, 0x41, 0x72, 0x48, 0x6c, 0xaa, - 0xd3, 0x7c, 0xa4, 0x43, 0x52, 0xe5, 0xc7, 0x3f, 0x3e, 0x3d, 0x04, 0xec, 0x4a, 0xca, 0x61, 0xbe, - 0x90, 0x05, 0x37, 0xa1, 0xae, 0xfb, 0x8d, 0x27, 0xba, 0x09, 0x55, 0x4b, 0x5c, 0x3f, 0x67, 0xa6, - 0x95, 0x17, 0x2b, 0x3e, 0xe6, 0x96, 0xd7, 0xfd, 0xc2, 0xf4, 0xd4, 0xf5, 0xba, 0x09, 0xd5, 0x4c, - 0xb2, 0x7f, 0x57, 0xda, 0x16, 0xb1, 0x42, 0x93, 0x73, 0xae, 0x68, 0x94, 0x59, 0x11, 0x89, 0x4c, - 0xb3, 0xa2, 0xde, 0xd0, 0xfc, 0x8b, 0x00, 0x92, 0xce, 0xb2, 0xaf, 0x0e, 0x2b, 0xb9, 0x09, 0xf8, - 0x0b, 0xdc, 0xbb, 0x26, 0x85, 0x53, 0x90, 0x21, 0x78, 0x15, 0x6a, 0x38, 0x5d, 0x16, 0x8b, 0x52, - 0xf7, 0x55, 0xba, 0x5d, 0x22, 0x9b, 0x70, 0xe1, 0x3e, 0x8d, 0xc4, 0x1a, 0x67, 0xd3, 0x30, 0x0a, - 0xdc, 0x46, 0x54, 0x78, 0xab, 0x28, 0xcf, 0x26, 0x19, 0x34, 0x7b, 0xef, 0x32, 0x7e, 0xb5, 0x6c, - 0x7e, 0x85, 0x74, 0x05, 0x1e, 0xb4, 0xe2, 0xaa, 0xe2, 0x2c, 0x4d, 0xcc, 0x9f, 0xe2, 0x43, 0xdc, - 0x41, 0x27, 0x9f, 0xb4, 0x1c, 0xc7, 0x35, 0x11, 0xa7, 0xad, 0x9b, 0x30, 0xc8, 0x89, 0x72, 0x37, - 0xd4, 0x31, 0x9d, 0x86, 0xdc, 0x81, 0x11, 0xe5, 0x61, 0x43, 0x8c, 0xa2, 0xdc, 0x76, 0xdd, 0x81, - 0x11, 0x7e, 0xb4, 0x3a, 0x3d, 0xc9, 0xc7, 0x30, 0xa2, 0x5c, 0x72, 0xce, 0xbc, 0xd3, 0x7f, 0x06, - 0xe3, 0xba, 0x73, 0xce, 0xd9, 0x05, 0xf9, 0x7d, 0xbc, 0xfb, 0x95, 0x57, 0x2c, 0xf9, 0xf4, 0xd3, - 0x89, 0x5c, 0x5e, 0x42, 0xa4, 0x7c, 0x81, 0x94, 0xc0, 0xdc, 0xe6, 0x9f, 0x4f, 0x51, 0x93, 0x8f, - 0xe5, 0x7b, 0x29, 0x45, 0x9c, 0x46, 0x2a, 0x90, 0xd9, 0x04, 0x17, 0xf3, 0x8b, 0x10, 0xab, 0x05, - 0xb6, 0x6b, 0xb3, 0x4f, 0x73, 0x47, 0xdd, 0x5d, 0x74, 0x79, 0x5c, 0xb6, 0x50, 0x4b, 0x4b, 0x65, - 0x99, 0xcb, 0x67, 0x74, 0x25, 0x3f, 0x31, 0x1d, 0x0e, 0xc6, 0x03, 0x3c, 0x05, 0xa6, 0x4a, 0x73, - 0xbb, 0x57, 0x90, 0xe8, 0x2e, 0x3e, 0xf6, 0xa6, 0xd9, 0x15, 0x90, 0x15, 0x9d, 0xa2, 0xc5, 0x2b, - 0xd0, 0x57, 0xc2, 0x6e, 0x4d, 0xfa, 0x38, 0x9e, 0xbe, 0xb3, 0xf9, 0x2d, 0xbb, 0x94, 0x71, 0x2b, - 0xde, 0x75, 0x2c, 0xf2, 0xd8, 0xfd, 0x1a, 0x6a, 0x87, 0x99, 0xe1, 0xbe, 0xf2, 0x99, 0x5d, 0xd7, - 0x1c, 0x2b, 0x32, 0x29, 0xd5, 0xa6, 0xf7, 0x04, 0x1f, 0xa2, 0x65, 0xe7, 0xe1, 0x7b, 0xb3, 0x0b, - 0x17, 0x29, 0x89, 0xb7, 0xba, 0xe2, 0xa9, 0x3b, 0xd6, 0x4b, 0x7c, 0x87, 0xcd, 0xae, 0xaf, 0x4b, - 0x5e, 0xc1, 0x8c, 0x6b, 0x6f, 0xe5, 0x40, 0x9a, 0xcd, 0xd0, 0x74, 0x20, 0x2d, 0xec, 0x43, 0x9e, - 0xf8, 0x3f, 0x87, 0x4a, 0xec, 0x3d, 0x72, 0xb6, 0x41, 0xc8, 0xf7, 0x5b, 0x24, 0x29, 0x49, 0x85, - 0xa4, 0x28, 0xd1, 0xce, 0xdc, 0xb5, 0x3c, 0x09, 0x87, 0x9a, 0x5b, 0x92, 0xf0, 0x7b, 0x4b, 0x64, - 0xa4, 0xcc, 0xcb, 0x6d, 0x59, 0x60, 0x87, 0x15, 0x2f, 0xf3, 0x5e, 0x09, 0xa3, 0xf4, 0x68, 0x9f, - 0x9d, 0x91, 0x72, 0xee, 0x48, 0x30, 0xb2, 0x0a, 0x86, 0xf7, 0x2c, 0xbe, 0x6b, 0xc9, 0xa1, 0x38, - 0xeb, 0x80, 0x3a, 0xf1, 0x6b, 0xb4, 0x44, 0x74, 0x40, 0xfd, 0x05, 0x70, 0xba, 0x28, 0xf9, 0x94, - 0x2a, 0x0b, 0x43, 0x79, 0x54, 0xcd, 0xca, 0x2a, 0x18, 0x9c, 0x1d, 0x45, 0xfc, 0xc0, 0x8d, 0x9e, - 0x2f, 0xd9, 0xeb, 0xb1, 0x59, 0x41, 0x2f, 0x90, 0xbc, 0x41, 0x16, 0xda, 0xeb, 0xe4, 0x2b, 0x5c, - 0x4a, 0x04, 0xfb, 0x45, 0xdf, 0x8f, 0xc2, 0x28, 0x70, 0xda, 0xb5, 0x46, 0xe0, 0xb6, 0xa3, 0xdc, - 0x4e, 0xc7, 0x2e, 0xde, 0x59, 0x64, 0x9a, 0xc7, 0xa9, 0x88, 0x1e, 0x9f, 0x15, 0x5f, 0x47, 0xbd, - 0xba, 0xc9, 0x2a, 0x2c, 0x38, 0xb9, 0xd4, 0x64, 0xbc, 0xf8, 0x57, 0xc9, 0xb4, 0x0e, 0x33, 0x39, - 0x51, 0x89, 0xd4, 0xed, 0x6d, 0x71, 0xd4, 0xa2, 0xb9, 0xe2, 0x8a, 0xc9, 0x0f, 0x61, 0x3a, 0x33, - 0x6c, 0x91, 0xb2, 0x40, 0x17, 0x05, 0x35, 0xea, 0xc6, 0xfc, 0x09, 0xcc, 0xf2, 0xf7, 0x1e, 0xe8, - 0xd6, 0x6c, 0x44, 0xb0, 0x89, 0x5f, 0x01, 0xe5, 0x20, 0x24, 0xd7, 0xeb, 0x7c, 0x3c, 0xf5, 0xa4, - 0x7d, 0x0a, 0x43, 0x97, 0x24, 0x12, 0x9e, 0xab, 0x0f, 0x2f, 0xab, 0xb0, 0xe8, 0xa9, 0xd1, 0x36, - 0x4c, 0xef, 0xd1, 0xc0, 0x7d, 0xfc, 0x3c, 0xc9, 0x50, 0x4a, 0x26, 0xb3, 0xb4, 0x88, 0xe3, 0x17, - 0x30, 0xb3, 0xe4, 0x1f, 0xb5, 0xc5, 0xa3, 0x3e, 0x83, 0xa7, 0xba, 0x8a, 0xcf, 0x2e, 0xef, 0xee, - 0x08, 0x35, 0x97, 0x9f, 0x9a, 0x5e, 0xf9, 0xbf, 0x75, 0xcd, 0x5e, 0xaf, 0x9e, 0xa6, 0x99, 0xf4, - 0x3b, 0x38, 0x09, 0xb3, 0x72, 0xd5, 0xeb, 0x93, 0xb0, 0x20, 0x97, 0x7d, 0xce, 0x13, 0xb1, 0x99, - 0x9c, 0xf4, 0xf4, 0x05, 0x5c, 0x4f, 0xd1, 0xda, 0x4d, 0xb9, 0xb7, 0x98, 0x89, 0xbc, 0x13, 0x3e, - 0xd5, 0x99, 0x59, 0xbe, 0x33, 0xdb, 0xa9, 0xc5, 0x6e, 0x68, 0xb5, 0x0a, 0x54, 0x2c, 0xa2, 0x07, - 0x6f, 0x60, 0x98, 0x68, 0xc4, 0x1f, 0xd7, 0x69, 0x8b, 0x56, 0xeb, 0x14, 0x31, 0x2a, 0xb5, 0x1f, - 0xc1, 0x58, 0x4d, 0xaf, 0x3c, 0xa3, 0x92, 0xdc, 0x49, 0xa1, 0x1e, 0x09, 0x75, 0x6f, 0x7b, 0x81, - 0x23, 0xa9, 0xda, 0x78, 0x4e, 0xd5, 0x8b, 0x5c, 0xd7, 0x19, 0x23, 0x2b, 0x9b, 0xda, 0x05, 0xb2, - 0x92, 0x26, 0x2a, 0xd7, 0x99, 0xec, 0x44, 0x6e, 0x75, 0x9e, 0x47, 0x26, 0x99, 0x13, 0x93, 0x58, - 0xdd, 0x93, 0xcf, 0x2a, 0x97, 0xf9, 0xc2, 0xa4, 0x9a, 0xdc, 0xcf, 0x27, 0xce, 0x43, 0xa7, 0xfb, - 0xf9, 0xa4, 0xb2, 0xdb, 0xe9, 0x7e, 0x3e, 0x19, 0xa9, 0xeb, 0x56, 0x90, 0x57, 0x9c, 0x80, 0xa7, - 0xc0, 0x18, 0xa1, 0xd8, 0x64, 0xe4, 0xf9, 0x79, 0xa8, 0x87, 0x00, 0xe1, 0x69, 0x7b, 0x0a, 0x6c, - 0xad, 0xc9, 0xd0, 0x1f, 0x89, 0x3c, 0x3f, 0xf7, 0xa0, 0xcc, 0x33, 0x18, 0xc4, 0x51, 0x13, 0x63, - 0xbf, 0xc1, 0x74, 0x62, 0x85, 0x82, 0x41, 0x2d, 0x27, 0xe3, 0xcd, 0x29, 0x93, 0x59, 0x4e, 0x20, - 0xba, 0x82, 0xa9, 0x0a, 0x71, 0x54, 0x39, 0x65, 0x98, 0x4a, 0x05, 0x9a, 0x9b, 0xbb, 0x98, 0x51, - 0xa2, 0x54, 0xca, 0x31, 0x3d, 0x06, 0x9d, 0xea, 0x52, 0x46, 0x60, 0xba, 0xb9, 0x4b, 0x99, 0x65, - 0x82, 0x51, 0xc4, 0xf3, 0x2f, 0x67, 0x67, 0x8d, 0x8e, 0xdf, 0x79, 0x15, 0xe0, 0xc8, 0x6a, 0x6e, - 0x9c, 0x06, 0x55, 0xd4, 0x4a, 0x55, 0xfa, 0xa1, 0x8c, 0x54, 0xd5, 0x6f, 0x65, 0xbc, 0xc7, 0x30, - 0x30, 0x62, 0x6f, 0xb0, 0xe2, 0xbc, 0xd9, 0xe4, 0x91, 0x4c, 0x07, 0x93, 0x53, 0x53, 0x37, 0x06, - 0xb9, 0x23, 0xf8, 0x48, 0x26, 0x80, 0x79, 0xd5, 0x8c, 0xf7, 0x61, 0x3e, 0xf1, 0xdc, 0xc3, 0x64, - 0x7c, 0x23, 0xfb, 0x4d, 0x48, 0xa6, 0x78, 0xf2, 0x75, 0xf6, 0xab, 0xe9, 0xb7, 0x21, 0x89, 0x71, - 0x3f, 0xeb, 0x9a, 0xb7, 0x01, 0x13, 0xb8, 0xcc, 0xc8, 0xa4, 0xeb, 0x71, 0x04, 0x1a, 0x13, 0x9c, - 0x0c, 0x85, 0x94, 0x2c, 0x55, 0x2e, 0xb3, 0x63, 0xe2, 0xcd, 0x30, 0x4f, 0xe1, 0x3e, 0x67, 0x3e, - 0x24, 0x46, 0x60, 0xd6, 0x2e, 0x26, 0x32, 0xc3, 0x93, 0xef, 0xc3, 0xb9, 0xf8, 0x29, 0x31, 0x67, - 0x91, 0x81, 0x56, 0x60, 0x28, 0x3b, 0x17, 0xbf, 0x27, 0x3e, 0x3b, 0xf9, 0xaa, 0xdc, 0x8a, 0x62, - 0xf2, 0xcb, 0xa9, 0x67, 0x32, 0x46, 0x1f, 0x4e, 0xb3, 0x23, 0x69, 0xb2, 0x3d, 0xeb, 0xe8, 0x34, - 0xf0, 0x73, 0xcb, 0x0e, 0xae, 0xa8, 0x7f, 0x6e, 0x85, 0x01, 0x20, 0x95, 0xfa, 0x9b, 0xc3, 0x67, - 0x03, 0x5e, 0xc3, 0x80, 0x2c, 0xdb, 0x3c, 0x04, 0x5f, 0x36, 0x56, 0x7e, 0xdb, 0x93, 0x61, 0x5c, - 0x5a, 0x70, 0xad, 0x6b, 0x74, 0x49, 0x72, 0xcb, 0x70, 0x71, 0xe9, 0x1e, 0x87, 0xb2, 0xe8, 0x69, - 0x5a, 0x56, 0x90, 0x46, 0xb5, 0xcf, 0x16, 0xc4, 0x8b, 0x54, 0xfb, 0x6c, 0x61, 0x94, 0xc7, 0x2f, - 0x30, 0xc7, 0x92, 0xd8, 0xa3, 0x30, 0xc8, 0x12, 0xf5, 0x78, 0xd8, 0xe9, 0xc2, 0x6b, 0x9f, 0x6b, - 0xe6, 0xa5, 0x68, 0x8a, 0x10, 0xcf, 0x34, 0x57, 0xc4, 0x49, 0x2c, 0x8f, 0x79, 0x77, 0x26, 0x05, - 0xae, 0xd5, 0x57, 0xf8, 0x04, 0x3c, 0x73, 0xcb, 0x73, 0xe0, 0x8b, 0xcb, 0x3f, 0xff, 0x0f, 0x57, - 0x4a, 0x3f, 0xff, 0xc5, 0x95, 0xd2, 0xbf, 0xf9, 0xc5, 0x95, 0xd2, 0xbf, 0xff, 0xc5, 0x95, 0xd2, - 0x57, 0x0b, 0xa7, 0x0b, 0x7e, 0xdc, 0x68, 0xb9, 0xd4, 0x8b, 0x6e, 0x71, 0x76, 0x83, 0xf8, 0xdf, - 0xdd, 0xff, 0x11, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x26, 0x7b, 0x15, 0xd6, 0xe4, 0x00, 0x00, + // 14749 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x5b, 0x6c, 0x5c, 0x4b, + 0x76, 0x18, 0xca, 0xe6, 0x9b, 0x8b, 0xaf, 0x56, 0x91, 0x14, 0x5b, 0x14, 0xa5, 0x96, 0xb6, 0xce, + 0x43, 0x47, 0x73, 0x46, 0x0f, 0xea, 0x9c, 0x33, 0xe7, 0x35, 0xe7, 0x4c, 0xf3, 0x21, 0x91, 0x12, + 0x5f, 0x67, 0x37, 0x49, 0x9d, 0x97, 0xa7, 0x67, 0xb3, 0xbb, 0x44, 0x6e, 0xab, 0xb9, 0x77, 0xcf, + 0xde, 0xbb, 0xa5, 0xa3, 0xf1, 0xb5, 0x2f, 0x3c, 0xbe, 0x17, 0xd7, 0x3f, 0x37, 0xb1, 0x81, 0x38, + 0x70, 0xe0, 0x0f, 0x23, 0x40, 0x0c, 0x04, 0xf9, 0x08, 0xfc, 0xe3, 0xf8, 0x27, 0xf9, 0xc8, 0x57, + 0x26, 0x06, 0x8c, 0x24, 0xb0, 0xfd, 0x93, 0x0f, 0x3a, 0x19, 0x20, 0x3f, 0x44, 0xf2, 0x61, 0x04, + 0x09, 0x90, 0x01, 0x0c, 0x04, 0xb5, 0xea, 0xb1, 0xab, 0xf6, 0xa3, 0x9b, 0x94, 0x74, 0xc6, 0xf9, + 0x91, 0xd8, 0xab, 0xd6, 0x5a, 0x55, 0xb5, 0xaa, 0x76, 0xd5, 0xaa, 0x55, 0xab, 0xd6, 0x82, 0x9b, + 0x11, 0x6d, 0xd2, 0x96, 0x1f, 0x44, 0xb7, 0x9a, 0xf4, 0xc0, 0xa9, 0x3f, 0xbf, 0x55, 0x6f, 0xba, + 0xd4, 0x8b, 0x6e, 0xb5, 0x02, 0x3f, 0xf2, 0x6f, 0x39, 0xed, 0xe8, 0x30, 0xa4, 0xc1, 0x53, 0xb7, + 0x4e, 0x6f, 0x22, 0x84, 0x0c, 0xe0, 0x7f, 0x73, 0xd3, 0x07, 0xfe, 0x81, 0xcf, 0x71, 0xd8, 0x5f, + 0xbc, 0x70, 0xee, 0xe2, 0x81, 0xef, 0x1f, 0x34, 0x29, 0x27, 0xde, 0x6f, 0x3f, 0xbe, 0x45, 0x8f, + 0x5a, 0xd1, 0x73, 0x51, 0x58, 0x4e, 0x16, 0x46, 0xee, 0x11, 0x0d, 0x23, 0xe7, 0xa8, 0x25, 0x10, + 0xde, 0x52, 0x4d, 0x71, 0xa2, 0x88, 0x95, 0x44, 0xae, 0xef, 0xdd, 0x7a, 0x7a, 0x47, 0xff, 0x29, + 0x50, 0xaf, 0x77, 0x6c, 0x75, 0x9d, 0x06, 0x51, 0x78, 0x2a, 0x4c, 0xfa, 0x94, 0x7a, 0x51, 0xaa, + 0x7a, 0x81, 0x19, 0x3d, 0x6f, 0xd1, 0x90, 0xa3, 0xc8, 0xff, 0x04, 0xea, 0xd5, 0x6c, 0x54, 0xfc, + 0x57, 0xa0, 0x7c, 0x37, 0x1b, 0xe5, 0x19, 0xdd, 0x67, 0x32, 0xf5, 0xd4, 0x1f, 0x5d, 0xd0, 0x03, + 0xa7, 0xd5, 0xa2, 0x41, 0xfc, 0x87, 0x40, 0xbf, 0xa0, 0xd0, 0x8f, 0x1e, 0x3b, 0x4c, 0x44, 0x47, + 0x8f, 0x9d, 0x54, 0x37, 0xda, 0xa1, 0x73, 0x40, 0x45, 0xf3, 0x9f, 0xde, 0xd1, 0x7f, 0x72, 0x54, + 0xeb, 0x0f, 0x0b, 0x30, 0xf0, 0xc8, 0x89, 0xea, 0x87, 0xe4, 0x53, 0x18, 0x78, 0xe8, 0x7a, 0x8d, + 0xb0, 0x54, 0xb8, 0xd2, 0x77, 0x7d, 0x74, 0xa1, 0x78, 0x93, 0x77, 0x05, 0x0b, 0x59, 0xc1, 0xe2, + 0xec, 0xcf, 0x8e, 0xcb, 0x3d, 0x27, 0xc7, 0xe5, 0xc9, 0x27, 0x0c, 0xed, 0x6d, 0xff, 0xc8, 0x8d, + 0x70, 0x6c, 0x6d, 0x4e, 0x47, 0x76, 0x61, 0xaa, 0xd2, 0x6c, 0xfa, 0xcf, 0xb6, 0x9d, 0x20, 0x72, + 0x9d, 0x66, 0xb5, 0x5d, 0xaf, 0xd3, 0x30, 0x2c, 0xf5, 0x5e, 0x29, 0x5c, 0x1f, 0x5e, 0xbc, 0x76, + 0x72, 0x5c, 0x2e, 0x3b, 0xac, 0xb8, 0xd6, 0xe2, 0xe5, 0xb5, 0x90, 0x23, 0x68, 0x8c, 0xb2, 0xe8, + 0xad, 0x3f, 0x1b, 0x84, 0xe2, 0xaa, 0x1f, 0x46, 0x4b, 0x6c, 0x44, 0x6d, 0xfa, 0xe3, 0x36, 0x0d, + 0x23, 0x72, 0x0d, 0x06, 0x19, 0x6c, 0x6d, 0xb9, 0x54, 0xb8, 0x52, 0xb8, 0x3e, 0xb2, 0x38, 0x7a, + 0x72, 0x5c, 0x1e, 0x3a, 0xf4, 0xc3, 0xa8, 0xe6, 0x36, 0x6c, 0x51, 0x44, 0xde, 0x82, 0xe1, 0x4d, + 0xbf, 0x41, 0x37, 0x9d, 0x23, 0x8a, 0xad, 0x18, 0x59, 0x1c, 0x3f, 0x39, 0x2e, 0x8f, 0x78, 0x7e, + 0x83, 0xd6, 0x3c, 0xe7, 0x88, 0xda, 0xaa, 0x98, 0xec, 0x41, 0xbf, 0xed, 0x37, 0x69, 0xa9, 0x0f, + 0xd1, 0x16, 0x4f, 0x8e, 0xcb, 0xfd, 0x81, 0xdf, 0xa4, 0xbf, 0x38, 0x2e, 0xbf, 0x77, 0xe0, 0x46, + 0x87, 0xed, 0xfd, 0x9b, 0x75, 0xff, 0xe8, 0xd6, 0x41, 0xe0, 0x3c, 0x75, 0xf9, 0x24, 0x74, 0x9a, + 0xb7, 0xe2, 0xa9, 0xda, 0x72, 0xc5, 0xb8, 0x57, 0x9f, 0x87, 0x11, 0x3d, 0x62, 0x9c, 0x6c, 0xe4, + 0x47, 0x1e, 0xc1, 0x74, 0xa5, 0xd1, 0x70, 0x39, 0xc5, 0x76, 0xe0, 0x7a, 0x75, 0xb7, 0xe5, 0x34, + 0xc3, 0x52, 0xff, 0x95, 0xbe, 0xeb, 0x23, 0x42, 0x28, 0xaa, 0xbc, 0xd6, 0x52, 0x08, 0x9a, 0x50, + 0x32, 0x19, 0x90, 0xbb, 0x30, 0xbc, 0xbc, 0x59, 0x65, 0x6d, 0x0f, 0x4b, 0x03, 0xc8, 0x6c, 0xf6, + 0xe4, 0xb8, 0x3c, 0xd5, 0xf0, 0x42, 0xec, 0x9a, 0xce, 0x40, 0x21, 0x92, 0xf7, 0x60, 0x6c, 0xbb, + 0xbd, 0xdf, 0x74, 0xeb, 0x3b, 0xeb, 0xd5, 0x87, 0xf4, 0x79, 0x69, 0xf0, 0x4a, 0xe1, 0xfa, 0xd8, + 0x22, 0x39, 0x39, 0x2e, 0x4f, 0xb4, 0x10, 0x5e, 0x8b, 0x9a, 0x61, 0xed, 0x09, 0x7d, 0x6e, 0x1b, + 0x78, 0x31, 0x5d, 0xb5, 0xba, 0xca, 0xe8, 0x86, 0x52, 0x74, 0x61, 0x78, 0xa8, 0xd3, 0x71, 0x3c, + 0x72, 0x0b, 0xc0, 0xa6, 0x47, 0x7e, 0x44, 0x2b, 0x8d, 0x46, 0x50, 0x1a, 0x46, 0xd9, 0x4e, 0x9e, + 0x1c, 0x97, 0x47, 0x03, 0x84, 0xd6, 0x9c, 0x46, 0x23, 0xb0, 0x35, 0x14, 0xb2, 0x04, 0xc3, 0xb6, + 0xcf, 0x05, 0x5c, 0x1a, 0xb9, 0x52, 0xb8, 0x3e, 0xba, 0x30, 0x29, 0xa6, 0xa1, 0x04, 0x2f, 0x9e, + 0x3f, 0x39, 0x2e, 0x93, 0x40, 0xfc, 0xd2, 0x7b, 0x29, 0x31, 0x48, 0x19, 0x86, 0x36, 0xfd, 0x25, + 0xa7, 0x7e, 0x48, 0x4b, 0x80, 0x73, 0x6f, 0xe0, 0xe4, 0xb8, 0x5c, 0xf8, 0xae, 0x2d, 0xa1, 0xe4, + 0x29, 0x8c, 0xc6, 0x03, 0x15, 0x96, 0x46, 0x51, 0x7c, 0x3b, 0x27, 0xc7, 0xe5, 0xf3, 0x21, 0x82, + 0x6b, 0x6c, 0xe8, 0x35, 0x09, 0xbe, 0xc4, 0x2c, 0xd0, 0x2b, 0x22, 0x5f, 0xc3, 0x4c, 0xfc, 0xb3, + 0x12, 0x86, 0x34, 0x60, 0x3c, 0xd6, 0x96, 0x4b, 0xe3, 0x28, 0x99, 0x37, 0x4e, 0x8e, 0xcb, 0x96, + 0xd6, 0x82, 0x9a, 0x23, 0x51, 0x6a, 0x6e, 0x43, 0xeb, 0x69, 0x36, 0x93, 0x07, 0xfd, 0xc3, 0x63, + 0xc5, 0x71, 0xfb, 0xd2, 0xae, 0x17, 0x46, 0xce, 0x7e, 0x93, 0x66, 0x22, 0x59, 0x7f, 0x5b, 0x00, + 0xb2, 0xd5, 0xa2, 0x5e, 0xb5, 0xba, 0xca, 0xbe, 0x27, 0xf9, 0x39, 0xbd, 0x0d, 0x23, 0x7c, 0xe0, + 0xd8, 0xe8, 0xf6, 0xe2, 0xe8, 0x4e, 0x9c, 0x1c, 0x97, 0x41, 0x8c, 0x2e, 0x1b, 0xd9, 0x18, 0x81, + 0xbc, 0x0e, 0x7d, 0x3b, 0x3b, 0xeb, 0xf8, 0xad, 0xf4, 0x2d, 0x4e, 0x9d, 0x1c, 0x97, 0xfb, 0xa2, + 0xa8, 0xf9, 0x8b, 0xe3, 0xf2, 0xf0, 0x72, 0x3b, 0x40, 0xb1, 0xd8, 0xac, 0x9c, 0xbc, 0x0e, 0x43, + 0x4b, 0xcd, 0x76, 0x18, 0xd1, 0xa0, 0xd4, 0x1f, 0x7f, 0xa4, 0x75, 0x0e, 0xb2, 0x65, 0x19, 0xf9, + 0x0e, 0xf4, 0xef, 0x86, 0x34, 0x28, 0x0d, 0xe0, 0x78, 0x8f, 0x8b, 0xf1, 0x66, 0xa0, 0xbd, 0x85, + 0xc5, 0x61, 0xf6, 0x25, 0xb6, 0x43, 0x1a, 0xd8, 0x88, 0x44, 0x6e, 0xc2, 0x00, 0x1f, 0xb4, 0x41, + 0x5c, 0xa4, 0xc6, 0xd5, 0xec, 0x68, 0xd2, 0xbd, 0xf7, 0x16, 0x47, 0x4e, 0x8e, 0xcb, 0x03, 0x38, + 0x78, 0x36, 0x47, 0x7b, 0xd0, 0x3f, 0x5c, 0x28, 0xf6, 0xda, 0xc3, 0x8c, 0x96, 0x7d, 0x16, 0xd6, + 0x77, 0x60, 0x54, 0xeb, 0x3e, 0x99, 0x87, 0x7e, 0xf6, 0x3f, 0x2e, 0x22, 0x63, 0xbc, 0x32, 0xb6, + 0x71, 0xd8, 0x08, 0xb5, 0xfe, 0xc5, 0x24, 0x14, 0x19, 0xa5, 0xb1, 0xf2, 0x18, 0xa2, 0x2a, 0x74, + 0x13, 0xd5, 0x75, 0x50, 0x75, 0x8b, 0x25, 0x68, 0xec, 0xe4, 0xb8, 0x3c, 0xdc, 0x16, 0xb0, 0xb8, + 0x65, 0xa4, 0x0a, 0x43, 0x2b, 0xdf, 0xb4, 0xdc, 0x80, 0x86, 0x28, 0xd8, 0xd1, 0x85, 0xb9, 0x9b, + 0x7c, 0xb3, 0xbc, 0x29, 0x37, 0xcb, 0x9b, 0x3b, 0x72, 0xb3, 0x5c, 0xbc, 0x24, 0x96, 0xe2, 0x73, + 0x94, 0x93, 0xc4, 0xb3, 0xe3, 0x77, 0xfe, 0xba, 0x5c, 0xb0, 0x25, 0x27, 0xf2, 0x36, 0x0c, 0xde, + 0xf3, 0x83, 0x23, 0x27, 0x12, 0x23, 0x30, 0x7d, 0x72, 0x5c, 0x2e, 0x3e, 0x46, 0x88, 0x36, 0xa1, + 0x04, 0x0e, 0xb9, 0x07, 0x13, 0xb6, 0xdf, 0x8e, 0xe8, 0x8e, 0x2f, 0xc7, 0x6d, 0x00, 0xa9, 0x2e, + 0x9f, 0x1c, 0x97, 0xe7, 0x02, 0x56, 0x52, 0x8b, 0xfc, 0x9a, 0x18, 0x40, 0x8d, 0x3e, 0x41, 0x45, + 0x56, 0x60, 0xa2, 0x82, 0x6b, 0xb7, 0x90, 0x19, 0x1f, 0xad, 0x91, 0xc5, 0x4b, 0x27, 0xc7, 0xe5, + 0x0b, 0x0e, 0x96, 0xd4, 0x02, 0x51, 0xa4, 0xb3, 0x31, 0x89, 0xc8, 0x26, 0x9c, 0x7b, 0xd8, 0xde, + 0xa7, 0x81, 0x47, 0x23, 0x1a, 0xca, 0x16, 0x0d, 0x61, 0x8b, 0xae, 0x9c, 0x1c, 0x97, 0xe7, 0x9f, + 0xa8, 0xc2, 0x8c, 0x36, 0xa5, 0x49, 0x09, 0x85, 0x49, 0xd1, 0xd0, 0x65, 0x27, 0x72, 0xf6, 0x9d, + 0x90, 0xe2, 0x92, 0x34, 0xba, 0x70, 0x9e, 0x8b, 0xf8, 0x66, 0xa2, 0x74, 0xf1, 0x9a, 0x90, 0xf2, + 0x45, 0xd5, 0xf7, 0x86, 0x28, 0xd2, 0x2a, 0x4a, 0xf2, 0x64, 0x2b, 0xb3, 0xda, 0x75, 0x46, 0xb0, + 0xb5, 0xb8, 0x32, 0xab, 0x5d, 0x47, 0x5f, 0xb3, 0xd4, 0xfe, 0xb3, 0x0e, 0x03, 0xbb, 0x6c, 0x6f, + 0xc6, 0x15, 0x6b, 0x62, 0xe1, 0xaa, 0x68, 0x51, 0x72, 0xf6, 0xdd, 0x64, 0x3f, 0x10, 0x11, 0xbf, + 0xbb, 0x49, 0xdc, 0xcf, 0xf5, 0x9d, 0x18, 0xcb, 0xc8, 0x67, 0x00, 0xa2, 0x55, 0x95, 0x56, 0xab, + 0x34, 0x8a, 0x9d, 0x3c, 0x67, 0x76, 0xb2, 0xd2, 0x6a, 0x2d, 0x5e, 0x16, 0xfd, 0x3b, 0xaf, 0xfa, + 0xe7, 0xb4, 0x5a, 0x1a, 0x37, 0x8d, 0x09, 0xf9, 0x14, 0xc6, 0x70, 0x41, 0x93, 0x23, 0x3a, 0x86, + 0x23, 0x7a, 0xf1, 0xe4, 0xb8, 0x3c, 0x8b, 0x6b, 0x55, 0xc6, 0x78, 0x1a, 0x04, 0xe4, 0x37, 0x60, + 0x46, 0xb0, 0x7b, 0xe4, 0x7a, 0x0d, 0xff, 0x59, 0xb8, 0x4c, 0xc3, 0x27, 0x91, 0xdf, 0xc2, 0xc5, + 0x6f, 0x74, 0x61, 0xde, 0x6c, 0x9e, 0x89, 0xb3, 0x78, 0x43, 0xb4, 0xd4, 0x52, 0x2d, 0x7d, 0xc6, + 0x11, 0x6a, 0x0d, 0x8e, 0xa1, 0x2f, 0x8f, 0x99, 0x2c, 0xc8, 0x1a, 0x4c, 0xee, 0x86, 0xd4, 0xe8, + 0xc3, 0x04, 0xee, 0x0e, 0x65, 0x36, 0xc2, 0xed, 0x90, 0xd6, 0xf2, 0xfa, 0x91, 0xa4, 0x23, 0x36, + 0x90, 0xe5, 0xc0, 0x6f, 0x25, 0xe6, 0xf8, 0x24, 0x4a, 0xc4, 0x3a, 0x39, 0x2e, 0x5f, 0x6e, 0x04, + 0x7e, 0xab, 0x96, 0x3f, 0xd1, 0x33, 0xa8, 0xc9, 0x0f, 0xe1, 0xfc, 0x92, 0xef, 0x79, 0xb4, 0xce, + 0xd6, 0xcf, 0x65, 0xd7, 0x39, 0xf0, 0xfc, 0x30, 0x72, 0xeb, 0x6b, 0xcb, 0xa5, 0x62, 0xbc, 0x39, + 0xd4, 0x15, 0x46, 0xad, 0xa1, 0x50, 0xcc, 0xcd, 0x21, 0x87, 0x0b, 0xf9, 0x0a, 0xc6, 0x45, 0x5d, + 0x34, 0xc0, 0xa9, 0x79, 0xae, 0xf3, 0x44, 0x53, 0xc8, 0x7c, 0x9b, 0x0f, 0xe4, 0x4f, 0xae, 0x38, + 0x99, 0xbc, 0xc8, 0xd7, 0x30, 0xba, 0x71, 0xaf, 0x62, 0xd3, 0xb0, 0xe5, 0x7b, 0x21, 0x2d, 0x11, + 0x1c, 0xd1, 0xcb, 0x82, 0xf5, 0xc6, 0xbd, 0x4a, 0xa5, 0x1d, 0x1d, 0x52, 0x2f, 0x72, 0xeb, 0x4e, + 0x44, 0x25, 0xd6, 0xe2, 0x1c, 0x9b, 0x79, 0x47, 0x8f, 0x9d, 0x5a, 0x20, 0x20, 0x5a, 0x2f, 0x74, + 0x76, 0x64, 0x0e, 0x86, 0xab, 0xd5, 0xd5, 0x75, 0xff, 0xc0, 0xf5, 0x4a, 0x53, 0x4c, 0x18, 0xb6, + 0xfa, 0x4d, 0xf6, 0x61, 0x46, 0x3b, 0x19, 0xd4, 0xd8, 0xff, 0xf4, 0x88, 0x7a, 0x51, 0x69, 0x1a, + 0xdb, 0xf0, 0x5d, 0x75, 0xb4, 0xb9, 0xa9, 0x1f, 0x20, 0x9e, 0xde, 0xb9, 0x59, 0x89, 0x7f, 0x56, + 0x25, 0x91, 0x3d, 0xed, 0x64, 0x40, 0xc9, 0x0e, 0x0c, 0x6d, 0xb7, 0x83, 0x96, 0x1f, 0xd2, 0xd2, + 0x0c, 0x0a, 0xed, 0x5a, 0xa7, 0xaf, 0x53, 0xa0, 0x2e, 0xce, 0xb0, 0xe5, 0xb9, 0xc5, 0x7f, 0x68, + 0x3d, 0x93, 0xac, 0xac, 0xcf, 0x61, 0x44, 0x7d, 0xcc, 0x64, 0x08, 0xfa, 0x2a, 0xcd, 0x66, 0xb1, + 0x87, 0xfd, 0x51, 0xad, 0xae, 0x16, 0x0b, 0x64, 0x02, 0x20, 0x5e, 0xc1, 0x8a, 0xbd, 0x64, 0x0c, + 0x86, 0xe5, 0x0a, 0x53, 0xec, 0x43, 0xfc, 0x56, 0xab, 0xd8, 0x4f, 0x08, 0x4c, 0x98, 0xf3, 0xbc, + 0x38, 0x60, 0xfd, 0x6e, 0x01, 0x46, 0xd4, 0xf8, 0x90, 0x49, 0x18, 0xdd, 0xdd, 0xac, 0x6e, 0xaf, + 0x2c, 0xad, 0xdd, 0x5b, 0x5b, 0x59, 0x2e, 0xf6, 0x90, 0x4b, 0x70, 0x61, 0xa7, 0xba, 0x5a, 0x5b, + 0x5e, 0xac, 0xad, 0x6f, 0x2d, 0x55, 0xd6, 0x6b, 0xdb, 0xf6, 0xd6, 0xe7, 0x5f, 0xd4, 0x76, 0x76, + 0x37, 0x37, 0x57, 0xd6, 0x8b, 0x05, 0x52, 0x82, 0x69, 0x56, 0xfc, 0x70, 0x77, 0x71, 0x45, 0x47, + 0x28, 0xf6, 0x92, 0xab, 0x70, 0x29, 0xab, 0xa4, 0xb6, 0xba, 0x52, 0x59, 0x5e, 0x5f, 0xa9, 0x56, + 0x8b, 0x7d, 0x64, 0x16, 0xa6, 0x18, 0x4a, 0x65, 0x7b, 0xdb, 0xa0, 0xed, 0xb7, 0x9a, 0x30, 0xaa, + 0x09, 0x87, 0xcc, 0x43, 0x69, 0x69, 0xc5, 0xde, 0xa9, 0x6d, 0xef, 0xda, 0xdb, 0x5b, 0xd5, 0x95, + 0x9a, 0xd9, 0xc2, 0x64, 0xe9, 0xfa, 0xd6, 0xfd, 0xb5, 0xcd, 0x1a, 0x03, 0x55, 0x8b, 0x05, 0xd6, + 0x0c, 0xa3, 0xb4, 0xba, 0xb6, 0x79, 0x7f, 0x7d, 0xa5, 0xb6, 0x5b, 0x5d, 0x11, 0x28, 0xbd, 0xd6, + 0x4f, 0x7b, 0x53, 0x4b, 0x3d, 0x59, 0x80, 0xd1, 0x2a, 0x3f, 0xc5, 0xe2, 0xf4, 0xe7, 0xc7, 0x86, + 0xe2, 0xc9, 0x71, 0x79, 0x4c, 0x1c, 0x6e, 0xf9, 0xcc, 0xd6, 0x91, 0xd8, 0xee, 0xbd, 0xcd, 0x46, + 0xba, 0xee, 0x37, 0xf5, 0xdd, 0xbb, 0x25, 0x60, 0xb6, 0x2a, 0x25, 0x0b, 0xda, 0x3e, 0xcf, 0xcf, + 0x10, 0xa8, 0xa7, 0xca, 0x7d, 0x5e, 0x5f, 0xf3, 0xd5, 0x8e, 0xbf, 0x10, 0x0f, 0xa9, 0xd8, 0x9e, + 0x91, 0x26, 0x63, 0x8f, 0x51, 0x78, 0xe4, 0x2d, 0xa9, 0xff, 0x70, 0x9d, 0x1f, 0x37, 0x81, 0x84, + 0xb6, 0x2a, 0x54, 0x1f, 0xab, 0x9d, 0xb3, 0xe0, 0x92, 0x8f, 0x92, 0x73, 0x46, 0x08, 0x03, 0x99, + 0x25, 0xd6, 0x55, 0x3b, 0x81, 0x4a, 0xca, 0x30, 0xc0, 0xbf, 0x44, 0x2e, 0x0f, 0xd4, 0xb8, 0x9a, + 0x0c, 0x60, 0x73, 0xb8, 0xf5, 0x27, 0x7d, 0xfa, 0xe6, 0xc3, 0x34, 0x2c, 0x4d, 0xde, 0xa8, 0x61, + 0xa1, 0x9c, 0x11, 0x4a, 0x6e, 0xc2, 0x48, 0x95, 0x86, 0x21, 0xd7, 0x82, 0x7b, 0xd5, 0x90, 0x40, + 0xc8, 0x81, 0x35, 0xb7, 0x51, 0x2a, 0xd8, 0x31, 0x0a, 0x3b, 0x50, 0x70, 0xdd, 0x0a, 0x0f, 0x14, + 0x7d, 0xf1, 0x81, 0x42, 0x68, 0x5f, 0xfc, 0x40, 0x11, 0xa3, 0xb0, 0x51, 0x17, 0xdb, 0x3f, 0xb6, + 0xa2, 0x3f, 0x1e, 0x75, 0xa1, 0x32, 0x88, 0x51, 0xd7, 0x90, 0xc8, 0x87, 0x00, 0x95, 0x47, 0x55, + 0xd4, 0x9c, 0xed, 0x4d, 0xa1, 0x02, 0xe1, 0x62, 0xe5, 0x3c, 0x0b, 0x85, 0x62, 0x1e, 0xe8, 0x27, + 0x0f, 0x0d, 0x9b, 0x2c, 0xc2, 0x78, 0xe5, 0x27, 0xed, 0x80, 0xae, 0x35, 0xd8, 0x7a, 0x17, 0xf1, + 0x23, 0xd6, 0xc8, 0xe2, 0xfc, 0xc9, 0x71, 0xb9, 0xe4, 0xb0, 0x82, 0x9a, 0x2b, 0x4a, 0x34, 0x06, + 0x26, 0x09, 0xd9, 0x82, 0x73, 0xf7, 0x97, 0xb6, 0xc5, 0x3c, 0xac, 0xd4, 0xeb, 0x7e, 0xdb, 0x8b, + 0x84, 0xde, 0x73, 0xf5, 0xe4, 0xb8, 0x7c, 0xe9, 0xa0, 0xde, 0xaa, 0xc9, 0x39, 0xeb, 0xf0, 0x62, + 0x5d, 0xf1, 0x49, 0xd1, 0x92, 0x6b, 0xd0, 0xb7, 0x6b, 0xaf, 0x89, 0xf3, 0xd7, 0xb9, 0x93, 0xe3, + 0xf2, 0x78, 0x3b, 0x70, 0x35, 0x12, 0x56, 0x6a, 0x35, 0x61, 0xe2, 0x3e, 0x8d, 0xd8, 0xe4, 0x94, + 0x9a, 0x6e, 0xe7, 0xa1, 0xfb, 0x18, 0x46, 0x1f, 0xb9, 0xd1, 0x61, 0x95, 0xd6, 0x03, 0x1a, 0xc9, + 0x53, 0x3e, 0x8a, 0xe9, 0x99, 0x1b, 0x1d, 0xd6, 0x42, 0x0e, 0xd7, 0xd7, 0x74, 0x0d, 0xdd, 0x5a, + 0x81, 0x49, 0x51, 0x9b, 0x52, 0xac, 0x17, 0x4c, 0x86, 0x05, 0x64, 0x88, 0x43, 0xa5, 0x33, 0x34, + 0xd9, 0xfc, 0x49, 0x2f, 0xcc, 0x2c, 0x1d, 0x3a, 0xde, 0x01, 0xdd, 0x76, 0xc2, 0xf0, 0x99, 0x1f, + 0x34, 0xb4, 0xc6, 0xe3, 0xa9, 0x22, 0xd5, 0x78, 0x3c, 0x46, 0x2c, 0xc0, 0xe8, 0x56, 0xb3, 0x21, + 0x69, 0xc4, 0x89, 0x07, 0xeb, 0xf2, 0x9b, 0x8d, 0x5a, 0x4b, 0xf2, 0xd2, 0x91, 0x18, 0xcd, 0x26, + 0x7d, 0xa6, 0x68, 0xfa, 0x62, 0x1a, 0x8f, 0x3e, 0xd3, 0x68, 0x34, 0x24, 0xb2, 0x02, 0xe7, 0xaa, + 0xb4, 0xee, 0x7b, 0x8d, 0x7b, 0x4e, 0x3d, 0xf2, 0x83, 0x1d, 0xff, 0x09, 0xf5, 0xc4, 0x24, 0x44, + 0xa5, 0x30, 0xc4, 0xc2, 0xda, 0x63, 0x2c, 0xad, 0x45, 0xac, 0xd8, 0x4e, 0x53, 0x90, 0x2d, 0x18, + 0x7e, 0x24, 0x6c, 0x45, 0xe2, 0x98, 0xf4, 0xfa, 0x4d, 0x65, 0x3c, 0x5a, 0x0a, 0x28, 0xce, 0x1c, + 0xa7, 0xa9, 0x0e, 0x7a, 0x6a, 0x8f, 0xc5, 0xe5, 0x4a, 0x62, 0xda, 0x8a, 0x89, 0xb5, 0x0b, 0xe3, + 0xdb, 0xcd, 0xf6, 0x81, 0xeb, 0xb1, 0x85, 0xa5, 0x4a, 0x7f, 0x4c, 0x96, 0x01, 0x62, 0x80, 0xb0, + 0x00, 0x4d, 0x89, 0xc3, 0x55, 0x5c, 0xb0, 0x77, 0x57, 0x7c, 0x6d, 0x08, 0x41, 0x6d, 0xd8, 0xd6, + 0xe8, 0xac, 0xff, 0xd5, 0x07, 0x44, 0x0c, 0x00, 0x6e, 0x9f, 0x55, 0x1a, 0xb1, 0x2d, 0xe8, 0x3c, + 0xf4, 0x2a, 0x43, 0xcd, 0xe0, 0xc9, 0x71, 0xb9, 0xd7, 0x6d, 0xd8, 0xbd, 0x6b, 0xcb, 0xe4, 0x1d, + 0x18, 0x40, 0x34, 0x94, 0xff, 0x84, 0xaa, 0x4f, 0xe7, 0xc0, 0x17, 0x18, 0xdc, 0xd6, 0x6d, 0x8e, + 0x4c, 0xde, 0x85, 0x91, 0x65, 0xda, 0xa4, 0x07, 0x4e, 0xe4, 0xcb, 0x25, 0x80, 0x9b, 0x3e, 0x24, + 0x50, 0x9b, 0x73, 0x31, 0x26, 0x3b, 0x0a, 0xd9, 0xd4, 0x09, 0x7d, 0x4f, 0x3f, 0x0a, 0x05, 0x08, + 0xd1, 0x8f, 0x42, 0x1c, 0x87, 0xfc, 0x5e, 0x01, 0x46, 0x2b, 0x9e, 0x27, 0x4c, 0x0a, 0xa1, 0x90, + 0xfa, 0xcc, 0x4d, 0x65, 0x83, 0x5b, 0x77, 0xf6, 0x69, 0x73, 0xcf, 0x69, 0xb6, 0x69, 0xb8, 0xf8, + 0x35, 0xd3, 0x4e, 0xff, 0xe3, 0x71, 0xf9, 0xa3, 0x33, 0x18, 0x09, 0x62, 0x6b, 0xde, 0x4e, 0xe0, + 0xb8, 0x51, 0x78, 0x72, 0x5c, 0x9e, 0x71, 0xe2, 0x0a, 0xf5, 0xef, 0x46, 0x6b, 0x47, 0xbc, 0xfe, + 0x0f, 0x76, 0x5b, 0xff, 0xc9, 0x11, 0x4c, 0x56, 0xc2, 0xb0, 0x7d, 0x44, 0xab, 0x91, 0x13, 0x44, + 0xec, 0xec, 0x88, 0x8b, 0x48, 0xe7, 0x83, 0xe5, 0x9b, 0x3f, 0x3b, 0x2e, 0x17, 0x98, 0x42, 0xec, + 0x20, 0x29, 0x53, 0xa8, 0x82, 0xa8, 0x16, 0xb9, 0xfa, 0x16, 0x86, 0x47, 0xcc, 0x24, 0x6f, 0xeb, + 0x9a, 0x52, 0x3a, 0xd6, 0x96, 0xf3, 0x46, 0xdc, 0x5a, 0x82, 0xf9, 0xfb, 0x34, 0xb2, 0x69, 0x48, + 0x23, 0xf9, 0x8d, 0xe0, 0x0c, 0x8f, 0xcd, 0x7a, 0x43, 0xf8, 0x5b, 0x11, 0xe3, 0xf0, 0xf3, 0xef, + 0x42, 0x96, 0x58, 0xff, 0x4f, 0x01, 0xca, 0x4b, 0x01, 0xe5, 0xba, 0x64, 0x0e, 0xa3, 0xce, 0x6b, + 0xd7, 0x3c, 0xf4, 0xef, 0x3c, 0x6f, 0xc9, 0x13, 0x39, 0x96, 0xb2, 0x41, 0xb1, 0x11, 0x7a, 0x4a, + 0xf3, 0x86, 0xf5, 0x18, 0x66, 0x6c, 0xea, 0xd1, 0x67, 0xce, 0x7e, 0x93, 0x1a, 0x16, 0x82, 0x32, + 0x0c, 0xf0, 0x0f, 0x3d, 0xd5, 0x05, 0x0e, 0x3f, 0x9b, 0xb5, 0xc5, 0x1a, 0x87, 0xd1, 0x6d, 0xd7, + 0x3b, 0x10, 0xdc, 0xad, 0x3f, 0xee, 0x83, 0x31, 0xfe, 0x5b, 0xa8, 0xc7, 0x89, 0x2d, 0xae, 0x70, + 0x9a, 0x2d, 0xee, 0x7d, 0x18, 0x67, 0x7b, 0x04, 0x0d, 0xf6, 0x68, 0xc0, 0xb6, 0x56, 0x21, 0x09, + 0x54, 0xf5, 0x43, 0x2c, 0xa8, 0x3d, 0xe5, 0x25, 0xb6, 0x89, 0x48, 0xd6, 0x61, 0x82, 0x03, 0xee, + 0x51, 0x27, 0x6a, 0xc7, 0xd6, 0x8a, 0x49, 0xa1, 0x13, 0x4b, 0x30, 0x9f, 0x9a, 0x82, 0xd7, 0x63, + 0x01, 0xb4, 0x13, 0xb4, 0xe4, 0x53, 0x98, 0xdc, 0x0e, 0xfc, 0x6f, 0x9e, 0x6b, 0x9b, 0x3a, 0xff, + 0x3a, 0xb9, 0xf6, 0xcc, 0x8a, 0x6a, 0xfa, 0xd6, 0x9e, 0xc4, 0x26, 0x6f, 0xc1, 0xf0, 0x5a, 0xb8, + 0xe8, 0x07, 0xae, 0x77, 0x80, 0xdf, 0xe8, 0x30, 0x37, 0xf1, 0xba, 0x61, 0x6d, 0x1f, 0x81, 0xb6, + 0x2a, 0x4e, 0x18, 0x23, 0x87, 0xba, 0x1b, 0x23, 0x6f, 0x03, 0xac, 0xfb, 0x4e, 0xa3, 0xd2, 0x6c, + 0x2e, 0x55, 0x42, 0xdc, 0x3d, 0xc5, 0x7e, 0xd4, 0xf4, 0x9d, 0x46, 0xcd, 0x69, 0x36, 0x6b, 0x75, + 0x27, 0xb4, 0x35, 0x9c, 0x07, 0xfd, 0xc3, 0x83, 0xc5, 0x21, 0x7b, 0x72, 0xdd, 0xad, 0x53, 0x2f, + 0xa4, 0x8f, 0x9c, 0xc0, 0x73, 0xbd, 0x83, 0xd0, 0xfa, 0xe7, 0xe7, 0x60, 0x58, 0x75, 0xf9, 0xa6, + 0xae, 0xd8, 0x8b, 0x5d, 0x0e, 0x47, 0x3f, 0x36, 0x67, 0xd8, 0x1a, 0x06, 0xb9, 0x80, 0xaa, 0xbe, + 0xd8, 0x5f, 0x87, 0xd8, 0x6c, 0x74, 0x5a, 0x2d, 0x9b, 0xc1, 0xd8, 0x57, 0xb6, 0xbc, 0x88, 0xf2, + 0x1f, 0xe6, 0x5f, 0x59, 0x63, 0xdf, 0xee, 0x5d, 0x5e, 0x64, 0xd3, 0x7b, 0x6b, 0x6d, 0x79, 0x09, + 0x45, 0x39, 0xcc, 0xa7, 0xb7, 0xef, 0x36, 0xea, 0x36, 0x42, 0x59, 0x69, 0xb5, 0xb2, 0xb1, 0x2e, + 0xc4, 0x85, 0xa5, 0xa1, 0x73, 0xd4, 0xb4, 0x11, 0xca, 0x94, 0x43, 0x7e, 0x32, 0x5d, 0xf2, 0xbd, + 0x28, 0xf0, 0x9b, 0x21, 0x6a, 0x30, 0xc3, 0x7c, 0x38, 0xc5, 0x91, 0xb6, 0x2e, 0x8a, 0xec, 0x04, + 0x2a, 0x79, 0x04, 0xb3, 0x95, 0xc6, 0x53, 0xc7, 0xab, 0xd3, 0x06, 0x2f, 0x79, 0xe4, 0x07, 0x4f, + 0x1e, 0x37, 0xfd, 0x67, 0x21, 0xca, 0x7b, 0x58, 0x58, 0x80, 0x04, 0x8a, 0x3c, 0x21, 0x3f, 0x93, + 0x48, 0x76, 0x1e, 0x35, 0xfb, 0xa4, 0x96, 0x9a, 0x7e, 0xbb, 0x21, 0x46, 0x01, 0x3f, 0xa9, 0x3a, + 0x03, 0xd8, 0x1c, 0xce, 0xa4, 0xb4, 0x5a, 0xdd, 0x40, 0x7b, 0x8b, 0x90, 0xd2, 0x61, 0x78, 0x64, + 0x33, 0x18, 0x79, 0x1d, 0x86, 0xa4, 0x9e, 0xcb, 0xcd, 0xc1, 0x68, 0x86, 0x94, 0xfa, 0xad, 0x2c, + 0x63, 0x9f, 0x84, 0x4d, 0xeb, 0xfe, 0x53, 0x1a, 0x3c, 0x5f, 0xf2, 0x1b, 0x54, 0x5a, 0x07, 0xc4, + 0xe9, 0x97, 0x17, 0xd4, 0xea, 0xac, 0xc4, 0x36, 0x11, 0x59, 0x05, 0x7c, 0x0f, 0x0c, 0x4b, 0x93, + 0x71, 0x05, 0x7c, 0x8f, 0x0c, 0x6d, 0x59, 0x46, 0x96, 0xe1, 0x5c, 0xa5, 0x1d, 0xf9, 0x47, 0x4e, + 0xe4, 0xd6, 0x77, 0x5b, 0x07, 0x81, 0xc3, 0x2a, 0x29, 0x22, 0x01, 0xea, 0xfd, 0x8e, 0x2c, 0xac, + 0xb5, 0x45, 0xa9, 0x9d, 0x26, 0x20, 0xef, 0xc1, 0xd8, 0x5a, 0xc8, 0x2d, 0x40, 0x4e, 0x48, 0x1b, + 0x78, 0x8c, 0x17, 0xad, 0x74, 0xc3, 0x1a, 0xda, 0x83, 0x6a, 0xec, 0xa4, 0xd0, 0xb0, 0x0d, 0x3c, + 0x62, 0xc1, 0x60, 0x25, 0x0c, 0xdd, 0x30, 0xc2, 0xd3, 0xf9, 0xf0, 0x22, 0x9c, 0x1c, 0x97, 0x07, + 0x1d, 0x84, 0xd8, 0xa2, 0x84, 0x3c, 0x82, 0xd1, 0x65, 0xca, 0x14, 0xc7, 0x9d, 0xa0, 0x1d, 0x46, + 0x78, 0xd6, 0x1e, 0x5d, 0xb8, 0x20, 0x3e, 0x6c, 0xad, 0x44, 0xcc, 0x65, 0xae, 0xed, 0x35, 0x10, + 0x5e, 0x8b, 0x58, 0x81, 0xbe, 0x6b, 0x69, 0xf8, 0x4c, 0x2b, 0x16, 0x34, 0xab, 0x6e, 0x83, 0x7d, + 0xaa, 0xd3, 0xd8, 0x06, 0xd4, 0x8a, 0xc5, 0xda, 0x50, 0x3b, 0xc4, 0x12, 0x5d, 0x2b, 0x36, 0x48, + 0x48, 0x3d, 0x65, 0x54, 0x9c, 0x31, 0x0c, 0x47, 0x66, 0xa1, 0x6c, 0xe2, 0x19, 0x4d, 0x8e, 0x1f, + 0xc3, 0xe8, 0x52, 0x3b, 0x8c, 0xfc, 0xa3, 0x9d, 0x43, 0x7a, 0x44, 0x4b, 0xe7, 0x63, 0xdd, 0xbf, + 0x8e, 0xe0, 0x5a, 0xc4, 0xe0, 0x7a, 0x37, 0x35, 0x74, 0xf2, 0x19, 0x10, 0xa9, 0xc4, 0xdf, 0x67, + 0xf3, 0xc3, 0x63, 0x73, 0xb9, 0x34, 0x8b, 0x7d, 0x45, 0xcd, 0x5d, 0xea, 0xfe, 0xb5, 0x03, 0x55, + 0xac, 0x9b, 0x85, 0xd2, 0xc4, 0xac, 0x41, 0xbc, 0x89, 0xf7, 0x03, 0xa7, 0x75, 0x58, 0x2a, 0xc5, + 0x5a, 0xb6, 0xe8, 0xd4, 0x01, 0x83, 0x1b, 0xda, 0x42, 0x8c, 0x4e, 0xaa, 0x00, 0xfc, 0xe7, 0x3a, + 0x1b, 0xf8, 0x0b, 0x28, 0xaf, 0x92, 0x21, 0x2f, 0x56, 0x20, 0x65, 0x75, 0x01, 0x75, 0x10, 0xce, + 0xb6, 0xe9, 0x1a, 0xa3, 0xa9, 0xb1, 0x21, 0x4f, 0xa0, 0xc8, 0x7f, 0x6d, 0xf8, 0x9e, 0x1b, 0xf1, + 0xa5, 0x77, 0xce, 0xb0, 0xf8, 0x24, 0x8b, 0x65, 0x05, 0x68, 0x69, 0x13, 0x15, 0x1c, 0xa9, 0x52, + 0xad, 0x9a, 0x14, 0x63, 0xb2, 0x0d, 0xa3, 0xdb, 0x81, 0xdf, 0x68, 0xd7, 0x23, 0xdc, 0xb0, 0x2f, + 0xa2, 0xa2, 0x48, 0x44, 0x3d, 0x5a, 0x09, 0x97, 0x49, 0x8b, 0x03, 0x6a, 0x6c, 0x33, 0xd7, 0x65, + 0xa2, 0x21, 0x92, 0x45, 0x18, 0xdc, 0xf6, 0x9b, 0x6e, 0xfd, 0x79, 0x69, 0x1e, 0x1b, 0x3d, 0x2d, + 0x99, 0x21, 0x50, 0x36, 0x15, 0xb5, 0xc3, 0x16, 0x82, 0x74, 0xed, 0x90, 0x23, 0x91, 0x0a, 0x8c, + 0x7f, 0xc6, 0x26, 0x8c, 0xeb, 0x7b, 0x9e, 0xe3, 0x06, 0xb4, 0x74, 0x09, 0xc7, 0x05, 0xad, 0xa1, + 0x3f, 0xd6, 0x0b, 0xf4, 0xe9, 0x6c, 0x50, 0x90, 0x35, 0x98, 0x5c, 0x0b, 0xab, 0x51, 0xe0, 0xb6, + 0xe8, 0x86, 0xe3, 0x39, 0x07, 0xb4, 0x51, 0xba, 0x1c, 0x9b, 0x23, 0xdd, 0xb0, 0x16, 0x62, 0x59, + 0xed, 0x88, 0x17, 0xea, 0xe6, 0xc8, 0x04, 0x1d, 0xf9, 0x1c, 0xa6, 0x57, 0xbe, 0x89, 0xd8, 0x8c, + 0x69, 0x56, 0xda, 0x0d, 0x37, 0xaa, 0x46, 0x7e, 0xe0, 0x1c, 0xd0, 0x52, 0x19, 0xf9, 0xbd, 0x76, + 0x72, 0x5c, 0xbe, 0x42, 0x45, 0x79, 0xcd, 0x61, 0x08, 0xb5, 0x90, 0x63, 0xe8, 0x97, 0x8c, 0x59, + 0x1c, 0x98, 0xf4, 0xab, 0xed, 0x16, 0x53, 0x5c, 0x51, 0xfa, 0x57, 0x0c, 0xe9, 0x6b, 0x25, 0x5c, + 0xfa, 0x21, 0x07, 0xa4, 0xa4, 0xaf, 0x21, 0x12, 0x1b, 0xc8, 0x03, 0xdf, 0xf5, 0x2a, 0xf5, 0xc8, + 0x7d, 0x4a, 0xc5, 0xb9, 0x3e, 0x2c, 0x5d, 0xc5, 0x96, 0xa2, 0xe9, 0xf4, 0x57, 0x7d, 0xd7, 0xab, + 0x39, 0x58, 0x5c, 0x13, 0x56, 0x00, 0xc3, 0x74, 0x9a, 0xa6, 0x26, 0x3f, 0x84, 0xf3, 0x1b, 0xfe, + 0xbe, 0xdb, 0xa4, 0x7c, 0xc9, 0xe1, 0x62, 0x41, 0x23, 0xa0, 0x85, 0x7c, 0xd1, 0x74, 0x7a, 0x84, + 0x18, 0x35, 0xb1, 0x5a, 0x1d, 0x29, 0x1c, 0xdd, 0x74, 0x9a, 0xcd, 0x85, 0xac, 0xc0, 0x18, 0x7e, + 0x97, 0x4d, 0xfc, 0x19, 0x96, 0xae, 0xe1, 0xe9, 0xe8, 0x6a, 0x42, 0xe1, 0xb9, 0xb9, 0xa2, 0xe1, + 0xac, 0x78, 0x51, 0xf0, 0xdc, 0x36, 0xc8, 0xc8, 0x27, 0x30, 0x97, 0x9c, 0xde, 0x4b, 0xbe, 0xf7, + 0xd8, 0x3d, 0x68, 0x07, 0xb4, 0x51, 0x7a, 0x8d, 0x35, 0xd5, 0xee, 0x80, 0x31, 0xf7, 0x08, 0xce, + 0xa5, 0xaa, 0x20, 0x45, 0xe8, 0x7b, 0x22, 0xee, 0xa1, 0x46, 0x6c, 0xf6, 0x27, 0x79, 0x1b, 0x06, + 0x9e, 0xb2, 0x63, 0x09, 0x6a, 0x0c, 0xf1, 0xdd, 0x86, 0x46, 0xba, 0xe6, 0x3d, 0xf6, 0x6d, 0x8e, + 0xf4, 0x61, 0xef, 0xfb, 0x85, 0x07, 0xfd, 0xc3, 0xa3, 0xc5, 0x31, 0x7e, 0x7d, 0xf8, 0xa0, 0x7f, + 0x78, 0xbc, 0x38, 0x61, 0x55, 0x60, 0x32, 0x81, 0x4f, 0x4a, 0x30, 0x44, 0x3d, 0xa6, 0xea, 0x36, + 0xb8, 0xce, 0x62, 0xcb, 0x9f, 0x64, 0x1a, 0x06, 0x9a, 0xee, 0x91, 0x1b, 0x61, 0x85, 0x03, 0x36, + 0xff, 0x61, 0xfd, 0x7e, 0x01, 0x48, 0x7a, 0xcb, 0x20, 0xb7, 0x12, 0x6c, 0xb8, 0xa2, 0x27, 0x40, + 0xba, 0x99, 0x54, 0x72, 0xff, 0x0c, 0xa6, 0xf8, 0x98, 0xc9, 0xcd, 0x4d, 0xab, 0x8b, 0x2f, 0xaa, + 0x19, 0xc5, 0xba, 0x39, 0x44, 0x14, 0xe3, 0x56, 0xb8, 0x8e, 0x4d, 0x6b, 0xc3, 0x4c, 0xe6, 0x66, + 0x41, 0x36, 0x60, 0xe6, 0xc8, 0xf7, 0xa2, 0xc3, 0xe6, 0x73, 0xb9, 0x57, 0x88, 0xda, 0x0a, 0x58, + 0x1b, 0xae, 0x8f, 0x99, 0x08, 0xf6, 0x94, 0x00, 0x0b, 0x8e, 0x58, 0xcf, 0x83, 0xfe, 0xe1, 0xde, + 0x62, 0x9f, 0xea, 0x89, 0x65, 0xc3, 0xb9, 0xd4, 0x9a, 0x4b, 0xbe, 0x0f, 0x63, 0x75, 0x3c, 0xca, + 0x18, 0x35, 0xf1, 0x1d, 0x47, 0x83, 0xeb, 0x9f, 0x13, 0x87, 0xf3, 0xae, 0xfc, 0x51, 0x01, 0x66, + 0x73, 0x56, 0xdb, 0xb3, 0x8b, 0xfa, 0x0b, 0x38, 0x7f, 0xe4, 0x7c, 0x53, 0x0b, 0xf0, 0xa4, 0x5a, + 0x0b, 0x1c, 0x2f, 0x21, 0x6d, 0x5c, 0x49, 0xb2, 0x31, 0x74, 0x1f, 0x8e, 0x23, 0xe7, 0x1b, 0x1b, + 0x11, 0x6c, 0x56, 0xce, 0xdb, 0xf9, 0x03, 0x18, 0x37, 0xd6, 0xd7, 0x33, 0x37, 0xce, 0xba, 0x03, + 0xe7, 0xd8, 0x59, 0x3e, 0xa2, 0xa7, 0xb6, 0x50, 0x59, 0xdb, 0x00, 0x55, 0x7a, 0xe4, 0xb4, 0x0e, + 0x7d, 0xa6, 0x77, 0x2f, 0xea, 0xbf, 0x84, 0x85, 0x83, 0x08, 0x8b, 0x83, 0x2a, 0xd8, 0xbb, 0xcb, + 0x75, 0xf1, 0x50, 0x61, 0xda, 0x1a, 0x95, 0xf5, 0xe7, 0xbd, 0x40, 0xc4, 0x02, 0x19, 0x50, 0xe7, + 0x48, 0x36, 0xe3, 0x03, 0x18, 0xe3, 0xe7, 0x51, 0x0e, 0xc6, 0xe6, 0x8c, 0x2e, 0x4c, 0x89, 0x2f, + 0x4f, 0x2f, 0x5a, 0xed, 0xb1, 0x0d, 0x54, 0x46, 0x6a, 0x53, 0x7e, 0x90, 0x46, 0xd2, 0x5e, 0x83, + 0x54, 0x2f, 0x62, 0xa4, 0xfa, 0x6f, 0xf2, 0x29, 0x4c, 0x2c, 0xf9, 0x47, 0x2d, 0x26, 0x13, 0x41, + 0xdc, 0x27, 0x8c, 0x14, 0xa2, 0x5e, 0xa3, 0x70, 0xb5, 0xc7, 0x4e, 0xa0, 0x93, 0x4d, 0x98, 0xba, + 0xd7, 0x6c, 0x87, 0x87, 0x15, 0xaf, 0xb1, 0xd4, 0xf4, 0x43, 0xc9, 0xa5, 0x5f, 0x18, 0x09, 0xc4, + 0xf2, 0x96, 0xc6, 0x58, 0xed, 0xb1, 0xb3, 0x08, 0xc9, 0xeb, 0x30, 0xb0, 0xf2, 0x94, 0x2d, 0xbb, + 0xf2, 0x26, 0x5f, 0x38, 0x1a, 0x6d, 0x79, 0x74, 0xeb, 0xf1, 0x6a, 0x8f, 0xcd, 0x4b, 0x17, 0x47, + 0x60, 0x48, 0x9e, 0x65, 0x6f, 0x31, 0x95, 0x58, 0x89, 0xb3, 0x1a, 0x39, 0x51, 0x3b, 0x24, 0x73, + 0x30, 0xbc, 0xdb, 0x62, 0x47, 0x2c, 0x69, 0x04, 0xb0, 0xd5, 0x6f, 0xeb, 0x6d, 0x53, 0xd2, 0x64, + 0x5e, 0xb7, 0x1f, 0x73, 0xe4, 0x18, 0x60, 0xad, 0x9a, 0xc2, 0xed, 0x8c, 0x6d, 0xd4, 0xdb, 0x9b, + 0xa8, 0xb7, 0x98, 0x94, 0xb5, 0x35, 0x93, 0x29, 0x3c, 0xeb, 0x73, 0xb8, 0xbc, 0xdb, 0x0a, 0x69, + 0x10, 0x55, 0x5a, 0xad, 0xa6, 0x5b, 0xe7, 0x37, 0x49, 0x78, 0xe6, 0x95, 0x93, 0xe5, 0x3d, 0x18, + 0xe4, 0x00, 0x31, 0x4d, 0xe4, 0x1c, 0xac, 0xb4, 0x5a, 0xe2, 0xa4, 0x7d, 0x97, 0x2b, 0xe7, 0xfc, + 0xec, 0x6c, 0x0b, 0x6c, 0xeb, 0x77, 0x0a, 0x70, 0x99, 0x7f, 0x01, 0xb9, 0xac, 0xbf, 0x03, 0x23, + 0xe8, 0xe7, 0xd3, 0x72, 0xea, 0xf2, 0x9b, 0xe0, 0x0e, 0x4f, 0x12, 0x68, 0xc7, 0xe5, 0x9a, 0x07, + 0x55, 0x6f, 0xbe, 0x07, 0x95, 0xfc, 0xc0, 0xfa, 0x32, 0x3f, 0xb0, 0xcf, 0xc0, 0x12, 0x2d, 0x6a, + 0x36, 0x53, 0x8d, 0x0a, 0x5f, 0xa4, 0x55, 0xd6, 0x7f, 0xeb, 0x85, 0xd9, 0xfb, 0xd4, 0xa3, 0x81, + 0x83, 0xfd, 0x34, 0x6c, 0x3a, 0xba, 0x2f, 0x45, 0xa1, 0xa3, 0x2f, 0x45, 0x59, 0x5a, 0xc9, 0x7a, + 0xd1, 0x4a, 0x96, 0x72, 0x0b, 0x61, 0xc7, 0xc5, 0x5d, 0x7b, 0x4d, 0x74, 0x0b, 0x8f, 0x8b, 0xed, + 0xc0, 0x45, 0x3b, 0x38, 0x59, 0x8b, 0xfd, 0x30, 0xfa, 0xbb, 0x9a, 0xcb, 0xa6, 0xc4, 0xbd, 0xf4, + 0x90, 0xf0, 0xc3, 0x30, 0xbd, 0x2f, 0x36, 0x61, 0x90, 0x1b, 0xf7, 0xf0, 0xb6, 0x66, 0x74, 0xe1, + 0x86, 0xf8, 0xa6, 0x72, 0x3a, 0x28, 0x2c, 0x81, 0xb8, 0xb1, 0xf3, 0x29, 0x10, 0x21, 0xc0, 0x16, + 0x5c, 0xe6, 0x3e, 0x83, 0x51, 0x0d, 0xe5, 0x34, 0x7b, 0xbf, 0x32, 0x32, 0x32, 0x8d, 0xd1, 0x3b, + 0xe0, 0xf6, 0x4a, 0x6d, 0xef, 0xb7, 0x3e, 0x82, 0x52, 0xba, 0x35, 0xc2, 0xb0, 0xd4, 0xcd, 0x8e, + 0x65, 0x2d, 0xc3, 0xf4, 0x7d, 0x1a, 0xe1, 0xc4, 0xc5, 0x8f, 0x48, 0x73, 0x91, 0x49, 0x7c, 0x67, + 0x72, 0x55, 0x95, 0xb7, 0x3a, 0xfa, 0x57, 0x5a, 0x85, 0x99, 0x04, 0x17, 0x51, 0xff, 0x87, 0x30, + 0x24, 0x40, 0x6a, 0x45, 0x15, 0x2e, 0x89, 0x74, 0x5f, 0x14, 0xec, 0x2d, 0xf0, 0x79, 0x2b, 0x38, + 0xdb, 0x92, 0xc0, 0x3a, 0x84, 0xf3, 0x6c, 0x9b, 0x8d, 0xb9, 0xaa, 0xe9, 0x78, 0x11, 0x46, 0x5a, + 0x4c, 0x51, 0x08, 0xdd, 0x9f, 0xf0, 0x69, 0x34, 0x60, 0x0f, 0x33, 0x40, 0xd5, 0xfd, 0x09, 0x25, + 0x97, 0x00, 0xb0, 0x10, 0xbb, 0x29, 0x56, 0x01, 0x44, 0xe7, 0x86, 0x3b, 0x02, 0xe8, 0x8b, 0xc4, + 0xe7, 0x8d, 0x8d, 0x7f, 0x5b, 0x01, 0xcc, 0xa6, 0x6a, 0x12, 0x1d, 0xb8, 0x05, 0xc3, 0x52, 0x85, + 0x4d, 0x98, 0xd4, 0xf5, 0x1e, 0xd8, 0x0a, 0x89, 0xbc, 0x01, 0x93, 0x1e, 0xfd, 0x26, 0xaa, 0xa5, + 0xda, 0x30, 0xce, 0xc0, 0xdb, 0xb2, 0x1d, 0xd6, 0xaf, 0xa0, 0x19, 0xb5, 0xea, 0xf9, 0xcf, 0x1e, + 0x37, 0x9d, 0x27, 0x34, 0x55, 0xf1, 0xf7, 0x61, 0xb8, 0xda, 0xbd, 0x62, 0xfe, 0xf9, 0xc8, 0xca, + 0x6d, 0x45, 0x62, 0x35, 0x61, 0x8e, 0x75, 0xa9, 0x5a, 0xd9, 0x58, 0x5f, 0x6b, 0x6c, 0x7f, 0xdb, + 0x02, 0x7c, 0x0a, 0x17, 0x33, 0x6b, 0xfb, 0xb6, 0x85, 0xf8, 0xaf, 0xfa, 0x61, 0x96, 0x6f, 0x26, + 0xe9, 0x19, 0x7c, 0xfa, 0xa5, 0xe6, 0x97, 0x72, 0x23, 0x79, 0x3b, 0xe3, 0x46, 0x12, 0x49, 0xf4, + 0x1b, 0x49, 0xe3, 0x1e, 0xf2, 0xfd, 0xec, 0x7b, 0x48, 0xb4, 0x13, 0x99, 0xf7, 0x90, 0xc9, 0xdb, + 0xc7, 0x95, 0xfc, 0xdb, 0x47, 0xbc, 0x66, 0xc9, 0xb8, 0x7d, 0xcc, 0xba, 0x73, 0x4c, 0xb8, 0x84, + 0x0c, 0xbf, 0x5a, 0x97, 0x90, 0x37, 0x60, 0xa8, 0xd2, 0x6a, 0x69, 0x2e, 0x56, 0x38, 0x3c, 0x4e, + 0xab, 0xc5, 0x85, 0x27, 0x0b, 0xe5, 0x3a, 0x0f, 0x19, 0xeb, 0xfc, 0x07, 0x00, 0x4b, 0xe8, 0x06, + 0x8e, 0x03, 0x37, 0x8a, 0x18, 0xa8, 0xe1, 0x73, 0xe7, 0x70, 0x1c, 0x38, 0xdd, 0x02, 0x12, 0x23, + 0x73, 0xc5, 0xde, 0xda, 0x83, 0x52, 0x7a, 0xfa, 0xbc, 0x82, 0xa5, 0xeb, 0x4f, 0x0b, 0x70, 0x49, + 0x28, 0x39, 0x89, 0x0f, 0xfc, 0xec, 0xb3, 0xf3, 0x5d, 0x18, 0x13, 0xb4, 0x3b, 0xf1, 0x87, 0xc0, + 0xaf, 0x80, 0xe5, 0x62, 0xcc, 0x57, 0x74, 0x03, 0x8d, 0xbc, 0x0b, 0xc3, 0xf8, 0x47, 0x7c, 0x0d, + 0xc2, 0x24, 0x33, 0x82, 0xa8, 0xb5, 0xe4, 0x65, 0x88, 0x42, 0xb5, 0xbe, 0x86, 0xcb, 0x79, 0x0d, + 0x7f, 0x05, 0x72, 0xf9, 0xd7, 0x05, 0xb8, 0x28, 0xd8, 0x1b, 0x4b, 0xc5, 0x0b, 0xed, 0x3a, 0x67, + 0x70, 0xcc, 0x7c, 0x00, 0xa3, 0xac, 0x42, 0xd9, 0xee, 0x3e, 0xb1, 0xb5, 0x8a, 0x93, 0x43, 0x5c, + 0xb2, 0xec, 0x44, 0x8e, 0x70, 0x28, 0x71, 0x8e, 0x9a, 0xd2, 0x78, 0x61, 0xeb, 0xc4, 0xd6, 0x97, + 0x30, 0x9f, 0xdd, 0x85, 0x57, 0x20, 0x9f, 0x07, 0x30, 0x97, 0xb1, 0x29, 0xbc, 0xd8, 0x9e, 0xfc, + 0x05, 0x5c, 0xcc, 0xe4, 0xf5, 0x0a, 0x9a, 0xb9, 0xca, 0x34, 0x8e, 0xe8, 0x15, 0x0c, 0xa1, 0xf5, + 0x08, 0x2e, 0x64, 0x70, 0x7a, 0x05, 0x4d, 0xbc, 0x0f, 0xb3, 0x4a, 0xd3, 0x7e, 0xa9, 0x16, 0x6e, + 0xc0, 0x25, 0xce, 0xe8, 0xd5, 0x8c, 0xca, 0x43, 0xb8, 0x28, 0xd8, 0xbd, 0x02, 0xe9, 0xad, 0xc2, + 0x7c, 0x7c, 0xa0, 0xce, 0xd0, 0x93, 0x4e, 0xbd, 0xc8, 0x58, 0xeb, 0x70, 0x25, 0xe6, 0x94, 0xa3, + 0x34, 0x9c, 0x9e, 0x1b, 0x57, 0x07, 0xe3, 0x51, 0x7a, 0x25, 0x23, 0xfa, 0x08, 0xce, 0x1b, 0x4c, + 0x5f, 0x99, 0xaa, 0xb4, 0x06, 0x53, 0x9c, 0xb1, 0xa9, 0x3a, 0x2f, 0xe8, 0xaa, 0xf3, 0xe8, 0xc2, + 0xb9, 0x98, 0x25, 0x82, 0xf7, 0xee, 0x66, 0x68, 0xd3, 0x1b, 0xa8, 0x4d, 0x4b, 0x94, 0xb8, 0x85, + 0xef, 0xc2, 0x20, 0x87, 0x88, 0xf6, 0x65, 0x30, 0xe3, 0x87, 0x05, 0x4e, 0x26, 0x90, 0xad, 0x1f, + 0xc2, 0x25, 0x7e, 0x12, 0x8d, 0xef, 0x12, 0xcd, 0xd3, 0xe2, 0xf7, 0x13, 0x07, 0xd1, 0x0b, 0x82, + 0x6f, 0x12, 0x3f, 0xe7, 0x3c, 0xba, 0x2f, 0xe7, 0x76, 0x1e, 0xff, 0x53, 0x3d, 0xd1, 0x91, 0x07, + 0xcc, 0xde, 0xcc, 0x03, 0xe6, 0x35, 0xb8, 0xaa, 0x0e, 0x98, 0xc9, 0x6a, 0xe4, 0xd4, 0xb2, 0xbe, + 0x84, 0x8b, 0xbc, 0xa3, 0xd2, 0x49, 0xce, 0x6c, 0xc6, 0x47, 0x89, 0x6e, 0xce, 0x8a, 0x6e, 0x9a, + 0xd8, 0x39, 0x9d, 0xfc, 0xff, 0x0b, 0xf2, 0x93, 0xcb, 0x66, 0xfe, 0xcb, 0x3e, 0x71, 0x6f, 0x42, + 0x59, 0x09, 0xc4, 0x6c, 0xd1, 0x8b, 0x1d, 0xb7, 0x37, 0x60, 0x46, 0x67, 0xe3, 0xd6, 0xe9, 0xde, + 0x1d, 0xbc, 0xe4, 0x79, 0x87, 0x7d, 0x16, 0x08, 0x90, 0xd3, 0xae, 0x94, 0x21, 0x37, 0xc4, 0xb7, + 0x15, 0xa6, 0x55, 0x83, 0xf9, 0xf4, 0x50, 0xb8, 0x75, 0xe9, 0x39, 0x4d, 0x3e, 0x65, 0x9f, 0x30, + 0x42, 0xc4, 0x60, 0xe4, 0x32, 0x95, 0xdf, 0x31, 0x27, 0x97, 0x54, 0x96, 0x25, 0x97, 0x9a, 0x44, + 0xff, 0x59, 0xed, 0x72, 0x3e, 0xfc, 0x3a, 0x10, 0x59, 0xb4, 0x54, 0xb5, 0x65, 0xd5, 0x17, 0xa0, + 0x6f, 0xa9, 0x6a, 0x8b, 0x07, 0x1b, 0xa8, 0x09, 0xd6, 0xc3, 0xc0, 0x66, 0xb0, 0xa4, 0x46, 0xde, + 0x7b, 0x0a, 0x8d, 0xfc, 0x41, 0xff, 0x70, 0x5f, 0xb1, 0xdf, 0x26, 0x55, 0xf7, 0xc0, 0x7b, 0xe4, + 0x46, 0x87, 0xaa, 0xc2, 0x8a, 0xf5, 0x15, 0x4c, 0x19, 0xd5, 0x8b, 0xaf, 0xb8, 0xe3, 0x4b, 0x13, + 0xa6, 0xcf, 0x2e, 0x55, 0xd0, 0x89, 0x04, 0x4d, 0x16, 0x63, 0x7c, 0xbd, 0xa9, 0x3b, 0x35, 0x7c, + 0xc6, 0x68, 0xcb, 0x42, 0xeb, 0x9f, 0xf4, 0x6b, 0xdc, 0xb5, 0xf7, 0x3b, 0x1d, 0x7a, 0x77, 0x07, + 0x80, 0xcf, 0x10, 0xad, 0x73, 0x4c, 0x01, 0x1c, 0x15, 0xbe, 0x19, 0x7c, 0x49, 0xb6, 0x35, 0xa4, + 0xd3, 0xbe, 0xef, 0x11, 0x1e, 0xb5, 0x9c, 0x48, 0x3e, 0x69, 0x53, 0x1e, 0xb5, 0x82, 0x75, 0x68, + 0xeb, 0x48, 0xe4, 0x87, 0x49, 0x37, 0xf4, 0x01, 0xbc, 0x53, 0x7a, 0x4d, 0x5e, 0x32, 0xa7, 0xfb, + 0x76, 0x36, 0x4f, 0xf4, 0x67, 0x30, 0xc3, 0x68, 0xdd, 0xc7, 0x78, 0xb0, 0x58, 0xf9, 0x26, 0xa2, + 0x1e, 0x5f, 0xdb, 0x07, 0xb1, 0x9e, 0xd7, 0x3b, 0xd4, 0x13, 0x23, 0x0b, 0xfb, 0x7b, 0xcc, 0xa7, + 0x46, 0x55, 0x99, 0x9d, 0xcd, 0x1f, 0x27, 0x91, 0xbd, 0xbe, 0xe2, 0x35, 0x5a, 0xbe, 0xab, 0x0e, + 0x4c, 0x7c, 0x12, 0x05, 0xcd, 0x1a, 0x15, 0x70, 0x5b, 0x47, 0xb2, 0xde, 0xe8, 0xe8, 0xa7, 0x3d, + 0x0c, 0xfd, 0x3b, 0x4b, 0x3b, 0xeb, 0xc5, 0x82, 0x75, 0x0b, 0x40, 0xab, 0x09, 0x60, 0x70, 0x73, + 0xcb, 0xde, 0xa8, 0xac, 0x17, 0x7b, 0xc8, 0x0c, 0x9c, 0x7b, 0xb4, 0xb6, 0xb9, 0xbc, 0xf5, 0xa8, + 0x5a, 0xab, 0x6e, 0x54, 0xec, 0x9d, 0xa5, 0x8a, 0xbd, 0x5c, 0x2c, 0x58, 0x5f, 0xc3, 0xb4, 0xd9, + 0xc3, 0x57, 0x3a, 0x09, 0x23, 0x98, 0x52, 0xfa, 0xcc, 0x83, 0x47, 0x3b, 0x9a, 0xff, 0xa6, 0x38, + 0xfc, 0x25, 0xfd, 0x90, 0xc4, 0x31, 0x51, 0x7c, 0x46, 0x1a, 0x12, 0x79, 0x8b, 0xab, 0x05, 0xc9, + 0x17, 0x9a, 0x4c, 0x2d, 0xa8, 0xc5, 0x7a, 0x01, 0x2e, 0x7d, 0xdf, 0x83, 0x69, 0xb3, 0xd6, 0xd3, + 0x5a, 0xa9, 0x5e, 0x43, 0xc7, 0x56, 0xed, 0x01, 0x07, 0x21, 0xfa, 0xb5, 0x81, 0x58, 0x59, 0xbf, + 0x07, 0x45, 0x81, 0x15, 0xef, 0xbc, 0xd7, 0xa4, 0x19, 0xb1, 0x90, 0xf1, 0xd8, 0x4c, 0xba, 0x59, + 0xfb, 0x50, 0x64, 0x2b, 0xa6, 0xa0, 0xe4, 0x15, 0x4c, 0xc3, 0xc0, 0x7a, 0x7c, 0x9d, 0x63, 0xf3, + 0x1f, 0xf8, 0x8e, 0x21, 0x72, 0x82, 0x48, 0x7a, 0x7d, 0x8d, 0xd8, 0xea, 0x37, 0x79, 0x0b, 0x06, + 0xef, 0xb9, 0xcd, 0x48, 0x98, 0x46, 0xe2, 0x4d, 0x9e, 0xb1, 0xe5, 0x05, 0xb6, 0x40, 0xb0, 0x6c, + 0x38, 0xa7, 0x55, 0x78, 0x86, 0xa6, 0x92, 0x12, 0x0c, 0x6d, 0xd2, 0x6f, 0xb4, 0xfa, 0xe5, 0x4f, + 0xeb, 0x3d, 0x38, 0x27, 0x3c, 0xea, 0x34, 0x31, 0x5d, 0x15, 0x6f, 0x62, 0x0b, 0xc6, 0xc3, 0x3c, + 0xc1, 0x12, 0x8b, 0x18, 0xdd, 0x6e, 0xab, 0xf1, 0x82, 0x74, 0x6c, 0xa3, 0x38, 0x23, 0xdd, 0x9b, + 0xf2, 0x16, 0xa8, 0xdb, 0x70, 0xfe, 0x79, 0x01, 0x4a, 0x09, 0x2b, 0xc3, 0xd2, 0xa1, 0xd3, 0x6c, + 0x52, 0xef, 0x80, 0x92, 0xeb, 0xd0, 0xbf, 0xb3, 0xb5, 0xb3, 0x2d, 0xac, 0xa4, 0xd2, 0x01, 0x80, + 0x81, 0x14, 0x8e, 0x8d, 0x18, 0xe4, 0x21, 0x9c, 0x93, 0x3e, 0xb3, 0xaa, 0x48, 0x8c, 0xd0, 0xa5, + 0xce, 0x1e, 0xb8, 0x69, 0x3a, 0xf2, 0x8e, 0x30, 0x89, 0xfc, 0xb8, 0xed, 0x06, 0xb4, 0x81, 0x96, + 0x9f, 0xf8, 0x36, 0x5d, 0x2b, 0xb1, 0x75, 0x34, 0xfe, 0x82, 0xd1, 0xfa, 0xbd, 0x02, 0xcc, 0xe6, + 0x58, 0x4d, 0xc8, 0x5b, 0x46, 0x77, 0xa6, 0xb4, 0xee, 0x48, 0x94, 0xd5, 0x1e, 0xd1, 0x9f, 0x25, + 0xcd, 0x91, 0xb8, 0xef, 0x0c, 0x8e, 0xc4, 0xab, 0x3d, 0xb1, 0xf3, 0xf0, 0x22, 0xc0, 0xb0, 0x84, + 0x5b, 0x93, 0x30, 0x6e, 0xc8, 0xcd, 0xb2, 0x60, 0x4c, 0xaf, 0x99, 0x0d, 0xce, 0x92, 0xdf, 0x50, + 0x83, 0xc3, 0xfe, 0xb6, 0x7e, 0xb7, 0x00, 0xd3, 0xd8, 0xc5, 0x03, 0x97, 0x2d, 0x7d, 0xb1, 0x84, + 0x16, 0x8c, 0x9e, 0xcc, 0x1b, 0x3d, 0x49, 0xe0, 0xaa, 0x2e, 0x7d, 0x98, 0xea, 0xd2, 0x7c, 0x56, + 0x97, 0x70, 0x7a, 0xbb, 0xbe, 0x67, 0xf4, 0x44, 0xbb, 0x8a, 0xfa, 0xfd, 0x02, 0x4c, 0x69, 0x6d, + 0x52, 0xed, 0xbf, 0x63, 0x34, 0xe9, 0x62, 0x46, 0x93, 0x52, 0x42, 0x5e, 0x4c, 0xb5, 0xe8, 0xb5, + 0x4e, 0x2d, 0xea, 0x2a, 0xe3, 0xff, 0x52, 0x80, 0x99, 0x4c, 0x19, 0x90, 0xf3, 0x4c, 0xb7, 0xad, + 0x07, 0x34, 0x12, 0xe2, 0x15, 0xbf, 0x18, 0x7c, 0x2d, 0x0c, 0xdb, 0x34, 0x10, 0xdf, 0xb9, 0xf8, + 0x45, 0x5e, 0x83, 0xf1, 0x6d, 0x1a, 0xb8, 0x7e, 0x83, 0xbb, 0x98, 0x73, 0xdf, 0xcd, 0x71, 0xdb, + 0x04, 0x92, 0x79, 0x18, 0xa9, 0x34, 0x0f, 0xfc, 0xc0, 0x8d, 0x0e, 0xf9, 0x6d, 0xe0, 0x88, 0x1d, + 0x03, 0x18, 0xef, 0x65, 0xf7, 0x80, 0x5f, 0x6a, 0x30, 0x62, 0xf1, 0x8b, 0x2d, 0x2e, 0xd2, 0x5a, + 0x38, 0xc8, 0x17, 0x17, 0x69, 0x0a, 0x3c, 0x0f, 0x83, 0x9f, 0xd9, 0x38, 0x09, 0xf0, 0xdd, 0xb8, + 0x2d, 0x7e, 0x91, 0x09, 0x74, 0x12, 0xc6, 0x57, 0x09, 0xe8, 0x1c, 0xfc, 0x21, 0x4c, 0x67, 0xc9, + 0x35, 0x6b, 0x0a, 0x09, 0xda, 0x5e, 0x45, 0xfb, 0x25, 0x4c, 0x55, 0x1a, 0x8d, 0x8d, 0x7b, 0x15, + 0xee, 0x73, 0x20, 0x46, 0x95, 0x7f, 0x3c, 0xdc, 0x5e, 0x27, 0x54, 0xb6, 0xfe, 0x35, 0xcf, 0x8d, + 0xec, 0xa9, 0x95, 0x6f, 0xdc, 0x30, 0x72, 0xbd, 0x03, 0xcd, 0xa8, 0x68, 0x9f, 0xdf, 0xa4, 0xcf, + 0x32, 0xa6, 0x00, 0xdb, 0x4d, 0x4d, 0xde, 0x1c, 0x9e, 0xc1, 0x7c, 0x5a, 0x63, 0x1b, 0x2f, 0x25, + 0xb3, 0x26, 0xdf, 0xb8, 0xa0, 0xaf, 0x52, 0x7f, 0x62, 0x7d, 0x0f, 0xce, 0xf3, 0x25, 0xad, 0x53, + 0xe3, 0x45, 0xb3, 0x75, 0x1b, 0xa8, 0xf5, 0xbe, 0xb4, 0x52, 0x74, 0x6c, 0x99, 0x3d, 0x66, 0xb4, + 0x05, 0xab, 0xfc, 0xaf, 0x05, 0x98, 0x4b, 0x90, 0x56, 0x9f, 0x7b, 0x75, 0xb9, 0x9e, 0xbe, 0x91, + 0x74, 0xc2, 0x46, 0x3d, 0x80, 0x1b, 0xff, 0xdc, 0x86, 0xf2, 0xc3, 0x26, 0xb7, 0x00, 0x38, 0xb1, + 0xb6, 0x7d, 0xa3, 0xe9, 0x5b, 0x38, 0xd9, 0xe0, 0x06, 0xae, 0xa1, 0x90, 0x36, 0x64, 0xc9, 0x5d, + 0x7c, 0x23, 0xdd, 0x6c, 0xc3, 0x18, 0x2b, 0x81, 0x0a, 0xf2, 0x5a, 0x8e, 0x91, 0x38, 0x8b, 0xbf, + 0xf5, 0xf7, 0xfa, 0x60, 0x56, 0x1f, 0xc0, 0x17, 0xe9, 0xeb, 0x36, 0x8c, 0x2e, 0xf9, 0x5e, 0x44, + 0xbf, 0x89, 0xb4, 0xb7, 0xea, 0x44, 0xdd, 0xb4, 0xab, 0x12, 0xa1, 0x3a, 0x72, 0x40, 0x8d, 0xe9, + 0x31, 0x86, 0xb3, 0x60, 0x8c, 0x48, 0x96, 0x60, 0x7c, 0x93, 0x3e, 0x4b, 0x09, 0x10, 0x1d, 0x16, + 0x3d, 0xfa, 0xac, 0xa6, 0x09, 0x51, 0xf7, 0x22, 0x33, 0x68, 0xc8, 0x3e, 0x4c, 0xc8, 0xc9, 0x65, + 0x08, 0x73, 0x4e, 0xdf, 0x55, 0xcc, 0xe9, 0xcc, 0x5f, 0x73, 0xb3, 0x1a, 0x72, 0x64, 0x98, 0xe0, + 0xc8, 0xba, 0xce, 0x6b, 0xe4, 0x0f, 0x94, 0xcd, 0x6d, 0x4b, 0x2b, 0x31, 0xdc, 0x41, 0x93, 0x0f, + 0x93, 0x75, 0x16, 0xd6, 0x36, 0x94, 0xd2, 0xe3, 0x21, 0x6a, 0x7b, 0x07, 0x06, 0x39, 0x54, 0xa8, + 0x01, 0x32, 0x0c, 0x89, 0xc2, 0xe6, 0xe7, 0x74, 0x5e, 0x8d, 0x2d, 0x70, 0xad, 0x55, 0xb4, 0x9d, + 0x28, 0x1c, 0xa5, 0x88, 0xdd, 0x4e, 0x0e, 0x2f, 0x7a, 0xda, 0xca, 0xe1, 0xd5, 0xfd, 0x4c, 0xe4, + 0xe3, 0x82, 0x25, 0x34, 0x3f, 0xe9, 0x9c, 0x44, 0xc3, 0x6e, 0xc0, 0x90, 0x00, 0x25, 0x02, 0xa4, + 0xc4, 0x9f, 0x9f, 0x44, 0xb0, 0x3e, 0x84, 0x0b, 0x68, 0x0b, 0x73, 0xbd, 0x83, 0x26, 0xdd, 0x0d, + 0x8d, 0xe7, 0x01, 0xdd, 0x3e, 0xeb, 0x8f, 0x61, 0x2e, 0x8b, 0xb6, 0xeb, 0x97, 0xcd, 0x43, 0x16, + 0xfc, 0x55, 0x2f, 0x4c, 0xaf, 0x85, 0xba, 0x32, 0x21, 0x24, 0x71, 0x33, 0xeb, 0x31, 0x3d, 0xca, + 0x64, 0xb5, 0x27, 0xeb, 0xb1, 0xfc, 0x3b, 0xda, 0xe3, 0xc4, 0xde, 0x4e, 0xaf, 0xe4, 0xd9, 0xb6, + 0xa5, 0x9e, 0x27, 0xbe, 0x01, 0xfd, 0x9b, 0x6c, 0xa9, 0xee, 0x13, 0x63, 0xc7, 0x29, 0x18, 0x08, + 0x1f, 0x07, 0xb2, 0x2d, 0x92, 0xfd, 0x20, 0xf7, 0x52, 0x4f, 0x10, 0xfb, 0xbb, 0xbf, 0x02, 0x5f, + 0xed, 0x49, 0xbd, 0x46, 0x7c, 0x0f, 0x46, 0x2b, 0x8d, 0x23, 0xee, 0x11, 0xe8, 0x7b, 0x89, 0xcf, + 0x52, 0x2b, 0x59, 0xed, 0xb1, 0x75, 0x44, 0x76, 0xc2, 0xad, 0xb4, 0x5a, 0xb8, 0x51, 0x65, 0xbd, + 0x8c, 0x5f, 0xed, 0x41, 0x07, 0xfb, 0xc5, 0x61, 0x18, 0xdc, 0x71, 0x82, 0x03, 0x1a, 0x59, 0x5f, + 0xc2, 0x9c, 0x70, 0x52, 0xe1, 0x96, 0x3f, 0x74, 0x65, 0x09, 0x63, 0x3f, 0xa4, 0x4e, 0x8e, 0x25, + 0x97, 0x01, 0x50, 0xcf, 0x5f, 0xf3, 0x1a, 0xf4, 0x1b, 0xe1, 0x25, 0xa7, 0x41, 0xac, 0x77, 0x61, + 0x44, 0x49, 0x08, 0x95, 0x59, 0x6d, 0xb3, 0x43, 0x69, 0x4d, 0x1b, 0x6f, 0x2e, 0xe5, 0x43, 0xcb, + 0x0b, 0x46, 0xdf, 0x45, 0xa4, 0x0b, 0xae, 0xfd, 0xba, 0x30, 0x93, 0x98, 0x04, 0xf1, 0x53, 0x6a, + 0xa5, 0x7f, 0x72, 0x37, 0x3e, 0xf5, 0x3b, 0xa9, 0x9e, 0xf6, 0x9e, 0x4a, 0x3d, 0xb5, 0xfe, 0x59, + 0x2f, 0x1e, 0x9c, 0x52, 0xf2, 0x48, 0xd8, 0xa0, 0x74, 0x3b, 0xd8, 0x22, 0x8c, 0x60, 0xef, 0x97, + 0xe5, 0xd3, 0xaf, 0xce, 0x3e, 0x16, 0xc3, 0x3f, 0x3b, 0x2e, 0xf7, 0xa0, 0x63, 0x45, 0x4c, 0x46, + 0x3e, 0x81, 0xa1, 0x15, 0xaf, 0x81, 0x1c, 0xfa, 0xce, 0xc0, 0x41, 0x12, 0xb1, 0x31, 0xc1, 0x26, + 0xef, 0xb0, 0x4f, 0x98, 0x9b, 0x2e, 0x6c, 0x0d, 0x12, 0x9f, 0xe0, 0x06, 0xf2, 0x4e, 0x70, 0x83, + 0x89, 0x13, 0x9c, 0x05, 0x03, 0x5b, 0x41, 0x43, 0x44, 0xa8, 0x98, 0x58, 0x18, 0x13, 0x82, 0x43, + 0x98, 0xcd, 0x8b, 0xac, 0xff, 0x5e, 0x80, 0xd9, 0xfb, 0x34, 0xca, 0x9c, 0x43, 0x86, 0x54, 0x0a, + 0x2f, 0x2d, 0x95, 0xde, 0x17, 0x91, 0x8a, 0xea, 0x75, 0x5f, 0x5e, 0xaf, 0xfb, 0xf3, 0x7a, 0x3d, + 0x90, 0xdf, 0xeb, 0xfb, 0x30, 0xc8, 0xbb, 0xca, 0x4e, 0xa9, 0x6b, 0x11, 0x3d, 0x8a, 0x4f, 0xa9, + 0xba, 0x87, 0x98, 0xcd, 0xcb, 0x98, 0x22, 0xb9, 0xee, 0x84, 0xfa, 0x29, 0x55, 0xfc, 0xb4, 0x7e, + 0x84, 0x8f, 0x46, 0xd7, 0xfd, 0xfa, 0x13, 0xcd, 0xda, 0x39, 0xc4, 0xbf, 0xd0, 0xa4, 0x75, 0x9c, + 0x61, 0xf1, 0x12, 0x5b, 0x62, 0x90, 0x2b, 0x30, 0xba, 0xe6, 0xdd, 0xf3, 0x83, 0x3a, 0xdd, 0xf2, + 0x9a, 0x9c, 0xfb, 0xb0, 0xad, 0x83, 0x84, 0x15, 0x40, 0xd4, 0x10, 0x1f, 0xad, 0x11, 0x90, 0x38, + 0x5a, 0x33, 0xd8, 0xde, 0x82, 0xcd, 0xcb, 0x84, 0x91, 0x81, 0xfd, 0xdd, 0xe9, 0x54, 0xaa, 0x8e, + 0xaf, 0xdd, 0x10, 0xf7, 0xe1, 0x82, 0x4d, 0x5b, 0x4d, 0x87, 0xe9, 0x74, 0x47, 0x3e, 0xc7, 0x57, + 0x7d, 0xbe, 0x92, 0xf1, 0xe0, 0xcb, 0xf4, 0x17, 0x50, 0x4d, 0xee, 0xed, 0xd0, 0xe4, 0x23, 0xb8, + 0x7a, 0x9f, 0x46, 0xe6, 0x82, 0x1a, 0xdb, 0x52, 0x45, 0xe7, 0x57, 0x61, 0x38, 0x34, 0xed, 0xc0, + 0x97, 0xe5, 0xf5, 0x43, 0x16, 0xe1, 0xde, 0x5d, 0x79, 0x53, 0x22, 0xf8, 0xa8, 0xbf, 0xac, 0x4f, + 0xa1, 0x9c, 0x57, 0xdd, 0xe9, 0xdc, 0x39, 0x5d, 0xb8, 0x92, 0xcf, 0x40, 0x34, 0x77, 0x05, 0xa4, + 0xcd, 0x58, 0x7c, 0x42, 0xdd, 0x5a, 0x6b, 0x9a, 0x99, 0xc5, 0x1f, 0xd6, 0xa2, 0x74, 0x6c, 0x7b, + 0x89, 0xe6, 0xd6, 0xf0, 0x3a, 0xd6, 0x64, 0x10, 0xcb, 0xb5, 0x02, 0xc3, 0x12, 0x26, 0xe4, 0x3a, + 0x9b, 0xd9, 0x52, 0x29, 0xd0, 0x86, 0x64, 0xa0, 0xc8, 0xac, 0x1f, 0xc9, 0xab, 0x09, 0x93, 0xe2, + 0x74, 0x2f, 0x20, 0x4f, 0x73, 0x17, 0x61, 0xf9, 0x70, 0xc1, 0xe4, 0xad, 0x9b, 0x9c, 0x8b, 0x9a, + 0xc9, 0x99, 0x5b, 0x9a, 0xaf, 0x98, 0x26, 0xd0, 0x5e, 0x31, 0x2f, 0x63, 0x10, 0xb9, 0xac, 0x1b, + 0x96, 0xc7, 0xd2, 0x4f, 0x2a, 0x6f, 0xc3, 0x5c, 0x56, 0x85, 0xda, 0x39, 0x50, 0x59, 0x2f, 0x85, + 0xbe, 0xb3, 0x0c, 0x97, 0x65, 0x8c, 0x18, 0xdf, 0x8f, 0xc2, 0x28, 0x70, 0x5a, 0xd5, 0x7a, 0xe0, + 0xb6, 0x62, 0x2a, 0x0b, 0x06, 0x39, 0x44, 0x48, 0x82, 0x5f, 0xf3, 0x70, 0x1c, 0x51, 0x62, 0xfd, + 0x66, 0x01, 0x2c, 0xc3, 0x07, 0x09, 0xc7, 0x79, 0x3b, 0xf0, 0x9f, 0xba, 0x0d, 0xed, 0x6a, 0xe5, + 0x2d, 0xc3, 0xac, 0xc7, 0x9f, 0xc4, 0x25, 0xdd, 0x9f, 0xc5, 0x9a, 0x79, 0x3b, 0x61, 0x6a, 0xe3, + 0x8a, 0x27, 0xfa, 0x25, 0x3d, 0xa1, 0xfa, 0x93, 0x12, 0x65, 0x82, 0xfb, 0x9f, 0x05, 0xb8, 0xd6, + 0xb1, 0x0d, 0xa2, 0x3f, 0xfb, 0x50, 0x4c, 0x96, 0x89, 0x19, 0x54, 0xd6, 0x7c, 0x12, 0xd2, 0x1c, + 0xf6, 0xee, 0x70, 0x1f, 0x6b, 0xe9, 0xbb, 0xd3, 0x52, 0x9c, 0x53, 0xfc, 0xce, 0xde, 0x7a, 0xf2, + 0x01, 0xc0, 0x8e, 0x1f, 0x39, 0xcd, 0x25, 0x34, 0x00, 0xf4, 0xc5, 0xfe, 0xf2, 0x11, 0x83, 0xd6, + 0x92, 0x41, 0x0a, 0x34, 0x64, 0xeb, 0x07, 0xf8, 0x5d, 0x67, 0x37, 0xfa, 0x74, 0x9f, 0xda, 0x12, + 0x5c, 0x4b, 0xdc, 0x8b, 0xbf, 0x00, 0x93, 0x08, 0x66, 0x98, 0xf8, 0x99, 0xee, 0x7d, 0x3f, 0xf0, + 0xdb, 0xad, 0x5f, 0xce, 0xa8, 0xff, 0x59, 0x81, 0x3b, 0x2a, 0xea, 0xd5, 0x8a, 0x81, 0x5e, 0x02, + 0x88, 0xa1, 0x09, 0x87, 0x75, 0x55, 0xb0, 0x77, 0x87, 0x1f, 0xb9, 0xd1, 0x62, 0x7e, 0xc0, 0x19, + 0x68, 0x64, 0xbf, 0xdc, 0x91, 0xbc, 0x8b, 0x97, 0xe1, 0xaa, 0xf6, 0xd3, 0xc9, 0xfd, 0x3d, 0x69, + 0xff, 0x38, 0x23, 0xdd, 0x21, 0x4c, 0xb3, 0x15, 0xa0, 0xd2, 0x8e, 0x0e, 0xfd, 0xc0, 0x8d, 0xe4, + 0xd3, 0x0b, 0xb2, 0x2d, 0xde, 0x76, 0x73, 0xaa, 0x8f, 0x7f, 0x71, 0x5c, 0x7e, 0xff, 0x2c, 0xb1, + 0xfb, 0x24, 0xcf, 0x1d, 0xf5, 0x1e, 0xdc, 0x9a, 0x85, 0xbe, 0x25, 0x7b, 0x1d, 0x17, 0x3c, 0x7b, + 0x5d, 0x2d, 0x78, 0xf6, 0xba, 0xf5, 0x37, 0xbd, 0x50, 0xe6, 0xd1, 0x27, 0xd0, 0x87, 0x22, 0xb6, + 0x5a, 0x68, 0x4e, 0x19, 0xa7, 0x35, 0x30, 0x24, 0xa2, 0x4b, 0xf4, 0x9e, 0x26, 0xba, 0xc4, 0xaf, + 0x41, 0x8e, 0xc9, 0xea, 0x14, 0x56, 0x80, 0x37, 0x4f, 0x8e, 0xcb, 0xd7, 0x62, 0x2b, 0x00, 0x2f, + 0xcd, 0x32, 0x07, 0xe4, 0x54, 0x91, 0xb6, 0x5f, 0xf4, 0xbf, 0x80, 0xfd, 0xe2, 0x36, 0x0c, 0xe1, + 0x61, 0x66, 0x6d, 0x5b, 0x78, 0x35, 0xe2, 0xf4, 0xc4, 0x78, 0x32, 0x35, 0x57, 0x0f, 0xea, 0x25, + 0xd1, 0xac, 0x7f, 0xd8, 0x0b, 0x57, 0xf2, 0x65, 0x2e, 0xda, 0xb6, 0x0c, 0x10, 0x7b, 0x6f, 0x74, + 0xf2, 0x16, 0xc1, 0x6f, 0xe7, 0x19, 0xdd, 0x57, 0xde, 0x5a, 0x1a, 0x1d, 0xd3, 0x7d, 0xe4, 0x43, + 0xdf, 0xc4, 0x55, 0x81, 0xf1, 0xfe, 0x57, 0x44, 0xa4, 0x14, 0x20, 0x23, 0x22, 0xa5, 0x80, 0x91, + 0x7d, 0x98, 0xdd, 0x0e, 0xdc, 0xa7, 0x4e, 0x44, 0x1f, 0xd2, 0xe7, 0xfc, 0x21, 0xcc, 0x8a, 0x78, + 0xfd, 0xc2, 0x5f, 0x6f, 0x5f, 0x3f, 0x39, 0x2e, 0xbf, 0xd6, 0xe2, 0x28, 0xec, 0xc3, 0xac, 0xf1, + 0xa7, 0x87, 0xb5, 0xf4, 0x83, 0x98, 0x3c, 0x46, 0xd6, 0xbf, 0x2d, 0xc0, 0x45, 0x54, 0xcb, 0x85, + 0xd9, 0x55, 0x56, 0xfe, 0x42, 0x4e, 0x83, 0x7a, 0x07, 0xc5, 0x5c, 0x44, 0xa7, 0x41, 0xe3, 0x21, + 0xb4, 0x6d, 0xa0, 0x91, 0x35, 0x18, 0x15, 0xbf, 0xf1, 0xfb, 0xeb, 0xc3, 0x03, 0xc1, 0x8c, 0xb6, + 0x60, 0xe1, 0x54, 0xe7, 0xa6, 0x22, 0x9c, 0xd8, 0x82, 0x19, 0xbe, 0x17, 0xb4, 0x75, 0x5a, 0xeb, + 0xe7, 0xbd, 0x30, 0xbf, 0x47, 0x03, 0xf7, 0xf1, 0xf3, 0x9c, 0xce, 0x6c, 0xc1, 0xb4, 0x04, 0xf1, + 0x08, 0x14, 0xc6, 0x27, 0xc6, 0xa3, 0xd2, 0xc9, 0xa6, 0x8a, 0x10, 0x16, 0xf2, 0x8b, 0xcb, 0x24, + 0x3c, 0x83, 0x3b, 0xe0, 0x3b, 0x30, 0x9c, 0x88, 0x01, 0x83, 0xe3, 0x2f, 0xbf, 0xd0, 0x78, 0xa8, + 0x56, 0x7b, 0x6c, 0x85, 0x49, 0x7e, 0x2b, 0xff, 0xfe, 0x46, 0x98, 0x3e, 0xba, 0xd9, 0x3f, 0xf1, + 0x83, 0x65, 0x1f, 0xab, 0xa3, 0x95, 0x66, 0x7c, 0xb0, 0xab, 0x3d, 0x76, 0x5e, 0x4d, 0x8b, 0xa3, + 0x30, 0x52, 0xc1, 0x3b, 0x29, 0x76, 0x72, 0xff, 0x1f, 0xbd, 0x70, 0x59, 0x3e, 0x6a, 0xc9, 0x11, + 0xf3, 0xe7, 0x30, 0x2b, 0x41, 0x95, 0x16, 0x53, 0x18, 0x68, 0xc3, 0x94, 0x34, 0x8f, 0x0c, 0x29, + 0x25, 0xed, 0x08, 0x9c, 0x58, 0xd8, 0x79, 0xe4, 0xaf, 0xc6, 0xfa, 0xf9, 0x49, 0x56, 0x44, 0x1e, + 0xb4, 0x42, 0xea, 0x6b, 0xa6, 0x21, 0x1a, 0x63, 0xfd, 0x6c, 0xa4, 0xac, 0xa7, 0xfd, 0x2f, 0x6b, + 0x3d, 0x5d, 0xed, 0x49, 0xda, 0x4f, 0x17, 0x27, 0x60, 0x6c, 0x93, 0x3e, 0x8b, 0xe5, 0xfe, 0xff, + 0x16, 0x12, 0x91, 0x06, 0x98, 0x86, 0xc1, 0x43, 0x0e, 0x14, 0xe2, 0xa0, 0x2e, 0x18, 0x69, 0x40, + 0xd7, 0x30, 0x38, 0xea, 0x1a, 0x0c, 0xf1, 0x8b, 0xda, 0xc6, 0x29, 0x4e, 0xf8, 0xea, 0x75, 0x0a, + 0x7f, 0x32, 0xd8, 0xe0, 0x87, 0x7d, 0x41, 0x6f, 0x3d, 0x84, 0xab, 0xc2, 0x7f, 0xd9, 0x1c, 0x7c, + 0xac, 0xe8, 0x8c, 0xdb, 0x97, 0xe5, 0xc0, 0xe5, 0xfb, 0x34, 0xb9, 0xf4, 0x18, 0xaf, 0x77, 0x3e, + 0x85, 0x49, 0x03, 0xae, 0x38, 0xa2, 0x56, 0xaa, 0xe6, 0x90, 0x62, 0x9d, 0xc4, 0xb6, 0xae, 0x64, + 0x55, 0xa1, 0x37, 0xd6, 0xa2, 0x18, 0xe2, 0x31, 0x88, 0xaf, 0xd8, 0xc2, 0x33, 0xac, 0x7a, 0xd7, + 0xb5, 0xef, 0x9a, 0xaf, 0x78, 0x3c, 0xd6, 0x9b, 0xdc, 0x79, 0x55, 0xa9, 0x35, 0x6e, 0xdc, 0x05, + 0x58, 0x13, 0x30, 0x26, 0x8b, 0x9a, 0x34, 0x0c, 0xad, 0x9f, 0x0e, 0x80, 0x25, 0x04, 0x9b, 0x75, + 0xfb, 0x2c, 0xe5, 0xb1, 0x9f, 0x6a, 0xac, 0xd8, 0xa8, 0xce, 0xeb, 0xd1, 0x05, 0xe3, 0x52, 0x3e, + 0xf3, 0x50, 0xcf, 0xab, 0xc7, 0x50, 0x63, 0xe6, 0xa5, 0x7a, 0xff, 0x55, 0xce, 0x32, 0xc9, 0x3f, + 0xb6, 0xd7, 0x4f, 0x8e, 0xcb, 0x57, 0x73, 0x96, 0x49, 0x83, 0x6f, 0xf6, 0x92, 0x69, 0x9b, 0x57, + 0x22, 0x7d, 0x2f, 0x72, 0x25, 0xc2, 0xbe, 0x48, 0xfd, 0x52, 0x64, 0xd7, 0x94, 0xa5, 0xf8, 0x1e, + 0xe5, 0x95, 0xb6, 0x5e, 0x24, 0x1e, 0xfc, 0x6b, 0x10, 0x83, 0xab, 0xc1, 0x86, 0xb8, 0x50, 0xd4, + 0x6c, 0x96, 0x4b, 0x87, 0xb4, 0xfe, 0x44, 0xd8, 0x8a, 0xe5, 0x85, 0x6e, 0x96, 0xcd, 0x9c, 0x47, + 0x99, 0xe5, 0xdf, 0x39, 0x2f, 0xa8, 0xd5, 0x19, 0xa9, 0x1e, 0xb0, 0x20, 0xc9, 0x96, 0xfc, 0x04, + 0xa6, 0xd4, 0x50, 0x27, 0xdc, 0x8f, 0x46, 0x17, 0x5e, 0x8b, 0xc3, 0x51, 0x1e, 0x3d, 0x76, 0x6e, + 0x3e, 0xbd, 0x73, 0x33, 0x03, 0x97, 0xbf, 0x83, 0xaf, 0xcb, 0x02, 0xcd, 0xf7, 0x48, 0xbf, 0xe8, + 0xca, 0x22, 0xd4, 0xae, 0xb3, 0xff, 0x81, 0x72, 0x96, 0x67, 0xfa, 0x82, 0xdb, 0xa4, 0xe2, 0xd5, + 0x8b, 0x9c, 0x7d, 0x39, 0x57, 0x71, 0x85, 0x6f, 0xf9, 0x2a, 0xee, 0x8f, 0x7b, 0xe5, 0x13, 0x81, + 0xf4, 0x6d, 0xe8, 0x99, 0x6f, 0xe4, 0x32, 0x7b, 0x70, 0xaa, 0xcd, 0x34, 0xb3, 0x71, 0x64, 0x51, + 0xde, 0x67, 0xaa, 0xd8, 0x50, 0x13, 0xea, 0x6e, 0x20, 0x2e, 0x30, 0xae, 0x38, 0x51, 0x75, 0xd1, + 0xa8, 0x92, 0x97, 0x65, 0x7d, 0x2f, 0x7f, 0x59, 0xf6, 0x2f, 0x47, 0xe0, 0xdc, 0xb6, 0x73, 0xe0, + 0x7a, 0x6c, 0xd1, 0xb6, 0x69, 0xe8, 0xb7, 0x83, 0x3a, 0x25, 0x15, 0x98, 0x30, 0xfd, 0x3f, 0xbb, + 0x78, 0xb7, 0xb2, 0x7d, 0xc9, 0x84, 0x91, 0x05, 0x18, 0x51, 0x6f, 0x4e, 0xc5, 0x66, 0x92, 0xf1, + 0x16, 0x75, 0xb5, 0xc7, 0x8e, 0xd1, 0xc8, 0x07, 0xc6, 0xfd, 0xce, 0xa4, 0x7a, 0x3e, 0x8d, 0xb8, + 0x0b, 0xdc, 0x41, 0xcf, 0xf3, 0x1b, 0xe6, 0x86, 0xc8, 0x2f, 0x31, 0x7e, 0x94, 0xba, 0xf2, 0x19, + 0x30, 0x5a, 0x9c, 0xb2, 0x7b, 0xa1, 0x2e, 0x90, 0x1b, 0xe6, 0x37, 0xe3, 0x32, 0xe8, 0x4b, 0x18, + 0x7d, 0xd8, 0xde, 0xa7, 0xf2, 0x72, 0x6b, 0x50, 0xec, 0x8f, 0x49, 0xaf, 0x66, 0x51, 0xbe, 0x77, + 0x97, 0x8f, 0xc1, 0x93, 0xf6, 0x3e, 0x4d, 0xc7, 0x8f, 0x66, 0x0b, 0x93, 0xc6, 0x8c, 0x1c, 0x42, + 0x31, 0xe9, 0x80, 0x2c, 0xa2, 0xa9, 0x75, 0x70, 0x9b, 0xc6, 0x50, 0x1e, 0x5a, 0x94, 0x6a, 0xee, + 0x16, 0x69, 0x54, 0x92, 0xe2, 0x4a, 0x7e, 0x1d, 0x66, 0x32, 0xad, 0x8e, 0xea, 0x09, 0x55, 0x67, + 0x83, 0x26, 0x2e, 0xea, 0x09, 0xa9, 0xc9, 0xf7, 0x5a, 0x46, 0xcd, 0xd9, 0xb5, 0x90, 0x06, 0x4c, + 0x26, 0x1c, 0x6b, 0x45, 0x20, 0xfe, 0x7c, 0x57, 0x5d, 0xdc, 0x98, 0x64, 0xd4, 0xd2, 0xcc, 0xba, + 0x92, 0x2c, 0xc9, 0x3a, 0x8c, 0xa8, 0xe3, 0x3e, 0xbe, 0xce, 0xca, 0x36, 0x6d, 0x94, 0x4e, 0x8e, + 0xcb, 0xd3, 0xb1, 0x69, 0xc3, 0xe0, 0x19, 0x33, 0x20, 0xbf, 0x01, 0x57, 0xd5, 0x14, 0xdd, 0x0a, + 0xb2, 0x8d, 0x40, 0x22, 0x0a, 0xf6, 0x8d, 0xe4, 0x0c, 0xcf, 0xc3, 0xdf, 0xbb, 0xb3, 0xd8, 0x5b, + 0x2a, 0xac, 0xf6, 0xd8, 0xdd, 0x59, 0x93, 0x9f, 0x16, 0xe0, 0x7c, 0x4e, 0xad, 0x63, 0x58, 0x6b, + 0x57, 0xcb, 0x1c, 0x2a, 0xf7, 0xf8, 0x6c, 0xc8, 0x6d, 0xc4, 0xcf, 0xeb, 0xa4, 0x89, 0xce, 0xe8, + 0x77, 0x4e, 0x4d, 0xe4, 0x6d, 0x18, 0xc4, 0x33, 0x72, 0x58, 0x1a, 0x47, 0x2d, 0x12, 0x23, 0xd8, + 0xe0, 0x49, 0x5a, 0xdf, 0x37, 0x04, 0x0e, 0x59, 0x65, 0xda, 0x18, 0xee, 0x5b, 0x52, 0x7b, 0x12, + 0xf1, 0xae, 0x84, 0x46, 0xcf, 0x8b, 0x64, 0x94, 0x0b, 0x23, 0xdc, 0xb9, 0x49, 0xb6, 0x08, 0x30, + 0x1c, 0x88, 0x55, 0xe9, 0x41, 0xff, 0x70, 0x7f, 0x71, 0x80, 0x7f, 0x38, 0xd2, 0x63, 0xfb, 0xb7, + 0x87, 0xf9, 0xf3, 0xce, 0x5d, 0xcf, 0x7d, 0xec, 0xc6, 0x0b, 0x98, 0x6e, 0x5d, 0x8b, 0xb3, 0x8e, + 0x08, 0xdd, 0x37, 0x27, 0xbf, 0x88, 0x32, 0xc4, 0xf5, 0x76, 0x35, 0xc4, 0xdd, 0xd5, 0xae, 0xac, + 0xb4, 0x10, 0x91, 0x5c, 0xc7, 0x31, 0x0d, 0x5f, 0xf1, 0x5d, 0xd6, 0xd7, 0x30, 0x88, 0x51, 0x1d, + 0xf9, 0x7d, 0xe0, 0xe8, 0xc2, 0x4d, 0xb1, 0x6c, 0x77, 0x68, 0x3e, 0x0f, 0x03, 0x29, 0x9e, 0x6c, + 0x73, 0x89, 0x23, 0xc0, 0x90, 0x38, 0x42, 0xc8, 0x0e, 0x4c, 0x6d, 0x07, 0xb4, 0x21, 0xfc, 0x86, + 0x5b, 0x81, 0x30, 0x4e, 0x70, 0xb3, 0x07, 0x6e, 0xf9, 0x2d, 0x59, 0x5c, 0xa3, 0xaa, 0x5c, 0xdf, + 0x50, 0x33, 0xc8, 0xc9, 0x0a, 0x4c, 0x54, 0xa9, 0x13, 0xd4, 0x0f, 0x1f, 0xd2, 0xe7, 0x4c, 0xdd, + 0x31, 0x42, 0xed, 0x87, 0x58, 0xc2, 0xfa, 0x8b, 0x45, 0xba, 0x8f, 0x87, 0x49, 0x44, 0x7e, 0x00, + 0x83, 0x55, 0x3f, 0x88, 0x16, 0x9f, 0x8b, 0x45, 0x4d, 0xde, 0x18, 0x71, 0xe0, 0xe2, 0x05, 0x99, + 0x6e, 0x20, 0xf4, 0x83, 0xa8, 0xb6, 0x6f, 0x84, 0x44, 0xe2, 0x28, 0xe4, 0x39, 0x4c, 0x9b, 0x0b, + 0x8a, 0x70, 0x67, 0x1d, 0x16, 0x6a, 0x56, 0xd6, 0xaa, 0xc5, 0x51, 0x16, 0xaf, 0x0b, 0xee, 0x57, + 0x92, 0xcb, 0xd6, 0x63, 0x2c, 0xd7, 0xa3, 0x14, 0x65, 0xd1, 0x93, 0x0d, 0xcc, 0xd2, 0xc0, 0x7b, + 0x54, 0x09, 0xb9, 0x1b, 0xec, 0x48, 0x1c, 0x74, 0xab, 0x8d, 0x8b, 0x12, 0x4a, 0xc2, 0x09, 0x93, + 0xa9, 0x3d, 0xec, 0x14, 0x29, 0xd9, 0x86, 0x73, 0xbb, 0x21, 0xdd, 0x0e, 0xe8, 0x53, 0x97, 0x3e, + 0x93, 0xfc, 0x20, 0x8e, 0x50, 0xc4, 0xf8, 0xb5, 0x78, 0x69, 0x16, 0xc3, 0x34, 0x31, 0xf9, 0x00, + 0x60, 0xdb, 0xf5, 0x3c, 0xda, 0xc0, 0x6b, 0xc7, 0x51, 0x64, 0x85, 0x26, 0xd5, 0x16, 0x42, 0x6b, + 0xbe, 0xd7, 0xd4, 0x45, 0xaa, 0x21, 0x93, 0x45, 0x18, 0x5f, 0xf3, 0xea, 0xcd, 0xb6, 0x70, 0x0f, + 0x08, 0x71, 0x41, 0x11, 0x91, 0xd3, 0x5c, 0x5e, 0x50, 0x4b, 0x7d, 0xe4, 0x26, 0x09, 0x79, 0x08, + 0x44, 0x00, 0xc4, 0xac, 0x75, 0xf6, 0x9b, 0x54, 0x7c, 0xee, 0x68, 0x2a, 0x91, 0x8c, 0x70, 0xba, + 0x1b, 0x01, 0xc9, 0x52, 0x64, 0x73, 0x1f, 0xc0, 0xa8, 0x36, 0xe7, 0x33, 0x62, 0x10, 0x4c, 0xeb, + 0x31, 0x08, 0x46, 0xf4, 0x58, 0x03, 0xff, 0xb8, 0x00, 0xf3, 0xd9, 0xdf, 0x92, 0x50, 0xc0, 0xb6, + 0x60, 0x44, 0x01, 0xd5, 0xab, 0x13, 0xa9, 0xfa, 0x27, 0x34, 0x20, 0xfe, 0x41, 0xcb, 0x95, 0x47, + 0xef, 0x7d, 0xcc, 0xe3, 0x05, 0xec, 0xf1, 0xff, 0xdf, 0x30, 0x4c, 0xa3, 0x77, 0x75, 0x72, 0x9d, + 0xfa, 0x14, 0x63, 0x89, 0x20, 0x4c, 0x33, 0x2f, 0x0b, 0x4b, 0x13, 0x87, 0x27, 0x03, 0x5f, 0x19, + 0x04, 0xe4, 0x5d, 0xdd, 0x27, 0xa2, 0x57, 0xcb, 0x0b, 0x21, 0x81, 0x7a, 0x17, 0x62, 0x67, 0x89, + 0xb7, 0x8c, 0x2b, 0xf9, 0x53, 0x2f, 0x7a, 0xfd, 0xa7, 0x5d, 0xf4, 0x76, 0xd5, 0xa2, 0xc7, 0x63, + 0x54, 0xbc, 0xa9, 0x2d, 0x7a, 0xaf, 0x7e, 0xb5, 0x1b, 0x7c, 0xd5, 0xab, 0xdd, 0xd0, 0xcb, 0xad, + 0x76, 0xc3, 0x2f, 0xb8, 0xda, 0xdd, 0x83, 0x89, 0x4d, 0x4a, 0x1b, 0xda, 0x45, 0xc9, 0x48, 0xbc, + 0x7b, 0x7a, 0x14, 0x4d, 0x60, 0x59, 0xb7, 0x25, 0x09, 0xaa, 0xdc, 0x55, 0x13, 0xfe, 0x6e, 0x56, + 0xcd, 0xd1, 0x57, 0xbc, 0x6a, 0x8e, 0xbd, 0xcc, 0xaa, 0x99, 0x5a, 0xfa, 0xc6, 0xcf, 0xbc, 0xf4, + 0xbd, 0xcc, 0x6a, 0xf5, 0x09, 0xba, 0x14, 0x56, 0xab, 0xab, 0xc2, 0x7b, 0x44, 0x73, 0xd7, 0x58, + 0xf5, 0x43, 0xe9, 0x71, 0x8d, 0x7f, 0x33, 0xd8, 0xb6, 0x1f, 0xc8, 0x2b, 0x6f, 0xfc, 0xdb, 0x5a, + 0x44, 0x47, 0x42, 0x9d, 0x5e, 0xb9, 0xeb, 0x0f, 0x89, 0x27, 0x7b, 0x62, 0x8d, 0x4b, 0x1e, 0xa3, + 0x6c, 0x59, 0x6e, 0xfd, 0x55, 0x81, 0x5f, 0x4a, 0xfe, 0x9f, 0xb8, 0x54, 0xbe, 0xcc, 0x45, 0xe1, + 0x6f, 0xc5, 0x4f, 0xf9, 0x45, 0xd8, 0x81, 0xc0, 0xa9, 0x3f, 0x89, 0x6f, 0x6a, 0x7f, 0xc8, 0xbe, + 0x73, 0xbd, 0x00, 0x03, 0xab, 0xc6, 0x67, 0x45, 0xb3, 0x70, 0xef, 0x8e, 0x5c, 0x00, 0x44, 0x44, + 0x03, 0x0e, 0x36, 0x17, 0x00, 0x9d, 0x00, 0x7d, 0xe5, 0x26, 0x2d, 0x9b, 0xbf, 0x44, 0xcf, 0x6c, + 0xc1, 0x7b, 0xe9, 0xb7, 0xd4, 0x78, 0x18, 0x89, 0xdf, 0x52, 0xeb, 0x62, 0x8c, 0x5f, 0x55, 0xef, + 0xc2, 0x45, 0x9b, 0x1e, 0xf9, 0x4f, 0xe9, 0xab, 0x65, 0xfb, 0x15, 0x5c, 0x30, 0x19, 0xf2, 0x57, + 0x37, 0x3c, 0x20, 0xfa, 0x27, 0xd9, 0x61, 0xd4, 0x05, 0x01, 0x0f, 0xa3, 0xce, 0xa3, 0x31, 0xb3, + 0x3f, 0xf5, 0x7d, 0x03, 0xcb, 0x2c, 0x1f, 0xe6, 0x4d, 0xe6, 0x95, 0x46, 0x03, 0x73, 0xf0, 0xd5, + 0xdd, 0x96, 0xe3, 0x45, 0x64, 0x0b, 0x46, 0xb5, 0x9f, 0x09, 0x53, 0x81, 0x56, 0x22, 0x74, 0x9a, + 0x18, 0x60, 0x84, 0xe0, 0x8c, 0xc1, 0x16, 0x85, 0x72, 0x52, 0x3c, 0x4c, 0x64, 0x7a, 0x9d, 0x8b, + 0x30, 0xae, 0xfd, 0x54, 0x26, 0x4b, 0xfc, 0xf8, 0xb5, 0x1a, 0x4c, 0x81, 0x99, 0x24, 0x56, 0x1d, + 0xe6, 0xb2, 0x84, 0x86, 0xd1, 0x99, 0x9e, 0x93, 0x95, 0x38, 0xce, 0x53, 0x77, 0x6f, 0xbb, 0xc9, + 0xbc, 0x18, 0x4f, 0xd6, 0xdf, 0xef, 0x87, 0x8b, 0x62, 0x30, 0x5e, 0xe5, 0x88, 0x93, 0x1f, 0xc1, + 0xa8, 0x36, 0xc6, 0x42, 0xe8, 0x57, 0x64, 0xe8, 0xcd, 0xbc, 0xb9, 0xc0, 0x4d, 0x1a, 0x6d, 0x04, + 0xd4, 0x12, 0xc3, 0xbd, 0xda, 0x63, 0xeb, 0x2c, 0x49, 0x13, 0x26, 0xcc, 0x81, 0x16, 0x56, 0x9d, + 0x6b, 0x99, 0x95, 0x98, 0xa8, 0x32, 0x90, 0x73, 0xa3, 0x96, 0x39, 0xdc, 0xab, 0x3d, 0x76, 0x82, + 0x37, 0xf9, 0x06, 0xce, 0xa5, 0x46, 0x59, 0x18, 0xeb, 0xde, 0xc8, 0xac, 0x30, 0x85, 0xcd, 0xcd, + 0xb1, 0x01, 0x82, 0x73, 0xab, 0x4d, 0x57, 0x42, 0x1a, 0x30, 0xa6, 0x0f, 0xbc, 0x30, 0x3b, 0x5d, + 0xed, 0x20, 0x4a, 0x8e, 0xc8, 0x95, 0x3b, 0x21, 0x4b, 0x1c, 0xfb, 0xe7, 0xa6, 0x89, 0xd9, 0x40, + 0x1e, 0x86, 0x41, 0xfe, 0x9b, 0x2d, 0x01, 0xdb, 0x01, 0x0d, 0xa9, 0x57, 0xa7, 0x86, 0x83, 0xf6, + 0x4b, 0x2e, 0x01, 0xff, 0xa6, 0x00, 0xa5, 0x2c, 0xbe, 0x55, 0xea, 0x35, 0xc8, 0x36, 0x14, 0x93, + 0x15, 0x89, 0x59, 0x6d, 0xa9, 0x58, 0xb9, 0xb9, 0x4d, 0x5a, 0xed, 0xb1, 0x53, 0xd4, 0x64, 0x13, + 0xce, 0x69, 0x30, 0x61, 0x5c, 0xed, 0x3d, 0x8d, 0x71, 0x95, 0x8d, 0x42, 0x8a, 0x54, 0xb7, 0x4d, + 0xaf, 0xe2, 0xce, 0xb8, 0xec, 0x1f, 0x39, 0xae, 0xc7, 0x14, 0x5d, 0x2d, 0xd4, 0x13, 0xc4, 0x50, + 0x21, 0x1b, 0x6e, 0x6d, 0x45, 0xa8, 0x7c, 0x50, 0xa2, 0x50, 0xac, 0x8f, 0x71, 0x05, 0x17, 0x36, + 0x3a, 0xfe, 0x3c, 0x55, 0x31, 0xbb, 0x02, 0x03, 0x3b, 0xeb, 0xd5, 0xa5, 0x8a, 0x78, 0xec, 0xca, + 0x43, 0x24, 0x34, 0xc3, 0x5a, 0xdd, 0xb1, 0x79, 0x81, 0xf5, 0x11, 0x90, 0xfb, 0x34, 0x12, 0xc1, + 0xda, 0x15, 0xdd, 0xeb, 0x30, 0x24, 0x40, 0x82, 0x12, 0x5d, 0xe3, 0x9a, 0x02, 0x4b, 0x96, 0x59, + 0xdb, 0xf2, 0x9c, 0xd0, 0xa4, 0x4e, 0xa8, 0x6d, 0xcc, 0xef, 0xc3, 0x70, 0x20, 0x60, 0x62, 0x5f, + 0x9e, 0x50, 0x69, 0x2d, 0x10, 0xcc, 0xed, 0xd9, 0x12, 0xc7, 0x56, 0x7f, 0x59, 0xeb, 0x18, 0xce, + 0x64, 0x6b, 0x6d, 0x79, 0x89, 0x49, 0x55, 0x08, 0x4b, 0x0e, 0xc7, 0x2d, 0xf4, 0x21, 0x8f, 0xa8, + 0xfe, 0xd4, 0x15, 0x45, 0x83, 0x1f, 0xb9, 0x08, 0xe2, 0xa3, 0xa1, 0x58, 0x77, 0x55, 0x70, 0x94, + 0x0c, 0x6e, 0x79, 0xe9, 0x19, 0x36, 0x31, 0xec, 0xcb, 0x7d, 0x74, 0x97, 0x79, 0x15, 0x8d, 0x70, + 0x60, 0x8e, 0x6f, 0xf3, 0xac, 0x57, 0x22, 0x31, 0x99, 0xaf, 0x96, 0xc6, 0x25, 0x18, 0x51, 0x30, + 0x75, 0xf7, 0xc5, 0x65, 0x65, 0xe0, 0xef, 0xdd, 0xe5, 0xaf, 0x82, 0xeb, 0x8a, 0x41, 0x4c, 0xc7, + 0xaa, 0xe0, 0xdf, 0xdd, 0xb7, 0x5c, 0x45, 0x48, 0x83, 0xe8, 0x5b, 0xad, 0x22, 0x8e, 0x0b, 0x74, + 0x96, 0x2a, 0x0c, 0xfc, 0xbd, 0x85, 0xd3, 0x08, 0xea, 0x5b, 0xae, 0x82, 0x09, 0xea, 0xdb, 0xab, + 0x82, 0xca, 0x00, 0x4a, 0x7c, 0x92, 0xa6, 0x2a, 0x59, 0x49, 0x57, 0x22, 0x0d, 0xd7, 0x09, 0x8a, + 0x8e, 0xe3, 0x41, 0x61, 0x9e, 0x0b, 0xeb, 0x97, 0x50, 0x0d, 0x13, 0xd8, 0xb7, 0x5b, 0xcd, 0x3f, + 0x2a, 0xf0, 0x70, 0x4e, 0xd5, 0x2d, 0x2d, 0x25, 0xa0, 0xf7, 0xd8, 0xd7, 0xae, 0xe6, 0xb5, 0xaf, + 0xfd, 0xa1, 0xeb, 0x35, 0xf4, 0xab, 0x79, 0xa7, 0x1d, 0x1d, 0xaa, 0x70, 0xc7, 0x4f, 0x5c, 0xaf, + 0x61, 0x27, 0xb1, 0xc9, 0x07, 0x30, 0xae, 0x81, 0x94, 0xb6, 0xc6, 0x73, 0x46, 0xe8, 0xe4, 0x6e, + 0xc3, 0x36, 0x31, 0xad, 0xbf, 0x2d, 0xc0, 0x54, 0x46, 0xaa, 0x5a, 0x34, 0x66, 0xe0, 0x29, 0x48, + 0x2d, 0x54, 0x22, 0x61, 0x12, 0x46, 0x96, 0x30, 0x36, 0x49, 0x85, 0x88, 0xd1, 0xf2, 0xb5, 0xb4, + 0xba, 0xbd, 0x5a, 0xea, 0xae, 0xec, 0x54, 0xba, 0x3a, 0x3a, 0x09, 0x01, 0xe2, 0x96, 0x08, 0xb3, + 0x71, 0x95, 0xa9, 0xb4, 0x5a, 0x4e, 0xde, 0x57, 0x92, 0x14, 0x58, 0xab, 0xc6, 0xfa, 0xad, 0x5e, + 0x38, 0x9f, 0xd1, 0xff, 0x2a, 0x8d, 0xfe, 0x2e, 0x44, 0x90, 0xc8, 0x8c, 0xdc, 0xf7, 0x4b, 0xca, + 0x8c, 0x6c, 0xfd, 0x87, 0x5e, 0x38, 0xbf, 0xdb, 0x0a, 0xf1, 0x85, 0xd5, 0x9a, 0xf7, 0x94, 0x7a, + 0x91, 0x1f, 0x3c, 0xc7, 0x57, 0x21, 0xe4, 0x5d, 0x18, 0x58, 0xa5, 0xcd, 0xa6, 0x2f, 0xe6, 0xff, + 0x25, 0xe9, 0x1d, 0x91, 0xc4, 0x46, 0xa4, 0xd5, 0x1e, 0x9b, 0x63, 0x93, 0x0f, 0x60, 0x64, 0x95, + 0x3a, 0x41, 0xb4, 0x4f, 0x1d, 0x79, 0x64, 0x91, 0x99, 0x2c, 0x34, 0x12, 0x81, 0xb0, 0xda, 0x63, + 0xc7, 0xd8, 0x64, 0x81, 0x9d, 0xe6, 0xbd, 0x03, 0xf5, 0x9a, 0x3c, 0xa7, 0x42, 0x86, 0xb3, 0xda, + 0x63, 0x23, 0x2e, 0xd9, 0x80, 0xf1, 0xca, 0x01, 0xf5, 0xa2, 0x0d, 0x1a, 0x39, 0x0d, 0x27, 0x72, + 0x84, 0x6a, 0xfb, 0x7a, 0x1e, 0xb1, 0x81, 0xbc, 0xda, 0x63, 0x9b, 0xd4, 0xe4, 0x23, 0x18, 0xba, + 0xef, 0xfb, 0x8d, 0xfd, 0xe7, 0x54, 0xa8, 0xab, 0xe5, 0x3c, 0x46, 0x02, 0x6d, 0xb5, 0xc7, 0x96, + 0x14, 0x8b, 0x03, 0xd0, 0xb7, 0x11, 0x1e, 0x58, 0xc7, 0x05, 0x28, 0x2d, 0xfb, 0xcf, 0xbc, 0x4c, + 0xa9, 0x7e, 0xcf, 0x94, 0xaa, 0x64, 0x9f, 0x81, 0x9f, 0x90, 0xeb, 0x3b, 0xd0, 0xbf, 0xed, 0x7a, + 0x07, 0x09, 0x55, 0x30, 0x83, 0x8e, 0x61, 0xa1, 0x78, 0x5c, 0xef, 0x80, 0xac, 0x4b, 0x1d, 0x5c, + 0xd8, 0x1a, 0xfb, 0x0c, 0xc5, 0x3f, 0x83, 0x5a, 0xc7, 0x8e, 0x75, 0x6d, 0xfe, 0x5b, 0x76, 0xf0, + 0x2d, 0x98, 0xcd, 0xa9, 0x57, 0x3c, 0x0f, 0x67, 0x7d, 0xeb, 0x47, 0xc5, 0xe6, 0x4d, 0x98, 0xc9, + 0x1c, 0xbf, 0x14, 0xe2, 0x3f, 0xcd, 0x9a, 0x88, 0xbc, 0xe7, 0x25, 0x18, 0x92, 0xd9, 0x92, 0xb8, + 0xed, 0x47, 0xfe, 0xc4, 0x07, 0x52, 0xf2, 0x43, 0x95, 0x81, 0x3d, 0xe4, 0xf7, 0xb8, 0xa7, 0x05, + 0x52, 0xe2, 0x9f, 0xd3, 0x87, 0x2f, 0xf1, 0xd1, 0x28, 0x5e, 0xac, 0xce, 0x55, 0x3f, 0x8c, 0x3c, + 0xe5, 0x79, 0x6b, 0xab, 0xdf, 0xe4, 0x06, 0x14, 0x65, 0x3a, 0x07, 0x91, 0x37, 0x46, 0x64, 0x72, + 0xb6, 0x53, 0x70, 0xf2, 0x3e, 0xcc, 0x26, 0x61, 0xb2, 0x97, 0xfc, 0x85, 0x5b, 0x5e, 0xb1, 0xf5, + 0x97, 0xbd, 0x18, 0xeb, 0xba, 0xc3, 0xbc, 0x66, 0xd2, 0xdd, 0xaa, 0x0a, 0x69, 0xf5, 0x6e, 0x55, + 0xc9, 0x3c, 0x8c, 0x6c, 0x55, 0x8d, 0x94, 0x53, 0x76, 0x0c, 0x60, 0xcd, 0x66, 0x5d, 0xa8, 0x04, + 0xf5, 0x43, 0x37, 0xa2, 0xf5, 0xa8, 0x1d, 0x88, 0x55, 0xd8, 0x4e, 0xc1, 0x89, 0x05, 0x63, 0xf7, + 0x9b, 0xee, 0x7e, 0x5d, 0x32, 0xe3, 0x22, 0x30, 0x60, 0xe4, 0x0d, 0x98, 0x58, 0xf3, 0xc2, 0xc8, + 0x69, 0x36, 0x37, 0x68, 0x74, 0xe8, 0x37, 0x44, 0xd2, 0x4c, 0x3b, 0x01, 0x65, 0xf5, 0x2e, 0xf9, + 0x5e, 0xe4, 0xb8, 0x1e, 0x0d, 0xec, 0xb6, 0x17, 0xb9, 0x47, 0x54, 0xf4, 0x3d, 0x05, 0x27, 0xef, + 0xc0, 0x8c, 0x82, 0x6d, 0x05, 0xf5, 0x43, 0x1a, 0x46, 0x01, 0x26, 0xa2, 0xc3, 0x80, 0x3f, 0x76, + 0x76, 0x21, 0xd6, 0xd0, 0xf4, 0xdb, 0x8d, 0x15, 0xef, 0xa9, 0x1b, 0xf8, 0x1e, 0xe6, 0xa6, 0x18, + 0x16, 0x35, 0x24, 0xe0, 0xd6, 0x1f, 0x0e, 0x67, 0x7e, 0xb6, 0x2f, 0x33, 0x07, 0xbf, 0x80, 0xb1, + 0x25, 0xa7, 0xe5, 0xec, 0xbb, 0x4d, 0x37, 0x72, 0x55, 0xc6, 0xae, 0x77, 0xbb, 0x7c, 0xf3, 0x32, + 0xc1, 0x07, 0x6d, 0xe8, 0xc4, 0xb6, 0xc1, 0x6a, 0xee, 0x6f, 0x06, 0x61, 0x26, 0x13, 0x8f, 0x5c, + 0x17, 0xa9, 0xbd, 0xd4, 0xba, 0x2a, 0x92, 0x5d, 0xd9, 0x49, 0x30, 0x1b, 0x4b, 0x04, 0x2d, 0x35, + 0xa9, 0xe3, 0xb5, 0x45, 0xaa, 0x2b, 0xdb, 0x80, 0xb1, 0xb1, 0x64, 0x7a, 0x83, 0xc6, 0x0c, 0x1d, + 0xa7, 0xed, 0x04, 0x94, 0x5c, 0x81, 0x51, 0x06, 0x91, 0xac, 0xfa, 0xf9, 0x13, 0x3f, 0x0d, 0xc4, + 0x38, 0x6d, 0xfa, 0x0d, 0xaa, 0x71, 0x1a, 0xe0, 0x9c, 0x4c, 0x28, 0xe3, 0xc4, 0x20, 0x92, 0xd3, + 0x20, 0xe7, 0xa4, 0x81, 0xc8, 0x6b, 0x30, 0x5e, 0x69, 0xb5, 0x34, 0x46, 0x98, 0xe3, 0xca, 0x36, + 0x81, 0xe4, 0x32, 0x40, 0xa5, 0xd5, 0x92, 0x6c, 0x30, 0x7f, 0x95, 0xad, 0x41, 0xc8, 0xcd, 0x38, + 0x5c, 0x99, 0xc6, 0x0a, 0xaf, 0x13, 0xec, 0x8c, 0x12, 0x26, 0x57, 0x15, 0xdb, 0x49, 0x30, 0x05, + 0x2e, 0xd7, 0x04, 0x98, 0x7c, 0x0c, 0x17, 0x12, 0x7e, 0x17, 0x5a, 0x05, 0x68, 0xea, 0xb7, 0xf3, + 0x11, 0xc8, 0x7b, 0x70, 0x3e, 0x51, 0x28, 0xab, 0x43, 0xab, 0xbe, 0x9d, 0x53, 0x4a, 0x3e, 0x84, + 0x52, 0xe2, 0xd9, 0x76, 0x5c, 0x29, 0x5a, 0xf0, 0xed, 0xdc, 0x72, 0xf6, 0x75, 0x25, 0xde, 0x7f, + 0x89, 0x2a, 0xf1, 0xb2, 0xd2, 0xce, 0x2e, 0x24, 0xab, 0x50, 0xce, 0xf4, 0x65, 0xd1, 0x2a, 0xc6, + 0xbc, 0x5c, 0x76, 0x37, 0x34, 0xb2, 0x08, 0xf3, 0x99, 0x28, 0xb2, 0x19, 0x98, 0xad, 0xcb, 0xee, + 0x88, 0x43, 0x16, 0x60, 0x3a, 0xf6, 0xe9, 0xd1, 0x9a, 0x80, 0x89, 0xba, 0xec, 0xcc, 0x32, 0xf2, + 0xb6, 0xf9, 0x38, 0x9f, 0x57, 0x86, 0x79, 0xba, 0xec, 0x74, 0x81, 0x75, 0x52, 0x80, 0xf9, 0xcc, + 0x8d, 0x52, 0xea, 0xf3, 0x73, 0x49, 0xc5, 0x51, 0x5b, 0x0b, 0x6e, 0x40, 0x3f, 0x2a, 0xf8, 0xdc, + 0x56, 0x2c, 0x7d, 0x4d, 0x91, 0x9e, 0xb3, 0x62, 0xa5, 0x36, 0xe2, 0x90, 0xfb, 0xea, 0x6e, 0xb0, + 0x0f, 0x2d, 0x19, 0xb7, 0x92, 0x0a, 0x54, 0x46, 0xe5, 0xfa, 0x1d, 0xa1, 0xbc, 0x0d, 0x7c, 0x99, + 0x6b, 0x98, 0xbf, 0x2c, 0x40, 0xb9, 0x8b, 0x7e, 0xa0, 0xfa, 0x54, 0x38, 0x45, 0x9f, 0x1e, 0xa8, + 0x3e, 0xf1, 0xb7, 0xb1, 0x0b, 0xa7, 0xd3, 0x41, 0x5e, 0x75, 0xb7, 0xda, 0x40, 0xd2, 0x6a, 0x28, + 0xf9, 0x2e, 0x8c, 0x54, 0xab, 0xab, 0x86, 0x43, 0x5f, 0xea, 0x72, 0x28, 0xc6, 0x20, 0xb7, 0x4f, + 0xe5, 0xc1, 0xa7, 0xf9, 0xef, 0x59, 0xcb, 0x50, 0xca, 0xd3, 0x20, 0x71, 0x61, 0xe1, 0xb1, 0xb5, + 0xb4, 0x8b, 0x25, 0xbe, 0xb0, 0x98, 0x60, 0xeb, 0x3d, 0x38, 0xaf, 0xa8, 0x79, 0xd2, 0x0e, 0xed, + 0xe1, 0xbf, 0x38, 0x76, 0xaa, 0x00, 0x03, 0x31, 0xc0, 0xfa, 0x8b, 0xfe, 0x14, 0x61, 0xb5, 0x7d, + 0x74, 0xe4, 0x04, 0xcf, 0x49, 0xc5, 0x24, 0xec, 0xeb, 0xaa, 0xe9, 0x2f, 0xf6, 0xff, 0xec, 0xb8, + 0xdc, 0xa3, 0x71, 0x67, 0xcb, 0x31, 0x6e, 0xec, 0x5e, 0x9d, 0xf2, 0x2b, 0xa9, 0x5e, 0x1e, 0xdc, + 0xc8, 0x00, 0x92, 0x3d, 0x18, 0x17, 0x5b, 0x26, 0xfe, 0x96, 0x53, 0xfb, 0x76, 0x72, 0x6a, 0x1b, + 0xcd, 0xbb, 0x69, 0x90, 0xf0, 0x49, 0x60, 0xb2, 0x21, 0x5f, 0xc0, 0x84, 0x54, 0x90, 0x04, 0x63, + 0xee, 0x44, 0x74, 0xa7, 0x33, 0x63, 0x93, 0x86, 0x73, 0x4e, 0x30, 0x62, 0x4d, 0x96, 0x6b, 0x0c, + 0xe7, 0x3c, 0x70, 0x9a, 0x26, 0x1b, 0x24, 0xa2, 0xc9, 0x06, 0x6c, 0xee, 0x07, 0x40, 0xd2, 0xfd, + 0xea, 0x36, 0x8b, 0xc7, 0xb5, 0x59, 0x3c, 0x57, 0x81, 0xa9, 0x8c, 0x0e, 0x9c, 0x89, 0xc5, 0x0f, + 0x80, 0xa4, 0x5b, 0x7a, 0x16, 0x0e, 0xd6, 0x75, 0x78, 0x43, 0x89, 0x40, 0xcd, 0x06, 0x83, 0xa7, + 0x34, 0x3c, 0xff, 0x66, 0x2f, 0x94, 0xbb, 0xa0, 0x92, 0x3f, 0x28, 0x24, 0xa5, 0xcd, 0x67, 0xe3, + 0x07, 0x49, 0x69, 0x67, 0xd3, 0x67, 0x88, 0x7d, 0xf1, 0xc3, 0x9f, 0xfe, 0xf5, 0x0b, 0x2b, 0xfc, + 0xe9, 0x21, 0x3b, 0xbb, 0xb4, 0xfa, 0x75, 0x69, 0xd9, 0x30, 0x6d, 0x1c, 0x95, 0x4e, 0xb3, 0x67, + 0x5c, 0x06, 0x10, 0x29, 0x3e, 0xd7, 0xfd, 0x03, 0xa1, 0x9e, 0x69, 0x10, 0xeb, 0x1e, 0xcc, 0x24, + 0x78, 0x0a, 0x63, 0xf8, 0x77, 0x41, 0x3d, 0xf0, 0x46, 0xa6, 0x7d, 0x8b, 0xe7, 0x7e, 0x71, 0x5c, + 0x1e, 0x67, 0x9a, 0xf4, 0xcd, 0x38, 0x7e, 0xbc, 0xfc, 0xcb, 0xda, 0xd0, 0xcd, 0xf9, 0x95, 0xa6, + 0x1e, 0xf8, 0x86, 0xdc, 0x81, 0x41, 0x0e, 0x49, 0x44, 0x69, 0xd6, 0xb1, 0xc5, 0x9a, 0x20, 0x10, + 0xad, 0x19, 0x7c, 0x8e, 0x8a, 0x3f, 0x2a, 0x71, 0xf8, 0x04, 0x6b, 0x97, 0x67, 0x2d, 0x89, 0xc1, + 0x2a, 0x12, 0x74, 0x7f, 0x25, 0x0e, 0xf3, 0x20, 0x7d, 0x2f, 0x24, 0x9e, 0xe7, 0x3f, 0x6b, 0xd2, + 0x06, 0xcf, 0x08, 0xb7, 0x38, 0x26, 0x7c, 0x2f, 0xfa, 0x1d, 0xc6, 0x00, 0xc9, 0xac, 0x4f, 0x61, + 0x86, 0x6d, 0xd0, 0x41, 0xb2, 0x3e, 0xcc, 0x55, 0xc0, 0x60, 0xa6, 0x43, 0xbb, 0xc3, 0x40, 0xe8, + 0xd0, 0x2e, 0x0a, 0xad, 0x75, 0xb8, 0xc0, 0x8d, 0x81, 0x7a, 0x97, 0x62, 0xd3, 0xfb, 0x00, 0xfe, + 0x4e, 0x3c, 0x66, 0xcc, 0xe8, 0x3d, 0xc7, 0xb3, 0x3e, 0xc1, 0xd7, 0x32, 0x62, 0x92, 0xba, 0xbe, + 0x17, 0x5b, 0xfe, 0x4e, 0xf7, 0xbc, 0xf6, 0xff, 0x86, 0xf9, 0x4a, 0xab, 0x45, 0xbd, 0x46, 0x4c, + 0xb8, 0x13, 0x38, 0xa7, 0x0c, 0x7e, 0x40, 0x2a, 0x30, 0x80, 0xd8, 0xea, 0xde, 0x52, 0x34, 0x37, + 0xa3, 0x39, 0x88, 0x27, 0xc2, 0x76, 0x62, 0x05, 0x9c, 0xd2, 0x6a, 0xc0, 0x6c, 0xb5, 0xbd, 0x7f, + 0xe4, 0x46, 0xe8, 0x06, 0x8f, 0x01, 0x44, 0x64, 0xdd, 0x6b, 0x32, 0xd1, 0x14, 0x17, 0xc6, 0xf5, + 0xf8, 0x55, 0x05, 0x7a, 0xd2, 0x8b, 0xa0, 0x22, 0x4f, 0xef, 0xdc, 0x8c, 0x49, 0xd1, 0xea, 0xc1, + 0x6b, 0xc1, 0x62, 0x91, 0x8c, 0xca, 0x9a, 0x82, 0x73, 0xfa, 0x1d, 0x10, 0x9f, 0x21, 0x33, 0x30, + 0x65, 0xde, 0xed, 0x70, 0xf0, 0xd7, 0x30, 0xcd, 0x6d, 0xcf, 0x3c, 0xec, 0xf6, 0x42, 0x1c, 0x61, + 0xba, 0x77, 0x6f, 0x21, 0xe1, 0x7f, 0x8f, 0x6e, 0xb9, 0x2a, 0xa1, 0xc2, 0xde, 0x02, 0x7f, 0xf1, + 0xf8, 0x74, 0xc1, 0xb8, 0x41, 0xec, 0xdd, 0x5b, 0x58, 0x1c, 0x12, 0xe1, 0x4b, 0x19, 0x77, 0x3e, + 0xfc, 0xdf, 0x0a, 0xf7, 0x05, 0x7c, 0x64, 0xbf, 0x4a, 0x1d, 0x7c, 0x10, 0x93, 0xfd, 0x54, 0x79, + 0x02, 0x7a, 0xdd, 0x86, 0x3c, 0xad, 0xbb, 0x0d, 0xeb, 0x4f, 0x0b, 0x70, 0x9d, 0xeb, 0x40, 0xd9, + 0x74, 0x78, 0xd1, 0x93, 0x43, 0x4c, 0xde, 0x07, 0x9e, 0xb5, 0x5d, 0x28, 0x9a, 0x96, 0x68, 0x79, + 0x27, 0x4e, 0x9c, 0x80, 0x54, 0x60, 0x4c, 0x7f, 0x52, 0x72, 0xba, 0xf0, 0x70, 0xf6, 0xe8, 0xd1, + 0x63, 0x47, 0x3d, 0x33, 0x79, 0x02, 0x17, 0x57, 0xbe, 0x61, 0x13, 0x42, 0xec, 0x4e, 0x42, 0x61, + 0x8f, 0x9f, 0xc2, 0x4e, 0xee, 0x88, 0x19, 0x63, 0x9e, 0xa6, 0x93, 0x60, 0x76, 0x34, 0x95, 0x1b, + 0x9c, 0xd2, 0x9a, 0x47, 0x6c, 0x03, 0x66, 0xfd, 0x45, 0x01, 0xe6, 0xb3, 0x6b, 0x13, 0x0b, 0xcb, + 0x1a, 0x9c, 0x5b, 0x72, 0x3c, 0xdf, 0x73, 0xeb, 0x4e, 0xb3, 0x5a, 0x3f, 0xa4, 0x8d, 0xb6, 0x0a, + 0x72, 0xaa, 0x56, 0x99, 0x03, 0xea, 0x49, 0x72, 0x89, 0x62, 0xa7, 0xa9, 0xd8, 0xa1, 0x0c, 0x5f, + 0x25, 0xf0, 0xb5, 0xb7, 0x49, 0x03, 0xc5, 0x8f, 0xb7, 0x2c, 0xa7, 0x94, 0xdc, 0x96, 0x46, 0xf6, + 0xc6, 0xae, 0xe7, 0x46, 0x8a, 0x88, 0x5b, 0x57, 0xb2, 0x8a, 0xac, 0x7f, 0x57, 0x80, 0x0b, 0x98, + 0xd7, 0xc8, 0xc8, 0x94, 0x18, 0xc7, 0xfa, 0x95, 0xe1, 0x6a, 0x0b, 0xc6, 0x2b, 0x0b, 0x03, 0xdb, + 0x8c, 0x5b, 0x4b, 0xde, 0x86, 0xfe, 0xaa, 0x74, 0x92, 0x9a, 0x48, 0xa4, 0xa1, 0x95, 0x29, 0xff, + 0xfd, 0x20, 0xb2, 0x11, 0x8b, 0xed, 0x39, 0xcb, 0x34, 0xac, 0x53, 0x0f, 0xf3, 0x05, 0xf3, 0xc3, + 0xbe, 0x06, 0x89, 0x43, 0x15, 0xf5, 0xe7, 0x85, 0x2a, 0x1a, 0x30, 0x43, 0x15, 0x59, 0x4f, 0x79, + 0x56, 0xa3, 0x64, 0x87, 0xc4, 0x20, 0x7d, 0x92, 0x4a, 0x2f, 0xcc, 0xf7, 0x81, 0xf3, 0x59, 0x3d, + 0xdb, 0xbb, 0x9b, 0xca, 0x1c, 0x9c, 0x1f, 0x5b, 0x77, 0x1b, 0x5e, 0x33, 0x70, 0x2b, 0xcd, 0xa6, + 0xff, 0x8c, 0x36, 0xb6, 0x03, 0xff, 0xc8, 0x8f, 0x8c, 0xac, 0x2e, 0x22, 0xbf, 0x76, 0x7c, 0x8d, + 0x22, 0x66, 0x65, 0x02, 0x6c, 0xfd, 0x5f, 0xf0, 0x7a, 0x17, 0x8e, 0xa2, 0x53, 0x55, 0x38, 0xe7, + 0x24, 0xca, 0xa4, 0xb7, 0xcb, 0xeb, 0x59, 0xfd, 0x4a, 0x32, 0x0a, 0xed, 0x34, 0xfd, 0x8d, 0x1d, + 0x23, 0x25, 0x2f, 0x29, 0xc1, 0xf4, 0xb6, 0xbd, 0xb5, 0xbc, 0xbb, 0xb4, 0x53, 0xdb, 0xf9, 0x62, + 0x7b, 0xa5, 0xb6, 0xbb, 0xf9, 0x70, 0x73, 0xeb, 0xd1, 0x26, 0x0f, 0x4e, 0x6d, 0x94, 0xec, 0xac, + 0x54, 0x36, 0x8a, 0x05, 0x32, 0x0d, 0x45, 0x03, 0xbc, 0xb2, 0xbb, 0x58, 0xec, 0xbd, 0xf1, 0xb5, + 0x91, 0x6a, 0x96, 0xcc, 0x43, 0xa9, 0xba, 0xbb, 0xbd, 0xbd, 0x65, 0x2b, 0xae, 0x7a, 0x68, 0xec, + 0x19, 0x38, 0x67, 0x94, 0xde, 0xb3, 0x57, 0x56, 0x8a, 0x05, 0xd6, 0x14, 0x03, 0xbc, 0x6d, 0xaf, + 0x6c, 0xac, 0xed, 0x6e, 0x14, 0x7b, 0x6f, 0xd4, 0xf4, 0xa7, 0x5d, 0xe4, 0x22, 0xcc, 0x2e, 0xaf, + 0xec, 0xad, 0x2d, 0xad, 0x64, 0xf1, 0x9e, 0x86, 0xa2, 0x5e, 0xb8, 0xb3, 0xb5, 0xb3, 0xcd, 0x59, + 0xeb, 0xd0, 0x47, 0x2b, 0x8b, 0x95, 0xdd, 0x9d, 0xd5, 0xcd, 0x62, 0x9f, 0xd5, 0x3f, 0xdc, 0x5b, + 0xec, 0xbd, 0xf1, 0x23, 0xe3, 0xdd, 0x17, 0x6b, 0xbe, 0x40, 0xdf, 0xad, 0x56, 0xee, 0xe7, 0x57, + 0xc1, 0x4b, 0x37, 0xee, 0x55, 0x8a, 0x05, 0x72, 0x09, 0x2e, 0x18, 0xd0, 0xed, 0x4a, 0xb5, 0xfa, + 0x68, 0xcb, 0x5e, 0x5e, 0x5f, 0xa9, 0x56, 0x8b, 0xbd, 0x37, 0xf6, 0x8c, 0xf0, 0x6c, 0xac, 0x86, + 0x8d, 0x7b, 0x95, 0x9a, 0xbd, 0xf2, 0xd9, 0xee, 0x9a, 0xbd, 0xb2, 0x9c, 0xae, 0xc1, 0x28, 0xfd, + 0x62, 0xa5, 0x5a, 0x2c, 0x90, 0x29, 0x98, 0x34, 0xa0, 0x9b, 0x5b, 0xc5, 0xde, 0x1b, 0x6f, 0x88, + 0x08, 0x5e, 0x64, 0x02, 0x60, 0x79, 0xa5, 0xba, 0xb4, 0xb2, 0xb9, 0xbc, 0xb6, 0x79, 0xbf, 0xd8, + 0x43, 0xc6, 0x61, 0xa4, 0xa2, 0x7e, 0x16, 0x6e, 0x7c, 0x08, 0x93, 0x89, 0x13, 0x35, 0xc3, 0x50, + 0x87, 0xd1, 0x62, 0x0f, 0x8a, 0x5f, 0xfe, 0x44, 0xb3, 0x26, 0x3f, 0x1c, 0x17, 0x0b, 0x37, 0x16, + 0x65, 0xea, 0x53, 0xed, 0x3b, 0x27, 0xa3, 0x30, 0xb4, 0xbc, 0x72, 0xaf, 0xb2, 0xbb, 0xbe, 0x53, + 0xec, 0x61, 0x3f, 0x96, 0xec, 0x95, 0xca, 0xce, 0xca, 0x72, 0xb1, 0x40, 0x46, 0x60, 0xa0, 0xba, + 0x53, 0xd9, 0x59, 0x29, 0xf6, 0x92, 0x61, 0xe8, 0xdf, 0xad, 0xae, 0xd8, 0xc5, 0xbe, 0x85, 0x3f, + 0xfa, 0x83, 0x02, 0xb7, 0xed, 0xc9, 0x37, 0x44, 0x5f, 0x6b, 0x87, 0x49, 0xb1, 0xe4, 0x89, 0x3c, + 0x8f, 0xb9, 0x27, 0x47, 0xd4, 0x02, 0xe6, 0x3a, 0x5c, 0x76, 0x20, 0xc2, 0xf5, 0xc2, 0xed, 0x02, + 0xb1, 0xd1, 0x39, 0x24, 0x71, 0xb6, 0x52, 0x9c, 0xb3, 0x8f, 0xbf, 0x73, 0x97, 0x3a, 0x1e, 0xc9, + 0xc8, 0xaf, 0x81, 0xa5, 0xf3, 0xcc, 0x39, 0x81, 0x7c, 0xf7, 0x74, 0x27, 0x0d, 0x59, 0xe7, 0x1b, + 0xa7, 0x43, 0x27, 0x0f, 0x60, 0x9c, 0xe9, 0xe6, 0x0a, 0x8d, 0x5c, 0x4c, 0x12, 0x6a, 0xc7, 0x81, + 0xb9, 0xf9, 0xec, 0x42, 0x95, 0x8a, 0x65, 0x0c, 0x3b, 0xc2, 0x0f, 0xd6, 0x21, 0x91, 0x51, 0x1e, + 0x24, 0x84, 0xaf, 0xf8, 0x73, 0xe7, 0x12, 0xe0, 0xbd, 0x3b, 0xb7, 0x0b, 0xa4, 0x8a, 0x21, 0xd6, + 0x0c, 0x25, 0x9f, 0xc8, 0x47, 0x6d, 0x69, 0xed, 0x9f, 0xb7, 0xa6, 0xac, 0x12, 0x27, 0xe6, 0x9c, + 0x0e, 0x36, 0x81, 0xa4, 0x75, 0x67, 0x72, 0x25, 0x9e, 0x07, 0xd9, 0x6a, 0xf5, 0xdc, 0xf9, 0x94, + 0xcf, 0xdf, 0x0a, 0xd3, 0x9e, 0xc8, 0x0a, 0x4c, 0x88, 0x27, 0xdc, 0x42, 0x9b, 0x27, 0x9d, 0xce, + 0x03, 0xb9, 0x6c, 0xee, 0xa3, 0x9c, 0xd4, 0x89, 0x80, 0xcc, 0xc5, 0xfd, 0x48, 0x1e, 0x13, 0xe6, + 0x2e, 0x66, 0x96, 0x89, 0xfe, 0xdd, 0x83, 0x09, 0xf3, 0x70, 0x41, 0xe4, 0x00, 0x65, 0x9e, 0x39, + 0x72, 0x1b, 0x54, 0x83, 0xd9, 0x0d, 0xc7, 0xc5, 0x2b, 0x0a, 0xe1, 0x59, 0x26, 0xfd, 0xc2, 0x48, + 0xb9, 0x83, 0xa3, 0x58, 0x95, 0x7a, 0x0d, 0x35, 0x08, 0x79, 0x61, 0xd5, 0xf1, 0xb3, 0xa9, 0x4a, + 0x1d, 0xd9, 0xf4, 0xab, 0x23, 0x96, 0x99, 0x0c, 0x37, 0xcb, 0x55, 0x72, 0x2e, 0xcf, 0xbb, 0x97, + 0x6c, 0xa0, 0x92, 0x9e, 0xe0, 0xa8, 0xcd, 0x89, 0x33, 0xb3, 0x2b, 0x61, 0x20, 0x01, 0x2d, 0x89, + 0xb8, 0x28, 0x0c, 0x49, 0x8e, 0xe0, 0x72, 0x99, 0xdd, 0x2e, 0x90, 0xaf, 0xf1, 0xab, 0xce, 0x64, + 0xf7, 0xc8, 0x8d, 0x0e, 0x85, 0xf6, 0x73, 0x31, 0x93, 0x81, 0xf8, 0x50, 0x3a, 0x70, 0xb7, 0x61, + 0x3a, 0xcb, 0xa1, 0x58, 0x09, 0xb4, 0x83, 0xb7, 0x71, 0xee, 0x2c, 0xb0, 0xd9, 0x51, 0xa3, 0x91, + 0x3f, 0x48, 0x1d, 0xfc, 0x59, 0x73, 0x79, 0x7e, 0x0c, 0x13, 0x6c, 0x96, 0x3c, 0xa4, 0xb4, 0x55, + 0x69, 0xba, 0x4f, 0x69, 0x48, 0x64, 0x7c, 0x5c, 0x05, 0xca, 0xa3, 0xbd, 0x5e, 0x20, 0xdf, 0x81, + 0xd1, 0x47, 0x4e, 0x54, 0x3f, 0x14, 0x71, 0x22, 0x65, 0x18, 0x49, 0x84, 0xcd, 0xc9, 0x5f, 0x58, + 0x78, 0xbb, 0x40, 0xbe, 0x0f, 0x43, 0xf7, 0x69, 0x84, 0x8f, 0x8a, 0xaf, 0x2a, 0xdf, 0x3a, 0x6e, + 0x9b, 0x5c, 0xf3, 0xd4, 0xcb, 0x19, 0xd9, 0xe0, 0xa4, 0x01, 0x95, 0xdc, 0x02, 0xe0, 0x0b, 0x02, + 0x72, 0x48, 0x16, 0xcf, 0xa5, 0x9a, 0x4d, 0xee, 0x33, 0xe5, 0xa1, 0x49, 0x23, 0x7a, 0xda, 0x2a, + 0xf3, 0x64, 0xb4, 0x0e, 0x13, 0x2a, 0x7b, 0xcd, 0x26, 0x86, 0xf3, 0xb0, 0x12, 0xcc, 0xc2, 0x33, + 0x70, 0xfb, 0x90, 0x7d, 0x15, 0x3c, 0x75, 0x2b, 0xc6, 0x7d, 0xc0, 0x95, 0x74, 0x56, 0x0f, 0x1e, + 0xa1, 0x2f, 0xa1, 0x52, 0x88, 0x1c, 0x4d, 0xa3, 0x5d, 0xf5, 0xc3, 0xc8, 0xa4, 0x55, 0x90, 0x6c, + 0xda, 0x5f, 0x85, 0x39, 0xbd, 0x5e, 0x33, 0x50, 0x71, 0xbc, 0xe6, 0xe6, 0xc5, 0x3f, 0x9e, 0xbb, + 0xda, 0x01, 0x43, 0x9c, 0xdf, 0xfa, 0x7e, 0xbb, 0xb7, 0x80, 0xcb, 0xc9, 0x32, 0x4c, 0xc9, 0xba, + 0xb6, 0x5a, 0xd4, 0xab, 0x56, 0x57, 0x31, 0x53, 0x89, 0xf4, 0xe4, 0xd0, 0x60, 0x92, 0x3b, 0x49, + 0x17, 0xb1, 0xad, 0xcf, 0x88, 0xef, 0x40, 0x3a, 0x45, 0x7d, 0x88, 0xb7, 0xbe, 0xcc, 0x08, 0xba, + 0x0f, 0xb9, 0x51, 0xc9, 0x50, 0xfe, 0xf7, 0x16, 0x48, 0x87, 0x03, 0xd0, 0x5c, 0xce, 0x11, 0xe2, + 0x76, 0x81, 0x7c, 0x01, 0x24, 0x7d, 0x24, 0x51, 0x22, 0xcc, 0x3d, 0x7e, 0x29, 0x11, 0x76, 0x38, + 0xcf, 0xac, 0xc0, 0x94, 0x8a, 0xee, 0x12, 0x97, 0x93, 0x9c, 0xb6, 0x74, 0xd8, 0xc1, 0x66, 0x32, + 0xd8, 0xec, 0x2d, 0x74, 0x60, 0x94, 0x09, 0x27, 0x9f, 0xc2, 0x94, 0x98, 0xfb, 0x46, 0x7b, 0x8a, + 0x6a, 0x19, 0x13, 0x87, 0x9b, 0xdc, 0x96, 0x3c, 0x80, 0x99, 0x6a, 0x42, 0xf0, 0xdc, 0x8f, 0xfd, + 0x82, 0xc9, 0x02, 0x81, 0x55, 0x1a, 0x71, 0xc9, 0x67, 0xf3, 0x7a, 0x08, 0x84, 0xdb, 0x96, 0x24, + 0xbb, 0xa7, 0x2e, 0x7d, 0x46, 0x2e, 0x25, 0x9a, 0xce, 0x80, 0x88, 0x86, 0xeb, 0x60, 0x6e, 0xcf, + 0x76, 0x78, 0xfe, 0x62, 0x84, 0x1a, 0x37, 0xe0, 0x57, 0x0c, 0x02, 0xe3, 0x12, 0x5d, 0x8c, 0xe3, + 0x85, 0x5c, 0x0c, 0xf2, 0x1b, 0x18, 0x9d, 0xb5, 0xf3, 0xe9, 0x8c, 0x7c, 0x27, 0xeb, 0x10, 0x9d, + 0x73, 0xbe, 0x9c, 0x7b, 0xfb, 0x74, 0xc8, 0xea, 0x3c, 0x3c, 0x7e, 0x9f, 0x46, 0xdb, 0xcd, 0xf6, + 0x81, 0x8b, 0x99, 0x2d, 0x89, 0xb2, 0x3d, 0x29, 0x90, 0x98, 0xde, 0x32, 0x28, 0x5a, 0x5c, 0x50, + 0xa5, 0x3f, 0x26, 0x6b, 0x50, 0xe4, 0xdb, 0x88, 0xc6, 0xe2, 0x52, 0x8a, 0x85, 0x40, 0x71, 0x02, + 0xe7, 0x28, 0xcc, 0x1d, 0xad, 0x5b, 0xdc, 0xe5, 0x88, 0xc8, 0x4f, 0x5b, 0xd7, 0x53, 0xa7, 0x0c, + 0x98, 0x8a, 0x58, 0xcf, 0x46, 0xc4, 0xa6, 0x21, 0x8d, 0x64, 0x18, 0x18, 0x9e, 0xd7, 0xf4, 0x5a, + 0xac, 0x33, 0xa4, 0x4b, 0xe3, 0x15, 0x24, 0x11, 0xb2, 0x6c, 0xef, 0x2e, 0x51, 0xb9, 0x5e, 0x33, + 0x98, 0xbe, 0x61, 0xa8, 0x36, 0x67, 0xe3, 0xfb, 0x0e, 0x6e, 0x65, 0x18, 0xfa, 0x66, 0x26, 0x6e, + 0x1b, 0xfb, 0x2d, 0xa9, 0xc6, 0x35, 0xaa, 0xbd, 0x05, 0x5c, 0x19, 0xd9, 0x5e, 0xcb, 0x34, 0xe1, + 0x76, 0x10, 0x50, 0x8f, 0x13, 0xe7, 0xa9, 0x2d, 0x59, 0xd4, 0x9f, 0xe0, 0x0a, 0xa6, 0x51, 0xf3, + 0xe7, 0x76, 0xdd, 0x58, 0xf0, 0x3c, 0x3c, 0xb7, 0x0b, 0xe4, 0x7d, 0x18, 0x16, 0x6d, 0x64, 0x44, + 0x46, 0xa3, 0xc3, 0x0e, 0xad, 0x46, 0x4a, 0xe0, 0x42, 0xc2, 0x36, 0x9b, 0x38, 0x79, 0xa3, 0xcf, + 0xdb, 0xfc, 0x3e, 0xdb, 0xb3, 0x1b, 0x2f, 0x42, 0xb9, 0x24, 0x37, 0x6f, 0xa4, 0x2c, 0xa9, 0x48, + 0x2c, 0x12, 0xd4, 0x65, 0x97, 0xe5, 0x4c, 0x98, 0xfa, 0x8d, 0x31, 0x07, 0x55, 0xe8, 0x30, 0xa5, + 0x7e, 0x1b, 0xe0, 0x6e, 0x5b, 0xf6, 0x1a, 0x14, 0x2b, 0x75, 0xdc, 0x50, 0xaa, 0xf4, 0xc8, 0x69, + 0x1d, 0xfa, 0x01, 0x55, 0x67, 0x9f, 0x64, 0x81, 0xe4, 0x35, 0xa3, 0x14, 0x14, 0x51, 0xb0, 0x4e, + 0x1d, 0x0c, 0xcc, 0x3c, 0xab, 0x34, 0x94, 0x44, 0x51, 0x36, 0x45, 0x87, 0xb3, 0xce, 0xf4, 0x12, + 0x3b, 0x9d, 0x35, 0x5f, 0x8e, 0xcd, 0x87, 0xb8, 0x60, 0x28, 0xe4, 0x50, 0xed, 0x10, 0x0a, 0xa4, + 0x4e, 0x85, 0xf2, 0xe5, 0x8d, 0x42, 0xad, 0xc8, 0xab, 0xe7, 0x58, 0x2c, 0x79, 0xd4, 0x79, 0xd5, + 0x7f, 0x0f, 0x26, 0x56, 0xd8, 0x82, 0xde, 0x6e, 0xb8, 0x3c, 0x18, 0x3d, 0x31, 0xa3, 0x8b, 0xe7, + 0x12, 0xae, 0xca, 0xd4, 0x57, 0x48, 0x2a, 0x2c, 0x08, 0x72, 0x4f, 0xd1, 0x60, 0x72, 0x3c, 0xa6, + 0x25, 0x5b, 0x91, 0x0f, 0x00, 0x4f, 0xf8, 0xc2, 0x64, 0x30, 0xcb, 0x15, 0xcb, 0x4a, 0xab, 0xd5, + 0x94, 0x96, 0x6d, 0x7e, 0x53, 0xff, 0xba, 0x71, 0x12, 0x4d, 0x95, 0x4b, 0xde, 0x69, 0xdd, 0xf3, + 0x73, 0x2d, 0x15, 0x6d, 0x0e, 0xcf, 0x9c, 0xf2, 0x6e, 0x73, 0x51, 0x85, 0x8f, 0xae, 0x34, 0x9b, + 0x29, 0xe2, 0x90, 0xbc, 0x65, 0x72, 0xcf, 0xc2, 0xe9, 0x56, 0x03, 0x9e, 0xf4, 0xb9, 0xf2, 0x56, + 0x69, 0xb5, 0xf8, 0x62, 0x79, 0x59, 0x2d, 0x18, 0x66, 0x41, 0xfa, 0xa4, 0x9f, 0x2c, 0x17, 0x6b, + 0xfb, 0x03, 0x9c, 0x66, 0x71, 0xbe, 0x5a, 0xa2, 0x9f, 0x9b, 0x93, 0xe9, 0x7a, 0x95, 0x2e, 0x97, + 0x28, 0x54, 0xfb, 0xc4, 0x64, 0x22, 0x75, 0xbf, 0x32, 0xf0, 0xa4, 0x52, 0xfa, 0x73, 0x7e, 0x97, + 0xf3, 0x8a, 0x95, 0xc1, 0xb5, 0x98, 0xcc, 0x09, 0xae, 0xba, 0x9c, 0x93, 0x6b, 0x5e, 0x75, 0x39, + 0x37, 0x99, 0xf8, 0x03, 0x28, 0x26, 0xd3, 0x11, 0x2b, 0xa6, 0x39, 0x79, 0x8a, 0x73, 0xc7, 0xe4, + 0x1e, 0x4c, 0xeb, 0x23, 0xaa, 0xfa, 0x9d, 0xb7, 0xfa, 0xe7, 0xf1, 0xd9, 0x81, 0x99, 0xcc, 0xec, + 0xc1, 0x6a, 0x8b, 0xed, 0x94, 0x5b, 0x38, 0x97, 0x2b, 0x85, 0xf3, 0xd9, 0x09, 0xc4, 0xc9, 0x6b, + 0xa6, 0xfd, 0x20, 0x3b, 0x9d, 0xf2, 0xdc, 0xeb, 0x5d, 0xb0, 0x84, 0x40, 0xbf, 0xc6, 0x1d, 0x30, + 0x55, 0xc7, 0x55, 0xcd, 0xa2, 0x90, 0x53, 0x81, 0xd5, 0x09, 0x45, 0xcd, 0x81, 0xe9, 0x8c, 0xe2, + 0x7c, 0x11, 0x5f, 0xcb, 0xe7, 0x19, 0x4f, 0xac, 0x3d, 0x19, 0x25, 0x39, 0x57, 0x32, 0x1d, 0x13, + 0x4d, 0x77, 0x38, 0x92, 0xce, 0xa9, 0xf9, 0x70, 0xfa, 0x26, 0xe7, 0x9b, 0x97, 0xa6, 0xb3, 0xd2, + 0x9b, 0x27, 0xad, 0x3f, 0x59, 0xd9, 0xab, 0x95, 0x18, 0x3a, 0xe6, 0x47, 0xdf, 0xe3, 0x96, 0x20, + 0x93, 0xbb, 0x6e, 0x09, 0xca, 0x64, 0x7d, 0x25, 0x1f, 0x21, 0x9e, 0x11, 0x46, 0xec, 0x75, 0xd1, + 0x7f, 0xfd, 0x9c, 0x95, 0x9d, 0xd8, 0x5a, 0xcd, 0x88, 0x4c, 0x14, 0xc1, 0xdd, 0x96, 0x1f, 0x5d, + 0x8e, 0x58, 0x3a, 0x24, 0xf5, 0xee, 0x70, 0x1c, 0x2a, 0xc5, 0x03, 0x97, 0x68, 0xf6, 0x59, 0x87, + 0xed, 0x6b, 0xb8, 0x90, 0x9b, 0xc0, 0x9b, 0xbc, 0x99, 0xfa, 0xa0, 0x73, 0x24, 0x91, 0xdf, 0xd2, + 0x71, 0x23, 0xf7, 0xb6, 0x32, 0x85, 0x25, 0xd2, 0x7c, 0xa7, 0x56, 0xec, 0x8c, 0x1c, 0xe0, 0xf7, + 0x51, 0xf3, 0xd5, 0xf2, 0x78, 0xe7, 0xf6, 0xf5, 0x52, 0x16, 0x9f, 0x30, 0xbd, 0xa6, 0x6a, 0xed, + 0x92, 0x9a, 0x58, 0xb2, 0xe0, 0x2c, 0x6b, 0xea, 0x69, 0x9a, 0x96, 0xc7, 0x67, 0x19, 0x46, 0xb5, + 0x04, 0xe0, 0xe4, 0x82, 0x21, 0x26, 0x63, 0x97, 0x9c, 0x33, 0x3a, 0x67, 0x6e, 0x90, 0x4b, 0x68, + 0x73, 0x56, 0x69, 0xc4, 0x73, 0x5b, 0x71, 0x31, 0xcd, 0xc3, 0xb0, 0x37, 0x2b, 0x29, 0xf0, 0xd6, + 0xcc, 0x27, 0x85, 0x63, 0x34, 0x28, 0xbf, 0x4b, 0x44, 0x17, 0x4d, 0x97, 0x26, 0xe5, 0x6b, 0xa8, + 0x53, 0x22, 0xcb, 0x28, 0x26, 0x43, 0x91, 0x31, 0xf9, 0xce, 0x2b, 0xe3, 0x99, 0x06, 0xed, 0x60, + 0xcb, 0xd8, 0xc6, 0xa7, 0x1d, 0x19, 0x19, 0xd1, 0xd5, 0x1a, 0xda, 0x31, 0x61, 0x7a, 0x86, 0x76, + 0xa6, 0x56, 0xe5, 0x5c, 0x8e, 0x1d, 0x53, 0xa4, 0xe7, 0xb6, 0xf4, 0x87, 0xda, 0xaa, 0x9c, 0xca, + 0x7b, 0x4e, 0xae, 0x27, 0x55, 0xb3, 0xbc, 0xd4, 0xe8, 0x1d, 0x56, 0xfd, 0xe9, 0xac, 0x94, 0xe9, + 0x9a, 0x01, 0x38, 0x37, 0x9f, 0x7a, 0x86, 0x14, 0xd4, 0xf2, 0x96, 0xc3, 0xad, 0x43, 0x02, 0xf5, + 0xdc, 0x16, 0x7e, 0xa9, 0x2d, 0x6f, 0x89, 0x44, 0xe7, 0xea, 0xc0, 0xdd, 0x25, 0x13, 0x7a, 0x2e, + 0xef, 0x4d, 0x7c, 0x0c, 0x94, 0xce, 0x52, 0xae, 0x74, 0x97, 0x4e, 0x39, 0xcc, 0x33, 0xed, 0xc3, + 0x33, 0xe9, 0x2e, 0x32, 0x7e, 0xe7, 0x13, 0xd6, 0xdd, 0x6e, 0x0d, 0x53, 0xeb, 0x70, 0x46, 0x76, + 0xf3, 0xc4, 0x3a, 0x9c, 0x9f, 0xff, 0xbc, 0xc3, 0x41, 0x67, 0xb2, 0xea, 0x1e, 0x78, 0x5a, 0x72, + 0x72, 0x75, 0xcc, 0x49, 0xe7, 0x4b, 0x57, 0x4b, 0x4c, 0x56, 0x2e, 0xf3, 0x2d, 0xa6, 0xe1, 0x70, + 0xfd, 0x5c, 0x4f, 0x33, 0x4d, 0xe6, 0xf2, 0xb3, 0x6b, 0xab, 0xe5, 0x26, 0x33, 0x2f, 0xb5, 0xc6, + 0x50, 0xcf, 0xf1, 0xac, 0x18, 0x66, 0xa4, 0x9b, 0x56, 0x0c, 0x33, 0x93, 0x42, 0xdf, 0x42, 0xbb, + 0x8a, 0xed, 0x37, 0xa9, 0x6e, 0x57, 0xd1, 0x92, 0x06, 0x27, 0xcc, 0x1a, 0xe4, 0x23, 0x34, 0x6a, + 0x74, 0xb6, 0x84, 0xcc, 0x9a, 0x9c, 0x74, 0xdf, 0x91, 0x11, 0x95, 0x91, 0x59, 0x59, 0xd1, 0x93, + 0x49, 0xa1, 0xe7, 0x4a, 0xe9, 0x02, 0x41, 0xff, 0xae, 0xb4, 0x8b, 0x60, 0x83, 0x4b, 0xa6, 0x3d, + 0x29, 0xbf, 0xcd, 0xef, 0x4a, 0xa3, 0x88, 0x41, 0x96, 0xca, 0xc7, 0x9c, 0x24, 0xfb, 0x1e, 0x8c, + 0xc5, 0xb9, 0x97, 0xf7, 0x16, 0x34, 0xc2, 0x44, 0x42, 0xe6, 0x24, 0xe1, 0xfb, 0xf2, 0xe2, 0x04, + 0xeb, 0x33, 0x0b, 0x3b, 0xdb, 0x4f, 0x3e, 0x91, 0x46, 0x18, 0xa3, 0xa5, 0xa9, 0x4c, 0xce, 0x1d, + 0x56, 0xee, 0x31, 0x3d, 0x61, 0xa4, 0x9a, 0x17, 0x19, 0x29, 0x5f, 0xd5, 0xbc, 0xc8, 0x4a, 0xd9, + 0x1a, 0x5f, 0x2c, 0x7c, 0x21, 0x2d, 0x0e, 0x31, 0xd3, 0x4b, 0x46, 0xb3, 0x52, 0x7c, 0x2f, 0xe7, + 0x15, 0x27, 0x59, 0x57, 0xa1, 0x98, 0xcc, 0x6e, 0xa9, 0x8e, 0x6b, 0x39, 0x69, 0x48, 0xd5, 0x19, + 0x30, 0x37, 0x2d, 0xe6, 0xb6, 0x34, 0x9f, 0x9b, 0x7c, 0xaf, 0x66, 0x37, 0x4a, 0x67, 0xdd, 0x59, + 0x2d, 0x8b, 0x13, 0x5d, 0xea, 0x07, 0xe9, 0x54, 0x22, 0x4d, 0x5d, 0x2d, 0xcb, 0xc8, 0x8d, 0xe9, + 0xca, 0x70, 0x4e, 0xd9, 0xf9, 0xb6, 0xdf, 0x32, 0x4f, 0xb8, 0x1d, 0xa2, 0xa2, 0x77, 0xbd, 0x64, + 0x26, 0xbf, 0x02, 0xb3, 0x39, 0x01, 0xa4, 0xc9, 0xeb, 0x09, 0x43, 0x6c, 0x76, 0x80, 0x69, 0x35, + 0x41, 0x32, 0x33, 0x50, 0x6f, 0xa0, 0x77, 0x82, 0x11, 0xb8, 0x21, 0x75, 0xe3, 0xf7, 0xc8, 0x8d, + 0x0e, 0x79, 0xa2, 0x65, 0x6d, 0xcd, 0xcd, 0x8c, 0xf8, 0x40, 0xaa, 0x78, 0x5e, 0x31, 0xa0, 0x19, + 0x97, 0x7e, 0x19, 0x0c, 0xe7, 0xb2, 0x19, 0xb2, 0xb5, 0x83, 0xcd, 0x85, 0x8c, 0xa8, 0x1a, 0x6a, + 0x2e, 0xe4, 0x47, 0xdc, 0xc8, 0x6d, 0xe6, 0xb6, 0x54, 0xb0, 0xb2, 0x39, 0xe6, 0x07, 0xd8, 0xc8, + 0xe5, 0xf8, 0x80, 0x71, 0x4c, 0xc5, 0xcc, 0x20, 0x39, 0xe8, 0x9d, 0x57, 0x0f, 0x5b, 0xee, 0xd7, + 0x26, 0xd5, 0x82, 0xd6, 0xbe, 0xbc, 0xe8, 0x1c, 0xb9, 0xed, 0x5b, 0x91, 0xdf, 0x53, 0x76, 0xfb, + 0x4e, 0xbb, 0x63, 0xab, 0xeb, 0xb1, 0x44, 0xd8, 0x16, 0xa3, 0xa3, 0x1a, 0x7c, 0x2e, 0x07, 0x4e, + 0x36, 0xd1, 0xdd, 0x28, 0x09, 0xd5, 0x0e, 0xae, 0xd9, 0x71, 0x61, 0x72, 0xf9, 0xf1, 0x79, 0x6c, + 0xc4, 0xd5, 0x38, 0xcb, 0x3c, 0x4e, 0x04, 0xe4, 0x10, 0xf3, 0xd8, 0x80, 0x9e, 0x6d, 0x1e, 0x27, + 0x18, 0x9a, 0xf3, 0x38, 0xd9, 0xcc, 0xa4, 0x21, 0x20, 0x77, 0x54, 0x93, 0xcd, 0x54, 0xf3, 0x38, + 0x9b, 0x63, 0x7e, 0xfc, 0x93, 0x5c, 0x8e, 0x6a, 0x1e, 0x9b, 0x1c, 0x73, 0xd0, 0x4f, 0x39, 0x8f, + 0x93, 0x95, 0x98, 0xf3, 0xf8, 0x4c, 0xed, 0x53, 0xf3, 0x38, 0xbb, 0x7d, 0x67, 0x9e, 0xc7, 0x89, + 0x80, 0x41, 0x46, 0x47, 0xb3, 0xe6, 0x71, 0x12, 0x9f, 0xcf, 0xe3, 0x24, 0x34, 0x61, 0x80, 0xe9, + 0x30, 0x8f, 0x93, 0x94, 0x9f, 0x21, 0xbf, 0x44, 0xb0, 0x93, 0xd3, 0xcc, 0xe4, 0xdc, 0x38, 0x29, + 0xe4, 0x11, 0x5a, 0xff, 0x12, 0xf0, 0xd3, 0xcd, 0xe6, 0xf9, 0x3c, 0xa6, 0x38, 0x9f, 0xf7, 0xa4, + 0x10, 0x93, 0xcd, 0x35, 0x4d, 0x5b, 0xd9, 0xb1, 0x5e, 0x3a, 0x34, 0x78, 0x8f, 0xcd, 0x9b, 0x46, + 0x07, 0xbe, 0x9d, 0x42, 0xd5, 0x74, 0xe0, 0xab, 0xce, 0x41, 0x49, 0xbe, 0xb9, 0x24, 0x9d, 0xe7, + 0xf7, 0xe7, 0xf2, 0xfe, 0x23, 0x49, 0xb7, 0x90, 0x38, 0x59, 0x9d, 0xb9, 0xa5, 0xea, 0x84, 0x95, + 0x6c, 0xe9, 0x59, 0xe7, 0xf9, 0x86, 0xd4, 0x1e, 0x52, 0x31, 0xae, 0x12, 0x9d, 0xd6, 0xe7, 0x7a, + 0x6e, 0x09, 0xd9, 0x41, 0x53, 0x6f, 0x1a, 0xae, 0x99, 0x89, 0xf3, 0x82, 0x69, 0x75, 0xe5, 0x9a, + 0x8a, 0xd6, 0xa3, 0x73, 0xcd, 0x0b, 0xe5, 0xa3, 0xb8, 0xa6, 0xa9, 0x3f, 0x45, 0xd3, 0x99, 0x78, + 0xd3, 0xe5, 0x3d, 0xf6, 0xf3, 0xcf, 0x39, 0x53, 0x86, 0x4b, 0x14, 0xc3, 0x45, 0x4f, 0xb4, 0x8f, + 0xc5, 0x05, 0x9f, 0x04, 0xe6, 0x0a, 0x3f, 0x8b, 0x9e, 0x7c, 0x0a, 0x45, 0xb1, 0xbc, 0xc5, 0x0c, + 0xb2, 0x10, 0x73, 0x87, 0x6e, 0x51, 0x5a, 0xec, 0x4e, 0xd1, 0x82, 0xd3, 0x58, 0xea, 0x4e, 0x23, + 0x89, 0x7c, 0xb3, 0x16, 0xdb, 0x0e, 0x77, 0x82, 0x76, 0x18, 0xd1, 0x46, 0xda, 0x1c, 0x65, 0x36, + 0x46, 0x3a, 0x4e, 0x98, 0xe8, 0x7b, 0x0b, 0x64, 0x0d, 0xd7, 0x36, 0x13, 0xdc, 0xc9, 0x5e, 0x97, + 0xcd, 0x06, 0x97, 0x9e, 0x55, 0xf5, 0x78, 0xc8, 0x6c, 0x53, 0x5e, 0xdd, 0xf9, 0x8d, 0x52, 0x22, + 0x3a, 0x65, 0xef, 0xf2, 0x44, 0xc4, 0x0f, 0xd4, 0xdc, 0x76, 0xd8, 0x4d, 0x32, 0xc9, 0xe7, 0x4c, + 0xe4, 0x07, 0x30, 0x22, 0x89, 0xbb, 0x0b, 0x24, 0x49, 0x8d, 0x02, 0x59, 0x86, 0x71, 0xe3, 0xad, + 0x96, 0x3a, 0xdd, 0x64, 0xbd, 0xe0, 0xea, 0x30, 0xce, 0xe3, 0xc6, 0x9b, 0x2c, 0xc5, 0x25, 0xeb, + 0xa5, 0x56, 0x2e, 0x97, 0xef, 0xc3, 0xa8, 0x10, 0x69, 0x47, 0x69, 0xe4, 0x1b, 0xeb, 0x66, 0x34, + 0xbf, 0xe7, 0x76, 0xc3, 0x8d, 0x96, 0x7c, 0xef, 0xb1, 0x7b, 0xd0, 0x55, 0x30, 0x69, 0x92, 0xbd, + 0x05, 0xf2, 0x15, 0xa6, 0x25, 0x96, 0xc9, 0xa2, 0x69, 0xf4, 0xcc, 0x0f, 0x9e, 0xb8, 0xde, 0x41, + 0x17, 0x96, 0x57, 0x4c, 0x96, 0x49, 0x3a, 0xe9, 0x5a, 0xf2, 0x15, 0xcc, 0x55, 0xf3, 0x99, 0x77, + 0x65, 0xd2, 0x79, 0x7b, 0xa9, 0xc2, 0x3c, 0x3a, 0xd7, 0x9c, 0xb5, 0xed, 0x1d, 0x99, 0x7e, 0xc1, + 0xc3, 0x24, 0x4a, 0x43, 0x7f, 0xdd, 0x0f, 0x1a, 0xdd, 0x39, 0x96, 0x4d, 0x77, 0xdd, 0x04, 0x99, + 0x14, 0xc6, 0x17, 0x70, 0xa1, 0x9a, 0xcb, 0xba, 0x1b, 0x8b, 0x6e, 0x9a, 0xe4, 0x45, 0x14, 0xc5, + 0x19, 0xdb, 0xdd, 0x91, 0xe7, 0x1a, 0xae, 0x69, 0x6c, 0x1f, 0xda, 0x0e, 0xe8, 0x63, 0x1a, 0xa0, + 0x53, 0x78, 0x37, 0x77, 0x68, 0x13, 0x5d, 0xf6, 0x7c, 0x0d, 0xce, 0x55, 0x53, 0xac, 0xf2, 0x48, + 0x3a, 0xb7, 0xea, 0x01, 0x4c, 0x61, 0x4f, 0x4f, 0xd9, 0xae, 0x2e, 0x4e, 0x44, 0xa3, 0xf7, 0x69, + 0xb4, 0xbb, 0xd6, 0x45, 0x4a, 0xf2, 0xd5, 0x82, 0x44, 0xdc, 0xbb, 0xc3, 0x28, 0xab, 0x1a, 0x65, + 0x1a, 0x23, 0xf7, 0xe3, 0xfd, 0x81, 0xbc, 0x48, 0xe9, 0x5a, 0x6d, 0x1e, 0x87, 0xbb, 0xb8, 0x16, + 0x0a, 0xc7, 0x68, 0xcd, 0x04, 0xc9, 0x21, 0xb1, 0xa9, 0x4e, 0xf3, 0x91, 0x0e, 0x49, 0x85, 0x1f, + 0xff, 0xf8, 0xf4, 0x10, 0xb0, 0xcb, 0x29, 0x87, 0xf9, 0x8e, 0x2c, 0xb8, 0x09, 0x75, 0xdd, 0xaf, + 0x3f, 0xd1, 0x4d, 0xa8, 0x5a, 0xe2, 0xfa, 0x39, 0x33, 0xad, 0xbc, 0x58, 0xf1, 0x31, 0xb7, 0xbc, + 0xee, 0x17, 0xa6, 0xa7, 0xae, 0xd7, 0x4d, 0xa8, 0x66, 0x92, 0xfd, 0xbb, 0xd2, 0xb6, 0x88, 0x15, + 0x9a, 0x9c, 0x73, 0x45, 0xa3, 0xcc, 0x8a, 0x48, 0x64, 0x9a, 0x15, 0xf5, 0x86, 0xe6, 0x5f, 0x04, + 0x90, 0x74, 0x96, 0x7d, 0x75, 0x58, 0xc9, 0x4d, 0xc0, 0xdf, 0xc1, 0xbd, 0x6b, 0x4a, 0x38, 0x05, + 0x19, 0x82, 0x57, 0xa1, 0x86, 0xd3, 0x65, 0xb1, 0x28, 0x75, 0x5f, 0xa5, 0xdb, 0x05, 0xb2, 0x09, + 0xe7, 0xef, 0xd3, 0x48, 0xac, 0x71, 0x36, 0x0d, 0xa3, 0xc0, 0xad, 0x47, 0x1d, 0x6f, 0x15, 0xe5, + 0xd9, 0x24, 0x83, 0x66, 0xef, 0x1d, 0xc6, 0xaf, 0x9a, 0xcd, 0xaf, 0x23, 0x5d, 0x07, 0x0f, 0x5a, + 0x71, 0x55, 0x71, 0x96, 0x26, 0xe6, 0x4f, 0xf1, 0x21, 0xee, 0xa0, 0x93, 0x4f, 0x5a, 0x8c, 0xe3, + 0x9a, 0x88, 0xd3, 0xd6, 0x4d, 0x18, 0xe4, 0x44, 0xb9, 0x1b, 0xea, 0x98, 0x4e, 0x43, 0xee, 0xc0, + 0x88, 0xf2, 0xb0, 0x21, 0x46, 0x51, 0x6e, 0xbb, 0xee, 0xc0, 0x08, 0x3f, 0x5a, 0x9d, 0x9e, 0xe4, + 0x23, 0x18, 0x51, 0x2e, 0x39, 0x67, 0xde, 0xe9, 0x3f, 0x85, 0x71, 0xdd, 0x39, 0xe7, 0xec, 0x82, + 0xfc, 0x3e, 0xde, 0xfd, 0xca, 0x2b, 0x96, 0x7c, 0xfa, 0x99, 0x44, 0x2e, 0x2f, 0x21, 0x52, 0xbe, + 0x40, 0x4a, 0x60, 0x6e, 0xf3, 0xcf, 0xa5, 0xa8, 0xc9, 0x47, 0xf2, 0xbd, 0x94, 0x22, 0x4e, 0x23, + 0x75, 0x90, 0xd9, 0x04, 0x17, 0xf3, 0x8b, 0x10, 0xab, 0x05, 0xb6, 0x6b, 0xb3, 0x4f, 0x73, 0x47, + 0xdd, 0x5d, 0x74, 0x79, 0x5c, 0xb6, 0x50, 0x4b, 0x4b, 0x65, 0x99, 0xcb, 0x67, 0x74, 0x39, 0x3f, + 0x31, 0x1d, 0x0e, 0xc6, 0x03, 0x3c, 0x05, 0xa6, 0x4a, 0x73, 0xbb, 0xd7, 0x21, 0xd1, 0x5d, 0x7c, + 0xec, 0x4d, 0xb3, 0xeb, 0x40, 0xd6, 0xe9, 0x14, 0x2d, 0x5e, 0x81, 0xbe, 0x12, 0x76, 0x6b, 0xd2, + 0xc7, 0xf1, 0xf4, 0x9d, 0xcd, 0x6f, 0xd9, 0xc5, 0x8c, 0x5b, 0xf1, 0xae, 0x63, 0x91, 0xc7, 0xee, + 0x57, 0x50, 0x3b, 0xcc, 0x0c, 0xf7, 0x95, 0xcf, 0xec, 0xba, 0xe6, 0x58, 0x91, 0x49, 0xa9, 0x36, + 0xbd, 0x27, 0xf8, 0x10, 0x2d, 0x3b, 0x0f, 0xdf, 0x1b, 0x5d, 0xb8, 0x48, 0x49, 0xbc, 0xd9, 0x15, + 0x4f, 0xdd, 0xb1, 0x5e, 0xe4, 0x3b, 0x6c, 0x76, 0x7d, 0x5d, 0xf2, 0x0a, 0x66, 0x5c, 0x7b, 0x2b, + 0x07, 0xd2, 0x6c, 0x86, 0xa6, 0x03, 0x69, 0xc7, 0x3e, 0xe4, 0x89, 0xff, 0x33, 0x28, 0xc7, 0xde, + 0x23, 0x67, 0x1b, 0x84, 0x7c, 0xbf, 0x45, 0x92, 0x92, 0x54, 0x48, 0x3a, 0x25, 0xda, 0x99, 0xbb, + 0x9a, 0x27, 0xe1, 0x50, 0x73, 0x4b, 0x12, 0x7e, 0x6f, 0x89, 0x8c, 0x94, 0x79, 0xb9, 0x2d, 0x3b, + 0xd8, 0x61, 0xc5, 0xcb, 0xbc, 0x57, 0xc2, 0x28, 0x3d, 0xda, 0x67, 0x67, 0xa4, 0x9c, 0x3b, 0x12, + 0x8c, 0xac, 0x0e, 0xc3, 0x7b, 0x16, 0xdf, 0xb5, 0xe4, 0x50, 0x9c, 0x75, 0x40, 0x9d, 0xf8, 0x35, + 0x5a, 0x22, 0x3a, 0xa0, 0xfe, 0x02, 0x38, 0x5d, 0x94, 0x7c, 0x4a, 0x95, 0x85, 0xa1, 0x3c, 0xaa, + 0x4a, 0xb2, 0x0a, 0x06, 0x67, 0x47, 0x11, 0x3f, 0x70, 0xa3, 0xe7, 0x4b, 0xf6, 0x7a, 0x6c, 0x56, + 0xd0, 0x0b, 0x24, 0x6f, 0x90, 0x85, 0xf6, 0x3a, 0xf9, 0x12, 0x97, 0x12, 0xc1, 0x7e, 0xd1, 0xf7, + 0xa3, 0x30, 0x0a, 0x9c, 0x56, 0xb5, 0x1e, 0xb8, 0xad, 0x28, 0xb7, 0xd3, 0xb1, 0x8b, 0x77, 0x16, + 0x99, 0xe6, 0x71, 0x2a, 0xa2, 0xc7, 0x67, 0xc5, 0xd7, 0x51, 0xaf, 0x6e, 0xb2, 0x0a, 0x3b, 0x9c, + 0x5c, 0xaa, 0x32, 0x5e, 0xfc, 0xab, 0x64, 0x5a, 0x83, 0xd9, 0x9c, 0xa8, 0x44, 0xea, 0xf6, 0xb6, + 0x73, 0xd4, 0xa2, 0xb9, 0xce, 0x15, 0x93, 0xaf, 0x60, 0x26, 0x33, 0x6c, 0x91, 0xb2, 0x40, 0x77, + 0x0a, 0x6a, 0xd4, 0x8d, 0xf9, 0x13, 0x28, 0xf1, 0xf7, 0x1e, 0xe8, 0xd6, 0x6c, 0x44, 0xb0, 0x89, + 0x5f, 0x01, 0xe5, 0x20, 0x24, 0xd7, 0xeb, 0x7c, 0x3c, 0xf5, 0xa4, 0x7d, 0x1a, 0x43, 0x97, 0x24, + 0x12, 0x9e, 0xab, 0x0f, 0x2f, 0xab, 0xb0, 0xd3, 0x53, 0xa3, 0x6d, 0x98, 0xd9, 0xa3, 0x81, 0xfb, + 0xf8, 0x79, 0x92, 0xa1, 0x94, 0x4c, 0x66, 0x69, 0x27, 0x8e, 0x9f, 0xc3, 0xec, 0x92, 0x7f, 0xd4, + 0x12, 0x8f, 0xfa, 0x0c, 0x9e, 0xea, 0x2a, 0x3e, 0xbb, 0xbc, 0xbb, 0x23, 0xd4, 0x5c, 0x7e, 0x6a, + 0x7a, 0xe5, 0xff, 0xd6, 0x35, 0x7b, 0xbd, 0x7a, 0x9a, 0x66, 0xd2, 0xef, 0xe0, 0x24, 0xcc, 0xca, + 0x55, 0xaf, 0x4f, 0xc2, 0x0e, 0xb9, 0xec, 0x73, 0x9e, 0x88, 0xcd, 0xe6, 0xa4, 0xa7, 0xef, 0xc0, + 0xf5, 0x14, 0xad, 0xdd, 0x94, 0x7b, 0x8b, 0x99, 0xc8, 0x3b, 0xe1, 0x53, 0x9d, 0x99, 0xe5, 0x3b, + 0xb3, 0x9d, 0x5a, 0xec, 0x86, 0x66, 0xb3, 0x83, 0x8a, 0x45, 0xf4, 0xe0, 0x0d, 0x0c, 0x13, 0x8d, + 0xf8, 0xe3, 0x3a, 0x6d, 0xa7, 0xd5, 0x3a, 0x45, 0x8c, 0x4a, 0xed, 0x87, 0x30, 0x56, 0xd5, 0x2b, + 0xcf, 0xa8, 0x24, 0x77, 0x52, 0xa8, 0x47, 0x42, 0xdd, 0xdb, 0xde, 0xc1, 0x91, 0x54, 0x6d, 0x3c, + 0xa7, 0xea, 0x45, 0xae, 0xeb, 0x8c, 0x91, 0x95, 0x4d, 0xed, 0x02, 0x59, 0x49, 0x13, 0x95, 0xeb, + 0x4c, 0x76, 0x22, 0xb7, 0x1a, 0xcf, 0x23, 0x93, 0xcc, 0x89, 0x49, 0xac, 0xee, 0xc9, 0x67, 0x95, + 0xcb, 0x7c, 0xc7, 0xa4, 0x9a, 0xdc, 0xcf, 0x27, 0xce, 0x43, 0xa7, 0xfb, 0xf9, 0xa4, 0xb2, 0xdb, + 0xe9, 0x7e, 0x3e, 0x19, 0xa9, 0xeb, 0x56, 0x90, 0x57, 0x9c, 0x80, 0xa7, 0x83, 0x31, 0x42, 0xb1, + 0xc9, 0xc8, 0xf3, 0xf3, 0x50, 0x0f, 0x01, 0xc2, 0xd3, 0xf6, 0x74, 0xb0, 0xb5, 0x26, 0x43, 0x7f, + 0x24, 0xf2, 0xfc, 0xdc, 0x83, 0x22, 0xcf, 0x60, 0x10, 0x47, 0x4d, 0x8c, 0xfd, 0x06, 0xd3, 0x89, + 0x15, 0x3a, 0x0c, 0x6a, 0x31, 0x19, 0x6f, 0x4e, 0x99, 0xcc, 0x72, 0x02, 0xd1, 0x75, 0x98, 0xaa, + 0x10, 0x47, 0x95, 0x53, 0x86, 0xa9, 0x54, 0xa0, 0xb9, 0xb9, 0x0b, 0x19, 0x25, 0x4a, 0xa5, 0x1c, + 0xd3, 0x63, 0xd0, 0xa9, 0x2e, 0x65, 0x04, 0xa6, 0x9b, 0xbb, 0x98, 0x59, 0x26, 0x18, 0x45, 0x3c, + 0xff, 0x72, 0x76, 0xd6, 0xe8, 0xf8, 0x9d, 0x57, 0x07, 0x1c, 0x59, 0xcd, 0x8d, 0xd3, 0xa0, 0x8a, + 0x5a, 0xa9, 0x4a, 0x3f, 0x94, 0x91, 0xaa, 0xfa, 0xcd, 0x8c, 0xf7, 0x18, 0x06, 0x46, 0xec, 0x0d, + 0xd6, 0x39, 0x6f, 0x36, 0x79, 0x24, 0xd3, 0xc1, 0xe4, 0xd4, 0xd4, 0x8d, 0x41, 0xee, 0x08, 0x3e, + 0x92, 0x09, 0x60, 0x5e, 0x35, 0xe3, 0x7d, 0x98, 0x4f, 0x3c, 0xf7, 0x30, 0x19, 0xdf, 0xc8, 0x7e, + 0x13, 0x92, 0x29, 0x9e, 0x7c, 0x9d, 0xfd, 0x4a, 0xfa, 0x6d, 0x48, 0x62, 0xdc, 0xcf, 0xba, 0xe6, + 0x6d, 0xc0, 0x04, 0x2e, 0x33, 0x32, 0xe9, 0x7a, 0x1c, 0x81, 0xc6, 0x04, 0x27, 0x43, 0x21, 0x25, + 0x4b, 0x95, 0xcb, 0xec, 0x98, 0x78, 0x33, 0xcc, 0x53, 0xb8, 0xcf, 0x99, 0x0f, 0x89, 0x11, 0x98, + 0xb5, 0x8b, 0x89, 0xcc, 0xf0, 0xe4, 0xfb, 0x30, 0x19, 0x3f, 0x25, 0xe6, 0x2c, 0x32, 0xd0, 0x3a, + 0x18, 0xca, 0x26, 0xe3, 0xf7, 0xc4, 0x67, 0x27, 0x5f, 0x95, 0x5b, 0x51, 0x4c, 0x7e, 0x29, 0xf5, + 0x4c, 0xc6, 0xe8, 0xc3, 0x69, 0x76, 0x24, 0x4d, 0xb6, 0x67, 0x1d, 0x9d, 0x3a, 0x7e, 0x6e, 0xd9, + 0xc1, 0x15, 0xf5, 0xcf, 0xad, 0x63, 0x00, 0x48, 0xa5, 0xfe, 0xe6, 0xf0, 0xd9, 0x80, 0x6b, 0x18, + 0x90, 0x65, 0x9b, 0x87, 0xe0, 0xcb, 0xc6, 0xca, 0x6f, 0x7b, 0x32, 0x8c, 0x4b, 0x13, 0xae, 0x76, + 0x8d, 0x2e, 0x49, 0x6e, 0x19, 0x2e, 0x2e, 0xdd, 0xe3, 0x50, 0x76, 0x7a, 0x9a, 0x96, 0x15, 0xa4, + 0x51, 0xed, 0xb3, 0x1d, 0xe2, 0x45, 0xaa, 0x7d, 0xb6, 0x63, 0x94, 0xc7, 0xcf, 0x31, 0xc7, 0x92, + 0xd8, 0xa3, 0x30, 0xc8, 0x12, 0xf5, 0x78, 0xd8, 0xe9, 0x8e, 0xd7, 0x3e, 0x57, 0xcd, 0x4b, 0xd1, + 0x14, 0x21, 0x9e, 0x69, 0x2e, 0x8b, 0x93, 0x58, 0x1e, 0xf3, 0xee, 0x4c, 0x3a, 0xb8, 0x56, 0x5f, + 0xe6, 0x13, 0xf0, 0xcc, 0x2d, 0xcf, 0x81, 0x2f, 0x2e, 0xff, 0xec, 0x3f, 0x5f, 0x2e, 0xfc, 0xec, + 0xe7, 0x97, 0x0b, 0xff, 0xfe, 0xe7, 0x97, 0x0b, 0xff, 0xe9, 0xe7, 0x97, 0x0b, 0x5f, 0x2e, 0x9c, + 0x2e, 0xf8, 0x71, 0xbd, 0xe9, 0x52, 0x2f, 0xba, 0xc5, 0xd9, 0x0d, 0xe2, 0x7f, 0x77, 0xff, 0x77, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xbd, 0x9d, 0x6e, 0x3e, 0x9c, 0xe6, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -27605,6 +27738,13 @@ func (m *RouteToApp) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.URI) > 0 { + i -= len(m.URI) + copy(dAtA[i:], m.URI) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.URI))) + i-- + dAtA[i] = 0x42 + } if len(m.GCPServiceAccount) > 0 { i -= len(m.GCPServiceAccount) copy(dAtA[i:], m.GCPServiceAccount) @@ -28221,6 +28361,46 @@ func (m *Features) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.AccessMonitoringConfigured { + i-- + if m.AccessMonitoringConfigured { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0xa0 + } + if len(m.Entitlements) > 0 { + for k := range m.Entitlements { + v := m.Entitlements[k] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthservice(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintAuthservice(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintAuthservice(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0x9a + } + } if m.MobileDeviceManagement { i-- if m.MobileDeviceManagement { @@ -28569,6 +28749,48 @@ func (m *Features) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *EntitlementInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *EntitlementInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EntitlementInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Limit != 0 { + i = encodeVarintAuthservice(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x10 + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *DeviceTrustFeature) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -29304,12 +29526,12 @@ func (m *GenerateAppTokenRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) dAtA[i] = 0x2a } } - n25, err25 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) - if err25 != nil { - return 0, err25 + n26, err26 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) + if err26 != nil { + return 0, err26 } - i -= n25 - i = encodeVarintAuthservice(dAtA, i, uint64(n25)) + i -= n26 + i = encodeVarintAuthservice(dAtA, i, uint64(n26)) i-- dAtA[i] = 0x22 if len(m.URI) > 0 { @@ -29698,6 +29920,27 @@ func (m *CreateAppSessionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ClientAddr) > 0 { + i -= len(m.ClientAddr) + copy(dAtA[i:], m.ClientAddr) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.ClientAddr))) + i-- + dAtA[i] = 0x5a + } + if len(m.URI) > 0 { + i -= len(m.URI) + copy(dAtA[i:], m.URI) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.URI))) + i-- + dAtA[i] = 0x52 + } + if len(m.AppName) > 0 { + i -= len(m.AppName) + copy(dAtA[i:], m.AppName) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.AppName))) + i-- + dAtA[i] = 0x4a + } if m.MFAResponse != nil { { size, err := m.MFAResponse.MarshalToSizedBuffer(dAtA[:i]) @@ -32605,21 +32848,21 @@ func (m *GetEventsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x22 } } - n60, err60 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndDate):]) - if err60 != nil { - return 0, err60 - } - i -= n60 - i = encodeVarintAuthservice(dAtA, i, uint64(n60)) - i-- - dAtA[i] = 0x1a - n61, err61 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartDate):]) + n61, err61 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndDate):]) if err61 != nil { return 0, err61 } i -= n61 i = encodeVarintAuthservice(dAtA, i, uint64(n61)) i-- + dAtA[i] = 0x1a + n62, err62 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartDate):]) + if err62 != nil { + return 0, err62 + } + i -= n62 + i = encodeVarintAuthservice(dAtA, i, uint64(n62)) + i-- dAtA[i] = 0x12 if len(m.Namespace) > 0 { i -= len(m.Namespace) @@ -32672,21 +32915,21 @@ func (m *GetSessionEventsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i-- dAtA[i] = 0x18 } - n62, err62 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndDate):]) - if err62 != nil { - return 0, err62 - } - i -= n62 - i = encodeVarintAuthservice(dAtA, i, uint64(n62)) - i-- - dAtA[i] = 0x12 - n63, err63 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartDate):]) + n63, err63 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.EndDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.EndDate):]) if err63 != nil { return 0, err63 } i -= n63 i = encodeVarintAuthservice(dAtA, i, uint64(n63)) i-- + dAtA[i] = 0x12 + n64, err64 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.StartDate, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.StartDate):]) + if err64 != nil { + return 0, err64 + } + i -= n64 + i = encodeVarintAuthservice(dAtA, i, uint64(n64)) + i-- dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -34051,12 +34294,12 @@ func (m *RecoveryCodes) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - n70, err70 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Created, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Created):]) - if err70 != nil { - return 0, err70 + n71, err71 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Created, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Created):]) + if err71 != nil { + return 0, err71 } - i -= n70 - i = encodeVarintAuthservice(dAtA, i, uint64(n70)) + i -= n71 + i = encodeVarintAuthservice(dAtA, i, uint64(n71)) i-- dAtA[i] = 0x12 if len(m.Codes) > 0 { @@ -35500,12 +35743,12 @@ func (m *SessionTrackerUpdateExpiry) MarshalToSizedBuffer(dAtA []byte) (int, err copy(dAtA[i:], m.XXX_unrecognized) } if m.Expires != nil { - n95, err95 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expires):]) - if err95 != nil { - return 0, err95 + n96, err96 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expires):]) + if err96 != nil { + return 0, err96 } - i -= n95 - i = encodeVarintAuthservice(dAtA, i, uint64(n95)) + i -= n96 + i = encodeVarintAuthservice(dAtA, i, uint64(n96)) i-- dAtA[i] = 0xa } @@ -38847,6 +39090,10 @@ func (m *RouteToApp) Size() (n int) { if l > 0 { n += 1 + l + sovAuthservice(uint64(l)) } + l = len(m.URI) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -39206,6 +39453,40 @@ func (m *Features) Size() (n int) { if m.MobileDeviceManagement { n += 3 } + if len(m.Entitlements) > 0 { + for k, v := range m.Entitlements { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovAuthservice(uint64(l)) + } + mapEntrySize := 1 + len(k) + sovAuthservice(uint64(len(k))) + l + n += mapEntrySize + 2 + sovAuthservice(uint64(mapEntrySize)) + } + } + if m.AccessMonitoringConfigured { + n += 3 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *EntitlementInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Enabled { + n += 2 + } + if m.Limit != 0 { + n += 1 + sovAuthservice(uint64(m.Limit)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -39765,6 +40046,18 @@ func (m *CreateAppSessionRequest) Size() (n int) { l = m.MFAResponse.Size() n += 1 + l + sovAuthservice(uint64(l)) } + l = len(m.AppName) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } + l = len(m.URI) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } + l = len(m.ClientAddr) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -45920,6 +46213,38 @@ func (m *RouteToApp) Unmarshal(dAtA []byte) error { } m.GCPServiceAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field URI", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.URI = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthservice(dAtA[iNdEx:]) @@ -48149,6 +48474,245 @@ func (m *Features) Unmarshal(dAtA []byte) error { } } m.MobileDeviceManagement = bool(v != 0) + case 35: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entitlements", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Entitlements == nil { + m.Entitlements = make(map[string]*EntitlementInfo) + } + var mapkey string + var mapvalue *EntitlementInfo + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthAuthservice + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthAuthservice + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthAuthservice + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &EntitlementInfo{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthservice + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Entitlements[mapkey] = mapvalue + iNdEx = postIndex + case 36: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessMonitoringConfigured", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AccessMonitoringConfigured = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EntitlementInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EntitlementInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EntitlementInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipAuthservice(dAtA[iNdEx:]) @@ -51062,6 +51626,102 @@ func (m *CreateAppSessionRequest) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field URI", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.URI = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthservice(dAtA[iNdEx:]) diff --git a/api/client/webclient/webconfig.go b/api/client/webclient/webconfig.go index 0bf621a251dac..349489bf218d2 100644 --- a/api/client/webclient/webconfig.go +++ b/api/client/webclient/webconfig.go @@ -72,45 +72,71 @@ type WebConfig struct { // PlayableDatabaseProtocols is a list of database protocols which session // recordings can be played. PlayableDatabaseProtocols []string `json:"playable_db_protocols"` - // HideInaccessibleFeatures is true when features should be undiscoverable to users without the necessary permissions. - // Usually, in order to encourage discoverability of features, we show UI elements even if the user doesn't have permission to access them, - // this flag disables that behavior. - HideInaccessibleFeatures bool `json:"hideInaccessibleFeatures"` // CustomTheme is a string that represents the name of the custom theme that the WebUI should use. CustomTheme string `json:"customTheme"` + // Questionnaire indicates whether cluster users should get an onboarding questionnaire + Questionnaire bool `json:"questionnaire"` + // IsStripeManaged indicates if the cluster billing & lifecycle is managed via Stripe + IsStripeManaged bool `json:"isStripeManaged"` + // PremiumSupport indicates whether the customer has premium support + PremiumSupport bool `json:"premiumSupport"` + // Edition is the edition of Teleport + Edition string `json:"edition"` + // entitlements define a customer’s access to a specific features + Entitlements map[string]EntitlementInfo `json:"entitlements,omitempty"` + + // Deprecated Fields // Deprecated: IsTeam is true if [Features.ProductType] = Team // Prefer checking the cluster features over this flag, as this will be removed. IsTeam bool `json:"isTeam"` + // HideInaccessibleFeatures is true when features should be undiscoverable to users without the necessary permissions. + // Usually, in order to encourage discoverability of features, we show UI elements even if the user doesn't have permission to access them, + // this flag disables that behavior. + // Deprecated, use entitlements + HideInaccessibleFeatures bool `json:"hideInaccessibleFeatures"` // IsIGSEnabled is true if [Features.IdentityGovernance] = true + // Deprecated, use entitlements IsIGSEnabled bool `json:"isIgsEnabled"` // IsPolicyEnabled is true if [Features.Policy] = true + // Deprecated, use entitlements IsPolicyEnabled bool `json:"isPolicyEnabled"` // featureLimits define limits for features. // Typically used with feature teasers if feature is not enabled for the // product type eg: Team product contains teasers to upgrade to Enterprise. + // Deprecated, use entitlements FeatureLimits FeatureLimits `json:"featureLimits"` - // Questionnaire indicates whether cluster users should get an onboarding questionnaire - Questionnaire bool `json:"questionnaire"` - // IsStripeManaged indicates if the cluster billing & lifecycle is managed via Stripe - IsStripeManaged bool `json:"isStripeManaged"` // ExternalAuditStorage indicates whether the EAS feature is enabled in the cluster. + // Deprecated, use entitlements ExternalAuditStorage bool `json:"externalAuditStorage"` - // PremiumSupport indicates whether the customer has premium support - PremiumSupport bool `json:"premiumSupport"` // JoinActiveSessions indicates whether joining active sessions via web UI is enabled + // Deprecated, use entitlements JoinActiveSessions bool `json:"joinActiveSessions"` // AccessRequests indicates whether access requests are enabled + // Deprecated, use entitlements AccessRequests bool `json:"accessRequests"` // TrustedDevices indicates whether trusted devices page is enabled + // Deprecated, use entitlements TrustedDevices bool `json:"trustedDevices"` // OIDC indicates whether the OIDC integration flow is enabled + // Deprecated, use entitlements OIDC bool `json:"oidc"` // SAML indicates whether the SAML integration flow is enabled + // Deprecated, use entitlements SAML bool `json:"saml"` // MobileDeviceManagement indicates whether adding Jamf plugin is enabled + // Deprecated, use entitlements MobileDeviceManagement bool `json:"mobileDeviceManagement"` - // Edition is the edition of Teleport - Edition string `json:"edition"` +} + +// EntitlementInfo is the state and limits of a particular entitlement; Example for feature X: +// { Enabled: true, Limit: 0 } => unlimited access to feature X +// { Enabled: true, Limit: >0 } => limited access to feature X +// { Enabled: false, Limit: >=0 } => no access to feature X +type EntitlementInfo struct { + // Enabled indicates the feature is 'on' if true; feature is disabled if false + Enabled bool `json:"enabled"` + // Limit indicates the allotted amount of use when limited; if 0 use is unlimited + Limit int32 `json:"limit"` } // featureLimits define limits for features. diff --git a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go index a5ed1ffa34534..6ddfa5028e2d7 100644 --- a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go +++ b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go @@ -132,9 +132,13 @@ type CrownJewelSpec struct { unknownFields protoimpl.UnknownFields // TeleportMatchers is a list of teleport matchers. + // DEPRECATED: Use query instead. TeleportMatchers []*TeleportMatcher `protobuf:"bytes,1,rep,name=teleport_matchers,json=teleportMatchers,proto3" json:"teleport_matchers,omitempty"` // AWSMatchers is a list of AWS matchers. + // DEPRECATED: Use query instead. AwsMatchers []*AWSMatcher `protobuf:"bytes,2,rep,name=aws_matchers,json=awsMatchers,proto3" json:"aws_matchers,omitempty"` + // Query is a Access Graph query to match resources. + Query string `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` } func (x *CrownJewelSpec) Reset() { @@ -183,6 +187,13 @@ func (x *CrownJewelSpec) GetAwsMatchers() []*AWSMatcher { return nil } +func (x *CrownJewelSpec) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + // TeleportMatcher represents a matcher for Teleport resources. type TeleportMatcher struct { state protoimpl.MessageState @@ -415,7 +426,7 @@ var file_teleport_crownjewel_v1_crownjewel_proto_rawDesc = []byte{ 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, - 0x63, 0x22, 0xad, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, + 0x63, 0x22, 0xc3, 0x01, 0x0a, 0x0e, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x53, 0x70, 0x65, 0x63, 0x12, 0x54, 0x0a, 0x11, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, @@ -426,35 +437,36 @@ var file_teleport_crownjewel_v1_crownjewel_proto_rawDesc = []byte{ 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x0b, 0x61, 0x77, 0x73, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, - 0x73, 0x22, 0x7b, 0x0a, 0x0f, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, 0x12, 0x30, 0x0a, 0x06, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, - 0x61, 0x62, 0x65, 0x6c, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x8f, - 0x01, 0x0a, 0x0a, 0x41, 0x57, 0x53, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, - 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, - 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x04, 0x61, 0x72, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x52, 0x03, 0x61, 0x72, 0x6e, - 0x22, 0x50, 0x0a, 0x06, 0x41, 0x57, 0x53, 0x54, 0x61, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x06, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x42, 0x58, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2f, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x3b, - 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x7b, 0x0a, 0x0f, 0x54, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x69, + 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x69, 0x6e, 0x64, 0x73, + 0x12, 0x30, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x8f, 0x01, 0x0a, 0x0a, 0x41, 0x57, 0x53, 0x4d, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x67, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x72, 0x6f, + 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x57, 0x53, 0x54, 0x61, + 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x6e, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, + 0x05, 0x52, 0x03, 0x61, 0x72, 0x6e, 0x22, 0x50, 0x0a, 0x06, 0x41, 0x57, 0x53, 0x54, 0x61, 0x67, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x58, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, + 0x65, 0x6c, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x6a, 0x65, 0x77, 0x65, 0x6c, + 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go b/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go index a5ab858bad303..fa462fc591c21 100644 --- a/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/awsoidc_service.pb.go @@ -1583,7 +1583,8 @@ type DeployDatabaseServiceResponse struct { // ClusterArn identifies the cluster where the deployment was made. ClusterArn string `protobuf:"bytes,1,opt,name=cluster_arn,json=clusterArn,proto3" json:"cluster_arn,omitempty"` - // ClusterDashboardUrl is the URL for Amazon Web Console that links directly to the Amazon ECS Cluster. + // ClusterDashboardURL is a link to the Amazon ECS cluster dashboard or a + // specific cluster service if a single deployment was requested. ClusterDashboardUrl string `protobuf:"bytes,2,opt,name=cluster_dashboard_url,json=clusterDashboardUrl,proto3" json:"cluster_dashboard_url,omitempty"` } diff --git a/api/gen/proto/go/teleport/machineid/v1/federation.pb.go b/api/gen/proto/go/teleport/machineid/v1/federation.pb.go new file mode 100644 index 0000000000000..c11aeea704338 --- /dev/null +++ b/api/gen/proto/go/teleport/machineid/v1/federation.pb.go @@ -0,0 +1,634 @@ +// Copyright 2024 Gravitational, Inc +// +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.0 +// protoc (unknown) +// source: teleport/machineid/v1/federation.proto + +package machineidv1 + +import ( + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// SPIFFEFederation is a resource that represents the configuration of a trust +// domain federation. +type SPIFFEFederation struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The kind of resource represented. + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + // Differentiates variations of the same kind. All resources should + // contain one, even if it is never populated. + SubKind string `protobuf:"bytes,2,opt,name=sub_kind,json=subKind,proto3" json:"sub_kind,omitempty"` + // The version of the resource being represented. + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + // Common metadata that all resources share. + // Importantly, the name MUST match the name of the trust domain you federate + // with. + Metadata *v1.Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + // The configured properties of the trust domain federation + Spec *SPIFFEFederationSpec `protobuf:"bytes,5,opt,name=spec,proto3" json:"spec,omitempty"` + // Fields that are set by the server as results of operations. These should + // not be modified by users. + Status *SPIFFEFederationStatus `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *SPIFFEFederation) Reset() { + *x = SPIFFEFederation{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederation) ProtoMessage() {} + +func (x *SPIFFEFederation) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[0] + 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 SPIFFEFederation.ProtoReflect.Descriptor instead. +func (*SPIFFEFederation) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{0} +} + +func (x *SPIFFEFederation) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *SPIFFEFederation) GetSubKind() string { + if x != nil { + return x.SubKind + } + return "" +} + +func (x *SPIFFEFederation) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *SPIFFEFederation) GetMetadata() *v1.Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *SPIFFEFederation) GetSpec() *SPIFFEFederationSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *SPIFFEFederation) GetStatus() *SPIFFEFederationStatus { + if x != nil { + return x.Status + } + return nil +} + +// SPIFFEFederationBundleSourceStatic is a static bundle source. It should be an +// option of last resort, as it requires manual updates. +type SPIFFEFederationBundleSourceStatic struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The SPIFFE JWKS bundle. + Bundle string `protobuf:"bytes,1,opt,name=bundle,proto3" json:"bundle,omitempty"` +} + +func (x *SPIFFEFederationBundleSourceStatic) Reset() { + *x = SPIFFEFederationBundleSourceStatic{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederationBundleSourceStatic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederationBundleSourceStatic) ProtoMessage() {} + +func (x *SPIFFEFederationBundleSourceStatic) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[1] + 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 SPIFFEFederationBundleSourceStatic.ProtoReflect.Descriptor instead. +func (*SPIFFEFederationBundleSourceStatic) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{1} +} + +func (x *SPIFFEFederationBundleSourceStatic) GetBundle() string { + if x != nil { + return x.Bundle + } + return "" +} + +// SPIFFEFederationBundleSourceHTTPSWeb is a bundle source that fetches the bundle +// from a HTTPS endpoint that is protected by a Web PKI certificate. +type SPIFFEFederationBundleSourceHTTPSWeb struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The URL of the SPIFFE Bundle Endpoint. + BundleEndpointUrl string `protobuf:"bytes,1,opt,name=bundle_endpoint_url,json=bundleEndpointUrl,proto3" json:"bundle_endpoint_url,omitempty"` +} + +func (x *SPIFFEFederationBundleSourceHTTPSWeb) Reset() { + *x = SPIFFEFederationBundleSourceHTTPSWeb{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederationBundleSourceHTTPSWeb) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederationBundleSourceHTTPSWeb) ProtoMessage() {} + +func (x *SPIFFEFederationBundleSourceHTTPSWeb) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[2] + 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 SPIFFEFederationBundleSourceHTTPSWeb.ProtoReflect.Descriptor instead. +func (*SPIFFEFederationBundleSourceHTTPSWeb) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{2} +} + +func (x *SPIFFEFederationBundleSourceHTTPSWeb) GetBundleEndpointUrl() string { + if x != nil { + return x.BundleEndpointUrl + } + return "" +} + +// SPIFFEFederationBundleSource configures how the federation bundle is sourced. +// Only one field can be set. +type SPIFFEFederationBundleSource struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Static *SPIFFEFederationBundleSourceStatic `protobuf:"bytes,1,opt,name=static,proto3" json:"static,omitempty"` + HttpsWeb *SPIFFEFederationBundleSourceHTTPSWeb `protobuf:"bytes,2,opt,name=https_web,json=httpsWeb,proto3" json:"https_web,omitempty"` +} + +func (x *SPIFFEFederationBundleSource) Reset() { + *x = SPIFFEFederationBundleSource{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederationBundleSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederationBundleSource) ProtoMessage() {} + +func (x *SPIFFEFederationBundleSource) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[3] + 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 SPIFFEFederationBundleSource.ProtoReflect.Descriptor instead. +func (*SPIFFEFederationBundleSource) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{3} +} + +func (x *SPIFFEFederationBundleSource) GetStatic() *SPIFFEFederationBundleSourceStatic { + if x != nil { + return x.Static + } + return nil +} + +func (x *SPIFFEFederationBundleSource) GetHttpsWeb() *SPIFFEFederationBundleSourceHTTPSWeb { + if x != nil { + return x.HttpsWeb + } + return nil +} + +// SPIFFEFederationSpec is the configuration of a trust domain federation. +type SPIFFEFederationSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The source of the federation bundle. + BundleSource *SPIFFEFederationBundleSource `protobuf:"bytes,1,opt,name=bundle_source,json=bundleSource,proto3" json:"bundle_source,omitempty"` +} + +func (x *SPIFFEFederationSpec) Reset() { + *x = SPIFFEFederationSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederationSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederationSpec) ProtoMessage() {} + +func (x *SPIFFEFederationSpec) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[4] + 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 SPIFFEFederationSpec.ProtoReflect.Descriptor instead. +func (*SPIFFEFederationSpec) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{4} +} + +func (x *SPIFFEFederationSpec) GetBundleSource() *SPIFFEFederationBundleSource { + if x != nil { + return x.BundleSource + } + return nil +} + +// FederationStatus is the status of a trust domain federation. +type SPIFFEFederationStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The most recently fetched bundle from the federated trust domain. + CurrentBundle string `protobuf:"bytes,1,opt,name=current_bundle,json=currentBundle,proto3" json:"current_bundle,omitempty"` + // The time that the most recently fetched bundle was obtained. + CurrentBundleSyncedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=current_bundle_synced_at,json=currentBundleSyncedAt,proto3" json:"current_bundle_synced_at,omitempty"` + // The duration that the current bundle suggests the next bundle should be + // refresh after. + CurrentBundleRefreshHint *durationpb.Duration `protobuf:"bytes,3,opt,name=current_bundle_refresh_hint,json=currentBundleRefreshHint,proto3" json:"current_bundle_refresh_hint,omitempty"` +} + +func (x *SPIFFEFederationStatus) Reset() { + *x = SPIFFEFederationStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SPIFFEFederationStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SPIFFEFederationStatus) ProtoMessage() {} + +func (x *SPIFFEFederationStatus) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_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 SPIFFEFederationStatus.ProtoReflect.Descriptor instead. +func (*SPIFFEFederationStatus) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_proto_rawDescGZIP(), []int{5} +} + +func (x *SPIFFEFederationStatus) GetCurrentBundle() string { + if x != nil { + return x.CurrentBundle + } + return "" +} + +func (x *SPIFFEFederationStatus) GetCurrentBundleSyncedAt() *timestamppb.Timestamp { + if x != nil { + return x.CurrentBundleSyncedAt + } + return nil +} + +func (x *SPIFFEFederationStatus) GetCurrentBundleRefreshHint() *durationpb.Duration { + if x != nil { + return x.CurrentBundleRefreshHint + } + return nil +} + +var File_teleport_machineid_v1_federation_proto protoreflect.FileDescriptor + +var file_teleport_machineid_v1_federation_proto_rawDesc = []byte{ + 0x0a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x1a, + 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x02, 0x0a, 0x10, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x75, 0x62, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x04, 0x73, + 0x70, 0x65, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x45, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, + 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x3c, 0x0a, 0x22, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x6e, 0x64, 0x6c, + 0x65, 0x22, 0x56, 0x0a, 0x24, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x48, 0x54, 0x54, 0x50, 0x53, 0x57, 0x65, 0x62, 0x12, 0x2e, 0x0a, 0x13, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x75, 0x72, 0x6c, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x45, 0x6e, + 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x55, 0x72, 0x6c, 0x22, 0xcb, 0x01, 0x0a, 0x1c, 0x53, 0x50, + 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x75, + 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12, 0x58, 0x0a, + 0x09, 0x68, 0x74, 0x74, 0x70, 0x73, 0x5f, 0x77, 0x65, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x3b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, + 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x54, 0x54, 0x50, 0x53, 0x57, 0x65, 0x62, 0x52, 0x08, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x57, 0x65, 0x62, 0x22, 0x70, 0x0a, 0x14, 0x53, 0x50, 0x49, 0x46, 0x46, + 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x70, 0x65, 0x63, 0x12, + 0x58, 0x0a, 0x0d, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0c, 0x62, 0x75, 0x6e, + 0x64, 0x6c, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x16, 0x53, 0x50, + 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x53, 0x0a, 0x18, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x5f, 0x73, 0x79, + 0x6e, 0x63, 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, 0x15, 0x63, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x65, 0x64, 0x41, 0x74, + 0x12, 0x58, 0x0a, 0x1b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x62, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x68, 0x69, 0x6e, 0x74, 0x18, + 0x03, 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, 0x18, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x48, 0x69, 0x6e, 0x74, 0x42, 0x56, 0x5a, 0x54, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, + 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x65, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, + 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_teleport_machineid_v1_federation_proto_rawDescOnce sync.Once + file_teleport_machineid_v1_federation_proto_rawDescData = file_teleport_machineid_v1_federation_proto_rawDesc +) + +func file_teleport_machineid_v1_federation_proto_rawDescGZIP() []byte { + file_teleport_machineid_v1_federation_proto_rawDescOnce.Do(func() { + file_teleport_machineid_v1_federation_proto_rawDescData = protoimpl.X.CompressGZIP(file_teleport_machineid_v1_federation_proto_rawDescData) + }) + return file_teleport_machineid_v1_federation_proto_rawDescData +} + +var file_teleport_machineid_v1_federation_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_teleport_machineid_v1_federation_proto_goTypes = []interface{}{ + (*SPIFFEFederation)(nil), // 0: teleport.machineid.v1.SPIFFEFederation + (*SPIFFEFederationBundleSourceStatic)(nil), // 1: teleport.machineid.v1.SPIFFEFederationBundleSourceStatic + (*SPIFFEFederationBundleSourceHTTPSWeb)(nil), // 2: teleport.machineid.v1.SPIFFEFederationBundleSourceHTTPSWeb + (*SPIFFEFederationBundleSource)(nil), // 3: teleport.machineid.v1.SPIFFEFederationBundleSource + (*SPIFFEFederationSpec)(nil), // 4: teleport.machineid.v1.SPIFFEFederationSpec + (*SPIFFEFederationStatus)(nil), // 5: teleport.machineid.v1.SPIFFEFederationStatus + (*v1.Metadata)(nil), // 6: teleport.header.v1.Metadata + (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 8: google.protobuf.Duration +} +var file_teleport_machineid_v1_federation_proto_depIdxs = []int32{ + 6, // 0: teleport.machineid.v1.SPIFFEFederation.metadata:type_name -> teleport.header.v1.Metadata + 4, // 1: teleport.machineid.v1.SPIFFEFederation.spec:type_name -> teleport.machineid.v1.SPIFFEFederationSpec + 5, // 2: teleport.machineid.v1.SPIFFEFederation.status:type_name -> teleport.machineid.v1.SPIFFEFederationStatus + 1, // 3: teleport.machineid.v1.SPIFFEFederationBundleSource.static:type_name -> teleport.machineid.v1.SPIFFEFederationBundleSourceStatic + 2, // 4: teleport.machineid.v1.SPIFFEFederationBundleSource.https_web:type_name -> teleport.machineid.v1.SPIFFEFederationBundleSourceHTTPSWeb + 3, // 5: teleport.machineid.v1.SPIFFEFederationSpec.bundle_source:type_name -> teleport.machineid.v1.SPIFFEFederationBundleSource + 7, // 6: teleport.machineid.v1.SPIFFEFederationStatus.current_bundle_synced_at:type_name -> google.protobuf.Timestamp + 8, // 7: teleport.machineid.v1.SPIFFEFederationStatus.current_bundle_refresh_hint:type_name -> google.protobuf.Duration + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_teleport_machineid_v1_federation_proto_init() } +func file_teleport_machineid_v1_federation_proto_init() { + if File_teleport_machineid_v1_federation_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_teleport_machineid_v1_federation_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederation); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederationBundleSourceStatic); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederationBundleSourceHTTPSWeb); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederationBundleSource); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederationSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SPIFFEFederationStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_teleport_machineid_v1_federation_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_teleport_machineid_v1_federation_proto_goTypes, + DependencyIndexes: file_teleport_machineid_v1_federation_proto_depIdxs, + MessageInfos: file_teleport_machineid_v1_federation_proto_msgTypes, + }.Build() + File_teleport_machineid_v1_federation_proto = out.File + file_teleport_machineid_v1_federation_proto_rawDesc = nil + file_teleport_machineid_v1_federation_proto_goTypes = nil + file_teleport_machineid_v1_federation_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go b/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go new file mode 100644 index 0000000000000..e58ad63436b61 --- /dev/null +++ b/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go @@ -0,0 +1,513 @@ +// Copyright 2024 Gravitational, Inc +// +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.0 +// protoc (unknown) +// source: teleport/machineid/v1/federation_service.proto + +package machineidv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// GetSPIFFEFederationRequest is the request message for GetSPIFFEFederation. +type GetSPIFFEFederationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the SPIFFEFederation resource to fetch. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *GetSPIFFEFederationRequest) Reset() { + *x = GetSPIFFEFederationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetSPIFFEFederationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSPIFFEFederationRequest) ProtoMessage() {} + +func (x *GetSPIFFEFederationRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[0] + 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 GetSPIFFEFederationRequest.ProtoReflect.Descriptor instead. +func (*GetSPIFFEFederationRequest) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetSPIFFEFederationRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// Request for ListSPIFFEFederations. +// +// Follows the pagination semantics of +// https://cloud.google.com/apis/design/standard_methods#list +type ListSPIFFEFederationsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The maximum number of items to return. + // The server may impose a different page size at its discretion. + PageSize int32 `protobuf:"varint,1,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // The page_token value returned from a previous ListSPIFFEFederations + // request, if any. + PageToken string `protobuf:"bytes,2,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` +} + +func (x *ListSPIFFEFederationsRequest) Reset() { + *x = ListSPIFFEFederationsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListSPIFFEFederationsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSPIFFEFederationsRequest) ProtoMessage() {} + +func (x *ListSPIFFEFederationsRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[1] + 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 ListSPIFFEFederationsRequest.ProtoReflect.Descriptor instead. +func (*ListSPIFFEFederationsRequest) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_service_proto_rawDescGZIP(), []int{1} +} + +func (x *ListSPIFFEFederationsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListSPIFFEFederationsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// ListSPIFFEFederationsResponse is the response message for ListSPIFFEFederations. +type ListSPIFFEFederationsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SpiffeFederations []*SPIFFEFederation `protobuf:"bytes,1,rep,name=spiffe_federations,json=spiffeFederations,proto3" json:"spiffe_federations,omitempty"` + // Token to retrieve the next page of results, or empty if there are no + // more results exist. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` +} + +func (x *ListSPIFFEFederationsResponse) Reset() { + *x = ListSPIFFEFederationsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListSPIFFEFederationsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSPIFFEFederationsResponse) ProtoMessage() {} + +func (x *ListSPIFFEFederationsResponse) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[2] + 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 ListSPIFFEFederationsResponse.ProtoReflect.Descriptor instead. +func (*ListSPIFFEFederationsResponse) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ListSPIFFEFederationsResponse) GetSpiffeFederations() []*SPIFFEFederation { + if x != nil { + return x.SpiffeFederations + } + return nil +} + +func (x *ListSPIFFEFederationsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// DeleteSPIFFEFederationRequest is the request message for DeleteSPIFFEFederation. +type DeleteSPIFFEFederationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the SPIFFEFederation resource to delete. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DeleteSPIFFEFederationRequest) Reset() { + *x = DeleteSPIFFEFederationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSPIFFEFederationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSPIFFEFederationRequest) ProtoMessage() {} + +func (x *DeleteSPIFFEFederationRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[3] + 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 DeleteSPIFFEFederationRequest.ProtoReflect.Descriptor instead. +func (*DeleteSPIFFEFederationRequest) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_service_proto_rawDescGZIP(), []int{3} +} + +func (x *DeleteSPIFFEFederationRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +// CreateSPIFFEFederationRequest is the request message for CreateSPIFFEFederation. +type CreateSPIFFEFederationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The SPIFFEFederation resource to create. + SpiffeFederation *SPIFFEFederation `protobuf:"bytes,1,opt,name=spiffe_federation,json=spiffeFederation,proto3" json:"spiffe_federation,omitempty"` +} + +func (x *CreateSPIFFEFederationRequest) Reset() { + *x = CreateSPIFFEFederationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateSPIFFEFederationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSPIFFEFederationRequest) ProtoMessage() {} + +func (x *CreateSPIFFEFederationRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_machineid_v1_federation_service_proto_msgTypes[4] + 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 CreateSPIFFEFederationRequest.ProtoReflect.Descriptor instead. +func (*CreateSPIFFEFederationRequest) Descriptor() ([]byte, []int) { + return file_teleport_machineid_v1_federation_service_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateSPIFFEFederationRequest) GetSpiffeFederation() *SPIFFEFederation { + if x != nil { + return x.SpiffeFederation + } + return nil +} + +var File_teleport_machineid_v1_federation_service_proto protoreflect.FileDescriptor + +var file_teleport_machineid_v1_federation_service_proto_rawDesc = []byte{ + 0x0a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x15, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, + 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x2f, 0x66, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x30, 0x0a, 0x1a, + 0x47, 0x65, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5a, + 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, + 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x9f, 0x01, 0x0a, 0x1d, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, + 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x66, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x11, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, + 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x33, 0x0a, 0x1d, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x22, 0x75, 0x0a, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x50, 0x49, 0x46, 0x46, + 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x66, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x10, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x46, 0x65, + 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0xf2, 0x03, 0x0a, 0x17, 0x53, 0x50, 0x49, + 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x71, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, + 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, + 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x82, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x50, + 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x16, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x77, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x50, + 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x50, 0x49, + 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x50, 0x49, + 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x56, 0x5a, + 0x54, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, + 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2f, 0x76, 0x31, 0x3b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, + 0x65, 0x69, 0x64, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_teleport_machineid_v1_federation_service_proto_rawDescOnce sync.Once + file_teleport_machineid_v1_federation_service_proto_rawDescData = file_teleport_machineid_v1_federation_service_proto_rawDesc +) + +func file_teleport_machineid_v1_federation_service_proto_rawDescGZIP() []byte { + file_teleport_machineid_v1_federation_service_proto_rawDescOnce.Do(func() { + file_teleport_machineid_v1_federation_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_teleport_machineid_v1_federation_service_proto_rawDescData) + }) + return file_teleport_machineid_v1_federation_service_proto_rawDescData +} + +var file_teleport_machineid_v1_federation_service_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_teleport_machineid_v1_federation_service_proto_goTypes = []interface{}{ + (*GetSPIFFEFederationRequest)(nil), // 0: teleport.machineid.v1.GetSPIFFEFederationRequest + (*ListSPIFFEFederationsRequest)(nil), // 1: teleport.machineid.v1.ListSPIFFEFederationsRequest + (*ListSPIFFEFederationsResponse)(nil), // 2: teleport.machineid.v1.ListSPIFFEFederationsResponse + (*DeleteSPIFFEFederationRequest)(nil), // 3: teleport.machineid.v1.DeleteSPIFFEFederationRequest + (*CreateSPIFFEFederationRequest)(nil), // 4: teleport.machineid.v1.CreateSPIFFEFederationRequest + (*SPIFFEFederation)(nil), // 5: teleport.machineid.v1.SPIFFEFederation + (*emptypb.Empty)(nil), // 6: google.protobuf.Empty +} +var file_teleport_machineid_v1_federation_service_proto_depIdxs = []int32{ + 5, // 0: teleport.machineid.v1.ListSPIFFEFederationsResponse.spiffe_federations:type_name -> teleport.machineid.v1.SPIFFEFederation + 5, // 1: teleport.machineid.v1.CreateSPIFFEFederationRequest.spiffe_federation:type_name -> teleport.machineid.v1.SPIFFEFederation + 0, // 2: teleport.machineid.v1.SPIFFEFederationService.GetSPIFFEFederation:input_type -> teleport.machineid.v1.GetSPIFFEFederationRequest + 1, // 3: teleport.machineid.v1.SPIFFEFederationService.ListSPIFFEFederations:input_type -> teleport.machineid.v1.ListSPIFFEFederationsRequest + 3, // 4: teleport.machineid.v1.SPIFFEFederationService.DeleteSPIFFEFederation:input_type -> teleport.machineid.v1.DeleteSPIFFEFederationRequest + 4, // 5: teleport.machineid.v1.SPIFFEFederationService.CreateSPIFFEFederation:input_type -> teleport.machineid.v1.CreateSPIFFEFederationRequest + 5, // 6: teleport.machineid.v1.SPIFFEFederationService.GetSPIFFEFederation:output_type -> teleport.machineid.v1.SPIFFEFederation + 2, // 7: teleport.machineid.v1.SPIFFEFederationService.ListSPIFFEFederations:output_type -> teleport.machineid.v1.ListSPIFFEFederationsResponse + 6, // 8: teleport.machineid.v1.SPIFFEFederationService.DeleteSPIFFEFederation:output_type -> google.protobuf.Empty + 5, // 9: teleport.machineid.v1.SPIFFEFederationService.CreateSPIFFEFederation:output_type -> teleport.machineid.v1.SPIFFEFederation + 6, // [6:10] is the sub-list for method output_type + 2, // [2:6] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_teleport_machineid_v1_federation_service_proto_init() } +func file_teleport_machineid_v1_federation_service_proto_init() { + if File_teleport_machineid_v1_federation_service_proto != nil { + return + } + file_teleport_machineid_v1_federation_proto_init() + if !protoimpl.UnsafeEnabled { + file_teleport_machineid_v1_federation_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetSPIFFEFederationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListSPIFFEFederationsRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListSPIFFEFederationsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteSPIFFEFederationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_teleport_machineid_v1_federation_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateSPIFFEFederationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_teleport_machineid_v1_federation_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_teleport_machineid_v1_federation_service_proto_goTypes, + DependencyIndexes: file_teleport_machineid_v1_federation_service_proto_depIdxs, + MessageInfos: file_teleport_machineid_v1_federation_service_proto_msgTypes, + }.Build() + File_teleport_machineid_v1_federation_service_proto = out.File + file_teleport_machineid_v1_federation_service_proto_rawDesc = nil + file_teleport_machineid_v1_federation_service_proto_goTypes = nil + file_teleport_machineid_v1_federation_service_proto_depIdxs = nil +} diff --git a/api/gen/proto/go/teleport/machineid/v1/federation_service_grpc.pb.go b/api/gen/proto/go/teleport/machineid/v1/federation_service_grpc.pb.go new file mode 100644 index 0000000000000..47fa1351948ae --- /dev/null +++ b/api/gen/proto/go/teleport/machineid/v1/federation_service_grpc.pb.go @@ -0,0 +1,248 @@ +// Copyright 2024 Gravitational, Inc +// +// 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. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: teleport/machineid/v1/federation_service.proto + +package machineidv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + SPIFFEFederationService_GetSPIFFEFederation_FullMethodName = "/teleport.machineid.v1.SPIFFEFederationService/GetSPIFFEFederation" + SPIFFEFederationService_ListSPIFFEFederations_FullMethodName = "/teleport.machineid.v1.SPIFFEFederationService/ListSPIFFEFederations" + SPIFFEFederationService_DeleteSPIFFEFederation_FullMethodName = "/teleport.machineid.v1.SPIFFEFederationService/DeleteSPIFFEFederation" + SPIFFEFederationService_CreateSPIFFEFederation_FullMethodName = "/teleport.machineid.v1.SPIFFEFederationService/CreateSPIFFEFederation" +) + +// SPIFFEFederationServiceClient is the client API for SPIFFEFederationService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type SPIFFEFederationServiceClient interface { + // GetSPIFFEFederation returns a SPIFFEFederation resource by name. + GetSPIFFEFederation(ctx context.Context, in *GetSPIFFEFederationRequest, opts ...grpc.CallOption) (*SPIFFEFederation, error) + // ListSPIFFEFederations returns a list of SPIFFEFederation resources. + // Follows the pagination semantics of + // https://cloud.google.com/apis/design/design_patterns#list_pagination + ListSPIFFEFederations(ctx context.Context, in *ListSPIFFEFederationsRequest, opts ...grpc.CallOption) (*ListSPIFFEFederationsResponse, error) + // DeleteSPIFFEFederation deletes a SPIFFEFederation resource by name. + DeleteSPIFFEFederation(ctx context.Context, in *DeleteSPIFFEFederationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + // CreateSPIFFEFederation creates a SPIFFEFederation resource. + CreateSPIFFEFederation(ctx context.Context, in *CreateSPIFFEFederationRequest, opts ...grpc.CallOption) (*SPIFFEFederation, error) +} + +type sPIFFEFederationServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewSPIFFEFederationServiceClient(cc grpc.ClientConnInterface) SPIFFEFederationServiceClient { + return &sPIFFEFederationServiceClient{cc} +} + +func (c *sPIFFEFederationServiceClient) GetSPIFFEFederation(ctx context.Context, in *GetSPIFFEFederationRequest, opts ...grpc.CallOption) (*SPIFFEFederation, error) { + out := new(SPIFFEFederation) + err := c.cc.Invoke(ctx, SPIFFEFederationService_GetSPIFFEFederation_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sPIFFEFederationServiceClient) ListSPIFFEFederations(ctx context.Context, in *ListSPIFFEFederationsRequest, opts ...grpc.CallOption) (*ListSPIFFEFederationsResponse, error) { + out := new(ListSPIFFEFederationsResponse) + err := c.cc.Invoke(ctx, SPIFFEFederationService_ListSPIFFEFederations_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sPIFFEFederationServiceClient) DeleteSPIFFEFederation(ctx context.Context, in *DeleteSPIFFEFederationRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, SPIFFEFederationService_DeleteSPIFFEFederation_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *sPIFFEFederationServiceClient) CreateSPIFFEFederation(ctx context.Context, in *CreateSPIFFEFederationRequest, opts ...grpc.CallOption) (*SPIFFEFederation, error) { + out := new(SPIFFEFederation) + err := c.cc.Invoke(ctx, SPIFFEFederationService_CreateSPIFFEFederation_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SPIFFEFederationServiceServer is the server API for SPIFFEFederationService service. +// All implementations must embed UnimplementedSPIFFEFederationServiceServer +// for forward compatibility +type SPIFFEFederationServiceServer interface { + // GetSPIFFEFederation returns a SPIFFEFederation resource by name. + GetSPIFFEFederation(context.Context, *GetSPIFFEFederationRequest) (*SPIFFEFederation, error) + // ListSPIFFEFederations returns a list of SPIFFEFederation resources. + // Follows the pagination semantics of + // https://cloud.google.com/apis/design/design_patterns#list_pagination + ListSPIFFEFederations(context.Context, *ListSPIFFEFederationsRequest) (*ListSPIFFEFederationsResponse, error) + // DeleteSPIFFEFederation deletes a SPIFFEFederation resource by name. + DeleteSPIFFEFederation(context.Context, *DeleteSPIFFEFederationRequest) (*emptypb.Empty, error) + // CreateSPIFFEFederation creates a SPIFFEFederation resource. + CreateSPIFFEFederation(context.Context, *CreateSPIFFEFederationRequest) (*SPIFFEFederation, error) + mustEmbedUnimplementedSPIFFEFederationServiceServer() +} + +// UnimplementedSPIFFEFederationServiceServer must be embedded to have forward compatible implementations. +type UnimplementedSPIFFEFederationServiceServer struct { +} + +func (UnimplementedSPIFFEFederationServiceServer) GetSPIFFEFederation(context.Context, *GetSPIFFEFederationRequest) (*SPIFFEFederation, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSPIFFEFederation not implemented") +} +func (UnimplementedSPIFFEFederationServiceServer) ListSPIFFEFederations(context.Context, *ListSPIFFEFederationsRequest) (*ListSPIFFEFederationsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListSPIFFEFederations not implemented") +} +func (UnimplementedSPIFFEFederationServiceServer) DeleteSPIFFEFederation(context.Context, *DeleteSPIFFEFederationRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSPIFFEFederation not implemented") +} +func (UnimplementedSPIFFEFederationServiceServer) CreateSPIFFEFederation(context.Context, *CreateSPIFFEFederationRequest) (*SPIFFEFederation, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateSPIFFEFederation not implemented") +} +func (UnimplementedSPIFFEFederationServiceServer) mustEmbedUnimplementedSPIFFEFederationServiceServer() { +} + +// UnsafeSPIFFEFederationServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SPIFFEFederationServiceServer will +// result in compilation errors. +type UnsafeSPIFFEFederationServiceServer interface { + mustEmbedUnimplementedSPIFFEFederationServiceServer() +} + +func RegisterSPIFFEFederationServiceServer(s grpc.ServiceRegistrar, srv SPIFFEFederationServiceServer) { + s.RegisterService(&SPIFFEFederationService_ServiceDesc, srv) +} + +func _SPIFFEFederationService_GetSPIFFEFederation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSPIFFEFederationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SPIFFEFederationServiceServer).GetSPIFFEFederation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SPIFFEFederationService_GetSPIFFEFederation_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SPIFFEFederationServiceServer).GetSPIFFEFederation(ctx, req.(*GetSPIFFEFederationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SPIFFEFederationService_ListSPIFFEFederations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSPIFFEFederationsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SPIFFEFederationServiceServer).ListSPIFFEFederations(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SPIFFEFederationService_ListSPIFFEFederations_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SPIFFEFederationServiceServer).ListSPIFFEFederations(ctx, req.(*ListSPIFFEFederationsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SPIFFEFederationService_DeleteSPIFFEFederation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSPIFFEFederationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SPIFFEFederationServiceServer).DeleteSPIFFEFederation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SPIFFEFederationService_DeleteSPIFFEFederation_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SPIFFEFederationServiceServer).DeleteSPIFFEFederation(ctx, req.(*DeleteSPIFFEFederationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _SPIFFEFederationService_CreateSPIFFEFederation_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSPIFFEFederationRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SPIFFEFederationServiceServer).CreateSPIFFEFederation(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: SPIFFEFederationService_CreateSPIFFEFederation_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SPIFFEFederationServiceServer).CreateSPIFFEFederation(ctx, req.(*CreateSPIFFEFederationRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// SPIFFEFederationService_ServiceDesc is the grpc.ServiceDesc for SPIFFEFederationService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var SPIFFEFederationService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "teleport.machineid.v1.SPIFFEFederationService", + HandlerType: (*SPIFFEFederationServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetSPIFFEFederation", + Handler: _SPIFFEFederationService_GetSPIFFEFederation_Handler, + }, + { + MethodName: "ListSPIFFEFederations", + Handler: _SPIFFEFederationService_ListSPIFFEFederations_Handler, + }, + { + MethodName: "DeleteSPIFFEFederation", + Handler: _SPIFFEFederationService_DeleteSPIFFEFederation_Handler, + }, + { + MethodName: "CreateSPIFFEFederation", + Handler: _SPIFFEFederationService_CreateSPIFFEFederation_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "teleport/machineid/v1/federation_service.proto", +} diff --git a/api/proto/teleport/crownjewel/v1/crownjewel.proto b/api/proto/teleport/crownjewel/v1/crownjewel.proto index 170a7da8d8ea6..55c453a913e18 100644 --- a/api/proto/teleport/crownjewel/v1/crownjewel.proto +++ b/api/proto/teleport/crownjewel/v1/crownjewel.proto @@ -42,9 +42,13 @@ message CrownJewel { // CrownJewelSpec is the specification of a Crown Jewel. message CrownJewelSpec { // TeleportMatchers is a list of teleport matchers. + // DEPRECATED: Use query instead. repeated TeleportMatcher teleport_matchers = 1; // AWSMatchers is a list of AWS matchers. + // DEPRECATED: Use query instead. repeated AWSMatcher aws_matchers = 2; + // Query is a Access Graph query to match resources. + string query = 3; } // TeleportMatcher represents a matcher for Teleport resources. diff --git a/api/proto/teleport/integration/v1/awsoidc_service.proto b/api/proto/teleport/integration/v1/awsoidc_service.proto index 0c0813df5ad7f..583dc68a8fd2b 100644 --- a/api/proto/teleport/integration/v1/awsoidc_service.proto +++ b/api/proto/teleport/integration/v1/awsoidc_service.proto @@ -359,7 +359,8 @@ message DeployDatabaseServiceDeployment { message DeployDatabaseServiceResponse { // ClusterArn identifies the cluster where the deployment was made. string cluster_arn = 1; - // ClusterDashboardUrl is the URL for Amazon Web Console that links directly to the Amazon ECS Cluster. + // ClusterDashboardURL is a link to the Amazon ECS cluster dashboard or a + // specific cluster service if a single deployment was requested. string cluster_dashboard_url = 2; } diff --git a/api/proto/teleport/legacy/client/proto/authservice.proto b/api/proto/teleport/legacy/client/proto/authservice.proto index 9f5eeed357ed8..c2f9be76363ca 100644 --- a/api/proto/teleport/legacy/client/proto/authservice.proto +++ b/api/proto/teleport/legacy/client/proto/authservice.proto @@ -314,6 +314,8 @@ message RouteToApp { string AzureIdentity = 6 [(gogoproto.jsontag) = "azure_identity,omitempty"]; // GCPServiceAccount is the GCP service account to assume when accessing GCP API. string GCPServiceAccount = 7 [(gogoproto.jsontag) = "gcp_service_account,omitempty"]; + // URI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + string URI = 8 [(gogoproto.jsontag) = "uri,omitempty"]; } // GetUserRequest specifies parameters for the GetUser method. @@ -459,34 +461,31 @@ enum SupportType { // Features are auth server features. message Features { // Kubernetes enables Kubernetes Access product + // Deprecated remove in v18; leverage entitlements bool Kubernetes = 1 [(gogoproto.jsontag) = "kubernetes"]; // App enables Application Access product + // Deprecated remove in v18; leverage entitlements bool App = 2 [(gogoproto.jsontag) = "app"]; // DB enables database access product + // Deprecated remove in v18; leverage entitlements bool DB = 3 [(gogoproto.jsontag) = "db"]; // OIDC enables OIDC connectors + // Deprecated remove in v18; leverage entitlements bool OIDC = 4 [(gogoproto.jsontag) = "oidc"]; // SAML enables SAML connectors + // Deprecated remove in v18; leverage entitlements bool SAML = 5 [(gogoproto.jsontag) = "saml"]; // AccessControls enables FIPS access controls bool AccessControls = 6 [(gogoproto.jsontag) = "access_controls"]; - // Currently this flag is to gate actions from OSS clusters. - // - // Determining support for access request is currently determined by: - // 1) Enterprise + [Features.IdentityGovernanceSecurity] == true, new flag - // introduced with Enterprise Usage Based (EUB) product. - // 2) Enterprise + [Features.IsUsageBasedBilling] == false, legacy support - // where before EUB, it was unlimited. - // - // AdvancedAccessWorkflows is currently set to true for all - // enterprise editions (team, cloud, on-prem). Historically, access request - // was only available for enterprise cloud and enterprise on-prem. + // AdvancedAccessWorkflows is currently set to the value of the Cloud AccessRequests entitlement bool AdvancedAccessWorkflows = 7 [(gogoproto.jsontag) = "advanced_access_workflows"]; // Cloud enables some cloud-related features bool Cloud = 8 [(gogoproto.jsontag) = "cloud"]; // HSM enables PKCS#11 HSM support + // Deprecated remove in v18; leverage entitlements bool HSM = 9 [(gogoproto.jsontag) = "hsm"]; // Desktop enables desktop access product + // Deprecated remove in v18; leverage entitlements bool Desktop = 10 [(gogoproto.jsontag) = "desktop"]; reserved 11; // bool ModeratedSessions reserved 12; // bool MachineID @@ -500,17 +499,22 @@ message Features { // IsUsageBased enables some usage-based billing features bool IsUsageBased = 17 [(gogoproto.jsontag) = "is_usage_based"]; // Assist enables the Assistant feature + // Deprecated remove in v18; leverage entitlements bool Assist = 18 [(gogoproto.jsontag) = "assist"]; // DeviceTrust holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements DeviceTrustFeature DeviceTrust = 19 [(gogoproto.jsontag) = "device_trust,omitempty"]; // FeatureHiding enables hiding features from being discoverable for users who don't have the necessary permissions. + // Deprecated remove in v18; leverage entitlements bool FeatureHiding = 20 [(gogoproto.jsontag) = "feature_hiding,omitempty"]; // AccessRequests holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements AccessRequestsFeature AccessRequests = 21 [(gogoproto.jsontag) = "access_requests,omitempty"]; // CustomTheme holds the name of WebUI custom theme. string CustomTheme = 22 [(gogoproto.jsontag) = "custom_theme,omitempty"]; // IdentityGovernance indicates whether IGS related features are enabled: // access list, access request, access monitoring, device trust. + // Deprecated remove in v18; leverage entitlements bool IdentityGovernance = 23 [(gogoproto.jsontag) = "identity_governance,omitempty"]; // AccessGraph enables the usage of access graph. // NOTE: this is a legacy flag that is currently used to signal @@ -519,26 +523,46 @@ message Features { // TODO(justinas): remove this field once "TAG enabled" status is moved to a resource in the backend. bool AccessGraph = 24 [(gogoproto.jsontag) = "access_graph,omitempty"]; // AccessListFeature holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements AccessListFeature AccessList = 25 [(gogoproto.jsontag) = "access_list,omitempty"]; // AccessMonitoringFeature holds its namesake feature settings. + // Deprecated remove in v18; leverage entitlements for access and AccessMonitoringConfigured for enabled AccessMonitoringFeature AccessMonitoring = 26 [(gogoproto.jsontag) = "access_monitoring,omitempty"]; // ProductType describes the product being used. ProductType ProductType = 27 [(gogoproto.jsontag) = "product_type,omitempty"]; // Policy enables the Teleport Policy feature set. // At the time of writing, this includes Teleport Access Graph (TAG). + // Deprecated remove in v18; leverage entitlements PolicyFeature Policy = 28 [(gogoproto.jsontag) = "policy,omitempty"]; // Questionnaire indicates whether cluster users should get an onboarding questionnaire bool Questionnaire = 29 [(gogoproto.jsontag) = "questionnaire,omitempty"]; // IsStripeManaged indicates if the cluster billing is managed via Stripe bool IsStripeManaged = 30 [(gogoproto.jsontag) = "is_stripe_managed,omitempty"]; // ExternalAuditStorage indicates whether the EAS feature is enabled in the cluster. + // Deprecated remove in v18; leverage entitlements bool ExternalAuditStorage = 31 [(gogoproto.jsontag) = "external_audit_storage,omitempty"]; // SupportType indicates the type of the customer's support SupportType SupportType = 32 [(gogoproto.jsontag) = "support_type,omitempty"]; // JoinActiveSessions indicates whether joining active sessions via web UI is enabled + // Deprecated remove in v18; leverage entitlements bool JoinActiveSessions = 33 [(gogoproto.jsontag) = "join_active_sessions,omitempty"]; // MobileDeviceManagement indicates whether endpoint management (like Jamf Plugin) can be used in the cluster + // Deprecated remove in v18; leverage entitlements bool MobileDeviceManagement = 34 [(gogoproto.jsontag) = "mobile_device_management,omitempty"]; + // entitlements define a customer’s access to a specific features + map entitlements = 35; + // AccessMonitoringConfigured contributes to the enablement of access monitoring. + // NOTE: this flag is used to signal that Access Monitoring is *enabled* on a cluster. + // *Access* to the feature is gated on the `AccessMonitoring` entitlement. + bool AccessMonitoringConfigured = 36; +} + +// EntitlementInfo is the state and limits of a particular entitlement +message EntitlementInfo { + // enabled indicates the feature is 'on' if true + bool enabled = 1; + // limit indicates the allotted amount of use when limited + int32 limit = 2; } // DeviceTrustFeature holds the Device Trust feature general and usage-based @@ -788,6 +812,12 @@ message CreateAppSessionRequest { // An optional field, that when provided, the response will be validated and // the ID of the validated MFA device will be stored in session's certificate. MFAAuthenticateResponse MFAResponse = 8 [(gogoproto.jsontag) = "mfa_response,omitempty"]; + // AppName is the name of the application. + string AppName = 9 [(gogoproto.jsontag) = "app_name"]; + // URI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + string URI = 10 [(gogoproto.jsontag) = "uri"]; + // ClientAddr is a client (user's) address. + string ClientAddr = 11 [(gogoproto.jsontag) = "client_addr,omitempty"]; } // CreateAppSessionResponse contains the requested application web session. diff --git a/api/proto/teleport/legacy/types/events/events.proto b/api/proto/teleport/legacy/types/events/events.proto index 5d4d5a6306933..7f34701705bf1 100644 --- a/api/proto/teleport/legacy/types/events/events.proto +++ b/api/proto/teleport/legacy/types/events/events.proto @@ -4445,6 +4445,8 @@ message OneOf { events.IntegrationCreate IntegrationCreate = 165; events.IntegrationUpdate IntegrationUpdate = 166; events.IntegrationDelete IntegrationDelete = 167; + events.SPIFFEFederationCreate SPIFFEFederationCreate = 168; + events.SPIFFEFederationDelete SPIFFEFederationDelete = 169; } } @@ -4593,6 +4595,8 @@ message RouteToApp { string AzureIdentity = 6 [(gogoproto.jsontag) = "azure_identity,omitempty"]; // GCPServiceAccount is the GCP service account to assume when accessing GCP API. string GCPServiceAccount = 7 [(gogoproto.jsontag) = "gcp_service_account,omitempty"]; + // URI is the application URI. + string URI = 8 [(gogoproto.jsontag) = "uri,omitempty"]; } // RouteToDatabase combines parameters for database service routing information. @@ -6650,3 +6654,65 @@ message AccessGraphSettingsUpdate { (gogoproto.jsontag) = "" ]; } + +// SPIFFEFederationCreate is emitted when a SPIFFE federation is created. +message SPIFFEFederationCreate { + // Metadata is a common event metadata + Metadata Metadata = 1 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // ResourceMetadata is a common resource event metadata + ResourceMetadata Resource = 2 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // User is a common user event metadata + UserMetadata User = 3 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // ConnectionMetadata holds information about the connection + ConnectionMetadata Connection = 4 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; +} + +// SPIFFEFederationDelete is emitted when a SPIFFE federation is deleted. +message SPIFFEFederationDelete { + // Metadata is a common event metadata + Metadata Metadata = 1 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // ResourceMetadata is a common resource event metadata + ResourceMetadata Resource = 2 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // User is a common user event metadata + UserMetadata User = 3 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; + + // ConnectionMetadata holds information about the connection + ConnectionMetadata Connection = 4 [ + (gogoproto.nullable) = false, + (gogoproto.embed) = true, + (gogoproto.jsontag) = "" + ]; +} diff --git a/api/proto/teleport/legacy/types/types.proto b/api/proto/teleport/legacy/types/types.proto index c164db3a03c08..b7be2466b7301 100644 --- a/api/proto/teleport/legacy/types/types.proto +++ b/api/proto/teleport/legacy/types/types.proto @@ -3467,6 +3467,13 @@ message UserSpecV2 { LocalAuthSecrets LocalAuth = 9 [(gogoproto.jsontag) = "local_auth,omitempty"]; // TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. + // + // Note that SSO users are transient and thus may contain an empty + // TrustedDeviceIDs field, even though the user->device association exists + // under the Device Trust subsystem. Do not rely on this field to determine + // device associations or ownership, it exists for legacy/informative purposes + // only. + // // Managed by the Device Trust subsystem, avoid manual edits. repeated string TrustedDeviceIDs = 10 [(gogoproto.jsontag) = "trusted_device_ids,omitempty"]; } @@ -3903,9 +3910,6 @@ message WebSessionSpecV2 { // // If during login a device is required and DeviceWebToken is nil, then it's // likely the user needs to enroll their device to avoid impacting access. - // - // Transient, only set in certain situations (such as the initial session - // returned during login). TrustedDeviceRequirement TrustedDeviceRequirement = 14 [(gogoproto.jsontag) = "trusted_device_requirement,omitempty"]; } @@ -4409,6 +4413,8 @@ message MaxAge { message SSOClientRedirectSettings { // a list of hostnames allowed for https client redirect URLs repeated string allowed_https_hostnames = 1; + // a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + repeated string insecure_allowed_cidr_ranges = 2; } // OIDCAuthRequest is a request to authenticate with OIDC @@ -4755,6 +4761,9 @@ message GithubAuthRequest { teleport.attestation.v1.AttestationStatement attestation_statement = 16 [(gogoproto.jsontag) = "attestation_statement,omitempty"]; // ClientLoginIP specifies IP address of the client for login, it will be written to the user's certificates. string ClientLoginIP = 17 [(gogoproto.jsontag) = "client_login_ip,omitempty"]; + // ClientUserAgent is the user agent of the Web browser, used for issuing + // a DeviceWebToken. + string ClientUserAgent = 18 [(gogoproto.jsontag) = "client_user_agent,omitempty"]; } // SSOWarnings conveys a user-facing main message along with auxiliary warnings. diff --git a/api/proto/teleport/machineid/v1/federation.proto b/api/proto/teleport/machineid/v1/federation.proto new file mode 100644 index 0000000000000..f80eda451bec6 --- /dev/null +++ b/api/proto/teleport/machineid/v1/federation.proto @@ -0,0 +1,82 @@ +// Copyright 2024 Gravitational, Inc +// +// 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. + +syntax = "proto3"; + +package teleport.machineid.v1; + +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "teleport/header/v1/metadata.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1;machineidv1"; + +// SPIFFEFederation is a resource that represents the configuration of a trust +// domain federation. +message SPIFFEFederation { + // The kind of resource represented. + string kind = 1; + // Differentiates variations of the same kind. All resources should + // contain one, even if it is never populated. + string sub_kind = 2; + // The version of the resource being represented. + string version = 3; + // Common metadata that all resources share. + // Importantly, the name MUST match the name of the trust domain you federate + // with. + teleport.header.v1.Metadata metadata = 4; + // The configured properties of the trust domain federation + SPIFFEFederationSpec spec = 5; + // Fields that are set by the server as results of operations. These should + // not be modified by users. + SPIFFEFederationStatus status = 6; +} + +// SPIFFEFederationBundleSourceStatic is a static bundle source. It should be an +// option of last resort, as it requires manual updates. +message SPIFFEFederationBundleSourceStatic { + // The SPIFFE JWKS bundle. + string bundle = 1; +} + +// SPIFFEFederationBundleSourceHTTPSWeb is a bundle source that fetches the bundle +// from a HTTPS endpoint that is protected by a Web PKI certificate. +message SPIFFEFederationBundleSourceHTTPSWeb { + // The URL of the SPIFFE Bundle Endpoint. + string bundle_endpoint_url = 1; +} + +// SPIFFEFederationBundleSource configures how the federation bundle is sourced. +// Only one field can be set. +message SPIFFEFederationBundleSource { + SPIFFEFederationBundleSourceStatic static = 1; + SPIFFEFederationBundleSourceHTTPSWeb https_web = 2; +} + +// SPIFFEFederationSpec is the configuration of a trust domain federation. +message SPIFFEFederationSpec { + // The source of the federation bundle. + SPIFFEFederationBundleSource bundle_source = 1; +} + +// FederationStatus is the status of a trust domain federation. +message SPIFFEFederationStatus { + // The most recently fetched bundle from the federated trust domain. + string current_bundle = 1; + // The time that the most recently fetched bundle was obtained. + google.protobuf.Timestamp current_bundle_synced_at = 2; + // The duration that the current bundle suggests the next bundle should be + // refresh after. + google.protobuf.Duration current_bundle_refresh_hint = 3; +} diff --git a/api/proto/teleport/machineid/v1/federation_service.proto b/api/proto/teleport/machineid/v1/federation_service.proto new file mode 100644 index 0000000000000..18d0f3bf4ecbd --- /dev/null +++ b/api/proto/teleport/machineid/v1/federation_service.proto @@ -0,0 +1,76 @@ +// Copyright 2024 Gravitational, Inc +// +// 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. + +syntax = "proto3"; + +package teleport.machineid.v1; + +import "google/protobuf/empty.proto"; +import "teleport/machineid/v1/federation.proto"; + +option go_package = "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1;machineidv1"; + +// GetSPIFFEFederationRequest is the request message for GetSPIFFEFederation. +message GetSPIFFEFederationRequest { + // The name of the SPIFFEFederation resource to fetch. + string name = 1; +} + +// Request for ListSPIFFEFederations. +// +// Follows the pagination semantics of +// https://cloud.google.com/apis/design/standard_methods#list +message ListSPIFFEFederationsRequest { + // The maximum number of items to return. + // The server may impose a different page size at its discretion. + int32 page_size = 1; + // The page_token value returned from a previous ListSPIFFEFederations + // request, if any. + string page_token = 2; +} + +// ListSPIFFEFederationsResponse is the response message for ListSPIFFEFederations. +message ListSPIFFEFederationsResponse { + repeated SPIFFEFederation spiffe_federations = 1; + // Token to retrieve the next page of results, or empty if there are no + // more results exist. + string next_page_token = 2; +} + +// DeleteSPIFFEFederationRequest is the request message for DeleteSPIFFEFederation. +message DeleteSPIFFEFederationRequest { + // The name of the SPIFFEFederation resource to delete. + string name = 1; +} + +// CreateSPIFFEFederationRequest is the request message for CreateSPIFFEFederation. +message CreateSPIFFEFederationRequest { + // The SPIFFEFederation resource to create. + SPIFFEFederation spiffe_federation = 1; +} + +// SPIFFEFederationService provides methods to manage SPIFFE Federations +// between trust domains. +service SPIFFEFederationService { + // GetSPIFFEFederation returns a SPIFFEFederation resource by name. + rpc GetSPIFFEFederation(GetSPIFFEFederationRequest) returns (SPIFFEFederation); + // ListSPIFFEFederations returns a list of SPIFFEFederation resources. + // Follows the pagination semantics of + // https://cloud.google.com/apis/design/design_patterns#list_pagination + rpc ListSPIFFEFederations(ListSPIFFEFederationsRequest) returns (ListSPIFFEFederationsResponse); + // DeleteSPIFFEFederation deletes a SPIFFEFederation resource by name. + rpc DeleteSPIFFEFederation(DeleteSPIFFEFederationRequest) returns (google.protobuf.Empty); + // CreateSPIFFEFederation creates a SPIFFEFederation resource. + rpc CreateSPIFFEFederation(CreateSPIFFEFederationRequest) returns (SPIFFEFederation); +} diff --git a/api/types/constants.go b/api/types/constants.go index 4554879289890..4c3584e825513 100644 --- a/api/types/constants.go +++ b/api/types/constants.go @@ -65,6 +65,8 @@ const ( // KindBot is a Machine ID bot resource KindBot = "bot" + // KindSPIFFEFederation is a SPIFFE federation resource + KindSPIFFEFederation = "spiffe_federation" // KindHostCert is a host certificate KindHostCert = "host_cert" diff --git a/api/types/device.pb.go b/api/types/device.pb.go index a806da7d9cac3..f7ee7ccc77d0b 100644 --- a/api/types/device.pb.go +++ b/api/types/device.pb.go @@ -7,8 +7,8 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" - _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" diff --git a/api/types/discoveryconfig/discoveryconfig_test.go b/api/types/discoveryconfig/discoveryconfig_test.go index f9f0d252ac994..1f963a8fc21ab 100644 --- a/api/types/discoveryconfig/discoveryconfig_test.go +++ b/api/types/discoveryconfig/discoveryconfig_test.go @@ -245,6 +245,69 @@ func TestNewDiscoveryConfig(t *testing.T) { }, errCheck: require.NoError, }, + { + name: "tag aws sync with invalid region", + inMetadata: header.Metadata{ + Name: "my-first-dc", + }, + inSpec: Spec{ + DiscoveryGroup: "dg1", + AccessGraph: &types.AccessGraphSync{ + AWS: []*types.AccessGraphAWSSync{ + { + Integration: "1234", + AssumeRole: &types.AssumeRole{ + RoleARN: "arn:aws:iam::123456789012:role/teleport", + }, + Regions: []string{"us&-west-2"}, + }, + }, + }, + }, + errCheck: require.Error, + }, + { + name: "tag aws sync with empty region", + inMetadata: header.Metadata{ + Name: "my-first-dc", + }, + inSpec: Spec{ + DiscoveryGroup: "dg1", + AccessGraph: &types.AccessGraphSync{ + AWS: []*types.AccessGraphAWSSync{ + { + Integration: "1234", + AssumeRole: &types.AssumeRole{ + RoleARN: "arn:aws:iam::123456789012:role/teleport", + }, + Regions: []string{""}, + }, + }, + }, + }, + errCheck: require.Error, + }, + { + name: "tag aws sync with region not set", + inMetadata: header.Metadata{ + Name: "my-first-dc", + }, + inSpec: Spec{ + DiscoveryGroup: "dg1", + AccessGraph: &types.AccessGraphSync{ + AWS: []*types.AccessGraphAWSSync{ + { + Integration: "1234", + AssumeRole: &types.AssumeRole{ + RoleARN: "arn:aws:iam::123456789012:role/teleport", + }, + Regions: nil, + }, + }, + }, + }, + errCheck: require.Error, + }, { name: "fills in kube matcher default values", inMetadata: header.Metadata{ diff --git a/api/types/events/events.pb.go b/api/types/events/events.pb.go index c27fdfa78a682..ddc931d175370 100644 --- a/api/types/events/events.pb.go +++ b/api/types/events/events.pb.go @@ -7,14 +7,12 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" github_com_gravitational_teleport_api_types "github.com/gravitational/teleport/api/types" - types "github.com/gravitational/teleport/api/types" + types1 "github.com/gravitational/teleport/api/types" _ "github.com/gravitational/teleport/api/types/wrappers" github_com_gravitational_teleport_api_types_wrappers "github.com/gravitational/teleport/api/types/wrappers" - _ "google.golang.org/protobuf/types/known/structpb" - _ "google.golang.org/protobuf/types/known/timestamppb" - _ "google.golang.org/protobuf/types/known/wrapperspb" io "io" math "math" math_bits "math/bits" @@ -1173,10 +1171,10 @@ var xxx_messageInfo_AccessListReviewMetadata proto.InternalMessageInfo // LockMetadata contains common metadata for lock resource events. type LockMetadata struct { // Target describes the set of interactions that the lock applies to - Target types.LockTarget `protobuf:"bytes,4,opt,name=Target,proto3" json:"target"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Target types1.LockTarget `protobuf:"bytes,4,opt,name=Target,proto3" json:"target"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *LockMetadata) Reset() { *m = LockMetadata{} } @@ -4294,10 +4292,10 @@ type SAMLConnectorCreate struct { // User is a common user event metadata UserMetadata `protobuf:"bytes,3,opt,name=User,proto3,embedded=User" json:""` // Connector is the new SAML connector - Connector *types.SAMLConnectorV2 `protobuf:"bytes,4,opt,name=Connector,proto3" json:"connector"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Connector *types1.SAMLConnectorV2 `protobuf:"bytes,4,opt,name=Connector,proto3" json:"connector"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *SAMLConnectorCreate) Reset() { *m = SAMLConnectorCreate{} } @@ -4342,10 +4340,10 @@ type SAMLConnectorUpdate struct { // User is a common user event metadata UserMetadata `protobuf:"bytes,3,opt,name=User,proto3,embedded=User" json:""` // Connector is the updated SAML connector - Connector *types.SAMLConnectorV2 `protobuf:"bytes,4,opt,name=Connector,proto3" json:"connector"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Connector *types1.SAMLConnectorV2 `protobuf:"bytes,4,opt,name=Connector,proto3" json:"connector"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *SAMLConnectorUpdate) Reset() { *m = SAMLConnectorUpdate{} } @@ -6195,7 +6193,7 @@ type LockCreate struct { UserMetadata `protobuf:"bytes,3,opt,name=User,proto3,embedded=User" json:""` // Target describes the set of interactions that the lock applies to // Deprecated: use Lock instead. - Target types.LockTarget `protobuf:"bytes,4,opt,name=Target,proto3" json:"target"` // Deprecated: Do not use. + Target types1.LockTarget `protobuf:"bytes,4,opt,name=Target,proto3" json:"target"` // Deprecated: Do not use. // Lock is a common lock event metadata Lock LockMetadata `protobuf:"bytes,5,opt,name=Lock,proto3" json:"lock"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -7506,6 +7504,8 @@ type OneOf struct { // *OneOf_IntegrationCreate // *OneOf_IntegrationUpdate // *OneOf_IntegrationDelete + // *OneOf_SPIFFEFederationCreate + // *OneOf_SPIFFEFederationDelete Event isOneOf_Event `protobuf_oneof:"Event"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -8049,6 +8049,12 @@ type OneOf_IntegrationUpdate struct { type OneOf_IntegrationDelete struct { IntegrationDelete *IntegrationDelete `protobuf:"bytes,167,opt,name=IntegrationDelete,proto3,oneof" json:"IntegrationDelete,omitempty"` } +type OneOf_SPIFFEFederationCreate struct { + SPIFFEFederationCreate *SPIFFEFederationCreate `protobuf:"bytes,168,opt,name=SPIFFEFederationCreate,proto3,oneof" json:"SPIFFEFederationCreate,omitempty"` +} +type OneOf_SPIFFEFederationDelete struct { + SPIFFEFederationDelete *SPIFFEFederationDelete `protobuf:"bytes,169,opt,name=SPIFFEFederationDelete,proto3,oneof" json:"SPIFFEFederationDelete,omitempty"` +} func (*OneOf_UserLogin) isOneOf_Event() {} func (*OneOf_UserCreate) isOneOf_Event() {} @@ -8216,6 +8222,8 @@ func (*OneOf_AccessGraphSettingsUpdate) isOneOf_Event() {} func (*OneOf_IntegrationCreate) isOneOf_Event() {} func (*OneOf_IntegrationUpdate) isOneOf_Event() {} func (*OneOf_IntegrationDelete) isOneOf_Event() {} +func (*OneOf_SPIFFEFederationCreate) isOneOf_Event() {} +func (*OneOf_SPIFFEFederationDelete) isOneOf_Event() {} func (m *OneOf) GetEvent() isOneOf_Event { if m != nil { @@ -9386,6 +9394,20 @@ func (m *OneOf) GetIntegrationDelete() *IntegrationDelete { return nil } +func (m *OneOf) GetSPIFFEFederationCreate() *SPIFFEFederationCreate { + if x, ok := m.GetEvent().(*OneOf_SPIFFEFederationCreate); ok { + return x.SPIFFEFederationCreate + } + return nil +} + +func (m *OneOf) GetSPIFFEFederationDelete() *SPIFFEFederationDelete { + if x, ok := m.GetEvent().(*OneOf_SPIFFEFederationDelete); ok { + return x.SPIFFEFederationDelete + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*OneOf) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -9555,6 +9577,8 @@ func (*OneOf) XXX_OneofWrappers() []interface{} { (*OneOf_IntegrationCreate)(nil), (*OneOf_IntegrationUpdate)(nil), (*OneOf_IntegrationDelete)(nil), + (*OneOf_SPIFFEFederationCreate)(nil), + (*OneOf_SPIFFEFederationDelete)(nil), } } @@ -9781,7 +9805,9 @@ type RouteToApp struct { // AzureIdentity is the Azure identity ot assume when accessing Azure API. AzureIdentity string `protobuf:"bytes,6,opt,name=AzureIdentity,proto3" json:"azure_identity,omitempty"` // GCPServiceAccount is the GCP service account to assume when accessing GCP API. - GCPServiceAccount string `protobuf:"bytes,7,opt,name=GCPServiceAccount,proto3" json:"gcp_service_account,omitempty"` + GCPServiceAccount string `protobuf:"bytes,7,opt,name=GCPServiceAccount,proto3" json:"gcp_service_account,omitempty"` + // URI is the application URI. + URI string `protobuf:"bytes,8,opt,name=URI,proto3" json:"uri,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -13374,6 +13400,102 @@ func (m *AccessGraphSettingsUpdate) XXX_DiscardUnknown() { var xxx_messageInfo_AccessGraphSettingsUpdate proto.InternalMessageInfo +// SPIFFEFederationCreate is emitted when a SPIFFE federation is created. +type SPIFFEFederationCreate struct { + // Metadata is a common event metadata + Metadata `protobuf:"bytes,1,opt,name=Metadata,proto3,embedded=Metadata" json:""` + // ResourceMetadata is a common resource event metadata + ResourceMetadata `protobuf:"bytes,2,opt,name=Resource,proto3,embedded=Resource" json:""` + // User is a common user event metadata + UserMetadata `protobuf:"bytes,3,opt,name=User,proto3,embedded=User" json:""` + // ConnectionMetadata holds information about the connection + ConnectionMetadata `protobuf:"bytes,4,opt,name=Connection,proto3,embedded=Connection" json:""` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SPIFFEFederationCreate) Reset() { *m = SPIFFEFederationCreate{} } +func (m *SPIFFEFederationCreate) String() string { return proto.CompactTextString(m) } +func (*SPIFFEFederationCreate) ProtoMessage() {} +func (*SPIFFEFederationCreate) Descriptor() ([]byte, []int) { + return fileDescriptor_007ba1c3d6266d56, []int{209} +} +func (m *SPIFFEFederationCreate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SPIFFEFederationCreate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SPIFFEFederationCreate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SPIFFEFederationCreate) XXX_Merge(src proto.Message) { + xxx_messageInfo_SPIFFEFederationCreate.Merge(m, src) +} +func (m *SPIFFEFederationCreate) XXX_Size() int { + return m.Size() +} +func (m *SPIFFEFederationCreate) XXX_DiscardUnknown() { + xxx_messageInfo_SPIFFEFederationCreate.DiscardUnknown(m) +} + +var xxx_messageInfo_SPIFFEFederationCreate proto.InternalMessageInfo + +// SPIFFEFederationDelete is emitted when a SPIFFE federation is deleted. +type SPIFFEFederationDelete struct { + // Metadata is a common event metadata + Metadata `protobuf:"bytes,1,opt,name=Metadata,proto3,embedded=Metadata" json:""` + // ResourceMetadata is a common resource event metadata + ResourceMetadata `protobuf:"bytes,2,opt,name=Resource,proto3,embedded=Resource" json:""` + // User is a common user event metadata + UserMetadata `protobuf:"bytes,3,opt,name=User,proto3,embedded=User" json:""` + // ConnectionMetadata holds information about the connection + ConnectionMetadata `protobuf:"bytes,4,opt,name=Connection,proto3,embedded=Connection" json:""` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SPIFFEFederationDelete) Reset() { *m = SPIFFEFederationDelete{} } +func (m *SPIFFEFederationDelete) String() string { return proto.CompactTextString(m) } +func (*SPIFFEFederationDelete) ProtoMessage() {} +func (*SPIFFEFederationDelete) Descriptor() ([]byte, []int) { + return fileDescriptor_007ba1c3d6266d56, []int{210} +} +func (m *SPIFFEFederationDelete) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SPIFFEFederationDelete) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SPIFFEFederationDelete.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SPIFFEFederationDelete) XXX_Merge(src proto.Message) { + xxx_messageInfo_SPIFFEFederationDelete.Merge(m, src) +} +func (m *SPIFFEFederationDelete) XXX_Size() int { + return m.Size() +} +func (m *SPIFFEFederationDelete) XXX_DiscardUnknown() { + xxx_messageInfo_SPIFFEFederationDelete.DiscardUnknown(m) +} + +var xxx_messageInfo_SPIFFEFederationDelete proto.InternalMessageInfo + func init() { proto.RegisterEnum("events.UserKind", UserKind_name, UserKind_value) proto.RegisterEnum("events.EventAction", EventAction_name, EventAction_value) @@ -13607,6 +13729,8 @@ func init() { proto.RegisterType((*AccessPathChanged)(nil), "events.AccessPathChanged") proto.RegisterType((*SpannerRPC)(nil), "events.SpannerRPC") proto.RegisterType((*AccessGraphSettingsUpdate)(nil), "events.AccessGraphSettingsUpdate") + proto.RegisterType((*SPIFFEFederationCreate)(nil), "events.SPIFFEFederationCreate") + proto.RegisterType((*SPIFFEFederationDelete)(nil), "events.SPIFFEFederationDelete") } func init() { @@ -13614,982 +13738,986 @@ func init() { } var fileDescriptor_007ba1c3d6266d56 = []byte{ - // 15593 bytes of a gzipped FileDescriptorProto + // 15662 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6b, 0x74, 0x1c, 0xc9, 0x75, 0x18, 0x8c, 0x79, 0x60, 0x00, 0x5c, 0x3c, 0x08, 0x14, 0x5f, 0x4d, 0x2e, 0xc9, 0xd9, 0xed, 0xd5, 0x52, 0xe4, 0x6a, 0x97, 0xd4, 0x72, 0xb9, 0xbb, 0xda, 0x97, 0x76, 0x07, 0x18, 0x80, 0x98, 0x25, 0x5e, 0xdb, 0x03, 0x92, 0x5a, 0xbd, 0xc6, 0x8d, 0xe9, 0x02, 0xd0, 0xcb, 0x99, 0xee, 0x51, - 0x77, 0x0f, 0x41, 0xec, 0xf7, 0xb2, 0xfc, 0xf9, 0x21, 0xf9, 0x93, 0x64, 0x7d, 0x72, 0x6c, 0xd9, - 0xb1, 0x13, 0xcb, 0xaf, 0xc4, 0xf1, 0x71, 0xec, 0x38, 0xc9, 0xb1, 0xad, 0x38, 0x3a, 0xb1, 0xa3, - 0x3c, 0xd6, 0xd1, 0x71, 0x8e, 0xed, 0x24, 0x3e, 0x3e, 0x89, 0x03, 0x39, 0x4a, 0x9c, 0x1f, 0x38, - 0xc9, 0x89, 0x93, 0xe8, 0xc4, 0x8e, 0xe3, 0xe4, 0xe4, 0xd4, 0xad, 0xea, 0xee, 0xea, 0xc7, 0x0c, - 0x9e, 0x6b, 0x2c, 0x44, 0xfc, 0x21, 0x31, 0xf7, 0xde, 0xba, 0x55, 0x7d, 0xeb, 0x56, 0xd5, 0xad, - 0xaa, 0x5b, 0xf7, 0xc2, 0x65, 0x8f, 0x36, 0x68, 0xcb, 0x76, 0xbc, 0xab, 0x0d, 0xba, 0xa2, 0xd7, - 0xd7, 0xaf, 0x7a, 0xeb, 0x2d, 0xea, 0x5e, 0xa5, 0xf7, 0xa8, 0xe5, 0xf9, 0xff, 0x5d, 0x69, 0x39, - 0xb6, 0x67, 0x93, 0x02, 0xff, 0x75, 0xf6, 0xc4, 0x8a, 0xbd, 0x62, 0x23, 0xe8, 0x2a, 0xfb, 0x8b, - 0x63, 0xcf, 0x9e, 0x5b, 0xb1, 0xed, 0x95, 0x06, 0xbd, 0x8a, 0xbf, 0x96, 0xda, 0xcb, 0x57, 0x5d, - 0xcf, 0x69, 0xd7, 0x3d, 0x81, 0x2d, 0xc6, 0xb1, 0x9e, 0xd9, 0xa4, 0xae, 0xa7, 0x37, 0x5b, 0x82, - 0xe0, 0x42, 0x9c, 0x60, 0xcd, 0xd1, 0x5b, 0x2d, 0xea, 0x88, 0xca, 0xcf, 0x3e, 0x92, 0xde, 0x4e, - 0xfc, 0x57, 0x90, 0x3c, 0x99, 0x4e, 0xe2, 0x33, 0x8a, 0x71, 0x54, 0xbf, 0x90, 0x85, 0xfe, 0x59, - 0xea, 0xe9, 0x86, 0xee, 0xe9, 0xe4, 0x1c, 0xf4, 0x56, 0x2c, 0x83, 0xde, 0x57, 0x32, 0x0f, 0x67, - 0x2e, 0xe5, 0xc6, 0x0b, 0x9b, 0x1b, 0xc5, 0x2c, 0x35, 0x35, 0x0e, 0x24, 0xe7, 0x21, 0xbf, 0xb8, - 0xde, 0xa2, 0x4a, 0xf6, 0xe1, 0xcc, 0xa5, 0x81, 0xf1, 0x81, 0xcd, 0x8d, 0x62, 0x2f, 0xca, 0x42, - 0x43, 0x30, 0x79, 0x04, 0xb2, 0x95, 0xb2, 0x92, 0x43, 0xe4, 0xd8, 0xe6, 0x46, 0x71, 0xb8, 0x6d, - 0x1a, 0x4f, 0xd8, 0x4d, 0xd3, 0xa3, 0xcd, 0x96, 0xb7, 0xae, 0x65, 0x2b, 0x65, 0x72, 0x11, 0xf2, - 0x13, 0xb6, 0x41, 0x95, 0x3c, 0x12, 0x91, 0xcd, 0x8d, 0xe2, 0x48, 0xdd, 0x36, 0xa8, 0x44, 0x85, - 0x78, 0xf2, 0x2a, 0xe4, 0x17, 0xcd, 0x26, 0x55, 0x7a, 0x1f, 0xce, 0x5c, 0x1a, 0xbc, 0x76, 0xf6, - 0x0a, 0x97, 0xca, 0x15, 0x5f, 0x2a, 0x57, 0x16, 0x7d, 0xb1, 0x8d, 0x8f, 0xbe, 0xbd, 0x51, 0xec, - 0xd9, 0xdc, 0x28, 0xe6, 0x99, 0x24, 0x3f, 0xff, 0xf5, 0x62, 0x46, 0xc3, 0x92, 0xe4, 0x25, 0x18, - 0x9c, 0x68, 0xb4, 0x5d, 0x8f, 0x3a, 0x73, 0x7a, 0x93, 0x2a, 0x05, 0xac, 0xf0, 0xec, 0xe6, 0x46, - 0xf1, 0x54, 0x9d, 0x83, 0x6b, 0x96, 0xde, 0x94, 0x2b, 0x96, 0xc9, 0xd5, 0x5f, 0xc9, 0xc0, 0xb1, - 0x2a, 0x75, 0x5d, 0xd3, 0xb6, 0x02, 0xd9, 0x3c, 0x06, 0x03, 0x02, 0x54, 0x29, 0xa3, 0x7c, 0x06, - 0xc6, 0xfb, 0x36, 0x37, 0x8a, 0x39, 0xd7, 0x34, 0xb4, 0x10, 0x43, 0xde, 0x0f, 0x7d, 0x77, 0x4c, - 0x6f, 0x75, 0x76, 0xaa, 0x24, 0xe4, 0x74, 0x6a, 0x73, 0xa3, 0x48, 0xd6, 0x4c, 0x6f, 0xb5, 0xd6, - 0x5c, 0xd6, 0xa5, 0x0a, 0x7d, 0x32, 0x32, 0x03, 0xa3, 0x0b, 0x8e, 0x79, 0x4f, 0xf7, 0xe8, 0x4d, - 0xba, 0xbe, 0x60, 0x37, 0xcc, 0xfa, 0xba, 0x90, 0xe2, 0xc3, 0x9b, 0x1b, 0xc5, 0x73, 0x2d, 0x8e, - 0xab, 0xdd, 0xa5, 0xeb, 0xb5, 0x16, 0x62, 0x25, 0x26, 0x89, 0x92, 0xea, 0x57, 0x7b, 0x61, 0xe8, - 0x96, 0x4b, 0x9d, 0xa0, 0xdd, 0x17, 0x21, 0xcf, 0x7e, 0x8b, 0x26, 0xa3, 0xcc, 0xdb, 0x2e, 0x75, - 0x64, 0x99, 0x33, 0x3c, 0xb9, 0x0c, 0xbd, 0x33, 0xf6, 0x8a, 0x69, 0x89, 0x66, 0x1f, 0xdf, 0xdc, - 0x28, 0x1e, 0x6b, 0x30, 0x80, 0x44, 0xc9, 0x29, 0xc8, 0x07, 0x61, 0xa8, 0xd2, 0x64, 0x3a, 0x64, - 0x5b, 0xba, 0x67, 0x3b, 0xa2, 0xb5, 0x28, 0x5d, 0x53, 0x82, 0x4b, 0x05, 0x23, 0xf4, 0xe4, 0x05, - 0x80, 0xd2, 0x9d, 0xaa, 0x66, 0x37, 0x68, 0x49, 0x9b, 0x13, 0xca, 0x80, 0xa5, 0xf5, 0x35, 0xb7, - 0xe6, 0xd8, 0x0d, 0x5a, 0xd3, 0x1d, 0xb9, 0x5a, 0x89, 0x9a, 0x4c, 0xc2, 0x48, 0xa9, 0x5e, 0xa7, - 0xae, 0xab, 0xd1, 0x4f, 0xb4, 0xa9, 0xeb, 0xb9, 0x4a, 0xef, 0xc3, 0xb9, 0x4b, 0x03, 0xe3, 0xe7, - 0x37, 0x37, 0x8a, 0x67, 0x74, 0xc4, 0xd4, 0x1c, 0x81, 0x92, 0x58, 0xc4, 0x0a, 0x91, 0x71, 0x18, - 0x2e, 0xbd, 0xd5, 0x76, 0x68, 0xc5, 0xa0, 0x96, 0x67, 0x7a, 0xeb, 0x42, 0x43, 0xce, 0x6d, 0x6e, - 0x14, 0x15, 0x9d, 0x21, 0x6a, 0xa6, 0xc0, 0x48, 0x4c, 0xa2, 0x45, 0xc8, 0x3c, 0x8c, 0xdd, 0x98, - 0x58, 0xa8, 0x52, 0xe7, 0x9e, 0x59, 0xa7, 0xa5, 0x7a, 0xdd, 0x6e, 0x5b, 0x9e, 0xd2, 0x87, 0x7c, - 0x1e, 0xd9, 0xdc, 0x28, 0x9e, 0x5f, 0xa9, 0xb7, 0x6a, 0x2e, 0xc7, 0xd6, 0x74, 0x8e, 0x96, 0x98, - 0x25, 0xcb, 0x92, 0x0f, 0xc3, 0xf0, 0xa2, 0xc3, 0xb4, 0xd0, 0x28, 0x53, 0x06, 0x57, 0xfa, 0x51, - 0xff, 0x4f, 0x5d, 0x11, 0x13, 0x10, 0x87, 0xfa, 0x3d, 0xcb, 0x1b, 0xeb, 0xf1, 0x02, 0x35, 0x03, - 0x71, 0x72, 0x63, 0x23, 0xac, 0x08, 0x05, 0x85, 0x7d, 0xbc, 0xe9, 0x50, 0x23, 0xa1, 0x6d, 0x03, - 0xd8, 0xe6, 0xcb, 0x9b, 0x1b, 0xc5, 0xc7, 0x1c, 0x41, 0x53, 0xeb, 0xaa, 0x76, 0x1d, 0x59, 0x91, - 0x49, 0xe8, 0x67, 0xda, 0x74, 0xd3, 0xb4, 0x0c, 0x05, 0x1e, 0xce, 0x5c, 0x1a, 0xb9, 0x36, 0xea, - 0xb7, 0xde, 0x87, 0x8f, 0x9f, 0xde, 0xdc, 0x28, 0x1e, 0x67, 0x3a, 0x58, 0xbb, 0x6b, 0x5a, 0xf2, - 0x14, 0x11, 0x14, 0x55, 0xff, 0x38, 0x0f, 0x23, 0x4c, 0x38, 0x92, 0x1e, 0x97, 0xd8, 0x90, 0x64, - 0x10, 0x36, 0x42, 0xdd, 0x96, 0x5e, 0xa7, 0x42, 0xa5, 0x91, 0x9d, 0xe5, 0x03, 0x25, 0x76, 0x71, - 0x7a, 0x72, 0x19, 0xfa, 0x39, 0xa8, 0x52, 0x16, 0x5a, 0x3e, 0xbc, 0xb9, 0x51, 0x1c, 0x70, 0x11, - 0x56, 0x33, 0x0d, 0x2d, 0x40, 0x33, 0x35, 0xe3, 0x7f, 0x4f, 0xdb, 0xae, 0xc7, 0x98, 0x0b, 0x25, - 0x47, 0x35, 0x13, 0x05, 0x56, 0x05, 0x4a, 0x56, 0xb3, 0x68, 0x21, 0xf2, 0x3c, 0x00, 0x87, 0x94, - 0x0c, 0xc3, 0x11, 0x9a, 0x7e, 0x66, 0x73, 0xa3, 0x78, 0x52, 0xb0, 0xd0, 0x0d, 0x43, 0x1e, 0x26, - 0x12, 0x31, 0x69, 0xc2, 0x10, 0xff, 0x35, 0xa3, 0x2f, 0xd1, 0x06, 0x57, 0xf3, 0xc1, 0x6b, 0x97, - 0x7c, 0x69, 0x46, 0xa5, 0x73, 0x45, 0x26, 0x9d, 0xb4, 0x3c, 0x67, 0x7d, 0xbc, 0x28, 0x66, 0xc6, - 0xd3, 0xa2, 0xaa, 0x06, 0xe2, 0xe4, 0x31, 0x29, 0x97, 0x61, 0x13, 0xe6, 0x94, 0xed, 0xac, 0xe9, - 0x8e, 0x41, 0x8d, 0xf1, 0x75, 0x79, 0xc2, 0x5c, 0xf6, 0xc1, 0xb5, 0x25, 0x59, 0x07, 0x64, 0x72, - 0x32, 0x01, 0xc3, 0x9c, 0x5b, 0xb5, 0xbd, 0x84, 0x7d, 0xdf, 0x97, 0x90, 0x96, 0xdb, 0x5e, 0x8a, - 0xf7, 0x77, 0xb4, 0x0c, 0x1b, 0x93, 0x1c, 0x70, 0x9b, 0x3a, 0x6c, 0x36, 0x45, 0xf5, 0x17, 0x63, - 0x52, 0x30, 0xb9, 0xc7, 0x31, 0x49, 0x1e, 0xa2, 0xc8, 0xd9, 0x57, 0x60, 0x2c, 0x21, 0x0a, 0x32, - 0x0a, 0xb9, 0xbb, 0x74, 0x9d, 0xab, 0x8b, 0xc6, 0xfe, 0x24, 0x27, 0xa0, 0xf7, 0x9e, 0xde, 0x68, - 0x8b, 0xb5, 0x4c, 0xe3, 0x3f, 0x5e, 0xc8, 0x7e, 0x20, 0xc3, 0xa6, 0x7e, 0x32, 0x61, 0x5b, 0x16, - 0xad, 0x7b, 0xf2, 0xec, 0xff, 0x2c, 0x0c, 0xcc, 0xd8, 0x75, 0xbd, 0x81, 0xfd, 0xc8, 0xf5, 0x4e, - 0xd9, 0xdc, 0x28, 0x9e, 0x60, 0x1d, 0x78, 0xa5, 0xc1, 0x30, 0x52, 0x9b, 0x42, 0x52, 0xa6, 0x00, - 0x1a, 0x6d, 0xda, 0x1e, 0xc5, 0x82, 0xd9, 0x50, 0x01, 0xb0, 0xa0, 0x83, 0x28, 0x59, 0x01, 0x42, - 0x62, 0x72, 0x15, 0xfa, 0x17, 0xd8, 0x82, 0x57, 0xb7, 0x1b, 0x42, 0xf9, 0x70, 0x4e, 0xc6, 0x45, - 0x50, 0x1e, 0x34, 0x3e, 0x91, 0x3a, 0x0d, 0x23, 0x13, 0x0d, 0x93, 0x5a, 0x9e, 0xdc, 0x6a, 0x36, - 0xa4, 0x4a, 0x2b, 0xd4, 0xf2, 0xe4, 0x56, 0xe3, 0xe0, 0xd3, 0x19, 0x54, 0x6e, 0x75, 0x40, 0xaa, - 0xfe, 0xd3, 0x1c, 0x9c, 0xb9, 0xd9, 0x5e, 0xa2, 0x8e, 0x45, 0x3d, 0xea, 0x8a, 0x95, 0x31, 0xe0, - 0x3a, 0x07, 0x63, 0x09, 0xa4, 0xe0, 0x8e, 0x2b, 0xd6, 0xdd, 0x00, 0x59, 0x13, 0x8b, 0xad, 0x3c, - 0xed, 0x25, 0x8a, 0x92, 0x69, 0x38, 0x16, 0x02, 0x59, 0x23, 0x5c, 0x25, 0x8b, 0x73, 0xfa, 0x85, - 0xcd, 0x8d, 0xe2, 0x59, 0x89, 0x1b, 0x6b, 0xb6, 0xac, 0xc1, 0xf1, 0x62, 0xe4, 0x26, 0x8c, 0x86, - 0xa0, 0x1b, 0x8e, 0xdd, 0x6e, 0xb9, 0x4a, 0x0e, 0x59, 0x15, 0x37, 0x37, 0x8a, 0x0f, 0x49, 0xac, - 0x56, 0x10, 0x29, 0xaf, 0xa4, 0xf1, 0x82, 0xe4, 0x3b, 0x33, 0x32, 0x37, 0x31, 0x0a, 0xf3, 0x38, - 0x0a, 0x9f, 0xf3, 0x47, 0x61, 0x47, 0x21, 0x5d, 0x89, 0x97, 0x14, 0x83, 0x32, 0xd6, 0x8c, 0xc4, - 0xa0, 0x4c, 0xd4, 0x78, 0x76, 0x02, 0x4e, 0xa6, 0xf2, 0xda, 0x91, 0x56, 0xff, 0x61, 0x4e, 0xe6, - 0xb2, 0x60, 0x1b, 0x41, 0x67, 0xce, 0xcb, 0x9d, 0xb9, 0x60, 0x1b, 0x68, 0x2e, 0x65, 0xc2, 0x45, - 0x4c, 0x6a, 0x6c, 0xcb, 0x36, 0xe2, 0x56, 0x53, 0xb2, 0x2c, 0xf9, 0x38, 0x9c, 0x4a, 0x00, 0xf9, - 0x74, 0xcd, 0xb5, 0xff, 0xe2, 0xe6, 0x46, 0x51, 0x4d, 0xe1, 0x1a, 0x9f, 0xbd, 0x3b, 0x70, 0x21, - 0x3a, 0x9c, 0x96, 0xa4, 0x6e, 0x5b, 0x9e, 0x6e, 0x5a, 0xc2, 0xca, 0xe3, 0xa3, 0xe4, 0xbd, 0x9b, - 0x1b, 0xc5, 0x47, 0x65, 0x1d, 0xf4, 0x69, 0xe2, 0x8d, 0xef, 0xc4, 0x87, 0x18, 0xa0, 0xa4, 0xa0, - 0x2a, 0x4d, 0x7d, 0xc5, 0x37, 0x5d, 0x2f, 0x6d, 0x6e, 0x14, 0xdf, 0x93, 0x5a, 0x87, 0xc9, 0xa8, - 0xe4, 0xa5, 0xb2, 0x13, 0x27, 0xa2, 0x01, 0x09, 0x71, 0x73, 0xb6, 0x41, 0xf1, 0x1b, 0x7a, 0x91, - 0xbf, 0xba, 0xb9, 0x51, 0xbc, 0x20, 0xf1, 0xb7, 0x6c, 0x83, 0xc6, 0x9b, 0x9f, 0x52, 0x5a, 0xfd, - 0x95, 0x1c, 0x5c, 0xa8, 0x96, 0x66, 0x67, 0x2a, 0x86, 0x6f, 0x5b, 0x2c, 0x38, 0xf6, 0x3d, 0xd3, - 0x90, 0x46, 0xef, 0x12, 0x9c, 0x8e, 0xa1, 0x26, 0xd1, 0x9c, 0x09, 0xac, 0x5a, 0xfc, 0x36, 0xdf, - 0x6e, 0x69, 0x09, 0x9a, 0x1a, 0xb7, 0x79, 0x6a, 0x11, 0x93, 0xbe, 0x13, 0x23, 0xd6, 0x47, 0x31, - 0x54, 0x75, 0xd5, 0x76, 0xbc, 0x7a, 0xdb, 0x13, 0x4a, 0x80, 0x7d, 0x94, 0xa8, 0xc3, 0x15, 0x44, - 0x5d, 0xaa, 0xf0, 0xf9, 0x90, 0x4f, 0x67, 0x60, 0xb4, 0xe4, 0x79, 0x8e, 0xb9, 0xd4, 0xf6, 0xe8, - 0xac, 0xde, 0x6a, 0x99, 0xd6, 0x0a, 0x8e, 0xf5, 0xc1, 0x6b, 0x2f, 0x05, 0x6b, 0x64, 0x57, 0x49, - 0x5c, 0x89, 0x17, 0x97, 0x86, 0xa8, 0xee, 0xa3, 0x6a, 0x4d, 0x8e, 0x93, 0x87, 0x68, 0xbc, 0x1c, - 0x1b, 0xa2, 0xa9, 0xbc, 0x76, 0x34, 0x44, 0xbf, 0x90, 0x83, 0x73, 0xf3, 0x77, 0x3d, 0x5d, 0xa3, - 0xae, 0xdd, 0x76, 0xea, 0xd4, 0xbd, 0xd5, 0x32, 0x74, 0x8f, 0x86, 0x23, 0xb5, 0x08, 0xbd, 0x25, - 0xc3, 0xa0, 0x06, 0xb2, 0xeb, 0xe5, 0xfb, 0x2f, 0x9d, 0x01, 0x34, 0x0e, 0x27, 0x8f, 0x41, 0x9f, - 0x28, 0x83, 0xdc, 0x7b, 0xc7, 0x07, 0x37, 0x37, 0x8a, 0x7d, 0x6d, 0x0e, 0xd2, 0x7c, 0x1c, 0x23, - 0x2b, 0xd3, 0x06, 0x65, 0x64, 0xb9, 0x90, 0xcc, 0xe0, 0x20, 0xcd, 0xc7, 0x91, 0xd7, 0x61, 0x04, - 0xd9, 0x06, 0xed, 0x11, 0x73, 0xdf, 0x09, 0x5f, 0xba, 0x72, 0x63, 0xf9, 0xd2, 0x84, 0xad, 0xa9, - 0x39, 0x7e, 0x01, 0x2d, 0xc6, 0x80, 0xdc, 0x81, 0x51, 0xd1, 0x88, 0x90, 0x69, 0x6f, 0x17, 0xa6, - 0x27, 0x37, 0x37, 0x8a, 0x63, 0xa2, 0xfd, 0x12, 0xdb, 0x04, 0x13, 0xc6, 0x58, 0x34, 0x3b, 0x64, - 0x5c, 0xd8, 0x8a, 0xb1, 0xf8, 0x62, 0x99, 0x71, 0x9c, 0x89, 0xfa, 0x06, 0x0c, 0xc9, 0x05, 0xc9, - 0x29, 0xdc, 0xe3, 0xf2, 0x71, 0x82, 0xbb, 0x63, 0xd3, 0xc0, 0x8d, 0xed, 0x53, 0x30, 0x58, 0xa6, - 0x6e, 0xdd, 0x31, 0x5b, 0xcc, 0x6a, 0x10, 0x4a, 0x7e, 0x6c, 0x73, 0xa3, 0x38, 0x68, 0x84, 0x60, - 0x4d, 0xa6, 0x51, 0xff, 0x5b, 0x06, 0x4e, 0x31, 0xde, 0x25, 0xd7, 0x35, 0x57, 0xac, 0xa6, 0xbc, - 0x6c, 0x3f, 0x01, 0x85, 0x2a, 0xd6, 0x27, 0x6a, 0x3a, 0xb1, 0xb9, 0x51, 0x1c, 0xe5, 0x2d, 0x90, - 0xf4, 0x50, 0xd0, 0x04, 0x1b, 0xbc, 0xec, 0x16, 0x1b, 0x3c, 0x66, 0xd2, 0x7a, 0xba, 0xe3, 0x99, - 0xd6, 0x4a, 0xd5, 0xd3, 0xbd, 0xb6, 0x1b, 0x31, 0x69, 0x05, 0xa6, 0xe6, 0x22, 0x2a, 0x62, 0xd2, - 0x46, 0x0a, 0x91, 0x57, 0x60, 0x68, 0xd2, 0x32, 0x42, 0x26, 0x7c, 0x42, 0x7c, 0x88, 0x59, 0x9a, - 0x14, 0xe1, 0x49, 0x16, 0x91, 0x02, 0xea, 0x5f, 0xcf, 0x80, 0xc2, 0x77, 0x63, 0x33, 0xa6, 0xeb, - 0xcd, 0xd2, 0xe6, 0x92, 0x34, 0x3b, 0x4d, 0xf9, 0xdb, 0x3b, 0x86, 0x93, 0xd6, 0x22, 0x34, 0x05, - 0xc4, 0xf6, 0xae, 0x61, 0xba, 0x5e, 0x7c, 0x32, 0x8c, 0x95, 0x22, 0x15, 0xe8, 0xe3, 0x9c, 0xb9, - 0x2d, 0x31, 0x78, 0x4d, 0xf1, 0x15, 0x21, 0x5e, 0x35, 0x57, 0x86, 0x26, 0x27, 0x96, 0xf7, 0xe7, - 0xa2, 0xbc, 0xfa, 0x37, 0xb2, 0x30, 0x1a, 0x2f, 0x44, 0xee, 0x40, 0xff, 0x6b, 0xb6, 0x69, 0x51, - 0x63, 0xde, 0xc2, 0x16, 0x76, 0x3f, 0xa5, 0xf0, 0x6d, 0xf1, 0xe3, 0x6f, 0x62, 0x99, 0x9a, 0x6c, - 0xc1, 0xe2, 0xa1, 0x45, 0xc0, 0x8c, 0x7c, 0x18, 0x06, 0x98, 0x0d, 0x78, 0x0f, 0x39, 0x67, 0xb7, - 0xe4, 0xfc, 0xb0, 0xe0, 0x7c, 0xc2, 0xe1, 0x85, 0x92, 0xac, 0x43, 0x76, 0x4c, 0xaf, 0x34, 0xaa, - 0xbb, 0xb6, 0x25, 0x7a, 0x1e, 0xf5, 0xca, 0x41, 0x88, 0xac, 0x57, 0x9c, 0x86, 0x99, 0xae, 0xfc, - 0x63, 0xb1, 0x1b, 0xa4, 0xbd, 0x0b, 0x97, 0x55, 0xbc, 0x07, 0x24, 0x62, 0xf5, 0xbb, 0xb3, 0xf0, - 0x64, 0x28, 0x32, 0x8d, 0xde, 0x33, 0xe9, 0x9a, 0x10, 0xe7, 0xaa, 0xd9, 0x12, 0x9b, 0x47, 0xa6, - 0xf2, 0xee, 0xc4, 0xaa, 0x6e, 0xad, 0x50, 0x83, 0x5c, 0x86, 0x5e, 0xb6, 0xc3, 0x77, 0x95, 0x0c, - 0x9a, 0x6b, 0x38, 0x9d, 0x38, 0x0c, 0x20, 0x9f, 0x3e, 0x20, 0x05, 0xb1, 0xa1, 0xb0, 0xe8, 0xe8, - 0xa6, 0xe7, 0xf7, 0x6c, 0x29, 0xd9, 0xb3, 0xdb, 0xa8, 0xf1, 0x0a, 0xe7, 0xc1, 0xe7, 0x7c, 0x14, - 0x84, 0x87, 0x00, 0x59, 0x10, 0x9c, 0xe4, 0xec, 0xf3, 0x30, 0x28, 0x11, 0xef, 0x68, 0x52, 0xff, - 0x72, 0x5e, 0xd6, 0x75, 0xbf, 0x59, 0x42, 0xd7, 0xaf, 0x32, 0x1d, 0x75, 0x5d, 0x66, 0x55, 0x70, - 0x25, 0x17, 0x9a, 0x88, 0xa0, 0xa8, 0x26, 0x22, 0x88, 0x3c, 0x0d, 0xfd, 0x9c, 0x45, 0xb0, 0x7f, - 0xc5, 0xbd, 0xaf, 0x83, 0xb0, 0xe8, 0xd2, 0x1c, 0x10, 0x92, 0x9f, 0xcd, 0xc0, 0xf9, 0xae, 0x92, - 0x40, 0x65, 0x18, 0xbc, 0xf6, 0xcc, 0xae, 0xc4, 0x38, 0xfe, 0xe4, 0xe6, 0x46, 0xf1, 0x72, 0x33, - 0x20, 0xa9, 0x39, 0x12, 0x4d, 0xad, 0xce, 0x89, 0xa4, 0x76, 0x75, 0x6f, 0x0a, 0x33, 0x1e, 0x79, - 0xa5, 0x53, 0x78, 0x86, 0x63, 0xd5, 0xd7, 0xfd, 0x46, 0xe6, 0x43, 0xe3, 0x51, 0x7c, 0xef, 0xb2, - 0x4f, 0x92, 0x52, 0x4d, 0x07, 0x2e, 0xa4, 0x0e, 0xa7, 0x39, 0xa6, 0xac, 0xaf, 0xcf, 0x2f, 0xcf, - 0xda, 0x96, 0xb7, 0xea, 0x57, 0xd0, 0x2b, 0x1f, 0x82, 0x60, 0x05, 0x86, 0xbe, 0x5e, 0xb3, 0x97, - 0x6b, 0x4d, 0x46, 0x95, 0x52, 0x47, 0x27, 0x4e, 0x6c, 0xa2, 0x15, 0x63, 0xce, 0x9f, 0x82, 0x0a, - 0xe1, 0x11, 0x95, 0x3f, 0x4e, 0x93, 0x13, 0x4e, 0xac, 0x90, 0x5a, 0x81, 0xa1, 0x19, 0xbb, 0x7e, - 0x37, 0x50, 0x97, 0xe7, 0xa1, 0xb0, 0xa8, 0x3b, 0x2b, 0xd4, 0x43, 0x59, 0x0c, 0x5e, 0x1b, 0xbb, - 0xc2, 0x8f, 0x7d, 0x19, 0x11, 0x47, 0x8c, 0x8f, 0x88, 0xd9, 0xa0, 0xe0, 0xe1, 0x6f, 0x4d, 0x14, - 0x50, 0xbf, 0xde, 0x0b, 0x43, 0xe2, 0x88, 0x12, 0x67, 0x73, 0xf2, 0x42, 0x78, 0xe8, 0x2b, 0xa6, - 0xaf, 0xe0, 0x98, 0x26, 0x38, 0x5e, 0x1a, 0x62, 0xcc, 0x7e, 0x6b, 0xa3, 0x98, 0xd9, 0xdc, 0x28, - 0xf6, 0x68, 0xfd, 0xd2, 0xa6, 0x32, 0x5c, 0x6f, 0xa4, 0x05, 0x56, 0x3e, 0x74, 0x8c, 0x95, 0xe5, - 0xeb, 0xcf, 0x2b, 0xd0, 0x27, 0xda, 0x20, 0x34, 0xee, 0x74, 0x78, 0x96, 0x11, 0x39, 0x6a, 0x8d, - 0x95, 0xf6, 0x4b, 0x91, 0x97, 0xa0, 0xc0, 0xf7, 0xf6, 0x42, 0x00, 0xa7, 0xd2, 0xcf, 0x42, 0x62, - 0xc5, 0x45, 0x19, 0x32, 0x0d, 0x10, 0xee, 0xeb, 0x83, 0x93, 0x65, 0xc1, 0x21, 0xb9, 0xe3, 0x8f, - 0x71, 0x91, 0xca, 0x92, 0x67, 0x61, 0x68, 0x91, 0x3a, 0x4d, 0xd3, 0xd2, 0x1b, 0x55, 0xf3, 0x2d, - 0xff, 0x70, 0x19, 0x17, 0x5e, 0xd7, 0x7c, 0x4b, 0x1e, 0xb9, 0x11, 0x3a, 0xf2, 0xb1, 0xb4, 0x7d, - 0x73, 0x1f, 0x36, 0xe4, 0x91, 0x2d, 0x37, 0x94, 0xb1, 0xf6, 0xa4, 0x6c, 0xa3, 0x5f, 0x87, 0xe1, - 0xc8, 0x96, 0x49, 0x9c, 0x1e, 0x9e, 0x4f, 0xb2, 0x96, 0xf6, 0x7f, 0x31, 0xb6, 0x51, 0x0e, 0x4c, - 0x93, 0x2b, 0x96, 0xe9, 0x99, 0x7a, 0x63, 0xc2, 0x6e, 0x36, 0x75, 0xcb, 0x50, 0x06, 0x42, 0x4d, - 0x36, 0x39, 0xa6, 0x56, 0xe7, 0x28, 0x59, 0x93, 0xa3, 0x85, 0xd8, 0xb6, 0x5c, 0xf4, 0xa1, 0x46, - 0xeb, 0xb6, 0xc3, 0x6c, 0x01, 0x3c, 0x1c, 0x14, 0xdb, 0x72, 0x97, 0xe3, 0x6a, 0x8e, 0x8f, 0x94, - 0x8d, 0xed, 0x78, 0xc1, 0xd7, 0xf2, 0xfd, 0x83, 0xa3, 0x43, 0xf1, 0xf3, 0x5c, 0xf5, 0xaf, 0xe5, - 0x60, 0x50, 0x90, 0xb2, 0xa5, 0xf4, 0x48, 0xc1, 0xf7, 0xa2, 0xe0, 0xa9, 0x8a, 0x5a, 0xd8, 0x2f, - 0x45, 0x55, 0x3f, 0x93, 0x0d, 0x66, 0xa3, 0x05, 0xc7, 0xb4, 0xf6, 0x36, 0x1b, 0x5d, 0x04, 0x98, - 0x58, 0x6d, 0x5b, 0x77, 0xf9, 0xbd, 0x55, 0x36, 0xbc, 0xb7, 0xaa, 0x9b, 0x9a, 0x84, 0x21, 0xe7, - 0x21, 0x5f, 0x66, 0xfc, 0x59, 0xcf, 0x0c, 0x8d, 0x0f, 0xbc, 0xcd, 0x39, 0x65, 0x9e, 0xd4, 0x10, - 0xcc, 0x36, 0x57, 0xe3, 0xeb, 0x1e, 0xe5, 0xe6, 0x6c, 0x8e, 0x6f, 0xae, 0x96, 0x18, 0x40, 0xe3, - 0x70, 0x72, 0x1d, 0xc6, 0xca, 0xb4, 0xa1, 0xaf, 0xcf, 0x9a, 0x8d, 0x86, 0xe9, 0xd2, 0xba, 0x6d, - 0x19, 0x2e, 0x0a, 0x59, 0x54, 0xd7, 0x74, 0xb5, 0x24, 0x01, 0x51, 0xa1, 0x30, 0xbf, 0xbc, 0xec, - 0x52, 0x0f, 0xc5, 0x97, 0x1b, 0x07, 0x36, 0x39, 0xdb, 0x08, 0xd1, 0x04, 0x46, 0xfd, 0x85, 0x0c, - 0xdb, 0xbd, 0xb8, 0x77, 0x3d, 0xbb, 0x15, 0x68, 0xf9, 0x9e, 0x44, 0x72, 0x39, 0xb4, 0x2b, 0xb2, - 0xf8, 0xb5, 0xc7, 0xc4, 0xd7, 0xf6, 0x09, 0xdb, 0x22, 0xb4, 0x28, 0x52, 0xbf, 0x2a, 0xb7, 0xc5, - 0x57, 0xa9, 0x7f, 0x94, 0x85, 0xd3, 0xa2, 0xc5, 0x13, 0x0d, 0xb3, 0xb5, 0x64, 0xeb, 0x8e, 0xa1, - 0xd1, 0x3a, 0x35, 0xef, 0xd1, 0xc3, 0x39, 0xf0, 0xa2, 0x43, 0x27, 0xbf, 0x87, 0xa1, 0x73, 0x0d, - 0x37, 0x82, 0x4c, 0x32, 0x78, 0xe0, 0xcb, 0x8d, 0x8a, 0xd1, 0xcd, 0x8d, 0xe2, 0x90, 0xc1, 0xc1, - 0x78, 0xe4, 0xaf, 0xc9, 0x44, 0x4c, 0x49, 0x66, 0xa8, 0xb5, 0xe2, 0xad, 0xa2, 0x92, 0xf4, 0x72, - 0x25, 0x69, 0x20, 0x44, 0x13, 0x18, 0xf5, 0x3f, 0x66, 0xe1, 0x44, 0x5c, 0xe4, 0x55, 0x6a, 0x19, - 0x47, 0xf2, 0x7e, 0x67, 0xe4, 0xfd, 0xcd, 0x1c, 0x3c, 0x24, 0xca, 0x54, 0x57, 0x75, 0x87, 0x1a, - 0x65, 0xd3, 0xa1, 0x75, 0xcf, 0x76, 0xd6, 0x0f, 0xb1, 0x01, 0xb5, 0x7f, 0x62, 0xbf, 0x0e, 0x05, - 0xb1, 0xfd, 0xe7, 0xeb, 0xcc, 0x48, 0xd0, 0x12, 0x84, 0x26, 0x56, 0x28, 0x7e, 0x74, 0x10, 0xeb, - 0xac, 0xc2, 0x76, 0x3a, 0xeb, 0x03, 0x30, 0x1c, 0x88, 0x1e, 0x37, 0xa2, 0x7d, 0xa1, 0xb5, 0x65, - 0xf8, 0x08, 0xdc, 0x8b, 0x6a, 0x51, 0x42, 0xac, 0xcd, 0x07, 0x54, 0xca, 0x68, 0x0d, 0x0d, 0x8b, - 0xda, 0x82, 0x72, 0xa6, 0xa1, 0xc9, 0x44, 0xea, 0x46, 0x1e, 0xce, 0xa6, 0x77, 0xbb, 0x46, 0x75, - 0xe3, 0xa8, 0xd7, 0xbf, 0x25, 0x7b, 0x9d, 0x3c, 0x02, 0xf9, 0x05, 0xdd, 0x5b, 0x15, 0xf7, 0xe0, - 0x78, 0x27, 0xbc, 0x6c, 0x36, 0x68, 0xad, 0xa5, 0x7b, 0xab, 0x1a, 0xa2, 0xa4, 0x39, 0x03, 0x90, - 0x63, 0xca, 0x9c, 0x21, 0x2d, 0xf6, 0x83, 0x0f, 0x67, 0x2e, 0xe5, 0x53, 0x17, 0xfb, 0xaf, 0xe7, - 0x3b, 0xcd, 0x2b, 0x77, 0x1c, 0xd3, 0xa3, 0x47, 0x1a, 0x76, 0xa4, 0x61, 0x7b, 0xd4, 0xb0, 0xdf, - 0xc9, 0xc2, 0x70, 0xb0, 0x69, 0x7a, 0x93, 0xd6, 0x0f, 0x66, 0xad, 0x0a, 0xb7, 0x32, 0xb9, 0x3d, - 0x6f, 0x65, 0xf6, 0xa2, 0x50, 0x6a, 0x70, 0xe4, 0xc9, 0x4d, 0x03, 0x94, 0x18, 0x3f, 0xf2, 0x0c, - 0x0e, 0x3a, 0x1f, 0x81, 0xbe, 0x59, 0xfd, 0xbe, 0xd9, 0x6c, 0x37, 0x85, 0x95, 0x8e, 0x7e, 0x5d, - 0x4d, 0xfd, 0xbe, 0xe6, 0xc3, 0xd5, 0x7f, 0x9e, 0x81, 0x11, 0x21, 0x54, 0xc1, 0x7c, 0x4f, 0x52, - 0x0d, 0xa5, 0x93, 0xdd, 0xb3, 0x74, 0x72, 0xbb, 0x97, 0x8e, 0xfa, 0xa3, 0x39, 0x50, 0xa6, 0xcc, - 0x06, 0x5d, 0x74, 0x74, 0xcb, 0x5d, 0xa6, 0x8e, 0xd8, 0x4e, 0x4f, 0x32, 0x56, 0x7b, 0xfa, 0x40, - 0x69, 0x4a, 0xc9, 0xee, 0x6a, 0x4a, 0x79, 0x1f, 0x0c, 0x88, 0xc6, 0x04, 0x3e, 0x85, 0x38, 0x6a, - 0x1c, 0x1f, 0xa8, 0x85, 0x78, 0x46, 0x5c, 0x6a, 0xb5, 0x1c, 0xfb, 0x1e, 0x75, 0xf8, 0x2d, 0x95, - 0x20, 0xd6, 0x7d, 0xa0, 0x16, 0xe2, 0x25, 0xce, 0xd4, 0xb7, 0x17, 0x65, 0xce, 0xd4, 0xd1, 0x42, - 0x3c, 0xb9, 0x04, 0xfd, 0x33, 0x76, 0x5d, 0x47, 0x41, 0xf3, 0x69, 0x65, 0x68, 0x73, 0xa3, 0xd8, - 0xdf, 0x10, 0x30, 0x2d, 0xc0, 0x32, 0xca, 0xb2, 0xbd, 0x66, 0x35, 0x6c, 0x9d, 0x3b, 0xbf, 0xf4, - 0x73, 0x4a, 0x43, 0xc0, 0xb4, 0x00, 0xcb, 0x28, 0x99, 0xcc, 0xd1, 0xa9, 0xa8, 0x3f, 0xe4, 0xb9, - 0x2c, 0x60, 0x5a, 0x80, 0x55, 0x7f, 0x21, 0xcf, 0xb4, 0xd7, 0x35, 0xdf, 0x7a, 0xe0, 0xd7, 0x85, - 0x70, 0xc0, 0xf4, 0xee, 0x62, 0xc0, 0x3c, 0x30, 0x07, 0x76, 0xea, 0x1f, 0xf7, 0x01, 0x08, 0xe9, - 0x4f, 0x1e, 0x6d, 0x0e, 0xf7, 0xa6, 0x35, 0x65, 0x18, 0x9b, 0xb4, 0x56, 0x75, 0xab, 0x4e, 0x8d, - 0xf0, 0xd8, 0xb2, 0x80, 0x43, 0x1b, 0x7d, 0x7a, 0xa9, 0x40, 0x86, 0xe7, 0x96, 0x5a, 0xb2, 0x00, - 0x79, 0x0a, 0x06, 0x2b, 0x96, 0x47, 0x1d, 0xbd, 0xee, 0x99, 0xf7, 0xa8, 0x98, 0x1a, 0xf0, 0x66, - 0xd8, 0x0c, 0xc1, 0x9a, 0x4c, 0x43, 0xae, 0xc3, 0xd0, 0x82, 0xee, 0x78, 0x66, 0xdd, 0x6c, 0xe9, - 0x96, 0xe7, 0x2a, 0xfd, 0x38, 0xa3, 0xa1, 0x85, 0xd1, 0x92, 0xe0, 0x5a, 0x84, 0x8a, 0x7c, 0x0c, - 0x06, 0x70, 0x6b, 0x8a, 0x8e, 0xd3, 0x03, 0x5b, 0x5e, 0x1c, 0x3e, 0x1a, 0xba, 0x07, 0xf2, 0xd3, - 0x57, 0xbc, 0x01, 0x8e, 0xdf, 0x1d, 0x06, 0x1c, 0xc9, 0x87, 0xa0, 0x6f, 0xd2, 0x32, 0x90, 0x39, - 0x6c, 0xc9, 0x5c, 0x15, 0xcc, 0x4f, 0x85, 0xcc, 0xed, 0x56, 0x8c, 0xb7, 0xcf, 0x2e, 0x7d, 0x94, - 0x0d, 0xbe, 0x73, 0xa3, 0x6c, 0xe8, 0x1d, 0x38, 0x16, 0x1f, 0xde, 0xaf, 0x63, 0xf1, 0x91, 0x5d, - 0x1e, 0x8b, 0xab, 0x6f, 0xc1, 0xe0, 0xf8, 0xc2, 0x54, 0x30, 0x7a, 0xcf, 0x40, 0x6e, 0x41, 0x78, - 0x2a, 0xe4, 0xb9, 0x3d, 0xd3, 0x32, 0x0d, 0x8d, 0xc1, 0xc8, 0x65, 0xe8, 0x9f, 0x40, 0xf7, 0x37, - 0x71, 0x8b, 0x98, 0xe7, 0xeb, 0x5f, 0x1d, 0x61, 0xe8, 0x05, 0xeb, 0xa3, 0xc9, 0x63, 0xd0, 0xb7, - 0xe0, 0xd8, 0x2b, 0x8e, 0xde, 0x14, 0x6b, 0x30, 0xba, 0x8a, 0xb4, 0x38, 0x48, 0xf3, 0x71, 0xea, - 0xf7, 0x67, 0x7c, 0xb3, 0x9d, 0x95, 0xa8, 0xb6, 0xf1, 0x68, 0x1e, 0xeb, 0xee, 0xe7, 0x25, 0x5c, - 0x0e, 0xd2, 0x7c, 0x1c, 0xb9, 0x0c, 0xbd, 0x93, 0x8e, 0x63, 0x3b, 0xb2, 0xb3, 0x39, 0x65, 0x00, - 0xf9, 0xba, 0x17, 0x29, 0xc8, 0x73, 0x30, 0xc8, 0xe7, 0x1c, 0x7e, 0xa2, 0x99, 0xeb, 0x76, 0x53, - 0x2a, 0x53, 0xaa, 0x5f, 0xcd, 0x49, 0x36, 0x1b, 0x97, 0xf8, 0x03, 0x78, 0x2b, 0xf0, 0x34, 0xe4, - 0xc6, 0x17, 0xa6, 0xc4, 0x04, 0x78, 0xdc, 0x2f, 0x2a, 0xa9, 0x4a, 0xac, 0x1c, 0xa3, 0x26, 0xe7, - 0x20, 0xbf, 0xc0, 0xd4, 0xa7, 0x80, 0xea, 0xd1, 0xbf, 0xb9, 0x51, 0xcc, 0xb7, 0x98, 0xfe, 0x20, - 0x14, 0xb1, 0x6c, 0x33, 0xc3, 0x77, 0x4c, 0x1c, 0x1b, 0xee, 0x63, 0xce, 0x41, 0xbe, 0xe4, 0xac, - 0xdc, 0x13, 0xb3, 0x16, 0x62, 0x75, 0x67, 0xe5, 0x9e, 0x86, 0x50, 0x72, 0x15, 0x40, 0xa3, 0x5e, - 0xdb, 0xb1, 0xf0, 0x1d, 0xc8, 0x00, 0x9e, 0xbf, 0xe1, 0x6c, 0xe8, 0x20, 0xb4, 0x56, 0xb7, 0x0d, - 0xaa, 0x49, 0x24, 0xea, 0x4f, 0x87, 0x17, 0x3b, 0x65, 0xd3, 0xbd, 0x7b, 0xd4, 0x85, 0x3b, 0xe8, - 0x42, 0x5d, 0x1c, 0x71, 0x26, 0x3b, 0xa9, 0x08, 0xbd, 0x53, 0x0d, 0x7d, 0xc5, 0xc5, 0x3e, 0x14, - 0xbe, 0x64, 0xcb, 0x0c, 0xa0, 0x71, 0x78, 0xac, 0x9f, 0xfa, 0xb7, 0xee, 0xa7, 0x2f, 0xf6, 0x06, - 0xa3, 0x6d, 0x8e, 0x7a, 0x6b, 0xb6, 0x73, 0xd4, 0x55, 0xdb, 0xed, 0xaa, 0x8b, 0xd0, 0x57, 0x75, - 0xea, 0xd2, 0xd1, 0x05, 0xee, 0x07, 0x5c, 0xa7, 0xce, 0x8f, 0x2d, 0x7c, 0x24, 0xa3, 0x2b, 0xbb, - 0x1e, 0xd2, 0xf5, 0x85, 0x74, 0x86, 0xeb, 0x09, 0x3a, 0x81, 0x14, 0x74, 0x0b, 0xb6, 0xe3, 0x89, - 0x8e, 0x0b, 0xe8, 0x5a, 0xb6, 0xe3, 0x69, 0x3e, 0x92, 0xbc, 0x0f, 0x60, 0x71, 0x62, 0xc1, 0x77, - 0xb6, 0x1f, 0x08, 0x7d, 0x01, 0x85, 0x97, 0xbd, 0x26, 0xa1, 0xc9, 0x22, 0x0c, 0xcc, 0xb7, 0xa8, - 0xc3, 0xb7, 0x42, 0xfc, 0x65, 0xc7, 0x7b, 0x63, 0xa2, 0x15, 0xfd, 0x7e, 0x45, 0xfc, 0x1f, 0x90, - 0xf3, 0xf5, 0xc5, 0xf6, 0x7f, 0x6a, 0x21, 0x23, 0xf2, 0x1c, 0x14, 0x4a, 0xdc, 0xce, 0x1b, 0x44, - 0x96, 0x81, 0xc8, 0x70, 0x0b, 0xca, 0x51, 0x7c, 0xcf, 0xae, 0xe3, 0xdf, 0x9a, 0x20, 0x57, 0x2f, - 0xc3, 0x68, 0xbc, 0x1a, 0x32, 0x08, 0x7d, 0x13, 0xf3, 0x73, 0x73, 0x93, 0x13, 0x8b, 0xa3, 0x3d, - 0xa4, 0x1f, 0xf2, 0xd5, 0xc9, 0xb9, 0xf2, 0x68, 0x46, 0xfd, 0x39, 0x69, 0x06, 0x61, 0xaa, 0x75, - 0x74, 0x35, 0xbc, 0xa7, 0xfb, 0x96, 0x51, 0xbc, 0x0f, 0xc5, 0x13, 0x83, 0xa6, 0xe9, 0x79, 0xd4, - 0x10, 0xab, 0x04, 0xde, 0x17, 0x7a, 0xf7, 0xb5, 0x04, 0x9e, 0x3c, 0x01, 0xc3, 0x08, 0x13, 0x57, - 0x84, 0x7c, 0x7f, 0x2c, 0x0a, 0x38, 0xf7, 0xb5, 0x28, 0x52, 0xfd, 0x5a, 0x78, 0x3b, 0x3c, 0x43, - 0xf5, 0xc3, 0x7a, 0xa3, 0xf8, 0x2e, 0xe9, 0x2f, 0xf5, 0xcf, 0xf2, 0xfc, 0x09, 0x08, 0x7f, 0xb8, - 0x77, 0x10, 0xa2, 0x0c, 0x8f, 0x74, 0x73, 0x3b, 0x38, 0xd2, 0x7d, 0x02, 0x0a, 0xb3, 0xd4, 0x5b, - 0xb5, 0x7d, 0xc7, 0x2f, 0xf4, 0xd0, 0x6b, 0x22, 0x44, 0xf6, 0xd0, 0xe3, 0x34, 0xe4, 0x2e, 0x10, - 0xff, 0x55, 0x5e, 0xe0, 0x88, 0xed, 0x1f, 0x21, 0x9f, 0x4e, 0xec, 0x53, 0xaa, 0xf8, 0x24, 0x17, - 0x7d, 0xec, 0x4f, 0x04, 0x8e, 0xde, 0x92, 0x27, 0xd6, 0x9f, 0x6e, 0x14, 0x0b, 0x9c, 0x46, 0x4b, - 0x61, 0x4b, 0x5e, 0x87, 0x81, 0xd9, 0xa9, 0x92, 0x78, 0xa1, 0xc7, 0xbd, 0x22, 0xce, 0x04, 0x52, - 0xf4, 0x11, 0x81, 0x48, 0xf0, 0xbd, 0x4d, 0x73, 0x59, 0x4f, 0x3e, 0xd0, 0x0b, 0xb9, 0x30, 0x6d, - 0xe1, 0x2f, 0x77, 0xc4, 0xe9, 0x42, 0xa0, 0x2d, 0xd1, 0xf7, 0x3c, 0x71, 0x59, 0x71, 0x6c, 0x4c, - 0x5b, 0xfa, 0xf7, 0x30, 0xba, 0xe7, 0x61, 0xac, 0xd4, 0x6a, 0x35, 0x4c, 0x6a, 0xa0, 0xbe, 0x68, - 0xed, 0x06, 0x75, 0x85, 0xcb, 0x0f, 0x3e, 0x06, 0xd1, 0x39, 0xb2, 0x86, 0xef, 0x42, 0x6b, 0x4e, - 0x3b, 0xea, 0x9f, 0x99, 0x2c, 0xab, 0xfe, 0x60, 0x16, 0x4e, 0x4d, 0x38, 0x54, 0xf7, 0xe8, 0xec, - 0x54, 0xa9, 0xd4, 0x46, 0x1f, 0xb9, 0x46, 0x83, 0x5a, 0x2b, 0x07, 0x33, 0xac, 0x5f, 0x84, 0x91, - 0xa0, 0x01, 0xd5, 0xba, 0xdd, 0xa2, 0xf2, 0xc3, 0xaa, 0xba, 0x8f, 0xa9, 0xb9, 0x0c, 0xa5, 0xc5, - 0x48, 0xc9, 0x4d, 0x38, 0x1e, 0x40, 0x4a, 0x8d, 0x86, 0xbd, 0xa6, 0xd1, 0xb6, 0xcb, 0x1d, 0x63, - 0xfb, 0xb9, 0x63, 0x6c, 0xc8, 0x41, 0x67, 0xf8, 0x9a, 0xc3, 0x08, 0xb4, 0xb4, 0x52, 0xea, 0x97, - 0x72, 0x70, 0xfa, 0xb6, 0xde, 0x30, 0x8d, 0x50, 0x34, 0x1a, 0x75, 0x5b, 0xb6, 0xe5, 0xd2, 0x43, - 0x34, 0x4a, 0x23, 0x43, 0x21, 0xbf, 0x2f, 0x43, 0x21, 0xd9, 0x45, 0xbd, 0x7b, 0xee, 0xa2, 0xc2, - 0xae, 0xba, 0xe8, 0x3f, 0x64, 0x60, 0xd4, 0x77, 0xfc, 0x97, 0x5f, 0x53, 0x4b, 0x5e, 0xe9, 0x78, - 0x84, 0x18, 0xf3, 0x83, 0x46, 0x3c, 0xa9, 0x42, 0xdf, 0xe4, 0xfd, 0x96, 0xe9, 0x50, 0x77, 0x1b, - 0x4e, 0xdc, 0xe7, 0xc5, 0x71, 0xc9, 0x18, 0xe5, 0x45, 0x12, 0x27, 0x25, 0x1c, 0x8c, 0xcf, 0xf9, - 0xf8, 0xd3, 0x87, 0x71, 0xff, 0x89, 0x38, 0x7f, 0xce, 0x27, 0x9e, 0x48, 0x44, 0xde, 0x67, 0x86, - 0xa4, 0xe4, 0x51, 0xc8, 0x2d, 0x2e, 0xce, 0x88, 0x99, 0x14, 0x9f, 0xe6, 0x7b, 0x9e, 0xfc, 0x5e, - 0x91, 0x61, 0xd5, 0xdf, 0xcf, 0x02, 0x30, 0x55, 0xe0, 0xc3, 0xf5, 0x40, 0x94, 0x70, 0x1c, 0xfa, - 0x7d, 0x81, 0x0b, 0x35, 0x0c, 0xbc, 0xf6, 0xe3, 0x1d, 0x11, 0xaf, 0x3b, 0x78, 0xa1, 0x51, 0xf4, - 0x1d, 0xc9, 0xf9, 0x3d, 0x00, 0xee, 0x6c, 0xd0, 0x91, 0xdc, 0x77, 0x1f, 0x7f, 0x1f, 0x0c, 0x88, - 0x19, 0xcf, 0x8e, 0x9c, 0xff, 0xd7, 0x7d, 0xa0, 0x16, 0xe2, 0x63, 0x53, 0x6b, 0x61, 0x0f, 0x0b, - 0xb1, 0x2f, 0x5e, 0xde, 0x2b, 0x47, 0xe2, 0xdd, 0x67, 0xf1, 0x7e, 0x4e, 0x88, 0x97, 0xbf, 0xe0, - 0x39, 0xb4, 0xe2, 0xdd, 0xb7, 0xb3, 0x6f, 0xf5, 0x77, 0x32, 0x40, 0x58, 0xb3, 0x16, 0x74, 0xd7, - 0x5d, 0xb3, 0x1d, 0x83, 0x3b, 0xa7, 0x1f, 0x88, 0x60, 0xf6, 0xef, 0xbe, 0xf2, 0xab, 0xfd, 0x70, - 0x3c, 0xe2, 0xf8, 0x7b, 0xc8, 0x27, 0xab, 0xcb, 0xd1, 0xd1, 0xd4, 0xed, 0xd5, 0xcb, 0x7b, 0xe4, - 0x0b, 0xd1, 0xde, 0xc8, 0x03, 0x34, 0xe9, 0x26, 0xf4, 0x49, 0x18, 0x12, 0x3f, 0xd8, 0x0a, 0xed, - 0xdf, 0x74, 0xe1, 0x28, 0x75, 0x19, 0x40, 0x8b, 0xa0, 0xc9, 0x33, 0x30, 0xc0, 0x06, 0xcc, 0x0a, - 0x46, 0xf1, 0xe8, 0x0b, 0x5f, 0x94, 0x18, 0x3e, 0x50, 0x5e, 0x4f, 0x02, 0x4a, 0xe9, 0x1d, 0x51, - 0xff, 0x36, 0xde, 0x11, 0x7d, 0x1c, 0x06, 0x4b, 0x96, 0x65, 0x7b, 0xb8, 0x49, 0x77, 0xc5, 0xd5, - 0x44, 0x47, 0xab, 0xfc, 0x51, 0x7c, 0x1c, 0x1f, 0xd2, 0xa7, 0x9a, 0xe5, 0x32, 0x43, 0x72, 0xcd, - 0x7f, 0x15, 0x43, 0x1d, 0xe1, 0x55, 0x8e, 0xd7, 0x33, 0x8e, 0x80, 0x25, 0x1f, 0xc5, 0x60, 0xe7, - 0x0d, 0x2f, 0x38, 0x76, 0xcb, 0x76, 0xa9, 0xc1, 0x05, 0x35, 0x18, 0x86, 0x1a, 0x68, 0x09, 0x04, - 0xbe, 0x63, 0x8b, 0x44, 0xd4, 0x88, 0x14, 0x21, 0xcb, 0x70, 0xc2, 0xbf, 0x28, 0x0e, 0x5e, 0x0c, - 0x56, 0xca, 0xae, 0x32, 0x84, 0xaf, 0x92, 0x48, 0x5c, 0x19, 0x2a, 0xe5, 0xf1, 0x0b, 0xfe, 0xb5, - 0x88, 0xff, 0xe4, 0xb0, 0x66, 0x1a, 0x72, 0x57, 0xa7, 0xf2, 0x23, 0xdf, 0x06, 0x83, 0xb3, 0xfa, - 0xfd, 0x72, 0x5b, 0x9c, 0xbd, 0x0c, 0x6f, 0xff, 0xf6, 0xa5, 0xa9, 0xdf, 0xaf, 0x19, 0xa2, 0x5c, - 0xcc, 0xa6, 0x90, 0x59, 0x92, 0x1a, 0x9c, 0x5a, 0x70, 0xec, 0xa6, 0xed, 0x51, 0x23, 0xf6, 0xf8, - 0xee, 0x58, 0xf8, 0x5a, 0xb7, 0x25, 0x28, 0x6a, 0x5d, 0x5e, 0xe1, 0x75, 0x60, 0x43, 0x9a, 0x70, - 0xac, 0xe4, 0xba, 0xed, 0x26, 0x0d, 0x6f, 0xa8, 0x46, 0xb7, 0xfc, 0x8c, 0xf7, 0x0a, 0xaf, 0xe5, - 0x87, 0x74, 0x2c, 0xca, 0x2f, 0xa8, 0x6a, 0x9e, 0x29, 0xd7, 0x88, 0xdf, 0x12, 0xe7, 0xfd, 0x5a, - 0xbe, 0x7f, 0x64, 0xf4, 0x98, 0x76, 0x3a, 0xd9, 0x98, 0x45, 0xd3, 0x6b, 0x50, 0xf5, 0x2b, 0x19, - 0x80, 0x50, 0xc0, 0xe4, 0xc9, 0x68, 0xa8, 0xa0, 0x4c, 0x78, 0xd1, 0x21, 0xa2, 0x17, 0x44, 0x62, - 0x03, 0x91, 0x73, 0x90, 0xc7, 0x08, 0x17, 0xd9, 0xf0, 0x60, 0xf5, 0xae, 0x69, 0x19, 0x1a, 0x42, - 0x19, 0x56, 0x7a, 0x8a, 0x8e, 0x58, 0xbc, 0xd4, 0xe7, 0x56, 0x61, 0x19, 0x8e, 0x55, 0xdb, 0x4b, - 0x7e, 0xdd, 0xd2, 0xbb, 0x3a, 0x0c, 0xb4, 0xe1, 0xb6, 0x97, 0x82, 0xc7, 0xa8, 0x91, 0x30, 0x26, - 0xd1, 0x22, 0xea, 0x2f, 0x64, 0x62, 0xb3, 0xe0, 0x01, 0x2e, 0x7a, 0xef, 0x49, 0xfa, 0x69, 0x24, - 0xa7, 0x25, 0xf5, 0xc7, 0xb2, 0x30, 0xb8, 0x60, 0x3b, 0x9e, 0x08, 0x19, 0x72, 0xb8, 0x57, 0x21, - 0x69, 0xaf, 0x94, 0xdf, 0xc1, 0x5e, 0xe9, 0x1c, 0xe4, 0x25, 0x17, 0x65, 0x7e, 0x2f, 0x62, 0x18, - 0x8e, 0x86, 0x50, 0xf5, 0xdb, 0xb3, 0x00, 0x1f, 0x7a, 0xea, 0xa9, 0x07, 0x58, 0x40, 0xea, 0x8f, - 0x64, 0xe0, 0x98, 0xb8, 0xa8, 0x93, 0x82, 0x6e, 0xf5, 0xf9, 0x57, 0xac, 0xf2, 0xb8, 0xe4, 0x20, - 0xcd, 0xc7, 0xb1, 0x25, 0x60, 0xf2, 0xbe, 0xe9, 0xe1, 0x5d, 0x85, 0x14, 0x75, 0x8b, 0x0a, 0x98, - 0xbc, 0x04, 0xf8, 0x74, 0xe4, 0x49, 0xff, 0x0a, 0x32, 0x17, 0xae, 0x7b, 0xac, 0xc0, 0x64, 0xea, - 0x35, 0xa4, 0xfa, 0x4b, 0x79, 0xc8, 0x4f, 0xde, 0xa7, 0xf5, 0x43, 0xde, 0x35, 0xd2, 0xc1, 0x66, - 0x7e, 0x8f, 0x07, 0x9b, 0xbb, 0xf1, 0xa9, 0x78, 0x25, 0xec, 0xcf, 0x42, 0xb4, 0xfa, 0x58, 0xcf, - 0xc7, 0xab, 0xf7, 0x7b, 0xfa, 0xf0, 0xb9, 0xe4, 0xfc, 0xc3, 0x1c, 0xe4, 0xaa, 0x13, 0x0b, 0x47, - 0x7a, 0x73, 0xa0, 0x7a, 0xd3, 0xfd, 0xce, 0x5a, 0x0d, 0xae, 0xa1, 0xfa, 0x43, 0x2f, 0xd1, 0xd8, - 0x8d, 0xd3, 0x37, 0x73, 0x30, 0x52, 0x9d, 0x5a, 0x5c, 0x90, 0x4e, 0x82, 0x6f, 0x72, 0x4f, 0x3e, - 0xf4, 0x29, 0xe3, 0x5d, 0x7a, 0x2e, 0x61, 0xcf, 0xdc, 0xaa, 0x58, 0xde, 0xb3, 0xd7, 0x6f, 0xeb, - 0x8d, 0x36, 0xc5, 0xa3, 0x17, 0xee, 0xf7, 0xeb, 0x9a, 0x6f, 0xd1, 0x2f, 0xe1, 0xc3, 0x7f, 0x9f, - 0x01, 0x79, 0x11, 0x72, 0xb7, 0x84, 0x47, 0x46, 0x27, 0x3e, 0x4f, 0x5f, 0xe3, 0x7c, 0xd8, 0x24, - 0x98, 0x6b, 0x9b, 0x06, 0x72, 0x60, 0xa5, 0x58, 0xe1, 0x1b, 0x62, 0x01, 0xde, 0x56, 0xe1, 0x15, - 0xbf, 0xf0, 0x8d, 0x4a, 0x99, 0x54, 0x61, 0x70, 0x81, 0x3a, 0x4d, 0x13, 0x3b, 0xca, 0x9f, 0xb3, - 0xbb, 0x33, 0x61, 0x3b, 0x95, 0xc1, 0x56, 0x58, 0x08, 0x99, 0xc9, 0x5c, 0xc8, 0x1b, 0x00, 0xdc, - 0x46, 0xd9, 0x66, 0x20, 0xc7, 0xf3, 0x68, 0xf7, 0x73, 0xd3, 0x32, 0xc5, 0xc6, 0x93, 0x98, 0x91, - 0xbb, 0x30, 0x3a, 0x6b, 0x1b, 0xe6, 0xb2, 0xc9, 0x5d, 0x2f, 0xb1, 0x82, 0xc2, 0xd6, 0x0e, 0x4f, - 0xcc, 0x94, 0x6c, 0x4a, 0xe5, 0xd2, 0xaa, 0x49, 0x30, 0x56, 0xff, 0x5e, 0x2f, 0xe4, 0x59, 0xb7, - 0x1f, 0x8d, 0xdf, 0xbd, 0x8c, 0xdf, 0x12, 0x8c, 0xde, 0xb1, 0x9d, 0xbb, 0xa6, 0xb5, 0x12, 0x78, - 0xc5, 0x8b, 0xbd, 0x29, 0x7a, 0xf2, 0xac, 0x71, 0x5c, 0x2d, 0x70, 0xa0, 0xd7, 0x12, 0xe4, 0x5b, - 0x8c, 0xe0, 0xe7, 0x01, 0xf8, 0x5b, 0x77, 0xa4, 0xe9, 0x0f, 0x83, 0x55, 0xf0, 0x97, 0xf0, 0xe8, - 0x68, 0x2f, 0x07, 0xab, 0x08, 0x89, 0xd9, 0x26, 0x9c, 0xfb, 0x42, 0x0c, 0xa0, 0xdf, 0x3d, 0x6e, - 0xc2, 0xd1, 0x17, 0x42, 0x36, 0x02, 0xb8, 0x57, 0xc4, 0x02, 0x80, 0x74, 0xbf, 0x04, 0x31, 0x41, - 0x44, 0x26, 0x07, 0x11, 0x1e, 0x2e, 0xe5, 0x7a, 0x49, 0x93, 0x78, 0x90, 0x67, 0x63, 0x17, 0xe0, - 0x24, 0xc2, 0xad, 0xe3, 0xfd, 0x77, 0xe8, 0x40, 0x35, 0xb4, 0x95, 0x03, 0x95, 0xfa, 0x99, 0x2c, - 0x0c, 0x54, 0xdb, 0x4b, 0xee, 0xba, 0xeb, 0xd1, 0xe6, 0x21, 0x57, 0x63, 0x7f, 0x7b, 0x95, 0x4f, - 0xdd, 0x5e, 0x3d, 0xea, 0x0b, 0x45, 0x3a, 0x77, 0x0c, 0x4c, 0x3a, 0x5f, 0x1c, 0x7f, 0x33, 0x0b, - 0xa3, 0xfc, 0xe2, 0xac, 0x6c, 0xba, 0xf5, 0x7d, 0x70, 0xe6, 0x3f, 0x78, 0xa9, 0xec, 0xed, 0xb2, - 0x79, 0x1b, 0x4f, 0x24, 0xd4, 0x4f, 0x66, 0x61, 0xb0, 0xd4, 0xf6, 0x56, 0x4b, 0x1e, 0xea, 0xd6, - 0x03, 0xb9, 0x3f, 0xf9, 0x8d, 0x0c, 0x1c, 0x63, 0x0d, 0x59, 0xb4, 0xef, 0x52, 0x6b, 0x1f, 0x0e, - 0x1e, 0xe5, 0x03, 0xc4, 0xec, 0x2e, 0x0f, 0x10, 0x7d, 0x59, 0xe6, 0x76, 0x26, 0x4b, 0x3c, 0x2e, - 0xd7, 0xec, 0x06, 0x3d, 0xdc, 0x9f, 0xb1, 0x8f, 0xc7, 0xe5, 0xbe, 0x40, 0xf6, 0xe1, 0x7a, 0xe6, - 0x5b, 0x4b, 0x20, 0xfb, 0x70, 0xb6, 0xf4, 0xad, 0x21, 0x90, 0xaf, 0x66, 0x60, 0x60, 0xdc, 0xf6, - 0x0e, 0xf9, 0xc0, 0x17, 0x5f, 0x71, 0xb8, 0xd5, 0xdc, 0xff, 0x8a, 0xc3, 0xad, 0x9b, 0xea, 0x0f, - 0x65, 0xe1, 0x84, 0x08, 0xd2, 0x2d, 0xce, 0x1f, 0x8e, 0xa6, 0x63, 0x31, 0xd8, 0x92, 0xa2, 0x39, - 0x9a, 0x87, 0x84, 0x68, 0x7e, 0x26, 0x07, 0x27, 0x30, 0x94, 0x29, 0xdb, 0x96, 0x7d, 0x0b, 0xd8, - 0x22, 0xa4, 0x1e, 0xbd, 0x04, 0x9d, 0x4d, 0xb9, 0x04, 0xfd, 0xd3, 0x8d, 0xe2, 0xb3, 0x2b, 0xa6, - 0xb7, 0xda, 0x5e, 0xba, 0x52, 0xb7, 0x9b, 0x57, 0x57, 0x1c, 0xfd, 0x9e, 0xc9, 0xaf, 0xff, 0xf4, - 0xc6, 0xd5, 0x20, 0xdf, 0x85, 0xde, 0x32, 0x45, 0x26, 0x8c, 0x2a, 0xee, 0x75, 0x18, 0x57, 0xff, - 0xfa, 0xd4, 0x05, 0x78, 0xcd, 0x36, 0x2d, 0xe1, 0x53, 0xc8, 0x0d, 0xdd, 0x2a, 0xdb, 0x1f, 0xbe, - 0x69, 0x9b, 0x56, 0x2d, 0xee, 0x58, 0xb8, 0xd3, 0xfa, 0x42, 0xd6, 0x9a, 0x54, 0x8d, 0xfa, 0xcf, - 0x32, 0x70, 0x26, 0xaa, 0xc5, 0xdf, 0x0a, 0xb6, 0xe3, 0x0f, 0x67, 0xe1, 0xe4, 0x0d, 0x14, 0x4e, - 0xe0, 0xc8, 0x71, 0x34, 0x6f, 0x89, 0xc1, 0x99, 0x22, 0x9b, 0x23, 0x8b, 0xb2, 0xb3, 0x6c, 0x8e, - 0x26, 0x75, 0x21, 0x9b, 0xdf, 0xcc, 0xc0, 0xf1, 0xf9, 0x4a, 0x79, 0xe2, 0x5b, 0x64, 0x44, 0x25, - 0xbf, 0xe7, 0x90, 0x1b, 0x9c, 0x89, 0xef, 0x39, 0xe4, 0xa6, 0xe7, 0x17, 0xb2, 0x70, 0xbc, 0x5a, - 0x9a, 0x9d, 0xf9, 0x56, 0x99, 0xc1, 0x27, 0x64, 0xaf, 0x43, 0xff, 0x10, 0x4c, 0xd8, 0x02, 0xf2, - 0x67, 0xde, 0xbe, 0xd6, 0xd9, 0x1b, 0x31, 0x29, 0x94, 0x43, 0x3e, 0x75, 0xef, 0x8b, 0x50, 0x98, - 0xe6, 0x47, 0xa8, 0x0f, 0xb9, 0xe6, 0xff, 0x83, 0x02, 0x0c, 0xde, 0x6c, 0x2f, 0x51, 0xe1, 0x9c, - 0xf2, 0x40, 0x9f, 0xfc, 0x5e, 0x83, 0x41, 0x21, 0x06, 0xbc, 0x35, 0x91, 0x82, 0xe7, 0x89, 0x60, - 0x28, 0x3c, 0x3e, 0x91, 0x4c, 0x44, 0xce, 0x41, 0xfe, 0x36, 0x75, 0x96, 0xe4, 0x77, 0xa5, 0xf7, - 0xa8, 0xb3, 0xa4, 0x21, 0x94, 0xcc, 0x84, 0x2e, 0xf3, 0xa5, 0x85, 0x0a, 0x26, 0x52, 0x11, 0x17, - 0x36, 0x98, 0x19, 0x26, 0xf0, 0x7b, 0xd3, 0x5b, 0x26, 0x4f, 0xc1, 0x22, 0xbf, 0x69, 0x8f, 0x97, - 0x24, 0x73, 0x30, 0x26, 0x3b, 0x3e, 0xf1, 0x2c, 0x22, 0xfd, 0x29, 0xec, 0xd2, 0xf2, 0x87, 0x24, - 0x8b, 0x92, 0x57, 0x60, 0xc8, 0x07, 0xa2, 0x0b, 0xd7, 0x40, 0x18, 0xba, 0x3e, 0x60, 0x15, 0x4b, - 0x51, 0x14, 0x29, 0x20, 0x33, 0xc0, 0x6b, 0x08, 0x48, 0x61, 0x10, 0x73, 0x89, 0x8b, 0x14, 0x20, - 0xcf, 0x20, 0x03, 0x7c, 0xe6, 0x81, 0xce, 0x2a, 0x83, 0xf8, 0xe8, 0x12, 0x5d, 0xf2, 0x1d, 0x01, - 0xe7, 0x4f, 0x6b, 0x23, 0x64, 0x64, 0x1e, 0x20, 0x74, 0x2a, 0x10, 0x01, 0x0c, 0x76, 0xec, 0xee, - 0x20, 0xb1, 0x90, 0xaf, 0x03, 0x87, 0x77, 0x73, 0x1d, 0xa8, 0xfe, 0x76, 0x16, 0x06, 0x4b, 0xad, - 0x56, 0x30, 0x14, 0x9e, 0x84, 0x42, 0xa9, 0xd5, 0xba, 0xa5, 0x55, 0xe4, 0x50, 0xe6, 0x7a, 0xab, - 0x55, 0x6b, 0x3b, 0xa6, 0xec, 0x13, 0xca, 0x89, 0xc8, 0x04, 0x0c, 0x97, 0x5a, 0xad, 0x85, 0xf6, - 0x52, 0xc3, 0xac, 0x4b, 0x99, 0x91, 0x78, 0x12, 0xb7, 0x56, 0xab, 0xd6, 0x42, 0x4c, 0x3c, 0x3d, - 0x56, 0xb4, 0x0c, 0xf9, 0x38, 0x86, 0xfd, 0x11, 0x89, 0x79, 0x78, 0xea, 0x0f, 0x35, 0x08, 0x62, - 0x1e, 0xb6, 0xed, 0x4a, 0x40, 0xc4, 0x83, 0xbd, 0x9f, 0xf3, 0x43, 0xe6, 0xb3, 0x8a, 0x12, 0x09, - 0x78, 0x42, 0x96, 0xe4, 0xfd, 0xd0, 0x57, 0x6a, 0xb5, 0xa4, 0xfb, 0x26, 0x74, 0x2a, 0x62, 0xa5, - 0x62, 0x7d, 0xec, 0x93, 0x9d, 0x7d, 0x09, 0x46, 0xa2, 0x95, 0xed, 0x28, 0x58, 0xfc, 0x9f, 0x64, - 0xf0, 0x83, 0x0e, 0xb9, 0x4f, 0xf3, 0xd3, 0x90, 0x2b, 0xb5, 0x5a, 0x62, 0x3e, 0x3a, 0x9e, 0xd2, - 0x1f, 0xf1, 0x27, 0xd0, 0xa5, 0x56, 0xcb, 0xff, 0xf4, 0x43, 0xfe, 0x38, 0x62, 0x57, 0x9f, 0xfe, - 0x55, 0xfe, 0xe9, 0x87, 0xfb, 0xe1, 0x82, 0xfa, 0x4b, 0x39, 0x38, 0x56, 0x6a, 0xb5, 0x8e, 0x82, - 0xcc, 0xef, 0xd7, 0x43, 0xeb, 0xa7, 0x00, 0xa4, 0xe9, 0xb1, 0x2f, 0x78, 0xba, 0x35, 0x28, 0x4d, - 0x8d, 0x4a, 0x46, 0x93, 0x88, 0x7c, 0xf5, 0xeb, 0xdf, 0x91, 0xfa, 0x7d, 0x32, 0x87, 0x53, 0xf1, - 0x61, 0x0f, 0x1a, 0xf5, 0x6e, 0xe9, 0x36, 0xd1, 0x07, 0x85, 0x1d, 0xf5, 0xc1, 0xaf, 0x47, 0x06, - 0x0f, 0x06, 0x2d, 0x3f, 0xea, 0x85, 0xde, 0x3d, 0x99, 0xc5, 0x23, 0xb2, 0x30, 0x45, 0x24, 0x1b, - 0x3f, 0x91, 0x92, 0x88, 0xab, 0x54, 0x67, 0xa8, 0x9a, 0x69, 0x68, 0x31, 0x5a, 0xbf, 0x0f, 0xfb, - 0x76, 0xd4, 0x87, 0x1b, 0x59, 0x7c, 0x3b, 0x1d, 0xc4, 0x65, 0xda, 0xfb, 0xee, 0xe2, 0x2a, 0x00, - 0xf7, 0x3c, 0x08, 0xdc, 0x9a, 0x87, 0x79, 0x08, 0x16, 0x9e, 0x5f, 0x49, 0x84, 0x60, 0x09, 0x49, - 0x02, 0x0f, 0xa9, 0x5c, 0xaa, 0x87, 0xd4, 0x65, 0xe8, 0xd7, 0xf4, 0xb5, 0xd7, 0xdb, 0xd4, 0x59, - 0x17, 0xe6, 0x0c, 0x0f, 0x7b, 0xa8, 0xaf, 0xd5, 0x3e, 0xc1, 0x80, 0x5a, 0x80, 0x26, 0x6a, 0xf0, - 0xf8, 0x5e, 0xf2, 0x08, 0xe1, 0x67, 0xe4, 0xc1, 0x93, 0xfb, 0xdd, 0x28, 0x3a, 0x79, 0x01, 0x72, - 0xa5, 0x3b, 0x55, 0x21, 0xd9, 0xa0, 0x6b, 0x4b, 0x77, 0xaa, 0x42, 0x5e, 0x1d, 0xcb, 0xde, 0xa9, - 0xaa, 0x9f, 0xcc, 0x02, 0x49, 0x52, 0x92, 0x67, 0x61, 0x00, 0xa1, 0x2b, 0x4c, 0x67, 0xe4, 0xc4, - 0x9c, 0x6b, 0x6e, 0xcd, 0x41, 0x68, 0xc4, 0xb8, 0xf3, 0x49, 0xc9, 0xf3, 0x98, 0x83, 0x58, 0xa4, - 0x86, 0x8b, 0x24, 0xe6, 0x5c, 0x73, 0xfd, 0xac, 0xbd, 0xb1, 0x14, 0xc4, 0x82, 0x18, 0xed, 0xc2, - 0x3b, 0xd5, 0x69, 0xdb, 0xf5, 0x84, 0xa8, 0xb9, 0x5d, 0xb8, 0xe6, 0x62, 0x46, 0xd8, 0x88, 0x5d, - 0xc8, 0xc9, 0x30, 0xab, 0xd5, 0x9d, 0x2a, 0x7f, 0xa6, 0x62, 0x68, 0x76, 0xc3, 0x37, 0x28, 0x79, - 0x56, 0xab, 0x35, 0xb7, 0xc6, 0x9f, 0xb8, 0x18, 0x98, 0xfc, 0x38, 0x92, 0xd5, 0x2a, 0x52, 0x4a, - 0xfd, 0x6c, 0x3f, 0x8c, 0x96, 0x75, 0x4f, 0x5f, 0xd2, 0x5d, 0x2a, 0xed, 0xa6, 0x8f, 0xf9, 0x30, - 0xff, 0x73, 0x24, 0x39, 0x18, 0x4b, 0x29, 0x5f, 0x13, 0x2f, 0x40, 0x5e, 0x0c, 0xf9, 0x06, 0x39, - 0x47, 0xe5, 0x24, 0x66, 0x4b, 0xb5, 0x96, 0x00, 0x6b, 0x09, 0x42, 0xf2, 0x04, 0x0c, 0xfa, 0x30, - 0xb6, 0x01, 0xc8, 0x85, 0x3a, 0x63, 0x2c, 0x31, 0xfb, 0x5f, 0x93, 0xd1, 0xe4, 0x79, 0x18, 0xf2, - 0x7f, 0x4a, 0xa6, 0x35, 0xcf, 0xc8, 0xb6, 0x94, 0xd8, 0x3d, 0xc9, 0xa4, 0x72, 0x51, 0x9c, 0xdf, - 0x7a, 0x23, 0x45, 0x63, 0x49, 0xcf, 0x22, 0xa4, 0xe4, 0x13, 0x30, 0xe2, 0xff, 0x16, 0x1b, 0x06, - 0x9e, 0x1f, 0xee, 0x89, 0x20, 0xb7, 0x72, 0x4c, 0xac, 0x57, 0xa2, 0xe4, 0x7c, 0xeb, 0xf0, 0x90, - 0x9f, 0xc7, 0xcb, 0x58, 0x4a, 0xee, 0x1c, 0x62, 0x15, 0x90, 0x0a, 0x8c, 0xf9, 0x90, 0x50, 0x43, - 0xfb, 0xc2, 0x1d, 0xa3, 0xb1, 0x54, 0x4b, 0x55, 0xd2, 0x64, 0x29, 0xd2, 0x80, 0x73, 0x11, 0xa0, - 0xe1, 0xae, 0x9a, 0xcb, 0x9e, 0xd8, 0xee, 0x89, 0x18, 0xc4, 0x22, 0x71, 0x63, 0xc0, 0x95, 0xd3, - 0xf8, 0x19, 0x58, 0xa3, 0xd9, 0xa1, 0xba, 0x72, 0x23, 0x55, 0x38, 0xe1, 0xe3, 0x6f, 0x4c, 0x2c, - 0x2c, 0x38, 0xf6, 0x9b, 0xb4, 0xee, 0x55, 0xca, 0x62, 0xbb, 0x8c, 0xb1, 0xe9, 0x8c, 0xa5, 0xda, - 0x4a, 0xbd, 0xc5, 0x94, 0x82, 0xe1, 0xa2, 0xcc, 0x53, 0x0b, 0x93, 0xdb, 0x70, 0x52, 0x82, 0x57, - 0x2c, 0xd7, 0xd3, 0xad, 0x3a, 0xad, 0x94, 0xc5, 0x1e, 0x1a, 0xf7, 0xf3, 0x82, 0xab, 0x29, 0x90, - 0x51, 0xb6, 0xe9, 0xc5, 0xc9, 0x4b, 0x30, 0xec, 0x23, 0xf8, 0x2d, 0xe2, 0x20, 0xde, 0x22, 0xe2, - 0x90, 0x34, 0x96, 0x6a, 0xf1, 0xd7, 0x94, 0x51, 0x62, 0x59, 0xa3, 0x30, 0xb5, 0xfd, 0x50, 0x44, - 0xa3, 0xbc, 0xf5, 0x56, 0xaa, 0x32, 0x62, 0xba, 0xfb, 0x57, 0x42, 0x8d, 0x9a, 0x77, 0xcc, 0x15, - 0x93, 0xef, 0xa4, 0xfd, 0x07, 0x94, 0x4b, 0x35, 0x1b, 0x81, 0x69, 0xfa, 0xc1, 0xc9, 0xcf, 0x96, - 0xe0, 0x78, 0x8a, 0x8e, 0xed, 0x68, 0xc7, 0xf8, 0x99, 0x6c, 0xd8, 0x88, 0x43, 0xbe, 0x6d, 0x1c, - 0x87, 0x7e, 0xff, 0x4b, 0x84, 0xf1, 0xa0, 0x74, 0x1a, 0x9a, 0x71, 0x1e, 0x3e, 0x3e, 0x22, 0x8e, - 0x43, 0xbe, 0x95, 0xdc, 0x0f, 0x71, 0xbc, 0x9d, 0x09, 0xc5, 0x71, 0xc8, 0xb7, 0x97, 0xbf, 0x99, - 0x0b, 0xe7, 0xa4, 0xa3, 0x3d, 0xe6, 0x7e, 0x99, 0xc9, 0xa1, 0x1f, 0x6c, 0x61, 0x07, 0x0f, 0x19, - 0x65, 0xd5, 0xec, 0xdb, 0xa5, 0x6a, 0xfe, 0x6e, 0xb2, 0x3f, 0xb9, 0xe9, 0x79, 0x28, 0xfb, 0x73, - 0x1f, 0x06, 0x2b, 0xb9, 0x16, 0xae, 0x63, 0xdc, 0x46, 0xef, 0x95, 0x42, 0xfc, 0x2d, 0x09, 0x13, - 0x3d, 0x4a, 0x42, 0x3e, 0x02, 0xa7, 0x23, 0x80, 0x05, 0xdd, 0xd1, 0x9b, 0xd4, 0x0b, 0x33, 0x0e, - 0x62, 0xd0, 0x26, 0xbf, 0x74, 0xad, 0x15, 0xa0, 0xe5, 0x2c, 0x86, 0x1d, 0x38, 0x48, 0xca, 0xd1, - 0xb7, 0x03, 0x27, 0xe9, 0x2f, 0xe6, 0x42, 0x53, 0x25, 0x1a, 0x7c, 0x55, 0xa3, 0x6e, 0xbb, 0xe1, - 0x3d, 0xb8, 0x1d, 0xbc, 0xbb, 0xd4, 0x16, 0xd3, 0x70, 0xac, 0xb4, 0xbc, 0x4c, 0xeb, 0x9e, 0x1f, - 0x53, 0xda, 0x15, 0xe1, 0xf6, 0xf8, 0xd6, 0x41, 0xa0, 0x44, 0x8c, 0xe0, 0x48, 0x6e, 0xfc, 0x58, - 0x31, 0xf5, 0xf7, 0xf2, 0xa0, 0x04, 0xa6, 0x7b, 0xf0, 0x50, 0xeb, 0x00, 0x97, 0xc9, 0x77, 0x45, - 0xaf, 0x98, 0x30, 0x16, 0x0a, 0xa3, 0xda, 0x6e, 0x36, 0x75, 0x1c, 0x7a, 0x6c, 0x6b, 0x50, 0x8c, - 0x33, 0x0b, 0x09, 0xf9, 0x6e, 0xe0, 0xac, 0xd8, 0x0d, 0x90, 0xf0, 0x21, 0x5c, 0xcd, 0xe5, 0x2c, - 0xb4, 0x24, 0x57, 0xf2, 0xb9, 0x0c, 0x9c, 0xf0, 0x3b, 0x65, 0x7e, 0x89, 0x99, 0xc5, 0x13, 0x76, - 0xdb, 0xf2, 0xfc, 0x9d, 0xc8, 0x0b, 0x9d, 0xab, 0xe3, 0x9d, 0x74, 0x25, 0xad, 0x30, 0x6f, 0x49, - 0x10, 0x58, 0x22, 0x50, 0x08, 0x1b, 0x69, 0x6a, 0x75, 0x24, 0xd2, 0x52, 0xeb, 0x3d, 0x7b, 0x03, - 0xce, 0x74, 0x64, 0xb9, 0x95, 0x19, 0xda, 0x2b, 0x9b, 0xa1, 0xff, 0x22, 0x13, 0x4e, 0x44, 0x31, - 0x21, 0x91, 0x2b, 0x00, 0x21, 0x48, 0x6c, 0x4c, 0x47, 0x36, 0x37, 0x8a, 0x10, 0x0a, 0x4d, 0x93, - 0x28, 0xc8, 0x3c, 0x14, 0x84, 0x58, 0x78, 0x76, 0xdf, 0xf7, 0x6d, 0xd1, 0x0b, 0x57, 0x64, 0x39, - 0xe0, 0xa6, 0x53, 0x7c, 0xb3, 0x60, 0x73, 0xf6, 0x79, 0x18, 0xdc, 0xed, 0x77, 0x7d, 0x2e, 0x07, - 0x44, 0xde, 0x45, 0x1e, 0xa0, 0x89, 0x7d, 0x88, 0xa7, 0xb0, 0x4b, 0xd0, 0xcf, 0x3e, 0x01, 0xf3, - 0x5d, 0x48, 0xf1, 0x6d, 0xdb, 0x02, 0xa6, 0x05, 0xd8, 0x30, 0xb8, 0x54, 0x5f, 0x7a, 0x70, 0x29, - 0xf5, 0x07, 0x72, 0x70, 0x4a, 0xee, 0x90, 0x32, 0xc5, 0x90, 0xf9, 0x47, 0x9d, 0xf2, 0x0e, 0x76, - 0x8a, 0x0a, 0x05, 0xbe, 0x79, 0x10, 0xb9, 0x0b, 0xf8, 0xc1, 0x0e, 0x42, 0x34, 0x81, 0x51, 0xff, - 0x6d, 0x16, 0x86, 0x17, 0x6c, 0xd7, 0x5b, 0x71, 0xa8, 0xbb, 0xa0, 0x3b, 0xee, 0x03, 0xdc, 0x1d, - 0x1f, 0x80, 0x61, 0x0c, 0x0f, 0xd4, 0xa4, 0x16, 0x0f, 0xa1, 0xd3, 0x2b, 0x25, 0x1b, 0xf1, 0x11, - 0x22, 0xaf, 0x54, 0x84, 0x90, 0x69, 0x3f, 0xb7, 0xfc, 0xa4, 0xa0, 0x4d, 0xdc, 0xec, 0xe3, 0x70, - 0xf5, 0x27, 0x72, 0x30, 0xe4, 0x4b, 0x79, 0xdc, 0x3c, 0xac, 0x37, 0x35, 0x07, 0x2b, 0xe4, 0xab, - 0x00, 0x0b, 0xb6, 0xe3, 0xe9, 0x8d, 0xb9, 0x50, 0xf3, 0xf1, 0x88, 0xb3, 0x85, 0x50, 0x5e, 0x46, - 0x22, 0xc1, 0xf5, 0x2b, 0x34, 0xab, 0xf9, 0xc4, 0xc4, 0xd7, 0xaf, 0x00, 0xaa, 0x49, 0x14, 0xea, - 0xaf, 0x66, 0xe1, 0x98, 0xdf, 0x49, 0x93, 0xf7, 0x69, 0xbd, 0xfd, 0x20, 0xcf, 0x4d, 0x51, 0x69, - 0xf7, 0x6e, 0x29, 0x6d, 0xf5, 0xbf, 0x4a, 0x13, 0xc9, 0x44, 0xc3, 0x3e, 0x9a, 0x48, 0xfe, 0x3c, - 0x74, 0x5c, 0xfd, 0xce, 0x1c, 0x9c, 0xf0, 0xa5, 0x3e, 0xd5, 0xb6, 0xf0, 0x70, 0x60, 0x42, 0x6f, - 0x34, 0x1e, 0xe4, 0xdd, 0xf8, 0xa0, 0x2f, 0x88, 0x79, 0x11, 0x6f, 0x4f, 0xe4, 0xf8, 0x5b, 0x16, - 0xe0, 0x9a, 0x6d, 0x1a, 0x9a, 0x4c, 0x44, 0x5e, 0x81, 0x21, 0xff, 0x67, 0xc9, 0x59, 0xf1, 0xb7, - 0xe0, 0x78, 0xd4, 0x1f, 0x14, 0xd2, 0x9d, 0x48, 0x58, 0x81, 0x48, 0x01, 0xf5, 0xdf, 0x17, 0xe0, - 0xec, 0x1d, 0xd3, 0x32, 0xec, 0x35, 0xd7, 0x4f, 0x11, 0x79, 0xe8, 0x8f, 0xba, 0x0e, 0x3a, 0x35, - 0xe4, 0xeb, 0x70, 0x32, 0x2e, 0x52, 0x27, 0x08, 0xdc, 0x2d, 0x7a, 0x67, 0x8d, 0x13, 0xd4, 0xfc, - 0x64, 0x91, 0xe2, 0xbe, 0x4c, 0x4b, 0x2f, 0x19, 0xcf, 0x36, 0xd9, 0xb7, 0x9d, 0x6c, 0x93, 0x8f, - 0x43, 0xa1, 0x6c, 0x37, 0x75, 0xd3, 0x0f, 0x30, 0x83, 0xa3, 0x38, 0xa8, 0x17, 0x31, 0x9a, 0xa0, - 0x60, 0xfc, 0x45, 0xc5, 0xd8, 0x65, 0x03, 0x21, 0x7f, 0xbf, 0x00, 0xb3, 0xd2, 0x34, 0x99, 0x88, - 0xd8, 0x30, 0x2c, 0xaa, 0x13, 0xb7, 0x5b, 0x80, 0x9b, 0xa7, 0x67, 0x7c, 0x19, 0x75, 0x56, 0xab, - 0x2b, 0x91, 0x72, 0x7c, 0x1b, 0xc5, 0x93, 0x60, 0x8a, 0x8f, 0xe1, 0xf7, 0x5c, 0x5a, 0x94, 0xbf, - 0x24, 0x04, 0x9c, 0x64, 0x06, 0x93, 0x42, 0xc0, 0x59, 0x46, 0x26, 0x22, 0x93, 0x30, 0x86, 0xe1, - 0x95, 0x83, 0xad, 0x14, 0x53, 0x89, 0x21, 0x34, 0x2a, 0xf1, 0xd2, 0x84, 0x47, 0x64, 0x66, 0x1f, - 0x57, 0xab, 0x0b, 0xb4, 0x96, 0x2c, 0x71, 0xf6, 0x55, 0x20, 0xc9, 0x36, 0xef, 0xe8, 0xda, 0xe4, - 0x1f, 0x49, 0xfb, 0xba, 0xc3, 0xee, 0xf8, 0xb2, 0x1f, 0xb3, 0x5d, 0x24, 0x75, 0x58, 0xef, 0x3b, - 0x99, 0x3a, 0xac, 0xb0, 0xaf, 0xa9, 0xc3, 0xd4, 0x9f, 0xcf, 0xc0, 0x58, 0x22, 0xce, 0x38, 0x79, - 0x1a, 0x80, 0x43, 0xa4, 0x78, 0x8e, 0x18, 0x20, 0x25, 0x8c, 0x3d, 0x2e, 0xd6, 0xc0, 0x90, 0x8c, - 0x5c, 0x85, 0x7e, 0xfe, 0x4b, 0xc4, 0x60, 0x4a, 0x16, 0x69, 0xb7, 0x4d, 0x43, 0x0b, 0x88, 0xc2, - 0x5a, 0xf0, 0xe2, 0x30, 0x97, 0x5a, 0xc4, 0x5b, 0x6f, 0x05, 0xb5, 0x30, 0x32, 0xf5, 0xb3, 0x59, - 0x18, 0x0a, 0x1a, 0x5c, 0x32, 0x0e, 0x4a, 0xe7, 0x0a, 0x22, 0x64, 0x7b, 0x6e, 0xab, 0x90, 0xed, - 0xb1, 0x49, 0x55, 0xc4, 0x68, 0xdf, 0xbf, 0x77, 0x4f, 0x9f, 0xcf, 0xc2, 0xb1, 0xa0, 0xd6, 0x03, - 0xbc, 0xa3, 0x7a, 0x17, 0x89, 0xe4, 0x73, 0x19, 0x50, 0xc6, 0xcd, 0x46, 0xc3, 0xb4, 0x56, 0x2a, - 0xd6, 0xb2, 0xed, 0x34, 0x71, 0xd6, 0x3b, 0xb8, 0x73, 0x5a, 0xf5, 0x7b, 0x32, 0x30, 0x26, 0x1a, - 0x34, 0xa1, 0x3b, 0xc6, 0xc1, 0x1d, 0x82, 0xc5, 0x5b, 0x72, 0x70, 0xfa, 0xa2, 0x7e, 0x39, 0x0b, - 0x30, 0x63, 0xd7, 0xef, 0x1e, 0xf2, 0x67, 0x53, 0x2f, 0x42, 0x81, 0x07, 0xc2, 0x12, 0x1a, 0x3b, - 0x26, 0x9e, 0x07, 0xb1, 0x4f, 0xe3, 0x88, 0xf1, 0x51, 0x31, 0x1f, 0x17, 0x78, 0x20, 0x2d, 0x25, - 0xa3, 0x89, 0x22, 0xac, 0x52, 0x46, 0x27, 0x16, 0x8c, 0xa0, 0x52, 0x06, 0x8b, 0x56, 0xba, 0xb9, - 0x51, 0xcc, 0x37, 0xec, 0xfa, 0x5d, 0x0d, 0xe9, 0xd5, 0x3f, 0xcb, 0x70, 0xd9, 0x1d, 0xf2, 0xc7, - 0x9f, 0xfe, 0xe7, 0xe7, 0x77, 0xf8, 0xf9, 0xdf, 0x9b, 0x81, 0x13, 0x1a, 0xad, 0xdb, 0xf7, 0xa8, - 0xb3, 0x3e, 0x61, 0x1b, 0xf4, 0x06, 0xb5, 0xa8, 0x73, 0x50, 0x23, 0xea, 0xef, 0x62, 0x8e, 0x8b, - 0xb0, 0x31, 0xb7, 0x5c, 0x6a, 0x1c, 0x9e, 0xfc, 0x23, 0xea, 0xdf, 0xee, 0x03, 0x25, 0xd5, 0xb4, - 0x3d, 0xb4, 0xe6, 0x5c, 0xc7, 0xfd, 0x4a, 0x7e, 0xbf, 0xf6, 0x2b, 0xbd, 0x3b, 0xdb, 0xaf, 0x14, - 0x76, 0xba, 0x5f, 0xe9, 0xdb, 0xce, 0x7e, 0xa5, 0x19, 0xdf, 0xaf, 0xf4, 0xe3, 0x7e, 0xe5, 0xe9, - 0xae, 0xfb, 0x95, 0x49, 0xcb, 0xd8, 0xe5, 0x6e, 0xe5, 0xd0, 0xe6, 0xc6, 0xdd, 0xcd, 0x36, 0xeb, - 0x12, 0x9b, 0x14, 0xeb, 0xb6, 0x63, 0x50, 0x43, 0xec, 0xae, 0xf0, 0x68, 0xdf, 0x11, 0x30, 0x2d, - 0xc0, 0x26, 0x12, 0x0d, 0x0f, 0x6f, 0x27, 0xd1, 0xf0, 0x3e, 0xec, 0xbf, 0x3e, 0x93, 0x85, 0xb1, - 0x09, 0xea, 0x78, 0x3c, 0xd2, 0xe6, 0x7e, 0x78, 0xae, 0x95, 0xe0, 0x98, 0xc4, 0x10, 0x2d, 0xf2, - 0x6c, 0xe8, 0x8d, 0x57, 0xa7, 0x8e, 0x17, 0x77, 0xe6, 0x8b, 0xd3, 0xb3, 0xea, 0xfd, 0x64, 0x5f, - 0x62, 0xec, 0x06, 0xd5, 0xfb, 0x70, 0x2e, 0x48, 0x53, 0xfc, 0xd2, 0x02, 0x7a, 0x29, 0x7f, 0x57, - 0x7e, 0xe7, 0xf9, 0xbb, 0xd4, 0x9f, 0xcb, 0xc0, 0x45, 0x8d, 0x5a, 0x74, 0x4d, 0x5f, 0x6a, 0x50, - 0xa9, 0x59, 0x62, 0x65, 0x60, 0xb3, 0x86, 0xe9, 0x36, 0x75, 0xaf, 0xbe, 0xba, 0x27, 0x19, 0x4d, - 0xc1, 0x90, 0x3c, 0x7f, 0xed, 0x60, 0x6e, 0x8b, 0x94, 0x53, 0xff, 0x53, 0x0e, 0xfa, 0xc6, 0x6d, - 0xef, 0x35, 0x7b, 0x8f, 0x09, 0xe5, 0xc2, 0x29, 0x3f, 0xbb, 0x83, 0x03, 0x9d, 0xf7, 0x63, 0xe5, - 0x52, 0x8c, 0x7d, 0xf4, 0xf4, 0x5c, 0xb2, 0x13, 0xb9, 0x08, 0x7c, 0xb2, 0x1d, 0xa6, 0x92, 0x7b, - 0x16, 0x06, 0x30, 0x48, 0x8b, 0x74, 0xe4, 0x8a, 0x7e, 0xd4, 0x1e, 0x03, 0xc6, 0xeb, 0x08, 0x49, - 0xc9, 0x47, 0x22, 0xa1, 0x41, 0x0b, 0x7b, 0x4f, 0x3d, 0x27, 0x47, 0x09, 0x7d, 0x9a, 0xdf, 0xd6, - 0x61, 0x9b, 0xa4, 0x34, 0x1d, 0x78, 0x54, 0x12, 0x6b, 0x52, 0x40, 0xb8, 0x7f, 0x69, 0xe1, 0xd4, - 0x6f, 0xe6, 0x61, 0xc8, 0x77, 0xb9, 0x3d, 0xa0, 0x6e, 0x7f, 0x12, 0x0a, 0xd3, 0xb6, 0x94, 0x64, - 0x00, 0x5d, 0x74, 0x57, 0x6d, 0x37, 0xe6, 0x7b, 0x2c, 0x88, 0x98, 0xc0, 0xe6, 0x6c, 0x43, 0x76, - 0x30, 0x47, 0x81, 0x59, 0xb6, 0x91, 0x78, 0xa0, 0x1b, 0x10, 0x92, 0x8b, 0x90, 0x47, 0xdf, 0x7c, - 0xe9, 0xa0, 0x3d, 0xe6, 0x8f, 0x8f, 0x78, 0x49, 0xa1, 0x0a, 0x3b, 0x55, 0xa8, 0xbe, 0xdd, 0x2a, - 0x54, 0xff, 0xfe, 0x2a, 0xd4, 0x1b, 0x30, 0x84, 0x35, 0xf9, 0x39, 0xca, 0xb6, 0x5e, 0x13, 0xcf, - 0x88, 0x65, 0x6b, 0x98, 0xb7, 0x5b, 0x64, 0x2a, 0xc3, 0xd5, 0x2a, 0xc2, 0x2a, 0xa6, 0x76, 0xb0, - 0x07, 0xb5, 0xfb, 0xdd, 0x0c, 0xf4, 0xdd, 0xb2, 0xee, 0x5a, 0xf6, 0xda, 0xde, 0x34, 0xee, 0x69, - 0x18, 0x14, 0x6c, 0xa4, 0x85, 0x01, 0xdf, 0x5c, 0xb7, 0x39, 0xb8, 0x86, 0x9c, 0x34, 0x99, 0x8a, - 0xbc, 0x14, 0x14, 0xc2, 0xe7, 0x37, 0xb9, 0x30, 0x4d, 0x87, 0x5f, 0xa8, 0x1e, 0xcd, 0x2c, 0x20, - 0x93, 0x93, 0x73, 0x90, 0x2f, 0xb3, 0xa6, 0x4a, 0x71, 0x6a, 0x59, 0x53, 0x34, 0x84, 0xaa, 0x9f, - 0xc9, 0xc3, 0x48, 0xec, 0xcc, 0xea, 0x71, 0x18, 0x10, 0x67, 0x46, 0xa6, 0x9f, 0xea, 0x00, 0x9f, - 0xe7, 0x04, 0x40, 0xad, 0x9f, 0xff, 0x59, 0x31, 0xc8, 0x07, 0xa1, 0xcf, 0x76, 0x71, 0x3d, 0xc3, - 0x6f, 0x19, 0x09, 0x87, 0xd0, 0x7c, 0x95, 0xb5, 0x9d, 0x0f, 0x0e, 0x41, 0x22, 0x6b, 0xa4, 0xed, - 0xe2, 0xa7, 0x5d, 0x87, 0x01, 0xdd, 0x75, 0xa9, 0x57, 0xf3, 0xf4, 0x15, 0x39, 0xfb, 0x41, 0x00, - 0x94, 0x47, 0x07, 0x02, 0x17, 0xf5, 0x15, 0xf2, 0x2a, 0x0c, 0xd7, 0x1d, 0x8a, 0x2b, 0x9e, 0xde, - 0x60, 0xad, 0x94, 0x2c, 0xd2, 0x08, 0x42, 0xbe, 0xdf, 0x08, 0x11, 0x15, 0x83, 0xdc, 0x86, 0x61, - 0xf1, 0x39, 0xdc, 0x37, 0x1e, 0x07, 0xda, 0x48, 0xb8, 0x02, 0x71, 0x91, 0x70, 0xef, 0x78, 0xf1, - 0x44, 0x42, 0x26, 0x97, 0xf9, 0x1a, 0x12, 0x29, 0x99, 0x07, 0xb2, 0x46, 0x97, 0x6a, 0x7a, 0xdb, - 0x5b, 0x65, 0x75, 0xf1, 0xe0, 0xdd, 0x22, 0xe9, 0x1f, 0xbe, 0x2b, 0x48, 0x62, 0xe5, 0xe7, 0x16, - 0x6b, 0x74, 0xa9, 0x14, 0x41, 0x92, 0x3b, 0x70, 0x32, 0x59, 0x84, 0x7d, 0x32, 0x3f, 0xbc, 0x7f, - 0x74, 0x73, 0xa3, 0x58, 0x4c, 0x25, 0x90, 0xd8, 0x1e, 0x4f, 0xb0, 0xad, 0x18, 0xaf, 0xe5, 0xfb, - 0xfb, 0x46, 0xfb, 0xb5, 0x11, 0x56, 0xd6, 0xb7, 0xfe, 0x4c, 0x43, 0xfd, 0x5a, 0x86, 0x59, 0x79, - 0xec, 0x83, 0x30, 0xeb, 0x31, 0xd3, 0xf5, 0xe6, 0x0e, 0x75, 0xbd, 0x19, 0xe6, 0x27, 0x2c, 0xb8, - 0x5d, 0x66, 0x57, 0x4d, 0x60, 0xc9, 0x15, 0x28, 0x18, 0xf2, 0x81, 0xd7, 0xa9, 0x68, 0x27, 0xf8, - 0xf5, 0x68, 0x82, 0x8a, 0x5c, 0x82, 0x3c, 0x5b, 0x6d, 0xe2, 0xbb, 0x5d, 0xd9, 0x30, 0xd0, 0x90, - 0x42, 0xfd, 0xf6, 0x2c, 0x0c, 0x49, 0x5f, 0x73, 0x6d, 0x4f, 0x9f, 0xf3, 0xc2, 0xf6, 0x9a, 0xe9, - 0x3b, 0xa5, 0xe0, 0x36, 0xc8, 0x6f, 0xf2, 0xf5, 0x40, 0x14, 0xdb, 0xba, 0x30, 0x12, 0x82, 0x79, - 0x56, 0x7c, 0x68, 0x61, 0xfb, 0x3b, 0x3f, 0x46, 0xff, 0x5a, 0xbe, 0x3f, 0x3b, 0x9a, 0x7b, 0x2d, - 0xdf, 0x9f, 0x1f, 0xed, 0xc5, 0x48, 0x57, 0x18, 0x5c, 0x9a, 0x6f, 0xab, 0xad, 0x65, 0x73, 0xe5, - 0x90, 0xbf, 0xce, 0xd8, 0xdf, 0x28, 0x60, 0x31, 0xd9, 0x1c, 0xf2, 0xa7, 0x1a, 0xef, 0xa8, 0x6c, - 0x8e, 0xf2, 0x19, 0x0a, 0xd9, 0xfc, 0x5e, 0x06, 0x94, 0x54, 0xd9, 0x94, 0x0e, 0xc8, 0x4f, 0x61, - 0xff, 0xb2, 0x1a, 0x7e, 0x23, 0x0b, 0x63, 0x15, 0xcb, 0xa3, 0x2b, 0x7c, 0xb3, 0x77, 0xc8, 0xa7, - 0x8a, 0x9b, 0x30, 0x28, 0x7d, 0x8c, 0xe8, 0xf3, 0x87, 0x82, 0xad, 0x74, 0x88, 0xea, 0xc0, 0x49, - 0x2e, 0xbd, 0x8f, 0x89, 0xd0, 0x63, 0x42, 0x3e, 0xe4, 0x73, 0xce, 0xe1, 0x10, 0xf2, 0x21, 0x9f, - 0xbc, 0xde, 0xa5, 0x42, 0xfe, 0xcf, 0x19, 0x38, 0x9e, 0x52, 0x39, 0xb9, 0x08, 0x7d, 0xd5, 0xf6, - 0x12, 0x06, 0xb6, 0xca, 0x84, 0x1e, 0xbd, 0x6e, 0x7b, 0x09, 0x63, 0x5a, 0x69, 0x3e, 0x92, 0x2c, - 0xe2, 0xf3, 0xf5, 0xf9, 0x4a, 0x79, 0x42, 0x48, 0x55, 0x95, 0x1e, 0xe2, 0x33, 0x70, 0xda, 0x97, - 0x05, 0x4f, 0xdc, 0x6d, 0xd3, 0xa8, 0xc7, 0x9e, 0xb8, 0xb3, 0x32, 0xe4, 0xa3, 0x30, 0x50, 0x7a, - 0xab, 0xed, 0x50, 0xe4, 0xcb, 0x25, 0xfe, 0x9e, 0x80, 0xaf, 0x8f, 0x48, 0xe3, 0xcc, 0x5f, 0xeb, - 0x33, 0x8a, 0x38, 0xef, 0x90, 0xa1, 0xfa, 0xd9, 0x0c, 0x9c, 0xed, 0xdc, 0x3a, 0xf2, 0x7e, 0xe8, - 0x63, 0x3b, 0xf3, 0x92, 0x36, 0x27, 0x3e, 0x9d, 0x67, 0x00, 0xb5, 0x1b, 0xb4, 0xa6, 0x3b, 0xb2, - 0xb1, 0xef, 0x93, 0x91, 0x97, 0x61, 0xb0, 0xe2, 0xba, 0x6d, 0xea, 0x54, 0x9f, 0xbe, 0xa5, 0x55, - 0xc4, 0x9e, 0x10, 0xf7, 0x1c, 0x26, 0x82, 0x6b, 0xee, 0xd3, 0xb1, 0xd0, 0x55, 0x32, 0xbd, 0xfa, - 0xa9, 0x0c, 0x9c, 0xeb, 0xf6, 0x55, 0xe4, 0x69, 0xe8, 0x5f, 0xa4, 0x96, 0x6e, 0x79, 0x95, 0xb2, - 0x68, 0x12, 0x6e, 0xb1, 0x3c, 0x84, 0x45, 0x77, 0x0a, 0x01, 0x21, 0x2b, 0xc4, 0x8f, 0x04, 0x03, - 0x1f, 0x04, 0x7e, 0x7c, 0x89, 0xb0, 0x58, 0x21, 0x9f, 0x50, 0xfd, 0xa9, 0x25, 0xe8, 0x9d, 0xb7, - 0xe8, 0xfc, 0x32, 0x79, 0x0a, 0x06, 0x98, 0xee, 0x63, 0xfa, 0x7d, 0x31, 0xd0, 0xc6, 0xe4, 0x01, - 0x83, 0x88, 0xe9, 0x1e, 0x2d, 0xa4, 0x22, 0xd7, 0xe5, 0x9c, 0xdf, 0x42, 0x1d, 0x88, 0x5c, 0x86, - 0x63, 0xa6, 0x7b, 0x34, 0x39, 0x37, 0xf8, 0x75, 0x39, 0xd7, 0xb2, 0xe8, 0xec, 0x48, 0x29, 0x8e, - 0xf1, 0x4b, 0x89, 0x69, 0x60, 0x26, 0x2d, 0x21, 0x71, 0xdc, 0x26, 0x48, 0x52, 0x4c, 0xf7, 0x68, - 0xe9, 0x89, 0x8c, 0x87, 0x64, 0x37, 0xa6, 0xf8, 0x2d, 0xa4, 0x8c, 0x9b, 0xee, 0xd1, 0x22, 0xb4, - 0xe4, 0x39, 0x18, 0x14, 0xbf, 0x5f, 0xb3, 0x4d, 0x2b, 0x1e, 0xc3, 0x42, 0x42, 0x4d, 0xf7, 0x68, - 0x32, 0xa5, 0x54, 0xe9, 0x82, 0x63, 0x5a, 0x9e, 0x78, 0x19, 0x17, 0xaf, 0x14, 0x71, 0x52, 0xa5, - 0xf8, 0x9b, 0xbc, 0x0c, 0xc3, 0x41, 0x70, 0x90, 0x37, 0x69, 0xdd, 0x13, 0x47, 0x3a, 0x27, 0x63, - 0x85, 0x39, 0x72, 0xba, 0x47, 0x8b, 0x52, 0x93, 0x4b, 0x50, 0xd0, 0xa8, 0x6b, 0xbe, 0xe5, 0xdf, - 0x5f, 0x8c, 0x48, 0xd3, 0x99, 0xf9, 0x16, 0x93, 0x92, 0xc0, 0xb3, 0xde, 0x09, 0x2f, 0x4c, 0xc4, - 0x01, 0x0c, 0x89, 0xd5, 0x32, 0x69, 0x19, 0xac, 0x77, 0xa4, 0xdb, 0xb2, 0x57, 0xc3, 0x90, 0x29, - 0x22, 0xd1, 0xda, 0x60, 0xfc, 0x6d, 0xaa, 0x8c, 0x9d, 0xee, 0xd1, 0x62, 0xf4, 0x92, 0x54, 0xcb, - 0xa6, 0x7b, 0x57, 0x44, 0xa9, 0x8b, 0x4b, 0x95, 0xa1, 0x24, 0xa9, 0xb2, 0x9f, 0x52, 0xd5, 0x73, - 0xd4, 0x5b, 0xb3, 0x9d, 0xbb, 0x22, 0x26, 0x5d, 0xbc, 0x6a, 0x81, 0x95, 0xaa, 0x16, 0x10, 0xb9, - 0x6a, 0xb6, 0xc8, 0x8c, 0xa4, 0x57, 0xad, 0x7b, 0xba, 0x5c, 0x35, 0xdf, 0x5f, 0xfa, 0x9d, 0x34, - 0x43, 0xf5, 0x7b, 0x3c, 0xdf, 0x6d, 0xb2, 0x43, 0x11, 0x27, 0x75, 0x28, 0xfe, 0x66, 0x95, 0x4a, - 0x39, 0x4d, 0x45, 0x42, 0xdb, 0xa0, 0x52, 0x09, 0xc5, 0x2a, 0x95, 0xb3, 0x9f, 0x5e, 0x97, 0x53, - 0x7d, 0x2a, 0x63, 0xd1, 0x0e, 0x0a, 0x31, 0xac, 0x83, 0xa4, 0x94, 0xa0, 0x45, 0x4c, 0x23, 0xa8, - 0x10, 0x24, 0x1f, 0x0c, 0x5a, 0x38, 0xb1, 0x30, 0xdd, 0xa3, 0x61, 0x82, 0x41, 0x95, 0x27, 0xa8, - 0x54, 0x8e, 0x23, 0xc5, 0x90, 0x4f, 0xc1, 0x60, 0xd3, 0x3d, 0x1a, 0x4f, 0x5e, 0xf9, 0x94, 0x94, - 0x0a, 0x4a, 0x39, 0x11, 0x9d, 0x22, 0x02, 0x04, 0x9b, 0x22, 0xc2, 0x84, 0x51, 0x53, 0xc9, 0x74, - 0x49, 0xca, 0xc9, 0xe8, 0x8a, 0x1a, 0xc7, 0x4f, 0xf7, 0x68, 0xc9, 0x14, 0x4b, 0xcf, 0x45, 0x32, - 0x08, 0x29, 0xa7, 0x62, 0x81, 0x63, 0x42, 0x14, 0x13, 0x97, 0x9c, 0x6b, 0x68, 0x3e, 0x35, 0xe7, - 0xb7, 0x72, 0x3a, 0xba, 0x1c, 0xa7, 0x90, 0x4c, 0xf7, 0x68, 0xa9, 0xd9, 0xc2, 0x27, 0x12, 0x79, - 0x7c, 0x14, 0x25, 0x7a, 0x59, 0x1b, 0x43, 0x4f, 0xf7, 0x68, 0x89, 0xcc, 0x3f, 0xd7, 0xe5, 0x04, - 0x3a, 0xca, 0x99, 0x68, 0x27, 0x86, 0x18, 0xd6, 0x89, 0x52, 0xa2, 0x9d, 0xeb, 0x72, 0x52, 0x15, - 0xe5, 0x6c, 0xb2, 0x54, 0x38, 0x73, 0x4a, 0xc9, 0x57, 0xb4, 0xf4, 0x3c, 0x11, 0xca, 0x43, 0x22, - 0x53, 0x9f, 0x28, 0x9f, 0x46, 0x33, 0xdd, 0xa3, 0xa5, 0xe7, 0x98, 0xd0, 0xd2, 0x13, 0x2c, 0x28, - 0xe7, 0xba, 0xf1, 0x0c, 0x5a, 0x97, 0x9e, 0x9c, 0x41, 0xef, 0x12, 0xee, 0x5e, 0x39, 0x1f, 0x8d, - 0x5a, 0xd9, 0x91, 0x70, 0xba, 0x47, 0xeb, 0x12, 0x34, 0xff, 0x56, 0x87, 0xd8, 0xf3, 0xca, 0x85, - 0x68, 0xa2, 0xce, 0x54, 0xa2, 0xe9, 0x1e, 0xad, 0x43, 0xe4, 0xfa, 0x5b, 0x1d, 0x42, 0x93, 0x2b, - 0xc5, 0xae, 0x6c, 0x03, 0x79, 0x74, 0x08, 0x6c, 0x3e, 0x9f, 0x1a, 0xd5, 0x5b, 0x79, 0x38, 0xaa, - 0xba, 0x29, 0x24, 0x4c, 0x75, 0xd3, 0xe2, 0x81, 0xcf, 0xa7, 0x86, 0xa1, 0x56, 0x1e, 0xe9, 0xc2, - 0x30, 0x68, 0x63, 0x6a, 0x00, 0xeb, 0xf9, 0xd4, 0x38, 0xd0, 0x8a, 0x1a, 0x65, 0x98, 0x42, 0xc2, - 0x18, 0xa6, 0x45, 0x90, 0x9e, 0x4f, 0x0d, 0x17, 0xac, 0x3c, 0xda, 0x85, 0x61, 0xd8, 0xc2, 0xb4, - 0x40, 0xc3, 0xcf, 0x45, 0xe2, 0xf5, 0x2a, 0xef, 0x89, 0xce, 0x1b, 0x12, 0x8a, 0xcd, 0x1b, 0x72, - 0x64, 0xdf, 0x89, 0x44, 0x44, 0x42, 0xe5, 0xb1, 0xe8, 0x30, 0x8f, 0xa1, 0xd9, 0x30, 0x8f, 0xc7, - 0x30, 0x9c, 0x48, 0x44, 0x66, 0x53, 0x2e, 0x76, 0x62, 0x82, 0xe8, 0x28, 0x13, 0x1e, 0xcb, 0xad, - 0x92, 0x12, 0x1a, 0x4c, 0x79, 0x6f, 0xd4, 0xd1, 0x30, 0x41, 0x30, 0xdd, 0xa3, 0xa5, 0x04, 0x14, - 0xd3, 0xd2, 0xe3, 0x60, 0x28, 0x97, 0xa2, 0xc3, 0x36, 0x8d, 0x86, 0x0d, 0xdb, 0xd4, 0x18, 0x1a, - 0x33, 0x69, 0xde, 0xd0, 0xca, 0xe5, 0xa8, 0x61, 0x96, 0xa4, 0x60, 0x86, 0x59, 0x8a, 0x17, 0xb5, - 0x96, 0x1e, 0xd9, 0x41, 0x79, 0xbc, 0x6b, 0x0b, 0x91, 0x26, 0xa5, 0x85, 0x3c, 0xd0, 0x41, 0x68, - 0x3b, 0xdd, 0x6a, 0x35, 0x6c, 0xdd, 0x50, 0xde, 0x97, 0x6a, 0x3b, 0x71, 0xa4, 0x64, 0x3b, 0x71, - 0x00, 0x5b, 0xe5, 0x65, 0xa7, 0x5b, 0xe5, 0x89, 0xe8, 0x2a, 0x2f, 0xe3, 0xd8, 0x2a, 0x1f, 0x71, - 0xd0, 0x9d, 0x48, 0x38, 0xa8, 0x2a, 0x4f, 0x46, 0x15, 0x20, 0x86, 0x66, 0x0a, 0x10, 0x77, 0x69, - 0xfd, 0x78, 0x67, 0x97, 0x4e, 0xe5, 0x0a, 0x72, 0x7b, 0xd8, 0xe7, 0xd6, 0x89, 0x6e, 0xba, 0x47, - 0xeb, 0xec, 0x16, 0x5a, 0x49, 0xf1, 0xd0, 0x54, 0xae, 0x46, 0x15, 0x2c, 0x41, 0xc0, 0x14, 0x2c, - 0xe9, 0xd7, 0x59, 0x49, 0x71, 0xb1, 0x54, 0xde, 0xdf, 0x91, 0x55, 0xf0, 0xcd, 0x29, 0x8e, 0x99, - 0xd7, 0x65, 0x1f, 0x49, 0xe5, 0xa9, 0xe8, 0x62, 0x17, 0x62, 0xd8, 0x62, 0x27, 0xf9, 0x52, 0x5e, - 0x97, 0xbd, 0x03, 0x95, 0x6b, 0xc9, 0x52, 0xe1, 0x12, 0x29, 0x79, 0x11, 0x6a, 0xe9, 0x4e, 0x75, - 0xca, 0xd3, 0x51, 0xad, 0x4b, 0xa3, 0x61, 0x5a, 0x97, 0xea, 0x90, 0x37, 0x95, 0xf4, 0x8d, 0x53, - 0xae, 0xc7, 0xcf, 0x12, 0xa2, 0x78, 0x66, 0xf9, 0x24, 0xfc, 0xe9, 0x5e, 0x8d, 0x07, 0x69, 0x52, - 0x9e, 0x89, 0x5d, 0x66, 0x44, 0xb0, 0xcc, 0xbe, 0x8d, 0x05, 0x75, 0x7a, 0x35, 0x1e, 0xd7, 0x48, - 0x79, 0x36, 0x9d, 0x43, 0xa0, 0x2b, 0xf1, 0x38, 0x48, 0xaf, 0xc6, 0x43, 0x01, 0x29, 0xcf, 0xa5, - 0x73, 0x08, 0xa4, 0x1b, 0x0f, 0x1d, 0xf4, 0x94, 0x14, 0x9c, 0x58, 0xf9, 0x40, 0xd4, 0x74, 0x0c, - 0x10, 0xcc, 0x74, 0x0c, 0x43, 0x18, 0x3f, 0x25, 0x05, 0xf5, 0x55, 0x9e, 0x4f, 0x14, 0x09, 0x1a, - 0x2b, 0x85, 0xfe, 0x7d, 0x4a, 0x0a, 0x86, 0xab, 0xbc, 0x90, 0x28, 0x12, 0xb4, 0x4e, 0x0a, 0x99, - 0x6b, 0x74, 0x7b, 0x35, 0xa5, 0xbc, 0x18, 0x3d, 0xe2, 0xe8, 0x4c, 0x39, 0xdd, 0xa3, 0x75, 0x7b, - 0x7d, 0xf5, 0xf1, 0xce, 0x9e, 0x86, 0xca, 0x4b, 0xd1, 0x21, 0xdc, 0x89, 0x8e, 0x0d, 0xe1, 0x8e, - 0xde, 0x8a, 0x2f, 0xc7, 0x5e, 0x50, 0x2b, 0x2f, 0x47, 0xa7, 0xb8, 0x08, 0x92, 0x4d, 0x71, 0xf1, - 0xf7, 0xd6, 0x91, 0xa7, 0xc1, 0xca, 0x07, 0xa3, 0x53, 0x9c, 0x8c, 0x63, 0x53, 0x5c, 0xe4, 0x19, - 0xf1, 0x44, 0xe2, 0xc5, 0xaa, 0xf2, 0x4a, 0x74, 0x8a, 0x8b, 0xa1, 0xd9, 0x14, 0x17, 0x7f, 0xe3, - 0xfa, 0x72, 0xec, 0xe1, 0xa6, 0xf2, 0x6a, 0x7a, 0xfb, 0x11, 0x29, 0xb7, 0x9f, 0x3f, 0xf3, 0xd4, - 0xd2, 0x5f, 0x20, 0x2a, 0xa5, 0xe8, 0xf8, 0x4d, 0xa3, 0x61, 0xe3, 0x37, 0xf5, 0xf5, 0x62, 0x7c, - 0xe3, 0x20, 0xb4, 0x6a, 0xbc, 0xcb, 0xc6, 0x21, 0x34, 0x45, 0x52, 0xc0, 0x91, 0x3d, 0x32, 0xdf, - 0x08, 0x4d, 0x74, 0xd8, 0x23, 0xfb, 0xdb, 0xa0, 0x18, 0x3d, 0x9b, 0x5d, 0x13, 0x8e, 0x6f, 0x4a, - 0x39, 0x3a, 0xbb, 0x26, 0x08, 0xd8, 0xec, 0x9a, 0x74, 0x97, 0x9b, 0x82, 0x51, 0xa1, 0x45, 0xdc, - 0x9f, 0xcf, 0xb4, 0x56, 0x94, 0xc9, 0xd8, 0x03, 0xa0, 0x18, 0x9e, 0xcd, 0x4e, 0x71, 0x18, 0xae, - 0xd7, 0x1c, 0x36, 0xd1, 0x30, 0x5b, 0x4b, 0xb6, 0xee, 0x18, 0x55, 0x6a, 0x19, 0xca, 0x54, 0x6c, - 0xbd, 0x4e, 0xa1, 0xc1, 0xf5, 0x3a, 0x05, 0x8e, 0x81, 0x89, 0x62, 0x70, 0x8d, 0xd6, 0xa9, 0x79, - 0x8f, 0x2a, 0x37, 0x90, 0x6d, 0xb1, 0x13, 0x5b, 0x41, 0x36, 0xdd, 0xa3, 0x75, 0xe2, 0xc0, 0x6c, - 0xf5, 0xd9, 0xf5, 0xea, 0xeb, 0x33, 0xc1, 0xa3, 0xd7, 0x05, 0x87, 0xb6, 0x74, 0x87, 0x2a, 0xd3, - 0x51, 0x5b, 0x3d, 0x95, 0x88, 0xd9, 0xea, 0xa9, 0x88, 0x24, 0x5b, 0x7f, 0x2c, 0x54, 0xba, 0xb1, - 0x0d, 0x47, 0x44, 0x7a, 0x69, 0x36, 0x3b, 0x45, 0x11, 0x4c, 0x40, 0x33, 0xb6, 0xb5, 0x82, 0x27, - 0x15, 0xaf, 0x45, 0x67, 0xa7, 0xce, 0x94, 0x6c, 0x76, 0xea, 0x8c, 0x65, 0xaa, 0x1e, 0xc5, 0xf2, - 0x31, 0x78, 0x33, 0xaa, 0xea, 0x29, 0x24, 0x4c, 0xd5, 0x53, 0xc0, 0x49, 0x86, 0x1a, 0x75, 0xa9, - 0xa7, 0xcc, 0x74, 0x63, 0x88, 0x24, 0x49, 0x86, 0x08, 0x4e, 0x32, 0x9c, 0xa2, 0x5e, 0x7d, 0x55, - 0x99, 0xed, 0xc6, 0x10, 0x49, 0x92, 0x0c, 0x11, 0xcc, 0x36, 0x9b, 0x51, 0xf0, 0x78, 0xbb, 0x71, - 0xd7, 0xef, 0xb3, 0xb9, 0xe8, 0x66, 0xb3, 0x23, 0x21, 0xdb, 0x6c, 0x76, 0x44, 0x92, 0x4f, 0x6d, - 0xdb, 0x31, 0x53, 0x99, 0xc7, 0x0a, 0xaf, 0x84, 0x76, 0xc1, 0x76, 0x4a, 0x4d, 0xf7, 0x68, 0xdb, - 0x75, 0xfc, 0x7c, 0x5f, 0xe0, 0x0a, 0xa5, 0x2c, 0x60, 0x55, 0xc7, 0x82, 0xb3, 0x0a, 0x0e, 0x9e, - 0xee, 0xd1, 0x02, 0x67, 0xa9, 0xe7, 0x60, 0x10, 0x3f, 0xaa, 0x62, 0x99, 0x5e, 0x79, 0x5c, 0x79, - 0x3d, 0xba, 0x65, 0x92, 0x50, 0x6c, 0xcb, 0x24, 0xfd, 0x64, 0x93, 0x38, 0xfe, 0xe4, 0x53, 0x4c, - 0x79, 0x5c, 0xd1, 0xa2, 0x93, 0x78, 0x04, 0xc9, 0x26, 0xf1, 0x08, 0x20, 0xa8, 0xb7, 0xec, 0xd8, - 0xad, 0xf2, 0xb8, 0x52, 0x4d, 0xa9, 0x97, 0xa3, 0x82, 0x7a, 0xf9, 0xcf, 0xa0, 0xde, 0xea, 0x6a, - 0xdb, 0x2b, 0xb3, 0x6f, 0x5c, 0x4c, 0xa9, 0xd7, 0x47, 0x06, 0xf5, 0xfa, 0x00, 0x36, 0x15, 0x22, - 0x60, 0xc1, 0xb1, 0xd9, 0xa4, 0x7d, 0xd3, 0x6c, 0x34, 0x94, 0x5b, 0xd1, 0xa9, 0x30, 0x8e, 0x67, - 0x53, 0x61, 0x1c, 0xc6, 0x4c, 0x4f, 0xde, 0x2a, 0xba, 0xd4, 0x5e, 0x51, 0x6e, 0x47, 0x4d, 0xcf, - 0x10, 0xc3, 0x4c, 0xcf, 0xf0, 0x17, 0xee, 0x2e, 0xd8, 0x2f, 0x8d, 0x2e, 0x3b, 0xd4, 0x5d, 0x55, - 0xee, 0xc4, 0x76, 0x17, 0x12, 0x0e, 0x77, 0x17, 0xd2, 0x6f, 0xb2, 0x02, 0x0f, 0x45, 0x16, 0x1a, - 0xff, 0xee, 0xa9, 0x4a, 0x75, 0xa7, 0xbe, 0xaa, 0x7c, 0x08, 0x59, 0x3d, 0x9a, 0xba, 0x54, 0x45, - 0x49, 0xa7, 0x7b, 0xb4, 0x6e, 0x9c, 0x70, 0x5b, 0xfe, 0xfa, 0x0c, 0x8f, 0x20, 0xa8, 0x2d, 0x4c, - 0xf8, 0x9b, 0xd0, 0x37, 0x62, 0xdb, 0xf2, 0x24, 0x09, 0x6e, 0xcb, 0x93, 0x60, 0xd2, 0x82, 0x0b, - 0xb1, 0xad, 0xda, 0xac, 0xde, 0x60, 0xfb, 0x12, 0x6a, 0x2c, 0xe8, 0xf5, 0xbb, 0xd4, 0x53, 0x3e, - 0x8c, 0xbc, 0x2f, 0x76, 0xd8, 0xf0, 0xc5, 0xa8, 0xa7, 0x7b, 0xb4, 0x2d, 0xf8, 0x11, 0x15, 0xf2, - 0xd5, 0xa9, 0xc5, 0x05, 0xe5, 0x23, 0xd1, 0xf3, 0x4d, 0x06, 0x9b, 0xee, 0xd1, 0x10, 0xc7, 0xac, - 0xb4, 0x5b, 0xad, 0x15, 0x47, 0x37, 0x28, 0x37, 0xb4, 0xd0, 0x76, 0x13, 0x06, 0xe8, 0x47, 0xa3, - 0x56, 0x5a, 0x27, 0x3a, 0x66, 0xa5, 0x75, 0xc2, 0x31, 0x45, 0x8d, 0x04, 0xcb, 0x57, 0x3e, 0x16, - 0x55, 0xd4, 0x08, 0x92, 0x29, 0x6a, 0x34, 0xb4, 0xfe, 0x87, 0xe0, 0x54, 0xb0, 0x9f, 0x17, 0xeb, - 0x2f, 0xef, 0x34, 0xe5, 0xe3, 0xc8, 0xe7, 0x42, 0xe2, 0x32, 0x20, 0x42, 0x35, 0xdd, 0xa3, 0x75, - 0x28, 0xcf, 0x56, 0xdc, 0x44, 0x1e, 0x18, 0x61, 0x5e, 0x7c, 0x5b, 0x74, 0xc5, 0xed, 0x40, 0xc6, - 0x56, 0xdc, 0x0e, 0xa8, 0x54, 0xe6, 0x42, 0xa8, 0xfa, 0x16, 0xcc, 0x03, 0x99, 0x76, 0xe2, 0x90, - 0xca, 0x5c, 0x58, 0x6a, 0x4b, 0x5b, 0x30, 0x0f, 0xac, 0xb5, 0x4e, 0x1c, 0xc8, 0x25, 0x28, 0x54, - 0xab, 0xb3, 0x5a, 0xdb, 0x52, 0xea, 0x31, 0x1f, 0x30, 0x84, 0x4e, 0xf7, 0x68, 0x02, 0xcf, 0xcc, - 0xa0, 0xc9, 0x86, 0xee, 0x7a, 0x66, 0xdd, 0xc5, 0x11, 0xe3, 0x8f, 0x10, 0x23, 0x6a, 0x06, 0xa5, - 0xd1, 0x30, 0x33, 0x28, 0x0d, 0xce, 0xec, 0xc5, 0x09, 0xdd, 0x75, 0x75, 0xcb, 0x70, 0xf4, 0x71, - 0x5c, 0x26, 0x68, 0xec, 0x79, 0x40, 0x04, 0xcb, 0xec, 0xc5, 0x28, 0x04, 0x0f, 0xdf, 0x7d, 0x88, - 0x6f, 0xe6, 0x2c, 0xc7, 0x0e, 0xdf, 0x63, 0x78, 0x3c, 0x7c, 0x8f, 0xc1, 0xd0, 0xee, 0xf4, 0x61, - 0x1a, 0x5d, 0x31, 0x99, 0x88, 0x94, 0x95, 0x98, 0xdd, 0x19, 0x27, 0x40, 0xbb, 0x33, 0x0e, 0x8c, - 0x34, 0xc9, 0x5f, 0x6e, 0x57, 0x3b, 0x34, 0x29, 0x5c, 0x65, 0x13, 0x65, 0xd8, 0xfa, 0x1d, 0x0e, - 0x8e, 0xf2, 0xba, 0xa5, 0x37, 0xed, 0xf2, 0xb8, 0x2f, 0x75, 0x33, 0xba, 0x7e, 0x77, 0x24, 0x64, - 0xeb, 0x77, 0x47, 0x24, 0x9b, 0x5d, 0xfd, 0x8d, 0xd6, 0xaa, 0xee, 0x50, 0xa3, 0x6c, 0x3a, 0x78, - 0xb2, 0xb8, 0xce, 0xb7, 0x86, 0x6f, 0x46, 0x67, 0xd7, 0x2e, 0xa4, 0x6c, 0x76, 0xed, 0x82, 0x66, - 0x46, 0x5e, 0x3a, 0x5a, 0xa3, 0xba, 0xa1, 0xdc, 0x8d, 0x1a, 0x79, 0x9d, 0x29, 0x99, 0x91, 0xd7, - 0x19, 0xdb, 0xf9, 0x73, 0xee, 0x38, 0xa6, 0x47, 0x95, 0xc6, 0x76, 0x3e, 0x07, 0x49, 0x3b, 0x7f, - 0x0e, 0xa2, 0xd9, 0x86, 0x30, 0xde, 0x21, 0xcd, 0xe8, 0x86, 0x30, 0xd9, 0x0d, 0xf1, 0x12, 0xcc, - 0x62, 0x11, 0xaf, 0x44, 0x14, 0x2b, 0x6a, 0xb1, 0x08, 0x30, 0xb3, 0x58, 0xc2, 0x77, 0x24, 0x91, - 0x07, 0x06, 0x8a, 0x1d, 0x5d, 0x43, 0x65, 0x1c, 0x5b, 0x43, 0x23, 0x8f, 0x11, 0x9e, 0x8b, 0x78, - 0xcf, 0x2a, 0xad, 0xa8, 0xd5, 0x21, 0xa1, 0x98, 0xd5, 0x21, 0xfb, 0xd9, 0x4e, 0xc0, 0x31, 0xbc, - 0x05, 0xd7, 0xda, 0xc1, 0x3d, 0xce, 0x27, 0xa2, 0x9f, 0x19, 0x43, 0xb3, 0xcf, 0x8c, 0x81, 0x22, - 0x4c, 0xc4, 0xb4, 0xe5, 0x74, 0x60, 0x12, 0x9e, 0x0f, 0xc6, 0x40, 0x64, 0x06, 0x48, 0xb5, 0x34, - 0x3b, 0x53, 0x31, 0x16, 0xe4, 0x2b, 0x32, 0x37, 0x7a, 0x02, 0x9b, 0xa4, 0x98, 0xee, 0xd1, 0x52, - 0xca, 0x91, 0x37, 0xe1, 0x9c, 0x80, 0x8a, 0x27, 0x80, 0x98, 0x2e, 0xda, 0x08, 0x16, 0x04, 0x2f, - 0xea, 0x9d, 0xd1, 0x8d, 0x76, 0xba, 0x47, 0xeb, 0xca, 0xab, 0x73, 0x5d, 0x62, 0x7d, 0x68, 0x6f, - 0xa7, 0xae, 0x60, 0x91, 0xe8, 0xca, 0xab, 0x73, 0x5d, 0x42, 0xee, 0xf7, 0xb6, 0x53, 0x57, 0xd0, - 0x09, 0x5d, 0x79, 0x11, 0x17, 0x8a, 0xdd, 0xf0, 0xa5, 0x46, 0x43, 0x59, 0xc3, 0xea, 0xde, 0xbb, - 0x9d, 0xea, 0x4a, 0x68, 0x70, 0x6e, 0xc5, 0x91, 0xcd, 0xd2, 0xf3, 0x2d, 0x6a, 0x55, 0x23, 0x0b, - 0xd0, 0xfd, 0xe8, 0x2c, 0x9d, 0x20, 0x60, 0xb3, 0x74, 0x02, 0xc8, 0x06, 0x94, 0xec, 0x84, 0xad, - 0xac, 0x47, 0x07, 0x94, 0x8c, 0x63, 0x03, 0x2a, 0xe2, 0xb0, 0x3d, 0x0f, 0xc7, 0xe7, 0xef, 0x7a, - 0xba, 0x6f, 0x41, 0xba, 0xa2, 0x2b, 0xdf, 0x8a, 0x5d, 0x32, 0x25, 0x49, 0xf0, 0x92, 0x29, 0x09, - 0x66, 0x63, 0x84, 0x81, 0xab, 0xeb, 0x56, 0x7d, 0x4a, 0x37, 0x1b, 0x6d, 0x87, 0x2a, 0xff, 0x47, - 0x74, 0x8c, 0xc4, 0xd0, 0x6c, 0x8c, 0xc4, 0x40, 0x6c, 0x81, 0x66, 0xa0, 0x92, 0xeb, 0x9a, 0x2b, - 0x96, 0xd8, 0x57, 0xb6, 0x1b, 0x9e, 0xf2, 0x7f, 0x46, 0x17, 0xe8, 0x34, 0x1a, 0xb6, 0x40, 0xa7, - 0xc1, 0xf1, 0xd4, 0x29, 0x25, 0x95, 0xba, 0xf2, 0x7f, 0xc5, 0x4e, 0x9d, 0x52, 0x68, 0xf0, 0xd4, - 0x29, 0x2d, 0x0d, 0xfb, 0x14, 0x8c, 0x72, 0x9b, 0x6c, 0xc6, 0x0c, 0xee, 0xaa, 0xff, 0xef, 0xe8, - 0xfa, 0x18, 0xc7, 0xb3, 0xf5, 0x31, 0x0e, 0x8b, 0xf2, 0x11, 0x5d, 0xf0, 0xff, 0x74, 0xe2, 0x13, - 0xc8, 0x3f, 0x51, 0x86, 0xdc, 0x90, 0xf9, 0x88, 0x91, 0xf2, 0xed, 0x99, 0x4e, 0x8c, 0x82, 0xe1, - 0x91, 0x28, 0x14, 0x65, 0xa4, 0xd1, 0x7b, 0x26, 0x5d, 0x53, 0x3e, 0xd9, 0x91, 0x11, 0x27, 0x88, - 0x32, 0xe2, 0x30, 0xf2, 0x06, 0x9c, 0x0a, 0x61, 0xb3, 0xb4, 0xb9, 0x14, 0xcc, 0x4c, 0xdf, 0x91, - 0x89, 0x9a, 0xc1, 0xe9, 0x64, 0xcc, 0x0c, 0x4e, 0xc7, 0xa4, 0xb1, 0x16, 0xa2, 0xfb, 0x7f, 0xb7, - 0x60, 0x1d, 0x48, 0xb0, 0x03, 0x83, 0x34, 0xd6, 0x42, 0x9a, 0xdf, 0xb9, 0x05, 0xeb, 0x40, 0xa6, - 0x1d, 0x18, 0x90, 0x4f, 0x67, 0xe0, 0x62, 0x3a, 0xaa, 0xd4, 0x68, 0x4c, 0xd9, 0x4e, 0x88, 0x53, - 0xbe, 0x2b, 0x13, 0x3d, 0x68, 0xd8, 0x5e, 0xb1, 0xe9, 0x1e, 0x6d, 0x9b, 0x15, 0x90, 0x0f, 0xc2, - 0x70, 0xa9, 0x6d, 0x98, 0x1e, 0x5e, 0xbc, 0x31, 0xc3, 0xf9, 0xbb, 0x33, 0xb1, 0x2d, 0x8e, 0x8c, - 0xc5, 0x2d, 0x8e, 0x0c, 0x20, 0xaf, 0xc1, 0x58, 0x95, 0xd6, 0xdb, 0x8e, 0xe9, 0xad, 0x6b, 0x98, - 0x26, 0x9f, 0xf1, 0xf8, 0x9e, 0x4c, 0x74, 0x12, 0x4b, 0x50, 0xb0, 0x49, 0x2c, 0x01, 0x24, 0xb7, - 0x3b, 0x24, 0x53, 0x57, 0x3e, 0x95, 0xe9, 0x7a, 0x2d, 0x1f, 0xf4, 0x65, 0x87, 0x5c, 0xec, 0x0b, - 0xa9, 0xc9, 0xa9, 0x95, 0x4f, 0x67, 0xba, 0x5c, 0xa3, 0x4b, 0x33, 0x5c, 0x4a, 0x5e, 0xeb, 0x85, - 0xd4, 0xcc, 0xc1, 0xca, 0xf7, 0x66, 0xba, 0x5c, 0x7b, 0x87, 0x1c, 0xd3, 0x92, 0x0e, 0x3f, 0xc3, - 0x3d, 0x45, 0x04, 0xa3, 0xff, 0x2f, 0x93, 0x74, 0x15, 0x09, 0xca, 0x4b, 0x84, 0xac, 0xd8, 0x2d, - 0x37, 0x50, 0xfa, 0xcf, 0x64, 0x92, 0xbe, 0x79, 0x61, 0xb1, 0xf0, 0x17, 0xa1, 0x70, 0x76, 0xf2, - 0xbe, 0x47, 0x1d, 0x4b, 0x6f, 0x60, 0x77, 0x56, 0x3d, 0xdb, 0xd1, 0x57, 0xe8, 0xa4, 0xa5, 0x2f, - 0x35, 0xa8, 0xf2, 0xd9, 0x4c, 0xd4, 0x82, 0xed, 0x4c, 0xca, 0x2c, 0xd8, 0xce, 0x58, 0xb2, 0x0a, - 0x0f, 0xa5, 0x61, 0xcb, 0xa6, 0x8b, 0xf5, 0x7c, 0x2e, 0x13, 0x35, 0x61, 0xbb, 0xd0, 0x32, 0x13, - 0xb6, 0x0b, 0x9a, 0x5c, 0x83, 0x81, 0x71, 0xdb, 0x9f, 0x7e, 0xbf, 0x2f, 0xe6, 0x0c, 0x19, 0x60, - 0xa6, 0x7b, 0xb4, 0x90, 0x4c, 0x94, 0x11, 0x83, 0xfa, 0xf3, 0xc9, 0x32, 0xe1, 0xe5, 0x53, 0xf0, - 0x43, 0x94, 0x11, 0xe2, 0xfe, 0xff, 0x93, 0x65, 0xc2, 0x3b, 0xae, 0xe0, 0x07, 0x9b, 0x49, 0x78, - 0x8d, 0xb3, 0x53, 0x25, 0x66, 0xb7, 0x4d, 0xac, 0xea, 0x8d, 0x06, 0xb5, 0x56, 0xa8, 0xf2, 0x85, - 0xd8, 0x4c, 0x92, 0x4e, 0xc6, 0x66, 0x92, 0x74, 0x0c, 0xf9, 0x28, 0x9c, 0xbe, 0xad, 0x37, 0x4c, - 0x23, 0xc4, 0xf9, 0x79, 0x64, 0x95, 0xef, 0xcf, 0x44, 0x77, 0xd3, 0x1d, 0xe8, 0xd8, 0x6e, 0xba, - 0x03, 0x8a, 0xcc, 0x02, 0xc1, 0x65, 0x34, 0x98, 0x2d, 0xd8, 0xfa, 0xac, 0xfc, 0x85, 0x4c, 0xd4, - 0x4e, 0x4d, 0x92, 0x30, 0x3b, 0x35, 0x09, 0x25, 0xb5, 0xce, 0x01, 0xe9, 0x95, 0x1f, 0xc8, 0x44, - 0x4f, 0x6b, 0x3a, 0x11, 0x4e, 0xf7, 0x68, 0x9d, 0xa3, 0xda, 0xdf, 0x80, 0xd1, 0xea, 0x42, 0x65, - 0x6a, 0x6a, 0xb2, 0x7a, 0xbb, 0x52, 0x46, 0xf7, 0x5d, 0x43, 0xf9, 0xc1, 0xd8, 0x8a, 0x15, 0x27, - 0x60, 0x2b, 0x56, 0x1c, 0x46, 0x5e, 0x84, 0x21, 0xd6, 0x7e, 0x36, 0x60, 0xf0, 0x93, 0xbf, 0x98, - 0x89, 0x9a, 0x53, 0x32, 0x92, 0x99, 0x53, 0xf2, 0x6f, 0x52, 0x85, 0x13, 0x4c, 0x8a, 0x0b, 0x0e, - 0x5d, 0xa6, 0x0e, 0xb5, 0xea, 0xfe, 0x98, 0xfe, 0xa1, 0x4c, 0xd4, 0xca, 0x48, 0x23, 0x62, 0x56, - 0x46, 0x1a, 0x9c, 0xdc, 0x85, 0x73, 0xf1, 0x93, 0x20, 0xf9, 0x31, 0x95, 0xf2, 0xc3, 0x99, 0x98, - 0x31, 0xdc, 0x85, 0x18, 0x8d, 0xe1, 0x2e, 0x78, 0x62, 0xc1, 0x79, 0x71, 0xac, 0x22, 0x1c, 0x2e, - 0xe3, 0xb5, 0xfd, 0x45, 0x5e, 0xdb, 0x63, 0xa1, 0x43, 0x60, 0x17, 0xea, 0xe9, 0x1e, 0xad, 0x3b, - 0x3b, 0xa6, 0x67, 0xc9, 0xb0, 0xeb, 0xca, 0x8f, 0x64, 0xd2, 0x3d, 0x52, 0x22, 0x6e, 0xca, 0x69, - 0xf1, 0xda, 0xdf, 0xe8, 0x14, 0x34, 0x5c, 0xf9, 0xd1, 0xd8, 0x78, 0x4b, 0x27, 0x63, 0xe3, 0xad, - 0x43, 0xd4, 0xf1, 0xd7, 0x60, 0x8c, 0x2b, 0xf5, 0x82, 0x8e, 0xc3, 0xd0, 0x5a, 0xa1, 0x86, 0xf2, - 0x97, 0x62, 0xab, 0x5d, 0x82, 0x02, 0x5d, 0x7b, 0xe2, 0x40, 0x36, 0x75, 0x57, 0x5b, 0xba, 0x65, - 0xe1, 0x31, 0xab, 0xf2, 0x97, 0x63, 0x53, 0x77, 0x88, 0x42, 0xc7, 0xdd, 0xe0, 0x17, 0xd3, 0x84, - 0x6e, 0x09, 0x37, 0x94, 0x1f, 0x8b, 0x69, 0x42, 0x37, 0x62, 0xa6, 0x09, 0x5d, 0xb3, 0x77, 0xdc, - 0xee, 0xf0, 0xb0, 0x51, 0xf9, 0x52, 0x6c, 0x45, 0x4e, 0xa5, 0x62, 0x2b, 0x72, 0xfa, 0xbb, 0xc8, - 0xdb, 0x1d, 0x1e, 0x05, 0x2a, 0x3f, 0xde, 0x9d, 0x6f, 0xb8, 0xd2, 0xa7, 0xbf, 0x29, 0xbc, 0xdd, - 0xe1, 0x41, 0x9d, 0xf2, 0x13, 0xdd, 0xf9, 0x86, 0x8e, 0x7d, 0xe9, 0xef, 0xf1, 0x6a, 0x9d, 0x1f, - 0xa3, 0x29, 0x3f, 0x19, 0x9f, 0xba, 0x3a, 0x10, 0xe2, 0xd4, 0xd5, 0xe9, 0x45, 0xdb, 0x12, 0x9c, - 0xe1, 0x1a, 0x72, 0xc3, 0xd1, 0x5b, 0xab, 0x55, 0xea, 0x79, 0xa6, 0xb5, 0xe2, 0xef, 0xc4, 0x7e, - 0x2a, 0x13, 0x3b, 0x1e, 0xeb, 0x44, 0x89, 0xc7, 0x63, 0x9d, 0x90, 0x4c, 0x79, 0x13, 0xcf, 0xce, - 0x94, 0x9f, 0x8e, 0x29, 0x6f, 0x82, 0x82, 0x29, 0x6f, 0xf2, 0xb5, 0xda, 0x6b, 0x29, 0xaf, 0xab, - 0x94, 0xbf, 0xd2, 0x99, 0x57, 0xd0, 0xbe, 0x94, 0x47, 0x59, 0xaf, 0xa5, 0x3c, 0x22, 0x52, 0xfe, - 0x6a, 0x67, 0x5e, 0xa1, 0x0f, 0x52, 0x02, 0x38, 0xde, 0x07, 0xbd, 0xb8, 0xab, 0x55, 0xbf, 0x94, - 0x81, 0xa1, 0xaa, 0xe7, 0x50, 0xbd, 0x29, 0x22, 0x4a, 0x9c, 0x85, 0x7e, 0xee, 0x1e, 0xe6, 0xbf, - 0xd0, 0xd0, 0x82, 0xdf, 0xe4, 0x22, 0x8c, 0xcc, 0xe8, 0xae, 0x87, 0x25, 0x2b, 0x96, 0x41, 0xef, - 0xe3, 0xd3, 0x88, 0x9c, 0x16, 0x83, 0x92, 0x19, 0x4e, 0xc7, 0xcb, 0x61, 0xfc, 0x9f, 0xdc, 0x96, - 0x81, 0x14, 0xfa, 0xdf, 0xde, 0x28, 0xf6, 0x60, 0xdc, 0x84, 0x58, 0x59, 0xf5, 0x6b, 0x19, 0x48, - 0x38, 0xae, 0xed, 0xfe, 0xe5, 0xd4, 0x3c, 0x1c, 0x8b, 0xc5, 0x9c, 0x12, 0xef, 0x3b, 0xb6, 0x19, - 0x92, 0x2a, 0x5e, 0x9a, 0xbc, 0x37, 0x78, 0x57, 0x70, 0x4b, 0x9b, 0x11, 0x41, 0x32, 0xfa, 0x36, - 0x37, 0x8a, 0xb9, 0xb6, 0xd3, 0xd0, 0x24, 0x94, 0x78, 0x04, 0xfd, 0xb7, 0x46, 0xc3, 0x80, 0x3a, - 0xe4, 0xa2, 0x78, 0xc6, 0x95, 0x09, 0x43, 0x6b, 0xc4, 0xd2, 0x35, 0xf2, 0x67, 0x5b, 0x1f, 0x84, - 0xa1, 0x4a, 0xb3, 0x45, 0x1d, 0xd7, 0xb6, 0x74, 0xcf, 0xf6, 0xd3, 0xc2, 0x63, 0xd8, 0x05, 0x53, - 0x82, 0xcb, 0xa1, 0x00, 0x64, 0x7a, 0x72, 0xd9, 0xcf, 0x20, 0x91, 0xc3, 0x50, 0x46, 0x18, 0x8f, - 0x33, 0x9e, 0x02, 0x90, 0x53, 0x30, 0xd2, 0x5b, 0xae, 0x8e, 0x2f, 0x50, 0x02, 0xd2, 0x36, 0x03, - 0xc8, 0xa4, 0x48, 0x41, 0x9e, 0x80, 0x02, 0x9e, 0xd8, 0xb9, 0x98, 0x19, 0x46, 0x04, 0xfc, 0x68, - 0x20, 0x44, 0x0e, 0xaf, 0xc0, 0x69, 0xc8, 0x4d, 0x18, 0x0d, 0xaf, 0x23, 0x6e, 0x38, 0x76, 0xbb, - 0xe5, 0xc7, 0x82, 0xc6, 0xd4, 0x89, 0x77, 0x03, 0x5c, 0x6d, 0x05, 0x91, 0x12, 0x8b, 0x44, 0x41, - 0x32, 0x0d, 0xc7, 0x42, 0x18, 0x13, 0x91, 0x1f, 0x83, 0x1e, 0xf3, 0xff, 0x48, 0xbc, 0x98, 0x38, - 0x23, 0xf9, 0x7f, 0x62, 0xc5, 0x48, 0x05, 0xfa, 0xfc, 0x68, 0x1f, 0xfd, 0x5b, 0x2a, 0xe9, 0x71, - 0x11, 0xed, 0xa3, 0x4f, 0x8e, 0xf3, 0xe1, 0x97, 0x27, 0x53, 0x30, 0xa2, 0xd9, 0x6d, 0x8f, 0x2e, - 0xda, 0x62, 0x1d, 0x17, 0x41, 0x8a, 0xb1, 0x4d, 0x0e, 0xc3, 0xd4, 0x3c, 0xdb, 0xcf, 0x3c, 0x29, - 0x67, 0x40, 0x8c, 0x96, 0x22, 0x73, 0x30, 0x96, 0xb8, 0xb8, 0x91, 0xf3, 0x41, 0x4a, 0x9f, 0x97, - 0x64, 0x96, 0x2c, 0x4a, 0xbe, 0x3b, 0x03, 0x85, 0x45, 0x47, 0x37, 0x3d, 0x57, 0x3c, 0x5e, 0x39, - 0x79, 0x65, 0xcd, 0xd1, 0x5b, 0x4c, 0x3f, 0xae, 0x60, 0xac, 0xaa, 0xdb, 0x7a, 0xa3, 0x4d, 0xdd, - 0xf1, 0x3b, 0xec, 0xeb, 0xfe, 0xe5, 0x46, 0xf1, 0xc5, 0x15, 0xdc, 0x1e, 0x5e, 0xa9, 0xdb, 0xcd, - 0xab, 0x2b, 0x8e, 0x7e, 0xcf, 0xf4, 0x70, 0xea, 0xd0, 0x1b, 0x57, 0x3d, 0xda, 0xc0, 0x5d, 0xe8, - 0x55, 0xbd, 0x65, 0x5e, 0xc5, 0x98, 0x88, 0x57, 0x03, 0x4e, 0xbc, 0x06, 0xa6, 0x02, 0x1e, 0xfe, - 0x25, 0xab, 0x00, 0xc7, 0x91, 0x39, 0xb6, 0x79, 0xc3, 0x4f, 0x2d, 0xb5, 0x5a, 0xe2, 0x25, 0x8c, - 0xb4, 0x77, 0xf3, 0x31, 0x5c, 0xb1, 0x03, 0x81, 0xe9, 0xad, 0x96, 0x9c, 0x71, 0x36, 0xa4, 0x63, - 0x5a, 0xb0, 0x28, 0x5a, 0xe4, 0x8b, 0x69, 0x38, 0x94, 0xb8, 0xdf, 0xd8, 0x14, 0x21, 0xc5, 0x8b, - 0x91, 0x25, 0x38, 0x26, 0xf8, 0x06, 0x51, 0x83, 0x47, 0xa2, 0xb3, 0x42, 0x0c, 0xcd, 0x95, 0x36, - 0x68, 0xa3, 0x21, 0xc0, 0x72, 0x1d, 0xb1, 0x12, 0x64, 0x3c, 0x4c, 0x65, 0x36, 0xa7, 0x37, 0xa9, - 0xab, 0x1c, 0x43, 0x8d, 0x3d, 0xb7, 0xb9, 0x51, 0x54, 0xfc, 0xf2, 0x18, 0xf8, 0x26, 0x35, 0x31, - 0x27, 0x16, 0x91, 0x79, 0x70, 0xad, 0x1f, 0x4d, 0xe1, 0x11, 0xd7, 0xf9, 0x68, 0x11, 0x32, 0x01, - 0xc3, 0x81, 0x23, 0xee, 0xad, 0x5b, 0x95, 0x32, 0x3e, 0xb5, 0x19, 0x18, 0x3f, 0xbf, 0xb9, 0x51, - 0x3c, 0x13, 0x8b, 0xeb, 0x2b, 0x33, 0x89, 0x94, 0x91, 0xde, 0xe4, 0xf1, 0xb7, 0x37, 0xb1, 0x37, - 0x79, 0xad, 0x94, 0x37, 0x79, 0x0b, 0xe4, 0x65, 0x18, 0x2c, 0xdd, 0xa9, 0x8a, 0xb7, 0x86, 0xae, - 0x72, 0x3c, 0x8c, 0x04, 0x8f, 0xb9, 0x59, 0xc5, 0xbb, 0x44, 0xb9, 0xe9, 0x32, 0x3d, 0x99, 0x84, - 0x91, 0xc8, 0x5d, 0xbe, 0xab, 0x9c, 0x40, 0x0e, 0xd8, 0x72, 0x1d, 0x31, 0x35, 0x47, 0xa0, 0x22, - 0xd9, 0x82, 0x23, 0x85, 0x98, 0xd6, 0xb0, 0xed, 0x70, 0xa3, 0x61, 0xaf, 0x69, 0x14, 0x9f, 0x35, - 0xe2, 0xc3, 0x9d, 0x7e, 0xae, 0x35, 0x86, 0x40, 0xd5, 0x1c, 0x8e, 0x8b, 0xa4, 0x07, 0x8e, 0x16, - 0x23, 0x6f, 0x02, 0xc1, 0x38, 0xdc, 0xd4, 0xf0, 0x8f, 0x76, 0x2b, 0x65, 0x57, 0x39, 0x85, 0x31, - 0xfb, 0x48, 0xfc, 0x5d, 0x6d, 0xa5, 0x3c, 0x7e, 0x51, 0x4c, 0x1f, 0x17, 0x74, 0x5e, 0xaa, 0xe6, - 0x08, 0x5c, 0xcd, 0x8c, 0x24, 0x29, 0x4b, 0xe1, 0x4a, 0xd6, 0xe0, 0xf4, 0x82, 0x43, 0xef, 0x99, - 0x76, 0xdb, 0xf5, 0x97, 0x0f, 0x7f, 0xde, 0x3a, 0xbd, 0xe5, 0xbc, 0xf5, 0x88, 0xa8, 0xf8, 0x64, - 0xcb, 0xa1, 0xf7, 0x6a, 0x7e, 0xa4, 0xb6, 0x48, 0xb4, 0xa2, 0x4e, 0xdc, 0x31, 0xd5, 0xda, 0x5b, - 0x6d, 0x87, 0x0a, 0xb8, 0x49, 0x5d, 0x45, 0x09, 0xa7, 0x5a, 0xfe, 0x42, 0xd5, 0x0c, 0x70, 0x91, - 0x54, 0x6b, 0xd1, 0x62, 0x44, 0x03, 0x72, 0x63, 0xc2, 0x3f, 0xe6, 0x2f, 0xd5, 0x79, 0x42, 0x2a, - 0xe5, 0x0c, 0x32, 0x53, 0x99, 0x58, 0x56, 0xea, 0x41, 0xd4, 0xc6, 0x9a, 0x2e, 0xf0, 0xb2, 0x58, - 0x92, 0xa5, 0xc9, 0x0c, 0x8c, 0x2e, 0x38, 0xb8, 0xe9, 0xb8, 0x49, 0xd7, 0x17, 0xec, 0x86, 0x59, - 0x5f, 0xc7, 0xf7, 0x43, 0x62, 0xaa, 0x6c, 0x71, 0x5c, 0xed, 0x2e, 0x5d, 0xaf, 0xb5, 0x10, 0x2b, - 0x2f, 0x2b, 0xf1, 0x92, 0x72, 0x14, 0xb5, 0x87, 0xb6, 0x17, 0x45, 0x8d, 0xc2, 0xa8, 0xb8, 0x24, - 0xb8, 0xef, 0x51, 0x8b, 0x2d, 0xf5, 0xae, 0x78, 0x2b, 0xa4, 0xc4, 0x2e, 0x15, 0x02, 0xbc, 0x48, - 0x15, 0xcc, 0x47, 0x19, 0x0d, 0xc0, 0x72, 0xc3, 0xe2, 0x45, 0xd4, 0xcf, 0xe5, 0xe4, 0xa9, 0x93, - 0x9c, 0x83, 0xbc, 0x14, 0xc4, 0x1b, 0xe3, 0x28, 0x61, 0xc0, 0xc3, 0xbc, 0x88, 0xec, 0x36, 0x20, - 0xcc, 0x8e, 0xe0, 0xc1, 0x2c, 0xa6, 0x66, 0x09, 0x63, 0xeb, 0x68, 0x21, 0x01, 0xa6, 0xc5, 0x68, - 0x2f, 0x35, 0xcc, 0x3a, 0x86, 0xc1, 0xcc, 0x49, 0x69, 0x31, 0x10, 0xca, 0xa3, 0x60, 0x4a, 0x24, - 0xe4, 0x1a, 0x0c, 0xfa, 0xfb, 0xd4, 0x30, 0x8e, 0x18, 0x46, 0x47, 0xf4, 0x93, 0x2a, 0xf3, 0xe0, - 0x8b, 0x12, 0x11, 0x79, 0x01, 0xd3, 0x8a, 0xfb, 0x8f, 0x91, 0x7b, 0x43, 0xf3, 0x45, 0x1e, 0xf8, - 0xb1, 0xbc, 0xe2, 0xfe, 0x9b, 0xe4, 0x71, 0x18, 0x96, 0x35, 0xc9, 0x4f, 0x04, 0x84, 0x73, 0x5e, - 0x44, 0xfd, 0xe4, 0xbe, 0x8d, 0x16, 0x21, 0xf3, 0x30, 0x96, 0x50, 0x1e, 0x11, 0x75, 0x0c, 0x93, - 0x41, 0xa6, 0x68, 0x9e, 0xbc, 0xa6, 0x26, 0xca, 0xaa, 0xdf, 0x91, 0x4d, 0xac, 0x18, 0x4c, 0x30, - 0x82, 0x4a, 0xea, 0x1c, 0x14, 0x8c, 0xcf, 0x9a, 0x0b, 0x46, 0x22, 0x22, 0x97, 0xa0, 0x3f, 0x96, - 0x59, 0x1c, 0x9f, 0xa7, 0x07, 0x69, 0xc5, 0x03, 0x2c, 0xb9, 0x26, 0xa5, 0xa6, 0x92, 0x42, 0xfc, - 0xf9, 0xa9, 0xa9, 0xe2, 0xb1, 0xee, 0x30, 0x49, 0xd5, 0xb5, 0x58, 0x14, 0x7c, 0x3f, 0x01, 0x74, - 0x72, 0xb5, 0x0a, 0xa3, 0xde, 0x07, 0xb6, 0x62, 0xef, 0x56, 0xb6, 0xa2, 0xfa, 0x6b, 0x99, 0xa4, - 0xf6, 0x93, 0xeb, 0xc9, 0x90, 0x5d, 0x3c, 0xf7, 0xb3, 0x0f, 0x94, 0x6b, 0x0d, 0x82, 0x77, 0x45, - 0x82, 0x6f, 0x65, 0x77, 0x1d, 0x7c, 0x2b, 0xb7, 0xc3, 0xe0, 0x5b, 0xea, 0xff, 0xc8, 0x77, 0x75, - 0x35, 0x3b, 0x90, 0x20, 0x0d, 0xcf, 0xb3, 0xfd, 0x0e, 0xab, 0xbd, 0xe4, 0x26, 0xac, 0x76, 0xee, - 0x49, 0x53, 0xd3, 0xf9, 0xa8, 0x71, 0xb5, 0x28, 0x25, 0x79, 0x05, 0x86, 0xfc, 0x0f, 0xc0, 0xa0, - 0x6e, 0x52, 0x30, 0xb2, 0x60, 0xad, 0x89, 0xa7, 0xef, 0x96, 0x0b, 0x90, 0x67, 0x60, 0x00, 0x2d, - 0x8d, 0x96, 0x5e, 0xf7, 0x23, 0xfe, 0xf1, 0x10, 0x81, 0x3e, 0x50, 0x0e, 0x44, 0x10, 0x50, 0x92, - 0x8f, 0x41, 0x21, 0x92, 0x3f, 0xfe, 0xea, 0x36, 0x7c, 0xf3, 0xae, 0xc8, 0xd1, 0x6a, 0xf9, 0xde, - 0x21, 0x9e, 0x3b, 0x5e, 0x30, 0x25, 0x8b, 0x70, 0x7c, 0xc1, 0xa1, 0x06, 0x7a, 0x81, 0x4e, 0xde, - 0x6f, 0x39, 0x22, 0x96, 0x30, 0x1f, 0xc0, 0xb8, 0x74, 0xb4, 0x7c, 0x34, 0x5b, 0xd4, 0x04, 0x5e, - 0x0e, 0x3b, 0x96, 0x52, 0x9c, 0xd9, 0x13, 0xbc, 0x25, 0x37, 0xe9, 0xfa, 0x1a, 0xe6, 0x10, 0xed, - 0x0f, 0xed, 0x09, 0x21, 0xe8, 0xbb, 0x02, 0x25, 0xdb, 0x13, 0xd1, 0x42, 0x67, 0x9f, 0x87, 0xc1, - 0xdd, 0x46, 0x7c, 0xfd, 0xc5, 0x6c, 0x07, 0xa7, 0xed, 0x07, 0x37, 0xe9, 0x46, 0x90, 0xee, 0xad, - 0xb7, 0x43, 0xba, 0xb7, 0x6f, 0x66, 0x3b, 0x78, 0xa4, 0x3f, 0xd0, 0x69, 0x99, 0x02, 0x61, 0x44, - 0xd3, 0x32, 0x85, 0x19, 0xb1, 0x4c, 0x43, 0x93, 0x89, 0x62, 0x09, 0xdc, 0x0a, 0x5b, 0x26, 0x70, - 0xfb, 0x99, 0x5c, 0x37, 0x8f, 0xfd, 0x23, 0xd9, 0xef, 0x44, 0xf6, 0xd7, 0x60, 0x30, 0x90, 0x6c, - 0xa5, 0x8c, 0xf6, 0xcc, 0x70, 0x10, 0x5f, 0x9a, 0x83, 0xb1, 0x8c, 0x44, 0x44, 0x2e, 0xf3, 0xb6, - 0x56, 0xcd, 0xb7, 0x78, 0xb8, 0xd4, 0x61, 0x11, 0x08, 0x53, 0xf7, 0xf4, 0x9a, 0x6b, 0xbe, 0x45, - 0xb5, 0x00, 0xad, 0xfe, 0xfd, 0x6c, 0xea, 0xb3, 0x87, 0xa3, 0x3e, 0xda, 0x41, 0x1f, 0xa5, 0x08, - 0x91, 0x3f, 0xd8, 0x38, 0x12, 0xe2, 0x0e, 0x84, 0xf8, 0x47, 0xd9, 0xd4, 0xe7, 0x2d, 0x47, 0x42, - 0xdc, 0xc9, 0x6c, 0xf1, 0x04, 0x0c, 0x68, 0xf6, 0x9a, 0x8b, 0xd9, 0x9a, 0xc5, 0x5c, 0x81, 0x13, - 0xb5, 0x63, 0xaf, 0xb9, 0x3c, 0x93, 0xb5, 0x16, 0x12, 0xa8, 0x7f, 0x92, 0xed, 0xf2, 0x00, 0xe8, - 0x48, 0xf0, 0xef, 0xe4, 0x12, 0xf9, 0xcb, 0xd9, 0xc8, 0x03, 0xa3, 0x07, 0x3a, 0xbf, 0x69, 0xb5, - 0xbe, 0x4a, 0x9b, 0x7a, 0x3c, 0xbf, 0xa9, 0x8b, 0x50, 0x91, 0x65, 0x2c, 0x24, 0x51, 0xbf, 0x9c, - 0x8d, 0xbd, 0xb0, 0x3a, 0x92, 0xdd, 0xb6, 0x65, 0x17, 0x68, 0x9d, 0x78, 0x34, 0x76, 0x24, 0xb9, - 0xed, 0x4a, 0xee, 0x53, 0xd9, 0xd8, 0xfb, 0xba, 0x07, 0x56, 0x76, 0x6c, 0x00, 0x26, 0xdf, 0xfd, - 0x3d, 0xb0, 0x9a, 0xf4, 0x04, 0x0c, 0x08, 0x39, 0x04, 0x4b, 0x05, 0x9f, 0xf7, 0x39, 0x10, 0x0f, - 0x50, 0x03, 0x02, 0xf5, 0xbb, 0xb2, 0x10, 0x7d, 0xf7, 0xf8, 0x80, 0xea, 0xd0, 0x2f, 0x67, 0xa3, - 0x2f, 0x3e, 0x1f, 0x5c, 0xfd, 0xb9, 0x02, 0x50, 0x6d, 0x2f, 0xd5, 0x45, 0xc0, 0xc0, 0x5e, 0xe9, - 0x04, 0x3e, 0x80, 0x6a, 0x12, 0x85, 0xfa, 0x3f, 0xb3, 0xa9, 0xcf, 0x50, 0x1f, 0x5c, 0x01, 0x3e, - 0x8d, 0xa7, 0xe2, 0x75, 0x2b, 0x9c, 0xc8, 0xf1, 0x10, 0x92, 0x8d, 0xbf, 0x44, 0x9e, 0x12, 0x9f, - 0x90, 0x7c, 0x20, 0xc5, 0x5c, 0xc3, 0x28, 0xaa, 0xa1, 0xb9, 0x26, 0xdf, 0x30, 0x48, 0x86, 0xdb, - 0x3f, 0xc9, 0x6e, 0xf5, 0x6a, 0xf7, 0x41, 0x5e, 0x55, 0xfb, 0x16, 0xf4, 0x75, 0x8c, 0x2e, 0xc5, - 0x7a, 0x62, 0x88, 0x67, 0xd1, 0x68, 0x71, 0x90, 0x7c, 0x23, 0x26, 0xa8, 0xd4, 0x3f, 0xec, 0x4d, - 0x7f, 0x32, 0xfa, 0xe0, 0x8a, 0xf0, 0x1c, 0xe4, 0x17, 0x74, 0x6f, 0x55, 0x68, 0x32, 0xde, 0xd6, - 0xb5, 0x74, 0x6f, 0x55, 0x43, 0x28, 0xb9, 0x0c, 0xfd, 0x9a, 0xbe, 0xc6, 0xcf, 0x3c, 0x0b, 0x61, - 0x86, 0x13, 0x47, 0x5f, 0xab, 0xf1, 0x73, 0xcf, 0x00, 0x4d, 0xd4, 0x20, 0xc3, 0x0e, 0x3f, 0xf9, - 0xc6, 0xf4, 0x0e, 0x3c, 0xc3, 0x4e, 0x90, 0x57, 0xe7, 0x1c, 0xe4, 0xc7, 0x6d, 0x63, 0x1d, 0x9d, - 0x59, 0x86, 0x78, 0x65, 0x4b, 0xb6, 0xb1, 0xae, 0x21, 0x94, 0x7c, 0x3a, 0x03, 0x7d, 0xd3, 0x54, - 0x37, 0xd8, 0x08, 0x19, 0xe8, 0xe6, 0x0b, 0xf2, 0xa1, 0xfd, 0xf1, 0x05, 0x19, 0x5b, 0xe5, 0x95, - 0xc9, 0x8a, 0x22, 0xea, 0x27, 0x37, 0xa0, 0x7f, 0x42, 0xf7, 0xe8, 0x8a, 0xed, 0xac, 0xa3, 0x77, - 0xcb, 0x48, 0xe8, 0x76, 0x18, 0xd1, 0x1f, 0x9f, 0x88, 0xdf, 0x8c, 0xd5, 0xc5, 0x2f, 0x2d, 0x28, - 0xcc, 0xc4, 0x22, 0xd2, 0x75, 0x0e, 0x86, 0x62, 0xe1, 0x79, 0x39, 0x83, 0xac, 0x9c, 0xc1, 0xb1, - 0xf2, 0x50, 0xfa, 0xb1, 0x32, 0x5a, 0x8f, 0xe8, 0x01, 0x87, 0x79, 0x6d, 0x86, 0x71, 0xd1, 0xe7, - 0xd6, 0x23, 0x42, 0x31, 0xad, 0x8d, 0x26, 0x91, 0xa8, 0x5f, 0xef, 0x85, 0xd4, 0x07, 0x66, 0x47, - 0x4a, 0x7e, 0xa4, 0xe4, 0xa1, 0x92, 0x97, 0x13, 0x4a, 0x7e, 0x36, 0xf9, 0x64, 0xf1, 0x5d, 0xaa, - 0xe1, 0x5f, 0xcc, 0x27, 0x1e, 0x3c, 0x3f, 0xd8, 0xbb, 0xcb, 0x50, 0x7a, 0xbd, 0x5b, 0x4a, 0x2f, - 0x18, 0x10, 0x85, 0x2d, 0x07, 0x44, 0xdf, 0x76, 0x07, 0x44, 0x7f, 0xc7, 0x01, 0x11, 0x2a, 0xc8, - 0x40, 0x47, 0x05, 0xa9, 0x88, 0x41, 0x03, 0xdd, 0x73, 0xa6, 0x9d, 0xdb, 0xdc, 0x28, 0x8e, 0xb0, - 0xd1, 0x94, 0x9a, 0x2d, 0x0d, 0x59, 0xa8, 0x5f, 0xcb, 0x77, 0x89, 0x52, 0x70, 0x20, 0x3a, 0xf2, - 0x34, 0xe4, 0x4a, 0xad, 0x96, 0xd0, 0x8f, 0xe3, 0x52, 0x80, 0x84, 0x0e, 0xa5, 0x18, 0x35, 0x79, - 0x01, 0x72, 0xa5, 0x3b, 0xd5, 0x78, 0xac, 0xf5, 0xd2, 0x9d, 0xaa, 0xf8, 0x92, 0x8e, 0x65, 0xef, - 0x54, 0xc9, 0x4b, 0x61, 0xd0, 0xb3, 0xd5, 0xb6, 0x75, 0x57, 0x6c, 0x14, 0x85, 0x13, 0xac, 0xef, - 0x69, 0x53, 0x67, 0x28, 0xb6, 0x5d, 0x8c, 0xd1, 0xc6, 0xb4, 0xa9, 0xb0, 0x7d, 0x6d, 0xea, 0xdb, - 0x52, 0x9b, 0xfa, 0xb7, 0xab, 0x4d, 0x03, 0xdb, 0xd0, 0x26, 0xd8, 0x52, 0x9b, 0x06, 0xf7, 0xae, - 0x4d, 0x2d, 0x38, 0x9b, 0x8c, 0x2c, 0x13, 0x68, 0x84, 0x06, 0x24, 0x89, 0x15, 0x8e, 0x25, 0x78, - 0xf5, 0xdf, 0xe6, 0xd8, 0x1a, 0x4f, 0xab, 0x1b, 0x4f, 0x4a, 0xab, 0xa5, 0x94, 0x56, 0x7f, 0x31, - 0xdb, 0x39, 0x20, 0xce, 0xe1, 0x9c, 0xe2, 0xbe, 0x2d, 0x55, 0x4a, 0xf9, 0xe8, 0x03, 0xc5, 0xce, - 0x52, 0x8e, 0xb1, 0x4d, 0x93, 0xd9, 0x57, 0x33, 0x9d, 0xa2, 0xf4, 0xec, 0x49, 0x62, 0x8f, 0x25, - 0x9d, 0xd5, 0xd0, 0x7b, 0xde, 0x8d, 0x7a, 0xa9, 0xc5, 0xb3, 0xb4, 0xe6, 0x76, 0x99, 0xa5, 0xf5, - 0xd7, 0x32, 0x70, 0xfc, 0x66, 0x7b, 0x89, 0x0a, 0xe7, 0xb4, 0xa0, 0x19, 0x6f, 0x02, 0x30, 0xb0, - 0x70, 0x62, 0xc9, 0xa0, 0x13, 0xcb, 0xfb, 0xe4, 0x08, 0x3b, 0xb1, 0x02, 0x57, 0x42, 0x6a, 0xee, - 0xc0, 0x72, 0xde, 0x77, 0xb1, 0xbc, 0xdb, 0x5e, 0xa2, 0xb5, 0x84, 0x27, 0x8b, 0xc4, 0xfd, 0xec, - 0xcb, 0xdc, 0x79, 0x7d, 0xb7, 0x4e, 0x23, 0x3f, 0x9f, 0xed, 0x18, 0xd4, 0xe8, 0xd0, 0xe6, 0x94, - 0xf9, 0x48, 0x6a, 0xaf, 0xc4, 0x73, 0xcb, 0xa4, 0x90, 0xc4, 0x38, 0xa6, 0x71, 0x49, 0x17, 0xd8, - 0x21, 0xcf, 0x74, 0xf4, 0x8e, 0x0a, 0xec, 0xb7, 0x33, 0x1d, 0x83, 0x4f, 0x1d, 0x56, 0x81, 0xa9, - 0xff, 0x2e, 0xe7, 0xc7, 0xbc, 0xda, 0xd3, 0x27, 0x3c, 0x01, 0x03, 0xe2, 0xe9, 0x5f, 0xd4, 0xb7, - 0x56, 0x1c, 0xe5, 0xe1, 0xd1, 0x70, 0x40, 0xc0, 0x96, 0x79, 0x3f, 0x26, 0x4f, 0x90, 0xa2, 0x17, - 0x97, 0x79, 0x53, 0x40, 0x19, 0xbd, 0x44, 0xc2, 0x16, 0xf2, 0xc9, 0xfb, 0xa6, 0x87, 0x56, 0x01, - 0xeb, 0xcb, 0x1c, 0x5f, 0xc8, 0xe9, 0x7d, 0xd3, 0xe3, 0x36, 0x41, 0x80, 0x66, 0x8b, 0x74, 0x35, - 0xcc, 0xe3, 0x28, 0x16, 0x69, 0x57, 0xa4, 0xb3, 0x14, 0x8f, 0xb9, 0x9e, 0x80, 0x01, 0xe1, 0xb0, - 0x2a, 0xdc, 0x4c, 0x44, 0x6b, 0x85, 0x8b, 0x2b, 0xb6, 0x36, 0x20, 0x60, 0x1c, 0x35, 0xba, 0x12, - 0x3a, 0xd6, 0x21, 0x47, 0x07, 0x21, 0x9a, 0xc0, 0x90, 0x6b, 0x30, 0x52, 0xf5, 0x74, 0xcb, 0xd0, - 0x1d, 0x63, 0xbe, 0xed, 0xb5, 0xda, 0x9e, 0x6c, 0x94, 0xba, 0x9e, 0x61, 0xb7, 0x3d, 0x2d, 0x46, - 0x41, 0xde, 0x0f, 0xc3, 0x3e, 0x64, 0xd2, 0x71, 0x6c, 0x47, 0xb6, 0x3c, 0x5c, 0xcf, 0xa0, 0x8e, - 0xa3, 0x45, 0x09, 0xc8, 0x07, 0x60, 0xb8, 0x62, 0xdd, 0xb3, 0x79, 0x82, 0xd0, 0x5b, 0xda, 0x8c, - 0xb0, 0x43, 0xf0, 0x81, 0x94, 0x19, 0x20, 0x6a, 0x6d, 0xa7, 0xa1, 0x45, 0x09, 0xd5, 0xcd, 0x6c, - 0x32, 0x34, 0xd8, 0x83, 0xbb, 0x69, 0xb9, 0x1c, 0x75, 0xa6, 0x43, 0x0f, 0x52, 0x34, 0x08, 0x65, - 0x5f, 0x5e, 0x6e, 0x17, 0x5e, 0x83, 0xfe, 0x9b, 0x74, 0x9d, 0xfb, 0x7d, 0x16, 0x42, 0x57, 0xe1, - 0xbb, 0x02, 0x26, 0x9f, 0xb8, 0xfa, 0x74, 0xea, 0x57, 0xb2, 0xc9, 0xa0, 0x67, 0x0f, 0xae, 0xb0, - 0xdf, 0x0f, 0x7d, 0x28, 0xca, 0x8a, 0x7f, 0xe4, 0x8f, 0x02, 0x44, 0x71, 0x47, 0x3d, 0x90, 0x7d, - 0x32, 0xf5, 0xc7, 0x0b, 0xf1, 0x48, 0x78, 0x0f, 0xae, 0xf4, 0x5e, 0x84, 0xc1, 0x09, 0xdb, 0x72, - 0x4d, 0xd7, 0xa3, 0x56, 0xdd, 0x57, 0xd8, 0x33, 0xcc, 0xa0, 0xaa, 0x87, 0x60, 0xf9, 0x65, 0x90, - 0x44, 0xbd, 0x1b, 0xe5, 0x25, 0xcf, 0xc2, 0x00, 0x8a, 0x1c, 0xfd, 0xa4, 0xa5, 0x04, 0xe4, 0x4b, - 0x0c, 0x18, 0x77, 0x92, 0x0e, 0x49, 0xc9, 0x2d, 0xe8, 0x9f, 0x58, 0x35, 0x1b, 0x86, 0x43, 0x2d, - 0xf4, 0x17, 0x96, 0x1e, 0x1c, 0x47, 0xfb, 0xf2, 0x0a, 0xfe, 0x8b, 0xb4, 0xbc, 0x39, 0x75, 0x51, - 0x2c, 0xf2, 0x36, 0x4a, 0xc0, 0xce, 0xfe, 0x40, 0x16, 0x20, 0x2c, 0x40, 0x1e, 0x86, 0x6c, 0x90, - 0x22, 0x0d, 0xdd, 0x54, 0x22, 0x1a, 0x94, 0xc5, 0xa5, 0x42, 0x8c, 0xed, 0xec, 0x96, 0x63, 0xfb, - 0x16, 0x14, 0xf8, 0x89, 0x17, 0x7a, 0x92, 0x4b, 0xc1, 0xb9, 0x3a, 0x36, 0xf8, 0x0a, 0xd2, 0xf3, - 0xcd, 0x2c, 0x5a, 0x9e, 0x11, 0xaf, 0x6c, 0xce, 0xec, 0x6c, 0x1d, 0x7a, 0xf1, 0x2f, 0x72, 0x11, - 0xf2, 0x28, 0xc5, 0x0c, 0xee, 0x63, 0x71, 0x96, 0x8e, 0xc9, 0x0f, 0xf1, 0xac, 0x9b, 0x26, 0x6c, - 0xcb, 0x63, 0x55, 0x63, 0xab, 0x87, 0x84, 0x5c, 0x04, 0x2c, 0x22, 0x17, 0x01, 0x53, 0xff, 0x71, - 0x36, 0x25, 0x46, 0xe3, 0x83, 0x3b, 0x4c, 0x9e, 0x07, 0xc0, 0x87, 0xd6, 0x4c, 0x9e, 0xfe, 0x13, - 0x0d, 0x1c, 0x25, 0xc8, 0x08, 0xd5, 0x36, 0xb2, 0xed, 0x08, 0x89, 0xd5, 0xdf, 0xc8, 0x24, 0x02, - 0xfb, 0xed, 0x49, 0x8e, 0xb2, 0x55, 0x96, 0xdd, 0xa5, 0x19, 0xeb, 0xf7, 0x45, 0x6e, 0x67, 0x7d, - 0x11, 0xfd, 0x96, 0x7d, 0xb0, 0x4c, 0x0f, 0xf2, 0x5b, 0xbe, 0x9e, 0x4d, 0x0b, 0x73, 0x78, 0x38, - 0x55, 0xfc, 0x7a, 0x60, 0x94, 0xe6, 0xb7, 0x93, 0x5c, 0x5c, 0x98, 0xa9, 0x1f, 0x87, 0x63, 0xb1, - 0xe0, 0x7f, 0x22, 0x6f, 0xe1, 0xc5, 0xee, 0x51, 0x04, 0x3b, 0x3f, 0xd1, 0x8f, 0x90, 0xa9, 0xff, - 0x2b, 0xd3, 0x3d, 0xf4, 0xe3, 0x81, 0xab, 0x4e, 0x8a, 0x00, 0x72, 0x7f, 0x3e, 0x02, 0xd8, 0x87, - 0x6d, 0xf0, 0xe1, 0x16, 0xc0, 0xbb, 0x64, 0xf2, 0x78, 0xa7, 0x05, 0xf0, 0xe3, 0x99, 0x2d, 0x23, - 0x77, 0x1e, 0xb4, 0x0c, 0xd4, 0x7f, 0x9d, 0x49, 0x8d, 0xb0, 0xb9, 0xa7, 0x76, 0xbd, 0x04, 0x05, - 0xee, 0x56, 0x23, 0x5a, 0x25, 0xe5, 0x24, 0x61, 0xd0, 0x0e, 0xe5, 0x45, 0x19, 0x32, 0x03, 0x7d, - 0xbc, 0x0d, 0x46, 0x3c, 0x77, 0x6f, 0x4a, 0x3b, 0x8d, 0x4e, 0x93, 0xa3, 0x40, 0xab, 0xbf, 0x9e, - 0x49, 0x04, 0xfc, 0x3c, 0xc0, 0x6f, 0x0b, 0xa7, 0xea, 0xdc, 0xf6, 0xa7, 0x6a, 0xf5, 0x0f, 0xb2, - 0xe9, 0xf1, 0x46, 0x0f, 0xf0, 0x43, 0xf6, 0xe3, 0x38, 0x6d, 0x77, 0xeb, 0xd6, 0x22, 0x8c, 0x44, - 0x65, 0x21, 0x96, 0xad, 0x0b, 0xe9, 0x51, 0x57, 0x3b, 0xb4, 0x22, 0xc6, 0x43, 0x7d, 0x3b, 0x93, - 0x0c, 0x95, 0x7a, 0xe0, 0xf3, 0xd3, 0xee, 0xb4, 0x25, 0xfa, 0x29, 0xef, 0x92, 0xb5, 0x66, 0x3f, - 0x3e, 0xe5, 0x5d, 0xb2, 0x6a, 0xec, 0xee, 0x53, 0x7e, 0x36, 0xdb, 0x29, 0xd2, 0xec, 0x81, 0x7f, - 0xd0, 0x87, 0x65, 0x21, 0xf3, 0x96, 0x89, 0x4f, 0x7b, 0xb8, 0x53, 0x68, 0xd7, 0x0e, 0x3c, 0x13, - 0x7c, 0x76, 0x37, 0xc6, 0x53, 0x85, 0xf5, 0x2e, 0x51, 0xe4, 0xc3, 0x21, 0xac, 0x77, 0xc9, 0x50, - 0x79, 0xf7, 0x09, 0xeb, 0xef, 0x64, 0xb7, 0x1b, 0xde, 0xf8, 0x48, 0x78, 0x09, 0xe1, 0x7d, 0x3e, - 0x9b, 0x0c, 0xbb, 0x7d, 0xe0, 0x62, 0x9a, 0x82, 0x82, 0x08, 0x00, 0xde, 0x51, 0x38, 0x1c, 0xdf, - 0xc9, 0xa2, 0x11, 0xdf, 0x71, 0x1d, 0xc4, 0x45, 0xce, 0xf6, 0x44, 0xc2, 0x69, 0xd5, 0x3f, 0xc9, - 0xc4, 0x62, 0x54, 0x1f, 0xc8, 0x11, 0xc2, 0xae, 0x96, 0x24, 0xf2, 0xb2, 0x7f, 0x98, 0x99, 0x8f, - 0xc5, 0x08, 0x0d, 0xbe, 0xa7, 0x4c, 0x3d, 0xdd, 0x6c, 0xc4, 0xcb, 0x8b, 0x98, 0x00, 0x5f, 0xc9, - 0xc2, 0x58, 0x82, 0x94, 0x5c, 0x8c, 0x44, 0xc9, 0xc1, 0x63, 0xc9, 0x98, 0xf3, 0x38, 0x8f, 0x97, - 0xb3, 0x83, 0x93, 0xd4, 0x8b, 0x90, 0x2f, 0xeb, 0xeb, 0xfc, 0xdb, 0x7a, 0x39, 0x4b, 0x43, 0x5f, - 0x97, 0x4f, 0xdc, 0x10, 0x4f, 0x96, 0xe0, 0x24, 0xbf, 0x0f, 0x31, 0x6d, 0x6b, 0xd1, 0x6c, 0xd2, - 0x8a, 0x35, 0x6b, 0x36, 0x1a, 0xa6, 0x2b, 0x2e, 0xf5, 0x9e, 0xd8, 0xdc, 0x28, 0x5e, 0xf2, 0x6c, - 0x4f, 0x6f, 0xd4, 0xa8, 0x4f, 0x56, 0xf3, 0xcc, 0x26, 0xad, 0x99, 0x56, 0xad, 0x89, 0x94, 0x12, - 0xcb, 0x74, 0x56, 0xa4, 0xc2, 0xc3, 0xc1, 0x56, 0xeb, 0xba, 0x65, 0x51, 0xa3, 0x62, 0x8d, 0xaf, - 0x7b, 0x94, 0x5f, 0x06, 0xe6, 0xf8, 0x91, 0x20, 0x7f, 0x1b, 0xce, 0xd1, 0x8c, 0xf1, 0x12, 0x23, - 0xd0, 0x52, 0x0a, 0xa9, 0xbf, 0x9a, 0x4f, 0x09, 0x4f, 0x7e, 0x88, 0xd4, 0xc7, 0xef, 0xe9, 0xfc, - 0x16, 0x3d, 0x7d, 0x15, 0xfa, 0x6e, 0x53, 0x07, 0xcf, 0xb7, 0xf8, 0x05, 0x03, 0x3a, 0xb3, 0xdf, - 0xe3, 0x20, 0xf9, 0x86, 0x46, 0x50, 0x91, 0x06, 0x9c, 0x5d, 0x64, 0xdd, 0x94, 0xde, 0x99, 0x85, - 0x5d, 0x74, 0x66, 0x17, 0x7e, 0xe4, 0x0d, 0x38, 0x8d, 0xd8, 0x94, 0x6e, 0xed, 0xc3, 0xaa, 0x30, - 0x72, 0x14, 0xaf, 0x2a, 0xbd, 0x73, 0x3b, 0x95, 0x27, 0x1f, 0x86, 0xa1, 0x60, 0x80, 0x98, 0xd4, - 0x15, 0x37, 0x17, 0x5d, 0xc6, 0x19, 0x0f, 0xcb, 0xc6, 0xc0, 0xe8, 0x42, 0x16, 0x0d, 0xed, 0x15, - 0xe1, 0xa5, 0xfe, 0xab, 0x4c, 0xb7, 0x30, 0xe9, 0x07, 0x3e, 0x2b, 0xbf, 0x0c, 0x7d, 0x06, 0xff, - 0x28, 0xa1, 0x53, 0xdd, 0x03, 0xa9, 0x73, 0x52, 0xcd, 0x2f, 0xa3, 0xfe, 0x7e, 0xa6, 0x6b, 0x74, - 0xf6, 0xc3, 0xfe, 0x79, 0x9f, 0xcf, 0x75, 0xf8, 0x3c, 0x31, 0x89, 0x5e, 0x86, 0x51, 0x33, 0x0c, - 0x1f, 0x5b, 0x0b, 0xc3, 0x4f, 0x69, 0xc7, 0x24, 0x38, 0x8e, 0xae, 0xeb, 0x70, 0xca, 0x77, 0x7c, - 0x74, 0x7c, 0x0f, 0x31, 0xb7, 0xd6, 0x76, 0x4c, 0x3e, 0x2e, 0xb5, 0x13, 0x6e, 0xcc, 0x7d, 0xcc, - 0xbd, 0xe5, 0x98, 0xac, 0x02, 0xdd, 0x5b, 0xa5, 0x96, 0x5e, 0x5b, 0xb3, 0x9d, 0xbb, 0x18, 0xfb, - 0x93, 0x0f, 0x4e, 0xed, 0x18, 0x87, 0xdf, 0xf1, 0xc1, 0xe4, 0x51, 0x18, 0x5e, 0x69, 0xb4, 0x69, - 0x10, 0x6d, 0x91, 0xdf, 0xf5, 0x69, 0x43, 0x0c, 0x18, 0xdc, 0x90, 0x9c, 0x07, 0x40, 0x22, 0x0f, - 0x63, 0xe7, 0xe3, 0xc5, 0x9e, 0x36, 0xc0, 0x20, 0x8b, 0xa2, 0xbb, 0xce, 0x72, 0xad, 0xe6, 0x42, - 0xaa, 0x35, 0x6c, 0x6b, 0xa5, 0xe6, 0x51, 0xa7, 0x89, 0x0d, 0x45, 0x67, 0x06, 0xed, 0x14, 0x52, - 0xe0, 0xd5, 0x89, 0x3b, 0x63, 0x5b, 0x2b, 0x8b, 0xd4, 0x69, 0xb2, 0xa6, 0x3e, 0x01, 0x44, 0x34, - 0xd5, 0xc1, 0x43, 0x0f, 0xfe, 0x71, 0xe8, 0xcd, 0xa0, 0x89, 0x8f, 0xe0, 0xa7, 0x21, 0xf8, 0x61, - 0x45, 0x18, 0xe4, 0x21, 0xe7, 0xb8, 0xd0, 0xd0, 0x85, 0x41, 0x03, 0x0e, 0x42, 0x79, 0x9d, 0x02, - 0xe1, 0x5d, 0xc1, 0xbd, 0xba, 0x35, 0xf1, 0x4b, 0xfd, 0x4c, 0x2e, 0x2d, 0xa0, 0xfc, 0x9e, 0x14, - 0x2d, 0x9c, 0x56, 0xb3, 0x3b, 0x9a, 0x56, 0x8f, 0x59, 0xed, 0x66, 0x4d, 0x6f, 0xb5, 0x6a, 0xcb, - 0x66, 0x03, 0x9f, 0x55, 0xe1, 0xc2, 0xa7, 0x0d, 0x5b, 0xed, 0x66, 0xa9, 0xd5, 0x9a, 0xe2, 0x40, - 0xf2, 0x38, 0x8c, 0x31, 0x3a, 0xec, 0xa4, 0x80, 0x32, 0x8f, 0x94, 0x8c, 0x01, 0xc6, 0x6c, 0xf5, - 0x69, 0xcf, 0x40, 0xbf, 0xe0, 0xc9, 0xd7, 0xaa, 0x5e, 0xad, 0x8f, 0x33, 0x73, 0x59, 0xcf, 0x05, - 0x6c, 0xf8, 0xe4, 0xda, 0xab, 0x0d, 0xf8, 0xe5, 0x31, 0x32, 0xb1, 0xd5, 0x6e, 0xf2, 0x88, 0x58, - 0x7d, 0x88, 0x0c, 0x7e, 0x93, 0x8b, 0x30, 0xc2, 0xb8, 0x04, 0x02, 0xe3, 0xc1, 0x5c, 0x7b, 0xb5, - 0x18, 0x94, 0x5c, 0x83, 0x13, 0x11, 0x08, 0xb7, 0x41, 0xf9, 0x33, 0x81, 0x5e, 0x2d, 0x15, 0xa7, - 0x7e, 0x39, 0x17, 0x0d, 0x73, 0x7f, 0x00, 0x1d, 0x71, 0x1a, 0xfa, 0x6c, 0x67, 0xa5, 0xd6, 0x76, - 0x1a, 0x62, 0xec, 0x15, 0x6c, 0x67, 0xe5, 0x96, 0xd3, 0x20, 0x27, 0xa1, 0xc0, 0x7a, 0xc7, 0x34, - 0xc4, 0x10, 0xeb, 0xd5, 0x5b, 0xad, 0x8a, 0x41, 0x4a, 0xbc, 0x43, 0x30, 0x10, 0x68, 0xad, 0x8e, - 0x5b, 0x7b, 0xee, 0x94, 0xd0, 0xcb, 0x57, 0xbc, 0x04, 0x12, 0xfb, 0x09, 0xc3, 0x83, 0xf2, 0x83, - 0x80, 0x18, 0x0b, 0x03, 0xb7, 0x25, 0x06, 0xef, 0x93, 0x38, 0x0b, 0x81, 0x0c, 0x59, 0xf0, 0x4d, - 0x8c, 0x41, 0xca, 0x40, 0x42, 0xaa, 0xa6, 0x6d, 0x98, 0xcb, 0x26, 0xe5, 0xaf, 0x3a, 0x7a, 0xf9, - 0xc5, 0x6f, 0x12, 0xab, 0x8d, 0xfa, 0x4c, 0x66, 0x05, 0x84, 0xbc, 0xc8, 0x95, 0x90, 0xd3, 0xe1, - 0xda, 0xc7, 0xfb, 0x96, 0xdb, 0x69, 0x31, 0x14, 0x6a, 0x26, 0x96, 0xc7, 0x85, 0x50, 0x7d, 0x3b, - 0x97, 0xcc, 0x75, 0x70, 0x20, 0x76, 0xcd, 0x34, 0x80, 0x48, 0x65, 0x12, 0x5e, 0xae, 0x05, 0x1e, - 0xe7, 0x21, 0xa6, 0x03, 0x0f, 0xa9, 0x2c, 0xb9, 0x0c, 0xfd, 0xfc, 0x8b, 0x2a, 0x65, 0x61, 0xef, - 0xa0, 0x8b, 0x98, 0xdb, 0x32, 0x97, 0x97, 0xd1, 0x9f, 0x2c, 0x40, 0x93, 0x8b, 0xd0, 0x57, 0x9e, - 0xab, 0x56, 0x4b, 0x73, 0xfe, 0x4d, 0x31, 0xbe, 0x2f, 0x31, 0x2c, 0xb7, 0xe6, 0xea, 0x96, 0xab, - 0xf9, 0x48, 0xf2, 0x28, 0x14, 0x2a, 0x0b, 0x48, 0xc6, 0x5f, 0x4d, 0x0e, 0x6e, 0x6e, 0x14, 0xfb, - 0xcc, 0x16, 0xa7, 0x12, 0x28, 0xac, 0xf7, 0x76, 0xa5, 0x2c, 0xb9, 0x4b, 0xf0, 0x7a, 0xef, 0x99, - 0x06, 0x5e, 0x3b, 0x6b, 0x01, 0x9a, 0x3c, 0x03, 0x43, 0x55, 0xea, 0x98, 0x7a, 0x63, 0xae, 0x8d, - 0x5b, 0x45, 0xee, 0x22, 0x36, 0xb6, 0xb9, 0x51, 0x1c, 0x76, 0x11, 0x5e, 0xb3, 0x10, 0xa1, 0x45, - 0xc8, 0xc8, 0x39, 0xc8, 0x4f, 0x9b, 0x96, 0xff, 0x84, 0x01, 0x7d, 0xdc, 0x57, 0x4d, 0xcb, 0xd3, - 0x10, 0xaa, 0xfe, 0x97, 0x6c, 0x7a, 0xc2, 0x88, 0x03, 0x18, 0x8e, 0xbb, 0xbc, 0xe9, 0x8d, 0x29, - 0x41, 0x7e, 0x0f, 0x4a, 0xb0, 0x0c, 0xc7, 0x4a, 0x46, 0xd3, 0xb4, 0x4a, 0xf8, 0xd3, 0x9d, 0x9d, - 0x2a, 0xe1, 0xf0, 0x96, 0x9e, 0xd0, 0xc5, 0xd0, 0xe2, 0x7b, 0x78, 0xa8, 0x5c, 0x86, 0xaa, 0xe9, - 0x1c, 0x57, 0x6b, 0x2e, 0xeb, 0xb5, 0x3a, 0xcf, 0xb5, 0xa0, 0xc5, 0x99, 0xaa, 0xdf, 0x9f, 0xdd, - 0x22, 0xc7, 0xc5, 0x83, 0x28, 0x7d, 0xf5, 0x0b, 0xd9, 0xee, 0x69, 0x46, 0x1e, 0x48, 0xa1, 0xfc, - 0x51, 0x36, 0x25, 0xe9, 0xc7, 0x9e, 0x24, 0x71, 0x19, 0xfa, 0x39, 0x9b, 0xc0, 0xd5, 0x16, 0x67, - 0x1c, 0xae, 0xac, 0x38, 0xd3, 0xf9, 0x68, 0x32, 0x07, 0x27, 0x4a, 0xcb, 0xcb, 0xb4, 0xee, 0x85, - 0x41, 0x93, 0xe7, 0xc2, 0x40, 0xa9, 0x3c, 0xd2, 0xac, 0xc0, 0x87, 0x41, 0x97, 0x31, 0x20, 0x48, - 0x6a, 0x39, 0xb2, 0x08, 0xa7, 0xe2, 0xf0, 0x2a, 0x37, 0xd3, 0xf3, 0x52, 0xf0, 0xd9, 0x04, 0x47, - 0xfe, 0x9f, 0xd6, 0xa1, 0x6c, 0x5a, 0x2b, 0x71, 0x3a, 0xed, 0xed, 0xd6, 0x4a, 0x9c, 0x5b, 0x53, - 0xcb, 0xa9, 0x5f, 0xc9, 0xc9, 0xb9, 0x51, 0x1e, 0x5c, 0xa7, 0xa8, 0xeb, 0x11, 0x57, 0xe8, 0xed, - 0x0e, 0x99, 0x67, 0x44, 0x94, 0x0f, 0xa3, 0xed, 0xf8, 0x5e, 0x83, 0x41, 0x94, 0x01, 0x04, 0xca, - 0xfe, 0x7f, 0x01, 0x25, 0xa9, 0x40, 0xbe, 0xe4, 0xac, 0x70, 0x13, 0x74, 0xab, 0x87, 0x4f, 0xba, - 0xb3, 0xe2, 0xa6, 0x3f, 0x7c, 0x62, 0x2c, 0xd4, 0xef, 0xcb, 0x76, 0x49, 0x67, 0xf2, 0x20, 0x4e, - 0x22, 0x8f, 0xcf, 0xf2, 0x20, 0xc7, 0x37, 0x4d, 0xcb, 0x20, 0x67, 0xe0, 0xe4, 0xad, 0xea, 0xa4, - 0x56, 0xbb, 0x59, 0x99, 0x2b, 0xd7, 0x6e, 0xcd, 0x55, 0x17, 0x26, 0x27, 0x2a, 0x53, 0x95, 0xc9, - 0xf2, 0x68, 0x0f, 0x39, 0x0e, 0xc7, 0x42, 0xd4, 0xf4, 0xad, 0xd9, 0xd2, 0xdc, 0x68, 0x86, 0x8c, - 0xc1, 0x70, 0x08, 0x1c, 0x9f, 0x5f, 0x1c, 0xcd, 0x3e, 0xfe, 0x5e, 0x18, 0xc4, 0x5d, 0x1c, 0x5f, - 0xd1, 0xc8, 0x10, 0xf4, 0xcf, 0x8f, 0x57, 0x27, 0xb5, 0xdb, 0xc8, 0x04, 0xa0, 0x50, 0x9e, 0x9c, - 0x63, 0x0c, 0x33, 0x8f, 0xff, 0xf7, 0x0c, 0x40, 0x75, 0x6a, 0x71, 0x41, 0x10, 0x0e, 0x42, 0x5f, - 0x65, 0xee, 0x76, 0x69, 0xa6, 0xc2, 0xe8, 0xfa, 0x21, 0x3f, 0xbf, 0x30, 0xc9, 0x6a, 0x18, 0x80, - 0xde, 0x89, 0x99, 0xf9, 0xea, 0xe4, 0x68, 0x96, 0x01, 0xb5, 0xc9, 0x52, 0x79, 0x34, 0xc7, 0x80, - 0x77, 0xb4, 0xca, 0xe2, 0xe4, 0x68, 0x9e, 0xfd, 0x39, 0x53, 0x5d, 0x2c, 0x2d, 0x8e, 0xf6, 0xb2, - 0x3f, 0xa7, 0xf0, 0xcf, 0x02, 0x63, 0x56, 0x9d, 0x5c, 0xc4, 0x1f, 0x7d, 0xac, 0x09, 0x53, 0xfe, - 0xaf, 0x7e, 0x86, 0x62, 0xac, 0xcb, 0x15, 0x6d, 0x74, 0x80, 0xfd, 0x60, 0x2c, 0xd9, 0x0f, 0x60, - 0x8d, 0xd3, 0x26, 0x67, 0xe7, 0x6f, 0x4f, 0x8e, 0x0e, 0x32, 0x5e, 0xb3, 0x37, 0x19, 0x78, 0x88, - 0xfd, 0xa9, 0xcd, 0xb2, 0x3f, 0x87, 0x19, 0x27, 0x6d, 0xb2, 0x34, 0xb3, 0x50, 0x5a, 0x9c, 0x1e, - 0x1d, 0x61, 0xed, 0x41, 0x9e, 0xc7, 0x78, 0xc9, 0xb9, 0xd2, 0xec, 0xe4, 0xe8, 0xa8, 0xa0, 0x29, - 0xcf, 0x54, 0xe6, 0x6e, 0x8e, 0x8e, 0x61, 0x43, 0xde, 0x98, 0xc5, 0x1f, 0x84, 0x15, 0xc0, 0xbf, - 0x8e, 0x3f, 0xfe, 0x51, 0x28, 0xcc, 0x57, 0xd1, 0x6e, 0x3b, 0x0d, 0xc7, 0xe7, 0xab, 0xb5, 0xc5, - 0x37, 0x16, 0x26, 0x63, 0xf2, 0x1e, 0x83, 0x61, 0x1f, 0x31, 0x53, 0x99, 0xbb, 0xf5, 0x21, 0x2e, - 0x6d, 0x1f, 0x34, 0x5b, 0x9a, 0x98, 0xaf, 0x8e, 0x66, 0x59, 0xaf, 0xf8, 0xa0, 0x3b, 0x95, 0xb9, - 0xf2, 0xfc, 0x9d, 0xea, 0x68, 0xee, 0xf1, 0x7b, 0x7e, 0xc6, 0xd5, 0x79, 0xc7, 0x5c, 0x31, 0x2d, - 0x72, 0x1e, 0xce, 0x94, 0x27, 0x6f, 0x57, 0x26, 0x26, 0x6b, 0xf3, 0x5a, 0xe5, 0x46, 0x65, 0x2e, - 0x56, 0xd3, 0x49, 0x18, 0x8b, 0xa2, 0x4b, 0x0b, 0x95, 0xd1, 0x0c, 0x39, 0x05, 0x24, 0x0a, 0x7e, - 0xad, 0x34, 0x3b, 0x35, 0x9a, 0x25, 0x0a, 0x9c, 0x88, 0xc2, 0x2b, 0x73, 0x8b, 0xb7, 0xe6, 0x26, - 0x47, 0x73, 0x8f, 0xff, 0x64, 0x06, 0x4e, 0xa6, 0x86, 0x11, 0x20, 0x2a, 0x5c, 0x98, 0x9c, 0x29, - 0x55, 0x17, 0x2b, 0x13, 0xd5, 0xc9, 0x92, 0x36, 0x31, 0x5d, 0x9b, 0x28, 0x2d, 0x4e, 0xde, 0x98, - 0xd7, 0xde, 0xa8, 0xdd, 0x98, 0x9c, 0x9b, 0xd4, 0x4a, 0x33, 0xa3, 0x3d, 0xe4, 0x51, 0x28, 0x76, - 0xa0, 0xa9, 0x4e, 0x4e, 0xdc, 0xd2, 0x2a, 0x8b, 0x6f, 0x8c, 0x66, 0xc8, 0x23, 0x70, 0xbe, 0x23, - 0x11, 0xfb, 0x3d, 0x9a, 0x25, 0x17, 0xe0, 0x6c, 0x27, 0x92, 0xd7, 0x67, 0x46, 0x73, 0x8f, 0xff, - 0x50, 0x06, 0x48, 0xf2, 0x1d, 0x38, 0x79, 0x18, 0xce, 0x31, 0xbd, 0xa8, 0x75, 0x6e, 0xe0, 0x23, - 0x70, 0x3e, 0x95, 0x42, 0x6a, 0x5e, 0x11, 0x1e, 0xea, 0x40, 0x22, 0x1a, 0x77, 0x0e, 0x94, 0x74, - 0x02, 0x6c, 0xda, 0x2f, 0x65, 0xe0, 0x64, 0xaa, 0x11, 0x49, 0x2e, 0xc1, 0x7b, 0x4a, 0xe5, 0x59, - 0xd6, 0x37, 0x13, 0x8b, 0x95, 0xf9, 0xb9, 0x6a, 0x6d, 0x76, 0xaa, 0x54, 0x63, 0xda, 0x77, 0xab, - 0x1a, 0xeb, 0xcd, 0x8b, 0xa0, 0x76, 0xa1, 0x9c, 0x98, 0x2e, 0xcd, 0xdd, 0x60, 0xc3, 0x8f, 0xbc, - 0x07, 0x1e, 0xee, 0x48, 0x37, 0x39, 0x57, 0x1a, 0x9f, 0x99, 0x2c, 0x8f, 0x66, 0xc9, 0x63, 0xf0, - 0x48, 0x47, 0xaa, 0x72, 0xa5, 0xca, 0xc9, 0x72, 0xe3, 0xe5, 0xb7, 0xff, 0xcd, 0x85, 0x9e, 0xb7, - 0xbf, 0x71, 0x21, 0xf3, 0x5b, 0xdf, 0xb8, 0x90, 0xf9, 0x83, 0x6f, 0x5c, 0xc8, 0x7c, 0xf8, 0xda, - 0x4e, 0xde, 0xf7, 0xf3, 0x69, 0x6b, 0xa9, 0x80, 0x13, 0xfa, 0xd3, 0xff, 0x3b, 0x00, 0x00, 0xff, - 0xff, 0x09, 0x71, 0x1b, 0xb1, 0x03, 0x57, 0x01, 0x00, + 0x77, 0x0f, 0x41, 0xec, 0xf7, 0xb2, 0xfc, 0xf9, 0x21, 0xf9, 0x93, 0x64, 0x7d, 0xf2, 0x67, 0xcb, + 0xaf, 0xef, 0xb3, 0x6c, 0x7f, 0xfe, 0x3e, 0xdb, 0xc7, 0xb1, 0xe3, 0x38, 0xc7, 0xb6, 0xe2, 0xe8, + 0xc4, 0x8e, 0xf2, 0x58, 0x47, 0xc7, 0x39, 0xb6, 0x93, 0xf8, 0xf8, 0x38, 0x0e, 0xe4, 0x28, 0x71, + 0x7e, 0xe0, 0x24, 0x27, 0x4e, 0xa2, 0x13, 0x3b, 0x8e, 0x93, 0x93, 0x53, 0xb7, 0xaa, 0xbb, 0xab, + 0x1f, 0x33, 0x78, 0xae, 0xb1, 0x10, 0xf1, 0x87, 0xc4, 0xdc, 0x7b, 0xeb, 0x56, 0xf5, 0xad, 0x5b, + 0x55, 0xb7, 0xaa, 0x6e, 0xdd, 0x0b, 0x97, 0x3d, 0xda, 0xa0, 0x2d, 0xdb, 0xf1, 0xae, 0x36, 0xe8, + 0x8a, 0x5e, 0x5f, 0xbf, 0xea, 0xad, 0xb7, 0xa8, 0x7b, 0x95, 0xde, 0xa3, 0x96, 0xe7, 0xff, 0x77, + 0xa5, 0xe5, 0xd8, 0x9e, 0x4d, 0x0a, 0xfc, 0xd7, 0xd9, 0x13, 0x2b, 0xf6, 0x8a, 0x8d, 0xa0, 0xab, + 0xec, 0x2f, 0x8e, 0x3d, 0x7b, 0x6e, 0xc5, 0xb6, 0x57, 0x1a, 0xf4, 0x2a, 0xfe, 0x5a, 0x6a, 0x2f, + 0x5f, 0x75, 0x3d, 0xa7, 0x5d, 0xf7, 0x04, 0xb6, 0x18, 0xc7, 0x7a, 0x66, 0x93, 0xba, 0x9e, 0xde, + 0x6c, 0x09, 0x82, 0x0b, 0x71, 0x82, 0x35, 0x47, 0x6f, 0xb5, 0xa8, 0x23, 0x2a, 0x3f, 0xfb, 0x48, + 0x7a, 0x3b, 0xf1, 0x5f, 0x41, 0xf2, 0x64, 0x3a, 0x89, 0xcf, 0x28, 0xc6, 0x51, 0xfd, 0x42, 0x16, + 0xfa, 0x67, 0xa9, 0xa7, 0x1b, 0xba, 0xa7, 0x93, 0x73, 0xd0, 0x5b, 0xb1, 0x0c, 0x7a, 0x5f, 0xc9, + 0x3c, 0x9c, 0xb9, 0x94, 0x1b, 0x2f, 0x6c, 0x6e, 0x14, 0xb3, 0xd4, 0xd4, 0x38, 0x90, 0x9c, 0x87, + 0xfc, 0xe2, 0x7a, 0x8b, 0x2a, 0xd9, 0x87, 0x33, 0x97, 0x06, 0xc6, 0x07, 0x36, 0x37, 0x8a, 0xbd, + 0x28, 0x0b, 0x0d, 0xc1, 0xe4, 0x11, 0xc8, 0x56, 0xca, 0x4a, 0x0e, 0x91, 0x63, 0x9b, 0x1b, 0xc5, + 0xe1, 0xb6, 0x69, 0x3c, 0x61, 0x37, 0x4d, 0x8f, 0x36, 0x5b, 0xde, 0xba, 0x96, 0xad, 0x94, 0xc9, + 0x45, 0xc8, 0x4f, 0xd8, 0x06, 0x55, 0xf2, 0x48, 0x44, 0x36, 0x37, 0x8a, 0x23, 0x75, 0xdb, 0xa0, + 0x12, 0x15, 0xe2, 0xc9, 0xab, 0x90, 0x5f, 0x34, 0x9b, 0x54, 0xe9, 0x7d, 0x38, 0x73, 0x69, 0xf0, + 0xda, 0xd9, 0x2b, 0x5c, 0x2a, 0x57, 0x7c, 0xa9, 0x5c, 0x59, 0xf4, 0xc5, 0x36, 0x3e, 0xfa, 0xf6, + 0x46, 0xb1, 0x67, 0x73, 0xa3, 0x98, 0x67, 0x92, 0xfc, 0xfc, 0xd7, 0x8b, 0x19, 0x0d, 0x4b, 0x92, + 0x97, 0x60, 0x70, 0xa2, 0xd1, 0x76, 0x3d, 0xea, 0xcc, 0xe9, 0x4d, 0xaa, 0x14, 0xb0, 0xc2, 0xb3, + 0x9b, 0x1b, 0xc5, 0x53, 0x75, 0x0e, 0xae, 0x59, 0x7a, 0x53, 0xae, 0x58, 0x26, 0x57, 0x7f, 0x2d, + 0x03, 0xc7, 0xaa, 0xd4, 0x75, 0x4d, 0xdb, 0x0a, 0x64, 0xf3, 0x18, 0x0c, 0x08, 0x50, 0xa5, 0x8c, + 0xf2, 0x19, 0x18, 0xef, 0xdb, 0xdc, 0x28, 0xe6, 0x5c, 0xd3, 0xd0, 0x42, 0x0c, 0x79, 0x3f, 0xf4, + 0xdd, 0x31, 0xbd, 0xd5, 0xd9, 0xa9, 0x92, 0x90, 0xd3, 0xa9, 0xcd, 0x8d, 0x22, 0x59, 0x33, 0xbd, + 0xd5, 0x5a, 0x73, 0x59, 0x97, 0x2a, 0xf4, 0xc9, 0xc8, 0x0c, 0x8c, 0x2e, 0x38, 0xe6, 0x3d, 0xdd, + 0xa3, 0x37, 0xe9, 0xfa, 0x82, 0xdd, 0x30, 0xeb, 0xeb, 0x42, 0x8a, 0x0f, 0x6f, 0x6e, 0x14, 0xcf, + 0xb5, 0x38, 0xae, 0x76, 0x97, 0xae, 0xd7, 0x5a, 0x88, 0x95, 0x98, 0x24, 0x4a, 0xaa, 0x5f, 0xed, + 0x85, 0xa1, 0x5b, 0x2e, 0x75, 0x82, 0x76, 0x5f, 0x84, 0x3c, 0xfb, 0x2d, 0x9a, 0x8c, 0x32, 0x6f, + 0xbb, 0xd4, 0x91, 0x65, 0xce, 0xf0, 0xe4, 0x32, 0xf4, 0xce, 0xd8, 0x2b, 0xa6, 0x25, 0x9a, 0x7d, + 0x7c, 0x73, 0xa3, 0x78, 0xac, 0xc1, 0x00, 0x12, 0x25, 0xa7, 0x20, 0x1f, 0x84, 0xa1, 0x4a, 0x93, + 0xe9, 0x90, 0x6d, 0xe9, 0x9e, 0xed, 0x88, 0xd6, 0xa2, 0x74, 0x4d, 0x09, 0x2e, 0x15, 0x8c, 0xd0, + 0x93, 0x17, 0x00, 0x4a, 0x77, 0xaa, 0x9a, 0xdd, 0xa0, 0x25, 0x6d, 0x4e, 0x28, 0x03, 0x96, 0xd6, + 0xd7, 0xdc, 0x9a, 0x63, 0x37, 0x68, 0x4d, 0x77, 0xe4, 0x6a, 0x25, 0x6a, 0x32, 0x09, 0x23, 0xa5, + 0x7a, 0x9d, 0xba, 0xae, 0x46, 0x3f, 0xd1, 0xa6, 0xae, 0xe7, 0x2a, 0xbd, 0x0f, 0xe7, 0x2e, 0x0d, + 0x8c, 0x9f, 0xdf, 0xdc, 0x28, 0x9e, 0xd1, 0x11, 0x53, 0x73, 0x04, 0x4a, 0x62, 0x11, 0x2b, 0x44, + 0xc6, 0x61, 0xb8, 0xf4, 0x56, 0xdb, 0xa1, 0x15, 0x83, 0x5a, 0x9e, 0xe9, 0xad, 0x0b, 0x0d, 0x39, + 0xb7, 0xb9, 0x51, 0x54, 0x74, 0x86, 0xa8, 0x99, 0x02, 0x23, 0x31, 0x89, 0x16, 0x21, 0xf3, 0x30, + 0x76, 0x63, 0x62, 0xa1, 0x4a, 0x9d, 0x7b, 0x66, 0x9d, 0x96, 0xea, 0x75, 0xbb, 0x6d, 0x79, 0x4a, + 0x1f, 0xf2, 0x79, 0x64, 0x73, 0xa3, 0x78, 0x7e, 0xa5, 0xde, 0xaa, 0xb9, 0x1c, 0x5b, 0xd3, 0x39, + 0x5a, 0x62, 0x96, 0x2c, 0x4b, 0x3e, 0x0c, 0xc3, 0x8b, 0x0e, 0xd3, 0x42, 0xa3, 0x4c, 0x19, 0x5c, + 0xe9, 0x47, 0xfd, 0x3f, 0x75, 0x45, 0x4c, 0x40, 0x1c, 0xea, 0xf7, 0x2c, 0x6f, 0xac, 0xc7, 0x0b, + 0xd4, 0x0c, 0xc4, 0xc9, 0x8d, 0x8d, 0xb0, 0x22, 0x14, 0x14, 0xf6, 0xf1, 0xa6, 0x43, 0x8d, 0x84, + 0xb6, 0x0d, 0x60, 0x9b, 0x2f, 0x6f, 0x6e, 0x14, 0x1f, 0x73, 0x04, 0x4d, 0xad, 0xab, 0xda, 0x75, + 0x64, 0x45, 0x26, 0xa1, 0x9f, 0x69, 0xd3, 0x4d, 0xd3, 0x32, 0x14, 0x78, 0x38, 0x73, 0x69, 0xe4, + 0xda, 0xa8, 0xdf, 0x7a, 0x1f, 0x3e, 0x7e, 0x7a, 0x73, 0xa3, 0x78, 0x9c, 0xe9, 0x60, 0xed, 0xae, + 0x69, 0xc9, 0x53, 0x44, 0x50, 0x54, 0xfd, 0xb3, 0x3c, 0x8c, 0x30, 0xe1, 0x48, 0x7a, 0x5c, 0x62, + 0x43, 0x92, 0x41, 0xd8, 0x08, 0x75, 0x5b, 0x7a, 0x9d, 0x0a, 0x95, 0x46, 0x76, 0x96, 0x0f, 0x94, + 0xd8, 0xc5, 0xe9, 0xc9, 0x65, 0xe8, 0xe7, 0xa0, 0x4a, 0x59, 0x68, 0xf9, 0xf0, 0xe6, 0x46, 0x71, + 0xc0, 0x45, 0x58, 0xcd, 0x34, 0xb4, 0x00, 0xcd, 0xd4, 0x8c, 0xff, 0x3d, 0x6d, 0xbb, 0x1e, 0x63, + 0x2e, 0x94, 0x1c, 0xd5, 0x4c, 0x14, 0x58, 0x15, 0x28, 0x59, 0xcd, 0xa2, 0x85, 0xc8, 0xf3, 0x00, + 0x1c, 0x52, 0x32, 0x0c, 0x47, 0x68, 0xfa, 0x99, 0xcd, 0x8d, 0xe2, 0x49, 0xc1, 0x42, 0x37, 0x0c, + 0x79, 0x98, 0x48, 0xc4, 0xa4, 0x09, 0x43, 0xfc, 0xd7, 0x8c, 0xbe, 0x44, 0x1b, 0x5c, 0xcd, 0x07, + 0xaf, 0x5d, 0xf2, 0xa5, 0x19, 0x95, 0xce, 0x15, 0x99, 0x74, 0xd2, 0xf2, 0x9c, 0xf5, 0xf1, 0xa2, + 0x98, 0x19, 0x4f, 0x8b, 0xaa, 0x1a, 0x88, 0x93, 0xc7, 0xa4, 0x5c, 0x86, 0x4d, 0x98, 0x53, 0xb6, + 0xb3, 0xa6, 0x3b, 0x06, 0x35, 0xc6, 0xd7, 0xe5, 0x09, 0x73, 0xd9, 0x07, 0xd7, 0x96, 0x64, 0x1d, + 0x90, 0xc9, 0xc9, 0x04, 0x0c, 0x73, 0x6e, 0xd5, 0xf6, 0x12, 0xf6, 0x7d, 0x5f, 0x42, 0x5a, 0x6e, + 0x7b, 0x29, 0xde, 0xdf, 0xd1, 0x32, 0x6c, 0x4c, 0x72, 0xc0, 0x6d, 0xea, 0xb0, 0xd9, 0x14, 0xd5, + 0x5f, 0x8c, 0x49, 0xc1, 0xe4, 0x1e, 0xc7, 0x24, 0x79, 0x88, 0x22, 0x67, 0x5f, 0x81, 0xb1, 0x84, + 0x28, 0xc8, 0x28, 0xe4, 0xee, 0xd2, 0x75, 0xae, 0x2e, 0x1a, 0xfb, 0x93, 0x9c, 0x80, 0xde, 0x7b, + 0x7a, 0xa3, 0x2d, 0xd6, 0x32, 0x8d, 0xff, 0x78, 0x21, 0xfb, 0x81, 0x0c, 0x9b, 0xfa, 0xc9, 0x84, + 0x6d, 0x59, 0xb4, 0xee, 0xc9, 0xb3, 0xff, 0xb3, 0x30, 0x30, 0x63, 0xd7, 0xf5, 0x06, 0xf6, 0x23, + 0xd7, 0x3b, 0x65, 0x73, 0xa3, 0x78, 0x82, 0x75, 0xe0, 0x95, 0x06, 0xc3, 0x48, 0x6d, 0x0a, 0x49, + 0x99, 0x02, 0x68, 0xb4, 0x69, 0x7b, 0x14, 0x0b, 0x66, 0x43, 0x05, 0xc0, 0x82, 0x0e, 0xa2, 0x64, + 0x05, 0x08, 0x89, 0xc9, 0x55, 0xe8, 0x5f, 0x60, 0x0b, 0x5e, 0xdd, 0x6e, 0x08, 0xe5, 0xc3, 0x39, + 0x19, 0x17, 0x41, 0x79, 0xd0, 0xf8, 0x44, 0xea, 0x34, 0x8c, 0x4c, 0x34, 0x4c, 0x6a, 0x79, 0x72, + 0xab, 0xd9, 0x90, 0x2a, 0xad, 0x50, 0xcb, 0x93, 0x5b, 0x8d, 0x83, 0x4f, 0x67, 0x50, 0xb9, 0xd5, + 0x01, 0xa9, 0xfa, 0x8f, 0x73, 0x70, 0xe6, 0x66, 0x7b, 0x89, 0x3a, 0x16, 0xf5, 0xa8, 0x2b, 0x56, + 0xc6, 0x80, 0xeb, 0x1c, 0x8c, 0x25, 0x90, 0x82, 0x3b, 0xae, 0x58, 0x77, 0x03, 0x64, 0x4d, 0x2c, + 0xb6, 0xf2, 0xb4, 0x97, 0x28, 0x4a, 0xa6, 0xe1, 0x58, 0x08, 0x64, 0x8d, 0x70, 0x95, 0x2c, 0xce, + 0xe9, 0x17, 0x36, 0x37, 0x8a, 0x67, 0x25, 0x6e, 0xac, 0xd9, 0xb2, 0x06, 0xc7, 0x8b, 0x91, 0x9b, + 0x30, 0x1a, 0x82, 0x6e, 0x38, 0x76, 0xbb, 0xe5, 0x2a, 0x39, 0x64, 0x55, 0xdc, 0xdc, 0x28, 0x3e, + 0x24, 0xb1, 0x5a, 0x41, 0xa4, 0xbc, 0x92, 0xc6, 0x0b, 0x92, 0xef, 0xcc, 0xc8, 0xdc, 0xc4, 0x28, + 0xcc, 0xe3, 0x28, 0x7c, 0xce, 0x1f, 0x85, 0x1d, 0x85, 0x74, 0x25, 0x5e, 0x52, 0x0c, 0xca, 0x58, + 0x33, 0x12, 0x83, 0x32, 0x51, 0xe3, 0xd9, 0x09, 0x38, 0x99, 0xca, 0x6b, 0x47, 0x5a, 0xfd, 0x27, + 0x39, 0x99, 0xcb, 0x82, 0x6d, 0x04, 0x9d, 0x39, 0x2f, 0x77, 0xe6, 0x82, 0x6d, 0xa0, 0xb9, 0x94, + 0x09, 0x17, 0x31, 0xa9, 0xb1, 0x2d, 0xdb, 0x88, 0x5b, 0x4d, 0xc9, 0xb2, 0xe4, 0xe3, 0x70, 0x2a, + 0x01, 0xe4, 0xd3, 0x35, 0xd7, 0xfe, 0x8b, 0x9b, 0x1b, 0x45, 0x35, 0x85, 0x6b, 0x7c, 0xf6, 0xee, + 0xc0, 0x85, 0xe8, 0x70, 0x5a, 0x92, 0xba, 0x6d, 0x79, 0xba, 0x69, 0x09, 0x2b, 0x8f, 0x8f, 0x92, + 0xf7, 0x6e, 0x6e, 0x14, 0x1f, 0x95, 0x75, 0xd0, 0xa7, 0x89, 0x37, 0xbe, 0x13, 0x1f, 0x62, 0x80, + 0x92, 0x82, 0xaa, 0x34, 0xf5, 0x15, 0xdf, 0x74, 0xbd, 0xb4, 0xb9, 0x51, 0x7c, 0x4f, 0x6a, 0x1d, + 0x26, 0xa3, 0x92, 0x97, 0xca, 0x4e, 0x9c, 0x88, 0x06, 0x24, 0xc4, 0xcd, 0xd9, 0x06, 0xc5, 0x6f, + 0xe8, 0x45, 0xfe, 0xea, 0xe6, 0x46, 0xf1, 0x82, 0xc4, 0xdf, 0xb2, 0x0d, 0x1a, 0x6f, 0x7e, 0x4a, + 0x69, 0xf5, 0xd7, 0x72, 0x70, 0xa1, 0x5a, 0x9a, 0x9d, 0xa9, 0x18, 0xbe, 0x6d, 0xb1, 0xe0, 0xd8, + 0xf7, 0x4c, 0x43, 0x1a, 0xbd, 0x4b, 0x70, 0x3a, 0x86, 0x9a, 0x44, 0x73, 0x26, 0xb0, 0x6a, 0xf1, + 0xdb, 0x7c, 0xbb, 0xa5, 0x25, 0x68, 0x6a, 0xdc, 0xe6, 0xa9, 0x45, 0x4c, 0xfa, 0x4e, 0x8c, 0x58, + 0x1f, 0xc5, 0x50, 0xd5, 0x55, 0xdb, 0xf1, 0xea, 0x6d, 0x4f, 0x28, 0x01, 0xf6, 0x51, 0xa2, 0x0e, + 0x57, 0x10, 0x75, 0xa9, 0xc2, 0xe7, 0x43, 0x3e, 0x9d, 0x81, 0xd1, 0x92, 0xe7, 0x39, 0xe6, 0x52, + 0xdb, 0xa3, 0xb3, 0x7a, 0xab, 0x65, 0x5a, 0x2b, 0x38, 0xd6, 0x07, 0xaf, 0xbd, 0x14, 0xac, 0x91, + 0x5d, 0x25, 0x71, 0x25, 0x5e, 0x5c, 0x1a, 0xa2, 0xba, 0x8f, 0xaa, 0x35, 0x39, 0x4e, 0x1e, 0xa2, + 0xf1, 0x72, 0x6c, 0x88, 0xa6, 0xf2, 0xda, 0xd1, 0x10, 0xfd, 0x42, 0x0e, 0xce, 0xcd, 0xdf, 0xf5, + 0x74, 0x8d, 0xba, 0x76, 0xdb, 0xa9, 0x53, 0xf7, 0x56, 0xcb, 0xd0, 0x3d, 0x1a, 0x8e, 0xd4, 0x22, + 0xf4, 0x96, 0x0c, 0x83, 0x1a, 0xc8, 0xae, 0x97, 0xef, 0xbf, 0x74, 0x06, 0xd0, 0x38, 0x9c, 0x3c, + 0x06, 0x7d, 0xa2, 0x0c, 0x72, 0xef, 0x1d, 0x1f, 0xdc, 0xdc, 0x28, 0xf6, 0xb5, 0x39, 0x48, 0xf3, + 0x71, 0x8c, 0xac, 0x4c, 0x1b, 0x94, 0x91, 0xe5, 0x42, 0x32, 0x83, 0x83, 0x34, 0x1f, 0x47, 0x5e, + 0x87, 0x11, 0x64, 0x1b, 0xb4, 0x47, 0xcc, 0x7d, 0x27, 0x7c, 0xe9, 0xca, 0x8d, 0xe5, 0x4b, 0x13, + 0xb6, 0xa6, 0xe6, 0xf8, 0x05, 0xb4, 0x18, 0x03, 0x72, 0x07, 0x46, 0x45, 0x23, 0x42, 0xa6, 0xbd, + 0x5d, 0x98, 0x9e, 0xdc, 0xdc, 0x28, 0x8e, 0x89, 0xf6, 0x4b, 0x6c, 0x13, 0x4c, 0x18, 0x63, 0xd1, + 0xec, 0x90, 0x71, 0x61, 0x2b, 0xc6, 0xe2, 0x8b, 0x65, 0xc6, 0x71, 0x26, 0xea, 0x1b, 0x30, 0x24, + 0x17, 0x24, 0xa7, 0x70, 0x8f, 0xcb, 0xc7, 0x09, 0xee, 0x8e, 0x4d, 0x03, 0x37, 0xb6, 0x4f, 0xc1, + 0x60, 0x99, 0xba, 0x75, 0xc7, 0x6c, 0x31, 0xab, 0x41, 0x28, 0xf9, 0xb1, 0xcd, 0x8d, 0xe2, 0xa0, + 0x11, 0x82, 0x35, 0x99, 0x46, 0xfd, 0xcf, 0x19, 0x38, 0xc5, 0x78, 0x97, 0x5c, 0xd7, 0x5c, 0xb1, + 0x9a, 0xf2, 0xb2, 0xfd, 0x04, 0x14, 0xaa, 0x58, 0x9f, 0xa8, 0xe9, 0xc4, 0xe6, 0x46, 0x71, 0x94, + 0xb7, 0x40, 0xd2, 0x43, 0x41, 0x13, 0x6c, 0xf0, 0xb2, 0x5b, 0x6c, 0xf0, 0x98, 0x49, 0xeb, 0xe9, + 0x8e, 0x67, 0x5a, 0x2b, 0x55, 0x4f, 0xf7, 0xda, 0x6e, 0xc4, 0xa4, 0x15, 0x98, 0x9a, 0x8b, 0xa8, + 0x88, 0x49, 0x1b, 0x29, 0x44, 0x5e, 0x81, 0xa1, 0x49, 0xcb, 0x08, 0x99, 0xf0, 0x09, 0xf1, 0x21, + 0x66, 0x69, 0x52, 0x84, 0x27, 0x59, 0x44, 0x0a, 0xa8, 0x7f, 0x2d, 0x03, 0x0a, 0xdf, 0x8d, 0xcd, + 0x98, 0xae, 0x37, 0x4b, 0x9b, 0x4b, 0xd2, 0xec, 0x34, 0xe5, 0x6f, 0xef, 0x18, 0x4e, 0x5a, 0x8b, + 0xd0, 0x14, 0x10, 0xdb, 0xbb, 0x86, 0xe9, 0x7a, 0xf1, 0xc9, 0x30, 0x56, 0x8a, 0x54, 0xa0, 0x8f, + 0x73, 0xe6, 0xb6, 0xc4, 0xe0, 0x35, 0xc5, 0x57, 0x84, 0x78, 0xd5, 0x5c, 0x19, 0x9a, 0x9c, 0x58, + 0xde, 0x9f, 0x8b, 0xf2, 0xea, 0x5f, 0xcf, 0xc2, 0x68, 0xbc, 0x10, 0xb9, 0x03, 0xfd, 0xaf, 0xd9, + 0xa6, 0x45, 0x8d, 0x79, 0x0b, 0x5b, 0xd8, 0xfd, 0x94, 0xc2, 0xb7, 0xc5, 0x8f, 0xbf, 0x89, 0x65, + 0x6a, 0xb2, 0x05, 0x8b, 0x87, 0x16, 0x01, 0x33, 0xf2, 0x61, 0x18, 0x60, 0x36, 0xe0, 0x3d, 0xe4, + 0x9c, 0xdd, 0x92, 0xf3, 0xc3, 0x82, 0xf3, 0x09, 0x87, 0x17, 0x4a, 0xb2, 0x0e, 0xd9, 0x31, 0xbd, + 0xd2, 0xa8, 0xee, 0xda, 0x96, 0xe8, 0x79, 0xd4, 0x2b, 0x07, 0x21, 0xb2, 0x5e, 0x71, 0x1a, 0x66, + 0xba, 0xf2, 0x8f, 0xc5, 0x6e, 0x90, 0xf6, 0x2e, 0x5c, 0x56, 0xf1, 0x1e, 0x90, 0x88, 0xd5, 0xef, + 0xce, 0xc2, 0x93, 0xa1, 0xc8, 0x34, 0x7a, 0xcf, 0xa4, 0x6b, 0x42, 0x9c, 0xab, 0x66, 0x4b, 0x6c, + 0x1e, 0x99, 0xca, 0xbb, 0x13, 0xab, 0xba, 0xb5, 0x42, 0x0d, 0x72, 0x19, 0x7a, 0xd9, 0x0e, 0xdf, + 0x55, 0x32, 0x68, 0xae, 0xe1, 0x74, 0xe2, 0x30, 0x80, 0x7c, 0xfa, 0x80, 0x14, 0xc4, 0x86, 0xc2, + 0xa2, 0xa3, 0x9b, 0x9e, 0xdf, 0xb3, 0xa5, 0x64, 0xcf, 0x6e, 0xa3, 0xc6, 0x2b, 0x9c, 0x07, 0x9f, + 0xf3, 0x51, 0x10, 0x1e, 0x02, 0x64, 0x41, 0x70, 0x92, 0xb3, 0xcf, 0xc3, 0xa0, 0x44, 0xbc, 0xa3, + 0x49, 0xfd, 0xcb, 0x79, 0x59, 0xd7, 0xfd, 0x66, 0x09, 0x5d, 0xbf, 0xca, 0x74, 0xd4, 0x75, 0x99, + 0x55, 0xc1, 0x95, 0x5c, 0x68, 0x22, 0x82, 0xa2, 0x9a, 0x88, 0x20, 0xf2, 0x34, 0xf4, 0x73, 0x16, + 0xc1, 0xfe, 0x15, 0xf7, 0xbe, 0x0e, 0xc2, 0xa2, 0x4b, 0x73, 0x40, 0x48, 0x7e, 0x2e, 0x03, 0xe7, + 0xbb, 0x4a, 0x02, 0x95, 0x61, 0xf0, 0xda, 0x33, 0xbb, 0x12, 0xe3, 0xf8, 0x93, 0x9b, 0x1b, 0xc5, + 0xcb, 0xcd, 0x80, 0xa4, 0xe6, 0x48, 0x34, 0xb5, 0x3a, 0x27, 0x92, 0xda, 0xd5, 0xbd, 0x29, 0xcc, + 0x78, 0xe4, 0x95, 0x4e, 0xe1, 0x19, 0x8e, 0x55, 0x5f, 0xf7, 0x1b, 0x99, 0x0f, 0x8d, 0x47, 0xf1, + 0xbd, 0xcb, 0x3e, 0x49, 0x4a, 0x35, 0x1d, 0xb8, 0x90, 0x3a, 0x9c, 0xe6, 0x98, 0xb2, 0xbe, 0x3e, + 0xbf, 0x3c, 0x6b, 0x5b, 0xde, 0xaa, 0x5f, 0x41, 0xaf, 0x7c, 0x08, 0x82, 0x15, 0x18, 0xfa, 0x7a, + 0xcd, 0x5e, 0xae, 0x35, 0x19, 0x55, 0x4a, 0x1d, 0x9d, 0x38, 0xb1, 0x89, 0x56, 0x8c, 0x39, 0x7f, + 0x0a, 0x2a, 0x84, 0x47, 0x54, 0xfe, 0x38, 0x4d, 0x4e, 0x38, 0xb1, 0x42, 0x6a, 0x05, 0x86, 0x66, + 0xec, 0xfa, 0xdd, 0x40, 0x5d, 0x9e, 0x87, 0xc2, 0xa2, 0xee, 0xac, 0x50, 0x0f, 0x65, 0x31, 0x78, + 0x6d, 0xec, 0x0a, 0x3f, 0xf6, 0x65, 0x44, 0x1c, 0x31, 0x3e, 0x22, 0x66, 0x83, 0x82, 0x87, 0xbf, + 0x35, 0x51, 0x40, 0xfd, 0x7a, 0x2f, 0x0c, 0x89, 0x23, 0x4a, 0x9c, 0xcd, 0xc9, 0x0b, 0xe1, 0xa1, + 0xaf, 0x98, 0xbe, 0x82, 0x63, 0x9a, 0xe0, 0x78, 0x69, 0x88, 0x31, 0xfb, 0x9d, 0x8d, 0x62, 0x66, + 0x73, 0xa3, 0xd8, 0xa3, 0xf5, 0x4b, 0x9b, 0xca, 0x70, 0xbd, 0x91, 0x16, 0x58, 0xf9, 0xd0, 0x31, + 0x56, 0x96, 0xaf, 0x3f, 0xaf, 0x40, 0x9f, 0x68, 0x83, 0xd0, 0xb8, 0xd3, 0xe1, 0x59, 0x46, 0xe4, + 0xa8, 0x35, 0x56, 0xda, 0x2f, 0x45, 0x5e, 0x82, 0x02, 0xdf, 0xdb, 0x0b, 0x01, 0x9c, 0x4a, 0x3f, + 0x0b, 0x89, 0x15, 0x17, 0x65, 0xc8, 0x34, 0x40, 0xb8, 0xaf, 0x0f, 0x4e, 0x96, 0x05, 0x87, 0xe4, + 0x8e, 0x3f, 0xc6, 0x45, 0x2a, 0x4b, 0x9e, 0x85, 0xa1, 0x45, 0xea, 0x34, 0x4d, 0x4b, 0x6f, 0x54, + 0xcd, 0xb7, 0xfc, 0xc3, 0x65, 0x5c, 0x78, 0x5d, 0xf3, 0x2d, 0x79, 0xe4, 0x46, 0xe8, 0xc8, 0xc7, + 0xd2, 0xf6, 0xcd, 0x7d, 0xd8, 0x90, 0x47, 0xb6, 0xdc, 0x50, 0xc6, 0xda, 0x93, 0xb2, 0x8d, 0x7e, + 0x1d, 0x86, 0x23, 0x5b, 0x26, 0x71, 0x7a, 0x78, 0x3e, 0xc9, 0x5a, 0xda, 0xff, 0xc5, 0xd8, 0x46, + 0x39, 0x30, 0x4d, 0xae, 0x58, 0xa6, 0x67, 0xea, 0x8d, 0x09, 0xbb, 0xd9, 0xd4, 0x2d, 0x43, 0x19, + 0x08, 0x35, 0xd9, 0xe4, 0x98, 0x5a, 0x9d, 0xa3, 0x64, 0x4d, 0x8e, 0x16, 0x62, 0xdb, 0x72, 0xd1, + 0x87, 0x1a, 0xad, 0xdb, 0x0e, 0xb3, 0x05, 0xf0, 0x70, 0x50, 0x6c, 0xcb, 0x5d, 0x8e, 0xab, 0x39, + 0x3e, 0x52, 0x36, 0xb6, 0xe3, 0x05, 0x5f, 0xcb, 0xf7, 0x0f, 0x8e, 0x0e, 0xc5, 0xcf, 0x73, 0xd5, + 0x9f, 0xcd, 0xc1, 0xa0, 0x20, 0x65, 0x4b, 0xe9, 0x91, 0x82, 0xef, 0x45, 0xc1, 0x53, 0x15, 0xb5, + 0xb0, 0x5f, 0x8a, 0xaa, 0x7e, 0x26, 0x1b, 0xcc, 0x46, 0x0b, 0x8e, 0x69, 0xed, 0x6d, 0x36, 0xba, + 0x08, 0x30, 0xb1, 0xda, 0xb6, 0xee, 0xf2, 0x7b, 0xab, 0x6c, 0x78, 0x6f, 0x55, 0x37, 0x35, 0x09, + 0x43, 0xce, 0x43, 0xbe, 0xcc, 0xf8, 0xb3, 0x9e, 0x19, 0x1a, 0x1f, 0x78, 0x9b, 0x73, 0xca, 0x3c, + 0xa9, 0x21, 0x98, 0x6d, 0xae, 0xc6, 0xd7, 0x3d, 0xca, 0xcd, 0xd9, 0x1c, 0xdf, 0x5c, 0x2d, 0x31, + 0x80, 0xc6, 0xe1, 0xe4, 0x3a, 0x8c, 0x95, 0x69, 0x43, 0x5f, 0x9f, 0x35, 0x1b, 0x0d, 0xd3, 0xa5, + 0x75, 0xdb, 0x32, 0x5c, 0x14, 0xb2, 0xa8, 0xae, 0xe9, 0x6a, 0x49, 0x02, 0xa2, 0x42, 0x61, 0x7e, + 0x79, 0xd9, 0xa5, 0x1e, 0x8a, 0x2f, 0x37, 0x0e, 0x6c, 0x72, 0xb6, 0x11, 0xa2, 0x09, 0x8c, 0xfa, + 0x8b, 0x19, 0xb6, 0x7b, 0x71, 0xef, 0x7a, 0x76, 0x2b, 0xd0, 0xf2, 0x3d, 0x89, 0xe4, 0x72, 0x68, + 0x57, 0x64, 0xf1, 0x6b, 0x8f, 0x89, 0xaf, 0xed, 0x13, 0xb6, 0x45, 0x68, 0x51, 0xa4, 0x7e, 0x55, + 0x6e, 0x8b, 0xaf, 0x52, 0xff, 0x34, 0x0b, 0xa7, 0x45, 0x8b, 0x27, 0x1a, 0x66, 0x6b, 0xc9, 0xd6, + 0x1d, 0x43, 0xa3, 0x75, 0x6a, 0xde, 0xa3, 0x87, 0x73, 0xe0, 0x45, 0x87, 0x4e, 0x7e, 0x0f, 0x43, + 0xe7, 0x1a, 0x6e, 0x04, 0x99, 0x64, 0xf0, 0xc0, 0x97, 0x1b, 0x15, 0xa3, 0x9b, 0x1b, 0xc5, 0x21, + 0x83, 0x83, 0xf1, 0xc8, 0x5f, 0x93, 0x89, 0x98, 0x92, 0xcc, 0x50, 0x6b, 0xc5, 0x5b, 0x45, 0x25, + 0xe9, 0xe5, 0x4a, 0xd2, 0x40, 0x88, 0x26, 0x30, 0xea, 0xbf, 0xcb, 0xc2, 0x89, 0xb8, 0xc8, 0xab, + 0xd4, 0x32, 0x8e, 0xe4, 0xfd, 0xce, 0xc8, 0xfb, 0x9b, 0x39, 0x78, 0x48, 0x94, 0xa9, 0xae, 0xea, + 0x0e, 0x35, 0xca, 0xa6, 0x43, 0xeb, 0x9e, 0xed, 0xac, 0x1f, 0x62, 0x03, 0x6a, 0xff, 0xc4, 0x7e, + 0x1d, 0x0a, 0x62, 0xfb, 0xcf, 0xd7, 0x99, 0x91, 0xa0, 0x25, 0x08, 0x4d, 0xac, 0x50, 0xfc, 0xe8, + 0x20, 0xd6, 0x59, 0x85, 0xed, 0x74, 0xd6, 0x07, 0x60, 0x38, 0x10, 0x3d, 0x6e, 0x44, 0xfb, 0x42, + 0x6b, 0xcb, 0xf0, 0x11, 0xb8, 0x17, 0xd5, 0xa2, 0x84, 0x58, 0x9b, 0x0f, 0xa8, 0x94, 0xd1, 0x1a, + 0x1a, 0x16, 0xb5, 0x05, 0xe5, 0x4c, 0x43, 0x93, 0x89, 0xd4, 0x8d, 0x3c, 0x9c, 0x4d, 0xef, 0x76, + 0x8d, 0xea, 0xc6, 0x51, 0xaf, 0x7f, 0x4b, 0xf6, 0x3a, 0x79, 0x04, 0xf2, 0x0b, 0xba, 0xb7, 0x2a, + 0xee, 0xc1, 0xf1, 0x4e, 0x78, 0xd9, 0x6c, 0xd0, 0x5a, 0x4b, 0xf7, 0x56, 0x35, 0x44, 0x49, 0x73, + 0x06, 0x20, 0xc7, 0x94, 0x39, 0x43, 0x5a, 0xec, 0x07, 0x1f, 0xce, 0x5c, 0xca, 0xa7, 0x2e, 0xf6, + 0x5f, 0xcf, 0x77, 0x9a, 0x57, 0xee, 0x38, 0xa6, 0x47, 0x8f, 0x34, 0xec, 0x48, 0xc3, 0xf6, 0xa8, + 0x61, 0xbf, 0x97, 0x85, 0xe1, 0x60, 0xd3, 0xf4, 0x26, 0xad, 0x1f, 0xcc, 0x5a, 0x15, 0x6e, 0x65, + 0x72, 0x7b, 0xde, 0xca, 0xec, 0x45, 0xa1, 0xd4, 0xe0, 0xc8, 0x93, 0x9b, 0x06, 0x28, 0x31, 0x7e, + 0xe4, 0x19, 0x1c, 0x74, 0x3e, 0x02, 0x7d, 0xb3, 0xfa, 0x7d, 0xb3, 0xd9, 0x6e, 0x0a, 0x2b, 0x1d, + 0xfd, 0xba, 0x9a, 0xfa, 0x7d, 0xcd, 0x87, 0xab, 0xff, 0x34, 0x03, 0x23, 0x42, 0xa8, 0x82, 0xf9, + 0x9e, 0xa4, 0x1a, 0x4a, 0x27, 0xbb, 0x67, 0xe9, 0xe4, 0x76, 0x2f, 0x1d, 0xf5, 0xc7, 0x72, 0xa0, + 0x4c, 0x99, 0x0d, 0xba, 0xe8, 0xe8, 0x96, 0xbb, 0x4c, 0x1d, 0xb1, 0x9d, 0x9e, 0x64, 0xac, 0xf6, + 0xf4, 0x81, 0xd2, 0x94, 0x92, 0xdd, 0xd5, 0x94, 0xf2, 0x3e, 0x18, 0x10, 0x8d, 0x09, 0x7c, 0x0a, + 0x71, 0xd4, 0x38, 0x3e, 0x50, 0x0b, 0xf1, 0x8c, 0xb8, 0xd4, 0x6a, 0x39, 0xf6, 0x3d, 0xea, 0xf0, + 0x5b, 0x2a, 0x41, 0xac, 0xfb, 0x40, 0x2d, 0xc4, 0x4b, 0x9c, 0xa9, 0x6f, 0x2f, 0xca, 0x9c, 0xa9, + 0xa3, 0x85, 0x78, 0x72, 0x09, 0xfa, 0x67, 0xec, 0xba, 0x8e, 0x82, 0xe6, 0xd3, 0xca, 0xd0, 0xe6, + 0x46, 0xb1, 0xbf, 0x21, 0x60, 0x5a, 0x80, 0x65, 0x94, 0x65, 0x7b, 0xcd, 0x6a, 0xd8, 0x3a, 0x77, + 0x7e, 0xe9, 0xe7, 0x94, 0x86, 0x80, 0x69, 0x01, 0x96, 0x51, 0x32, 0x99, 0xa3, 0x53, 0x51, 0x7f, + 0xc8, 0x73, 0x59, 0xc0, 0xb4, 0x00, 0xab, 0xfe, 0x62, 0x9e, 0x69, 0xaf, 0x6b, 0xbe, 0xf5, 0xc0, + 0xaf, 0x0b, 0xe1, 0x80, 0xe9, 0xdd, 0xc5, 0x80, 0x79, 0x60, 0x0e, 0xec, 0xd4, 0x3f, 0xeb, 0x03, + 0x10, 0xd2, 0x9f, 0x3c, 0xda, 0x1c, 0xee, 0x4d, 0x6b, 0xca, 0x30, 0x36, 0x69, 0xad, 0xea, 0x56, + 0x9d, 0x1a, 0xe1, 0xb1, 0x65, 0x01, 0x87, 0x36, 0xfa, 0xf4, 0x52, 0x81, 0x0c, 0xcf, 0x2d, 0xb5, + 0x64, 0x01, 0xf2, 0x14, 0x0c, 0x56, 0x2c, 0x8f, 0x3a, 0x7a, 0xdd, 0x33, 0xef, 0x51, 0x31, 0x35, + 0xe0, 0xcd, 0xb0, 0x19, 0x82, 0x35, 0x99, 0x86, 0x5c, 0x87, 0xa1, 0x05, 0xdd, 0xf1, 0xcc, 0xba, + 0xd9, 0xd2, 0x2d, 0xcf, 0x55, 0xfa, 0x71, 0x46, 0x43, 0x0b, 0xa3, 0x25, 0xc1, 0xb5, 0x08, 0x15, + 0xf9, 0x18, 0x0c, 0xe0, 0xd6, 0x14, 0x1d, 0xa7, 0x07, 0xb6, 0xbc, 0x38, 0x7c, 0x34, 0x74, 0x0f, + 0xe4, 0xa7, 0xaf, 0x78, 0x03, 0x1c, 0xbf, 0x3b, 0x0c, 0x38, 0x92, 0x0f, 0x41, 0xdf, 0xa4, 0x65, + 0x20, 0x73, 0xd8, 0x92, 0xb9, 0x2a, 0x98, 0x9f, 0x0a, 0x99, 0xdb, 0xad, 0x18, 0x6f, 0x9f, 0x5d, + 0xfa, 0x28, 0x1b, 0x7c, 0xe7, 0x46, 0xd9, 0xd0, 0x3b, 0x70, 0x2c, 0x3e, 0xbc, 0x5f, 0xc7, 0xe2, + 0x23, 0xbb, 0x3c, 0x16, 0x57, 0xdf, 0x82, 0xc1, 0xf1, 0x85, 0xa9, 0x60, 0xf4, 0x9e, 0x81, 0xdc, + 0x82, 0xf0, 0x54, 0xc8, 0x73, 0x7b, 0xa6, 0x65, 0x1a, 0x1a, 0x83, 0x91, 0xcb, 0xd0, 0x3f, 0x81, + 0xee, 0x6f, 0xe2, 0x16, 0x31, 0xcf, 0xd7, 0xbf, 0x3a, 0xc2, 0xd0, 0x0b, 0xd6, 0x47, 0x93, 0xc7, + 0xa0, 0x6f, 0xc1, 0xb1, 0x57, 0x1c, 0xbd, 0x29, 0xd6, 0x60, 0x74, 0x15, 0x69, 0x71, 0x90, 0xe6, + 0xe3, 0xd4, 0xef, 0xcf, 0xf8, 0x66, 0x3b, 0x2b, 0x51, 0x6d, 0xe3, 0xd1, 0x3c, 0xd6, 0xdd, 0xcf, + 0x4b, 0xb8, 0x1c, 0xa4, 0xf9, 0x38, 0x72, 0x19, 0x7a, 0x27, 0x1d, 0xc7, 0x76, 0x64, 0x67, 0x73, + 0xca, 0x00, 0xf2, 0x75, 0x2f, 0x52, 0x90, 0xe7, 0x60, 0x90, 0xcf, 0x39, 0xfc, 0x44, 0x33, 0xd7, + 0xed, 0xa6, 0x54, 0xa6, 0x54, 0xbf, 0x9a, 0x93, 0x6c, 0x36, 0x2e, 0xf1, 0x07, 0xf0, 0x56, 0xe0, + 0x69, 0xc8, 0x8d, 0x2f, 0x4c, 0x89, 0x09, 0xf0, 0xb8, 0x5f, 0x54, 0x52, 0x95, 0x58, 0x39, 0x46, + 0x4d, 0xce, 0x41, 0x7e, 0x81, 0xa9, 0x4f, 0x01, 0xd5, 0xa3, 0x7f, 0x73, 0xa3, 0x98, 0x6f, 0x31, + 0xfd, 0x41, 0x28, 0x62, 0xd9, 0x66, 0x86, 0xef, 0x98, 0x38, 0x36, 0xdc, 0xc7, 0x9c, 0x83, 0x7c, + 0xc9, 0x59, 0xb9, 0x27, 0x66, 0x2d, 0xc4, 0xea, 0xce, 0xca, 0x3d, 0x0d, 0xa1, 0xe4, 0x2a, 0x80, + 0x46, 0xbd, 0xb6, 0x63, 0xe1, 0x3b, 0x90, 0x01, 0x3c, 0x7f, 0xc3, 0xd9, 0xd0, 0x41, 0x68, 0xad, + 0x6e, 0x1b, 0x54, 0x93, 0x48, 0xd4, 0x9f, 0x0e, 0x2f, 0x76, 0xca, 0xa6, 0x7b, 0xf7, 0xa8, 0x0b, + 0x77, 0xd0, 0x85, 0xba, 0x38, 0xe2, 0x4c, 0x76, 0x52, 0x11, 0x7a, 0xa7, 0x1a, 0xfa, 0x8a, 0x8b, + 0x7d, 0x28, 0x7c, 0xc9, 0x96, 0x19, 0x40, 0xe3, 0xf0, 0x58, 0x3f, 0xf5, 0x6f, 0xdd, 0x4f, 0x5f, + 0xec, 0x0d, 0x46, 0xdb, 0x1c, 0xf5, 0xd6, 0x6c, 0xe7, 0xa8, 0xab, 0xb6, 0xdb, 0x55, 0x17, 0xa1, + 0xaf, 0xea, 0xd4, 0xa5, 0xa3, 0x0b, 0xdc, 0x0f, 0xb8, 0x4e, 0x9d, 0x1f, 0x5b, 0xf8, 0x48, 0x46, + 0x57, 0x76, 0x3d, 0xa4, 0xeb, 0x0b, 0xe9, 0x0c, 0xd7, 0x13, 0x74, 0x02, 0x29, 0xe8, 0x16, 0x6c, + 0xc7, 0x13, 0x1d, 0x17, 0xd0, 0xb5, 0x6c, 0xc7, 0xd3, 0x7c, 0x24, 0x79, 0x1f, 0xc0, 0xe2, 0xc4, + 0x82, 0xef, 0x6c, 0x3f, 0x10, 0xfa, 0x02, 0x0a, 0x2f, 0x7b, 0x4d, 0x42, 0x93, 0x45, 0x18, 0x98, + 0x6f, 0x51, 0x87, 0x6f, 0x85, 0xf8, 0xcb, 0x8e, 0xf7, 0xc6, 0x44, 0x2b, 0xfa, 0xfd, 0x8a, 0xf8, + 0x3f, 0x20, 0xe7, 0xeb, 0x8b, 0xed, 0xff, 0xd4, 0x42, 0x46, 0xe4, 0x39, 0x28, 0x94, 0xb8, 0x9d, + 0x37, 0x88, 0x2c, 0x03, 0x91, 0xe1, 0x16, 0x94, 0xa3, 0xf8, 0x9e, 0x5d, 0xc7, 0xbf, 0x35, 0x41, + 0xae, 0x5e, 0x86, 0xd1, 0x78, 0x35, 0x64, 0x10, 0xfa, 0x26, 0xe6, 0xe7, 0xe6, 0x26, 0x27, 0x16, + 0x47, 0x7b, 0x48, 0x3f, 0xe4, 0xab, 0x93, 0x73, 0xe5, 0xd1, 0x8c, 0xfa, 0xf3, 0xd2, 0x0c, 0xc2, + 0x54, 0xeb, 0xe8, 0x6a, 0x78, 0x4f, 0xf7, 0x2d, 0xa3, 0x78, 0x1f, 0x8a, 0x27, 0x06, 0x4d, 0xd3, + 0xf3, 0xa8, 0x21, 0x56, 0x09, 0xbc, 0x2f, 0xf4, 0xee, 0x6b, 0x09, 0x3c, 0x79, 0x02, 0x86, 0x11, + 0x26, 0xae, 0x08, 0xf9, 0xfe, 0x58, 0x14, 0x70, 0xee, 0x6b, 0x51, 0xa4, 0xfa, 0xb5, 0xf0, 0x76, + 0x78, 0x86, 0xea, 0x87, 0xf5, 0x46, 0xf1, 0x5d, 0xd2, 0x5f, 0xea, 0x5f, 0xe6, 0xf9, 0x13, 0x10, + 0xfe, 0x70, 0xef, 0x20, 0x44, 0x19, 0x1e, 0xe9, 0xe6, 0x76, 0x70, 0xa4, 0xfb, 0x04, 0x14, 0x66, + 0xa9, 0xb7, 0x6a, 0xfb, 0x8e, 0x5f, 0xe8, 0xa1, 0xd7, 0x44, 0x88, 0xec, 0xa1, 0xc7, 0x69, 0xc8, + 0x5d, 0x20, 0xfe, 0xab, 0xbc, 0xc0, 0x11, 0xdb, 0x3f, 0x42, 0x3e, 0x9d, 0xd8, 0xa7, 0x54, 0xf1, + 0x49, 0x2e, 0xfa, 0xd8, 0x9f, 0x08, 0x1c, 0xbd, 0x25, 0x4f, 0xac, 0xbf, 0xd8, 0x28, 0x16, 0x38, + 0x8d, 0x96, 0xc2, 0x96, 0xbc, 0x0e, 0x03, 0xb3, 0x53, 0x25, 0xf1, 0x42, 0x8f, 0x7b, 0x45, 0x9c, + 0x09, 0xa4, 0xe8, 0x23, 0x02, 0x91, 0xe0, 0x7b, 0x9b, 0xe6, 0xb2, 0x9e, 0x7c, 0xa0, 0x17, 0x72, + 0x61, 0xda, 0xc2, 0x5f, 0xee, 0x88, 0xd3, 0x85, 0x40, 0x5b, 0xa2, 0xef, 0x79, 0xe2, 0xb2, 0xe2, + 0xd8, 0x98, 0xb6, 0xf4, 0xef, 0x61, 0x74, 0xcf, 0xc3, 0x58, 0xa9, 0xd5, 0x6a, 0x98, 0xd4, 0x40, + 0x7d, 0xd1, 0xda, 0x0d, 0xea, 0x0a, 0x97, 0x1f, 0x7c, 0x0c, 0xa2, 0x73, 0x64, 0x0d, 0xdf, 0x85, + 0xd6, 0x9c, 0x76, 0xd4, 0x3f, 0x33, 0x59, 0x56, 0xfd, 0xc1, 0x2c, 0x9c, 0x9a, 0x70, 0xa8, 0xee, + 0xd1, 0xd9, 0xa9, 0x52, 0xa9, 0x8d, 0x3e, 0x72, 0x8d, 0x06, 0xb5, 0x56, 0x0e, 0x66, 0x58, 0xbf, + 0x08, 0x23, 0x41, 0x03, 0xaa, 0x75, 0xbb, 0x45, 0xe5, 0x87, 0x55, 0x75, 0x1f, 0x53, 0x73, 0x19, + 0x4a, 0x8b, 0x91, 0x92, 0x9b, 0x70, 0x3c, 0x80, 0x94, 0x1a, 0x0d, 0x7b, 0x4d, 0xa3, 0x6d, 0x97, + 0x3b, 0xc6, 0xf6, 0x73, 0xc7, 0xd8, 0x90, 0x83, 0xce, 0xf0, 0x35, 0x87, 0x11, 0x68, 0x69, 0xa5, + 0xd4, 0x2f, 0xe5, 0xe0, 0xf4, 0x6d, 0xbd, 0x61, 0x1a, 0xa1, 0x68, 0x34, 0xea, 0xb6, 0x6c, 0xcb, + 0xa5, 0x87, 0x68, 0x94, 0x46, 0x86, 0x42, 0x7e, 0x5f, 0x86, 0x42, 0xb2, 0x8b, 0x7a, 0xf7, 0xdc, + 0x45, 0x85, 0x5d, 0x75, 0xd1, 0xbf, 0xcd, 0xc0, 0xa8, 0xef, 0xf8, 0x2f, 0xbf, 0xa6, 0x96, 0xbc, + 0xd2, 0xf1, 0x08, 0x31, 0xe6, 0x07, 0x8d, 0x78, 0x52, 0x85, 0xbe, 0xc9, 0xfb, 0x2d, 0xd3, 0xa1, + 0xee, 0x36, 0x9c, 0xb8, 0xcf, 0x8b, 0xe3, 0x92, 0x31, 0xca, 0x8b, 0x24, 0x4e, 0x4a, 0x38, 0x18, + 0x9f, 0xf3, 0xf1, 0xa7, 0x0f, 0xe3, 0xfe, 0x13, 0x71, 0xfe, 0x9c, 0x4f, 0x3c, 0x91, 0x88, 0xbc, + 0xcf, 0x0c, 0x49, 0xc9, 0xa3, 0x90, 0x5b, 0x5c, 0x9c, 0x11, 0x33, 0x29, 0x3e, 0xcd, 0xf7, 0x3c, + 0xf9, 0xbd, 0x22, 0xc3, 0xaa, 0x7f, 0x94, 0x05, 0x60, 0xaa, 0xc0, 0x87, 0xeb, 0x81, 0x28, 0xe1, + 0x38, 0xf4, 0xfb, 0x02, 0x17, 0x6a, 0x18, 0x78, 0xed, 0xc7, 0x3b, 0x22, 0x5e, 0x77, 0xf0, 0x42, + 0xa3, 0xe8, 0x3b, 0x92, 0xf3, 0x7b, 0x00, 0xdc, 0xd9, 0xa0, 0x23, 0xb9, 0xef, 0x3e, 0xfe, 0x3e, + 0x18, 0x10, 0x33, 0x9e, 0x1d, 0x39, 0xff, 0xaf, 0xfb, 0x40, 0x2d, 0xc4, 0xc7, 0xa6, 0xd6, 0xc2, + 0x1e, 0x16, 0x62, 0x5f, 0xbc, 0xbc, 0x57, 0x8e, 0xc4, 0xbb, 0xcf, 0xe2, 0xfd, 0x9c, 0x10, 0x2f, + 0x7f, 0xc1, 0x73, 0x68, 0xc5, 0xbb, 0x6f, 0x67, 0xdf, 0xea, 0xef, 0x65, 0x80, 0xb0, 0x66, 0x2d, + 0xe8, 0xae, 0xbb, 0x66, 0x3b, 0x06, 0x77, 0x4e, 0x3f, 0x10, 0xc1, 0xec, 0xdf, 0x7d, 0xe5, 0x57, + 0xfb, 0xe1, 0x78, 0xc4, 0xf1, 0xf7, 0x90, 0x4f, 0x56, 0x97, 0xa3, 0xa3, 0xa9, 0xdb, 0xab, 0x97, + 0xf7, 0xc8, 0x17, 0xa2, 0xbd, 0x91, 0x07, 0x68, 0xd2, 0x4d, 0xe8, 0x93, 0x30, 0x24, 0x7e, 0xb0, + 0x15, 0xda, 0xbf, 0xe9, 0xc2, 0x51, 0xea, 0x32, 0x80, 0x16, 0x41, 0x93, 0x67, 0x60, 0x80, 0x0d, + 0x98, 0x15, 0x8c, 0xe2, 0xd1, 0x17, 0xbe, 0x28, 0x31, 0x7c, 0xa0, 0xbc, 0x9e, 0x04, 0x94, 0xd2, + 0x3b, 0xa2, 0xfe, 0x6d, 0xbc, 0x23, 0xfa, 0x38, 0x0c, 0x96, 0x2c, 0xcb, 0xf6, 0x70, 0x93, 0xee, + 0x8a, 0xab, 0x89, 0x8e, 0x56, 0xf9, 0xa3, 0xf8, 0x38, 0x3e, 0xa4, 0x4f, 0x35, 0xcb, 0x65, 0x86, + 0xe4, 0x9a, 0xff, 0x2a, 0x86, 0x3a, 0xc2, 0xab, 0x1c, 0xaf, 0x67, 0x1c, 0x01, 0x4b, 0x3e, 0x8a, + 0xc1, 0xce, 0x1b, 0x5e, 0x70, 0xec, 0x96, 0xed, 0x52, 0x83, 0x0b, 0x6a, 0x30, 0x0c, 0x35, 0xd0, + 0x12, 0x08, 0x7c, 0xc7, 0x16, 0x89, 0xa8, 0x11, 0x29, 0x42, 0x96, 0xe1, 0x84, 0x7f, 0x51, 0x1c, + 0xbc, 0x18, 0xac, 0x94, 0x5d, 0x65, 0x08, 0x5f, 0x25, 0x91, 0xb8, 0x32, 0x54, 0xca, 0xe3, 0x17, + 0xfc, 0x6b, 0x11, 0xff, 0xc9, 0x61, 0xcd, 0x34, 0xe4, 0xae, 0x4e, 0xe5, 0x47, 0xbe, 0x0d, 0x06, + 0x67, 0xf5, 0xfb, 0xe5, 0xb6, 0x38, 0x7b, 0x19, 0xde, 0xfe, 0xed, 0x4b, 0x53, 0xbf, 0x5f, 0x33, + 0x44, 0xb9, 0x98, 0x4d, 0x21, 0xb3, 0x24, 0x35, 0x38, 0xb5, 0xe0, 0xd8, 0x4d, 0xdb, 0xa3, 0x46, + 0xec, 0xf1, 0xdd, 0xb1, 0xf0, 0xb5, 0x6e, 0x4b, 0x50, 0xd4, 0xba, 0xbc, 0xc2, 0xeb, 0xc0, 0x86, + 0x34, 0xe1, 0x58, 0xc9, 0x75, 0xdb, 0x4d, 0x1a, 0xde, 0x50, 0x8d, 0x6e, 0xf9, 0x19, 0xef, 0x15, + 0x5e, 0xcb, 0x0f, 0xe9, 0x58, 0x94, 0x5f, 0x50, 0xd5, 0x3c, 0x53, 0xae, 0x11, 0xbf, 0x25, 0xce, + 0xfb, 0xb5, 0x7c, 0xff, 0xc8, 0xe8, 0x31, 0xed, 0x74, 0xb2, 0x31, 0x8b, 0xa6, 0xd7, 0xa0, 0xea, + 0x57, 0x32, 0x00, 0xa1, 0x80, 0xc9, 0x93, 0xd1, 0x50, 0x41, 0x99, 0xf0, 0xa2, 0x43, 0x44, 0x2f, + 0x88, 0xc4, 0x06, 0x22, 0xe7, 0x20, 0x8f, 0x11, 0x2e, 0xb2, 0xe1, 0xc1, 0xea, 0x5d, 0xd3, 0x32, + 0x34, 0x84, 0x32, 0xac, 0xf4, 0x14, 0x1d, 0xb1, 0x78, 0xa9, 0xcf, 0xad, 0xc2, 0x32, 0x1c, 0xab, + 0xb6, 0x97, 0xfc, 0xba, 0xa5, 0x77, 0x75, 0x18, 0x68, 0xc3, 0x6d, 0x2f, 0x05, 0x8f, 0x51, 0x23, + 0x61, 0x4c, 0xa2, 0x45, 0xd4, 0x5f, 0xcc, 0xc4, 0x66, 0xc1, 0x03, 0x5c, 0xf4, 0xde, 0x93, 0xf4, + 0xd3, 0x48, 0x4e, 0x4b, 0xea, 0x8f, 0x67, 0x61, 0x70, 0xc1, 0x76, 0x3c, 0x11, 0x32, 0xe4, 0x70, + 0xaf, 0x42, 0xd2, 0x5e, 0x29, 0xbf, 0x83, 0xbd, 0xd2, 0x39, 0xc8, 0x4b, 0x2e, 0xca, 0xfc, 0x5e, + 0xc4, 0x30, 0x1c, 0x0d, 0xa1, 0xea, 0xb7, 0x67, 0x01, 0x3e, 0xf4, 0xd4, 0x53, 0x0f, 0xb0, 0x80, + 0xd4, 0x1f, 0xcd, 0xc0, 0x31, 0x71, 0x51, 0x27, 0x05, 0xdd, 0xea, 0xf3, 0xaf, 0x58, 0xe5, 0x71, + 0xc9, 0x41, 0x9a, 0x8f, 0x63, 0x4b, 0xc0, 0xe4, 0x7d, 0xd3, 0xc3, 0xbb, 0x0a, 0x29, 0xea, 0x16, + 0x15, 0x30, 0x79, 0x09, 0xf0, 0xe9, 0xc8, 0x93, 0xfe, 0x15, 0x64, 0x2e, 0x5c, 0xf7, 0x58, 0x81, + 0xc9, 0xd4, 0x6b, 0x48, 0xf5, 0x57, 0xf2, 0x90, 0x9f, 0xbc, 0x4f, 0xeb, 0x87, 0xbc, 0x6b, 0xa4, + 0x83, 0xcd, 0xfc, 0x1e, 0x0f, 0x36, 0x77, 0xe3, 0x53, 0xf1, 0x4a, 0xd8, 0x9f, 0x85, 0x68, 0xf5, + 0xb1, 0x9e, 0x8f, 0x57, 0xef, 0xf7, 0xf4, 0xe1, 0x73, 0xc9, 0xf9, 0xfb, 0x39, 0xc8, 0x55, 0x27, + 0x16, 0x8e, 0xf4, 0xe6, 0x40, 0xf5, 0xa6, 0xfb, 0x9d, 0xb5, 0x1a, 0x5c, 0x43, 0xf5, 0x87, 0x5e, + 0xa2, 0xb1, 0x1b, 0xa7, 0x6f, 0xe6, 0x60, 0xa4, 0x3a, 0xb5, 0xb8, 0x20, 0x9d, 0x04, 0xdf, 0xe4, + 0x9e, 0x7c, 0xe8, 0x53, 0xc6, 0xbb, 0xf4, 0x5c, 0xc2, 0x9e, 0xb9, 0x55, 0xb1, 0xbc, 0x67, 0xaf, + 0xdf, 0xd6, 0x1b, 0x6d, 0x8a, 0x47, 0x2f, 0xdc, 0xef, 0xd7, 0x35, 0xdf, 0xa2, 0x5f, 0xc2, 0x87, + 0xff, 0x3e, 0x03, 0xf2, 0x22, 0xe4, 0x6e, 0x09, 0x8f, 0x8c, 0x4e, 0x7c, 0x9e, 0xbe, 0xc6, 0xf9, + 0xb0, 0x49, 0x30, 0xd7, 0x36, 0x0d, 0xe4, 0xc0, 0x4a, 0xb1, 0xc2, 0x37, 0xc4, 0x02, 0xbc, 0xad, + 0xc2, 0x2b, 0x7e, 0xe1, 0x1b, 0x95, 0x32, 0xa9, 0xc2, 0xe0, 0x02, 0x75, 0x9a, 0x26, 0x76, 0x94, + 0x3f, 0x67, 0x77, 0x67, 0xc2, 0x76, 0x2a, 0x83, 0xad, 0xb0, 0x10, 0x32, 0x93, 0xb9, 0x90, 0x37, + 0x00, 0xb8, 0x8d, 0xb2, 0xcd, 0x40, 0x8e, 0xe7, 0xd1, 0xee, 0xe7, 0xa6, 0x65, 0x8a, 0x8d, 0x27, + 0x31, 0x23, 0x77, 0x61, 0x74, 0xd6, 0x36, 0xcc, 0x65, 0x93, 0xbb, 0x5e, 0x62, 0x05, 0x85, 0xad, + 0x1d, 0x9e, 0x98, 0x29, 0xd9, 0x94, 0xca, 0xa5, 0x55, 0x93, 0x60, 0xac, 0xfe, 0x9d, 0x5e, 0xc8, + 0xb3, 0x6e, 0x3f, 0x1a, 0xbf, 0x7b, 0x19, 0xbf, 0x25, 0x18, 0xbd, 0x63, 0x3b, 0x77, 0x4d, 0x6b, + 0x25, 0xf0, 0x8a, 0x17, 0x7b, 0x53, 0xf4, 0xe4, 0x59, 0xe3, 0xb8, 0x5a, 0xe0, 0x40, 0xaf, 0x25, + 0xc8, 0xb7, 0x18, 0xc1, 0xcf, 0x03, 0xf0, 0xb7, 0xee, 0x48, 0xd3, 0x1f, 0x06, 0xab, 0xe0, 0x2f, + 0xe1, 0xd1, 0xd1, 0x5e, 0x0e, 0x56, 0x11, 0x12, 0xb3, 0x4d, 0x38, 0xf7, 0x85, 0x18, 0x40, 0xbf, + 0x7b, 0xdc, 0x84, 0xa3, 0x2f, 0x84, 0x6c, 0x04, 0x70, 0xaf, 0x88, 0x05, 0x00, 0xe9, 0x7e, 0x09, + 0x62, 0x82, 0x88, 0x4c, 0x0e, 0x22, 0x3c, 0x5c, 0xca, 0xf5, 0x92, 0x26, 0xf1, 0x20, 0xcf, 0xc6, + 0x2e, 0xc0, 0x49, 0x84, 0x5b, 0xc7, 0xfb, 0xef, 0xd0, 0x81, 0x6a, 0x68, 0x2b, 0x07, 0x2a, 0xf5, + 0x33, 0x59, 0x18, 0xa8, 0xb6, 0x97, 0xdc, 0x75, 0xd7, 0xa3, 0xcd, 0x43, 0xae, 0xc6, 0xfe, 0xf6, + 0x2a, 0x9f, 0xba, 0xbd, 0x7a, 0xd4, 0x17, 0x8a, 0x74, 0xee, 0x18, 0x98, 0x74, 0xbe, 0x38, 0xfe, + 0x46, 0x16, 0x46, 0xf9, 0xc5, 0x59, 0xd9, 0x74, 0xeb, 0xfb, 0xe0, 0xcc, 0x7f, 0xf0, 0x52, 0xd9, + 0xdb, 0x65, 0xf3, 0x36, 0x9e, 0x48, 0xa8, 0x9f, 0xcc, 0xc2, 0x60, 0xa9, 0xed, 0xad, 0x96, 0x3c, + 0xd4, 0xad, 0x07, 0x72, 0x7f, 0xf2, 0x5b, 0x19, 0x38, 0xc6, 0x1a, 0xb2, 0x68, 0xdf, 0xa5, 0xd6, + 0x3e, 0x1c, 0x3c, 0xca, 0x07, 0x88, 0xd9, 0x5d, 0x1e, 0x20, 0xfa, 0xb2, 0xcc, 0xed, 0x4c, 0x96, + 0x78, 0x5c, 0xae, 0xd9, 0x0d, 0x7a, 0xb8, 0x3f, 0x63, 0x1f, 0x8f, 0xcb, 0x7d, 0x81, 0xec, 0xc3, + 0xf5, 0xcc, 0xb7, 0x96, 0x40, 0xf6, 0xe1, 0x6c, 0xe9, 0x5b, 0x43, 0x20, 0x5f, 0xcd, 0xc0, 0xc0, + 0xb8, 0xed, 0x1d, 0xf2, 0x81, 0x2f, 0xbe, 0xe2, 0x70, 0xab, 0xb9, 0xff, 0x15, 0x87, 0x5b, 0x37, + 0xd5, 0x1f, 0xca, 0xc2, 0x09, 0x11, 0xa4, 0x5b, 0x9c, 0x3f, 0x1c, 0x4d, 0xc7, 0x62, 0xb0, 0x25, + 0x45, 0x73, 0x34, 0x0f, 0x09, 0xd1, 0xfc, 0x4c, 0x0e, 0x4e, 0x60, 0x28, 0x53, 0xb6, 0x2d, 0xfb, + 0x16, 0xb0, 0x45, 0x48, 0x3d, 0x7a, 0x09, 0x3a, 0x9b, 0x72, 0x09, 0xfa, 0x17, 0x1b, 0xc5, 0x67, + 0x57, 0x4c, 0x6f, 0xb5, 0xbd, 0x74, 0xa5, 0x6e, 0x37, 0xaf, 0xae, 0x38, 0xfa, 0x3d, 0x93, 0x5f, + 0xff, 0xe9, 0x8d, 0xab, 0x41, 0xbe, 0x0b, 0xbd, 0x65, 0x8a, 0x4c, 0x18, 0x55, 0xdc, 0xeb, 0x30, + 0xae, 0xfe, 0xf5, 0xa9, 0x0b, 0xf0, 0x9a, 0x6d, 0x5a, 0xc2, 0xa7, 0x90, 0x1b, 0xba, 0x55, 0xb6, + 0x3f, 0x7c, 0xd3, 0x36, 0xad, 0x5a, 0xdc, 0xb1, 0x70, 0xa7, 0xf5, 0x85, 0xac, 0x35, 0xa9, 0x1a, + 0xf5, 0x9f, 0x64, 0xe0, 0x4c, 0x54, 0x8b, 0xbf, 0x15, 0x6c, 0xc7, 0x1f, 0xce, 0xc2, 0xc9, 0x1b, + 0x28, 0x9c, 0xc0, 0x91, 0xe3, 0x68, 0xde, 0x12, 0x83, 0x33, 0x45, 0x36, 0x47, 0x16, 0x65, 0x67, + 0xd9, 0x1c, 0x4d, 0xea, 0x42, 0x36, 0xbf, 0x9d, 0x81, 0xe3, 0xf3, 0x95, 0xf2, 0xc4, 0xb7, 0xc8, + 0x88, 0x4a, 0x7e, 0xcf, 0x21, 0x37, 0x38, 0x13, 0xdf, 0x73, 0xc8, 0x4d, 0xcf, 0x2f, 0x64, 0xe1, + 0x78, 0xb5, 0x34, 0x3b, 0xf3, 0xad, 0x32, 0x83, 0x4f, 0xc8, 0x5e, 0x87, 0xfe, 0x21, 0x98, 0xb0, + 0x05, 0xe4, 0xcf, 0xbc, 0x7d, 0xad, 0xb3, 0x37, 0x62, 0x52, 0x28, 0x87, 0x7c, 0xea, 0xde, 0x17, + 0xa1, 0x30, 0xcd, 0x8f, 0x50, 0x1f, 0x72, 0xcd, 0xff, 0x7b, 0x05, 0x18, 0xbc, 0xd9, 0x5e, 0xa2, + 0xc2, 0x39, 0xe5, 0x81, 0x3e, 0xf9, 0xbd, 0x06, 0x83, 0x42, 0x0c, 0x78, 0x6b, 0x22, 0x05, 0xcf, + 0x13, 0xc1, 0x50, 0x78, 0x7c, 0x22, 0x99, 0x88, 0x9c, 0x83, 0xfc, 0x6d, 0xea, 0x2c, 0xc9, 0xef, + 0x4a, 0xef, 0x51, 0x67, 0x49, 0x43, 0x28, 0x99, 0x09, 0x5d, 0xe6, 0x4b, 0x0b, 0x15, 0x4c, 0xa4, + 0x22, 0x2e, 0x6c, 0x30, 0x33, 0x4c, 0xe0, 0xf7, 0xa6, 0xb7, 0x4c, 0x9e, 0x82, 0x45, 0x7e, 0xd3, + 0x1e, 0x2f, 0x49, 0xe6, 0x60, 0x4c, 0x76, 0x7c, 0xe2, 0x59, 0x44, 0xfa, 0x53, 0xd8, 0xa5, 0xe5, + 0x0f, 0x49, 0x16, 0x25, 0xaf, 0xc0, 0x90, 0x0f, 0x44, 0x17, 0xae, 0x81, 0x30, 0x74, 0x7d, 0xc0, + 0x2a, 0x96, 0xa2, 0x28, 0x52, 0x40, 0x66, 0x80, 0xd7, 0x10, 0x90, 0xc2, 0x20, 0xe6, 0x12, 0x17, + 0x29, 0x40, 0x9e, 0x41, 0x06, 0xf8, 0xcc, 0x03, 0x9d, 0x55, 0x06, 0xf1, 0xd1, 0x25, 0xba, 0xe4, + 0x3b, 0x02, 0xce, 0x9f, 0xd6, 0x46, 0xc8, 0xc8, 0x3c, 0x40, 0xe8, 0x54, 0x20, 0x02, 0x18, 0xec, + 0xd8, 0xdd, 0x41, 0x62, 0x21, 0x5f, 0x07, 0x0e, 0xef, 0xe6, 0x3a, 0x50, 0xfd, 0xdd, 0x2c, 0x0c, + 0x96, 0x5a, 0xad, 0x60, 0x28, 0x3c, 0x09, 0x85, 0x52, 0xab, 0x75, 0x4b, 0xab, 0xc8, 0xa1, 0xcc, + 0xf5, 0x56, 0xab, 0xd6, 0x76, 0x4c, 0xd9, 0x27, 0x94, 0x13, 0x91, 0x09, 0x18, 0x2e, 0xb5, 0x5a, + 0x0b, 0xed, 0xa5, 0x86, 0x59, 0x97, 0x32, 0x23, 0xf1, 0x24, 0x6e, 0xad, 0x56, 0xad, 0x85, 0x98, + 0x78, 0x7a, 0xac, 0x68, 0x19, 0xf2, 0x71, 0x0c, 0xfb, 0x23, 0x12, 0xf3, 0xf0, 0xd4, 0x1f, 0x6a, + 0x10, 0xc4, 0x3c, 0x6c, 0xdb, 0x95, 0x80, 0x88, 0x07, 0x7b, 0x3f, 0xe7, 0x87, 0xcc, 0x67, 0x15, + 0x25, 0x12, 0xf0, 0x84, 0x2c, 0xc9, 0xfb, 0xa1, 0xaf, 0xd4, 0x6a, 0x49, 0xf7, 0x4d, 0xe8, 0x54, + 0xc4, 0x4a, 0xc5, 0xfa, 0xd8, 0x27, 0x3b, 0xfb, 0x12, 0x8c, 0x44, 0x2b, 0xdb, 0x51, 0xb0, 0xf8, + 0x3f, 0xcf, 0xe0, 0x07, 0x1d, 0x72, 0x9f, 0xe6, 0xa7, 0x21, 0x57, 0x6a, 0xb5, 0xc4, 0x7c, 0x74, + 0x3c, 0xa5, 0x3f, 0xe2, 0x4f, 0xa0, 0x4b, 0xad, 0x96, 0xff, 0xe9, 0x87, 0xfc, 0x71, 0xc4, 0xae, + 0x3e, 0xfd, 0xab, 0xfc, 0xd3, 0x0f, 0xf7, 0xc3, 0x05, 0xf5, 0x57, 0x72, 0x70, 0xac, 0xd4, 0x6a, + 0x1d, 0x05, 0x99, 0xdf, 0xaf, 0x87, 0xd6, 0x4f, 0x01, 0x48, 0xd3, 0x63, 0x5f, 0xf0, 0x74, 0x6b, + 0x50, 0x9a, 0x1a, 0x95, 0x8c, 0x26, 0x11, 0xf9, 0xea, 0xd7, 0xbf, 0x23, 0xf5, 0xfb, 0x64, 0x0e, + 0xa7, 0xe2, 0xc3, 0x1e, 0x34, 0xea, 0xdd, 0xd2, 0x6d, 0xa2, 0x0f, 0x0a, 0x3b, 0xea, 0x83, 0xdf, + 0x8c, 0x0c, 0x1e, 0x0c, 0x5a, 0x7e, 0xd4, 0x0b, 0xbd, 0x7b, 0x32, 0x8b, 0x47, 0x64, 0x61, 0x8a, + 0x48, 0x36, 0x7e, 0x22, 0x25, 0x11, 0x57, 0xa9, 0xce, 0x50, 0x35, 0xd3, 0xd0, 0x62, 0xb4, 0x7e, + 0x1f, 0xf6, 0xed, 0xa8, 0x0f, 0x37, 0xb2, 0xf8, 0x76, 0x3a, 0x88, 0xcb, 0xb4, 0xf7, 0xdd, 0xc5, + 0x55, 0x00, 0xee, 0x79, 0x10, 0xb8, 0x35, 0x0f, 0xf3, 0x10, 0x2c, 0x3c, 0xbf, 0x92, 0x08, 0xc1, + 0x12, 0x92, 0x04, 0x1e, 0x52, 0xb9, 0x54, 0x0f, 0xa9, 0xcb, 0xd0, 0xaf, 0xe9, 0x6b, 0xaf, 0xb7, + 0xa9, 0xb3, 0x2e, 0xcc, 0x19, 0x1e, 0xf6, 0x50, 0x5f, 0xab, 0x7d, 0x82, 0x01, 0xb5, 0x00, 0x4d, + 0xd4, 0xe0, 0xf1, 0xbd, 0xe4, 0x11, 0xc2, 0xcf, 0xc8, 0x83, 0x27, 0xf7, 0xbb, 0x51, 0x74, 0xf2, + 0x02, 0xe4, 0x4a, 0x77, 0xaa, 0x42, 0xb2, 0x41, 0xd7, 0x96, 0xee, 0x54, 0x85, 0xbc, 0x3a, 0x96, + 0xbd, 0x53, 0x55, 0x3f, 0x99, 0x05, 0x92, 0xa4, 0x24, 0xcf, 0xc2, 0x00, 0x42, 0x57, 0x98, 0xce, + 0xc8, 0x89, 0x39, 0xd7, 0xdc, 0x9a, 0x83, 0xd0, 0x88, 0x71, 0xe7, 0x93, 0x92, 0xe7, 0x31, 0x07, + 0xb1, 0x48, 0x0d, 0x17, 0x49, 0xcc, 0xb9, 0xe6, 0xfa, 0x59, 0x7b, 0x63, 0x29, 0x88, 0x05, 0x31, + 0xda, 0x85, 0x77, 0xaa, 0xd3, 0xb6, 0xeb, 0x09, 0x51, 0x73, 0xbb, 0x70, 0xcd, 0xc5, 0x8c, 0xb0, + 0x11, 0xbb, 0x90, 0x93, 0x61, 0x56, 0xab, 0x3b, 0x55, 0xfe, 0x4c, 0xc5, 0xd0, 0xec, 0x86, 0x6f, + 0x50, 0xf2, 0xac, 0x56, 0x6b, 0x6e, 0x8d, 0x3f, 0x71, 0x31, 0x30, 0xf9, 0x71, 0x24, 0xab, 0x55, + 0xa4, 0x94, 0xfa, 0xd9, 0x7e, 0x18, 0x2d, 0xeb, 0x9e, 0xbe, 0xa4, 0xbb, 0x54, 0xda, 0x4d, 0x1f, + 0xf3, 0x61, 0xfe, 0xe7, 0x48, 0x72, 0x30, 0x96, 0x52, 0xbe, 0x26, 0x5e, 0x80, 0xbc, 0x18, 0xf2, + 0x0d, 0x72, 0x8e, 0xca, 0x49, 0xcc, 0x96, 0x6a, 0x2d, 0x01, 0xd6, 0x12, 0x84, 0xe4, 0x09, 0x18, + 0xf4, 0x61, 0x6c, 0x03, 0x90, 0x0b, 0x75, 0xc6, 0x58, 0x62, 0xf6, 0xbf, 0x26, 0xa3, 0xc9, 0xf3, + 0x30, 0xe4, 0xff, 0x94, 0x4c, 0x6b, 0x9e, 0x91, 0x6d, 0x29, 0xb1, 0x7b, 0x92, 0x49, 0xe5, 0xa2, + 0x38, 0xbf, 0xf5, 0x46, 0x8a, 0xc6, 0x92, 0x9e, 0x45, 0x48, 0xc9, 0x27, 0x60, 0xc4, 0xff, 0x2d, + 0x36, 0x0c, 0x3c, 0x3f, 0xdc, 0x13, 0x41, 0x6e, 0xe5, 0x98, 0x58, 0xaf, 0x44, 0xc9, 0xf9, 0xd6, + 0xe1, 0x21, 0x3f, 0x8f, 0x97, 0xb1, 0x94, 0xdc, 0x39, 0xc4, 0x2a, 0x20, 0x15, 0x18, 0xf3, 0x21, + 0xa1, 0x86, 0xf6, 0x85, 0x3b, 0x46, 0x63, 0xa9, 0x96, 0xaa, 0xa4, 0xc9, 0x52, 0xa4, 0x01, 0xe7, + 0x22, 0x40, 0xc3, 0x5d, 0x35, 0x97, 0x3d, 0xb1, 0xdd, 0x13, 0x31, 0x88, 0x45, 0xe2, 0xc6, 0x80, + 0x2b, 0xa7, 0xf1, 0x33, 0xb0, 0x46, 0xb3, 0x43, 0x75, 0xe5, 0x46, 0xaa, 0x70, 0xc2, 0xc7, 0xdf, + 0x98, 0x58, 0x58, 0x70, 0xec, 0x37, 0x69, 0xdd, 0xab, 0x94, 0xc5, 0x76, 0x19, 0x63, 0xd3, 0x19, + 0x4b, 0xb5, 0x95, 0x7a, 0x8b, 0x29, 0x05, 0xc3, 0x45, 0x99, 0xa7, 0x16, 0x26, 0xb7, 0xe1, 0xa4, + 0x04, 0xaf, 0x58, 0xae, 0xa7, 0x5b, 0x75, 0x5a, 0x29, 0x8b, 0x3d, 0x34, 0xee, 0xe7, 0x05, 0x57, + 0x53, 0x20, 0xa3, 0x6c, 0xd3, 0x8b, 0x93, 0x97, 0x60, 0xd8, 0x47, 0xf0, 0x5b, 0xc4, 0x41, 0xbc, + 0x45, 0xc4, 0x21, 0x69, 0x2c, 0xd5, 0xe2, 0xaf, 0x29, 0xa3, 0xc4, 0xb2, 0x46, 0x61, 0x6a, 0xfb, + 0xa1, 0x88, 0x46, 0x79, 0xeb, 0xad, 0x54, 0x65, 0xc4, 0x74, 0xf7, 0xaf, 0x84, 0x1a, 0x35, 0xef, + 0x98, 0x2b, 0x26, 0xdf, 0x49, 0xfb, 0x0f, 0x28, 0x97, 0x6a, 0x36, 0x02, 0xd3, 0xf4, 0x83, 0x93, + 0x9f, 0x2d, 0xc1, 0xf1, 0x14, 0x1d, 0xdb, 0xd1, 0x8e, 0xf1, 0x33, 0xd9, 0xb0, 0x11, 0x87, 0x7c, + 0xdb, 0x38, 0x0e, 0xfd, 0xfe, 0x97, 0x08, 0xe3, 0x41, 0xe9, 0x34, 0x34, 0xe3, 0x3c, 0x7c, 0x7c, + 0x44, 0x1c, 0x87, 0x7c, 0x2b, 0xb9, 0x1f, 0xe2, 0x78, 0x3b, 0x13, 0x8a, 0xe3, 0x90, 0x6f, 0x2f, + 0x7f, 0x3b, 0x17, 0xce, 0x49, 0x47, 0x7b, 0xcc, 0xfd, 0x32, 0x93, 0x43, 0x3f, 0xd8, 0xc2, 0x0e, + 0x1e, 0x32, 0xca, 0xaa, 0xd9, 0xb7, 0x4b, 0xd5, 0xfc, 0xfd, 0x64, 0x7f, 0x72, 0xd3, 0xf3, 0x50, + 0xf6, 0xe7, 0x3e, 0x0c, 0x56, 0x72, 0x2d, 0x5c, 0xc7, 0xb8, 0x8d, 0xde, 0x2b, 0x85, 0xf8, 0x5b, + 0x12, 0x26, 0x7a, 0x94, 0x84, 0x7c, 0x04, 0x4e, 0x47, 0x00, 0x0b, 0xba, 0xa3, 0x37, 0xa9, 0x17, + 0x66, 0x1c, 0xc4, 0xa0, 0x4d, 0x7e, 0xe9, 0x5a, 0x2b, 0x40, 0xcb, 0x59, 0x0c, 0x3b, 0x70, 0x90, + 0x94, 0xa3, 0x6f, 0x07, 0x4e, 0xd2, 0x5f, 0xcc, 0x85, 0xa6, 0x4a, 0x34, 0xf8, 0xaa, 0x46, 0xdd, + 0x76, 0xc3, 0x7b, 0x70, 0x3b, 0x78, 0x77, 0xa9, 0x2d, 0xa6, 0xe1, 0x58, 0x69, 0x79, 0x99, 0xd6, + 0x3d, 0x3f, 0xa6, 0xb4, 0x2b, 0xc2, 0xed, 0xf1, 0xad, 0x83, 0x40, 0x89, 0x18, 0xc1, 0x91, 0xdc, + 0xf8, 0xb1, 0x62, 0xea, 0x1f, 0xe4, 0x41, 0x09, 0x4c, 0xf7, 0xe0, 0xa1, 0xd6, 0x01, 0x2e, 0x93, + 0xef, 0x8a, 0x5e, 0x31, 0x61, 0x2c, 0x14, 0x46, 0xb5, 0xdd, 0x6c, 0xea, 0x38, 0xf4, 0xd8, 0xd6, + 0xa0, 0x18, 0x67, 0x16, 0x12, 0xf2, 0xdd, 0xc0, 0x59, 0xb1, 0x1b, 0x20, 0xe1, 0x43, 0xb8, 0x9a, + 0xcb, 0x59, 0x68, 0x49, 0xae, 0xe4, 0x73, 0x19, 0x38, 0xe1, 0x77, 0xca, 0xfc, 0x12, 0x33, 0x8b, + 0x27, 0xec, 0xb6, 0xe5, 0xf9, 0x3b, 0x91, 0x17, 0x3a, 0x57, 0xc7, 0x3b, 0xe9, 0x4a, 0x5a, 0x61, + 0xde, 0x92, 0x20, 0xb0, 0x44, 0xa0, 0x10, 0x36, 0xd2, 0xd4, 0xea, 0x48, 0xa4, 0xa5, 0xd6, 0x7b, + 0xf6, 0x06, 0x9c, 0xe9, 0xc8, 0x72, 0x2b, 0x33, 0xb4, 0x57, 0x36, 0x43, 0xff, 0x59, 0x26, 0x9c, + 0x88, 0x62, 0x42, 0x22, 0x57, 0x00, 0x42, 0x90, 0xd8, 0x98, 0x8e, 0x6c, 0x6e, 0x14, 0x21, 0x14, + 0x9a, 0x26, 0x51, 0x90, 0x79, 0x28, 0x08, 0xb1, 0xf0, 0xec, 0xbe, 0xef, 0xdb, 0xa2, 0x17, 0xae, + 0xc8, 0x72, 0xc0, 0x4d, 0xa7, 0xf8, 0x66, 0xc1, 0xe6, 0xec, 0xf3, 0x30, 0xb8, 0xdb, 0xef, 0xfa, + 0x5c, 0x0e, 0x88, 0xbc, 0x8b, 0x3c, 0x40, 0x13, 0xfb, 0x10, 0x4f, 0x61, 0x97, 0xa0, 0x9f, 0x7d, + 0x02, 0xe6, 0xbb, 0x90, 0xe2, 0xdb, 0xb6, 0x05, 0x4c, 0x0b, 0xb0, 0x61, 0x70, 0xa9, 0xbe, 0xf4, + 0xe0, 0x52, 0xea, 0x0f, 0xe4, 0xe0, 0x94, 0xdc, 0x21, 0x65, 0x8a, 0x21, 0xf3, 0x8f, 0x3a, 0xe5, + 0x1d, 0xec, 0x14, 0x15, 0x0a, 0x7c, 0xf3, 0x20, 0x72, 0x17, 0xf0, 0x83, 0x1d, 0x84, 0x68, 0x02, + 0xa3, 0xfe, 0xab, 0x2c, 0x0c, 0x2f, 0xd8, 0xae, 0xb7, 0xe2, 0x50, 0x77, 0x41, 0x77, 0xdc, 0x07, + 0xb8, 0x3b, 0x3e, 0x00, 0xc3, 0x18, 0x1e, 0xa8, 0x49, 0x2d, 0x1e, 0x42, 0xa7, 0x57, 0x4a, 0x36, + 0xe2, 0x23, 0x44, 0x5e, 0xa9, 0x08, 0x21, 0xd3, 0x7e, 0x6e, 0xf9, 0x49, 0x41, 0x9b, 0xb8, 0xd9, + 0xc7, 0xe1, 0xea, 0x4f, 0xe6, 0x60, 0xc8, 0x97, 0xf2, 0xb8, 0x79, 0x58, 0x6f, 0x6a, 0x0e, 0x56, + 0xc8, 0x57, 0x01, 0x16, 0x6c, 0xc7, 0xd3, 0x1b, 0x73, 0xa1, 0xe6, 0xe3, 0x11, 0x67, 0x0b, 0xa1, + 0xbc, 0x8c, 0x44, 0x82, 0xeb, 0x57, 0x68, 0x56, 0xf3, 0x89, 0x89, 0xaf, 0x5f, 0x01, 0x54, 0x93, + 0x28, 0xd4, 0x5f, 0xcf, 0xc2, 0x31, 0xbf, 0x93, 0x26, 0xef, 0xd3, 0x7a, 0xfb, 0x41, 0x9e, 0x9b, + 0xa2, 0xd2, 0xee, 0xdd, 0x52, 0xda, 0xea, 0x7f, 0x92, 0x26, 0x92, 0x89, 0x86, 0x7d, 0x34, 0x91, + 0xfc, 0x55, 0xe8, 0xb8, 0xfa, 0x9d, 0x39, 0x38, 0xe1, 0x4b, 0x7d, 0xaa, 0x6d, 0xe1, 0xe1, 0xc0, + 0x84, 0xde, 0x68, 0x3c, 0xc8, 0xbb, 0xf1, 0x41, 0x5f, 0x10, 0xf3, 0x22, 0xde, 0x9e, 0xc8, 0xf1, + 0xb7, 0x2c, 0xc0, 0x35, 0xdb, 0x34, 0x34, 0x99, 0x88, 0xbc, 0x02, 0x43, 0xfe, 0xcf, 0x92, 0xb3, + 0xe2, 0x6f, 0xc1, 0xf1, 0xa8, 0x3f, 0x28, 0xa4, 0x3b, 0x91, 0xb0, 0x02, 0x91, 0x02, 0xea, 0xbf, + 0x29, 0xc0, 0xd9, 0x3b, 0xa6, 0x65, 0xd8, 0x6b, 0xae, 0x9f, 0x22, 0xf2, 0xd0, 0x1f, 0x75, 0x1d, + 0x74, 0x6a, 0xc8, 0xd7, 0xe1, 0x64, 0x5c, 0xa4, 0x4e, 0x10, 0xb8, 0x5b, 0xf4, 0xce, 0x1a, 0x27, + 0xa8, 0xf9, 0xc9, 0x22, 0xc5, 0x7d, 0x99, 0x96, 0x5e, 0x32, 0x9e, 0x6d, 0xb2, 0x6f, 0x3b, 0xd9, + 0x26, 0x1f, 0x87, 0x42, 0xd9, 0x6e, 0xea, 0xa6, 0x1f, 0x60, 0x06, 0x47, 0x71, 0x50, 0x2f, 0x62, + 0x34, 0x41, 0xc1, 0xf8, 0x8b, 0x8a, 0xb1, 0xcb, 0x06, 0x42, 0xfe, 0x7e, 0x01, 0x66, 0xa5, 0x69, + 0x32, 0x11, 0xb1, 0x61, 0x58, 0x54, 0x27, 0x6e, 0xb7, 0x00, 0x37, 0x4f, 0xcf, 0xf8, 0x32, 0xea, + 0xac, 0x56, 0x57, 0x22, 0xe5, 0xf8, 0x36, 0x8a, 0x27, 0xc1, 0x14, 0x1f, 0xc3, 0xef, 0xb9, 0xb4, + 0x28, 0x7f, 0x49, 0x08, 0x38, 0xc9, 0x0c, 0x26, 0x85, 0x80, 0xb3, 0x8c, 0x4c, 0x44, 0x26, 0x61, + 0x0c, 0xc3, 0x2b, 0x07, 0x5b, 0x29, 0xa6, 0x12, 0x43, 0x68, 0x54, 0xe2, 0xa5, 0x09, 0x8f, 0xc8, + 0xcc, 0x3e, 0xae, 0x56, 0x17, 0x68, 0x2d, 0x59, 0xe2, 0xec, 0xab, 0x40, 0x92, 0x6d, 0xde, 0xd1, + 0xb5, 0xc9, 0x3f, 0x90, 0xf6, 0x75, 0x87, 0xdd, 0xf1, 0x65, 0x3f, 0x66, 0xbb, 0x48, 0xea, 0xb0, + 0xde, 0x77, 0x32, 0x75, 0x58, 0x61, 0x5f, 0x53, 0x87, 0xa9, 0xbf, 0x90, 0x81, 0xb1, 0x44, 0x9c, + 0x71, 0xf2, 0x34, 0x00, 0x87, 0x48, 0xf1, 0x1c, 0x31, 0x40, 0x4a, 0x18, 0x7b, 0x5c, 0xac, 0x81, + 0x21, 0x19, 0xb9, 0x0a, 0xfd, 0xfc, 0x97, 0x88, 0xc1, 0x94, 0x2c, 0xd2, 0x6e, 0x9b, 0x86, 0x16, + 0x10, 0x85, 0xb5, 0xe0, 0xc5, 0x61, 0x2e, 0xb5, 0x88, 0xb7, 0xde, 0x0a, 0x6a, 0x61, 0x64, 0xea, + 0x67, 0xb3, 0x30, 0x14, 0x34, 0xb8, 0x64, 0x1c, 0x94, 0xce, 0x15, 0x44, 0xc8, 0xf6, 0xdc, 0x56, + 0x21, 0xdb, 0x63, 0x93, 0xaa, 0x88, 0xd1, 0xbe, 0x7f, 0xef, 0x9e, 0x3e, 0x9f, 0x85, 0x63, 0x41, + 0xad, 0x07, 0x78, 0x47, 0xf5, 0x2e, 0x12, 0xc9, 0xe7, 0x32, 0xa0, 0x8c, 0x9b, 0x8d, 0x86, 0x69, + 0xad, 0x54, 0xac, 0x65, 0xdb, 0x69, 0xe2, 0xac, 0x77, 0x70, 0xe7, 0xb4, 0xea, 0xf7, 0x64, 0x60, + 0x4c, 0x34, 0x68, 0x42, 0x77, 0x8c, 0x83, 0x3b, 0x04, 0x8b, 0xb7, 0xe4, 0xe0, 0xf4, 0x45, 0xfd, + 0x72, 0x16, 0x60, 0xc6, 0xae, 0xdf, 0x3d, 0xe4, 0xcf, 0xa6, 0x5e, 0x84, 0x02, 0x0f, 0x84, 0x25, + 0x34, 0x76, 0x4c, 0x3c, 0x0f, 0x62, 0x9f, 0xc6, 0x11, 0xe3, 0xa3, 0x62, 0x3e, 0x2e, 0xf0, 0x40, + 0x5a, 0x4a, 0x46, 0x13, 0x45, 0x58, 0xa5, 0x8c, 0x4e, 0x2c, 0x18, 0x41, 0xa5, 0x0c, 0x16, 0xad, + 0x74, 0x73, 0xa3, 0x98, 0x6f, 0xd8, 0xf5, 0xbb, 0x1a, 0xd2, 0xab, 0x7f, 0x99, 0xe1, 0xb2, 0x3b, + 0xe4, 0x8f, 0x3f, 0xfd, 0xcf, 0xcf, 0xef, 0xf0, 0xf3, 0xbf, 0x37, 0x03, 0x27, 0x34, 0x5a, 0xb7, + 0xef, 0x51, 0x67, 0x7d, 0xc2, 0x36, 0xe8, 0x0d, 0x6a, 0x51, 0xe7, 0xa0, 0x46, 0xd4, 0xdf, 0xc6, + 0x1c, 0x17, 0x61, 0x63, 0x6e, 0xb9, 0xd4, 0x38, 0x3c, 0xf9, 0x47, 0xd4, 0xbf, 0xd9, 0x07, 0x4a, + 0xaa, 0x69, 0x7b, 0x68, 0xcd, 0xb9, 0x8e, 0xfb, 0x95, 0xfc, 0x7e, 0xed, 0x57, 0x7a, 0x77, 0xb6, + 0x5f, 0x29, 0xec, 0x74, 0xbf, 0xd2, 0xb7, 0x9d, 0xfd, 0x4a, 0x33, 0xbe, 0x5f, 0xe9, 0xc7, 0xfd, + 0xca, 0xd3, 0x5d, 0xf7, 0x2b, 0x93, 0x96, 0xb1, 0xcb, 0xdd, 0xca, 0xa1, 0xcd, 0x8d, 0xbb, 0x9b, + 0x6d, 0xd6, 0x25, 0x36, 0x29, 0xd6, 0x6d, 0xc7, 0xa0, 0x86, 0xd8, 0x5d, 0xe1, 0xd1, 0xbe, 0x23, + 0x60, 0x5a, 0x80, 0x4d, 0x24, 0x1a, 0x1e, 0xde, 0x4e, 0xa2, 0xe1, 0x7d, 0xd8, 0x7f, 0x7d, 0x26, + 0x0b, 0x63, 0x13, 0xd4, 0xf1, 0x78, 0xa4, 0xcd, 0xfd, 0xf0, 0x5c, 0x2b, 0xc1, 0x31, 0x89, 0x21, + 0x5a, 0xe4, 0xd9, 0xd0, 0x1b, 0xaf, 0x4e, 0x1d, 0x2f, 0xee, 0xcc, 0x17, 0xa7, 0x67, 0xd5, 0xfb, + 0xc9, 0xbe, 0xc4, 0xd8, 0x0d, 0xaa, 0xf7, 0xe1, 0x5c, 0x90, 0xa6, 0xf8, 0xa5, 0x05, 0xf4, 0x52, + 0xfe, 0xae, 0xfc, 0xce, 0xf3, 0x77, 0xa9, 0x3f, 0x9f, 0x81, 0x8b, 0x1a, 0xb5, 0xe8, 0x9a, 0xbe, + 0xd4, 0xa0, 0x52, 0xb3, 0xc4, 0xca, 0xc0, 0x66, 0x0d, 0xd3, 0x6d, 0xea, 0x5e, 0x7d, 0x75, 0x4f, + 0x32, 0x9a, 0x82, 0x21, 0x79, 0xfe, 0xda, 0xc1, 0xdc, 0x16, 0x29, 0xa7, 0xfe, 0xfb, 0x1c, 0xf4, + 0x8d, 0xdb, 0xde, 0x6b, 0xf6, 0x1e, 0x13, 0xca, 0x85, 0x53, 0x7e, 0x76, 0x07, 0x07, 0x3a, 0xef, + 0xc7, 0xca, 0xa5, 0x18, 0xfb, 0xe8, 0xe9, 0xb9, 0x64, 0x27, 0x72, 0x11, 0xf8, 0x64, 0x3b, 0x4c, + 0x25, 0xf7, 0x2c, 0x0c, 0x60, 0x90, 0x16, 0xe9, 0xc8, 0x15, 0xfd, 0xa8, 0x3d, 0x06, 0x8c, 0xd7, + 0x11, 0x92, 0x92, 0x8f, 0x44, 0x42, 0x83, 0x16, 0xf6, 0x9e, 0x7a, 0x4e, 0x8e, 0x12, 0xfa, 0x34, + 0xbf, 0xad, 0xc3, 0x36, 0x49, 0x69, 0x3a, 0xf0, 0xa8, 0x24, 0xd6, 0xa4, 0x80, 0x70, 0xff, 0xd2, + 0xc2, 0xa9, 0xdf, 0xcc, 0xc3, 0x90, 0xef, 0x72, 0x7b, 0x40, 0xdd, 0xfe, 0x24, 0x14, 0xa6, 0x6d, + 0x29, 0xc9, 0x00, 0xba, 0xe8, 0xae, 0xda, 0x6e, 0xcc, 0xf7, 0x58, 0x10, 0x31, 0x81, 0xcd, 0xd9, + 0x86, 0xec, 0x60, 0x8e, 0x02, 0xb3, 0x6c, 0x23, 0xf1, 0x40, 0x37, 0x20, 0x24, 0x17, 0x21, 0x8f, + 0xbe, 0xf9, 0xd2, 0x41, 0x7b, 0xcc, 0x1f, 0x1f, 0xf1, 0x92, 0x42, 0x15, 0x76, 0xaa, 0x50, 0x7d, + 0xbb, 0x55, 0xa8, 0xfe, 0xfd, 0x55, 0xa8, 0x37, 0x60, 0x08, 0x6b, 0xf2, 0x73, 0x94, 0x6d, 0xbd, + 0x26, 0x9e, 0x11, 0xcb, 0xd6, 0x30, 0x6f, 0xb7, 0xc8, 0x54, 0x86, 0xab, 0x55, 0x84, 0x55, 0x4c, + 0xed, 0x60, 0x0f, 0x6a, 0xf7, 0xfb, 0x19, 0xe8, 0xbb, 0x65, 0xdd, 0xb5, 0xec, 0xb5, 0xbd, 0x69, + 0xdc, 0xd3, 0x30, 0x28, 0xd8, 0x48, 0x0b, 0x03, 0xbe, 0xb9, 0x6e, 0x73, 0x70, 0x0d, 0x39, 0x69, + 0x32, 0x15, 0x79, 0x29, 0x28, 0x84, 0xcf, 0x6f, 0x72, 0x61, 0x9a, 0x0e, 0xbf, 0x50, 0x3d, 0x9a, + 0x59, 0x40, 0x26, 0x27, 0xe7, 0x20, 0x5f, 0x66, 0x4d, 0x95, 0xe2, 0xd4, 0xb2, 0xa6, 0x68, 0x08, + 0x55, 0x3f, 0x93, 0x87, 0x91, 0xd8, 0x99, 0xd5, 0xe3, 0x30, 0x20, 0xce, 0x8c, 0x4c, 0x3f, 0xd5, + 0x01, 0x3e, 0xcf, 0x09, 0x80, 0x5a, 0x3f, 0xff, 0xb3, 0x62, 0x90, 0x0f, 0x42, 0x9f, 0xed, 0xe2, + 0x7a, 0x86, 0xdf, 0x32, 0x12, 0x0e, 0xa1, 0xf9, 0x2a, 0x6b, 0x3b, 0x1f, 0x1c, 0x82, 0x44, 0xd6, + 0x48, 0xdb, 0xc5, 0x4f, 0xbb, 0x0e, 0x03, 0xba, 0xeb, 0x52, 0xaf, 0xe6, 0xe9, 0x2b, 0x72, 0xf6, + 0x83, 0x00, 0x28, 0x8f, 0x0e, 0x04, 0x2e, 0xea, 0x2b, 0xe4, 0x55, 0x18, 0xae, 0x3b, 0x14, 0x57, + 0x3c, 0xbd, 0xc1, 0x5a, 0x29, 0x59, 0xa4, 0x11, 0x84, 0x7c, 0xbf, 0x11, 0x22, 0x2a, 0x06, 0xb9, + 0x0d, 0xc3, 0xe2, 0x73, 0xb8, 0x6f, 0x3c, 0x0e, 0xb4, 0x91, 0x70, 0x05, 0xe2, 0x22, 0xe1, 0xde, + 0xf1, 0xe2, 0x89, 0x84, 0x4c, 0x2e, 0xf3, 0x35, 0x24, 0x52, 0x32, 0x0f, 0x64, 0x8d, 0x2e, 0xd5, + 0xf4, 0xb6, 0xb7, 0xca, 0xea, 0xe2, 0xc1, 0xbb, 0x45, 0xd2, 0x3f, 0x7c, 0x57, 0x90, 0xc4, 0xca, + 0xcf, 0x2d, 0xd6, 0xe8, 0x52, 0x29, 0x82, 0x24, 0x77, 0xe0, 0x64, 0xb2, 0x08, 0xfb, 0x64, 0x7e, + 0x78, 0xff, 0xe8, 0xe6, 0x46, 0xb1, 0x98, 0x4a, 0x20, 0xb1, 0x3d, 0x9e, 0x60, 0x5b, 0x31, 0x5e, + 0xcb, 0xf7, 0xf7, 0x8d, 0xf6, 0x6b, 0x23, 0xac, 0xac, 0x6f, 0xfd, 0x99, 0x86, 0xfa, 0xb5, 0x0c, + 0xb3, 0xf2, 0xd8, 0x07, 0x61, 0xd6, 0x63, 0xa6, 0xeb, 0xcd, 0x1d, 0xea, 0x7a, 0x33, 0xcc, 0x4f, + 0x58, 0x70, 0xbb, 0xcc, 0xae, 0x9a, 0xc0, 0x92, 0x2b, 0x50, 0x30, 0xe4, 0x03, 0xaf, 0x53, 0xd1, + 0x4e, 0xf0, 0xeb, 0xd1, 0x04, 0x15, 0xb9, 0x04, 0x79, 0xb6, 0xda, 0xc4, 0x77, 0xbb, 0xb2, 0x61, + 0xa0, 0x21, 0x85, 0xfa, 0xed, 0x59, 0x18, 0x92, 0xbe, 0xe6, 0xda, 0x9e, 0x3e, 0xe7, 0x85, 0xed, + 0x35, 0xd3, 0x77, 0x4a, 0xc1, 0x6d, 0x90, 0xdf, 0xe4, 0xeb, 0x81, 0x28, 0xb6, 0x75, 0x61, 0x24, + 0x04, 0xf3, 0xac, 0xf8, 0xd0, 0xc2, 0xf6, 0x77, 0x7e, 0x8c, 0xfe, 0xb5, 0x7c, 0x7f, 0x76, 0x34, + 0xf7, 0x5a, 0xbe, 0x3f, 0x3f, 0xda, 0x8b, 0x91, 0xae, 0x30, 0xb8, 0x34, 0xdf, 0x56, 0x5b, 0xcb, + 0xe6, 0xca, 0x21, 0x7f, 0x9d, 0xb1, 0xbf, 0x51, 0xc0, 0x62, 0xb2, 0x39, 0xe4, 0x4f, 0x35, 0xde, + 0x51, 0xd9, 0x1c, 0xe5, 0x33, 0x14, 0xb2, 0xf9, 0x83, 0x0c, 0x28, 0xa9, 0xb2, 0x29, 0x1d, 0x90, + 0x9f, 0xc2, 0xfe, 0x65, 0x35, 0xfc, 0x46, 0x16, 0xc6, 0x2a, 0x96, 0x47, 0x57, 0xf8, 0x66, 0xef, + 0x90, 0x4f, 0x15, 0x37, 0x61, 0x50, 0xfa, 0x18, 0xd1, 0xe7, 0x0f, 0x05, 0x5b, 0xe9, 0x10, 0xd5, + 0x81, 0x93, 0x5c, 0x7a, 0x1f, 0x13, 0xa1, 0xc7, 0x84, 0x7c, 0xc8, 0xe7, 0x9c, 0xc3, 0x21, 0xe4, + 0x43, 0x3e, 0x79, 0xbd, 0x4b, 0x85, 0xfc, 0x1f, 0x32, 0x70, 0x3c, 0xa5, 0x72, 0x72, 0x11, 0xfa, + 0xaa, 0xed, 0x25, 0x0c, 0x6c, 0x95, 0x09, 0x3d, 0x7a, 0xdd, 0xf6, 0x12, 0xc6, 0xb4, 0xd2, 0x7c, + 0x24, 0x59, 0xc4, 0xe7, 0xeb, 0xf3, 0x95, 0xf2, 0x84, 0x90, 0xaa, 0x2a, 0x3d, 0xc4, 0x67, 0xe0, + 0xb4, 0x2f, 0x0b, 0x9e, 0xb8, 0xdb, 0xa6, 0x51, 0x8f, 0x3d, 0x71, 0x67, 0x65, 0xc8, 0x47, 0x61, + 0xa0, 0xf4, 0x56, 0xdb, 0xa1, 0xc8, 0x97, 0x4b, 0xfc, 0x3d, 0x01, 0x5f, 0x1f, 0x91, 0xc6, 0x99, + 0xbf, 0xd6, 0x67, 0x14, 0x71, 0xde, 0x21, 0x43, 0xf5, 0xb3, 0x19, 0x38, 0xdb, 0xb9, 0x75, 0xe4, + 0xfd, 0xd0, 0xc7, 0x76, 0xe6, 0x25, 0x6d, 0x4e, 0x7c, 0x3a, 0xcf, 0x00, 0x6a, 0x37, 0x68, 0x4d, + 0x77, 0x64, 0x63, 0xdf, 0x27, 0x23, 0x2f, 0xc3, 0x60, 0xc5, 0x75, 0xdb, 0xd4, 0xa9, 0x3e, 0x7d, + 0x4b, 0xab, 0x88, 0x3d, 0x21, 0xee, 0x39, 0x4c, 0x04, 0xd7, 0xdc, 0xa7, 0x63, 0xa1, 0xab, 0x64, + 0x7a, 0xf5, 0x53, 0x19, 0x38, 0xd7, 0xed, 0xab, 0xc8, 0xd3, 0xd0, 0xbf, 0x48, 0x2d, 0xdd, 0xf2, + 0x2a, 0x65, 0xd1, 0x24, 0xdc, 0x62, 0x79, 0x08, 0x8b, 0xee, 0x14, 0x02, 0x42, 0x56, 0x88, 0x1f, + 0x09, 0x06, 0x3e, 0x08, 0xfc, 0xf8, 0x12, 0x61, 0xb1, 0x42, 0x3e, 0xa1, 0xfa, 0x87, 0x75, 0xe8, + 0x9d, 0xb7, 0xe8, 0xfc, 0x32, 0x79, 0x0a, 0x06, 0x98, 0xee, 0x63, 0xfa, 0x7d, 0x31, 0xd0, 0xc6, + 0xe4, 0x01, 0x83, 0x88, 0xe9, 0x1e, 0x2d, 0xa4, 0x22, 0xd7, 0xe5, 0x9c, 0xdf, 0x42, 0x1d, 0x88, + 0x5c, 0x86, 0x63, 0xa6, 0x7b, 0x34, 0x39, 0x37, 0xf8, 0x75, 0x39, 0xd7, 0xb2, 0xe8, 0xec, 0x48, + 0x29, 0x8e, 0xf1, 0x4b, 0x89, 0x69, 0x60, 0x26, 0x2d, 0x21, 0x71, 0xdc, 0x26, 0x48, 0x52, 0x4c, + 0xf7, 0x68, 0xe9, 0x89, 0x8c, 0x87, 0x64, 0x37, 0xa6, 0xf8, 0x2d, 0xa4, 0x8c, 0x9b, 0xee, 0xd1, + 0x22, 0xb4, 0xe4, 0x39, 0x18, 0x14, 0xbf, 0x5f, 0xb3, 0x4d, 0x2b, 0x1e, 0xc3, 0x42, 0x42, 0x4d, + 0xf7, 0x68, 0x32, 0xa5, 0x54, 0xe9, 0x82, 0x63, 0x5a, 0x9e, 0x78, 0x19, 0x17, 0xaf, 0x14, 0x71, + 0x52, 0xa5, 0xf8, 0x9b, 0xbc, 0x0c, 0xc3, 0x41, 0x70, 0x90, 0x37, 0x69, 0xdd, 0x13, 0x47, 0x3a, + 0x27, 0x63, 0x85, 0x39, 0x72, 0xba, 0x47, 0x8b, 0x52, 0x93, 0x4b, 0x50, 0xd0, 0xa8, 0x6b, 0xbe, + 0xe5, 0xdf, 0x5f, 0x8c, 0x48, 0xd3, 0x99, 0xf9, 0x16, 0x93, 0x92, 0xc0, 0xb3, 0xde, 0x09, 0x2f, + 0x4c, 0xc4, 0x01, 0x0c, 0x89, 0xd5, 0x32, 0x69, 0x19, 0xac, 0x77, 0xa4, 0xdb, 0xb2, 0x57, 0xc3, + 0x90, 0x29, 0x22, 0xd1, 0xda, 0x60, 0xfc, 0x6d, 0xaa, 0x8c, 0x9d, 0xee, 0xd1, 0x62, 0xf4, 0x92, + 0x54, 0xcb, 0xa6, 0x7b, 0x57, 0x44, 0xa9, 0x8b, 0x4b, 0x95, 0xa1, 0x24, 0xa9, 0xb2, 0x9f, 0x52, + 0xd5, 0x73, 0xd4, 0x5b, 0xb3, 0x9d, 0xbb, 0x22, 0x26, 0x5d, 0xbc, 0x6a, 0x81, 0x95, 0xaa, 0x16, + 0x10, 0xb9, 0x6a, 0xb6, 0xc8, 0x8c, 0xa4, 0x57, 0xad, 0x7b, 0xba, 0x5c, 0x35, 0xdf, 0x5f, 0xfa, + 0x9d, 0x34, 0x43, 0xf5, 0x7b, 0x3c, 0xdf, 0x6d, 0xb2, 0x43, 0x11, 0x27, 0x75, 0x28, 0xfe, 0x66, + 0x95, 0x4a, 0x39, 0x4d, 0x45, 0x42, 0xdb, 0xa0, 0x52, 0x09, 0xc5, 0x2a, 0x95, 0xb3, 0x9f, 0x5e, + 0x97, 0x53, 0x7d, 0x2a, 0x63, 0xd1, 0x0e, 0x0a, 0x31, 0xac, 0x83, 0xa4, 0x94, 0xa0, 0x45, 0x4c, + 0x23, 0xa8, 0x10, 0x24, 0x1f, 0x0c, 0x5a, 0x38, 0xb1, 0x30, 0xdd, 0xa3, 0x61, 0x82, 0x41, 0x95, + 0x27, 0xa8, 0x54, 0x8e, 0x23, 0xc5, 0x90, 0x4f, 0xc1, 0x60, 0xd3, 0x3d, 0x1a, 0x4f, 0x5e, 0xf9, + 0x94, 0x94, 0x0a, 0x4a, 0x39, 0x11, 0x9d, 0x22, 0x02, 0x04, 0x9b, 0x22, 0xc2, 0x84, 0x51, 0x53, + 0xc9, 0x74, 0x49, 0xca, 0xc9, 0xe8, 0x8a, 0x1a, 0xc7, 0x4f, 0xf7, 0x68, 0xc9, 0x14, 0x4b, 0xcf, + 0x45, 0x32, 0x08, 0x29, 0xa7, 0x62, 0x81, 0x63, 0x42, 0x14, 0x13, 0x97, 0x9c, 0x6b, 0x68, 0x3e, + 0x35, 0xe7, 0xb7, 0x72, 0x3a, 0xba, 0x1c, 0xa7, 0x90, 0x4c, 0xf7, 0x68, 0xa9, 0xd9, 0xc2, 0x27, + 0x12, 0x79, 0x7c, 0x14, 0x25, 0x7a, 0x59, 0x1b, 0x43, 0x4f, 0xf7, 0x68, 0x89, 0xcc, 0x3f, 0xd7, + 0xe5, 0x04, 0x3a, 0xca, 0x99, 0x68, 0x27, 0x86, 0x18, 0xd6, 0x89, 0x52, 0xa2, 0x9d, 0xeb, 0x72, + 0x52, 0x15, 0xe5, 0x6c, 0xb2, 0x54, 0x38, 0x73, 0x4a, 0xc9, 0x57, 0xb4, 0xf4, 0x3c, 0x11, 0xca, + 0x43, 0x22, 0x53, 0x9f, 0x28, 0x9f, 0x46, 0x33, 0xdd, 0xa3, 0xa5, 0xe7, 0x98, 0xd0, 0xd2, 0x13, + 0x2c, 0x28, 0xe7, 0xba, 0xf1, 0x0c, 0x5a, 0x97, 0x9e, 0x9c, 0x41, 0xef, 0x12, 0xee, 0x5e, 0x39, + 0x1f, 0x8d, 0x5a, 0xd9, 0x91, 0x70, 0xba, 0x47, 0xeb, 0x12, 0x34, 0xff, 0x56, 0x87, 0xd8, 0xf3, + 0xca, 0x85, 0x68, 0xa2, 0xce, 0x54, 0xa2, 0xe9, 0x1e, 0xad, 0x43, 0xe4, 0xfa, 0x5b, 0x1d, 0x42, + 0x93, 0x2b, 0xc5, 0xae, 0x6c, 0x03, 0x79, 0x74, 0x08, 0x6c, 0x3e, 0x9f, 0x1a, 0xd5, 0x5b, 0x79, + 0x38, 0xaa, 0xba, 0x29, 0x24, 0x4c, 0x75, 0xd3, 0xe2, 0x81, 0xcf, 0xa7, 0x86, 0xa1, 0x56, 0x1e, + 0xe9, 0xc2, 0x30, 0x68, 0x63, 0x6a, 0x00, 0xeb, 0xf9, 0xd4, 0x38, 0xd0, 0x8a, 0x1a, 0x65, 0x98, + 0x42, 0xc2, 0x18, 0xa6, 0x45, 0x90, 0x9e, 0x4f, 0x0d, 0x17, 0xac, 0x3c, 0xda, 0x85, 0x61, 0xd8, + 0xc2, 0xb4, 0x40, 0xc3, 0xcf, 0x45, 0xe2, 0xf5, 0x2a, 0xef, 0x89, 0xce, 0x1b, 0x12, 0x8a, 0xcd, + 0x1b, 0x72, 0x64, 0xdf, 0x89, 0x44, 0x44, 0x42, 0xe5, 0xb1, 0xe8, 0x30, 0x8f, 0xa1, 0xd9, 0x30, + 0x8f, 0xc7, 0x30, 0x9c, 0x48, 0x44, 0x66, 0x53, 0x2e, 0x76, 0x62, 0x82, 0xe8, 0x28, 0x13, 0x1e, + 0xcb, 0xad, 0x92, 0x12, 0x1a, 0x4c, 0x79, 0x6f, 0xd4, 0xd1, 0x30, 0x41, 0x30, 0xdd, 0xa3, 0xa5, + 0x04, 0x14, 0xd3, 0xd2, 0xe3, 0x60, 0x28, 0x97, 0xa2, 0xc3, 0x36, 0x8d, 0x86, 0x0d, 0xdb, 0xd4, + 0x18, 0x1a, 0x33, 0x69, 0xde, 0xd0, 0xca, 0xe5, 0xa8, 0x61, 0x96, 0xa4, 0x60, 0x86, 0x59, 0x8a, + 0x17, 0xb5, 0x96, 0x1e, 0xd9, 0x41, 0x79, 0xbc, 0x6b, 0x0b, 0x91, 0x26, 0xa5, 0x85, 0x3c, 0xd0, + 0x41, 0x68, 0x3b, 0xdd, 0x6a, 0x35, 0x6c, 0xdd, 0x50, 0xde, 0x97, 0x6a, 0x3b, 0x71, 0xa4, 0x64, + 0x3b, 0x71, 0x00, 0x5b, 0xe5, 0x65, 0xa7, 0x5b, 0xe5, 0x89, 0xe8, 0x2a, 0x2f, 0xe3, 0xd8, 0x2a, + 0x1f, 0x71, 0xd0, 0x9d, 0x48, 0x38, 0xa8, 0x2a, 0x4f, 0x46, 0x15, 0x20, 0x86, 0x66, 0x0a, 0x10, + 0x77, 0x69, 0xfd, 0x78, 0x67, 0x97, 0x4e, 0xe5, 0x0a, 0x72, 0x7b, 0xd8, 0xe7, 0xd6, 0x89, 0x6e, + 0xba, 0x47, 0xeb, 0xec, 0x16, 0x5a, 0x49, 0xf1, 0xd0, 0x54, 0xae, 0x46, 0x15, 0x2c, 0x41, 0xc0, + 0x14, 0x2c, 0xe9, 0xd7, 0x59, 0x49, 0x71, 0xb1, 0x54, 0xde, 0xdf, 0x91, 0x55, 0xf0, 0xcd, 0x29, + 0x8e, 0x99, 0xd7, 0x65, 0x1f, 0x49, 0xe5, 0xa9, 0xe8, 0x62, 0x17, 0x62, 0xd8, 0x62, 0x27, 0xf9, + 0x52, 0x5e, 0x97, 0xbd, 0x03, 0x95, 0x6b, 0xc9, 0x52, 0xe1, 0x12, 0x29, 0x79, 0x11, 0x6a, 0xe9, + 0x4e, 0x75, 0xca, 0xd3, 0x51, 0xad, 0x4b, 0xa3, 0x61, 0x5a, 0x97, 0xea, 0x90, 0x37, 0x95, 0xf4, + 0x8d, 0x53, 0xae, 0xc7, 0xcf, 0x12, 0xa2, 0x78, 0x66, 0xf9, 0x24, 0xfc, 0xe9, 0x5e, 0x8d, 0x07, + 0x69, 0x52, 0x9e, 0x89, 0x5d, 0x66, 0x44, 0xb0, 0xcc, 0xbe, 0x8d, 0x05, 0x75, 0x7a, 0x35, 0x1e, + 0xd7, 0x48, 0x79, 0x36, 0x9d, 0x43, 0xa0, 0x2b, 0xf1, 0x38, 0x48, 0xaf, 0xc6, 0x43, 0x01, 0x29, + 0xcf, 0xa5, 0x73, 0x08, 0xa4, 0x1b, 0x0f, 0x1d, 0xf4, 0x94, 0x14, 0x9c, 0x58, 0xf9, 0x40, 0xd4, + 0x74, 0x0c, 0x10, 0xcc, 0x74, 0x0c, 0x43, 0x18, 0x3f, 0x25, 0x05, 0xf5, 0x55, 0x9e, 0x4f, 0x14, + 0x09, 0x1a, 0x2b, 0x85, 0xfe, 0x7d, 0x4a, 0x0a, 0x86, 0xab, 0xbc, 0x90, 0x28, 0x12, 0xb4, 0x4e, + 0x0a, 0x99, 0x6b, 0x74, 0x7b, 0x35, 0xa5, 0xbc, 0x18, 0x3d, 0xe2, 0xe8, 0x4c, 0x39, 0xdd, 0xa3, + 0x75, 0x7b, 0x7d, 0xf5, 0xf1, 0xce, 0x9e, 0x86, 0xca, 0x4b, 0xd1, 0x21, 0xdc, 0x89, 0x8e, 0x0d, + 0xe1, 0x8e, 0xde, 0x8a, 0x2f, 0xc7, 0x5e, 0x50, 0x2b, 0x2f, 0x47, 0xa7, 0xb8, 0x08, 0x92, 0x4d, + 0x71, 0xf1, 0xf7, 0xd6, 0x91, 0xa7, 0xc1, 0xca, 0x07, 0xa3, 0x53, 0x9c, 0x8c, 0x63, 0x53, 0x5c, + 0xe4, 0x19, 0xf1, 0x44, 0xe2, 0xc5, 0xaa, 0xf2, 0x4a, 0x74, 0x8a, 0x8b, 0xa1, 0xd9, 0x14, 0x17, + 0x7f, 0xe3, 0xfa, 0x72, 0xec, 0xe1, 0xa6, 0xf2, 0x6a, 0x7a, 0xfb, 0x11, 0x29, 0xb7, 0x9f, 0x3f, + 0xf3, 0xd4, 0xd2, 0x5f, 0x20, 0x2a, 0xa5, 0xe8, 0xf8, 0x4d, 0xa3, 0x61, 0xe3, 0x37, 0xf5, 0xf5, + 0x62, 0x7c, 0xe3, 0x20, 0xb4, 0x6a, 0xbc, 0xcb, 0xc6, 0x21, 0x34, 0x45, 0x52, 0xc0, 0x91, 0x3d, + 0x32, 0xdf, 0x08, 0x4d, 0x74, 0xd8, 0x23, 0xfb, 0xdb, 0xa0, 0x18, 0x3d, 0x9b, 0x5d, 0x13, 0x8e, + 0x6f, 0x4a, 0x39, 0x3a, 0xbb, 0x26, 0x08, 0xd8, 0xec, 0x9a, 0x74, 0x97, 0x9b, 0x82, 0x51, 0xa1, + 0x45, 0xdc, 0x9f, 0xcf, 0xb4, 0x56, 0x94, 0xc9, 0xd8, 0x03, 0xa0, 0x18, 0x9e, 0xcd, 0x4e, 0x71, + 0x18, 0xae, 0xd7, 0x1c, 0x36, 0xd1, 0x30, 0x5b, 0x4b, 0xb6, 0xee, 0x18, 0x55, 0x6a, 0x19, 0xca, + 0x54, 0x6c, 0xbd, 0x4e, 0xa1, 0xc1, 0xf5, 0x3a, 0x05, 0x8e, 0x81, 0x89, 0x62, 0x70, 0x8d, 0xd6, + 0xa9, 0x79, 0x8f, 0x2a, 0x37, 0x90, 0x6d, 0xb1, 0x13, 0x5b, 0x41, 0x36, 0xdd, 0xa3, 0x75, 0xe2, + 0xc0, 0x6c, 0xf5, 0xd9, 0xf5, 0xea, 0xeb, 0x33, 0xc1, 0xa3, 0xd7, 0x05, 0x87, 0xb6, 0x74, 0x87, + 0x2a, 0xd3, 0x51, 0x5b, 0x3d, 0x95, 0x88, 0xd9, 0xea, 0xa9, 0x88, 0x24, 0x5b, 0x7f, 0x2c, 0x54, + 0xba, 0xb1, 0x0d, 0x47, 0x44, 0x7a, 0x69, 0x36, 0x3b, 0x45, 0x11, 0x4c, 0x40, 0x33, 0xb6, 0xb5, + 0x82, 0x27, 0x15, 0xaf, 0x45, 0x67, 0xa7, 0xce, 0x94, 0x6c, 0x76, 0xea, 0x8c, 0x65, 0xaa, 0x1e, + 0xc5, 0xf2, 0x31, 0x78, 0x33, 0xaa, 0xea, 0x29, 0x24, 0x4c, 0xd5, 0x53, 0xc0, 0x49, 0x86, 0x1a, + 0x75, 0xa9, 0xa7, 0xcc, 0x74, 0x63, 0x88, 0x24, 0x49, 0x86, 0x08, 0x4e, 0x32, 0x9c, 0xa2, 0x5e, + 0x7d, 0x55, 0x99, 0xed, 0xc6, 0x10, 0x49, 0x92, 0x0c, 0x11, 0xcc, 0x36, 0x9b, 0x51, 0xf0, 0x78, + 0xbb, 0x71, 0xd7, 0xef, 0xb3, 0xb9, 0xe8, 0x66, 0xb3, 0x23, 0x21, 0xdb, 0x6c, 0x76, 0x44, 0x92, + 0x4f, 0x6d, 0xdb, 0x31, 0x53, 0x99, 0xc7, 0x0a, 0xaf, 0x84, 0x76, 0xc1, 0x76, 0x4a, 0x4d, 0xf7, + 0x68, 0xdb, 0x75, 0xfc, 0x7c, 0x5f, 0xe0, 0x0a, 0xa5, 0x2c, 0x60, 0x55, 0xc7, 0x82, 0xb3, 0x0a, + 0x0e, 0x9e, 0xee, 0xd1, 0x02, 0x67, 0xa9, 0xe7, 0x60, 0x10, 0x3f, 0xaa, 0x62, 0x99, 0x5e, 0x79, + 0x5c, 0x79, 0x3d, 0xba, 0x65, 0x92, 0x50, 0x6c, 0xcb, 0x24, 0xfd, 0x64, 0x93, 0x38, 0xfe, 0xe4, + 0x53, 0x4c, 0x79, 0x5c, 0xd1, 0xa2, 0x93, 0x78, 0x04, 0xc9, 0x26, 0xf1, 0x08, 0x20, 0xa8, 0xb7, + 0xec, 0xd8, 0xad, 0xf2, 0xb8, 0x52, 0x4d, 0xa9, 0x97, 0xa3, 0x82, 0x7a, 0xf9, 0xcf, 0xa0, 0xde, + 0xea, 0x6a, 0xdb, 0x2b, 0xb3, 0x6f, 0x5c, 0x4c, 0xa9, 0xd7, 0x47, 0x06, 0xf5, 0xfa, 0x00, 0x36, + 0x15, 0x22, 0x60, 0xc1, 0xb1, 0xd9, 0xa4, 0x7d, 0xd3, 0x6c, 0x34, 0x94, 0x5b, 0xd1, 0xa9, 0x30, + 0x8e, 0x67, 0x53, 0x61, 0x1c, 0xc6, 0x4c, 0x4f, 0xde, 0x2a, 0xba, 0xd4, 0x5e, 0x51, 0x6e, 0x47, + 0x4d, 0xcf, 0x10, 0xc3, 0x4c, 0xcf, 0xf0, 0x17, 0xee, 0x2e, 0xd8, 0x2f, 0x8d, 0x2e, 0x3b, 0xd4, + 0x5d, 0x55, 0xee, 0xc4, 0x76, 0x17, 0x12, 0x0e, 0x77, 0x17, 0xd2, 0x6f, 0xb2, 0x02, 0x0f, 0x45, + 0x16, 0x1a, 0xff, 0xee, 0xa9, 0x4a, 0x75, 0xa7, 0xbe, 0xaa, 0x7c, 0x08, 0x59, 0x3d, 0x9a, 0xba, + 0x54, 0x45, 0x49, 0xa7, 0x7b, 0xb4, 0x6e, 0x9c, 0x70, 0x5b, 0xfe, 0xfa, 0x0c, 0x8f, 0x20, 0xa8, + 0x2d, 0x4c, 0xf8, 0x9b, 0xd0, 0x37, 0x62, 0xdb, 0xf2, 0x24, 0x09, 0x6e, 0xcb, 0x93, 0x60, 0xd2, + 0x82, 0x0b, 0xb1, 0xad, 0xda, 0xac, 0xde, 0x60, 0xfb, 0x12, 0x6a, 0x2c, 0xe8, 0xf5, 0xbb, 0xd4, + 0x53, 0x3e, 0x8c, 0xbc, 0x2f, 0x76, 0xd8, 0xf0, 0xc5, 0xa8, 0xa7, 0x7b, 0xb4, 0x2d, 0xf8, 0x11, + 0x15, 0xf2, 0xd5, 0xa9, 0xc5, 0x05, 0xe5, 0x23, 0xd1, 0xf3, 0x4d, 0x06, 0x9b, 0xee, 0xd1, 0x10, + 0xc7, 0xac, 0xb4, 0x5b, 0xad, 0x15, 0x47, 0x37, 0x28, 0x37, 0xb4, 0xd0, 0x76, 0x13, 0x06, 0xe8, + 0x47, 0xa3, 0x56, 0x5a, 0x27, 0x3a, 0x66, 0xa5, 0x75, 0xc2, 0x31, 0x45, 0x8d, 0x04, 0xcb, 0x57, + 0x3e, 0x16, 0x55, 0xd4, 0x08, 0x92, 0x29, 0x6a, 0x34, 0xb4, 0xfe, 0x87, 0xe0, 0x54, 0xb0, 0x9f, + 0x17, 0xeb, 0x2f, 0xef, 0x34, 0xe5, 0xe3, 0xc8, 0xe7, 0x42, 0xe2, 0x32, 0x20, 0x42, 0x35, 0xdd, + 0xa3, 0x75, 0x28, 0xcf, 0x56, 0xdc, 0x44, 0x1e, 0x18, 0x61, 0x5e, 0x7c, 0x5b, 0x74, 0xc5, 0xed, + 0x40, 0xc6, 0x56, 0xdc, 0x0e, 0xa8, 0x54, 0xe6, 0x42, 0xa8, 0xfa, 0x16, 0xcc, 0x03, 0x99, 0x76, + 0xe2, 0x90, 0xca, 0x5c, 0x58, 0x6a, 0x4b, 0x5b, 0x30, 0x0f, 0xac, 0xb5, 0x4e, 0x1c, 0xc8, 0x25, + 0x28, 0x54, 0xab, 0xb3, 0x5a, 0xdb, 0x52, 0xea, 0x31, 0x1f, 0x30, 0x84, 0x4e, 0xf7, 0x68, 0x02, + 0xcf, 0xcc, 0xa0, 0xc9, 0x86, 0xee, 0x7a, 0x66, 0xdd, 0xc5, 0x11, 0xe3, 0x8f, 0x10, 0x23, 0x6a, + 0x06, 0xa5, 0xd1, 0x30, 0x33, 0x28, 0x0d, 0xce, 0xec, 0xc5, 0x09, 0xdd, 0x75, 0x75, 0xcb, 0x70, + 0xf4, 0x71, 0x5c, 0x26, 0x68, 0xec, 0x79, 0x40, 0x04, 0xcb, 0xec, 0xc5, 0x28, 0x04, 0x0f, 0xdf, + 0x7d, 0x88, 0x6f, 0xe6, 0x2c, 0xc7, 0x0e, 0xdf, 0x63, 0x78, 0x3c, 0x7c, 0x8f, 0xc1, 0xd0, 0xee, + 0xf4, 0x61, 0x1a, 0x5d, 0x31, 0x99, 0x88, 0x94, 0x95, 0x98, 0xdd, 0x19, 0x27, 0x40, 0xbb, 0x33, + 0x0e, 0x8c, 0x34, 0xc9, 0x5f, 0x6e, 0x57, 0x3b, 0x34, 0x29, 0x5c, 0x65, 0x13, 0x65, 0xd8, 0xfa, + 0x1d, 0x0e, 0x8e, 0xf2, 0xba, 0xa5, 0x37, 0xed, 0xf2, 0xb8, 0x2f, 0x75, 0x33, 0xba, 0x7e, 0x77, + 0x24, 0x64, 0xeb, 0x77, 0x47, 0x24, 0x9b, 0x5d, 0xfd, 0x8d, 0xd6, 0xaa, 0xee, 0x50, 0xa3, 0x6c, + 0x3a, 0x78, 0xb2, 0xb8, 0xce, 0xb7, 0x86, 0x6f, 0x46, 0x67, 0xd7, 0x2e, 0xa4, 0x6c, 0x76, 0xed, + 0x82, 0x66, 0x46, 0x5e, 0x3a, 0x5a, 0xa3, 0xba, 0xa1, 0xdc, 0x8d, 0x1a, 0x79, 0x9d, 0x29, 0x99, + 0x91, 0xd7, 0x19, 0xdb, 0xf9, 0x73, 0xee, 0x38, 0xa6, 0x47, 0x95, 0xc6, 0x76, 0x3e, 0x07, 0x49, + 0x3b, 0x7f, 0x0e, 0xa2, 0xd9, 0x86, 0x30, 0xde, 0x21, 0xcd, 0xe8, 0x86, 0x30, 0xd9, 0x0d, 0xf1, + 0x12, 0xcc, 0x62, 0x11, 0xaf, 0x44, 0x14, 0x2b, 0x6a, 0xb1, 0x08, 0x30, 0xb3, 0x58, 0xc2, 0x77, + 0x24, 0x91, 0x07, 0x06, 0x8a, 0x1d, 0x5d, 0x43, 0x65, 0x1c, 0x5b, 0x43, 0x23, 0x8f, 0x11, 0x9e, + 0x8b, 0x78, 0xcf, 0x2a, 0xad, 0xa8, 0xd5, 0x21, 0xa1, 0x98, 0xd5, 0x21, 0xfb, 0xd9, 0x4e, 0xc0, + 0x31, 0xbc, 0x05, 0xd7, 0xda, 0xc1, 0x3d, 0xce, 0x27, 0xa2, 0x9f, 0x19, 0x43, 0xb3, 0xcf, 0x8c, + 0x81, 0x22, 0x4c, 0xc4, 0xb4, 0xe5, 0x74, 0x60, 0x12, 0x9e, 0x0f, 0xc6, 0x40, 0x64, 0x06, 0x48, + 0xb5, 0x34, 0x3b, 0x53, 0x31, 0x16, 0xe4, 0x2b, 0x32, 0x37, 0x7a, 0x02, 0x9b, 0xa4, 0x98, 0xee, + 0xd1, 0x52, 0xca, 0x91, 0x37, 0xe1, 0x9c, 0x80, 0x8a, 0x27, 0x80, 0x98, 0x2e, 0xda, 0x08, 0x16, + 0x04, 0x2f, 0xea, 0x9d, 0xd1, 0x8d, 0x76, 0xba, 0x47, 0xeb, 0xca, 0xab, 0x73, 0x5d, 0x62, 0x7d, + 0x68, 0x6f, 0xa7, 0xae, 0x60, 0x91, 0xe8, 0xca, 0xab, 0x73, 0x5d, 0x42, 0xee, 0xf7, 0xb6, 0x53, + 0x57, 0xd0, 0x09, 0x5d, 0x79, 0x11, 0x17, 0x8a, 0xdd, 0xf0, 0xa5, 0x46, 0x43, 0x59, 0xc3, 0xea, + 0xde, 0xbb, 0x9d, 0xea, 0x4a, 0x68, 0x70, 0x6e, 0xc5, 0x91, 0xcd, 0xd2, 0xf3, 0x2d, 0x6a, 0x55, + 0x23, 0x0b, 0xd0, 0xfd, 0xe8, 0x2c, 0x9d, 0x20, 0x60, 0xb3, 0x74, 0x02, 0xc8, 0x06, 0x94, 0xec, + 0x84, 0xad, 0xac, 0x47, 0x07, 0x94, 0x8c, 0x63, 0x03, 0x2a, 0xe2, 0xb0, 0x3d, 0x0f, 0xc7, 0xe7, + 0xef, 0x7a, 0xba, 0x6f, 0x41, 0xba, 0xa2, 0x2b, 0xdf, 0x8a, 0x5d, 0x32, 0x25, 0x49, 0xf0, 0x92, + 0x29, 0x09, 0x66, 0x63, 0x84, 0x81, 0xab, 0xeb, 0x56, 0x7d, 0x4a, 0x37, 0x1b, 0x6d, 0x87, 0x2a, + 0xff, 0x53, 0x74, 0x8c, 0xc4, 0xd0, 0x6c, 0x8c, 0xc4, 0x40, 0x6c, 0x81, 0x66, 0xa0, 0x92, 0xeb, + 0x9a, 0x2b, 0x96, 0xd8, 0x57, 0xb6, 0x1b, 0x9e, 0xf2, 0x3f, 0x47, 0x17, 0xe8, 0x34, 0x1a, 0xb6, + 0x40, 0xa7, 0xc1, 0xf1, 0xd4, 0x29, 0x25, 0x95, 0xba, 0xf2, 0xbf, 0xc4, 0x4e, 0x9d, 0x52, 0x68, + 0xf0, 0xd4, 0x29, 0x2d, 0x0d, 0xfb, 0x14, 0x8c, 0x72, 0x9b, 0x6c, 0xc6, 0x0c, 0xee, 0xaa, 0xff, + 0xd7, 0xe8, 0xfa, 0x18, 0xc7, 0xb3, 0xf5, 0x31, 0x0e, 0x8b, 0xf2, 0x11, 0x5d, 0xf0, 0xbf, 0x75, + 0xe2, 0x13, 0xc8, 0x3f, 0x51, 0x86, 0xdc, 0x90, 0xf9, 0x88, 0x91, 0xf2, 0xed, 0x99, 0x4e, 0x8c, + 0x82, 0xe1, 0x91, 0x28, 0x14, 0x65, 0xa4, 0xd1, 0x7b, 0x26, 0x5d, 0x53, 0x3e, 0xd9, 0x91, 0x11, + 0x27, 0x88, 0x32, 0xe2, 0x30, 0xf2, 0x06, 0x9c, 0x0a, 0x61, 0xb3, 0xb4, 0xb9, 0x14, 0xcc, 0x4c, + 0xdf, 0x91, 0x89, 0x9a, 0xc1, 0xe9, 0x64, 0xcc, 0x0c, 0x4e, 0xc7, 0xa4, 0xb1, 0x16, 0xa2, 0xfb, + 0xdf, 0xb7, 0x60, 0x1d, 0x48, 0xb0, 0x03, 0x83, 0x34, 0xd6, 0x42, 0x9a, 0xdf, 0xb9, 0x05, 0xeb, + 0x40, 0xa6, 0x1d, 0x18, 0x90, 0x4f, 0x67, 0xe0, 0x62, 0x3a, 0xaa, 0xd4, 0x68, 0x4c, 0xd9, 0x4e, + 0x88, 0x53, 0xbe, 0x2b, 0x13, 0x3d, 0x68, 0xd8, 0x5e, 0xb1, 0xe9, 0x1e, 0x6d, 0x9b, 0x15, 0x90, + 0x0f, 0xc2, 0x70, 0xa9, 0x6d, 0x98, 0x1e, 0x5e, 0xbc, 0x31, 0xc3, 0xf9, 0xbb, 0x33, 0xb1, 0x2d, + 0x8e, 0x8c, 0xc5, 0x2d, 0x8e, 0x0c, 0x20, 0xaf, 0xc1, 0x58, 0x95, 0xd6, 0xdb, 0x8e, 0xe9, 0xad, + 0x6b, 0x98, 0x26, 0x9f, 0xf1, 0xf8, 0x9e, 0x4c, 0x74, 0x12, 0x4b, 0x50, 0xb0, 0x49, 0x2c, 0x01, + 0x24, 0xb7, 0x3b, 0x24, 0x53, 0x57, 0x3e, 0x95, 0xe9, 0x7a, 0x2d, 0x1f, 0xf4, 0x65, 0x87, 0x5c, + 0xec, 0x0b, 0xa9, 0xc9, 0xa9, 0x95, 0x4f, 0x67, 0xba, 0x5c, 0xa3, 0x4b, 0x33, 0x5c, 0x4a, 0x5e, + 0xeb, 0x85, 0xd4, 0xcc, 0xc1, 0xca, 0xf7, 0x66, 0xba, 0x5c, 0x7b, 0x87, 0x1c, 0xd3, 0x92, 0x0e, + 0x3f, 0xc3, 0x3d, 0x45, 0x04, 0xa3, 0xff, 0x23, 0x93, 0x74, 0x15, 0x09, 0xca, 0x4b, 0x84, 0xac, + 0xd8, 0x2d, 0x37, 0x50, 0xfa, 0xcf, 0x64, 0x92, 0xbe, 0x79, 0x61, 0xb1, 0xf0, 0x17, 0xa1, 0x70, + 0x76, 0xf2, 0xbe, 0x47, 0x1d, 0x4b, 0x6f, 0x60, 0x77, 0x56, 0x3d, 0xdb, 0xd1, 0x57, 0xe8, 0xa4, + 0xa5, 0x2f, 0x35, 0xa8, 0xf2, 0xd9, 0x4c, 0xd4, 0x82, 0xed, 0x4c, 0xca, 0x2c, 0xd8, 0xce, 0x58, + 0xb2, 0x0a, 0x0f, 0xa5, 0x61, 0xcb, 0xa6, 0x8b, 0xf5, 0x7c, 0x2e, 0x13, 0x35, 0x61, 0xbb, 0xd0, + 0x32, 0x13, 0xb6, 0x0b, 0x9a, 0x5c, 0x83, 0x81, 0x71, 0xdb, 0x9f, 0x7e, 0xbf, 0x2f, 0xe6, 0x0c, + 0x19, 0x60, 0xa6, 0x7b, 0xb4, 0x90, 0x4c, 0x94, 0x11, 0x83, 0xfa, 0xf3, 0xc9, 0x32, 0xe1, 0xe5, + 0x53, 0xf0, 0x43, 0x94, 0x11, 0xe2, 0xfe, 0x3f, 0x93, 0x65, 0xc2, 0x3b, 0xae, 0xe0, 0x07, 0x9b, + 0x49, 0x78, 0x8d, 0xb3, 0x53, 0x25, 0x66, 0xb7, 0x4d, 0xac, 0xea, 0x8d, 0x06, 0xb5, 0x56, 0xa8, + 0xf2, 0x85, 0xd8, 0x4c, 0x92, 0x4e, 0xc6, 0x66, 0x92, 0x74, 0x0c, 0xf9, 0x28, 0x9c, 0xbe, 0xad, + 0x37, 0x4c, 0x23, 0xc4, 0xf9, 0x79, 0x64, 0x95, 0xef, 0xcf, 0x44, 0x77, 0xd3, 0x1d, 0xe8, 0xd8, + 0x6e, 0xba, 0x03, 0x8a, 0xcc, 0x02, 0xc1, 0x65, 0x34, 0x98, 0x2d, 0xd8, 0xfa, 0xac, 0xfc, 0x5f, + 0x99, 0xa8, 0x9d, 0x9a, 0x24, 0x61, 0x76, 0x6a, 0x12, 0x4a, 0x6a, 0x9d, 0x03, 0xd2, 0x2b, 0x3f, + 0x90, 0x89, 0x9e, 0xd6, 0x74, 0x22, 0x9c, 0xee, 0xd1, 0x3a, 0x47, 0xb5, 0xbf, 0x01, 0xa3, 0xd5, + 0x85, 0xca, 0xd4, 0xd4, 0x64, 0xf5, 0x76, 0xa5, 0x8c, 0xee, 0xbb, 0x86, 0xf2, 0x83, 0xb1, 0x15, + 0x2b, 0x4e, 0xc0, 0x56, 0xac, 0x38, 0x8c, 0xbc, 0x08, 0x43, 0xac, 0xfd, 0x6c, 0xc0, 0xe0, 0x27, + 0x7f, 0x31, 0x13, 0x35, 0xa7, 0x64, 0x24, 0x33, 0xa7, 0xe4, 0xdf, 0xa4, 0x0a, 0x27, 0x98, 0x14, + 0x17, 0x1c, 0xba, 0x4c, 0x1d, 0x6a, 0xd5, 0xfd, 0x31, 0xfd, 0x43, 0x99, 0xa8, 0x95, 0x91, 0x46, + 0xc4, 0xac, 0x8c, 0x34, 0x38, 0xb9, 0x0b, 0xe7, 0xe2, 0x27, 0x41, 0xf2, 0x63, 0x2a, 0xe5, 0x87, + 0x33, 0x31, 0x63, 0xb8, 0x0b, 0x31, 0x1a, 0xc3, 0x5d, 0xf0, 0xc4, 0x82, 0xf3, 0xe2, 0x58, 0x45, + 0x38, 0x5c, 0xc6, 0x6b, 0xfb, 0x11, 0x5e, 0xdb, 0x63, 0xa1, 0x43, 0x60, 0x17, 0xea, 0xe9, 0x1e, + 0xad, 0x3b, 0x3b, 0xa6, 0x67, 0xc9, 0xb0, 0xeb, 0xca, 0x8f, 0x66, 0xd2, 0x3d, 0x52, 0x22, 0x6e, + 0xca, 0x69, 0xf1, 0xda, 0xdf, 0xe8, 0x14, 0x34, 0x5c, 0xf9, 0xb1, 0xd8, 0x78, 0x4b, 0x27, 0x63, + 0xe3, 0xad, 0x43, 0xd4, 0xf1, 0xd7, 0x60, 0x8c, 0x2b, 0xf5, 0x82, 0x8e, 0xc3, 0xd0, 0x5a, 0xa1, + 0x86, 0xf2, 0x7f, 0xc7, 0x56, 0xbb, 0x04, 0x05, 0xba, 0xf6, 0xc4, 0x81, 0x6c, 0xea, 0xae, 0xb6, + 0x74, 0xcb, 0xc2, 0x63, 0x56, 0xe5, 0xff, 0x89, 0x4d, 0xdd, 0x21, 0x0a, 0x1d, 0x77, 0x83, 0x5f, + 0x4c, 0x13, 0xba, 0x25, 0xdc, 0x50, 0x7e, 0x3c, 0xa6, 0x09, 0xdd, 0x88, 0x99, 0x26, 0x74, 0xcd, + 0xde, 0x71, 0xbb, 0xc3, 0xc3, 0x46, 0xe5, 0x4b, 0xb1, 0x15, 0x39, 0x95, 0x8a, 0xad, 0xc8, 0xe9, + 0xef, 0x22, 0x6f, 0x77, 0x78, 0x14, 0xa8, 0xfc, 0x44, 0x77, 0xbe, 0xe1, 0x4a, 0x9f, 0xfe, 0xa6, + 0xf0, 0x76, 0x87, 0x07, 0x75, 0xca, 0x4f, 0x76, 0xe7, 0x1b, 0x3a, 0xf6, 0xa5, 0xbf, 0xc7, 0xab, + 0x75, 0x7e, 0x8c, 0xa6, 0xfc, 0x54, 0x7c, 0xea, 0xea, 0x40, 0x88, 0x53, 0x57, 0xa7, 0x17, 0x6d, + 0x4b, 0x70, 0x86, 0x6b, 0xc8, 0x0d, 0x47, 0x6f, 0xad, 0x56, 0xa9, 0xe7, 0x99, 0xd6, 0x8a, 0xbf, + 0x13, 0xfb, 0x7f, 0x33, 0xb1, 0xe3, 0xb1, 0x4e, 0x94, 0x78, 0x3c, 0xd6, 0x09, 0xc9, 0x94, 0x37, + 0xf1, 0xec, 0x4c, 0xf9, 0xe9, 0x98, 0xf2, 0x26, 0x28, 0x98, 0xf2, 0x26, 0x5f, 0xab, 0xbd, 0x96, + 0xf2, 0xba, 0x4a, 0xf9, 0xff, 0x3a, 0xf3, 0x0a, 0xda, 0x97, 0xf2, 0x28, 0xeb, 0xb5, 0x94, 0x47, + 0x44, 0xca, 0xff, 0xdf, 0x99, 0x57, 0xe8, 0x83, 0x94, 0x7c, 0x7b, 0xf4, 0x06, 0x9c, 0xe2, 0xb3, + 0xf9, 0x14, 0x35, 0x68, 0xe4, 0x43, 0x7f, 0x26, 0x36, 0xf6, 0xd3, 0xc9, 0xf0, 0xc8, 0x3d, 0x15, + 0x93, 0xc6, 0x5a, 0xb4, 0xf5, 0x67, 0xb7, 0x60, 0x1d, 0x6e, 0x08, 0xd2, 0x31, 0xe3, 0x7d, 0xd0, + 0x8b, 0x7b, 0x71, 0xf5, 0x4b, 0x19, 0x18, 0xaa, 0x7a, 0x0e, 0xd5, 0x9b, 0x22, 0x0e, 0xc6, 0x59, + 0xe8, 0xe7, 0x4e, 0x6d, 0xfe, 0xbb, 0x12, 0x2d, 0xf8, 0x4d, 0x2e, 0xc2, 0xc8, 0x8c, 0xee, 0x7a, + 0x58, 0xb2, 0x62, 0x19, 0xf4, 0x3e, 0x3e, 0xe8, 0xc8, 0x69, 0x31, 0x28, 0x99, 0xe1, 0x74, 0xbc, + 0x1c, 0x46, 0x2d, 0xca, 0x6d, 0x19, 0xfe, 0xa1, 0xff, 0xed, 0x8d, 0x62, 0x0f, 0x46, 0x7b, 0x88, + 0x95, 0x55, 0xbf, 0x96, 0x81, 0x84, 0xbb, 0xdd, 0xee, 0xdf, 0x7b, 0xcd, 0xc3, 0xb1, 0x58, 0xa4, + 0x2c, 0xf1, 0x2a, 0x65, 0x9b, 0x81, 0xb4, 0xe2, 0xa5, 0xc9, 0x7b, 0x83, 0xd7, 0x10, 0xb7, 0xb4, + 0x19, 0x11, 0xda, 0xa3, 0x6f, 0x73, 0xa3, 0x98, 0x6b, 0x3b, 0x0d, 0x4d, 0x42, 0x89, 0xa7, 0xdb, + 0xbf, 0x3c, 0x1a, 0x86, 0x01, 0x22, 0x17, 0xc5, 0xe3, 0xb3, 0x4c, 0x18, 0x10, 0x24, 0x96, 0x64, + 0x92, 0x3f, 0x36, 0xfb, 0x20, 0x0c, 0x55, 0x9a, 0x2d, 0xea, 0xb8, 0xb6, 0xa5, 0x7b, 0xb6, 0x9f, + 0xcc, 0x1e, 0x83, 0x45, 0x98, 0x12, 0x5c, 0x0e, 0x60, 0x20, 0xd3, 0x93, 0xcb, 0x7e, 0xde, 0x8b, + 0x1c, 0x06, 0x60, 0xc2, 0x28, 0xa2, 0xf1, 0xc4, 0x85, 0x9c, 0x82, 0x91, 0xde, 0x72, 0x75, 0x7c, + 0x37, 0x13, 0x90, 0xb6, 0x19, 0x40, 0x26, 0x45, 0x0a, 0xf2, 0x04, 0x14, 0xf0, 0x9c, 0xd1, 0xc5, + 0x7c, 0x36, 0x22, 0x4c, 0x49, 0x03, 0x21, 0x72, 0x50, 0x08, 0x4e, 0x43, 0x6e, 0xc2, 0x68, 0x78, + 0x89, 0x72, 0xc3, 0xb1, 0xdb, 0x2d, 0x3f, 0x82, 0x35, 0x26, 0x7c, 0xbc, 0x1b, 0xe0, 0x6a, 0x2b, + 0x88, 0x94, 0x58, 0x24, 0x0a, 0x92, 0x69, 0x38, 0x16, 0xc2, 0x98, 0x88, 0xfc, 0xc8, 0xf9, 0x98, + 0xb5, 0x48, 0xe2, 0xc5, 0xc4, 0x19, 0xc9, 0x5a, 0x14, 0x2b, 0x46, 0x2a, 0xd0, 0xe7, 0xc7, 0x28, + 0xe9, 0xdf, 0x52, 0x49, 0x8f, 0x8b, 0x18, 0x25, 0x7d, 0x72, 0x74, 0x12, 0xbf, 0x3c, 0x99, 0x82, + 0x11, 0xcd, 0x6e, 0x7b, 0x74, 0xd1, 0x16, 0xd6, 0x87, 0x08, 0xad, 0x8c, 0x6d, 0x72, 0x18, 0xa6, + 0xe6, 0xd9, 0x7e, 0xbe, 0x4c, 0x39, 0x6f, 0x63, 0xb4, 0x14, 0x99, 0x83, 0xb1, 0xc4, 0x75, 0x93, + 0x9c, 0xc5, 0x52, 0xfa, 0xbc, 0x24, 0xb3, 0x64, 0x51, 0xf2, 0xdd, 0x19, 0x28, 0x2c, 0x3a, 0xba, + 0xe9, 0xb9, 0xe2, 0xc9, 0xcd, 0xc9, 0x2b, 0x6b, 0x8e, 0xde, 0x62, 0xfa, 0x71, 0x05, 0x23, 0x6c, + 0xdd, 0xd6, 0x1b, 0x6d, 0xea, 0x8e, 0xdf, 0x61, 0x5f, 0xf7, 0x87, 0x1b, 0xc5, 0x17, 0x57, 0x70, + 0x53, 0x7b, 0xa5, 0x6e, 0x37, 0xaf, 0xae, 0x38, 0xfa, 0x3d, 0xd3, 0xc3, 0xa9, 0x43, 0x6f, 0x5c, + 0xf5, 0x68, 0x03, 0xf7, 0xce, 0x57, 0xf5, 0x96, 0x79, 0x15, 0x23, 0x39, 0x5e, 0x0d, 0x38, 0xf1, + 0x1a, 0x98, 0x0a, 0x78, 0xf8, 0x97, 0xac, 0x02, 0x1c, 0x47, 0xe6, 0xd8, 0x96, 0x13, 0x3f, 0xb5, + 0xd4, 0x6a, 0x89, 0xf7, 0x3b, 0xd2, 0x8e, 0xd3, 0xc7, 0x70, 0xc5, 0x0e, 0x04, 0xa6, 0xb7, 0x5a, + 0x72, 0x9e, 0xdc, 0x90, 0x8e, 0x69, 0xc1, 0xa2, 0x68, 0x91, 0x2f, 0xa6, 0xe1, 0x50, 0xe2, 0x7e, + 0x63, 0x53, 0x84, 0x14, 0x2f, 0x46, 0x96, 0xe0, 0x98, 0xe0, 0x1b, 0xc4, 0x3a, 0x1e, 0x89, 0xce, + 0x0a, 0x31, 0x34, 0x57, 0xda, 0xa0, 0x8d, 0x86, 0x00, 0xcb, 0x75, 0xc4, 0x4a, 0x90, 0xf1, 0x30, + 0x01, 0xdb, 0x9c, 0xde, 0xa4, 0xae, 0x72, 0x0c, 0x35, 0xf6, 0xdc, 0xe6, 0x46, 0x51, 0xf1, 0xcb, + 0x63, 0xb8, 0x9e, 0xd4, 0x74, 0xa2, 0x58, 0x44, 0xe6, 0xc1, 0xb5, 0x7e, 0x34, 0x85, 0x47, 0x5c, + 0xe7, 0xa3, 0x45, 0xc8, 0x04, 0x0c, 0x07, 0xee, 0xc3, 0xb7, 0x6e, 0x55, 0xca, 0xf8, 0x40, 0x68, + 0x60, 0xfc, 0xfc, 0xe6, 0x46, 0xf1, 0x4c, 0x2c, 0x1a, 0xb1, 0xcc, 0x24, 0x52, 0x46, 0x7a, 0x49, + 0xc8, 0x5f, 0x0c, 0xc5, 0x5e, 0x12, 0xb6, 0x52, 0x5e, 0x12, 0x2e, 0x90, 0x97, 0x61, 0xb0, 0x74, + 0xa7, 0x2a, 0x5e, 0x48, 0xba, 0xca, 0xf1, 0x30, 0x7e, 0x3d, 0x66, 0x94, 0x15, 0xaf, 0x29, 0xe5, + 0xa6, 0xcb, 0xf4, 0x64, 0x12, 0x46, 0x22, 0x1e, 0x08, 0xae, 0x72, 0x02, 0x39, 0x60, 0xcb, 0x75, + 0xc4, 0xd4, 0x1c, 0x81, 0x8a, 0xe4, 0x38, 0x8e, 0x14, 0x62, 0x5a, 0xc3, 0x36, 0xf1, 0x8d, 0x86, + 0xbd, 0xa6, 0x51, 0x7c, 0x8c, 0x89, 0xcf, 0x8d, 0xfa, 0xb9, 0xd6, 0x18, 0x02, 0x55, 0x73, 0x38, + 0x2e, 0x92, 0xd4, 0x38, 0x5a, 0x8c, 0xbc, 0x09, 0x04, 0xa3, 0x87, 0x53, 0xc3, 0x3f, 0x90, 0xae, + 0x94, 0x5d, 0xe5, 0x14, 0x46, 0x1a, 0x24, 0xf1, 0xd7, 0xc0, 0x95, 0xf2, 0xf8, 0x45, 0x31, 0x7d, + 0x5c, 0xd0, 0x79, 0xa9, 0x9a, 0x23, 0x70, 0x35, 0x33, 0x92, 0x5a, 0x2d, 0x85, 0x2b, 0x59, 0x83, + 0xd3, 0x0b, 0x0e, 0xbd, 0x67, 0xda, 0x6d, 0xd7, 0x5f, 0x3e, 0xfc, 0x79, 0xeb, 0xf4, 0x96, 0xf3, + 0xd6, 0x23, 0xa2, 0xe2, 0x93, 0x2d, 0x87, 0xde, 0xab, 0xf9, 0xf1, 0xe5, 0x22, 0x31, 0x96, 0x3a, + 0x71, 0xc7, 0x04, 0x71, 0x6f, 0xb5, 0x1d, 0x2a, 0xe0, 0x26, 0x75, 0x15, 0x25, 0x9c, 0x6a, 0xf9, + 0xbb, 0x5a, 0x33, 0xc0, 0x45, 0x12, 0xc4, 0x45, 0x8b, 0x11, 0x0d, 0xc8, 0x8d, 0x09, 0xff, 0x72, + 0xa2, 0x54, 0xe7, 0x69, 0xb4, 0x94, 0x33, 0xc8, 0x4c, 0x65, 0x62, 0x59, 0xa9, 0x07, 0xb1, 0x26, + 0x6b, 0xba, 0xc0, 0xcb, 0x62, 0x49, 0x96, 0x26, 0x33, 0x30, 0xba, 0xe0, 0xe0, 0x56, 0xe9, 0x26, + 0x5d, 0x5f, 0xb0, 0x1b, 0x66, 0x7d, 0x1d, 0x5f, 0x3d, 0x89, 0xa9, 0xb2, 0xc5, 0x71, 0xb5, 0xbb, + 0x74, 0xbd, 0xd6, 0x42, 0xac, 0xbc, 0xac, 0xc4, 0x4b, 0xca, 0xb1, 0xdf, 0x1e, 0xda, 0x5e, 0xec, + 0x37, 0x0a, 0xa3, 0xe2, 0x6a, 0xe3, 0xbe, 0x47, 0x2d, 0xb6, 0xd4, 0xbb, 0xe2, 0x85, 0x93, 0x12, + 0xbb, 0x0a, 0x09, 0xf0, 0x22, 0xc1, 0x31, 0x1f, 0x65, 0x34, 0x00, 0xcb, 0x0d, 0x8b, 0x17, 0x51, + 0x7f, 0x39, 0x27, 0x4f, 0x9d, 0xe4, 0x1c, 0xe4, 0xa5, 0xd0, 0xe3, 0x18, 0xfd, 0x09, 0xc3, 0x34, + 0xe6, 0x45, 0x3c, 0xba, 0x01, 0x61, 0x76, 0x04, 0xcf, 0x7c, 0x31, 0xa1, 0x4c, 0x18, 0x11, 0x48, + 0x0b, 0x09, 0x30, 0x99, 0x47, 0x7b, 0xa9, 0x61, 0xd6, 0x31, 0x78, 0x67, 0x4e, 0x4a, 0xe6, 0x81, + 0x50, 0x1e, 0xbb, 0x53, 0x22, 0x21, 0xd7, 0x60, 0xd0, 0xdf, 0x5d, 0x87, 0xd1, 0xcf, 0x30, 0xa6, + 0xa3, 0x9f, 0x0a, 0x9a, 0x87, 0x8c, 0x94, 0x88, 0xc8, 0x0b, 0x98, 0x0c, 0xdd, 0x7f, 0x42, 0xdd, + 0x1b, 0x9a, 0x2f, 0xf2, 0xc0, 0x8f, 0x65, 0x43, 0xf7, 0x5f, 0x52, 0x8f, 0xc3, 0xb0, 0xac, 0x49, + 0x7e, 0xfa, 0x22, 0x9c, 0xf3, 0x22, 0xea, 0x27, 0xf7, 0x6d, 0xb4, 0x08, 0x99, 0x87, 0xb1, 0x84, + 0xf2, 0x88, 0x58, 0x69, 0x98, 0xc2, 0x32, 0x45, 0xf3, 0xe4, 0x35, 0x35, 0x51, 0x96, 0x3c, 0x0a, + 0xb9, 0x5b, 0x5a, 0x45, 0xc4, 0x6b, 0xe2, 0xa1, 0xbe, 0x22, 0x8f, 0xb9, 0x19, 0x56, 0xfd, 0x8e, + 0x6c, 0x62, 0x59, 0x61, 0xd2, 0x13, 0xac, 0xa4, 0x1e, 0x44, 0xe9, 0xf9, 0xf5, 0x73, 0xe9, 0x49, + 0x44, 0xe4, 0x12, 0xf4, 0xc7, 0x92, 0xa6, 0xe3, 0xcb, 0xfb, 0x20, 0x63, 0x7a, 0x80, 0x25, 0xd7, + 0xa4, 0xac, 0x5b, 0x52, 0xf4, 0x42, 0x3f, 0xeb, 0x56, 0x3c, 0x8c, 0x1f, 0xe6, 0xdf, 0xba, 0x16, + 0x0b, 0xf0, 0xef, 0xe7, 0xb6, 0x4e, 0x2e, 0x69, 0x61, 0x40, 0xff, 0xc0, 0xa0, 0xec, 0xdd, 0xca, + 0xa0, 0x54, 0x7f, 0x23, 0x93, 0x1c, 0x22, 0xe4, 0x7a, 0x32, 0x1a, 0x19, 0x4f, 0x6b, 0xed, 0x03, + 0xe5, 0x5a, 0x83, 0xb8, 0x64, 0x91, 0xb8, 0x62, 0xd9, 0x5d, 0xc7, 0x15, 0xcb, 0xed, 0x30, 0xae, + 0x98, 0xfa, 0x5f, 0xf3, 0x5d, 0xbd, 0xe8, 0x0e, 0x24, 0xfe, 0xc4, 0xf3, 0x6c, 0x53, 0xc4, 0x6a, + 0x2f, 0xb9, 0x09, 0xd3, 0x9e, 0x3b, 0x09, 0xd5, 0x74, 0x3e, 0xb4, 0x5c, 0x2d, 0x4a, 0x49, 0x5e, + 0x81, 0x21, 0xff, 0x03, 0x30, 0x5e, 0x9d, 0x14, 0x67, 0x2d, 0x58, 0x90, 0xe2, 0x99, 0xc9, 0xe5, + 0x02, 0xe4, 0x19, 0x18, 0x40, 0x73, 0xa4, 0xa5, 0xd7, 0xfd, 0x60, 0x86, 0x3c, 0xfa, 0xa1, 0x0f, + 0x94, 0x63, 0x2c, 0x04, 0x94, 0xe4, 0x63, 0x50, 0x88, 0xa4, 0xc6, 0xbf, 0xba, 0x0d, 0xb7, 0xc3, + 0x2b, 0x72, 0x20, 0x5e, 0xbe, 0xc1, 0x88, 0xa7, 0xc5, 0x17, 0x4c, 0xc9, 0x22, 0x1c, 0x5f, 0x70, + 0xa8, 0x81, 0x0e, 0xae, 0x93, 0xf7, 0x5b, 0x8e, 0x08, 0x93, 0xcc, 0x47, 0x39, 0xae, 0x2f, 0x2d, + 0x1f, 0xcd, 0x56, 0x3e, 0x81, 0x97, 0x23, 0xaa, 0xa5, 0x14, 0x67, 0x46, 0x07, 0x6f, 0xc9, 0x4d, + 0xba, 0xbe, 0x86, 0xe9, 0x51, 0xfb, 0x43, 0xa3, 0x43, 0x08, 0xfa, 0xae, 0x40, 0xc9, 0x46, 0x47, + 0xb4, 0xd0, 0xd9, 0xe7, 0x61, 0x70, 0xb7, 0xc1, 0x6c, 0x7f, 0x29, 0xdb, 0xc1, 0x1f, 0xfd, 0xc1, + 0xcd, 0x27, 0x12, 0x64, 0xb2, 0xeb, 0xed, 0x90, 0xc9, 0xee, 0x9b, 0xd9, 0x0e, 0xce, 0xf6, 0x0f, + 0x74, 0xc6, 0xa9, 0x40, 0x18, 0xd1, 0x8c, 0x53, 0x61, 0xb2, 0x2f, 0xd3, 0xd0, 0x64, 0xa2, 0x58, + 0x6e, 0xba, 0xc2, 0x96, 0xb9, 0xe9, 0x7e, 0x26, 0xd7, 0xed, 0x31, 0xc2, 0x91, 0xec, 0x77, 0x22, + 0xfb, 0x6b, 0x30, 0x18, 0x48, 0xb6, 0x52, 0x46, 0xa3, 0x67, 0x38, 0x08, 0x9d, 0xcd, 0xc1, 0x58, + 0x46, 0x22, 0x22, 0x97, 0x79, 0x5b, 0xab, 0xe6, 0x5b, 0x3c, 0x12, 0xec, 0xb0, 0x88, 0xf1, 0xa9, + 0x7b, 0x7a, 0xcd, 0x35, 0xdf, 0xa2, 0x5a, 0x80, 0x56, 0xff, 0x6e, 0x36, 0xf5, 0x45, 0xc7, 0x51, + 0x1f, 0xed, 0xa0, 0x8f, 0x52, 0x84, 0xc8, 0xdf, 0xa2, 0x1c, 0x09, 0x71, 0x07, 0x42, 0xfc, 0xd3, + 0x6c, 0xea, 0xcb, 0x9d, 0x23, 0x21, 0xee, 0x64, 0xb6, 0x78, 0x02, 0x06, 0x34, 0x7b, 0xcd, 0xc5, + 0x44, 0xd4, 0x62, 0xae, 0xc0, 0x89, 0xda, 0xb1, 0xd7, 0x5c, 0x9e, 0xa4, 0x5b, 0x0b, 0x09, 0xd4, + 0x3f, 0xcf, 0x76, 0x79, 0xdb, 0x74, 0x24, 0xf8, 0x77, 0x72, 0x89, 0xfc, 0xd5, 0x6c, 0xe4, 0xed, + 0xd4, 0x03, 0x9d, 0xba, 0xb5, 0x5a, 0x5f, 0xa5, 0x4d, 0x3d, 0x9e, 0xba, 0xd5, 0x45, 0xa8, 0x48, + 0xa0, 0x16, 0x92, 0xa8, 0x5f, 0xce, 0xc6, 0x1e, 0x8f, 0x1d, 0xc9, 0x6e, 0xdb, 0xb2, 0x0b, 0xb4, + 0x4e, 0xbc, 0x87, 0x3b, 0x92, 0xdc, 0x76, 0x25, 0xf7, 0xa9, 0x6c, 0xec, 0xe9, 0xe0, 0x03, 0x2b, + 0x3b, 0x36, 0x00, 0x93, 0x4f, 0x1a, 0x1f, 0x58, 0x4d, 0x7a, 0x02, 0x06, 0x84, 0x1c, 0x82, 0xa5, + 0x82, 0xcf, 0xfb, 0x1c, 0x88, 0xa7, 0xac, 0x01, 0x81, 0xfa, 0x5d, 0x59, 0x88, 0x3e, 0xe9, 0x7c, + 0x40, 0x75, 0xe8, 0x57, 0xb3, 0xd1, 0xc7, 0xac, 0x0f, 0xae, 0xfe, 0x5c, 0x01, 0xa8, 0xb6, 0x97, + 0xea, 0x22, 0x16, 0x62, 0xaf, 0x74, 0x4c, 0x1f, 0x40, 0x35, 0x89, 0x42, 0xfd, 0x6f, 0xd9, 0xd4, + 0x17, 0xb6, 0x0f, 0xae, 0x00, 0x9f, 0xc6, 0x53, 0xf1, 0xba, 0x15, 0x4e, 0xe4, 0x78, 0x08, 0xc9, + 0xc6, 0x5f, 0x22, 0x05, 0x8b, 0x4f, 0x48, 0x3e, 0x90, 0x62, 0xae, 0x61, 0x80, 0xd8, 0xd0, 0x5c, + 0x93, 0xaf, 0x21, 0x24, 0xc3, 0xed, 0x1f, 0x65, 0xb7, 0x7a, 0x90, 0xfc, 0x20, 0xaf, 0xaa, 0x7d, + 0x0b, 0xfa, 0x3a, 0x06, 0xce, 0x62, 0x3d, 0x31, 0xc4, 0x13, 0x84, 0xb4, 0x38, 0x48, 0xbe, 0x36, + 0x13, 0x54, 0xea, 0x9f, 0xf4, 0xa6, 0xbf, 0x86, 0x7d, 0x70, 0x45, 0x78, 0x0e, 0xf2, 0x0b, 0xba, + 0xb7, 0x2a, 0x34, 0x19, 0xaf, 0xf4, 0x5a, 0xba, 0xb7, 0xaa, 0x21, 0x94, 0x5c, 0x86, 0x7e, 0x4d, + 0x5f, 0xe3, 0x67, 0x9e, 0x85, 0x30, 0x79, 0x8b, 0xa3, 0xaf, 0xd5, 0xf8, 0xb9, 0x67, 0x80, 0x26, + 0x6a, 0x90, 0x3c, 0x88, 0x9f, 0x7c, 0x63, 0xe6, 0x0a, 0x9e, 0x3c, 0x28, 0x48, 0x19, 0x74, 0x0e, + 0xf2, 0xe3, 0xb6, 0xb1, 0x8e, 0xd7, 0x57, 0x43, 0xbc, 0xb2, 0x25, 0xdb, 0x58, 0xd7, 0x10, 0x4a, + 0x3e, 0x9d, 0x81, 0xbe, 0x69, 0xaa, 0x1b, 0x6c, 0x84, 0x0c, 0x74, 0x73, 0x18, 0xf9, 0xd0, 0xfe, + 0x38, 0x8c, 0x8c, 0xad, 0xf2, 0xca, 0x64, 0x45, 0x11, 0xf5, 0x93, 0x1b, 0xd0, 0x3f, 0xa1, 0x7b, + 0x74, 0xc5, 0x76, 0xd6, 0xd1, 0x05, 0x66, 0x24, 0xf4, 0xa8, 0x8c, 0xe8, 0x8f, 0x4f, 0xc4, 0x6f, + 0xc6, 0xea, 0xe2, 0x97, 0x16, 0x14, 0x66, 0x62, 0x11, 0x99, 0x48, 0x07, 0x43, 0xb1, 0xf0, 0x94, + 0xa3, 0x41, 0xc2, 0xd1, 0xe0, 0x58, 0x79, 0x28, 0xfd, 0x58, 0x19, 0xad, 0x47, 0x74, 0x93, 0xc3, + 0x94, 0x3d, 0xc3, 0xb8, 0xe8, 0x73, 0xeb, 0x11, 0xa1, 0x98, 0xb1, 0x47, 0x93, 0x48, 0xd4, 0xaf, + 0xf7, 0x42, 0xea, 0xdb, 0xb9, 0x23, 0x25, 0x3f, 0x52, 0xf2, 0x50, 0xc9, 0xcb, 0x09, 0x25, 0x3f, + 0x9b, 0x7c, 0x8d, 0xf9, 0x2e, 0xd5, 0xf0, 0x2f, 0xe6, 0x13, 0x6f, 0xb9, 0x1f, 0xec, 0xdd, 0x65, + 0x28, 0xbd, 0xde, 0x2d, 0xa5, 0x17, 0x0c, 0x88, 0xc2, 0x96, 0x03, 0xa2, 0x6f, 0xbb, 0x03, 0xa2, + 0xbf, 0xe3, 0x80, 0x08, 0x15, 0x64, 0xa0, 0xa3, 0x82, 0x54, 0xc4, 0xa0, 0x81, 0xee, 0xe9, 0xe0, + 0xce, 0x6d, 0x6e, 0x14, 0x47, 0xd8, 0x68, 0x4a, 0x4d, 0x04, 0x87, 0x2c, 0xd4, 0xaf, 0xe5, 0xbb, + 0x04, 0x60, 0x38, 0x10, 0x1d, 0x79, 0x1a, 0x72, 0xa5, 0x56, 0x4b, 0xe8, 0xc7, 0x71, 0x29, 0xf6, + 0x43, 0x87, 0x52, 0x8c, 0x9a, 0xbc, 0x00, 0xb9, 0xd2, 0x9d, 0x6a, 0x3c, 0x8c, 0x7c, 0xe9, 0x4e, + 0x55, 0x7c, 0x49, 0xc7, 0xb2, 0x77, 0xaa, 0xe4, 0xa5, 0x30, 0x9e, 0xdb, 0x6a, 0xdb, 0xba, 0x2b, + 0x36, 0x8a, 0xc2, 0x53, 0xd6, 0x77, 0xc7, 0xa9, 0x33, 0x14, 0xdb, 0x2e, 0xc6, 0x68, 0x63, 0xda, + 0x54, 0xd8, 0xbe, 0x36, 0xf5, 0x6d, 0xa9, 0x4d, 0xfd, 0xdb, 0xd5, 0xa6, 0x81, 0x6d, 0x68, 0x13, + 0x6c, 0xa9, 0x4d, 0x83, 0x7b, 0xd7, 0xa6, 0x16, 0x9c, 0x4d, 0x06, 0xcd, 0x09, 0x34, 0x42, 0x03, + 0x92, 0xc4, 0x0a, 0xc7, 0x12, 0xbc, 0xfa, 0x6f, 0x73, 0x6c, 0x8d, 0x67, 0x0c, 0x8e, 0xe7, 0xdb, + 0xd5, 0x52, 0x4a, 0xab, 0xbf, 0x94, 0xed, 0x1c, 0xeb, 0xe7, 0x70, 0x4e, 0x71, 0xdf, 0x96, 0x2a, + 0xa5, 0x7c, 0xf4, 0xed, 0x65, 0x67, 0x29, 0xc7, 0xd8, 0xa6, 0xc9, 0xec, 0xab, 0x99, 0x4e, 0x01, + 0x88, 0xf6, 0x24, 0xb1, 0xc7, 0x92, 0x1e, 0x6d, 0xe8, 0x62, 0xef, 0x46, 0x5d, 0xd9, 0xe2, 0x09, + 0x68, 0x73, 0xbb, 0x4c, 0x40, 0xfb, 0x1b, 0x19, 0x38, 0x7e, 0xb3, 0xbd, 0x44, 0x85, 0x07, 0x5b, + 0xd0, 0x8c, 0x37, 0x01, 0x18, 0x58, 0x38, 0xb1, 0x64, 0xd0, 0x89, 0xe5, 0x7d, 0x72, 0xf0, 0xa0, + 0x58, 0x81, 0x2b, 0x21, 0x35, 0x77, 0x60, 0x39, 0xef, 0xfb, 0x61, 0xde, 0x6d, 0x2f, 0xd1, 0x5a, + 0xc2, 0x93, 0x45, 0xe2, 0x7e, 0xf6, 0x65, 0xee, 0xe1, 0xbe, 0x5b, 0xa7, 0x91, 0x5f, 0xc8, 0x76, + 0x8c, 0xd7, 0x74, 0x68, 0xd3, 0xe5, 0x7c, 0x24, 0xb5, 0x57, 0xe2, 0x69, 0x73, 0x52, 0x48, 0x62, + 0x1c, 0xd3, 0xb8, 0xa4, 0x0b, 0xec, 0x90, 0x27, 0x71, 0x7a, 0x47, 0x05, 0xf6, 0xbb, 0x99, 0x8e, + 0x71, 0xb5, 0x0e, 0xab, 0xc0, 0xd4, 0x7f, 0x9d, 0xf3, 0xc3, 0x79, 0xed, 0xe9, 0x13, 0x9e, 0x80, + 0x01, 0xf1, 0xaa, 0x31, 0xea, 0x80, 0x2b, 0x8e, 0xf2, 0xf0, 0x68, 0x38, 0x20, 0x60, 0xcb, 0xbc, + 0x1f, 0x6e, 0x28, 0xc8, 0x3e, 0x8c, 0xcb, 0xbc, 0x29, 0xa0, 0x8c, 0x5e, 0x22, 0x61, 0x0b, 0xf9, + 0xe4, 0x7d, 0xd3, 0x43, 0xab, 0x80, 0xf5, 0x65, 0x8e, 0x2f, 0xe4, 0xf4, 0xbe, 0xe9, 0x71, 0x9b, + 0x20, 0x40, 0xb3, 0x45, 0xba, 0x1a, 0xa6, 0xa8, 0x14, 0x8b, 0xb4, 0x2b, 0x32, 0x75, 0x8a, 0x17, + 0x5f, 0x4f, 0xc0, 0x80, 0xf0, 0x6a, 0x15, 0x6e, 0x26, 0xa2, 0xb5, 0xc2, 0x0f, 0x16, 0x5b, 0x1b, + 0x10, 0x30, 0x8e, 0x1a, 0x5d, 0x09, 0x1d, 0xeb, 0x90, 0xa3, 0x83, 0x10, 0x4d, 0x60, 0xc8, 0x35, + 0x18, 0xa9, 0x7a, 0xba, 0x65, 0xe8, 0x8e, 0x31, 0xdf, 0xf6, 0x5a, 0x6d, 0x4f, 0x36, 0x4a, 0x5d, + 0xcf, 0xb0, 0xdb, 0x9e, 0x16, 0xa3, 0x20, 0xef, 0x87, 0x61, 0x1f, 0x32, 0xe9, 0x38, 0xb6, 0x23, + 0x5b, 0x1e, 0xae, 0x67, 0x50, 0xc7, 0xd1, 0xa2, 0x04, 0xe4, 0x03, 0x30, 0x5c, 0xb1, 0xee, 0xd9, + 0x3c, 0xf7, 0xe9, 0x2d, 0x6d, 0x46, 0xd8, 0x21, 0xf8, 0x8a, 0xca, 0x0c, 0x10, 0xb5, 0xb6, 0xd3, + 0xd0, 0xa2, 0x84, 0xea, 0x66, 0x36, 0x19, 0xf5, 0xec, 0xc1, 0xdd, 0xb4, 0x5c, 0x8e, 0x3a, 0xd3, + 0xa1, 0x07, 0x29, 0x1a, 0x84, 0xb2, 0x2f, 0x2f, 0xb7, 0x0b, 0xaf, 0x41, 0xff, 0x4d, 0xba, 0xce, + 0xfd, 0x3e, 0x0b, 0xa1, 0xab, 0xf0, 0x5d, 0x01, 0x93, 0x4f, 0x5c, 0x7d, 0x3a, 0xf5, 0x2b, 0xd9, + 0x64, 0x3c, 0xb7, 0x07, 0x57, 0xd8, 0xef, 0x87, 0x3e, 0x14, 0x65, 0xc5, 0x3f, 0xf2, 0x47, 0x01, + 0xa2, 0xb8, 0xa3, 0x1e, 0xc8, 0x3e, 0x99, 0xfa, 0x13, 0x85, 0x78, 0x90, 0xbf, 0x07, 0x57, 0x7a, + 0x2f, 0xc2, 0xe0, 0x84, 0x6d, 0xb9, 0xa6, 0xeb, 0x51, 0xab, 0xee, 0x2b, 0xec, 0x19, 0x66, 0x50, + 0xd5, 0x43, 0xb0, 0xfc, 0x7c, 0x48, 0xa2, 0xde, 0x8d, 0xf2, 0x92, 0x67, 0x61, 0x00, 0x45, 0x8e, + 0x7e, 0xd2, 0x52, 0x6e, 0xf5, 0x25, 0x06, 0x8c, 0x3b, 0x49, 0x87, 0xa4, 0xe4, 0x16, 0xf4, 0x4f, + 0xac, 0x9a, 0x0d, 0xc3, 0xa1, 0x16, 0xfa, 0x0b, 0x4b, 0x6f, 0xa9, 0xa3, 0x7d, 0x79, 0x05, 0xff, + 0x45, 0x5a, 0xde, 0x9c, 0xba, 0x28, 0x16, 0x79, 0x40, 0x25, 0x60, 0x67, 0x7f, 0x20, 0x0b, 0x10, + 0x16, 0x20, 0x0f, 0x43, 0x36, 0xc8, 0xfe, 0x86, 0x6e, 0x2a, 0x11, 0x0d, 0xca, 0xe2, 0x52, 0x21, + 0xc6, 0x76, 0x76, 0xcb, 0xb1, 0x7d, 0x0b, 0x0a, 0xfc, 0xc4, 0x0b, 0x3d, 0xc9, 0xa5, 0xb8, 0x63, + 0x1d, 0x1b, 0x7c, 0x05, 0xe9, 0xf9, 0x66, 0x16, 0x2d, 0xcf, 0x88, 0x57, 0x36, 0x67, 0x76, 0xb6, + 0x0e, 0xbd, 0xf8, 0x17, 0xb9, 0x08, 0x79, 0x94, 0x62, 0x06, 0xf7, 0xb1, 0x38, 0x4b, 0xc7, 0xe4, + 0x87, 0x78, 0xd6, 0x4d, 0x13, 0xb6, 0xe5, 0xb1, 0xaa, 0xb1, 0xd5, 0x43, 0x42, 0x2e, 0x02, 0x16, + 0x91, 0x8b, 0x80, 0xa9, 0xff, 0x30, 0x9b, 0x12, 0x7e, 0xf2, 0xc1, 0x1d, 0x26, 0xcf, 0x03, 0xe0, + 0x6b, 0x6c, 0x26, 0x4f, 0xff, 0x89, 0x06, 0x8e, 0x12, 0x64, 0x84, 0x6a, 0x1b, 0xd9, 0x76, 0x84, + 0xc4, 0xea, 0x6f, 0x65, 0x12, 0x31, 0x0b, 0xf7, 0x24, 0x47, 0xd9, 0x2a, 0xcb, 0xee, 0xd2, 0x8c, + 0xf5, 0xfb, 0x22, 0xb7, 0xb3, 0xbe, 0x88, 0x7e, 0xcb, 0x3e, 0x58, 0xa6, 0x07, 0xf9, 0x2d, 0x5f, + 0xcf, 0xa6, 0x45, 0x70, 0x3c, 0x9c, 0x2a, 0x7e, 0x3d, 0x30, 0x4a, 0xf3, 0xdb, 0xc9, 0x9b, 0x2e, + 0xcc, 0xd4, 0x8f, 0xc3, 0xb1, 0x58, 0x5c, 0x43, 0x91, 0x92, 0xf1, 0x62, 0xf7, 0x00, 0x89, 0x9d, + 0xdf, 0xf1, 0x47, 0xc8, 0xd4, 0xff, 0x9e, 0xe9, 0x1e, 0xd5, 0xf2, 0xc0, 0x55, 0x27, 0x45, 0x00, + 0xb9, 0xbf, 0x1a, 0x01, 0xec, 0xc3, 0x36, 0xf8, 0x70, 0x0b, 0xe0, 0x5d, 0x32, 0x79, 0xbc, 0xd3, + 0x02, 0xf8, 0x89, 0xcc, 0x96, 0x41, 0x49, 0x0f, 0x5a, 0x06, 0xea, 0xbf, 0xc8, 0xa4, 0x06, 0x0f, + 0xdd, 0x53, 0xbb, 0x5e, 0x82, 0x02, 0x77, 0xab, 0x11, 0xad, 0x92, 0xd2, 0xad, 0x30, 0x68, 0x87, + 0xf2, 0xa2, 0x0c, 0x99, 0x81, 0x3e, 0xde, 0x06, 0x23, 0x9e, 0x96, 0x38, 0xa5, 0x9d, 0x46, 0xa7, + 0xc9, 0x51, 0xa0, 0xd5, 0xdf, 0xcc, 0x24, 0x62, 0x99, 0x1e, 0xe0, 0xb7, 0x85, 0x53, 0x75, 0x6e, + 0xfb, 0x53, 0xb5, 0xfa, 0xc7, 0xd9, 0xf4, 0x50, 0xaa, 0x07, 0xf8, 0x21, 0xfb, 0x71, 0x9c, 0xb6, + 0xbb, 0x75, 0x6b, 0x11, 0x46, 0xa2, 0xb2, 0x10, 0xcb, 0xd6, 0x85, 0xf4, 0x80, 0xb2, 0x1d, 0x5a, + 0x11, 0xe3, 0xa1, 0xbe, 0x9d, 0x49, 0x46, 0x81, 0x3d, 0xf0, 0xf9, 0x69, 0x77, 0xda, 0x12, 0xfd, + 0x94, 0x77, 0xc9, 0x5a, 0xb3, 0x1f, 0x9f, 0xf2, 0x2e, 0x59, 0x35, 0x76, 0xf7, 0x29, 0x3f, 0x97, + 0xed, 0x14, 0x44, 0xf7, 0xc0, 0x3f, 0xe8, 0xc3, 0xb2, 0x90, 0x79, 0xcb, 0xc4, 0xa7, 0x3d, 0xdc, + 0x29, 0x6a, 0x6d, 0x07, 0x9e, 0x09, 0x3e, 0xbb, 0x1b, 0xe3, 0xa9, 0xc2, 0x7a, 0x97, 0x28, 0xf2, + 0xe1, 0x10, 0xd6, 0xbb, 0x64, 0xa8, 0xbc, 0xfb, 0x84, 0xf5, 0xb7, 0xb2, 0xdb, 0x8d, 0xdc, 0x7c, + 0x24, 0xbc, 0x84, 0xf0, 0x3e, 0x9f, 0x4d, 0x46, 0x14, 0x3f, 0x70, 0x31, 0x4d, 0x41, 0x41, 0xc4, + 0x36, 0xef, 0x28, 0x1c, 0x8e, 0xef, 0x64, 0xd1, 0x88, 0xef, 0xb8, 0x0e, 0xe2, 0x22, 0x67, 0x7b, + 0x22, 0xe1, 0xb4, 0xea, 0x9f, 0x67, 0x62, 0xe1, 0xb7, 0x0f, 0xe4, 0x08, 0x61, 0x57, 0x4b, 0x12, + 0x79, 0xd9, 0x3f, 0xcc, 0xcc, 0xc7, 0xc2, 0x9f, 0x06, 0xdf, 0x53, 0xa6, 0x9e, 0x6e, 0x36, 0xe2, + 0xe5, 0x45, 0x4c, 0x80, 0xaf, 0x64, 0x61, 0x2c, 0x41, 0x4a, 0x2e, 0x46, 0x42, 0xe9, 0xe0, 0xb1, + 0x64, 0xcc, 0x79, 0x9c, 0x07, 0xd5, 0xd9, 0xc1, 0x49, 0xea, 0x45, 0xc8, 0x97, 0xf5, 0x75, 0xfe, + 0x6d, 0xbd, 0x9c, 0xa5, 0xa1, 0xaf, 0xcb, 0x27, 0x6e, 0x88, 0x27, 0x4b, 0x70, 0x92, 0xdf, 0x87, + 0x98, 0xb6, 0xb5, 0x68, 0x36, 0x69, 0xc5, 0x9a, 0x35, 0x1b, 0x0d, 0xd3, 0x15, 0x97, 0x7a, 0x4f, + 0x6c, 0x6e, 0x14, 0x2f, 0x79, 0xb6, 0xa7, 0x37, 0x6a, 0xd4, 0x27, 0xab, 0x79, 0x66, 0x93, 0xd6, + 0x4c, 0xab, 0xd6, 0x44, 0x4a, 0x89, 0x65, 0x3a, 0x2b, 0x52, 0xe1, 0x91, 0x6e, 0xab, 0x75, 0xdd, + 0xb2, 0xa8, 0x51, 0xb1, 0xc6, 0xd7, 0x3d, 0xca, 0x2f, 0x03, 0x73, 0xfc, 0x48, 0x90, 0xbf, 0x0d, + 0xe7, 0x68, 0xc6, 0x78, 0x89, 0x11, 0x68, 0x29, 0x85, 0xd4, 0x5f, 0xcf, 0xa7, 0x44, 0x5e, 0x3f, + 0x44, 0xea, 0xe3, 0xf7, 0x74, 0x7e, 0x8b, 0x9e, 0xbe, 0x0a, 0x7d, 0xb7, 0xa9, 0x83, 0xe7, 0x5b, + 0xfc, 0x82, 0x01, 0x9d, 0xd9, 0xef, 0x71, 0x90, 0x7c, 0x43, 0x23, 0xa8, 0x48, 0x03, 0xce, 0x2e, + 0xb2, 0x6e, 0x4a, 0xef, 0xcc, 0xc2, 0x2e, 0x3a, 0xb3, 0x0b, 0x3f, 0xf2, 0x06, 0x9c, 0x46, 0x6c, + 0x4a, 0xb7, 0xf6, 0x61, 0x55, 0x18, 0x5e, 0x8a, 0x57, 0x95, 0xde, 0xb9, 0x9d, 0xca, 0x93, 0x0f, + 0xc3, 0x50, 0x30, 0x40, 0x4c, 0xea, 0x8a, 0x9b, 0x8b, 0x2e, 0xe3, 0x8c, 0xc7, 0x6e, 0x63, 0x60, + 0x74, 0x21, 0x8b, 0xc6, 0xff, 0x8a, 0xf0, 0x52, 0xff, 0x79, 0xa6, 0x5b, 0x04, 0xf8, 0x03, 0x9f, + 0x95, 0x5f, 0x86, 0x3e, 0x83, 0x7f, 0x94, 0xd0, 0xa9, 0xee, 0x31, 0xe2, 0x39, 0xa9, 0xe6, 0x97, + 0x51, 0xff, 0x28, 0xd3, 0x35, 0xf0, 0xfc, 0x61, 0xff, 0xbc, 0xcf, 0xe7, 0x3a, 0x7c, 0x9e, 0x98, + 0x44, 0x2f, 0xc3, 0xa8, 0x19, 0x46, 0xc6, 0xad, 0x85, 0xe1, 0xa7, 0xb4, 0x63, 0x12, 0x1c, 0x47, + 0xd7, 0x75, 0x38, 0xe5, 0x3b, 0x3e, 0x3a, 0xbe, 0x87, 0x98, 0x5b, 0x6b, 0x3b, 0x26, 0x1f, 0x97, + 0xda, 0x09, 0x37, 0xe6, 0x3e, 0xe6, 0xde, 0x72, 0x4c, 0x56, 0x81, 0xee, 0xad, 0x52, 0x4b, 0xaf, + 0xad, 0xd9, 0xce, 0x5d, 0x0c, 0x10, 0xca, 0x07, 0xa7, 0x76, 0x8c, 0xc3, 0xef, 0xf8, 0x60, 0xf2, + 0x28, 0x0c, 0xaf, 0x34, 0xda, 0x34, 0x08, 0xc9, 0xc8, 0xef, 0xfa, 0xb4, 0x21, 0x06, 0x0c, 0x6e, + 0x48, 0xce, 0x03, 0x20, 0x91, 0x87, 0x69, 0x01, 0xf0, 0x62, 0x4f, 0x1b, 0x60, 0x90, 0x45, 0xd1, + 0x5d, 0x67, 0xb9, 0x56, 0x73, 0x21, 0xd5, 0x1a, 0xb6, 0xb5, 0x52, 0xf3, 0xa8, 0xd3, 0xc4, 0x86, + 0xa2, 0x33, 0x83, 0x76, 0x0a, 0x29, 0xf0, 0xea, 0xc4, 0x9d, 0xb1, 0xad, 0x95, 0x45, 0xea, 0x34, + 0x59, 0x53, 0x9f, 0x00, 0x22, 0x9a, 0xea, 0xe0, 0xa1, 0x07, 0xff, 0x38, 0xf4, 0x66, 0xd0, 0xc4, + 0x47, 0xf0, 0xd3, 0x10, 0xfc, 0xb0, 0x22, 0x0c, 0xf2, 0xb8, 0x74, 0x5c, 0x68, 0xe8, 0xc2, 0xa0, + 0x01, 0x07, 0xa1, 0xbc, 0x4e, 0x81, 0xf0, 0xae, 0xe0, 0x5e, 0xdd, 0x9a, 0xf8, 0xa5, 0x7e, 0x26, + 0x97, 0x16, 0x2b, 0x7f, 0x4f, 0x8a, 0x16, 0x4e, 0xab, 0xd9, 0x1d, 0x4d, 0xab, 0xc7, 0xac, 0x76, + 0xb3, 0xa6, 0xb7, 0x5a, 0xb5, 0x65, 0xb3, 0x81, 0xcf, 0xaa, 0x70, 0xe1, 0xd3, 0x86, 0xad, 0x76, + 0xb3, 0xd4, 0x6a, 0x4d, 0x71, 0x20, 0x79, 0x1c, 0xc6, 0x18, 0x1d, 0x76, 0x52, 0x40, 0x99, 0x47, + 0x4a, 0xc6, 0x00, 0x03, 0xbb, 0xfa, 0xb4, 0x67, 0xa0, 0x5f, 0xf0, 0xe4, 0x6b, 0x55, 0xaf, 0xd6, + 0xc7, 0x99, 0xb9, 0xac, 0xe7, 0x02, 0x36, 0x7c, 0x72, 0xed, 0xd5, 0x06, 0xfc, 0xf2, 0x18, 0xbe, + 0xd8, 0x6a, 0x37, 0x79, 0x44, 0xac, 0x3e, 0x44, 0x06, 0xbf, 0xc9, 0x45, 0x18, 0x61, 0x5c, 0x02, + 0x81, 0xf1, 0x88, 0xaf, 0xbd, 0x5a, 0x0c, 0x4a, 0xae, 0xc1, 0x89, 0x08, 0x84, 0xdb, 0xa0, 0xfc, + 0x99, 0x40, 0xaf, 0x96, 0x8a, 0x53, 0xbf, 0x9c, 0x8b, 0x46, 0xf0, 0x3f, 0x80, 0x8e, 0x38, 0x0d, + 0x7d, 0xb6, 0xb3, 0x52, 0x6b, 0x3b, 0x0d, 0x31, 0xf6, 0x0a, 0xb6, 0xb3, 0x72, 0xcb, 0x69, 0x90, + 0x93, 0x50, 0x60, 0xbd, 0x63, 0x1a, 0x62, 0x88, 0xf5, 0xea, 0xad, 0x56, 0xc5, 0x20, 0x25, 0xde, + 0x21, 0x18, 0x2d, 0xb4, 0x56, 0xc7, 0xad, 0x3d, 0x77, 0x4a, 0xe8, 0xe5, 0x2b, 0x5e, 0x02, 0x89, + 0xfd, 0x84, 0x31, 0x44, 0xf9, 0x41, 0x40, 0x8c, 0x85, 0x81, 0xdb, 0x12, 0x83, 0xf7, 0x49, 0x9c, + 0x85, 0x40, 0x86, 0x2c, 0xf8, 0x26, 0xc6, 0x20, 0x65, 0x20, 0x21, 0x55, 0xd3, 0x36, 0xcc, 0x65, + 0x93, 0xf2, 0x57, 0x1d, 0xbd, 0xfc, 0xe2, 0x37, 0x89, 0xd5, 0x46, 0x7d, 0x26, 0xb3, 0x02, 0x42, + 0x5e, 0xe4, 0x4a, 0xc8, 0xe9, 0x70, 0xed, 0xe3, 0x7d, 0xcb, 0xed, 0xb4, 0x18, 0x0a, 0x35, 0x13, + 0xcb, 0xe3, 0x42, 0xa8, 0xbe, 0x9d, 0x4b, 0xa6, 0x71, 0x38, 0x10, 0xbb, 0x66, 0x1a, 0x40, 0x64, + 0x69, 0x09, 0x2f, 0xd7, 0x02, 0x8f, 0xf3, 0x10, 0xd3, 0x81, 0x87, 0x54, 0x96, 0x5c, 0x86, 0x7e, + 0xfe, 0x45, 0x95, 0xb2, 0xb0, 0x77, 0xd0, 0x45, 0xcc, 0x6d, 0x99, 0xcb, 0xcb, 0xe8, 0x4f, 0x16, + 0xa0, 0xc9, 0x45, 0xe8, 0x2b, 0xcf, 0x55, 0xab, 0xa5, 0x39, 0xff, 0xa6, 0x18, 0xdf, 0x97, 0x18, + 0x96, 0x5b, 0x73, 0x75, 0xcb, 0xd5, 0x7c, 0x24, 0x79, 0x14, 0x0a, 0x95, 0x05, 0x24, 0xe3, 0xaf, + 0x26, 0x07, 0x37, 0x37, 0x8a, 0x7d, 0x66, 0x8b, 0x53, 0x09, 0x14, 0xd6, 0x7b, 0xbb, 0x52, 0x96, + 0xdc, 0x25, 0x78, 0xbd, 0xf7, 0x4c, 0x03, 0xaf, 0x9d, 0xb5, 0x00, 0x4d, 0x9e, 0x81, 0xa1, 0x2a, + 0x75, 0x4c, 0xbd, 0x31, 0xd7, 0xc6, 0xad, 0xa2, 0x14, 0x4a, 0xd1, 0x45, 0x78, 0xcd, 0x42, 0x84, + 0x16, 0x21, 0x23, 0xe7, 0x20, 0x3f, 0x6d, 0x5a, 0xfe, 0x13, 0x06, 0xf4, 0x71, 0x5f, 0x35, 0x2d, + 0x4f, 0x43, 0xa8, 0xfa, 0x1f, 0xb3, 0xe9, 0xb9, 0x30, 0x0e, 0x60, 0x38, 0xee, 0xf2, 0xa6, 0x37, + 0xa6, 0x04, 0xf9, 0x3d, 0x28, 0xc1, 0x32, 0x1c, 0x2b, 0x19, 0x4d, 0xd3, 0x2a, 0xe1, 0x4f, 0x77, + 0x76, 0xaa, 0x84, 0xc3, 0x5b, 0x7a, 0x42, 0x17, 0x43, 0x8b, 0xef, 0xe1, 0xf1, 0x74, 0x19, 0xaa, + 0xa6, 0x73, 0x5c, 0xad, 0xb9, 0xac, 0xd7, 0xea, 0x3c, 0x8d, 0x84, 0x16, 0x67, 0xaa, 0x7e, 0x7f, + 0x76, 0x8b, 0xf4, 0x1d, 0x0f, 0xa2, 0xf4, 0xd5, 0x2f, 0x64, 0xbb, 0x67, 0x50, 0x79, 0x20, 0x85, + 0xf2, 0xa7, 0xd9, 0x94, 0x7c, 0x26, 0x7b, 0x92, 0xc4, 0x65, 0xe8, 0xe7, 0x6c, 0x02, 0x57, 0x5b, + 0x9c, 0x71, 0xb8, 0xb2, 0xe2, 0x4c, 0xe7, 0xa3, 0xc9, 0x1c, 0x9c, 0x28, 0x2d, 0x2f, 0xd3, 0xba, + 0x17, 0x46, 0x56, 0x9e, 0x0b, 0x03, 0xa5, 0xf2, 0x70, 0xb4, 0x02, 0x1f, 0x46, 0x66, 0xc6, 0x80, + 0x20, 0xa9, 0xe5, 0xc8, 0x22, 0x9c, 0x8a, 0xc3, 0xab, 0xdc, 0x4c, 0xcf, 0x4b, 0x11, 0x6a, 0x13, + 0x1c, 0xf9, 0x7f, 0x5a, 0x87, 0xb2, 0x69, 0xad, 0xc4, 0xe9, 0xb4, 0xb7, 0x5b, 0x2b, 0x71, 0x6e, + 0x4d, 0x2d, 0xa7, 0x7e, 0x25, 0x27, 0xa7, 0x7d, 0x79, 0x70, 0x9d, 0xa2, 0xae, 0x47, 0x5c, 0xa1, + 0xb7, 0x3b, 0x64, 0x9e, 0x11, 0x51, 0x3e, 0x8c, 0xb6, 0xe3, 0x7b, 0x0d, 0x06, 0x51, 0x06, 0x10, + 0x28, 0xfb, 0xff, 0x05, 0x94, 0xa4, 0x02, 0xf9, 0x92, 0xb3, 0xc2, 0x4d, 0xd0, 0xad, 0x1e, 0x3e, + 0xe9, 0xce, 0x8a, 0x9b, 0xfe, 0xf0, 0x89, 0xb1, 0x50, 0xbf, 0x2f, 0xdb, 0x25, 0x53, 0xcb, 0x03, + 0x39, 0x89, 0xfc, 0x48, 0xb6, 0x53, 0xce, 0x95, 0xc3, 0xea, 0xde, 0xf5, 0x0e, 0x0b, 0xe7, 0x70, + 0xfb, 0xbe, 0xed, 0x9f, 0x70, 0x1e, 0x9f, 0xe5, 0xe1, 0xb1, 0x6f, 0x9a, 0x96, 0x41, 0xce, 0xc0, + 0xc9, 0x5b, 0xd5, 0x49, 0xad, 0x76, 0xb3, 0x32, 0x57, 0xae, 0xdd, 0x9a, 0xab, 0x2e, 0x4c, 0x4e, + 0x54, 0xa6, 0x2a, 0x93, 0xe5, 0xd1, 0x1e, 0x72, 0x1c, 0x8e, 0x85, 0xa8, 0xe9, 0x5b, 0xb3, 0xa5, + 0xb9, 0xd1, 0x0c, 0x19, 0x83, 0xe1, 0x10, 0x38, 0x3e, 0xbf, 0x38, 0x9a, 0x7d, 0xfc, 0xbd, 0x30, + 0x88, 0xfb, 0x7f, 0x6e, 0x0b, 0x91, 0x21, 0xe8, 0x9f, 0x1f, 0xaf, 0x4e, 0x6a, 0xb7, 0x91, 0x09, + 0x40, 0xa1, 0x3c, 0x39, 0xc7, 0x18, 0x66, 0x1e, 0xff, 0x2f, 0x19, 0x80, 0xea, 0xd4, 0xe2, 0x82, + 0x20, 0x1c, 0x84, 0xbe, 0xca, 0xdc, 0xed, 0xd2, 0x4c, 0x85, 0xd1, 0xf5, 0x43, 0x7e, 0x7e, 0x61, + 0x92, 0xd5, 0x30, 0x00, 0xbd, 0x13, 0x33, 0xf3, 0xd5, 0xc9, 0xd1, 0x2c, 0x03, 0x6a, 0x93, 0xa5, + 0xf2, 0x68, 0x8e, 0x01, 0xef, 0x68, 0x95, 0xc5, 0xc9, 0xd1, 0x3c, 0xfb, 0x73, 0xa6, 0xba, 0x58, + 0x5a, 0x1c, 0xed, 0x65, 0x7f, 0x4e, 0xe1, 0x9f, 0x05, 0xc6, 0xac, 0x3a, 0xb9, 0x88, 0x3f, 0xfa, + 0x58, 0x13, 0xa6, 0xfc, 0x5f, 0xfd, 0x0c, 0xc5, 0x58, 0x97, 0x2b, 0xda, 0xe8, 0x00, 0xfb, 0xc1, + 0x58, 0xb2, 0x1f, 0xc0, 0x1a, 0xa7, 0x4d, 0xce, 0xce, 0xdf, 0x9e, 0x1c, 0x1d, 0x64, 0xbc, 0x66, + 0x6f, 0x32, 0xf0, 0x10, 0xfb, 0x53, 0x9b, 0x65, 0x7f, 0x0e, 0x33, 0x4e, 0xda, 0x64, 0x69, 0x66, + 0xa1, 0xb4, 0x38, 0x3d, 0x3a, 0xc2, 0xda, 0x83, 0x3c, 0x8f, 0xf1, 0x92, 0x73, 0xa5, 0xd9, 0xc9, + 0xd1, 0x51, 0x41, 0x53, 0x9e, 0xa9, 0xcc, 0xdd, 0x1c, 0x1d, 0xc3, 0x86, 0xbc, 0x31, 0x8b, 0x3f, + 0x08, 0x2b, 0x80, 0x7f, 0x1d, 0x7f, 0xfc, 0xa3, 0x50, 0x98, 0xaf, 0xa2, 0xc5, 0x7f, 0x1a, 0x8e, + 0xcf, 0x57, 0x6b, 0x8b, 0x6f, 0x2c, 0x4c, 0xc6, 0xe4, 0x3d, 0x06, 0xc3, 0x3e, 0x62, 0xa6, 0x32, + 0x77, 0xeb, 0x43, 0x5c, 0xda, 0x3e, 0x68, 0xb6, 0x34, 0x31, 0x5f, 0x1d, 0xcd, 0xb2, 0x5e, 0xf1, + 0x41, 0x77, 0x2a, 0x73, 0xe5, 0xf9, 0x3b, 0xd5, 0xd1, 0xdc, 0xe3, 0xf7, 0xfc, 0x34, 0xc4, 0xf3, + 0x8e, 0xb9, 0x62, 0x5a, 0xe4, 0x3c, 0x9c, 0x29, 0x4f, 0xde, 0xae, 0x4c, 0x4c, 0xd6, 0xe6, 0xb5, + 0xca, 0x8d, 0xca, 0x5c, 0xac, 0xa6, 0x93, 0x30, 0x16, 0x45, 0x97, 0x16, 0x2a, 0xa3, 0x19, 0x72, + 0x0a, 0x48, 0x14, 0xfc, 0x5a, 0x69, 0x76, 0x6a, 0x34, 0x4b, 0x14, 0x38, 0x11, 0x85, 0x57, 0xe6, + 0x16, 0x6f, 0xcd, 0x4d, 0x8e, 0xe6, 0x1e, 0xff, 0xa9, 0x0c, 0x9c, 0x4c, 0x0d, 0x40, 0x41, 0x54, + 0xb8, 0x30, 0x39, 0x53, 0xaa, 0x2e, 0x56, 0x26, 0xaa, 0x93, 0x25, 0x6d, 0x62, 0xba, 0x36, 0x51, + 0x5a, 0x9c, 0xbc, 0x31, 0xaf, 0xbd, 0x51, 0xbb, 0x31, 0x39, 0x37, 0xa9, 0x95, 0x66, 0x46, 0x7b, + 0xc8, 0xa3, 0x50, 0xec, 0x40, 0x53, 0x9d, 0x9c, 0xb8, 0xa5, 0x55, 0x16, 0xdf, 0x18, 0xcd, 0x90, + 0x47, 0xe0, 0x7c, 0x47, 0x22, 0xf6, 0x7b, 0x34, 0x4b, 0x2e, 0xc0, 0xd9, 0x4e, 0x24, 0xaf, 0xcf, + 0x8c, 0xe6, 0x1e, 0xff, 0xa1, 0x0c, 0x90, 0x64, 0x04, 0x01, 0xf2, 0x30, 0x9c, 0x63, 0x7a, 0x51, + 0xeb, 0xdc, 0xc0, 0x47, 0xe0, 0x7c, 0x2a, 0x85, 0xd4, 0xbc, 0x22, 0x3c, 0xd4, 0x81, 0x44, 0x34, + 0xee, 0x1c, 0x28, 0xe9, 0x04, 0xd8, 0xb4, 0x5f, 0xc9, 0xc0, 0xc9, 0xd4, 0xed, 0x07, 0xb9, 0x04, + 0xef, 0x29, 0x95, 0x67, 0x59, 0xdf, 0x4c, 0x2c, 0x56, 0xe6, 0xe7, 0xaa, 0xb5, 0xd9, 0xa9, 0x52, + 0x8d, 0x69, 0xdf, 0xad, 0x6a, 0xac, 0x37, 0x2f, 0x82, 0xda, 0x85, 0x72, 0x62, 0xba, 0x34, 0x77, + 0x83, 0x0d, 0x3f, 0xf2, 0x1e, 0x78, 0xb8, 0x23, 0xdd, 0xe4, 0x5c, 0x69, 0x7c, 0x66, 0xb2, 0x3c, + 0x9a, 0x25, 0x8f, 0xc1, 0x23, 0x1d, 0xa9, 0xca, 0x95, 0x2a, 0x27, 0xcb, 0x8d, 0x97, 0xdf, 0xfe, + 0x97, 0x17, 0x7a, 0xde, 0xfe, 0xc6, 0x85, 0xcc, 0xef, 0x7c, 0xe3, 0x42, 0xe6, 0x8f, 0xbf, 0x71, + 0x21, 0xf3, 0xe1, 0x6b, 0x3b, 0x89, 0x0c, 0xc1, 0xa7, 0xad, 0xa5, 0x02, 0x9a, 0x02, 0x4f, 0xff, + 0x8f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x62, 0x28, 0xf0, 0x18, 0x5a, 0x01, 0x00, } func (m *Metadata) Marshal() (dAtA []byte, err error) { @@ -28592,6 +28720,52 @@ func (m *OneOf_IntegrationDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) } return len(dAtA) - i, nil } +func (m *OneOf_SPIFFEFederationCreate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OneOf_SPIFFEFederationCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SPIFFEFederationCreate != nil { + { + size, err := m.SPIFFEFederationCreate.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + i-- + dAtA[i] = 0xc2 + } + return len(dAtA) - i, nil +} +func (m *OneOf_SPIFFEFederationDelete) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OneOf_SPIFFEFederationDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.SPIFFEFederationDelete != nil { + { + size, err := m.SPIFFEFederationDelete.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + i-- + dAtA[i] = 0xca + } + return len(dAtA) - i, nil +} func (m *StreamStatus) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -28616,12 +28790,12 @@ func (m *StreamStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - n612, err612 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastUploadTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastUploadTime):]) - if err612 != nil { - return 0, err612 + n614, err614 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastUploadTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastUploadTime):]) + if err614 != nil { + return 0, err614 } - i -= n612 - i = encodeVarintEvents(dAtA, i, uint64(n612)) + i -= n614 + i = encodeVarintEvents(dAtA, i, uint64(n614)) i-- dAtA[i] = 0x1a if m.LastEventIndex != 0 { @@ -28771,12 +28945,12 @@ func (m *Identity) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xc2 } } - n616, err616 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.PreviousIdentityExpires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.PreviousIdentityExpires):]) - if err616 != nil { - return 0, err616 + n618, err618 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.PreviousIdentityExpires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.PreviousIdentityExpires):]) + if err618 != nil { + return 0, err618 } - i -= n616 - i = encodeVarintEvents(dAtA, i, uint64(n616)) + i -= n618 + i = encodeVarintEvents(dAtA, i, uint64(n618)) i-- dAtA[i] = 0x1 i-- @@ -28924,12 +29098,12 @@ func (m *Identity) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x4a } - n620, err620 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) - if err620 != nil { - return 0, err620 + n622, err622 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) + if err622 != nil { + return 0, err622 } - i -= n620 - i = encodeVarintEvents(dAtA, i, uint64(n620)) + i -= n622 + i = encodeVarintEvents(dAtA, i, uint64(n622)) i-- dAtA[i] = 0x42 if len(m.KubernetesUsers) > 0 { @@ -29018,6 +29192,13 @@ func (m *RouteToApp) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.URI) > 0 { + i -= len(m.URI) + copy(dAtA[i:], m.URI) + i = encodeVarintEvents(dAtA, i, uint64(len(m.URI))) + i-- + dAtA[i] = 0x42 + } if len(m.GCPServiceAccount) > 0 { i -= len(m.GCPServiceAccount) copy(dAtA[i:], m.GCPServiceAccount) @@ -34123,6 +34304,140 @@ func (m *AccessGraphSettingsUpdate) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *SPIFFEFederationCreate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SPIFFEFederationCreate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SPIFFEFederationCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.ConnectionMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.UserMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.ResourceMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *SPIFFEFederationDelete) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SPIFFEFederationDelete) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SPIFFEFederationDelete) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + { + size, err := m.ConnectionMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.UserMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size, err := m.ResourceMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { offset -= sovEvents(v) base := offset @@ -39837,6 +40152,30 @@ func (m *OneOf_IntegrationDelete) Size() (n int) { } return n } +func (m *OneOf_SPIFFEFederationCreate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SPIFFEFederationCreate != nil { + l = m.SPIFFEFederationCreate.Size() + n += 2 + l + sovEvents(uint64(l)) + } + return n +} +func (m *OneOf_SPIFFEFederationDelete) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SPIFFEFederationDelete != nil { + l = m.SPIFFEFederationDelete.Size() + n += 2 + l + sovEvents(uint64(l)) + } + return n +} func (m *StreamStatus) Size() (n int) { if m == nil { return 0 @@ -40053,6 +40392,10 @@ func (m *RouteToApp) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + l = len(m.URI) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -41876,6 +42219,46 @@ func (m *AccessGraphSettingsUpdate) Size() (n int) { return n } +func (m *SPIFFEFederationCreate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Metadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.ResourceMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.UserMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.ConnectionMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *SPIFFEFederationDelete) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Metadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.ResourceMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.UserMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + l = m.ConnectionMetadata.Size() + n += 1 + l + sovEvents(uint64(l)) + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovEvents(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -59097,7 +59480,7 @@ func (m *SAMLConnectorCreate) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Connector == nil { - m.Connector = &types.SAMLConnectorV2{} + m.Connector = &types1.SAMLConnectorV2{} } if err := m.Connector.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -59283,7 +59666,7 @@ func (m *SAMLConnectorUpdate) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Connector == nil { - m.Connector = &types.SAMLConnectorV2{} + m.Connector = &types1.SAMLConnectorV2{} } if err := m.Connector.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -78034,15 +78417,85 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &SpannerRPC{} + v := &SpannerRPC{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Event = &OneOf_SpannerRPC{v} + iNdEx = postIndex + case 159: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DatabaseSessionCommandResult", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &DatabaseSessionCommandResult{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Event = &OneOf_DatabaseSessionCommandResult{v} + iNdEx = postIndex + case 160: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigCreate", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &DiscoveryConfigCreate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_SpannerRPC{v} + m.Event = &OneOf_DiscoveryConfigCreate{v} iNdEx = postIndex - case 159: + case 161: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DatabaseSessionCommandResult", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigUpdate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78069,15 +78522,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &DatabaseSessionCommandResult{} + v := &DiscoveryConfigUpdate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_DatabaseSessionCommandResult{v} + m.Event = &OneOf_DiscoveryConfigUpdate{v} iNdEx = postIndex - case 160: + case 162: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigCreate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigDelete", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78104,15 +78557,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &DiscoveryConfigCreate{} + v := &DiscoveryConfigDelete{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_DiscoveryConfigCreate{v} + m.Event = &OneOf_DiscoveryConfigDelete{v} iNdEx = postIndex - case 161: + case 163: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigUpdate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigDeleteAll", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78139,15 +78592,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &DiscoveryConfigUpdate{} + v := &DiscoveryConfigDeleteAll{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_DiscoveryConfigUpdate{v} + m.Event = &OneOf_DiscoveryConfigDeleteAll{v} iNdEx = postIndex - case 162: + case 164: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigDelete", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AccessGraphSettingsUpdate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78174,15 +78627,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &DiscoveryConfigDelete{} + v := &AccessGraphSettingsUpdate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_DiscoveryConfigDelete{v} + m.Event = &OneOf_AccessGraphSettingsUpdate{v} iNdEx = postIndex - case 163: + case 165: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DiscoveryConfigDeleteAll", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IntegrationCreate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78209,15 +78662,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &DiscoveryConfigDeleteAll{} + v := &IntegrationCreate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_DiscoveryConfigDeleteAll{v} + m.Event = &OneOf_IntegrationCreate{v} iNdEx = postIndex - case 164: + case 166: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AccessGraphSettingsUpdate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IntegrationUpdate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78244,15 +78697,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &AccessGraphSettingsUpdate{} + v := &IntegrationUpdate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_AccessGraphSettingsUpdate{v} + m.Event = &OneOf_IntegrationUpdate{v} iNdEx = postIndex - case 165: + case 167: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IntegrationCreate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IntegrationDelete", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78279,15 +78732,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &IntegrationCreate{} + v := &IntegrationDelete{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_IntegrationCreate{v} + m.Event = &OneOf_IntegrationDelete{v} iNdEx = postIndex - case 166: + case 168: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IntegrationUpdate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SPIFFEFederationCreate", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78314,15 +78767,15 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &IntegrationUpdate{} + v := &SPIFFEFederationCreate{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_IntegrationUpdate{v} + m.Event = &OneOf_SPIFFEFederationCreate{v} iNdEx = postIndex - case 167: + case 169: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IntegrationDelete", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SPIFFEFederationDelete", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78349,11 +78802,11 @@ func (m *OneOf) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - v := &IntegrationDelete{} + v := &SPIFFEFederationDelete{} if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } - m.Event = &OneOf_IntegrationDelete{v} + m.Event = &OneOf_SPIFFEFederationDelete{v} iNdEx = postIndex default: iNdEx = preIndex @@ -79866,6 +80319,38 @@ func (m *RouteToApp) Unmarshal(dAtA []byte) error { } m.GCPServiceAccount = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field URI", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.URI = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -93376,13 +93861,224 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.SPIFFEID = string(dAtA[iNdEx:postIndex]) + m.SPIFFEID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DNSSANs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DNSSANs = append(m.DNSSANs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IPSANs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IPSANs = append(m.IPSANs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SVIDType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SVIDType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SerialNumber", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SerialNumber = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hint = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AuthPreferenceUpdate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AuthPreferenceUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AuthPreferenceUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DNSSANs", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -93392,29 +94088,30 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.DNSSANs = append(m.DNSSANs, string(dAtA[iNdEx:postIndex])) + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 6: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IPSANs", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -93424,29 +94121,30 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.IPSANs = append(m.IPSANs, string(dAtA[iNdEx:postIndex])) + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 7: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SVIDType", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -93456,29 +94154,30 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.SVIDType = string(dAtA[iNdEx:postIndex]) + if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 8: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SerialNumber", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -93488,29 +94187,30 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.SerialNumber = string(dAtA[iNdEx:postIndex]) + if err := m.ConnectionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hint", wireType) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdminActionsMFA", wireType) } - var stringLen uint64 + m.AdminActionsMFA = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -93520,24 +94220,11 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.AdminActionsMFA |= AdminActionsMFAStatus(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Hint = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -93560,7 +94247,7 @@ func (m *SPIFFESVIDIssued) Unmarshal(dAtA []byte) error { } return nil } -func (m *AuthPreferenceUpdate) Unmarshal(dAtA []byte) error { +func (m *ClusterNetworkingConfigUpdate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -93583,10 +94270,10 @@ func (m *AuthPreferenceUpdate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AuthPreferenceUpdate: wiretype end group for non-group") + return fmt.Errorf("proto: ClusterNetworkingConfigUpdate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AuthPreferenceUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ClusterNetworkingConfigUpdate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -93721,25 +94408,6 @@ func (m *AuthPreferenceUpdate) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AdminActionsMFA", wireType) - } - m.AdminActionsMFA = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.AdminActionsMFA |= AdminActionsMFAStatus(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -93762,7 +94430,7 @@ func (m *AuthPreferenceUpdate) Unmarshal(dAtA []byte) error { } return nil } -func (m *ClusterNetworkingConfigUpdate) Unmarshal(dAtA []byte) error { +func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -93785,10 +94453,10 @@ func (m *ClusterNetworkingConfigUpdate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ClusterNetworkingConfigUpdate: wiretype end group for non-group") + return fmt.Errorf("proto: SessionRecordingConfigUpdate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ClusterNetworkingConfigUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SessionRecordingConfigUpdate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -93945,7 +94613,7 @@ func (m *ClusterNetworkingConfigUpdate) Unmarshal(dAtA []byte) error { } return nil } -func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { +func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -93968,10 +94636,10 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SessionRecordingConfigUpdate: wiretype end group for non-group") + return fmt.Errorf("proto: AccessPathChanged: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SessionRecordingConfigUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AccessPathChanged: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -94009,9 +94677,9 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChangeID", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94021,30 +94689,29 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ChangeID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceName", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94054,30 +94721,29 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.AffectedResourceName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConnectionMetadata", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceSource", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94087,24 +94753,55 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ConnectionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.AffectedResourceSource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF } + m.AffectedResourceType = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -94128,7 +94825,7 @@ func (m *SessionRecordingConfigUpdate) Unmarshal(dAtA []byte) error { } return nil } -func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { +func (m *SpannerRPC) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -94151,10 +94848,10 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AccessPathChanged: wiretype end group for non-group") + return fmt.Errorf("proto: SpannerRPC: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AccessPathChanged: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SpannerRPC: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -94192,9 +94889,9 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChangeID", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94204,29 +94901,30 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChangeID = string(dAtA[iNdEx:postIndex]) + if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceName", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SessionMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94236,29 +94934,30 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.AffectedResourceName = string(dAtA[iNdEx:postIndex]) + if err := m.SessionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceSource", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DatabaseMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94268,27 +94967,61 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.AffectedResourceSource = string(dAtA[iNdEx:postIndex]) + if err := m.DatabaseMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AffectedResourceType", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Procedure", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -94316,7 +95049,43 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AffectedResourceType = string(dAtA[iNdEx:postIndex]) + m.Procedure = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Args", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Args == nil { + m.Args = &Struct{} + } + if err := m.Args.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -94340,7 +95109,7 @@ func (m *AccessPathChanged) Unmarshal(dAtA []byte) error { } return nil } -func (m *SpannerRPC) Unmarshal(dAtA []byte) error { +func (m *AccessGraphSettingsUpdate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -94363,10 +95132,10 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: SpannerRPC: wiretype end group for non-group") + return fmt.Errorf("proto: AccessGraphSettingsUpdate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: SpannerRPC: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AccessGraphSettingsUpdate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -94404,7 +95173,7 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94431,13 +95200,13 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SessionMetadata", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94464,13 +95233,13 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.SessionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DatabaseMetadata", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionMetadata", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94497,13 +95266,64 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.DatabaseMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ConnectionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 5: + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SPIFFEFederationCreate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SPIFFEFederationCreate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SPIFFEFederationCreate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94530,15 +95350,15 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 6: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Procedure", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ResourceMetadata", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -94548,27 +95368,28 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.Procedure = string(dAtA[iNdEx:postIndex]) + if err := m.ResourceMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 7: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Args", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field UserMetadata", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94595,10 +95416,40 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Args == nil { - m.Args = &Struct{} + if err := m.UserMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - if err := m.Args.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ConnectionMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -94624,7 +95475,7 @@ func (m *SpannerRPC) Unmarshal(dAtA []byte) error { } return nil } -func (m *AccessGraphSettingsUpdate) Unmarshal(dAtA []byte) error { +func (m *SPIFFEFederationDelete) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -94647,10 +95498,10 @@ func (m *AccessGraphSettingsUpdate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AccessGraphSettingsUpdate: wiretype end group for non-group") + return fmt.Errorf("proto: SPIFFEFederationDelete: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AccessGraphSettingsUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: SPIFFEFederationDelete: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -94688,7 +95539,7 @@ func (m *AccessGraphSettingsUpdate) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ResourceMetadata", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -94715,7 +95566,7 @@ func (m *AccessGraphSettingsUpdate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ResourceMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/api/types/events/oneof.go b/api/types/events/oneof.go index 5ea72a16c63e1..b3221e54a0e9e 100644 --- a/api/types/events/oneof.go +++ b/api/types/events/oneof.go @@ -704,6 +704,14 @@ func ToOneOf(in AuditEvent) (*OneOf, error) { out.Event = &OneOf_IntegrationDelete{ IntegrationDelete: e, } + case *SPIFFEFederationCreate: + out.Event = &OneOf_SPIFFEFederationCreate{ + SPIFFEFederationCreate: e, + } + case *SPIFFEFederationDelete: + out.Event = &OneOf_SPIFFEFederationDelete{ + SPIFFEFederationDelete: e, + } default: slog.ErrorContext(context.Background(), "Attempted to convert dynamic event of unknown type into protobuf event.", "event_type", in.GetType()) unknown := &Unknown{} diff --git a/api/types/license.go b/api/types/license.go index 9b1419f8b49fc..b255b921ee4db 100644 --- a/api/types/license.go +++ b/api/types/license.go @@ -105,7 +105,7 @@ type License interface { // GetSupportsFeatureHiding returns feature hiding support flag. GetSupportsFeatureHiding() Bool - // GetSupportsFeatureHiding sets feature hiding support flag. + // SetSupportsFeatureHiding sets feature hiding support flag. SetSupportsFeatureHiding(Bool) // GetTrial returns the trial flag. @@ -156,8 +156,24 @@ type License interface { // GetSupportsPolicy returns Teleport Policy support flag. GetSupportsPolicy() Bool - //SGetSupportsPolicy sets Teleport Policy support flag. + // SetSupportsPolicy sets Teleport Policy support flag. SetSupportsPolicy(Bool) + + // GetEntitlements returns the Entitlements object + GetEntitlements() map[string]EntitlementInfo + // SetEntitlements sets the Entitlements object + SetEntitlements(map[string]EntitlementInfo) +} + +// EntitlementInfo is the state and limits of a particular entitlement; Example for feature X: +// { Enabled: true, Limit: 0 } => unlimited access to feature X +// { Enabled: true, Limit: >0 } => limited access to feature X +// { Enabled: false, Limit: >=0 } => no access to feature X +type EntitlementInfo struct { + // Enabled indicates the feature is 'on' if true; feature is disabled if false + Enabled Bool + // Limit indicates the allotted amount of use when limited; if 0 use is unlimited + Limit int32 } // FeatureSource defines where the list of features enabled @@ -494,6 +510,16 @@ func (c *LicenseV3) SetSupportsPolicy(value Bool) { c.Spec.SupportsPolicy = value } +// GetEntitlements returns Entitlements +func (c *LicenseV3) GetEntitlements() map[string]EntitlementInfo { + return c.Spec.Entitlements +} + +// SetEntitlements sets Entitlements +func (c *LicenseV3) SetEntitlements(value map[string]EntitlementInfo) { + c.Spec.Entitlements = value +} + // String represents a human readable version of license enabled features func (c *LicenseV3) String() string { var features []string @@ -601,4 +627,7 @@ type LicenseSpecV3 struct { AnonymizationKey string `json:"anonymization_key,omitempty"` // SupportsPolicy turns Teleport Policy features on or off. SupportsPolicy Bool `json:"policy,omitempty"` + + // entitlements define a customer’s access to a specific features + Entitlements map[string]EntitlementInfo `json:"entitlements,omitempty"` } diff --git a/api/types/matchers_accessgraph.go b/api/types/matchers_accessgraph.go index b76e8bc494eda..2ba6961c88680 100644 --- a/api/types/matchers_accessgraph.go +++ b/api/types/matchers_accessgraph.go @@ -18,6 +18,8 @@ package types import ( "github.com/gravitational/trace" + + awsapiutils "github.com/gravitational/teleport/api/utils/aws" ) // CheckAndSetDefaults that the matcher is correct and adds default values. @@ -34,5 +36,11 @@ func (a *AccessGraphAWSSync) CheckAndSetDefaults() error { if len(a.Regions) == 0 { return trace.BadParameter("discovery service requires at least one region") } + + for _, region := range a.Regions { + if err := awsapiutils.IsValidRegion(region); err != nil { + return trace.BadParameter("discovery service does not support region %q", region) + } + } return nil } diff --git a/api/types/oidc.go b/api/types/oidc.go index a5a498bc425ba..d80da8a72f33f 100644 --- a/api/types/oidc.go +++ b/api/types/oidc.go @@ -17,6 +17,7 @@ limitations under the License. package types import ( + "net/netip" "net/url" "slices" "time" @@ -35,6 +36,11 @@ type OIDCConnector interface { // ResourceWithSecrets provides common methods for objects ResourceWithSecrets ResourceWithOrigin + // Validate will preform checks not found in CheckAndSetDefaults + // that should only be preformed when the OIDC connector resource + // itself is being created or updated, not when a OIDCConnector + // object is being created or updated. + Validate() error // Issuer URL is the endpoint of the provider, e.g. https://accounts.google.com GetIssuerURL() string // ClientID is id for authentication client (in our case it's our Auth server) @@ -449,6 +455,23 @@ func (o *OIDCConnectorV3) CheckAndSetDefaults() error { return nil } +// Validate will preform checks not found in CheckAndSetDefaults +// that should only be preformed when the OIDC connector resource +// itself is being created or updated, not when a OIDCConnector +// object is being created or updated. +func (o *OIDCConnectorV3) Validate() error { + if o.Spec.ClientRedirectSettings != nil { + for _, cidrStr := range o.Spec.ClientRedirectSettings.InsecureAllowedCidrRanges { + _, err := netip.ParsePrefix(cidrStr) + if err != nil { + return trace.BadParameter("bad CIDR range in insecure_allowed_cidr_ranges '%s': %v", cidrStr, err) + } + } + } + + return nil +} + // GetAllowUnverifiedEmail returns true if unverified emails should be allowed in received users. func (o *OIDCConnectorV3) GetAllowUnverifiedEmail() bool { return o.Spec.AllowUnverifiedEmail diff --git a/api/types/types.pb.go b/api/types/types.pb.go index 1b5939c90c4e0..0ea2c9c4f96b8 100644 --- a/api/types/types.pb.go +++ b/api/types/types.pb.go @@ -9,12 +9,12 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/types" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" github_com_gravitational_teleport_api_constants "github.com/gravitational/teleport/api/constants" v1 "github.com/gravitational/teleport/api/gen/proto/go/attestation/v1" _ "github.com/gravitational/teleport/api/types/wrappers" github_com_gravitational_teleport_api_types_wrappers "github.com/gravitational/teleport/api/types/wrappers" - _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" @@ -8622,6 +8622,13 @@ type UserSpecV2 struct { // authentication LocalAuth *LocalAuthSecrets `protobuf:"bytes,9,opt,name=LocalAuth,proto3" json:"local_auth,omitempty"` // TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. + // + // Note that SSO users are transient and thus may contain an empty + // TrustedDeviceIDs field, even though the user->device association exists + // under the Device Trust subsystem. Do not rely on this field to determine + // device associations or ownership, it exists for legacy/informative purposes + // only. + // // Managed by the Device Trust subsystem, avoid manual edits. TrustedDeviceIDs []string `protobuf:"bytes,10,rep,name=TrustedDeviceIDs,proto3" json:"trusted_device_ids,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -9825,9 +9832,6 @@ type WebSessionSpecV2 struct { // // If during login a device is required and DeviceWebToken is nil, then it's // likely the user needs to enroll their device to avoid impacting access. - // - // Transient, only set in certain situations (such as the initial session - // returned during login). TrustedDeviceRequirement TrustedDeviceRequirement `protobuf:"varint,14,opt,name=TrustedDeviceRequirement,proto3,enum=types.TrustedDeviceRequirement" json:"trusted_device_requirement,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -11410,9 +11414,11 @@ var xxx_messageInfo_MaxAge proto.InternalMessageInfo type SSOClientRedirectSettings struct { // a list of hostnames allowed for https client redirect URLs AllowedHttpsHostnames []string `protobuf:"bytes,1,rep,name=allowed_https_hostnames,json=allowedHttpsHostnames,proto3" json:"allowed_https_hostnames,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + // a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + InsecureAllowedCidrRanges []string `protobuf:"bytes,2,rep,name=insecure_allowed_cidr_ranges,json=insecureAllowedCidrRanges,proto3" json:"insecure_allowed_cidr_ranges,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *SSOClientRedirectSettings) Reset() { *m = SSOClientRedirectSettings{} } @@ -12073,7 +12079,10 @@ type GithubAuthRequest struct { // attestation_statement is an attestation statement for the given public key. AttestationStatement *v1.AttestationStatement `protobuf:"bytes,16,opt,name=attestation_statement,json=attestationStatement,proto3" json:"attestation_statement,omitempty"` // ClientLoginIP specifies IP address of the client for login, it will be written to the user's certificates. - ClientLoginIP string `protobuf:"bytes,17,opt,name=ClientLoginIP,proto3" json:"client_login_ip,omitempty"` + ClientLoginIP string `protobuf:"bytes,17,opt,name=ClientLoginIP,proto3" json:"client_login_ip,omitempty"` + // ClientUserAgent is the user agent of the Web browser, used for issuing + // a DeviceWebToken. + ClientUserAgent string `protobuf:"bytes,18,opt,name=ClientUserAgent,proto3" json:"client_user_agent,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -19285,1658 +19294,1663 @@ func init() { func init() { proto.RegisterFile("teleport/legacy/types/types.proto", fileDescriptor_9198ee693835762e) } var fileDescriptor_9198ee693835762e = []byte{ - // 26408 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6b, 0x70, 0x1c, 0x49, - 0x7a, 0x20, 0x36, 0xfd, 0x00, 0xd0, 0xf8, 0xf0, 0x6a, 0x24, 0x40, 0x12, 0xe4, 0x90, 0x03, 0x4e, - 0x71, 0x86, 0x43, 0xce, 0x83, 0x5c, 0x82, 0x3b, 0xdc, 0x9d, 0x9d, 0x67, 0xa3, 0x1b, 0x24, 0x9a, - 0x04, 0x01, 0x6c, 0x35, 0x08, 0xec, 0x68, 0x76, 0xb7, 0xb6, 0xd0, 0x9d, 0x00, 0x6a, 0xd0, 0xdd, - 0xd5, 0x5b, 0x55, 0x4d, 0x10, 0xab, 0x3b, 0x6b, 0x25, 0x9d, 0x6e, 0x2d, 0xdf, 0xe9, 0xe5, 0x5b, - 0x59, 0x7b, 0x0e, 0x9d, 0x42, 0x21, 0xdf, 0x9d, 0xe5, 0xc7, 0x29, 0x1c, 0x92, 0x2e, 0x7c, 0x0e, - 0x85, 0xe5, 0x93, 0x43, 0x56, 0xc8, 0x72, 0x9c, 0x2d, 0x87, 0xdf, 0x6b, 0x05, 0x64, 0x59, 0x17, - 0x17, 0x0e, 0x86, 0xed, 0xd0, 0x59, 0x8e, 0x0b, 0x7b, 0x1c, 0xb2, 0x1d, 0xf9, 0x65, 0x66, 0x55, - 0x66, 0x55, 0x75, 0xa3, 0x31, 0xc3, 0x39, 0x89, 0x63, 0xff, 0x21, 0xd1, 0x5f, 0x7e, 0xdf, 0x97, - 0xcf, 0xca, 0xfc, 0xf2, 0xcb, 0xef, 0x01, 0xcf, 0x07, 0xb4, 0x49, 0x3b, 0xae, 0x17, 0x5c, 0x6f, - 0xd2, 0x5d, 0xbb, 0x7e, 0x78, 0x3d, 0x38, 0xec, 0x50, 0x9f, 0xff, 0x7b, 0xad, 0xe3, 0xb9, 0x81, - 0x4b, 0x86, 0xf0, 0xc7, 0xb9, 0xd9, 0x5d, 0x77, 0xd7, 0x45, 0xc8, 0x75, 0xf6, 0x17, 0x2f, 0x3c, - 0x37, 0xbf, 0xeb, 0xba, 0xbb, 0x4d, 0x7a, 0x1d, 0x7f, 0x6d, 0x77, 0x77, 0xae, 0x07, 0x4e, 0x8b, - 0xfa, 0x81, 0xdd, 0xea, 0x08, 0x84, 0xab, 0x61, 0x05, 0x76, 0x10, 0xb0, 0x92, 0xc0, 0x71, 0xdb, - 0xd7, 0x1f, 0xde, 0x50, 0x7f, 0x0a, 0xd4, 0xd7, 0xd2, 0xdb, 0x72, 0xe0, 0xd9, 0x9d, 0x0e, 0xf5, - 0xa2, 0x3f, 0x38, 0xba, 0xf1, 0x0b, 0x39, 0x18, 0xbd, 0x47, 0x69, 0xa7, 0xd4, 0x74, 0x1e, 0x52, - 0x72, 0x09, 0xf2, 0xab, 0x76, 0x8b, 0xce, 0x65, 0x2e, 0x66, 0xae, 0x8c, 0x2e, 0x4e, 0x3d, 0x3e, - 0x9a, 0x1f, 0xf3, 0xa9, 0xf7, 0x90, 0x7a, 0x56, 0xdb, 0x6e, 0x51, 0x13, 0x0b, 0xc9, 0x2b, 0x30, - 0xca, 0xfe, 0xf7, 0x3b, 0x76, 0x9d, 0xce, 0x65, 0x11, 0x73, 0xe2, 0xf1, 0xd1, 0xfc, 0x68, 0x5b, - 0x02, 0xcd, 0xa8, 0x9c, 0x54, 0x61, 0x64, 0xe9, 0x51, 0xc7, 0xf1, 0xa8, 0x3f, 0x97, 0xbf, 0x98, - 0xb9, 0x32, 0xb6, 0x70, 0xee, 0x1a, 0xef, 0xec, 0x35, 0xd9, 0xd9, 0x6b, 0x1b, 0xb2, 0xb3, 0x8b, - 0x33, 0xbf, 0x7b, 0x34, 0xff, 0xcc, 0xe3, 0xa3, 0xf9, 0x11, 0xca, 0x49, 0x7e, 0xfa, 0x0f, 0xe7, - 0x33, 0xa6, 0xa4, 0x27, 0x6f, 0x41, 0x7e, 0xe3, 0xb0, 0x43, 0xe7, 0x46, 0x2f, 0x66, 0xae, 0x4c, - 0x2e, 0x3c, 0x77, 0x8d, 0x0f, 0x6f, 0xd8, 0xf8, 0xe8, 0x2f, 0x86, 0xb5, 0x58, 0x78, 0x7c, 0x34, - 0x9f, 0x67, 0x28, 0x26, 0x52, 0x91, 0xd7, 0x60, 0x78, 0xd9, 0xf5, 0x83, 0x6a, 0x65, 0x0e, 0xb0, - 0xc9, 0xa7, 0x1e, 0x1f, 0xcd, 0x4f, 0xef, 0xb9, 0x7e, 0x60, 0x39, 0x8d, 0x57, 0xdd, 0x96, 0x13, - 0xd0, 0x56, 0x27, 0x38, 0x34, 0x05, 0x92, 0xf1, 0x08, 0x26, 0x34, 0x7e, 0x64, 0x0c, 0x46, 0x1e, - 0xac, 0xde, 0x5b, 0x5d, 0xdb, 0x5a, 0x2d, 0x3e, 0x43, 0x0a, 0x90, 0x5f, 0x5d, 0xab, 0x2c, 0x15, - 0x33, 0x64, 0x04, 0x72, 0xa5, 0xf5, 0xf5, 0x62, 0x96, 0x8c, 0x43, 0xa1, 0x52, 0xda, 0x28, 0x2d, - 0x96, 0x6a, 0x4b, 0xc5, 0x1c, 0x99, 0x81, 0xa9, 0xad, 0xea, 0x6a, 0x65, 0x6d, 0xab, 0x66, 0x55, - 0x96, 0x6a, 0xf7, 0x36, 0xd6, 0xd6, 0x8b, 0x79, 0x32, 0x09, 0x70, 0xef, 0xc1, 0xe2, 0x92, 0xb9, - 0xba, 0xb4, 0xb1, 0x54, 0x2b, 0x0e, 0x91, 0x59, 0x28, 0x4a, 0x12, 0xab, 0xb6, 0x64, 0x6e, 0x56, - 0xcb, 0x4b, 0xc5, 0xe1, 0xbb, 0xf9, 0x42, 0xae, 0x98, 0x37, 0x47, 0x56, 0xa8, 0xed, 0xd3, 0x6a, - 0xc5, 0xf8, 0xd7, 0x72, 0x50, 0xb8, 0x4f, 0x03, 0xbb, 0x61, 0x07, 0x36, 0x39, 0xaf, 0xcd, 0x0f, - 0x76, 0x51, 0x99, 0x98, 0x4b, 0xc9, 0x89, 0x19, 0x7a, 0x7c, 0x34, 0x9f, 0x79, 0x4d, 0x9d, 0x90, - 0x37, 0x61, 0xac, 0x42, 0xfd, 0xba, 0xe7, 0x74, 0xd8, 0xa2, 0x99, 0xcb, 0x21, 0xda, 0xd9, 0xc7, - 0x47, 0xf3, 0xa7, 0x1a, 0x11, 0x58, 0x19, 0x10, 0x15, 0x9b, 0x54, 0x61, 0x78, 0xc5, 0xde, 0xa6, - 0x4d, 0x7f, 0x6e, 0xe8, 0x62, 0xee, 0xca, 0xd8, 0xc2, 0xb3, 0x62, 0x12, 0x64, 0x03, 0xaf, 0xf1, - 0xd2, 0xa5, 0x76, 0xe0, 0x1d, 0x2e, 0xce, 0x3e, 0x3e, 0x9a, 0x2f, 0x36, 0x11, 0xa0, 0x0e, 0x30, - 0x47, 0x21, 0xb5, 0x68, 0x61, 0x0c, 0x1f, 0xbb, 0x30, 0x2e, 0xfc, 0xee, 0xd1, 0x7c, 0x86, 0x4d, - 0x98, 0x58, 0x18, 0x11, 0x3f, 0x7d, 0x89, 0x2c, 0x40, 0xc1, 0xa4, 0x0f, 0x1d, 0x9f, 0xf5, 0xac, - 0x80, 0x3d, 0x3b, 0xfd, 0xf8, 0x68, 0x9e, 0x78, 0x02, 0xa6, 0x34, 0x23, 0xc4, 0x3b, 0xf7, 0x06, - 0x8c, 0x29, 0xad, 0x26, 0x45, 0xc8, 0xed, 0xd3, 0x43, 0x3e, 0xc2, 0x26, 0xfb, 0x93, 0xcc, 0xc2, - 0xd0, 0x43, 0xbb, 0xd9, 0x15, 0x43, 0x6a, 0xf2, 0x1f, 0x5f, 0xca, 0x7e, 0x31, 0x73, 0x37, 0x5f, - 0x18, 0x29, 0x16, 0xcc, 0x6c, 0xb5, 0x62, 0xfc, 0xcb, 0x79, 0x28, 0x98, 0x2e, 0xff, 0x10, 0xc9, - 0x55, 0x18, 0xaa, 0x05, 0x76, 0x20, 0xa7, 0x69, 0xe6, 0xf1, 0xd1, 0xfc, 0x14, 0xfb, 0x48, 0xa9, - 0x52, 0x3f, 0xc7, 0x60, 0xa8, 0xeb, 0x7b, 0xb6, 0x2f, 0xa7, 0x0b, 0x51, 0x3b, 0x0c, 0xa0, 0xa2, - 0x22, 0x06, 0xb9, 0x0c, 0xf9, 0xfb, 0x6e, 0x83, 0x8a, 0x19, 0x23, 0x8f, 0x8f, 0xe6, 0x27, 0x5b, - 0x6e, 0x43, 0x45, 0xc4, 0x72, 0xf2, 0x2a, 0x8c, 0x96, 0xbb, 0x9e, 0x47, 0xdb, 0x6c, 0xad, 0xe7, - 0x11, 0x79, 0xf2, 0xf1, 0xd1, 0x3c, 0xd4, 0x39, 0xd0, 0x72, 0x1a, 0x66, 0x84, 0xc0, 0xa6, 0xa1, - 0x16, 0xd8, 0x5e, 0x40, 0x1b, 0x73, 0x43, 0x03, 0x4d, 0x03, 0xfb, 0x3e, 0xa7, 0x7d, 0x4e, 0x12, - 0x9f, 0x06, 0xc1, 0x89, 0x2c, 0xc3, 0xd8, 0x1d, 0xcf, 0xae, 0xd3, 0x75, 0xea, 0x39, 0x6e, 0x03, - 0xe7, 0x37, 0xb7, 0x78, 0xf9, 0xf1, 0xd1, 0xfc, 0xe9, 0x5d, 0x06, 0xb6, 0x3a, 0x08, 0x8f, 0xa8, - 0x3f, 0x3a, 0x9a, 0x2f, 0x54, 0xba, 0x1e, 0x8e, 0x9e, 0xa9, 0x92, 0x92, 0x6f, 0xb0, 0xc9, 0xf1, - 0x03, 0x1c, 0x5a, 0xda, 0x98, 0x1b, 0x39, 0xb6, 0x89, 0x86, 0x68, 0xe2, 0xe9, 0xa6, 0xed, 0x07, - 0x96, 0xc7, 0xe9, 0x62, 0xed, 0x54, 0x59, 0x92, 0x35, 0x28, 0xd4, 0xea, 0x7b, 0xb4, 0xd1, 0x6d, - 0x52, 0x5c, 0x32, 0x63, 0x0b, 0x67, 0xc4, 0xa2, 0x96, 0xf3, 0x29, 0x8b, 0x17, 0xcf, 0x09, 0xde, - 0xc4, 0x17, 0x10, 0x75, 0x3d, 0x49, 0xac, 0x2f, 0x15, 0xbe, 0xf7, 0x8b, 0xf3, 0xcf, 0x7c, 0xfb, - 0x0f, 0x2e, 0x3e, 0x63, 0xfc, 0xbb, 0x59, 0x28, 0xc6, 0x99, 0x90, 0x1d, 0x98, 0x78, 0xd0, 0x69, - 0xd8, 0x01, 0x2d, 0x37, 0x1d, 0xda, 0x0e, 0x7c, 0x5c, 0x24, 0xfd, 0xfb, 0xf4, 0x82, 0xa8, 0x77, - 0xae, 0x8b, 0x84, 0x56, 0x9d, 0x53, 0xc6, 0x7a, 0xa5, 0xb3, 0x8d, 0xea, 0xa9, 0xe1, 0x06, 0xee, - 0xe3, 0x0a, 0x3b, 0x59, 0x3d, 0x7c, 0xeb, 0xef, 0x51, 0x8f, 0x60, 0x2b, 0x16, 0x50, 0xbb, 0xb1, - 0x7d, 0x88, 0x2b, 0x73, 0xf0, 0x05, 0xc4, 0x48, 0x52, 0x16, 0x10, 0x03, 0x1b, 0xff, 0x38, 0x03, - 0x93, 0x26, 0xf5, 0xdd, 0xae, 0x57, 0xa7, 0xcb, 0xd4, 0x6e, 0x50, 0x8f, 0x2d, 0xff, 0x7b, 0x4e, - 0xbb, 0x21, 0xbe, 0x29, 0x5c, 0xfe, 0xfb, 0x4e, 0x5b, 0xdd, 0xba, 0xb1, 0x9c, 0x7c, 0x0e, 0x46, - 0x6a, 0xdd, 0x6d, 0x44, 0xcd, 0x46, 0x3b, 0x80, 0xdf, 0xdd, 0xb6, 0x62, 0xe8, 0x12, 0x8d, 0x5c, - 0x87, 0x91, 0x4d, 0xea, 0xf9, 0xd1, 0x6e, 0x88, 0x47, 0xc3, 0x43, 0x0e, 0x52, 0x09, 0x04, 0x16, - 0xb9, 0x13, 0xed, 0xc8, 0xe2, 0x50, 0x9b, 0x8a, 0xed, 0x83, 0xd1, 0x52, 0x69, 0x09, 0x88, 0xba, - 0x54, 0x24, 0x96, 0xf1, 0x33, 0x59, 0x28, 0x56, 0xec, 0xc0, 0xde, 0xb6, 0x7d, 0x31, 0x9e, 0x9b, - 0x37, 0xd9, 0x1e, 0xaf, 0x74, 0x14, 0xf7, 0x78, 0xd6, 0xf2, 0x8f, 0xdd, 0xbd, 0x17, 0xe3, 0xdd, - 0x1b, 0x63, 0x27, 0xac, 0xe8, 0x5e, 0xd4, 0xa9, 0xb7, 0x8f, 0xef, 0x54, 0x51, 0x74, 0xaa, 0x20, - 0x3b, 0x15, 0x75, 0x85, 0xbc, 0x0d, 0xf9, 0x5a, 0x87, 0xd6, 0xc5, 0x26, 0x22, 0xcf, 0x05, 0xbd, - 0x73, 0x0c, 0x61, 0xf3, 0xe6, 0xe2, 0xb8, 0x60, 0x93, 0xf7, 0x3b, 0xb4, 0x6e, 0x22, 0x99, 0xf2, - 0xd1, 0xfc, 0x83, 0x1c, 0xcc, 0xa6, 0x91, 0xa9, 0xfd, 0x18, 0xee, 0xd3, 0x8f, 0x2b, 0x50, 0x60, - 0x47, 0x38, 0x3b, 0x16, 0x71, 0xbb, 0x18, 0x5d, 0x1c, 0x67, 0x4d, 0xde, 0x13, 0x30, 0x33, 0x2c, - 0x25, 0x97, 0x42, 0x89, 0xa0, 0x10, 0xf1, 0x13, 0x12, 0x81, 0x94, 0x03, 0xd8, 0x5c, 0xcb, 0x4f, - 0x18, 0x05, 0x87, 0x68, 0x58, 0x24, 0x38, 0x9a, 0x6b, 0x4f, 0x40, 0xb4, 0x63, 0x46, 0x1e, 0x0a, - 0x4b, 0x50, 0x90, 0xdd, 0x9a, 0x1b, 0x47, 0x46, 0xd3, 0xb1, 0x41, 0xda, 0xbc, 0xc9, 0x27, 0xb3, - 0x21, 0x7e, 0xab, 0x6c, 0x24, 0x0e, 0xb9, 0x09, 0x85, 0x75, 0xcf, 0x7d, 0x74, 0x58, 0xad, 0xf8, - 0x73, 0x13, 0x17, 0x73, 0x57, 0x46, 0x17, 0xcf, 0x3c, 0x3e, 0x9a, 0x9f, 0xe9, 0x30, 0x98, 0xe5, - 0x34, 0xd4, 0x93, 0x36, 0x44, 0xbc, 0x9b, 0x2f, 0x64, 0x8a, 0xd9, 0xbb, 0xf9, 0x42, 0xb6, 0x98, - 0xe3, 0xe2, 0xc5, 0xdd, 0x7c, 0x21, 0x5f, 0x1c, 0xba, 0x9b, 0x2f, 0x0c, 0xa1, 0xc0, 0x31, 0x5a, - 0x84, 0xbb, 0xf9, 0xc2, 0x58, 0x71, 0x5c, 0x3b, 0xed, 0x91, 0x41, 0xe0, 0xd6, 0xdd, 0xa6, 0x99, - 0x7b, 0x60, 0x56, 0xcd, 0xe1, 0x72, 0xa9, 0x4c, 0xbd, 0xc0, 0xcc, 0x95, 0xb6, 0x6a, 0xe6, 0x44, - 0xe5, 0xb0, 0x6d, 0xb7, 0x9c, 0x3a, 0x3f, 0x3a, 0xcd, 0xdc, 0x9d, 0xf2, 0xba, 0x51, 0x82, 0xc9, - 0xa8, 0x2f, 0x2b, 0x8e, 0x1f, 0x90, 0xeb, 0x30, 0x2a, 0x21, 0x6c, 0xa3, 0xcb, 0xa5, 0xf6, 0xda, - 0x8c, 0x70, 0x8c, 0xdf, 0xc9, 0x02, 0x44, 0x25, 0x4f, 0xe9, 0xb7, 0xf0, 0x05, 0xed, 0x5b, 0x38, - 0x15, 0xff, 0x16, 0x7a, 0x7e, 0x05, 0xe4, 0x5d, 0x18, 0x66, 0x62, 0x41, 0x57, 0x8a, 0x44, 0x67, - 0xe2, 0xa4, 0x58, 0xb8, 0x79, 0x73, 0x71, 0x52, 0x10, 0x0f, 0xfb, 0x08, 0x31, 0x05, 0x99, 0xf2, - 0x19, 0xfd, 0xc2, 0x48, 0x34, 0x19, 0xe2, 0x03, 0xba, 0x02, 0xe1, 0x84, 0x8a, 0x01, 0xc5, 0x2f, - 0xa3, 0x23, 0x27, 0x39, 0x2c, 0x25, 0x67, 0x81, 0x4d, 0xb8, 0x18, 0xd4, 0x91, 0xc7, 0x47, 0xf3, - 0xb9, 0xae, 0xe7, 0xe0, 0x22, 0x20, 0xd7, 0x41, 0x2c, 0x03, 0x31, 0x80, 0x6c, 0xf5, 0x4d, 0xd7, - 0x6d, 0xab, 0x4e, 0xbd, 0x20, 0x1a, 0xf1, 0xb9, 0x8c, 0x5c, 0x2d, 0xa4, 0x03, 0xfa, 0x52, 0x99, - 0xcb, 0xe3, 0x32, 0xb8, 0x92, 0x3a, 0x2a, 0xd7, 0x34, 0x54, 0x2e, 0x46, 0x5e, 0x94, 0xa7, 0x52, - 0x83, 0x97, 0x59, 0x09, 0x91, 0x52, 0xaf, 0x80, 0xdc, 0x04, 0xb6, 0x42, 0xc5, 0xe8, 0x83, 0xa8, - 0xa7, 0xb4, 0x55, 0x5b, 0x3c, 0x25, 0x38, 0x4d, 0xd8, 0x07, 0x2a, 0x39, 0xc3, 0x26, 0x6f, 0x02, - 0x5b, 0xc2, 0x62, 0xdc, 0x89, 0x20, 0xba, 0x53, 0x5e, 0x2f, 0x37, 0xdd, 0x6e, 0xa3, 0xf6, 0xe5, - 0x95, 0x88, 0x78, 0xb7, 0xde, 0x51, 0x89, 0xef, 0x94, 0xd7, 0xc9, 0x9b, 0x30, 0x54, 0xfa, 0x56, - 0xd7, 0xa3, 0x42, 0x3e, 0x19, 0x97, 0x75, 0x32, 0xd8, 0xe2, 0x19, 0x41, 0x38, 0x65, 0xb3, 0x9f, - 0xaa, 0x5c, 0x87, 0xe5, 0xac, 0xe6, 0x8d, 0x95, 0x9a, 0x90, 0x3d, 0x48, 0x6c, 0x58, 0x36, 0x56, - 0x94, 0x66, 0x07, 0x5a, 0xaf, 0x19, 0x15, 0xb9, 0x0e, 0xd9, 0x52, 0x05, 0x6f, 0x44, 0x63, 0x0b, - 0xa3, 0xb2, 0xda, 0xca, 0xe2, 0xac, 0x20, 0x19, 0xb7, 0xd5, 0xcf, 0x20, 0x5b, 0xaa, 0x90, 0x45, - 0x18, 0xba, 0x7f, 0x58, 0xfb, 0xf2, 0x8a, 0xd8, 0xcc, 0x66, 0xe4, 0xba, 0x66, 0xb0, 0x35, 0xfc, - 0xec, 0xfd, 0xa8, 0xc5, 0xad, 0x43, 0xff, 0x9b, 0x4d, 0xb5, 0xc5, 0x88, 0x46, 0xd6, 0x61, 0xb4, - 0xd4, 0x68, 0x39, 0xed, 0x07, 0x3e, 0xf5, 0xe6, 0xc6, 0x90, 0xcf, 0x5c, 0xac, 0xdd, 0x61, 0xf9, - 0xe2, 0xdc, 0xe3, 0xa3, 0xf9, 0x59, 0x9b, 0xfd, 0xb4, 0xba, 0x3e, 0xf5, 0x14, 0x6e, 0x11, 0x13, - 0xb2, 0x0e, 0x70, 0xdf, 0x6d, 0xef, 0xba, 0xa5, 0xa0, 0x69, 0xfb, 0xb1, 0xed, 0x31, 0x2a, 0x08, - 0xc5, 0x87, 0x53, 0x2d, 0x06, 0xb3, 0x6c, 0x06, 0x54, 0x18, 0x2a, 0x3c, 0xc8, 0x6d, 0x18, 0x5e, - 0xf3, 0xec, 0x7a, 0x93, 0xce, 0x4d, 0x20, 0xb7, 0x59, 0xc1, 0x8d, 0x03, 0x65, 0x4f, 0xe7, 0x04, - 0xc3, 0xa2, 0x8b, 0x60, 0xf5, 0x9a, 0xc2, 0x11, 0xcf, 0x6d, 0x01, 0x49, 0xae, 0xc9, 0x94, 0x4b, - 0xc2, 0x2b, 0xea, 0x25, 0x21, 0xfa, 0xe8, 0xcb, 0x6e, 0xab, 0x65, 0xb7, 0x1b, 0x48, 0xbb, 0xb9, - 0xa0, 0xdc, 0x1d, 0x8c, 0x6f, 0xc2, 0x74, 0x62, 0xb0, 0x8e, 0xb9, 0xdf, 0xbd, 0x03, 0x53, 0x15, - 0xba, 0x63, 0x77, 0x9b, 0x41, 0x78, 0x92, 0xf0, 0x4f, 0x14, 0x6f, 0x5a, 0x0d, 0x5e, 0x64, 0xc9, - 0xe3, 0xc3, 0x8c, 0x23, 0x1b, 0x6f, 0xc3, 0x84, 0xd6, 0x7d, 0x76, 0x55, 0x28, 0x75, 0x1b, 0x4e, - 0x80, 0x13, 0x99, 0x89, 0xae, 0x0a, 0x36, 0x03, 0xe2, 0x74, 0x99, 0x11, 0x82, 0xf1, 0xb7, 0x55, - 0x69, 0x45, 0xec, 0x44, 0xec, 0x5a, 0x2d, 0xf6, 0x83, 0x4c, 0x24, 0x3b, 0x25, 0xf6, 0x83, 0x70, - 0x37, 0xb8, 0xca, 0xbf, 0xcd, 0x6c, 0xe2, 0xdb, 0x1c, 0x13, 0x33, 0x91, 0xb3, 0x0f, 0x7c, 0xfe, - 0x45, 0x86, 0x2b, 0x35, 0xf7, 0xf1, 0x57, 0xea, 0xbb, 0x30, 0x7e, 0xdf, 0x6e, 0xdb, 0xbb, 0xb4, - 0xc1, 0x7a, 0xc0, 0xf7, 0x9e, 0xd1, 0xc5, 0x67, 0x1f, 0x1f, 0xcd, 0x9f, 0x69, 0x71, 0x38, 0xf6, - 0x52, 0x5d, 0x44, 0x1a, 0x01, 0xb9, 0x21, 0xbf, 0xec, 0xa1, 0x94, 0x2f, 0x7b, 0x42, 0xd4, 0x3e, - 0x84, 0x5f, 0xb6, 0xf8, 0x9e, 0x8d, 0xff, 0xbd, 0x80, 0x7d, 0x24, 0xaf, 0xc2, 0xb0, 0x49, 0x77, - 0xd9, 0x51, 0x93, 0x89, 0x26, 0xc9, 0x43, 0x88, 0x3a, 0x30, 0x1c, 0x07, 0xe5, 0x0c, 0xda, 0xf0, - 0xf7, 0x9c, 0x9d, 0x40, 0x8c, 0x4e, 0x28, 0x67, 0x08, 0xb0, 0x22, 0x67, 0x08, 0x88, 0x7e, 0x9d, - 0xe5, 0x30, 0xb6, 0xfb, 0x99, 0x95, 0x9a, 0x18, 0x34, 0x39, 0xc2, 0x66, 0x45, 0xd9, 0x46, 0x3c, - 0x4d, 0x4a, 0x60, 0xd8, 0xe4, 0x16, 0x8c, 0x96, 0xea, 0x75, 0xb7, 0xab, 0xdc, 0x19, 0xf9, 0x77, - 0xcb, 0x81, 0xba, 0x8a, 0x24, 0x42, 0x25, 0x35, 0x18, 0x5b, 0x62, 0x17, 0x2d, 0xa7, 0x6c, 0xd7, - 0xf7, 0xe4, 0x20, 0xc9, 0x3d, 0x4c, 0x29, 0x89, 0xbe, 0x5c, 0x8a, 0xc0, 0x3a, 0x03, 0xaa, 0x4a, - 0x06, 0x05, 0x97, 0x6c, 0xc0, 0x58, 0x8d, 0xd6, 0x3d, 0x1a, 0xd4, 0x02, 0xd7, 0xa3, 0xb1, 0x2d, - 0x59, 0x29, 0x59, 0x7c, 0x4e, 0xde, 0xf5, 0x7c, 0x04, 0x5a, 0x3e, 0x83, 0xaa, 0x5c, 0x15, 0x64, - 0x2e, 0xb4, 0xb7, 0x5c, 0xef, 0xb0, 0xb2, 0x28, 0xb6, 0xe9, 0xe8, 0x4c, 0xe7, 0x60, 0x55, 0x68, - 0x67, 0x90, 0xc6, 0xb6, 0x2e, 0xb4, 0x73, 0x2c, 0x9c, 0xa9, 0x4a, 0x0d, 0x65, 0x2b, 0xb1, 0x69, - 0x4f, 0x45, 0xa3, 0x8c, 0x60, 0x65, 0xa6, 0x1a, 0x3e, 0x4a, 0x66, 0xda, 0x4c, 0x09, 0x2c, 0xd2, - 0x01, 0x22, 0x67, 0x8d, 0x0b, 0xba, 0x4d, 0xea, 0xfb, 0x62, 0x2f, 0x3f, 0x1b, 0x9b, 0xfc, 0x08, - 0x61, 0xf1, 0x45, 0xc1, 0xfc, 0x82, 0x5c, 0x06, 0xe2, 0x9e, 0xc6, 0x0a, 0x95, 0x7a, 0x52, 0x78, - 0x93, 0x37, 0x00, 0x96, 0x1e, 0x05, 0xd4, 0x6b, 0xdb, 0xcd, 0x50, 0x0f, 0x86, 0xaa, 0x1f, 0x2a, - 0xa0, 0xfa, 0x44, 0x2b, 0xc8, 0xa4, 0x0c, 0x13, 0x25, 0xdf, 0xef, 0xb6, 0xa8, 0xe9, 0x36, 0x69, - 0xc9, 0x5c, 0xc5, 0x7d, 0x7f, 0x74, 0xf1, 0xc2, 0xe3, 0xa3, 0xf9, 0xb3, 0x36, 0x16, 0x58, 0x9e, - 0xdb, 0xa4, 0x96, 0xed, 0xa9, 0xab, 0x5b, 0xa7, 0x21, 0x6b, 0x00, 0x6b, 0x1d, 0xda, 0xae, 0x51, - 0xdb, 0xab, 0xef, 0xc5, 0xb6, 0xf9, 0xa8, 0x60, 0xf1, 0xbc, 0xe8, 0xe1, 0xac, 0xdb, 0xa1, 0x6d, - 0x1f, 0x61, 0x6a, 0xab, 0x22, 0x4c, 0xb2, 0x05, 0x53, 0xd5, 0xd2, 0xfd, 0x75, 0xb7, 0xe9, 0xd4, - 0x0f, 0x85, 0xe4, 0x34, 0x89, 0xda, 0xc1, 0xd3, 0x82, 0x6b, 0xac, 0x94, 0x6f, 0x4f, 0x8e, 0xdd, - 0xb2, 0x3a, 0x08, 0xb5, 0x84, 0xfc, 0x14, 0xe7, 0x42, 0xde, 0x67, 0x6b, 0xd0, 0x67, 0xc2, 0xe0, - 0x86, 0xbd, 0xeb, 0xcf, 0x4d, 0x69, 0xda, 0xae, 0xd2, 0x56, 0xed, 0x9a, 0x52, 0xca, 0xc5, 0x94, - 0x73, 0x7c, 0x21, 0x22, 0xd4, 0x0a, 0xec, 0x5d, 0x5f, 0x5f, 0x88, 0x21, 0xf6, 0xb9, 0x77, 0xa0, - 0x18, 0x27, 0x3e, 0xa1, 0xd2, 0x69, 0xa2, 0x38, 0xa9, 0xb4, 0x78, 0xe9, 0x91, 0xe3, 0x07, 0xbe, - 0xf1, 0x83, 0xda, 0x57, 0xc3, 0xbe, 0xe8, 0x7b, 0xf4, 0x70, 0xdd, 0xa3, 0x3b, 0xce, 0x23, 0xb1, - 0x01, 0xe1, 0x17, 0xbd, 0x4f, 0x0f, 0xad, 0x0e, 0x42, 0xd5, 0x2f, 0x3a, 0x44, 0x25, 0x9f, 0x87, - 0xc2, 0xbd, 0xfb, 0xb5, 0x7b, 0xf4, 0xb0, 0x5a, 0x11, 0x87, 0x0b, 0x27, 0x6b, 0xf9, 0x16, 0x23, - 0xd5, 0xd6, 0x47, 0x88, 0x69, 0x2c, 0x46, 0xbb, 0x17, 0xab, 0xb9, 0xdc, 0xec, 0xfa, 0x01, 0xf5, - 0xaa, 0x15, 0xb5, 0xe6, 0x3a, 0x07, 0xc6, 0xf6, 0x92, 0x10, 0xd5, 0xf8, 0x07, 0x59, 0xdc, 0xb9, - 0xd8, 0x22, 0xad, 0xb6, 0xfd, 0xc0, 0x6e, 0xd7, 0x69, 0xc8, 0x00, 0x17, 0xa9, 0x23, 0xa0, 0xb1, - 0x45, 0x1a, 0x21, 0xeb, 0x55, 0x67, 0x07, 0xae, 0x9a, 0x55, 0x29, 0xb5, 0x0d, 0xd5, 0x8a, 0xaa, - 0x12, 0xf5, 0x04, 0x34, 0x56, 0x65, 0x84, 0x4c, 0x2e, 0xc3, 0x48, 0xb5, 0x74, 0xbf, 0xd4, 0x0d, - 0xf6, 0x70, 0xdf, 0x2c, 0x70, 0x99, 0x9a, 0xad, 0x30, 0xbb, 0x1b, 0xec, 0x99, 0xb2, 0x90, 0x5c, - 0xc7, 0xbb, 0x4a, 0x9b, 0x06, 0x5c, 0x75, 0x2a, 0x0e, 0x4a, 0x9f, 0x83, 0x62, 0x57, 0x15, 0x06, - 0x22, 0x2f, 0xc3, 0xd0, 0xe6, 0x7a, 0xb9, 0x5a, 0x11, 0x97, 0x5d, 0x3c, 0x3d, 0x1e, 0x76, 0xea, - 0x7a, 0x4b, 0x38, 0x8a, 0xf1, 0x5b, 0x99, 0x68, 0x4f, 0x22, 0x97, 0x35, 0x19, 0x02, 0x15, 0x25, - 0x4c, 0x86, 0x50, 0x15, 0x25, 0x28, 0x4d, 0x98, 0x40, 0xca, 0x5d, 0x3f, 0x70, 0x5b, 0x4b, 0xed, - 0x46, 0xc7, 0x75, 0xda, 0x01, 0x52, 0xf1, 0x51, 0x33, 0x1e, 0x1f, 0xcd, 0x3f, 0x57, 0xc7, 0x52, - 0x8b, 0x8a, 0x62, 0x2b, 0xc6, 0x25, 0x85, 0xfa, 0x13, 0x0c, 0xa4, 0xf1, 0x7b, 0x59, 0xed, 0x2c, - 0x61, 0xcd, 0x33, 0x69, 0xa7, 0xe9, 0xd4, 0xf1, 0xfa, 0x7c, 0xc7, 0x73, 0xbb, 0x9d, 0x70, 0x39, - 0x60, 0xf3, 0xbc, 0xa8, 0xd4, 0xda, 0x65, 0xc5, 0x3a, 0xef, 0x14, 0x6a, 0xf2, 0x1e, 0x8c, 0xb3, - 0x63, 0x5d, 0xfc, 0xf4, 0xe7, 0xb2, 0x38, 0x13, 0xe7, 0x51, 0xe5, 0xe5, 0x53, 0x2f, 0x64, 0xa3, - 0xc9, 0x03, 0x2a, 0x05, 0x69, 0xc0, 0xdc, 0x86, 0x67, 0xb7, 0x7d, 0x27, 0x58, 0x6a, 0xd7, 0xbd, - 0x43, 0x14, 0x43, 0x96, 0xda, 0xf6, 0x76, 0x93, 0x36, 0xb0, 0xbb, 0x85, 0xc5, 0x2b, 0x8f, 0x8f, - 0xe6, 0x5f, 0x08, 0x38, 0x8e, 0x45, 0x43, 0x24, 0x8b, 0x72, 0x2c, 0x85, 0x73, 0x4f, 0x4e, 0x4c, - 0x6c, 0x91, 0xc3, 0x8a, 0x2f, 0x1e, 0xfc, 0x44, 0x46, 0xb1, 0x25, 0x9c, 0x0d, 0xb6, 0x15, 0xa9, - 0xcd, 0x54, 0x09, 0x8c, 0x7f, 0x96, 0x89, 0x4e, 0x3b, 0xf2, 0x16, 0x8c, 0x89, 0xa5, 0xae, 0xac, - 0x0b, 0xdc, 0xae, 0xe4, 0x77, 0x11, 0x9b, 0x59, 0x15, 0x9d, 0x5d, 0xb2, 0x4b, 0xe5, 0x15, 0x65, - 0x6d, 0xe0, 0x25, 0xdb, 0xae, 0x37, 0xe3, 0x54, 0x12, 0x8d, 0x2d, 0x82, 0x8d, 0x95, 0x9a, 0x3e, - 0x2a, 0xb8, 0x08, 0x82, 0xa6, 0x9f, 0x32, 0x0c, 0x0a, 0xf2, 0x27, 0xef, 0xf8, 0x7f, 0x93, 0x49, - 0x3b, 0x54, 0xc9, 0x22, 0x4c, 0x6c, 0xb9, 0xde, 0x3e, 0xce, 0xaf, 0x32, 0x08, 0x38, 0xf3, 0x07, - 0xb2, 0x20, 0xde, 0x21, 0x9d, 0x44, 0x6d, 0x9b, 0x32, 0x1a, 0x7a, 0xdb, 0x62, 0x1c, 0x34, 0x02, - 0x36, 0x0f, 0x21, 0xc7, 0xf0, 0xeb, 0xc0, 0x79, 0x88, 0x9a, 0xa0, 0x2d, 0x61, 0x15, 0xdd, 0xf8, - 0xf7, 0x33, 0xea, 0xe1, 0xc9, 0x06, 0xb9, 0xe2, 0xb6, 0x6c, 0xa7, 0xad, 0x74, 0x87, 0xbf, 0xe2, - 0x20, 0x34, 0xde, 0x12, 0x05, 0x99, 0xdc, 0x84, 0x02, 0xff, 0x15, 0x6e, 0x92, 0xa8, 0x42, 0x12, - 0x84, 0xfa, 0x0e, 0x2f, 0x11, 0x13, 0x33, 0x93, 0x3b, 0xe9, 0xcc, 0x7c, 0x3b, 0x03, 0x63, 0xca, - 0x7d, 0x9a, 0xed, 0xd5, 0xeb, 0x9e, 0xfb, 0x21, 0xad, 0x07, 0xfa, 0x31, 0xd1, 0xe1, 0xc0, 0xd8, - 0x5e, 0x1d, 0xa2, 0xc6, 0x8e, 0x87, 0xec, 0x09, 0x8e, 0x07, 0xe3, 0x9f, 0x66, 0x84, 0x34, 0x3f, - 0xf0, 0x1e, 0xa9, 0xef, 0x67, 0xd9, 0x93, 0x1c, 0x0c, 0xef, 0xc1, 0x90, 0x49, 0x1b, 0x8e, 0x2f, - 0x24, 0xf1, 0x69, 0xf5, 0xe6, 0x80, 0x05, 0xd1, 0xe5, 0xc5, 0x63, 0x3f, 0xd5, 0x5d, 0x1d, 0xcb, - 0x99, 0xc8, 0x55, 0xf5, 0x6f, 0x37, 0xe9, 0x23, 0x87, 0xaf, 0x64, 0x71, 0xc0, 0xa0, 0xc8, 0xe5, - 0xf8, 0xd6, 0x0e, 0x2b, 0x11, 0xb2, 0x9f, 0xba, 0x6a, 0x35, 0x1a, 0xe3, 0x7d, 0x80, 0xa8, 0x4a, - 0x72, 0x0f, 0x8a, 0xe2, 0xdb, 0x76, 0xda, 0xbb, 0x5c, 0x7c, 0x10, 0x63, 0x30, 0xff, 0xf8, 0x68, - 0xfe, 0xd9, 0x7a, 0x58, 0x26, 0xe4, 0x23, 0x85, 0x6f, 0x82, 0xd0, 0xf8, 0xd7, 0xb3, 0x90, 0x2d, - 0xe1, 0x84, 0xdc, 0xa3, 0x87, 0x81, 0xbd, 0x7d, 0xdb, 0x69, 0x6a, 0x2b, 0x71, 0x1f, 0xa1, 0xd6, - 0x8e, 0xa3, 0x5d, 0xac, 0x15, 0x64, 0xb6, 0x12, 0xef, 0x79, 0xdb, 0xaf, 0x23, 0xa1, 0xb2, 0x12, - 0xf7, 0xbd, 0xed, 0xd7, 0xe3, 0x64, 0x21, 0x22, 0x31, 0x60, 0x98, 0xaf, 0x4a, 0xb1, 0x06, 0xe1, - 0xf1, 0xd1, 0xfc, 0x30, 0x5f, 0xbc, 0xa6, 0x28, 0x21, 0x67, 0x21, 0x57, 0x5b, 0x5f, 0x15, 0xdb, - 0x07, 0x2a, 0xb0, 0xfc, 0x4e, 0xdb, 0x64, 0x30, 0x56, 0xe7, 0x4a, 0xa5, 0xb4, 0x8e, 0x57, 0xd6, - 0xa1, 0xa8, 0xce, 0x66, 0xc3, 0xee, 0xc4, 0x2f, 0xad, 0x21, 0x22, 0x79, 0x1b, 0xc6, 0xee, 0x55, - 0xca, 0xcb, 0xae, 0xcf, 0x3f, 0xfd, 0xe1, 0x68, 0xf1, 0xef, 0x37, 0xea, 0x16, 0xea, 0x8c, 0xe3, - 0x7b, 0xa8, 0x82, 0x6f, 0xfc, 0x58, 0x16, 0xc6, 0x14, 0x8d, 0x0e, 0xf9, 0xbc, 0x78, 0xca, 0xcb, - 0x68, 0xb2, 0xaa, 0x82, 0xc1, 0x4a, 0xf9, 0xf5, 0xbf, 0xe5, 0x36, 0xa8, 0x78, 0xd8, 0x8b, 0xae, - 0xda, 0xd9, 0x41, 0xae, 0xda, 0x6f, 0x00, 0xf0, 0x35, 0x80, 0x4d, 0x56, 0xce, 0x62, 0xe5, 0x45, - 0x5f, 0x9d, 0x97, 0x08, 0x99, 0x6c, 0xc2, 0xcc, 0x86, 0xd7, 0xf5, 0x83, 0xda, 0xa1, 0x1f, 0xd0, - 0x16, 0xe3, 0xb6, 0xee, 0xba, 0x4d, 0xb1, 0xfe, 0x5e, 0x78, 0x7c, 0x34, 0x7f, 0x31, 0x60, 0xc5, - 0x96, 0x8f, 0xe5, 0xd8, 0x00, 0xab, 0xe3, 0xba, 0xea, 0x05, 0x3c, 0x8d, 0x81, 0x61, 0xc2, 0xb8, - 0x7a, 0x7d, 0x67, 0xdb, 0xb2, 0x78, 0xf6, 0x10, 0x4a, 0x59, 0x65, 0x5b, 0x16, 0xad, 0x4c, 0x3e, - 0xc3, 0xe8, 0x24, 0xc6, 0xe7, 0x55, 0xd5, 0xd1, 0xa0, 0x1f, 0xb6, 0xf1, 0x23, 0x99, 0x68, 0x1b, - 0xd9, 0xbc, 0x41, 0xde, 0x84, 0x61, 0xfe, 0xcc, 0x24, 0x5e, 0xe3, 0x4e, 0x85, 0xd7, 0x2f, 0xf5, - 0x0d, 0x8a, 0xeb, 0x6c, 0x7f, 0x9f, 0x3f, 0x45, 0x3f, 0x63, 0x0a, 0x92, 0x50, 0xdd, 0xab, 0x6b, - 0x7e, 0x24, 0x77, 0x54, 0x6c, 0xde, 0x48, 0x53, 0xf7, 0x1a, 0xbf, 0x9d, 0x87, 0x49, 0x1d, 0x4d, - 0x7d, 0x8b, 0xca, 0x0c, 0xf4, 0x16, 0xf5, 0x1e, 0x14, 0xd8, 0x78, 0x38, 0x75, 0x2a, 0xc5, 0x99, - 0x17, 0x50, 0x09, 0x2e, 0x60, 0xda, 0x1b, 0x2b, 0xf0, 0xe9, 0x60, 0xb7, 0x31, 0x33, 0xa4, 0x22, - 0x0b, 0xca, 0x83, 0x49, 0x2e, 0x3a, 0xe1, 0xe5, 0x83, 0x89, 0xfa, 0x3d, 0x84, 0x4f, 0x27, 0xaf, - 0xc1, 0x30, 0x93, 0x6a, 0x43, 0x65, 0x01, 0xb6, 0x92, 0x09, 0xbc, 0x31, 0x63, 0x0a, 0x8e, 0x44, - 0xb6, 0xa0, 0xb0, 0x62, 0xfb, 0x41, 0x8d, 0xd2, 0xf6, 0x00, 0xaf, 0xcc, 0xf3, 0x62, 0xa8, 0x66, - 0xf0, 0x09, 0xd7, 0xa7, 0xb4, 0x1d, 0x7b, 0x26, 0x0c, 0x99, 0x91, 0xaf, 0x01, 0x94, 0xdd, 0x76, - 0xe0, 0xb9, 0xcd, 0x15, 0x77, 0x77, 0x6e, 0x18, 0x6f, 0x69, 0xcf, 0xc5, 0x26, 0x20, 0x42, 0xe0, - 0x17, 0xb5, 0x50, 0x15, 0x51, 0xe7, 0x05, 0x56, 0xd3, 0xdd, 0x55, 0xbf, 0x83, 0x08, 0x9f, 0xdc, - 0x86, 0xa2, 0xbc, 0x02, 0x3f, 0xe8, 0xec, 0x7a, 0xb8, 0x40, 0x46, 0xa2, 0x63, 0x9b, 0x3e, 0x0a, - 0xac, 0xae, 0x80, 0xab, 0x3b, 0x65, 0x9c, 0x86, 0x7c, 0x15, 0xce, 0xc4, 0x61, 0x72, 0x96, 0x0b, - 0x91, 0x40, 0xab, 0xb2, 0x4b, 0x59, 0xf7, 0xbd, 0x58, 0x18, 0x1f, 0x65, 0xe1, 0x4c, 0x8f, 0xce, - 0xb2, 0xef, 0x01, 0x8f, 0x6b, 0xe5, 0x7b, 0x88, 0x9d, 0xd2, 0xdc, 0x3a, 0xe6, 0x22, 0x64, 0xc5, - 0x01, 0x97, 0x5f, 0x2c, 0x3e, 0x3e, 0x9a, 0x1f, 0xd7, 0xe6, 0x31, 0x5b, 0xad, 0x90, 0xbb, 0x90, - 0x67, 0x53, 0x34, 0xc0, 0x23, 0xaf, 0xd4, 0x7e, 0x4c, 0x06, 0x8e, 0xba, 0x7c, 0x70, 0xea, 0x90, - 0x07, 0xf9, 0x3c, 0xe4, 0x36, 0x36, 0x56, 0x70, 0xed, 0xe4, 0xb0, 0xef, 0x13, 0x41, 0xd0, 0xd4, - 0x96, 0xea, 0x04, 0xa3, 0xbd, 0x16, 0xda, 0x04, 0x30, 0x74, 0xf2, 0x95, 0x98, 0xf1, 0xc9, 0xcb, - 0xfd, 0x27, 0x7a, 0x70, 0x5b, 0x94, 0x4f, 0x60, 0x02, 0x62, 0xfc, 0x7c, 0x36, 0xfa, 0x86, 0x6f, - 0x3b, 0xcd, 0x80, 0x7a, 0xe4, 0x1c, 0xff, 0x24, 0xa3, 0xfb, 0xaf, 0x19, 0xfe, 0x26, 0x73, 0xd1, - 0xf7, 0xcd, 0x59, 0x85, 0x1f, 0xf2, 0xcb, 0xca, 0x87, 0x9c, 0xc3, 0x0f, 0x79, 0xb2, 0xe7, 0x27, - 0xfb, 0x72, 0xca, 0xba, 0xc4, 0x0f, 0x31, 0x65, 0xed, 0xbd, 0x00, 0x13, 0xab, 0xee, 0xd2, 0xa3, - 0x20, 0x44, 0x64, 0x1f, 0x60, 0xc1, 0xd4, 0x81, 0x8c, 0xe3, 0x5a, 0xb3, 0x41, 0xbd, 0x8d, 0x3d, - 0xbb, 0xad, 0xbd, 0xb2, 0x9a, 0x09, 0x38, 0xc3, 0x5d, 0xa5, 0x07, 0x3a, 0xee, 0x08, 0xc7, 0x8d, - 0xc3, 0x8d, 0x1f, 0xce, 0xca, 0xc1, 0xd8, 0x5c, 0x78, 0x4a, 0x5f, 0xf3, 0x5e, 0xd7, 0x5e, 0xf3, - 0x66, 0x42, 0x3d, 0x64, 0xf8, 0x34, 0xbd, 0x70, 0xcc, 0x8b, 0xf6, 0x7f, 0x3b, 0x04, 0xe3, 0x2a, - 0x3a, 0x1b, 0x87, 0x52, 0xa3, 0xe1, 0xa9, 0xe3, 0x60, 0x37, 0x1a, 0x9e, 0x89, 0x50, 0xed, 0x01, - 0x3b, 0xd7, 0xf7, 0x01, 0xfb, 0xeb, 0x30, 0x5a, 0x6e, 0x35, 0xb4, 0x67, 0x35, 0x23, 0xa5, 0x79, - 0xd7, 0x42, 0x24, 0xfe, 0x2d, 0x84, 0xea, 0xb5, 0x7a, 0xab, 0x91, 0x7c, 0x4c, 0x8b, 0x58, 0x6a, - 0x6f, 0xdf, 0x43, 0x9f, 0xe4, 0xed, 0xfb, 0x16, 0x8c, 0x3e, 0xf0, 0xe9, 0x46, 0xb7, 0xdd, 0xa6, - 0x4d, 0x5c, 0x56, 0x05, 0x2e, 0xeb, 0x77, 0x7d, 0x6a, 0x05, 0x08, 0x55, 0x1b, 0x10, 0xa2, 0xaa, - 0x13, 0x3c, 0xd2, 0x67, 0x82, 0x6f, 0x42, 0x61, 0x9d, 0x52, 0x0f, 0xc7, 0x74, 0x2c, 0x12, 0xe9, - 0x3a, 0x94, 0x7a, 0x16, 0x1b, 0x58, 0xed, 0x4d, 0x5c, 0x20, 0x6a, 0x0f, 0xe9, 0xe3, 0x03, 0x3e, - 0xa4, 0x93, 0xe7, 0x61, 0xbc, 0xd3, 0xdd, 0x6e, 0x3a, 0x75, 0xe4, 0x2b, 0x5e, 0xe0, 0xcd, 0x31, - 0x0e, 0x63, 0x6c, 0x7d, 0xf2, 0x15, 0x98, 0xc0, 0x3b, 0x4e, 0xb8, 0xe4, 0x26, 0xb5, 0xf7, 0x27, - 0xad, 0x8c, 0x4b, 0x3a, 0x75, 0x06, 0xb2, 0x52, 0x0c, 0x45, 0x74, 0x46, 0xe7, 0x6a, 0x30, 0xa9, - 0xcf, 0xe4, 0x13, 0x78, 0x86, 0x0a, 0x8d, 0x02, 0x0a, 0xc5, 0xd1, 0xbb, 0xf9, 0x02, 0x14, 0xc7, - 0xb8, 0x39, 0x80, 0x09, 0xeb, 0x61, 0x9f, 0x4c, 0x72, 0xaf, 0xbb, 0x4d, 0xbd, 0x36, 0x0d, 0xa8, - 0x2f, 0x2e, 0x01, 0xbe, 0x99, 0x2f, 0x75, 0x3a, 0xbe, 0xf1, 0xeb, 0x59, 0x18, 0x29, 0x6d, 0xd5, - 0xaa, 0xed, 0x1d, 0x17, 0x1f, 0x93, 0xc2, 0x37, 0x04, 0xf5, 0x31, 0x29, 0x7c, 0x43, 0x50, 0x5f, - 0x0e, 0xae, 0xa7, 0x5c, 0xe3, 0xd0, 0xde, 0x54, 0xb9, 0xc6, 0x69, 0xba, 0xbd, 0xe8, 0x39, 0x25, - 0x37, 0xc0, 0x73, 0x4a, 0xa8, 0x3d, 0xcb, 0x1f, 0xab, 0x3d, 0x23, 0x6f, 0xc2, 0x58, 0xb5, 0x1d, - 0xd0, 0x5d, 0x2f, 0x5a, 0xe9, 0xe1, 0x95, 0x32, 0x04, 0xab, 0xa2, 0xbd, 0x82, 0xcd, 0x96, 0x11, - 0xd7, 0xd8, 0x85, 0x9a, 0x3a, 0x5c, 0x46, 0x5c, 0xb1, 0x17, 0xbb, 0x4c, 0x4b, 0x44, 0xa3, 0x12, - 0x5b, 0x23, 0xf2, 0xc9, 0x9a, 0x0b, 0x9f, 0x93, 0x91, 0x9a, 0x99, 0x0d, 0xec, 0xe2, 0x74, 0xfa, - 0x93, 0xb5, 0xf1, 0x9d, 0x2c, 0x8c, 0x95, 0x3a, 0x9d, 0xa7, 0xdc, 0x70, 0xe8, 0x8b, 0xda, 0xf6, - 0x2a, 0xef, 0x42, 0x61, 0xbf, 0x06, 0xb2, 0x19, 0xfa, 0x95, 0x2c, 0x4c, 0xc5, 0x28, 0xd4, 0xd6, - 0x67, 0x06, 0x34, 0x17, 0xca, 0x0e, 0x68, 0x2e, 0x94, 0x1b, 0xcc, 0x5c, 0x28, 0xff, 0x49, 0xb6, - 0xcc, 0x97, 0x20, 0x57, 0xea, 0x74, 0xe2, 0xcf, 0x8e, 0x9d, 0xce, 0xe6, 0x4d, 0x7e, 0x9f, 0xb5, - 0x3b, 0x1d, 0x93, 0x61, 0x68, 0xfb, 0xd8, 0xf0, 0x80, 0xfb, 0x98, 0xf1, 0x1a, 0x8c, 0x22, 0x2f, - 0x34, 0xd2, 0xb9, 0x08, 0xf8, 0x31, 0x0b, 0xfb, 0x1c, 0xad, 0x2e, 0xf1, 0x99, 0xff, 0x5f, 0x19, - 0x18, 0xc2, 0xdf, 0x4f, 0xe9, 0x1a, 0x5b, 0xd0, 0xd6, 0x58, 0x51, 0x59, 0x63, 0x83, 0xac, 0xae, - 0xff, 0x35, 0x8f, 0xa3, 0x25, 0xd6, 0x95, 0xb0, 0x8d, 0xc9, 0xa4, 0xd8, 0xc6, 0xbc, 0x01, 0xca, - 0xae, 0xa9, 0x6a, 0x8b, 0x94, 0x33, 0x43, 0xbd, 0x69, 0x44, 0xc8, 0x64, 0x3f, 0x6e, 0x25, 0x93, - 0xc3, 0xc9, 0xb8, 0x14, 0x6f, 0xea, 0x13, 0x31, 0x90, 0x59, 0x06, 0x52, 0x6d, 0xfb, 0xb4, 0xde, - 0xf5, 0x68, 0x6d, 0xdf, 0xe9, 0x6c, 0x52, 0xcf, 0xd9, 0x39, 0x14, 0xb7, 0x7b, 0x3c, 0x97, 0x1d, - 0x51, 0x6a, 0xf9, 0xfb, 0x4e, 0x87, 0x5d, 0x45, 0x9c, 0x9d, 0x43, 0x33, 0x85, 0x86, 0xbc, 0x0b, - 0x23, 0x26, 0x3d, 0xf0, 0x9c, 0x40, 0xbe, 0xfd, 0x4e, 0x86, 0x17, 0x67, 0x84, 0xf2, 0x8b, 0xa1, - 0xc7, 0x7f, 0xa8, 0xf3, 0x2f, 0xca, 0xc9, 0x02, 0xdf, 0xf8, 0xf8, 0x1b, 0xef, 0x44, 0xd4, 0xdb, - 0xd2, 0x56, 0xad, 0xd7, 0xbe, 0x47, 0xae, 0xc2, 0x10, 0xee, 0x9e, 0x42, 0x26, 0x40, 0x9b, 0x69, - 0x3c, 0x43, 0xd5, 0xad, 0x1d, 0x31, 0xc8, 0x73, 0x00, 0xa1, 0xfa, 0xde, 0x9f, 0x2b, 0xe0, 0x69, - 0xad, 0x40, 0xe2, 0x5b, 0xff, 0xe8, 0x49, 0xb6, 0xfe, 0x4f, 0xcf, 0x34, 0xe4, 0x57, 0xb2, 0x70, - 0x29, 0xdc, 0xce, 0xd6, 0xbc, 0x5a, 0xe9, 0xfe, 0x4a, 0xb5, 0xb1, 0x2e, 0xa4, 0xff, 0x75, 0xcf, - 0x7d, 0xe8, 0xb0, 0xdb, 0xdf, 0x8d, 0x63, 0x3e, 0xc6, 0x15, 0xbe, 0x6a, 0xb9, 0xea, 0x30, 0xab, - 0x3d, 0xa2, 0x2b, 0xa7, 0x86, 0x78, 0xe7, 0xef, 0x74, 0x12, 0x9a, 0xc4, 0xe5, 0x67, 0xcc, 0x88, - 0x01, 0xf9, 0x91, 0x0c, 0x9c, 0x4e, 0x6f, 0x88, 0xb8, 0x11, 0xce, 0x4b, 0xc9, 0xb3, 0x47, 0x6b, - 0x17, 0x5f, 0x7a, 0x7c, 0x34, 0x7f, 0xc9, 0xb7, 0x5b, 0x4d, 0xcb, 0x69, 0xf0, 0xda, 0x9c, 0x3a, - 0xb5, 0x3a, 0x02, 0x41, 0xab, 0xb7, 0x47, 0x4d, 0x5f, 0x02, 0xf9, 0x4d, 0xce, 0x65, 0x16, 0x01, - 0x0a, 0x52, 0x3b, 0x63, 0xfc, 0xfd, 0x0c, 0x28, 0x2b, 0xaa, 0x60, 0xd2, 0x86, 0xe3, 0xd1, 0x7a, - 0x80, 0x3b, 0x5a, 0xe8, 0x02, 0xc0, 0x61, 0x31, 0x9b, 0x09, 0x84, 0x91, 0x77, 0x60, 0x84, 0xeb, - 0x72, 0xb8, 0x0e, 0x25, 0x5a, 0x89, 0x42, 0xef, 0xc3, 0x7d, 0x45, 0x38, 0x86, 0xba, 0x8a, 0x05, - 0x11, 0x93, 0x6f, 0xef, 0x6e, 0x6d, 0x94, 0x9b, 0xb6, 0xd3, 0xf2, 0xc5, 0x3e, 0x86, 0xc3, 0xfa, - 0xe1, 0x41, 0x60, 0xd5, 0x11, 0xaa, 0xca, 0xb7, 0x21, 0xaa, 0x71, 0x47, 0xaa, 0x9d, 0x8e, 0x31, - 0xfc, 0x99, 0x87, 0xa1, 0xcd, 0xe8, 0xfa, 0xb9, 0x38, 0xfa, 0xf8, 0x68, 0x9e, 0x2f, 0x17, 0x93, - 0xc3, 0x8d, 0xbf, 0x96, 0x81, 0x49, 0x7d, 0x3d, 0x91, 0x6b, 0x30, 0x2c, 0xcc, 0xef, 0x33, 0x78, - 0xcd, 0x66, 0xa3, 0x30, 0xcc, 0x0d, 0xef, 0x35, 0x73, 0x7b, 0x81, 0xc5, 0x76, 0x62, 0xc1, 0x41, - 0xe8, 0x91, 0x70, 0x27, 0xae, 0x73, 0x90, 0x29, 0xcb, 0x88, 0xc1, 0xc4, 0x30, 0xbf, 0xdb, 0x0c, - 0x54, 0xed, 0xab, 0x87, 0x10, 0x53, 0x94, 0x18, 0x65, 0x18, 0xe6, 0x9f, 0x70, 0xcc, 0xe0, 0x20, - 0x73, 0x02, 0x83, 0x03, 0xe3, 0x28, 0x03, 0x50, 0xab, 0x2d, 0xdf, 0xa3, 0x87, 0xeb, 0xb6, 0xe3, - 0xe1, 0x73, 0x01, 0x6e, 0x97, 0xf7, 0xc4, 0xc7, 0x35, 0x2e, 0x9e, 0x0b, 0xf8, 0xd6, 0xba, 0x4f, - 0x0f, 0xb5, 0xe7, 0x02, 0x89, 0x8a, 0x7b, 0xb2, 0xe7, 0x3c, 0xb4, 0x03, 0xca, 0x08, 0xb3, 0x48, - 0xc8, 0xf7, 0x64, 0x0e, 0x8d, 0x51, 0x2a, 0xc8, 0xe4, 0x6b, 0x30, 0x19, 0xfd, 0x0a, 0x1f, 0x3d, - 0x26, 0xc3, 0x0f, 0x58, 0x2f, 0x5c, 0x7c, 0xee, 0xf1, 0xd1, 0xfc, 0x39, 0x85, 0x6b, 0xfc, 0x39, - 0x24, 0xc6, 0xcc, 0xf8, 0xa5, 0x0c, 0xbe, 0x93, 0xc9, 0x0e, 0x5e, 0x86, 0x7c, 0x68, 0x46, 0x35, - 0xce, 0x35, 0x35, 0x31, 0xc5, 0x2e, 0x96, 0x93, 0x4b, 0x90, 0x8b, 0x7a, 0x82, 0x5b, 0xa4, 0xde, - 0x03, 0x56, 0x4a, 0xee, 0xc0, 0xc8, 0x40, 0x6d, 0xc6, 0x4f, 0x23, 0xa5, 0xad, 0x92, 0x1a, 0x67, - 0xe1, 0xee, 0xd6, 0xc6, 0x67, 0x77, 0x16, 0x7e, 0x2a, 0x0b, 0x53, 0x6c, 0x5c, 0x4b, 0xdd, 0x60, - 0xcf, 0xf5, 0x9c, 0xe0, 0xf0, 0xa9, 0xd5, 0x53, 0xbc, 0xa5, 0x09, 0x39, 0xe7, 0xe4, 0x29, 0xa3, - 0xf6, 0x6d, 0x20, 0x75, 0xc5, 0xef, 0x0c, 0xc1, 0x4c, 0x0a, 0x15, 0x79, 0x55, 0x53, 0x25, 0xce, - 0x49, 0xf7, 0xba, 0x8f, 0x8e, 0xe6, 0xc7, 0x25, 0xfa, 0x46, 0xe4, 0x6e, 0xb7, 0xa0, 0x3f, 0x3a, - 0xf3, 0x91, 0x42, 0xcd, 0xa2, 0xfa, 0xe8, 0xac, 0x3f, 0x35, 0x5f, 0x85, 0x21, 0xd3, 0x6d, 0x52, - 0x69, 0x21, 0x81, 0x07, 0xbb, 0xc7, 0x00, 0xda, 0xdb, 0x18, 0x03, 0x90, 0x65, 0x18, 0x61, 0x7f, - 0xdc, 0xb7, 0x3b, 0x42, 0xeb, 0x4b, 0x42, 0x31, 0x1b, 0xa1, 0x1d, 0xa7, 0xbd, 0xab, 0x4a, 0xda, - 0x4d, 0x6a, 0xb5, 0xec, 0x8e, 0x26, 0x81, 0x70, 0x44, 0x4d, 0x62, 0x2f, 0xf4, 0x96, 0xd8, 0x33, - 0xc7, 0x4a, 0xec, 0x0d, 0x80, 0x9a, 0xb3, 0xdb, 0x76, 0xda, 0xbb, 0xa5, 0xe6, 0xae, 0x70, 0x52, - 0xbc, 0xda, 0x7b, 0x16, 0xae, 0x45, 0xc8, 0xb8, 0x70, 0xf9, 0xd3, 0x0c, 0x87, 0x59, 0x76, 0x53, - 0x53, 0x49, 0x47, 0xa8, 0x64, 0x15, 0xa0, 0x54, 0x0f, 0x9c, 0x87, 0x6c, 0x01, 0xfb, 0xc2, 0xf8, - 0x56, 0x36, 0xb8, 0x5c, 0xba, 0x47, 0x0f, 0x6b, 0x34, 0x88, 0x54, 0xdc, 0x36, 0xa2, 0xb2, 0xef, - 0x40, 0xb3, 0x93, 0x8d, 0x38, 0x90, 0x0e, 0x9c, 0x2a, 0x35, 0x1a, 0x0e, 0xeb, 0x81, 0xdd, 0xc4, - 0x37, 0x1b, 0xda, 0x40, 0xd6, 0xe3, 0xe9, 0xac, 0xaf, 0x0a, 0xd6, 0xcf, 0xdb, 0x21, 0x95, 0x15, - 0x70, 0xb2, 0x78, 0x35, 0xe9, 0x8c, 0x8d, 0x35, 0x98, 0xd4, 0xbb, 0xae, 0xbb, 0x56, 0x8e, 0x43, - 0xc1, 0xac, 0x95, 0xac, 0xda, 0x72, 0xe9, 0x46, 0x31, 0x43, 0x8a, 0x30, 0x2e, 0x7e, 0x2d, 0x58, - 0x0b, 0xaf, 0xdf, 0x2a, 0x66, 0x35, 0xc8, 0xeb, 0x37, 0x16, 0x12, 0x1e, 0x0d, 0x23, 0xc5, 0x02, - 0x57, 0x64, 0x18, 0xbf, 0x9a, 0x81, 0x82, 0x6c, 0x37, 0xb9, 0x05, 0xb9, 0x5a, 0x6d, 0x39, 0xe6, - 0x83, 0x10, 0x9d, 0x2f, 0x7c, 0x27, 0xf5, 0x7d, 0xd5, 0xd0, 0x8c, 0x11, 0x30, 0xba, 0x8d, 0x95, - 0x9a, 0x10, 0x0b, 0x24, 0x5d, 0xb4, 0x6d, 0x73, 0xba, 0x14, 0xc3, 0xec, 0x5b, 0x90, 0xbb, 0xbb, - 0xb5, 0x21, 0xc4, 0x78, 0x49, 0x17, 0xed, 0xa4, 0x9c, 0xee, 0xc3, 0x03, 0x75, 0x7f, 0x67, 0x04, - 0x86, 0x09, 0x63, 0xca, 0x12, 0xe6, 0xc7, 0x6d, 0xcb, 0x0d, 0x7d, 0x09, 0xc5, 0x71, 0xcb, 0x20, - 0xa6, 0x28, 0x61, 0xd2, 0xc1, 0x8a, 0x5b, 0xb7, 0x9b, 0xe2, 0xdc, 0x46, 0xe9, 0xa0, 0xc9, 0x00, - 0x26, 0x87, 0x1b, 0xbf, 0x95, 0x81, 0x22, 0xca, 0x50, 0x68, 0x74, 0xe6, 0xee, 0xd3, 0xf6, 0xe6, - 0x0d, 0xf2, 0x9a, 0xfc, 0xd8, 0x32, 0xe1, 0xa5, 0x71, 0x08, 0x3f, 0xb6, 0x98, 0xd6, 0x59, 0x7c, - 0x70, 0x8a, 0xbb, 0x66, 0x76, 0x70, 0x37, 0xaf, 0x63, 0xdc, 0x35, 0xe7, 0x61, 0x08, 0x9b, 0x23, - 0xb6, 0x45, 0x6c, 0x79, 0xc0, 0x00, 0x26, 0x87, 0x2b, 0xbb, 0xd2, 0xcf, 0x64, 0x13, 0x7d, 0x58, - 0xf8, 0x4c, 0xb9, 0x4a, 0xe9, 0x9d, 0x1b, 0x68, 0xa7, 0x7e, 0x1f, 0x66, 0xe3, 0x43, 0x82, 0x17, - 0xfa, 0x12, 0x4c, 0xe9, 0x70, 0x79, 0xb7, 0x3f, 0x93, 0x5a, 0xd7, 0xe6, 0x82, 0x19, 0xc7, 0x37, - 0xfe, 0xc7, 0x0c, 0x8c, 0xe2, 0x9f, 0x66, 0xb7, 0x89, 0x66, 0x10, 0xa5, 0xad, 0x9a, 0x50, 0xde, - 0xa9, 0x62, 0x9c, 0x7d, 0xe0, 0x5b, 0x42, 0xbf, 0xa7, 0xed, 0x2f, 0x21, 0xb2, 0x20, 0xe5, 0x5a, - 0x39, 0xf9, 0x42, 0x19, 0x92, 0x72, 0xf5, 0x9d, 0x1f, 0x23, 0x15, 0xc8, 0x68, 0x79, 0xb4, 0x55, - 0x63, 0xcb, 0x4f, 0x7d, 0x97, 0x44, 0x3a, 0xb7, 0xa9, 0x5b, 0x1e, 0x71, 0x34, 0x7c, 0x96, 0xdc, - 0xaa, 0x95, 0xcc, 0x55, 0xed, 0x59, 0x92, 0xb5, 0x51, 0xb3, 0x4a, 0x15, 0x48, 0xc6, 0x3f, 0x1a, - 0x8d, 0x0f, 0xa0, 0x38, 0xea, 0x4e, 0xf8, 0x6d, 0xbc, 0x09, 0x43, 0xa5, 0x66, 0xd3, 0x3d, 0x10, - 0xbb, 0x84, 0xd4, 0x2f, 0x84, 0xe3, 0xc7, 0x4f, 0x32, 0x9b, 0xa1, 0x68, 0xee, 0x1f, 0x0c, 0x40, - 0xca, 0x30, 0x5a, 0xda, 0xaa, 0x55, 0xab, 0x95, 0x8d, 0x0d, 0x6e, 0xea, 0x9e, 0x5b, 0x7c, 0x51, - 0x8e, 0x8f, 0xe3, 0x34, 0xac, 0xf8, 0xcb, 0x58, 0x24, 0xb9, 0x47, 0x74, 0xe4, 0x6d, 0x80, 0xbb, - 0xae, 0xd3, 0xbe, 0x4f, 0x83, 0x3d, 0xb7, 0x21, 0x3a, 0x7f, 0xe1, 0xf1, 0xd1, 0xfc, 0xd8, 0x87, - 0xae, 0xd3, 0xb6, 0x5a, 0x08, 0x66, 0x6d, 0x8f, 0x90, 0x4c, 0xe5, 0x6f, 0x36, 0xd2, 0x8b, 0x2e, - 0x37, 0x6d, 0x18, 0x8a, 0x46, 0x7a, 0xdb, 0x4d, 0x58, 0x35, 0x48, 0x34, 0xd2, 0x82, 0xa9, 0x5a, - 0x77, 0x77, 0x97, 0xb2, 0x5d, 0x5d, 0x68, 0x2c, 0x86, 0xc5, 0xed, 0x36, 0x0c, 0x30, 0xc0, 0x6f, - 0x22, 0xec, 0x7e, 0xe2, 0x2f, 0xbe, 0xca, 0x16, 0xf2, 0xf7, 0x8f, 0xe6, 0xc5, 0x8b, 0x1b, 0x13, - 0xd2, 0x7c, 0x49, 0x9f, 0xd4, 0x57, 0xc4, 0x79, 0x93, 0x35, 0x18, 0xbe, 0xe3, 0x04, 0xcb, 0xdd, - 0x6d, 0x61, 0xba, 0xfd, 0x7c, 0x9f, 0x8f, 0x86, 0x23, 0x72, 0x95, 0xef, 0xae, 0x13, 0xec, 0x75, - 0x55, 0x33, 0x6e, 0xc1, 0x86, 0x6c, 0x41, 0xa1, 0xec, 0x78, 0xf5, 0x26, 0x2d, 0x57, 0xc5, 0xa9, - 0x7f, 0xa9, 0x0f, 0x4b, 0x89, 0xca, 0xc7, 0xa5, 0x8e, 0xbf, 0xea, 0x8e, 0x2a, 0x05, 0x48, 0x0c, - 0xf2, 0x37, 0x32, 0xf0, 0x6c, 0xd8, 0xfa, 0xd2, 0x2e, 0x6d, 0x07, 0xf7, 0xed, 0xa0, 0xbe, 0x47, - 0x3d, 0x31, 0x4a, 0xa3, 0xfd, 0x46, 0xe9, 0x4b, 0x89, 0x51, 0xba, 0x12, 0x8d, 0x92, 0xcd, 0x98, - 0x59, 0x2d, 0xce, 0x2d, 0x39, 0x66, 0xfd, 0x6a, 0x25, 0x16, 0x40, 0xa4, 0xc3, 0x17, 0xae, 0x3f, - 0x2f, 0xf6, 0xe9, 0x70, 0x84, 0x2c, 0xcc, 0x7f, 0xc3, 0xdf, 0x9a, 0x25, 0x4f, 0x08, 0x25, 0xf7, - 0xa4, 0x9f, 0x04, 0x97, 0x48, 0x2e, 0xf6, 0xe1, 0xcd, 0x7d, 0x27, 0x66, 0xfa, 0x78, 0x44, 0xf1, - 0xd9, 0x5e, 0xb1, 0xb7, 0x85, 0x10, 0x72, 0xcc, 0x6c, 0xaf, 0xd8, 0xd1, 0x6c, 0x37, 0xed, 0xf8, - 0x6c, 0xaf, 0xd8, 0xdb, 0xa4, 0xcc, 0x9d, 0xbb, 0xb8, 0x27, 0xd0, 0x73, 0xfd, 0xb8, 0x95, 0xd7, - 0xf9, 0xc9, 0x9c, 0xe2, 0xe4, 0xf5, 0x01, 0x8c, 0xd6, 0x3a, 0x76, 0x9d, 0x36, 0x9d, 0x9d, 0x40, - 0x3c, 0xea, 0xbc, 0xd0, 0x87, 0x55, 0x88, 0x2b, 0x1e, 0x04, 0xe4, 0x4f, 0xf5, 0x82, 0x14, 0xe2, - 0xb0, 0x16, 0x6e, 0xac, 0xdf, 0x9f, 0x9b, 0x3a, 0xb6, 0x85, 0x1b, 0xeb, 0xf7, 0x85, 0xcc, 0xd1, - 0x69, 0x69, 0x32, 0xc7, 0xfa, 0x7d, 0xe3, 0x37, 0x72, 0x70, 0xa6, 0x07, 0x0d, 0x59, 0x95, 0x7b, - 0x54, 0x46, 0x53, 0x2c, 0xf6, 0x40, 0xbf, 0x76, 0xec, 0xb6, 0xb5, 0x02, 0xc5, 0xa5, 0x7b, 0x28, - 0xd6, 0xb2, 0x9f, 0xb4, 0x51, 0x2e, 0xc9, 0xdd, 0xfd, 0xe2, 0xe3, 0xa3, 0xf9, 0xf3, 0x74, 0x1f, - 0x8d, 0x82, 0x6c, 0x5e, 0x68, 0xd5, 0x35, 0x3f, 0xad, 0x04, 0xe5, 0xb9, 0x1f, 0xce, 0x42, 0x1e, - 0x4f, 0x9a, 0x58, 0x74, 0x8a, 0xcc, 0x89, 0xa2, 0x53, 0xbc, 0x07, 0xe3, 0x4b, 0xf7, 0xf8, 0xa5, - 0x73, 0xd9, 0xf6, 0xf7, 0xc4, 0x3e, 0x88, 0x6f, 0x6c, 0x74, 0xdf, 0x12, 0x77, 0xd4, 0x3d, 0x5b, - 0x13, 0xf2, 0x34, 0x0a, 0xf2, 0x00, 0x66, 0x78, 0xdb, 0x9c, 0x1d, 0xa7, 0xce, 0x9d, 0xdc, 0x1d, - 0xbb, 0x29, 0x36, 0xc5, 0x4b, 0x8f, 0x8f, 0xe6, 0xe7, 0xe9, 0x3e, 0x9a, 0x3b, 0x89, 0x72, 0xcb, - 0x47, 0x04, 0xd5, 0xee, 0x29, 0x85, 0x5e, 0xf5, 0xbc, 0x35, 0x47, 0xb1, 0x42, 0x56, 0x1b, 0xab, - 0x9b, 0xe1, 0x72, 0x24, 0xe3, 0xef, 0x0f, 0xc1, 0xb9, 0xde, 0xfb, 0x19, 0xf9, 0xb2, 0x3e, 0x81, - 0x97, 0x8f, 0xdd, 0x01, 0x8f, 0x9f, 0xc3, 0xaf, 0xc0, 0xec, 0x52, 0x3b, 0xa0, 0x5e, 0xc7, 0x73, - 0xa4, 0xaf, 0xf5, 0xb2, 0xeb, 0x4b, 0xf3, 0x32, 0xb4, 0xf3, 0xa2, 0x61, 0xb9, 0xd0, 0x0f, 0xa2, - 0xb1, 0x9b, 0xc2, 0x2a, 0x95, 0x03, 0x59, 0x82, 0x49, 0x05, 0xde, 0xec, 0xee, 0x8a, 0x13, 0x1c, - 0x6d, 0x17, 0x55, 0x9e, 0xcd, 0xae, 0x7a, 0xd1, 0x89, 0x11, 0x9d, 0xfb, 0xa5, 0x9c, 0x58, 0x16, - 0x97, 0x20, 0x57, 0xeb, 0x6e, 0x8b, 0xe5, 0xc0, 0x45, 0x75, 0x6d, 0x5b, 0x67, 0xa5, 0xe4, 0x8b, - 0x00, 0x26, 0xed, 0xb8, 0xbe, 0x13, 0xb8, 0xde, 0xa1, 0x6a, 0xfe, 0xef, 0x85, 0x50, 0xdd, 0x56, - 0x53, 0x42, 0xc9, 0x32, 0x4c, 0x45, 0xbf, 0xd6, 0x0e, 0xda, 0x42, 0xa9, 0x39, 0xca, 0xb5, 0x09, - 0x11, 0xb9, 0xe5, 0xb2, 0x32, 0xf5, 0xa0, 0x8a, 0x91, 0x91, 0x05, 0x28, 0x6c, 0xb9, 0xde, 0xfe, - 0x0e, 0x9b, 0xa8, 0x7c, 0x74, 0x94, 0x1e, 0x08, 0x98, 0x7a, 0x64, 0x48, 0x3c, 0xb6, 0xe6, 0x97, - 0xda, 0x0f, 0x1d, 0xcf, 0x6d, 0xb7, 0x68, 0x3b, 0x50, 0xdf, 0x1f, 0x69, 0x04, 0xd6, 0x9c, 0xa5, - 0x22, 0x30, 0xbb, 0x33, 0x97, 0xea, 0x81, 0xeb, 0x89, 0xc7, 0x47, 0x3e, 0xdd, 0x0c, 0xa0, 0x4d, - 0x37, 0x03, 0xb0, 0x41, 0x34, 0xe9, 0x8e, 0xd0, 0x9a, 0xe3, 0x20, 0x7a, 0x74, 0x47, 0xf3, 0x04, - 0xa3, 0x3b, 0x4c, 0x14, 0x30, 0xe9, 0x0e, 0x5e, 0xf4, 0xb5, 0x00, 0x2a, 0x3b, 0x09, 0x15, 0x91, - 0x40, 0x33, 0x7e, 0x77, 0xb4, 0xe7, 0xba, 0x65, 0x7b, 0xef, 0xc9, 0xd6, 0xed, 0x8a, 0x3d, 0xc0, - 0xba, 0x7d, 0x35, 0xb4, 0x00, 0x55, 0xdd, 0x1f, 0x11, 0xa2, 0x6e, 0xfe, 0x1c, 0xe7, 0xdc, 0x2f, - 0x17, 0x4e, 0xb2, 0x88, 0xc4, 0x20, 0x65, 0x07, 0x1d, 0xa4, 0xdc, 0x40, 0x83, 0x44, 0x16, 0x61, - 0x22, 0x0c, 0xc1, 0xb3, 0x6e, 0x07, 0xda, 0xde, 0x14, 0xc6, 0x4d, 0xb2, 0x3a, 0x76, 0xa0, 0xee, - 0x4d, 0x3a, 0x09, 0x79, 0x0b, 0xc6, 0x84, 0x19, 0x34, 0x72, 0x18, 0x8a, 0x0c, 0xd1, 0xa4, 0xcd, - 0x74, 0x8c, 0x5e, 0x45, 0x67, 0x9f, 0xe4, 0xba, 0xd3, 0xa1, 0x4d, 0xa7, 0x4d, 0x6b, 0xa8, 0x35, - 0x17, 0x2b, 0x06, 0x3f, 0xc9, 0x8e, 0x28, 0xb1, 0xb8, 0x42, 0x5d, 0xd3, 0x97, 0x69, 0x44, 0xf1, - 0xc5, 0x3a, 0x72, 0xa2, 0xc5, 0xca, 0xed, 0x40, 0xbc, 0x15, 0x77, 0xd7, 0x91, 0x96, 0x6f, 0xd2, - 0x0e, 0xc4, 0xb3, 0x9a, 0x0c, 0x1a, 0xb3, 0x03, 0xe1, 0xa8, 0x4c, 0xae, 0x67, 0x3f, 0xaa, 0x15, - 0xf1, 0x42, 0x83, 0x72, 0x3d, 0x12, 0xe9, 0xe6, 0x86, 0x1c, 0x49, 0x56, 0xb3, 0xd4, 0xb2, 0x9d, - 0xa6, 0xf0, 0x72, 0x8b, 0xaa, 0xa1, 0x0c, 0x1a, 0xaf, 0x06, 0x51, 0x49, 0x1d, 0xc6, 0x4d, 0xba, - 0xb3, 0xee, 0xb9, 0x01, 0xad, 0x07, 0xb4, 0x21, 0x64, 0x19, 0x29, 0xce, 0x2f, 0xba, 0x2e, 0x97, - 0xd3, 0x16, 0x5f, 0xfb, 0xdd, 0xa3, 0xf9, 0xcc, 0xf7, 0x8f, 0xe6, 0x81, 0x81, 0xb8, 0x2d, 0xeb, - 0xe3, 0xa3, 0xf9, 0x33, 0x6c, 0xfe, 0x3b, 0x92, 0x58, 0x3d, 0x62, 0x54, 0xa6, 0xe4, 0x07, 0xd9, - 0xa6, 0x1b, 0x0e, 0x49, 0x54, 0xd9, 0x78, 0x8f, 0xca, 0x5e, 0x4f, 0xad, 0x6c, 0x5e, 0x19, 0xed, - 0xd4, 0x4a, 0x53, 0x2b, 0x21, 0x6f, 0xc3, 0x58, 0xb9, 0x5a, 0x76, 0xdb, 0x3b, 0xce, 0x6e, 0x6d, - 0xb9, 0x84, 0x02, 0x91, 0xb0, 0x63, 0xae, 0x3b, 0x56, 0x1d, 0xe1, 0x96, 0xbf, 0x67, 0x6b, 0xbe, - 0x20, 0x11, 0x3e, 0xb9, 0x03, 0x93, 0xf2, 0xa7, 0x49, 0x77, 0x1e, 0x98, 0x55, 0x94, 0x83, 0xa4, - 0xf1, 0x78, 0xc8, 0x81, 0x0d, 0x44, 0xd7, 0x53, 0xe5, 0xe3, 0x18, 0x19, 0x5b, 0x8c, 0x15, 0xda, - 0x69, 0xba, 0x87, 0xac, 0x79, 0x1b, 0x0e, 0xf5, 0x50, 0xf2, 0x11, 0x8b, 0xb1, 0x11, 0x96, 0x58, - 0x81, 0xa3, 0x6d, 0xb7, 0x31, 0x22, 0xb2, 0x0a, 0xd3, 0x62, 0x89, 0x6f, 0x3a, 0xbe, 0xb3, 0xed, - 0x34, 0x9d, 0xe0, 0x70, 0xae, 0x88, 0x9c, 0x50, 0x0a, 0x91, 0xdf, 0xc5, 0xc3, 0xb0, 0x54, 0x61, - 0x96, 0x24, 0x35, 0x7e, 0x35, 0x0b, 0xe7, 0xfb, 0xc9, 0xff, 0xa4, 0xa6, 0x6f, 0x66, 0x57, 0x06, - 0xb8, 0x33, 0x1c, 0xbf, 0x9d, 0x2d, 0xc1, 0xe4, 0x9a, 0xb7, 0x6b, 0xb7, 0x9d, 0x6f, 0xe1, 0xbd, - 0x2e, 0x34, 0x87, 0xc1, 0xc1, 0x70, 0x95, 0x12, 0x7d, 0xb5, 0xc7, 0x88, 0xce, 0x3d, 0x14, 0xdb, - 0xdc, 0xc7, 0x75, 0xac, 0xb8, 0x05, 0xa3, 0x65, 0xb7, 0x1d, 0xd0, 0x47, 0x41, 0xcc, 0x79, 0x8e, - 0x03, 0xe3, 0xce, 0x73, 0x12, 0xd5, 0xf8, 0x7f, 0xb2, 0x70, 0xa1, 0xaf, 0x00, 0x4c, 0x36, 0xf4, - 0x51, 0xbb, 0x3a, 0x88, 0xd4, 0x7c, 0xfc, 0xb0, 0x2d, 0x24, 0x2c, 0x37, 0x8e, 0xb5, 0x5b, 0x3e, - 0xf7, 0x5f, 0x64, 0xc4, 0x20, 0x7d, 0x0e, 0x46, 0xb0, 0xaa, 0x70, 0x88, 0xb8, 0x6e, 0x08, 0x77, - 0x61, 0x47, 0xd7, 0x0d, 0x71, 0x34, 0x72, 0x13, 0x0a, 0x65, 0xbb, 0xd9, 0x54, 0x5c, 0x0b, 0x51, - 0xae, 0xaf, 0x23, 0x2c, 0x66, 0xe8, 0x23, 0x11, 0xc9, 0x1b, 0x00, 0xfc, 0x6f, 0xe5, 0xac, 0xc0, - 0xcd, 0x52, 0x90, 0xc5, 0x8e, 0x0b, 0x05, 0x19, 0x83, 0x88, 0xd5, 0xdd, 0xd0, 0x07, 0x8a, 0x07, - 0x11, 0x63, 0x00, 0x2d, 0x88, 0x18, 0x03, 0x18, 0xbf, 0x96, 0x83, 0xe7, 0xfa, 0xdf, 0xe2, 0xc8, - 0x03, 0x7d, 0x0a, 0x5e, 0x1e, 0xe8, 0xee, 0x77, 0xfc, 0x1c, 0xc8, 0x90, 0x7c, 0x7c, 0x40, 0xae, - 0x24, 0xcd, 0x8b, 0x3f, 0x3a, 0x9a, 0x57, 0xac, 0xc7, 0xee, 0xba, 0x4e, 0x5b, 0x79, 0x23, 0xf8, - 0x26, 0x40, 0x2d, 0xb0, 0x03, 0xa7, 0x7e, 0x77, 0xeb, 0x9e, 0xf4, 0x58, 0xbf, 0x35, 0x58, 0xcb, - 0x22, 0x3a, 0xbe, 0xaf, 0x08, 0xf5, 0x39, 0x42, 0xad, 0x0f, 0x0f, 0xf6, 0xb5, 0x7b, 0x6a, 0x84, - 0x7c, 0xee, 0x4b, 0x50, 0x8c, 0x93, 0x92, 0xcb, 0x90, 0xc7, 0x06, 0x28, 0x36, 0xd2, 0x31, 0x0e, - 0x58, 0x7e, 0xee, 0xbe, 0x58, 0x3b, 0x4b, 0x30, 0x29, 0x1e, 0xa6, 0x75, 0x8d, 0x18, 0x7e, 0xaf, - 0xf2, 0x5d, 0x3b, 0xa9, 0x15, 0x8b, 0x11, 0x19, 0x7f, 0x96, 0x81, 0xb3, 0x3d, 0xef, 0xc7, 0x64, - 0x5d, 0x9f, 0xb0, 0x17, 0x8f, 0xbb, 0x50, 0x1f, 0x3b, 0x57, 0xe7, 0x7e, 0x42, 0xae, 0xfd, 0x77, - 0x60, 0xbc, 0xd6, 0xdd, 0x8e, 0x5f, 0xb2, 0xb8, 0xff, 0xb2, 0x02, 0x57, 0x4f, 0x30, 0x15, 0x9f, - 0xf5, 0x5f, 0xbe, 0xbc, 0x0b, 0xc3, 0x0a, 0x7e, 0xf1, 0xc3, 0xfe, 0x87, 0x8e, 0x51, 0xe8, 0xb7, - 0xa6, 0x0e, 0x62, 0x8c, 0xc8, 0xf8, 0x95, 0x6c, 0xfa, 0x6d, 0x95, 0xdd, 0xb5, 0x4f, 0x70, 0x5b, - 0xbd, 0x53, 0x5e, 0x3f, 0xbe, 0xef, 0xff, 0xa1, 0xec, 0x3b, 0x3e, 0x44, 0x8a, 0x1d, 0x4f, 0xaa, - 0xf7, 0xc4, 0x43, 0xa4, 0xdc, 0x1d, 0x7d, 0xfd, 0x21, 0x52, 0x22, 0x93, 0xd7, 0x61, 0x74, 0xc5, - 0xe5, 0xfe, 0xa4, 0xb2, 0xc7, 0xdc, 0x73, 0x48, 0x02, 0xd5, 0xed, 0x31, 0xc4, 0x64, 0x77, 0x0b, - 0x7d, 0xe2, 0xa5, 0x79, 0x37, 0xde, 0x2d, 0x62, 0xcb, 0x45, 0x57, 0x82, 0xe9, 0x64, 0xc6, 0x4f, - 0x64, 0x61, 0x92, 0x2f, 0x5e, 0xae, 0xa4, 0x7d, 0x6a, 0x15, 0xe0, 0x6f, 0x6a, 0x0a, 0x70, 0x19, - 0xea, 0x40, 0xed, 0xda, 0x40, 0xea, 0xef, 0x3d, 0x20, 0x49, 0x1a, 0x62, 0xc2, 0xb8, 0x0a, 0xed, - 0xaf, 0xf9, 0xbe, 0x11, 0x45, 0xc5, 0x10, 0x7b, 0x07, 0x3e, 0x3f, 0xf8, 0xa6, 0xc6, 0xc3, 0xf8, - 0x6b, 0x59, 0x98, 0x50, 0x1e, 0x2a, 0x9f, 0xda, 0x81, 0xff, 0x92, 0x36, 0xf0, 0x73, 0xa1, 0x49, - 0x72, 0xd8, 0xb3, 0x81, 0xc6, 0xbd, 0x0b, 0xd3, 0x09, 0x92, 0xf8, 0x7b, 0x6f, 0x66, 0x90, 0xf7, - 0xde, 0x57, 0x93, 0xee, 0xfa, 0x3c, 0x52, 0x65, 0xe8, 0xae, 0xaf, 0xc6, 0x07, 0xf8, 0xa9, 0x2c, - 0xcc, 0x8a, 0x5f, 0x18, 0x93, 0x86, 0xef, 0xde, 0x4f, 0xed, 0x5c, 0x94, 0xb4, 0xb9, 0x98, 0xd7, - 0xe7, 0x42, 0xe9, 0x60, 0xef, 0x29, 0x31, 0xfe, 0x0a, 0xc0, 0x5c, 0x2f, 0x82, 0x81, 0x3d, 0x7f, - 0x22, 0xbb, 0xea, 0xec, 0x00, 0x76, 0xd5, 0x2b, 0x50, 0xc4, 0xaa, 0x44, 0x04, 0x0b, 0x9f, 0xdd, - 0x01, 0x72, 0x91, 0xc0, 0xcd, 0x03, 0x07, 0x89, 0x28, 0x18, 0x7e, 0xec, 0x12, 0x90, 0xa0, 0x24, - 0xbf, 0x94, 0x81, 0x49, 0x04, 0x2e, 0x3d, 0xa4, 0xed, 0x00, 0x99, 0xe5, 0x85, 0x19, 0x70, 0xa8, - 0x1f, 0xaf, 0x05, 0x9e, 0xd3, 0xde, 0x15, 0x0a, 0xf2, 0x6d, 0xa1, 0x20, 0x7f, 0x8b, 0x2b, 0xf6, - 0xaf, 0xd5, 0xdd, 0xd6, 0xf5, 0x5d, 0xcf, 0x7e, 0xe8, 0xf0, 0x37, 0x78, 0xbb, 0x79, 0x3d, 0x0a, - 0x94, 0xdc, 0x71, 0x62, 0xa1, 0x8f, 0x05, 0x2b, 0x7c, 0x7c, 0xe0, 0x0d, 0xa5, 0x58, 0x6d, 0xfc, - 0xae, 0xa2, 0xb7, 0x88, 0xfc, 0x00, 0x9c, 0xe1, 0xee, 0xe9, 0x4c, 0xe4, 0x75, 0xda, 0x5d, 0xb7, - 0xeb, 0x2f, 0xda, 0xf5, 0x7d, 0x76, 0xee, 0x71, 0x57, 0x06, 0xec, 0x79, 0x3d, 0x2c, 0xb4, 0xb6, - 0x79, 0xa9, 0xe6, 0xba, 0x95, 0xce, 0x80, 0x2c, 0xc3, 0x34, 0x2f, 0x2a, 0x75, 0x03, 0xb7, 0x56, - 0xb7, 0x9b, 0x4e, 0x7b, 0x17, 0xef, 0xd4, 0x05, 0x7e, 0x1e, 0xdb, 0xdd, 0xc0, 0xb5, 0x7c, 0x0e, - 0x57, 0xaf, 0x2e, 0x09, 0x22, 0x52, 0x85, 0x29, 0x93, 0xda, 0x8d, 0xfb, 0xf6, 0xa3, 0xb2, 0xdd, - 0xb1, 0xeb, 0xec, 0x22, 0x54, 0xc0, 0xc7, 0x24, 0xbc, 0x9b, 0x79, 0xd4, 0x6e, 0x58, 0x2d, 0xfb, - 0x91, 0x55, 0x17, 0x85, 0xba, 0x0e, 0x4b, 0xa3, 0x0b, 0x59, 0x39, 0xed, 0x90, 0xd5, 0x68, 0x9c, - 0x95, 0xd3, 0xee, 0xcd, 0x2a, 0xa2, 0x93, 0xac, 0x36, 0x6c, 0x6f, 0x97, 0x06, 0xdc, 0x84, 0x8d, - 0xdd, 0xc7, 0x33, 0x0a, 0xab, 0x00, 0xcb, 0x2c, 0x34, 0x67, 0x8b, 0xb3, 0x52, 0xe8, 0xd8, 0xca, - 0xdb, 0xf2, 0x9c, 0x80, 0xaa, 0x3d, 0x1c, 0xc3, 0x66, 0xe1, 0xf8, 0xa3, 0xf1, 0x5f, 0xaf, 0x2e, - 0x26, 0x28, 0x23, 0x6e, 0x4a, 0x27, 0xc7, 0x13, 0xdc, 0xd2, 0x7b, 0x99, 0xa0, 0x0c, 0xb9, 0xa9, - 0xfd, 0x9c, 0xc0, 0x7e, 0x2a, 0xdc, 0x7a, 0x74, 0x34, 0x41, 0x49, 0x56, 0xd9, 0xa0, 0x05, 0xb4, - 0xcd, 0x56, 0xb4, 0x30, 0xe1, 0x9b, 0xc4, 0xa6, 0xbd, 0x20, 0xec, 0x50, 0x8a, 0x9e, 0x2c, 0xb6, - 0x52, 0x0c, 0xfa, 0xe2, 0xc4, 0xe4, 0x2f, 0xc1, 0xd4, 0x03, 0x9f, 0xde, 0xae, 0xae, 0xd7, 0xa4, - 0x43, 0x3e, 0xde, 0xb6, 0x27, 0x17, 0x6e, 0x1c, 0xb3, 0xe9, 0x5c, 0x53, 0x69, 0x30, 0x5e, 0x31, - 0x9f, 0xb7, 0xae, 0x4f, 0xad, 0x1d, 0xa7, 0xe3, 0x87, 0xa1, 0x41, 0xd4, 0x79, 0x8b, 0x55, 0x65, - 0x2c, 0xc3, 0x74, 0x82, 0x0d, 0x99, 0x04, 0x60, 0x40, 0xeb, 0xc1, 0x6a, 0x6d, 0x69, 0xa3, 0xf8, - 0x0c, 0x29, 0xc2, 0x38, 0xfe, 0x5e, 0x5a, 0x2d, 0x2d, 0xae, 0x2c, 0x55, 0x8a, 0x19, 0x32, 0x0d, - 0x13, 0x08, 0xa9, 0x54, 0x6b, 0x1c, 0x94, 0xe5, 0xd1, 0x2a, 0xcd, 0x22, 0xff, 0x74, 0x03, 0xf6, - 0x01, 0xe0, 0x99, 0x62, 0xfc, 0xcd, 0x2c, 0x9c, 0x95, 0xc7, 0x0a, 0x0d, 0x0e, 0x5c, 0x6f, 0xdf, - 0x69, 0xef, 0x3e, 0xe5, 0xa7, 0xc3, 0x6d, 0xed, 0x74, 0x78, 0x21, 0x76, 0x52, 0xc7, 0x7a, 0xd9, - 0xe7, 0x88, 0xf8, 0x9f, 0x0b, 0x70, 0xa1, 0x2f, 0x15, 0xf9, 0x32, 0x3b, 0xcd, 0x1d, 0xda, 0x0e, - 0xaa, 0x8d, 0x26, 0xdd, 0x70, 0x5a, 0xd4, 0xed, 0x06, 0xc2, 0x64, 0xf4, 0x12, 0x5e, 0x70, 0xb1, - 0xd0, 0x72, 0x1a, 0x4d, 0x6a, 0x05, 0xbc, 0x58, 0x5b, 0x6e, 0x49, 0x6a, 0xc6, 0x32, 0x8c, 0x9d, - 0x5e, 0x6d, 0x07, 0xd4, 0x7b, 0x88, 0xc6, 0x29, 0x21, 0xcb, 0x7d, 0x4a, 0x3b, 0x96, 0xcd, 0x4a, - 0x2d, 0x47, 0x14, 0xeb, 0x2c, 0x13, 0xd4, 0xe4, 0xb6, 0xc2, 0xb2, 0xcc, 0xc4, 0xe1, 0xfb, 0xf6, - 0x23, 0xf1, 0x5a, 0x2e, 0xc2, 0x1a, 0x85, 0x2c, 0xb9, 0xb7, 0x51, 0xcb, 0x7e, 0x64, 0x26, 0x49, - 0xc8, 0xd7, 0xe0, 0x94, 0x38, 0x80, 0x84, 0xb7, 0xa8, 0xec, 0x31, 0xf7, 0x45, 0x7d, 0xe9, 0xf1, - 0xd1, 0xfc, 0x19, 0x19, 0xc4, 0x49, 0xfa, 0x07, 0xa7, 0xf5, 0x3a, 0x9d, 0x0b, 0xd9, 0x60, 0x07, - 0x72, 0x6c, 0x38, 0xee, 0x53, 0xdf, 0xb7, 0x77, 0xe5, 0xcb, 0x3a, 0xb7, 0xaf, 0x57, 0x06, 0xd3, - 0x6a, 0xf1, 0x72, 0xb3, 0x27, 0x25, 0x59, 0x86, 0xc9, 0x2d, 0xba, 0xad, 0xce, 0xcf, 0x70, 0xb8, - 0x55, 0x15, 0x0f, 0xe8, 0x76, 0xef, 0xc9, 0x89, 0xd1, 0x11, 0x07, 0x15, 0x66, 0x8f, 0x0e, 0x57, - 0x1c, 0x3f, 0xa0, 0x6d, 0xea, 0x61, 0x14, 0x82, 0x11, 0xdc, 0x0c, 0xe6, 0x22, 0x09, 0x59, 0x2f, - 0x5f, 0x7c, 0xfe, 0xf1, 0xd1, 0xfc, 0x05, 0xee, 0x4f, 0xd2, 0x14, 0x70, 0x2b, 0x16, 0x79, 0x3c, - 0xc9, 0x95, 0x7c, 0x03, 0xa6, 0x4c, 0xb7, 0x1b, 0x38, 0xed, 0xdd, 0x5a, 0xe0, 0xd9, 0x01, 0xdd, - 0xe5, 0x07, 0x52, 0x14, 0xee, 0x20, 0x56, 0x2a, 0xde, 0x5a, 0x38, 0xd0, 0xf2, 0x05, 0x54, 0x3b, - 0x11, 0x74, 0x02, 0xf2, 0x75, 0x98, 0xe4, 0x7e, 0x82, 0x61, 0x05, 0xa3, 0x5a, 0xd4, 0x54, 0xbd, - 0x70, 0xf3, 0x06, 0xbf, 0xa0, 0x72, 0x7f, 0xc3, 0xb4, 0x0a, 0x62, 0xdc, 0xc8, 0x07, 0x62, 0xb0, - 0xd6, 0x9d, 0xf6, 0x6e, 0xb8, 0x8c, 0x01, 0x47, 0xfe, 0xb5, 0x68, 0x48, 0x3a, 0xac, 0xb9, 0x72, - 0x19, 0xf7, 0xb0, 0xd4, 0x48, 0xf2, 0x21, 0x01, 0x5c, 0x28, 0xf9, 0xbe, 0xe3, 0x07, 0xc2, 0xb0, - 0x7a, 0xe9, 0x11, 0xad, 0x77, 0x19, 0xf2, 0x96, 0xeb, 0xed, 0x53, 0x8f, 0x9b, 0xf6, 0x0d, 0x2d, - 0x5e, 0x7b, 0x7c, 0x34, 0xff, 0xb2, 0x8d, 0x88, 0x96, 0xb0, 0xc5, 0xb6, 0xa8, 0x44, 0xb5, 0x0e, - 0x38, 0xae, 0xd2, 0x87, 0xfe, 0x4c, 0xc9, 0xd7, 0xe1, 0x74, 0xd9, 0xf6, 0x69, 0xb5, 0xed, 0xd3, - 0xb6, 0xef, 0x04, 0xce, 0x43, 0x2a, 0x06, 0x15, 0x0f, 0xbf, 0x02, 0xc6, 0x68, 0x37, 0xea, 0xb6, - 0xcf, 0x3e, 0xcc, 0x10, 0xc5, 0x12, 0x93, 0xa2, 0x54, 0xd3, 0x83, 0x8b, 0x71, 0x94, 0x81, 0x62, - 0x7c, 0xd8, 0xc9, 0x57, 0x60, 0x94, 0x9b, 0x24, 0x50, 0x7f, 0x4f, 0xb8, 0xb8, 0xc9, 0x17, 0xee, - 0x10, 0xae, 0x13, 0x09, 0xa7, 0x04, 0x6e, 0xf0, 0x40, 0xd5, 0xf7, 0x5a, 0x74, 0x4a, 0x90, 0x44, - 0xa4, 0x01, 0xe3, 0x7c, 0x64, 0x29, 0xc6, 0x25, 0x11, 0x96, 0x69, 0xcf, 0xab, 0x2b, 0x59, 0x14, - 0xc5, 0xf8, 0xa3, 0xca, 0x5b, 0xcc, 0x1f, 0x47, 0xd0, 0xaa, 0xd0, 0xb8, 0x2e, 0x02, 0x14, 0x24, - 0xa1, 0x71, 0x16, 0xce, 0xf4, 0x68, 0xb3, 0xf1, 0x10, 0x9f, 0xc1, 0x7a, 0xd4, 0x48, 0xbe, 0x02, - 0xb3, 0x48, 0x58, 0x76, 0xdb, 0x6d, 0x5a, 0x0f, 0x70, 0xeb, 0x90, 0xaa, 0xa3, 0x1c, 0x7f, 0x6b, - 0xe5, 0xfd, 0xad, 0x87, 0x08, 0x56, 0x5c, 0x83, 0x94, 0xca, 0xc1, 0xf8, 0xb9, 0x2c, 0xcc, 0x89, - 0xdd, 0xc8, 0xa4, 0x75, 0xd7, 0x6b, 0x3c, 0xfd, 0xa7, 0xdf, 0x92, 0x76, 0xfa, 0x5d, 0x0a, 0x7d, - 0x9a, 0xd3, 0x3a, 0xd9, 0xe7, 0xf0, 0xfb, 0x95, 0x0c, 0x9c, 0xef, 0x47, 0xc4, 0x46, 0x27, 0x8c, - 0xc3, 0x32, 0x9a, 0x88, 0xb7, 0xd2, 0x81, 0x19, 0x9c, 0xd0, 0xf2, 0x1e, 0xad, 0xef, 0xfb, 0xcb, - 0xae, 0x1f, 0xa0, 0x61, 0x6c, 0xb6, 0xc7, 0x43, 0xcd, 0xab, 0xa9, 0x0f, 0x35, 0xa7, 0xf9, 0x2a, - 0xab, 0x23, 0x0f, 0x1e, 0x29, 0x66, 0x9f, 0x1e, 0xfa, 0x66, 0x1a, 0x6b, 0x34, 0x72, 0x2c, 0x75, - 0x83, 0xbd, 0x75, 0x8f, 0xee, 0x50, 0x8f, 0xb6, 0xeb, 0xf4, 0x33, 0x66, 0xe4, 0xa8, 0x77, 0x6e, - 0x20, 0x6d, 0xc3, 0xaf, 0x8c, 0xc3, 0x6c, 0x1a, 0x19, 0x1b, 0x17, 0xe5, 0x82, 0x1b, 0x4f, 0xf7, - 0xf2, 0xa3, 0x19, 0x18, 0xaf, 0xd1, 0xba, 0xdb, 0x6e, 0xdc, 0xc6, 0xe7, 0x70, 0x31, 0x3a, 0x16, - 0x3f, 0xe0, 0x19, 0xdc, 0xda, 0x89, 0xbd, 0x93, 0x7f, 0x74, 0x34, 0xff, 0xde, 0x60, 0xf7, 0xca, - 0xba, 0x8b, 0x7e, 0xc9, 0x01, 0x86, 0x23, 0x0d, 0xab, 0x40, 0xcd, 0xb6, 0x56, 0x29, 0x59, 0x84, - 0x09, 0xf1, 0xb9, 0xba, 0x6a, 0x18, 0x1e, 0xee, 0xf6, 0x2d, 0x0b, 0x12, 0x71, 0xc7, 0x34, 0x12, - 0x72, 0x13, 0x72, 0x0f, 0x16, 0x6e, 0x8b, 0x39, 0x90, 0x01, 0x5d, 0x1f, 0x2c, 0xdc, 0x46, 0xd5, - 0x15, 0xbb, 0x0e, 0x4c, 0x74, 0x17, 0xb4, 0x17, 0xea, 0x07, 0x0b, 0xb7, 0xc9, 0x0f, 0xc1, 0xa9, - 0x8a, 0xe3, 0x8b, 0x2a, 0xb8, 0xb9, 0x6d, 0x03, 0xdd, 0x4b, 0x86, 0x7b, 0xac, 0xde, 0x2f, 0xa4, - 0xae, 0xde, 0xe7, 0x1b, 0x21, 0x13, 0x8b, 0xdb, 0xf2, 0x36, 0xe2, 0xe1, 0x86, 0xd2, 0xeb, 0x21, - 0x1f, 0xc2, 0x24, 0xaa, 0x5e, 0xd1, 0x02, 0x19, 0xc3, 0x23, 0x8e, 0xf4, 0xa8, 0xf9, 0x73, 0xa9, - 0x35, 0x9f, 0x43, 0x4d, 0xae, 0x85, 0x76, 0xcc, 0x18, 0x4a, 0x51, 0xbb, 0xa1, 0x6b, 0x9c, 0xc9, - 0x5d, 0x98, 0x12, 0xa2, 0xd2, 0xda, 0xce, 0xc6, 0x1e, 0xad, 0xd8, 0x87, 0xe2, 0x71, 0x19, 0x6f, - 0x5f, 0x42, 0xbe, 0xb2, 0xdc, 0x1d, 0x2b, 0xd8, 0xa3, 0x56, 0xc3, 0xd6, 0x84, 0x8a, 0x18, 0x21, - 0xf9, 0x41, 0x18, 0x5b, 0x71, 0xeb, 0x4c, 0x4a, 0xc6, 0x9d, 0x81, 0xbf, 0x37, 0xbf, 0x8f, 0x09, - 0x45, 0x38, 0x38, 0x26, 0xfa, 0x7c, 0x74, 0x34, 0xff, 0xe6, 0x49, 0x17, 0x8d, 0x52, 0x81, 0xa9, - 0xd6, 0x46, 0xca, 0x50, 0xd8, 0xa2, 0xdb, 0xac, 0xb7, 0xf1, 0x64, 0x03, 0x12, 0x2c, 0xcc, 0x49, - 0xc4, 0x2f, 0xcd, 0x9c, 0x44, 0xc0, 0x88, 0x07, 0xd3, 0x38, 0x3e, 0xeb, 0xb6, 0xef, 0x1f, 0xb8, - 0x5e, 0x03, 0xa3, 0xca, 0xf6, 0x7a, 0xca, 0x5e, 0x48, 0x1d, 0xfc, 0xf3, 0x7c, 0xf0, 0x3b, 0x0a, - 0x07, 0x55, 0xd8, 0x4b, 0xb0, 0x27, 0xdf, 0x80, 0x49, 0x93, 0x7e, 0xb3, 0xeb, 0x78, 0xf4, 0xfe, - 0xed, 0x12, 0x7e, 0x95, 0xe3, 0x9a, 0x93, 0x8e, 0x5e, 0xc8, 0x25, 0x4a, 0x8f, 0xc3, 0xa4, 0xb6, - 0xc8, 0x6a, 0xed, 0xd8, 0xfa, 0x6b, 0x81, 0x4a, 0x42, 0xd6, 0x61, 0xac, 0x42, 0x1f, 0x3a, 0x75, - 0x8a, 0xae, 0x04, 0xc2, 0x94, 0x2f, 0x8c, 0x96, 0x1e, 0x95, 0x70, 0xbd, 0x49, 0x03, 0x01, 0xdc, - 0x31, 0x41, 0xb7, 0x16, 0x0b, 0x11, 0xc9, 0x2d, 0xc8, 0x55, 0x2b, 0xeb, 0xc2, 0x92, 0x4f, 0x5a, - 0xe8, 0x57, 0x1b, 0xeb, 0x32, 0xb6, 0x34, 0x1a, 0x7f, 0x38, 0x0d, 0xcd, 0x0e, 0xb0, 0x5a, 0x59, - 0x27, 0x3b, 0x30, 0x81, 0x03, 0xb0, 0x4c, 0x6d, 0x3e, 0xb6, 0x53, 0x3d, 0xc6, 0xf6, 0x5a, 0xea, - 0xd8, 0xce, 0xf1, 0xb1, 0xdd, 0x13, 0xd4, 0x5a, 0xb0, 0x5c, 0x95, 0x2d, 0x13, 0x3f, 0x45, 0x00, - 0x6f, 0x19, 0x2e, 0x76, 0x63, 0x05, 0x1f, 0xb7, 0x85, 0xf8, 0x29, 0xe3, 0x7d, 0x87, 0x31, 0x67, - 0x7b, 0x1a, 0x0a, 0x27, 0xf9, 0x90, 0x2f, 0x41, 0x7e, 0x6d, 0x3f, 0xb0, 0xe7, 0xa6, 0xb5, 0x71, - 0x64, 0x20, 0xd9, 0x7d, 0xd4, 0x18, 0xba, 0xfb, 0x5a, 0x40, 0x0a, 0xa4, 0x21, 0x0b, 0x30, 0xb2, - 0x5e, 0xdd, 0xac, 0x35, 0xdd, 0x60, 0x8e, 0x84, 0x77, 0x1a, 0xd2, 0x71, 0x1e, 0x5a, 0x7e, 0xd3, - 0xd5, 0x93, 0x00, 0x48, 0x44, 0x36, 0x7d, 0xcb, 0xb6, 0xd7, 0x38, 0xb0, 0x3d, 0xf4, 0x00, 0x9b, - 0xd1, 0xaa, 0x55, 0x4a, 0xf8, 0xf4, 0xed, 0x09, 0x40, 0xcc, 0x2d, 0x4c, 0x65, 0x21, 0xb4, 0x01, - 0xd3, 0x62, 0x99, 0x88, 0xae, 0xdd, 0xbf, 0x5d, 0x32, 0xfe, 0xbd, 0x0c, 0x6e, 0x98, 0xe4, 0x65, - 0xf4, 0x59, 0x0f, 0x1f, 0x78, 0x51, 0xaf, 0x69, 0x77, 0x62, 0x21, 0x16, 0x39, 0x0a, 0x79, 0x15, - 0x86, 0x6f, 0xdb, 0x75, 0x1a, 0xc8, 0x87, 0x1d, 0x44, 0xde, 0x41, 0x88, 0xaa, 0x04, 0xe5, 0x38, - 0x4c, 0x96, 0xe3, 0x0b, 0xa9, 0x14, 0x65, 0x5f, 0x2b, 0x97, 0xe4, 0xbb, 0x0e, 0xca, 0x72, 0x62, - 0x01, 0x2a, 0xe9, 0xd9, 0x62, 0x36, 0x90, 0xa9, 0x1c, 0x8c, 0x3f, 0xc9, 0x44, 0x3b, 0x00, 0x79, - 0x09, 0xf2, 0xe6, 0x7a, 0xd8, 0x7e, 0xee, 0x0d, 0x15, 0x6b, 0x3e, 0x22, 0x90, 0x0f, 0xe0, 0x94, - 0xc2, 0x27, 0x61, 0x90, 0xf9, 0x22, 0xba, 0xeb, 0x28, 0x2d, 0x49, 0xb7, 0xca, 0x4c, 0xe7, 0x81, - 0x82, 0x6b, 0x54, 0x50, 0xa1, 0x6d, 0x87, 0xf3, 0x56, 0x3a, 0xab, 0xf2, 0x6e, 0x20, 0x42, 0xbc, - 0xb3, 0x69, 0x1c, 0xb8, 0xc7, 0x8e, 0xf1, 0x9b, 0x19, 0xed, 0xcb, 0x0e, 0xd3, 0x5c, 0x65, 0x8e, - 0x49, 0x73, 0xf5, 0x06, 0x40, 0xa9, 0x1b, 0xb8, 0x4b, 0x6d, 0xcf, 0x6d, 0x72, 0xed, 0x82, 0x88, - 0x32, 0x8a, 0x3a, 0x53, 0x8a, 0x60, 0xcd, 0xb1, 0x20, 0x44, 0x4e, 0xb5, 0x5d, 0xcd, 0x7d, 0x5c, - 0xdb, 0x55, 0xe3, 0xf7, 0x32, 0xda, 0xda, 0x66, 0x12, 0x99, 0xfc, 0x3c, 0x14, 0xd3, 0x82, 0xe4, - 0xe7, 0x11, 0x7d, 0x1c, 0xff, 0x62, 0x06, 0x4e, 0x73, 0x23, 0xd0, 0xd5, 0x6e, 0x6b, 0x9b, 0x7a, - 0x9b, 0x76, 0xd3, 0x69, 0x70, 0x8f, 0x34, 0x2e, 0x6c, 0x5e, 0x49, 0x7e, 0x28, 0xe9, 0xf8, 0xfc, - 0x02, 0xc7, 0x8d, 0x52, 0xad, 0x36, 0x16, 0x5a, 0x0f, 0xc3, 0x52, 0xf5, 0x02, 0x97, 0x4e, 0x6f, - 0xfc, 0x6a, 0x06, 0x9e, 0x3f, 0xb6, 0x16, 0x72, 0x1d, 0x46, 0x64, 0x78, 0xd7, 0x0c, 0x0e, 0x3c, - 0x1a, 0x64, 0x25, 0x43, 0xbb, 0x4a, 0x2c, 0xf2, 0x55, 0x38, 0xa5, 0xb2, 0xda, 0xf0, 0x6c, 0x47, - 0x0d, 0xa2, 0x9a, 0xd2, 0xea, 0x80, 0xa1, 0xc4, 0x25, 0xa3, 0x74, 0x26, 0xc6, 0xff, 0x99, 0x51, - 0x12, 0xdf, 0x3d, 0xa5, 0xf2, 0xf2, 0x2d, 0x4d, 0x5e, 0x96, 0xd1, 0x82, 0xc2, 0x5e, 0xb1, 0xb2, - 0xd4, 0x3b, 0xce, 0x94, 0x62, 0x58, 0x88, 0x80, 0xef, 0x64, 0x61, 0xec, 0x81, 0x4f, 0x3d, 0xfe, - 0xc0, 0xf9, 0xd9, 0x8a, 0x0a, 0x13, 0xf6, 0x6b, 0xa0, 0xb8, 0x1d, 0x7f, 0x94, 0x41, 0xc5, 0xb7, - 0x4a, 0xc1, 0x46, 0x43, 0x49, 0x76, 0x81, 0xa3, 0x81, 0x69, 0x2e, 0x10, 0xca, 0x63, 0x7b, 0xac, - 0xe8, 0x79, 0x6f, 0x30, 0xf9, 0xd1, 0x0a, 0x79, 0x0f, 0x86, 0x1e, 0xa0, 0x1a, 0x4f, 0xf7, 0x3e, - 0x0e, 0xf9, 0x63, 0x21, 0xdf, 0xa4, 0xbb, 0xec, 0x4f, 0xf5, 0x8c, 0xc1, 0x32, 0x52, 0x83, 0x91, - 0xb2, 0x47, 0x31, 0x8d, 0x5d, 0x7e, 0x70, 0x0f, 0xba, 0x3a, 0x27, 0x89, 0x7b, 0xd0, 0x09, 0x4e, - 0xc6, 0xcf, 0x66, 0x81, 0x44, 0x7d, 0xc4, 0xf8, 0xef, 0xfe, 0x53, 0x3b, 0xe9, 0xef, 0x6a, 0x93, - 0x7e, 0x21, 0x31, 0xe9, 0xbc, 0x7b, 0x03, 0xcd, 0xfd, 0x6f, 0x65, 0xe0, 0x74, 0x3a, 0x21, 0xb9, - 0x04, 0xc3, 0x6b, 0x1b, 0xeb, 0xd2, 0x81, 0x5d, 0x74, 0xc5, 0xed, 0xe0, 0xbd, 0xdc, 0x14, 0x45, - 0xe4, 0x35, 0x18, 0xfe, 0xb2, 0x59, 0x66, 0xe7, 0x90, 0x12, 0x6b, 0xf5, 0x9b, 0x9e, 0x55, 0xd7, - 0x8f, 0x22, 0x81, 0xa4, 0xce, 0x6d, 0xee, 0x89, 0xcd, 0xed, 0x4f, 0x65, 0x61, 0xaa, 0x54, 0xaf, - 0x53, 0xdf, 0x67, 0x42, 0x0e, 0xf5, 0x83, 0xa7, 0x76, 0x62, 0xd3, 0x5d, 0xd3, 0xb5, 0xbe, 0x0d, - 0x34, 0xab, 0xbf, 0x93, 0x81, 0x53, 0x92, 0xea, 0xa1, 0x43, 0x0f, 0x36, 0xf6, 0x3c, 0xea, 0xef, - 0xb9, 0xcd, 0xc6, 0xc0, 0x01, 0x9d, 0x99, 0xa0, 0x87, 0x51, 0x1a, 0xd5, 0xd7, 0xee, 0x1d, 0x84, - 0x68, 0x82, 0x1e, 0x8f, 0xe4, 0x78, 0x1d, 0x46, 0x4a, 0x9d, 0x8e, 0xe7, 0x3e, 0xe4, 0x9f, 0xfd, - 0x84, 0x70, 0x28, 0xe4, 0x20, 0xcd, 0x01, 0x91, 0x83, 0x58, 0x33, 0x2a, 0xb4, 0xcd, 0x63, 0xe9, - 0x4c, 0xf0, 0x66, 0x34, 0x68, 0x5b, 0x95, 0x61, 0xb1, 0xdc, 0xa8, 0x01, 0x59, 0xf7, 0xdc, 0x96, - 0x1b, 0xd0, 0x06, 0xef, 0x0f, 0xfa, 0x6d, 0x1e, 0x1b, 0x04, 0x64, 0xc3, 0x09, 0x9a, 0x5a, 0x10, - 0x90, 0x80, 0x01, 0x4c, 0x0e, 0x37, 0xfe, 0xb7, 0x21, 0x18, 0x57, 0x47, 0x87, 0x18, 0x3c, 0x4a, - 0xab, 0xeb, 0xa9, 0xce, 0xc3, 0x36, 0x42, 0x4c, 0x51, 0x12, 0xf9, 0xdc, 0x67, 0x8f, 0xf5, 0xb9, - 0xdf, 0x82, 0x89, 0x75, 0xcf, 0xed, 0xb8, 0x3e, 0x6d, 0xf0, 0xf4, 0xa6, 0x7c, 0x2b, 0x9c, 0x51, - 0xee, 0x78, 0x6c, 0x22, 0xf1, 0x9d, 0x10, 0x35, 0x1c, 0x1d, 0x81, 0x6d, 0xc5, 0x93, 0x9f, 0xea, - 0x7c, 0xb8, 0x09, 0x82, 0xed, 0x8b, 0x90, 0x59, 0xa1, 0x09, 0x02, 0x83, 0xe8, 0x26, 0x08, 0x0c, - 0xa2, 0x7e, 0x6b, 0x43, 0x4f, 0xea, 0x5b, 0x23, 0x3f, 0x9b, 0x81, 0xb1, 0x52, 0xbb, 0x2d, 0x7c, - 0xf9, 0x8f, 0x71, 0x66, 0xfc, 0xaa, 0xb0, 0x42, 0x78, 0xf3, 0x63, 0x59, 0x21, 0xa0, 0xdc, 0xe2, - 0xa3, 0xa4, 0x1a, 0x55, 0xa8, 0xde, 0x72, 0x94, 0x76, 0x90, 0x37, 0xa1, 0x18, 0x2e, 0xf2, 0x6a, - 0xbb, 0x41, 0x1f, 0x51, 0x7f, 0x6e, 0xe4, 0x62, 0xee, 0xca, 0x84, 0x08, 0x96, 0xa7, 0x4a, 0xa6, - 0x71, 0x44, 0xb2, 0x01, 0x60, 0x87, 0xab, 0x2b, 0x96, 0x58, 0x26, 0xb9, 0xfc, 0x84, 0xf4, 0x8c, - 0xbf, 0xf1, 0xa1, 0x47, 0x95, 0x9e, 0x23, 0x3e, 0xa4, 0x05, 0x53, 0x3c, 0xab, 0x0b, 0x66, 0x7b, - 0xc5, 0x98, 0xb0, 0x70, 0xec, 0x3c, 0xbc, 0x24, 0x74, 0x55, 0xcf, 0x8a, 0x5c, 0x31, 0x98, 0x40, - 0xd6, 0x4a, 0x09, 0x10, 0x1b, 0xe7, 0xcd, 0x43, 0x13, 0x9a, 0x67, 0x92, 0xed, 0xe5, 0x8b, 0xfe, - 0xa7, 0x32, 0x70, 0x5a, 0x5d, 0xf4, 0xb5, 0xee, 0x76, 0xcb, 0xc1, 0xbb, 0x20, 0xb9, 0x06, 0xa3, - 0x62, 0x4d, 0x86, 0x97, 0xa8, 0x64, 0x68, 0xdb, 0x08, 0x85, 0x2c, 0xb1, 0x65, 0xc8, 0x78, 0x08, - 0xa9, 0x7b, 0x26, 0xb6, 0x4f, 0xb1, 0xa2, 0x28, 0x63, 0x98, 0x87, 0xbf, 0xf5, 0xf5, 0xc9, 0x20, - 0xc6, 0x3b, 0x30, 0xad, 0xcf, 0x44, 0x8d, 0x06, 0xe4, 0x2a, 0x8c, 0xc8, 0xe9, 0xcb, 0xa4, 0x4f, - 0x9f, 0x2c, 0x37, 0xb6, 0x80, 0x24, 0xe8, 0x7d, 0x34, 0x17, 0xa2, 0x81, 0x34, 0x67, 0x93, 0x8f, - 0x75, 0x09, 0xc4, 0x30, 0x85, 0xf6, 0x98, 0x66, 0xbf, 0xca, 0x48, 0x8d, 0x3f, 0x99, 0x84, 0x99, - 0x94, 0x3d, 0xf7, 0x18, 0x99, 0x68, 0x5e, 0xdf, 0x20, 0x46, 0x43, 0x5f, 0x68, 0xb9, 0x2d, 0xbc, - 0x23, 0xb3, 0x1d, 0xf7, 0xd9, 0x0e, 0xfa, 0xa5, 0x40, 0xfe, 0x34, 0xe4, 0x22, 0x35, 0x5c, 0xc1, - 0xd0, 0x13, 0x0b, 0x57, 0xb0, 0x08, 0x13, 0xa2, 0x57, 0x62, 0xbb, 0x1a, 0x8e, 0xb4, 0xb9, 0x1e, - 0x2f, 0xb0, 0x12, 0xdb, 0x96, 0x4e, 0xc2, 0x79, 0xf8, 0x6e, 0xf3, 0x21, 0x15, 0x3c, 0x46, 0x54, - 0x1e, 0x58, 0x90, 0xca, 0x43, 0x21, 0x21, 0xff, 0x16, 0x26, 0xb9, 0x40, 0x88, 0xba, 0x67, 0x15, - 0xfa, 0xed, 0x59, 0x8d, 0x27, 0xb3, 0x67, 0x5d, 0x90, 0x6d, 0x4c, 0xdf, 0xbb, 0x52, 0x9a, 0x45, - 0x7e, 0x39, 0x03, 0xd3, 0xdc, 0x67, 0x5e, 0x6d, 0x6c, 0x5f, 0x3f, 0xe8, 0xfa, 0x93, 0x69, 0xec, - 0x79, 0x11, 0x9f, 0x3e, 0xbd, 0xad, 0xc9, 0x46, 0x91, 0x1f, 0x00, 0x08, 0xbf, 0x28, 0x7f, 0x0e, - 0xf0, 0x53, 0x3b, 0x9f, 0xb2, 0x0b, 0x84, 0x48, 0x51, 0x2c, 0xdd, 0x20, 0xa4, 0xd3, 0x52, 0x9b, - 0x84, 0x50, 0xf2, 0x43, 0x30, 0xcb, 0xbe, 0x97, 0x10, 0x22, 0x22, 0x7c, 0xcc, 0x8d, 0x61, 0x2d, - 0x9f, 0xef, 0x2d, 0x13, 0x5d, 0x4b, 0x23, 0xe3, 0x91, 0xff, 0xa2, 0x94, 0x6e, 0x81, 0xea, 0x0c, - 0x9c, 0x5a, 0x11, 0x86, 0xcc, 0xc1, 0xd6, 0xf3, 0x78, 0xb7, 0x3d, 0xf6, 0xb7, 0xb3, 0xf2, 0x5b, - 0xe0, 0xfb, 0x9b, 0xaf, 0x3b, 0xb3, 0x21, 0x88, 0x7c, 0x19, 0x48, 0xe8, 0x6c, 0xce, 0x61, 0x54, - 0xc6, 0xc2, 0xe5, 0xaa, 0xdd, 0xc8, 0x69, 0xdd, 0x93, 0xc5, 0xea, 0x22, 0x49, 0x12, 0x13, 0x0a, - 0xb3, 0xa2, 0xd3, 0x0c, 0x2a, 0x93, 0x68, 0xf8, 0x73, 0x93, 0x5a, 0xfc, 0x94, 0xa8, 0x24, 0xca, - 0xfd, 0xa6, 0x64, 0xe2, 0xd0, 0x54, 0x4e, 0x69, 0xec, 0xc8, 0x2d, 0x18, 0x45, 0x8f, 0xb2, 0x65, - 0x69, 0x04, 0x25, 0x0c, 0x32, 0xd0, 0xf7, 0xcc, 0xda, 0xd3, 0x4d, 0x99, 0x22, 0x54, 0x76, 0x1d, - 0xa8, 0x78, 0x87, 0x66, 0xb7, 0x8d, 0x0a, 0x58, 0xa1, 0xef, 0x68, 0x78, 0x87, 0x96, 0xd7, 0xd5, - 0x5d, 0x0e, 0x11, 0x89, 0x7c, 0x03, 0xc6, 0xee, 0xdb, 0x8f, 0xa4, 0xfe, 0x55, 0x28, 0x59, 0x07, - 0xca, 0x5a, 0xde, 0xb2, 0x1f, 0x59, 0x8d, 0x6e, 0x3c, 0xee, 0x20, 0xcf, 0x5a, 0xae, 0xb0, 0x24, - 0x5f, 0x03, 0x50, 0xb4, 0xc2, 0xe4, 0xd8, 0x0a, 0x9e, 0x97, 0x11, 0x81, 0x52, 0xb5, 0xc5, 0xc8, - 0x5f, 0x61, 0x18, 0x93, 0x1c, 0x66, 0x3f, 0x3d, 0xc9, 0xe1, 0xd4, 0xa7, 0x27, 0x39, 0x9c, 0xdb, - 0x86, 0xb3, 0x3d, 0x3f, 0x9d, 0x94, 0x30, 0x8d, 0xd7, 0xf5, 0x30, 0x8d, 0x67, 0x7b, 0x1d, 0xb1, - 0xbe, 0x1e, 0x3e, 0x79, 0xa6, 0x38, 0xdb, 0x5b, 0x3a, 0xf9, 0x7e, 0x36, 0x76, 0xe4, 0x8a, 0x8b, - 0x05, 0x0f, 0xb7, 0xdf, 0x4b, 0x26, 0xc9, 0x62, 0x5e, 0x31, 0x7e, 0x28, 0x67, 0xa3, 0x0b, 0x4d, - 0x2c, 0x7d, 0x2a, 0x3f, 0x9e, 0x3f, 0xe9, 0xe9, 0xfb, 0x16, 0x4c, 0xf2, 0x8c, 0x42, 0xf7, 0xe8, - 0xe1, 0x81, 0xeb, 0x35, 0x64, 0x8e, 0x4c, 0x94, 0xc1, 0x13, 0xb9, 0xf7, 0x62, 0xb8, 0xa4, 0x22, - 0x9d, 0x94, 0x86, 0xb0, 0xf6, 0xb3, 0xa9, 0xbb, 0x18, 0x43, 0xe8, 0xe7, 0xbf, 0x44, 0x5e, 0x0f, - 0x05, 0x35, 0xea, 0xa9, 0x41, 0x94, 0x3d, 0x09, 0x4c, 0x91, 0xd7, 0xa8, 0x67, 0xfc, 0x41, 0x0e, - 0x08, 0xaf, 0xa9, 0x6c, 0x77, 0x6c, 0x74, 0xe1, 0x73, 0x30, 0x14, 0x45, 0x51, 0xe0, 0xd8, 0xdb, - 0x4d, 0xaa, 0xc6, 0x71, 0x11, 0x46, 0xa7, 0x61, 0x99, 0x15, 0xbf, 0xe8, 0x24, 0x08, 0x7b, 0x6c, - 0x75, 0xd9, 0x4f, 0xb2, 0xd5, 0x7d, 0x03, 0x9e, 0x2d, 0x75, 0x30, 0x35, 0x99, 0xac, 0xe5, 0xb6, - 0xeb, 0xc9, 0x4d, 0x4a, 0x73, 0x0e, 0xb1, 0x43, 0xb4, 0x44, 0x4b, 0xfb, 0xb1, 0x50, 0xe4, 0x14, - 0xb6, 0x2e, 0x3b, 0x81, 0xea, 0x6c, 0x2c, 0xe5, 0x94, 0x0e, 0x96, 0xa4, 0xc8, 0x29, 0x9c, 0x44, - 0xf2, 0x70, 0x3c, 0x29, 0xa7, 0x60, 0xda, 0x80, 0x88, 0x87, 0xe3, 0xd1, 0x1e, 0xb2, 0x4e, 0x48, - 0x42, 0xde, 0x82, 0xb1, 0x52, 0x37, 0x70, 0x05, 0x63, 0x61, 0x2d, 0x1d, 0xd9, 0x35, 0x8b, 0xa6, - 0x68, 0x57, 0x9f, 0x08, 0xdd, 0xf8, 0xe3, 0x1c, 0x9c, 0x4d, 0x4e, 0xaf, 0x28, 0x0d, 0xbf, 0x8f, - 0xcc, 0x31, 0xdf, 0x47, 0xda, 0x6a, 0xe0, 0x8f, 0x05, 0x4f, 0x6c, 0x35, 0xf0, 0x0c, 0x67, 0x1f, - 0x73, 0x35, 0xd4, 0x60, 0x4c, 0x3d, 0xef, 0xf2, 0x1f, 0xf7, 0xbc, 0x53, 0xb9, 0xb0, 0x4b, 0x3d, - 0xf7, 0xb1, 0x1e, 0x8a, 0x9e, 0x8e, 0xe2, 0xee, 0xd5, 0x1c, 0x83, 0xfc, 0x0b, 0x70, 0x91, 0xef, - 0x49, 0xf1, 0xce, 0x2e, 0x1e, 0x4a, 0x8e, 0x62, 0xe2, 0x16, 0x1e, 0x1f, 0xcd, 0x5f, 0xe3, 0xaa, - 0x12, 0x2b, 0x31, 0x6c, 0xd6, 0xf6, 0xa1, 0x25, 0x5b, 0xa6, 0x54, 0x72, 0x2c, 0x6f, 0x4c, 0x6b, - 0xa6, 0x64, 0xcd, 0x7a, 0x2d, 0xcd, 0x8d, 0x84, 0x47, 0x22, 0xe5, 0x60, 0xdd, 0x83, 0x44, 0xaa, - 0xc3, 0xb2, 0xa9, 0xea, 0x30, 0xa9, 0x4f, 0xc9, 0xa5, 0xea, 0x53, 0x2a, 0x30, 0x55, 0xeb, 0x6e, - 0xcb, 0xba, 0x11, 0x31, 0xaf, 0x79, 0xc2, 0xa5, 0x75, 0x28, 0x4e, 0x62, 0xfc, 0x78, 0x16, 0xc6, - 0xd7, 0x9b, 0xdd, 0x5d, 0xa7, 0x5d, 0xb1, 0x03, 0xfb, 0xa9, 0xd5, 0xd0, 0xbd, 0xa1, 0x69, 0xe8, - 0x42, 0x6f, 0xa9, 0xb0, 0x63, 0x03, 0xa9, 0xe7, 0xbe, 0x9b, 0x81, 0xa9, 0x88, 0x84, 0x9f, 0xb3, - 0xcb, 0x90, 0x67, 0x3f, 0xc4, 0xbd, 0xf5, 0x62, 0x82, 0x31, 0x4f, 0xd5, 0x12, 0xfe, 0x25, 0x74, - 0x66, 0x7a, 0x1e, 0x04, 0xe4, 0x70, 0xee, 0x0b, 0x30, 0x1a, 0xb1, 0x3d, 0x49, 0x8a, 0x96, 0x5f, - 0xcb, 0x40, 0x31, 0xde, 0x13, 0x72, 0x0f, 0x46, 0x18, 0x27, 0x87, 0xca, 0x2b, 0xf5, 0x0b, 0x3d, - 0xfa, 0x7c, 0x4d, 0xa0, 0xf1, 0xe6, 0xe1, 0xe0, 0x53, 0x0e, 0x31, 0x25, 0x87, 0x73, 0x26, 0x8c, - 0xab, 0x58, 0x29, 0xad, 0x7b, 0x55, 0x17, 0x2e, 0x4e, 0xa7, 0x8f, 0x83, 0x96, 0x58, 0x46, 0x6b, - 0xb5, 0x90, 0x1b, 0x2e, 0x6b, 0x8b, 0x0b, 0xc7, 0x2a, 0xb6, 0x6e, 0xf8, 0x32, 0x5b, 0x88, 0x82, - 0x23, 0xab, 0xeb, 0x2c, 0x65, 0x41, 0x87, 0x78, 0xe4, 0x55, 0x18, 0xe6, 0xf5, 0xa9, 0x09, 0x16, - 0x3a, 0x08, 0x51, 0x45, 0x5c, 0x8e, 0x63, 0xfc, 0xad, 0x1c, 0x9c, 0x8e, 0x9a, 0xf7, 0xa0, 0xd3, - 0xb0, 0x03, 0xba, 0x6e, 0x7b, 0x76, 0xcb, 0x3f, 0xe6, 0x0b, 0xb8, 0x92, 0x68, 0x1a, 0x06, 0xdc, - 0x97, 0x4d, 0x53, 0x1a, 0x64, 0xc4, 0x1a, 0x84, 0xea, 0x4b, 0xde, 0x20, 0xd9, 0x0c, 0x72, 0x0f, - 0x72, 0x35, 0x1a, 0x88, 0x6d, 0xf3, 0x72, 0x62, 0x54, 0xd5, 0x76, 0x5d, 0xab, 0xd1, 0x80, 0x4f, - 0x22, 0x8f, 0xfd, 0x41, 0xb5, 0xd8, 0x8b, 0x35, 0x1a, 0x90, 0x2d, 0x18, 0x5e, 0x7a, 0xd4, 0xa1, - 0xf5, 0x40, 0x24, 0x18, 0xba, 0xda, 0x9f, 0x1f, 0xc7, 0x55, 0xf2, 0x0b, 0x51, 0x04, 0xa8, 0x83, - 0xc5, 0x51, 0xce, 0xdd, 0x82, 0x82, 0xac, 0xfc, 0x24, 0x2b, 0xf7, 0xdc, 0x1b, 0x30, 0xa6, 0x54, - 0x72, 0xa2, 0x45, 0xff, 0x0b, 0x6c, 0x5f, 0x75, 0x9b, 0x32, 0x27, 0xd1, 0x52, 0x42, 0xcc, 0xcb, - 0x44, 0x3e, 0xbb, 0x5c, 0xcc, 0xb3, 0xf6, 0x45, 0x51, 0x1f, 0x79, 0xaf, 0x0a, 0x53, 0xb5, 0x7d, - 0xa7, 0x13, 0x85, 0xc0, 0xd3, 0x0e, 0x53, 0x8c, 0x16, 0x2f, 0xee, 0xdc, 0xf1, 0xc3, 0x34, 0x4e, - 0x67, 0xfc, 0x59, 0x06, 0x86, 0xd9, 0x5f, 0x9b, 0xb7, 0x9e, 0xd2, 0x2d, 0xf3, 0xa6, 0xb6, 0x65, - 0x4e, 0x2b, 0xf1, 0x67, 0x71, 0xe3, 0xb8, 0x75, 0xcc, 0x66, 0x79, 0x24, 0x26, 0x88, 0x23, 0x93, - 0x3b, 0x30, 0x22, 0x2c, 0x6f, 0x84, 0x89, 0xb4, 0x1a, 0xd0, 0x56, 0xda, 0xe4, 0x84, 0x97, 0x73, - 0xb7, 0x13, 0xd7, 0x66, 0x48, 0x6a, 0x26, 0x92, 0xcb, 0x60, 0x84, 0x5a, 0x26, 0x3b, 0x17, 0xfd, - 0xcf, 0x78, 0x40, 0x56, 0x25, 0xf7, 0x64, 0x0f, 0xc7, 0xfe, 0x92, 0x78, 0xc8, 0xc8, 0xf5, 0x63, - 0x72, 0x5a, 0x26, 0xfa, 0x4a, 0x7d, 0xe3, 0xf8, 0xc3, 0x19, 0x1e, 0xca, 0x54, 0x36, 0xec, 0x6d, - 0x18, 0xbf, 0xed, 0x7a, 0x07, 0xb6, 0xc7, 0x03, 0xd4, 0x09, 0xcb, 0x01, 0x76, 0x75, 0x9c, 0xd8, - 0xe1, 0x70, 0x1e, 0xe2, 0xee, 0xa3, 0xa3, 0xf9, 0xfc, 0xa2, 0xeb, 0x36, 0x4d, 0x0d, 0x9d, 0xac, - 0xc1, 0xc4, 0x7d, 0xfb, 0x91, 0x72, 0xe9, 0xe5, 0x0e, 0x25, 0x57, 0xd9, 0x02, 0x66, 0xb7, 0xe6, - 0xe3, 0xcd, 0xa0, 0x74, 0x7a, 0xe2, 0xc0, 0xe4, 0xba, 0xeb, 0x05, 0xa2, 0x12, 0xa7, 0xbd, 0x2b, - 0x3a, 0x9b, 0x34, 0xe4, 0xba, 0x9e, 0x6a, 0xc8, 0x75, 0xb6, 0xe3, 0x7a, 0x81, 0xb5, 0x13, 0x92, - 0x6b, 0x41, 0x73, 0x34, 0xc6, 0xe4, 0x6d, 0x98, 0x56, 0x82, 0x82, 0xdd, 0x76, 0xbd, 0x96, 0x2d, - 0x85, 0x72, 0xd4, 0x03, 0xa3, 0xbd, 0xc9, 0x0e, 0x82, 0xcd, 0x24, 0x26, 0xf9, 0x20, 0xcd, 0x45, - 0x67, 0x28, 0xb2, 0x04, 0x4b, 0x71, 0xd1, 0xe9, 0x65, 0x09, 0x96, 0x74, 0xd6, 0xd9, 0xed, 0x67, - 0x29, 0x5a, 0x58, 0xbc, 0x21, 0xae, 0xdf, 0xc7, 0x5b, 0x82, 0x86, 0xf3, 0xd6, 0xc3, 0x22, 0x74, - 0x01, 0x72, 0x8b, 0xeb, 0xb7, 0xf1, 0xf5, 0x42, 0x1a, 0xda, 0xb4, 0xf7, 0xec, 0x76, 0x1d, 0x85, - 0x65, 0x61, 0x9d, 0xad, 0xee, 0xc8, 0x8b, 0xeb, 0xb7, 0x89, 0x0d, 0x33, 0xeb, 0xd4, 0x6b, 0x39, - 0xc1, 0x57, 0x6e, 0xdc, 0x50, 0x26, 0xaa, 0x80, 0x4d, 0xbb, 0x2e, 0x9a, 0x36, 0xdf, 0x41, 0x14, - 0xeb, 0xd1, 0x8d, 0x1b, 0xa9, 0xd3, 0x11, 0x36, 0x2c, 0x8d, 0x17, 0xdb, 0x19, 0xef, 0xdb, 0x8f, - 0x22, 0xa3, 0x7a, 0x5f, 0x38, 0x3b, 0x5e, 0x90, 0x0b, 0x2b, 0x32, 0xc8, 0xd7, 0x76, 0x46, 0x9d, - 0x88, 0xdd, 0x75, 0xa2, 0xe5, 0xe5, 0x0b, 0x37, 0x91, 0x73, 0x52, 0xa5, 0x23, 0x3d, 0x62, 0x55, - 0x81, 0x5d, 0x41, 0x27, 0x0f, 0xc2, 0x1b, 0x1b, 0xbf, 0xf1, 0x88, 0x34, 0x56, 0xd7, 0xd5, 0x1b, - 0x1b, 0x57, 0xa4, 0x68, 0xdd, 0x9a, 0x0a, 0xaf, 0xf9, 0xdc, 0xcb, 0xc0, 0xd4, 0xb9, 0x24, 0x2f, - 0x82, 0xe3, 0x27, 0xbf, 0x08, 0x52, 0xc8, 0xaf, 0xb8, 0xf5, 0x7d, 0x11, 0xe9, 0xe7, 0xcb, 0xec, - 0x73, 0x6f, 0xba, 0xf5, 0xfd, 0x27, 0x67, 0x01, 0x8b, 0xec, 0xc9, 0x2a, 0x6b, 0x2a, 0x5b, 0x05, - 0x62, 0x4c, 0x84, 0x55, 0xe5, 0x6c, 0x78, 0x13, 0x52, 0xca, 0xb8, 0xe0, 0xc3, 0x17, 0x8d, 0x1c, - 0x5a, 0x53, 0x27, 0x27, 0x14, 0x8a, 0x15, 0xea, 0xef, 0x07, 0x6e, 0xa7, 0xdc, 0x74, 0x3a, 0xdb, - 0xae, 0xed, 0x35, 0x50, 0x77, 0x97, 0xf6, 0x7d, 0xbf, 0x94, 0xfa, 0x7d, 0x4f, 0x37, 0x38, 0xbd, - 0x55, 0x97, 0x0c, 0xcc, 0x04, 0x4b, 0xf2, 0x01, 0x4c, 0xb2, 0xc5, 0xbd, 0xf4, 0x28, 0xa0, 0x6d, - 0x3e, 0xf3, 0xd3, 0x28, 0x3a, 0xcc, 0x2a, 0x81, 0xbf, 0xc3, 0x42, 0xbe, 0xa6, 0xf0, 0x63, 0xa7, - 0x21, 0x81, 0x16, 0x25, 0x49, 0x63, 0x45, 0x1a, 0x30, 0x77, 0xdf, 0x7e, 0xa4, 0x24, 0xdf, 0x52, - 0x16, 0x29, 0xc1, 0x05, 0x86, 0xc9, 0xc6, 0xd9, 0x02, 0x8b, 0x02, 0x74, 0xf6, 0x58, 0xaf, 0x3d, - 0x39, 0x91, 0x1f, 0x84, 0x33, 0xa2, 0x5b, 0x15, 0xcc, 0x86, 0xe1, 0x7a, 0x87, 0xb5, 0x3d, 0x1b, - 0xfd, 0x69, 0x66, 0x4e, 0xb6, 0x21, 0xca, 0x01, 0x6b, 0x48, 0x3e, 0x96, 0xcf, 0x19, 0x99, 0xbd, - 0x6a, 0x20, 0x1f, 0xc2, 0x24, 0x7f, 0xb2, 0x59, 0x76, 0xfd, 0x00, 0x2f, 0xf4, 0xb3, 0x27, 0x33, - 0x13, 0xe7, 0xef, 0x40, 0xdc, 0xb1, 0x22, 0xa6, 0x00, 0x88, 0x71, 0x26, 0x6f, 0xc2, 0xd8, 0xba, - 0xd3, 0xe6, 0x71, 0xcc, 0xaa, 0xeb, 0xa8, 0x7a, 0x14, 0xe7, 0x4f, 0xc7, 0x69, 0x5b, 0xf2, 0x56, - 0xdd, 0x09, 0xb7, 0x0b, 0x15, 0x9b, 0x6c, 0xc1, 0x58, 0xad, 0xb6, 0x7c, 0xdb, 0x61, 0x07, 0x60, - 0xe7, 0x70, 0xee, 0x74, 0x8f, 0x56, 0x5e, 0x4a, 0x6d, 0xe5, 0x84, 0xef, 0xef, 0x61, 0x42, 0x63, - 0xab, 0xee, 0x76, 0x0e, 0x4d, 0x95, 0x53, 0x8a, 0xe9, 0xf4, 0x99, 0x27, 0x6c, 0x3a, 0x5d, 0x85, - 0x29, 0xc5, 0xc0, 0x12, 0x8d, 0x2b, 0xe7, 0xa2, 0xb0, 0x5d, 0xaa, 0xa9, 0x74, 0xdc, 0xad, 0x2f, - 0x4e, 0x27, 0x6d, 0xa6, 0xcf, 0x9e, 0xd4, 0x66, 0xda, 0x81, 0x69, 0x3e, 0x19, 0x62, 0x1d, 0xe0, - 0x4c, 0x9f, 0xeb, 0x31, 0x86, 0x57, 0x53, 0xc7, 0x70, 0x46, 0xcc, 0xb4, 0x5c, 0x64, 0xf8, 0x44, - 0x99, 0xe4, 0x4a, 0x76, 0x80, 0x08, 0xa0, 0x48, 0xa7, 0x8c, 0x75, 0x3d, 0xdb, 0xa3, 0xae, 0x17, - 0x52, 0xeb, 0x9a, 0x94, 0x75, 0x6d, 0xf3, 0x6a, 0x52, 0x38, 0x92, 0xb6, 0xac, 0x47, 0xae, 0x2f, - 0x1c, 0xd8, 0xf3, 0x9a, 0x1e, 0x34, 0x89, 0xc0, 0x83, 0x88, 0xc6, 0x17, 0x6d, 0x7c, 0xdc, 0x53, - 0x38, 0x93, 0x47, 0x70, 0x3a, 0xd9, 0x0a, 0xac, 0xf3, 0x02, 0xd6, 0x79, 0x41, 0xab, 0x33, 0x8e, - 0xc4, 0xd7, 0x8d, 0xde, 0xad, 0x78, 0xad, 0x3d, 0xf8, 0xdf, 0xcd, 0x17, 0x26, 0x8a, 0x93, 0x69, - 0x96, 0xd6, 0xff, 0x30, 0x1b, 0xdb, 0xb4, 0x49, 0x15, 0x46, 0xc4, 0x5c, 0x08, 0x29, 0x36, 0x39, - 0xe2, 0x17, 0x52, 0x47, 0x7c, 0x44, 0x4c, 0xab, 0x29, 0xe9, 0xc9, 0x01, 0x63, 0x85, 0x66, 0xeb, - 0x42, 0xec, 0xff, 0x1a, 0xdf, 0x93, 0x11, 0xa4, 0x9d, 0x3e, 0x95, 0x93, 0x3b, 0xed, 0xe8, 0x3e, - 0x61, 0x78, 0x0c, 0xc9, 0xda, 0xc8, 0x3e, 0xcf, 0x14, 0x90, 0x0b, 0x3d, 0x3f, 0xf4, 0xb4, 0x00, - 0x4f, 0xac, 0x42, 0x56, 0x8b, 0xf1, 0x9b, 0x19, 0x98, 0xd0, 0x76, 0x7d, 0x72, 0x4b, 0x71, 0x6b, - 0x8a, 0xbc, 0x72, 0x35, 0x1c, 0xdc, 0x08, 0xe2, 0x0e, 0x4f, 0xb7, 0x84, 0xdd, 0x74, 0xb6, 0x37, - 0x5d, 0x6a, 0x56, 0xf1, 0xfe, 0x4a, 0xb2, 0x30, 0xf3, 0x50, 0xbe, 0x47, 0xe6, 0xa1, 0x5f, 0x7f, - 0x16, 0x26, 0xf5, 0x6b, 0x01, 0x79, 0x15, 0x86, 0x51, 0xb7, 0x28, 0xef, 0x98, 0x3c, 0xf7, 0x2e, - 0x42, 0xb4, 0xdc, 0xbb, 0x08, 0x21, 0x2f, 0x02, 0x84, 0x06, 0xac, 0x52, 0xb3, 0x3e, 0xf4, 0xf8, - 0x68, 0x3e, 0xf3, 0x9a, 0xa9, 0x14, 0x90, 0xaf, 0x03, 0xac, 0xba, 0x0d, 0x1a, 0x66, 0x47, 0xeb, - 0xf3, 0x7a, 0xfc, 0x52, 0x22, 0x8a, 0xf6, 0xa9, 0xb6, 0xdb, 0xa0, 0xc9, 0x90, 0xd9, 0x0a, 0x47, - 0xf2, 0x25, 0x18, 0x32, 0xbb, 0xec, 0x3e, 0xcb, 0x55, 0x09, 0x63, 0x72, 0xf7, 0xed, 0x36, 0xa9, - 0x92, 0xa8, 0xbf, 0x1b, 0x37, 0x8c, 0x62, 0x00, 0xf2, 0x2e, 0x8f, 0xae, 0x2d, 0x82, 0x61, 0x0d, - 0x45, 0x6f, 0x0d, 0xca, 0xa9, 0x9c, 0x08, 0x87, 0xa5, 0x90, 0x90, 0x35, 0x18, 0x51, 0x95, 0xe4, - 0x8a, 0x7f, 0xac, 0xfa, 0x90, 0xa2, 0xdc, 0xbc, 0x44, 0x5a, 0xb5, 0xb8, 0xfe, 0x5c, 0x72, 0x21, - 0x6f, 0xc1, 0x28, 0x63, 0xcf, 0x3e, 0x61, 0x5f, 0x48, 0xdc, 0xf8, 0xa2, 0xa0, 0x34, 0x88, 0xed, - 0x00, 0x5a, 0xc8, 0xaa, 0x90, 0x80, 0x7c, 0x80, 0x99, 0xc3, 0xc4, 0x50, 0xf7, 0xb5, 0x2a, 0xb8, - 0x9c, 0x18, 0x6a, 0x4c, 0x25, 0x96, 0x4c, 0x2a, 0x1b, 0xf2, 0x23, 0xbb, 0x61, 0x28, 0xa5, 0x41, - 0x22, 0xa2, 0xbf, 0x9c, 0xa8, 0x60, 0x4e, 0x46, 0x07, 0x4a, 0x66, 0xb9, 0xd3, 0xf8, 0x92, 0x0e, - 0x14, 0x23, 0x81, 0x47, 0xd4, 0x05, 0xfd, 0xea, 0x7a, 0x2d, 0x51, 0x97, 0x3a, 0x81, 0x89, 0xea, - 0x12, 0xdc, 0x49, 0x03, 0x26, 0xe5, 0xe6, 0x29, 0xea, 0x1b, 0xeb, 0x57, 0xdf, 0x8b, 0x89, 0xfa, - 0x66, 0x1a, 0xdb, 0xc9, 0x7a, 0x62, 0x3c, 0xc9, 0x5b, 0x30, 0x21, 0x21, 0xf8, 0x7d, 0x88, 0xec, - 0xb5, 0xa8, 0x15, 0x69, 0x6c, 0xa3, 0xc9, 0xbc, 0x9e, 0xfb, 0x4f, 0x45, 0x56, 0xa9, 0xf9, 0xea, - 0x98, 0xd0, 0xa8, 0xe3, 0xab, 0x42, 0x47, 0x26, 0xef, 0xc3, 0x58, 0xb5, 0xc5, 0x3a, 0xe2, 0xb6, - 0xed, 0x80, 0x0a, 0xdf, 0x29, 0x69, 0x21, 0xa1, 0x94, 0x28, 0x4b, 0x95, 0x67, 0xd3, 0x8b, 0x8a, - 0xb4, 0x6c, 0x7a, 0x11, 0x98, 0x0d, 0x1e, 0x7f, 0x15, 0x11, 0x6b, 0x58, 0xfa, 0x55, 0x5d, 0x48, - 0xb1, 0x52, 0x50, 0xd8, 0x8b, 0xa0, 0x73, 0x0c, 0x2a, 0x5f, 0x25, 0x62, 0x41, 0xe7, 0x54, 0x9e, - 0xe4, 0x6d, 0x18, 0x13, 0xc9, 0x22, 0x4a, 0xe6, 0xaa, 0x3f, 0x57, 0xc4, 0xce, 0xa3, 0x37, 0xb8, - 0xcc, 0x2b, 0x61, 0xd9, 0x5e, 0xcc, 0x1c, 0x2f, 0xc2, 0x27, 0x5f, 0x81, 0xd9, 0x2d, 0xa7, 0xdd, - 0x70, 0x0f, 0x7c, 0x71, 0x4c, 0x89, 0x8d, 0x6e, 0x3a, 0x72, 0x86, 0x39, 0xe0, 0xe5, 0xa1, 0x9c, - 0x92, 0xd8, 0xf8, 0x52, 0x39, 0x90, 0xbf, 0x9c, 0xe0, 0xcc, 0x57, 0x10, 0xe9, 0xb7, 0x82, 0x16, - 0x12, 0x2b, 0x28, 0x59, 0x7d, 0x7c, 0x39, 0xa5, 0x56, 0x43, 0x5c, 0x20, 0xfa, 0xf9, 0x7e, 0xd7, - 0x75, 0xda, 0x73, 0x33, 0xb8, 0x17, 0x3e, 0x1b, 0xf7, 0xbf, 0x46, 0xbc, 0x75, 0xb7, 0xe9, 0xd4, - 0x0f, 0x79, 0xe6, 0xfa, 0xb8, 0x3c, 0xfa, 0xa1, 0xab, 0xe9, 0x8c, 0x53, 0x58, 0x93, 0xf7, 0x61, - 0x9c, 0xfd, 0x1f, 0x5e, 0x98, 0x67, 0x35, 0xbb, 0x36, 0x05, 0x53, 0xd4, 0x83, 0x73, 0x84, 0xd9, - 0x2c, 0x52, 0xee, 0xd2, 0x1a, 0x2b, 0xf2, 0x06, 0x00, 0x93, 0x9c, 0xc4, 0x76, 0x7c, 0x2a, 0x8a, - 0xf1, 0x87, 0xf2, 0x56, 0x72, 0x23, 0x8e, 0x90, 0xd9, 0x2d, 0x9e, 0xfd, 0xaa, 0x75, 0x1b, 0x2e, - 0xfb, 0x36, 0x4e, 0x23, 0x2d, 0x77, 0x49, 0x63, 0xb4, 0x3e, 0x87, 0x6b, 0x2e, 0x69, 0x11, 0x3a, - 0x59, 0x86, 0x29, 0x8c, 0xc5, 0x58, 0x6d, 0xd0, 0x76, 0x80, 0xaf, 0x95, 0x73, 0x67, 0x94, 0xd7, - 0x5c, 0x56, 0x64, 0x39, 0x61, 0x99, 0x2a, 0x67, 0xc7, 0xc8, 0x88, 0x0f, 0x33, 0xd1, 0xee, 0x12, - 0xbd, 0x0d, 0xcf, 0xe1, 0x20, 0x49, 0xe9, 0x32, 0x89, 0xc1, 0xf7, 0x63, 0x36, 0x23, 0xca, 0xc6, - 0x25, 0x35, 0xeb, 0x6a, 0x85, 0x69, 0xdc, 0x89, 0x09, 0xe4, 0x4e, 0x79, 0x3d, 0x1e, 0xac, 0xf0, - 0x2c, 0xf6, 0x00, 0xa7, 0x79, 0xb7, 0x1e, 0xe5, 0x6d, 0x4c, 0x09, 0x58, 0x98, 0x42, 0x4d, 0xbe, - 0x05, 0xa7, 0xe4, 0x0e, 0x22, 0x8a, 0xc4, 0xba, 0x3e, 0x77, 0xc2, 0x9d, 0xb8, 0xb1, 0x1d, 0x56, - 0x9d, 0x58, 0xd2, 0xe9, 0x55, 0x10, 0x1b, 0xc6, 0x70, 0x5a, 0x45, 0x8d, 0xcf, 0xf6, 0xab, 0xf1, - 0x4a, 0xa2, 0xc6, 0xd3, 0xb8, 0x50, 0x92, 0x95, 0xa9, 0x3c, 0xc9, 0x22, 0x4c, 0x88, 0xef, 0x48, - 0xac, 0xb6, 0xf3, 0x38, 0x5a, 0xa8, 0x60, 0x91, 0x5f, 0x60, 0x62, 0xc1, 0xe9, 0x24, 0xea, 0x8e, - 0xcc, 0x35, 0xea, 0x17, 0xb4, 0x1d, 0x39, 0xae, 0x48, 0xd7, 0x91, 0xd9, 0x8e, 0x14, 0x49, 0x31, - 0x4b, 0x8f, 0x3a, 0x9e, 0x50, 0x9f, 0x3c, 0x17, 0xc5, 0xf0, 0x57, 0x84, 0x1f, 0x8b, 0x86, 0x18, - 0xea, 0x96, 0x90, 0xc6, 0x81, 0x3c, 0x80, 0x99, 0xf0, 0xd4, 0x56, 0x18, 0xcf, 0x47, 0xb9, 0x10, - 0xa2, 0xa3, 0x3e, 0x9d, 0x6f, 0x1a, 0x3d, 0xb1, 0xe1, 0x8c, 0x76, 0x4e, 0x2b, 0xac, 0x2f, 0x22, - 0x6b, 0xcc, 0x13, 0xaa, 0x1f, 0xf2, 0xe9, 0xec, 0x7b, 0xf1, 0x21, 0x1f, 0xc2, 0xb9, 0xf8, 0xd9, - 0xac, 0xd4, 0xf2, 0x3c, 0xd6, 0xf2, 0xf2, 0xe3, 0xa3, 0xf9, 0xcb, 0x89, 0xe3, 0x3d, 0xbd, 0xa2, - 0x3e, 0xdc, 0xc8, 0xd7, 0x61, 0x4e, 0x3f, 0x9f, 0x95, 0x9a, 0x0c, 0xac, 0x09, 0x3f, 0x9d, 0xf0, - 0x60, 0x4f, 0xaf, 0xa1, 0x27, 0x0f, 0x12, 0xc0, 0x7c, 0xea, 0xea, 0x56, 0xaa, 0xb9, 0x14, 0x75, - 0x28, 0xf1, 0x95, 0xa4, 0x57, 0x77, 0x1c, 0x4b, 0x72, 0x00, 0xcf, 0xa5, 0x1d, 0x13, 0x4a, 0xa5, - 0x2f, 0x84, 0x0a, 0xca, 0x57, 0xd2, 0x8f, 0x9c, 0xf4, 0x9a, 0x8f, 0x61, 0x4b, 0x3e, 0x80, 0x53, - 0xca, 0xf7, 0xa5, 0xd4, 0xf7, 0x22, 0xd6, 0x87, 0xae, 0xac, 0xea, 0x87, 0x99, 0x5e, 0x4b, 0x3a, - 0x0f, 0xd2, 0x82, 0x19, 0xd9, 0x71, 0xd4, 0x04, 0x8b, 0xa3, 0xe7, 0xb2, 0xb6, 0xab, 0x26, 0x31, - 0x94, 0x04, 0xcb, 0xdb, 0x56, 0x27, 0x22, 0x54, 0x57, 0x7a, 0x0a, 0x5f, 0xb2, 0x0c, 0xc3, 0xb5, - 0xf5, 0xea, 0xed, 0xdb, 0x4b, 0x73, 0x2f, 0x61, 0x0d, 0xd2, 0xef, 0x85, 0x03, 0xb5, 0x4b, 0x93, - 0x30, 0xb7, 0xea, 0x38, 0x3b, 0x3b, 0x9a, 0x7b, 0x11, 0x47, 0xbd, 0x9b, 0x2f, 0x5c, 0x29, 0x5e, - 0xbd, 0x9b, 0x2f, 0x5c, 0x2d, 0xbe, 0x6c, 0x9e, 0x4f, 0xcf, 0x8d, 0xcb, 0x3b, 0x6b, 0x5e, 0xee, - 0x57, 0x1a, 0x0d, 0x85, 0xf1, 0x0b, 0x19, 0x98, 0x49, 0x69, 0x07, 0xb9, 0x0c, 0x79, 0x4c, 0x2e, - 0xa0, 0x3c, 0x30, 0xc7, 0x92, 0x0a, 0x60, 0x39, 0xf9, 0x1c, 0x8c, 0x54, 0x56, 0x6b, 0xb5, 0xd2, - 0xaa, 0xbc, 0xb2, 0xf1, 0xed, 0xaa, 0xed, 0x5b, 0xbe, 0xad, 0xbf, 0x4b, 0x09, 0x34, 0xf2, 0x1a, - 0x0c, 0x57, 0xd7, 0x91, 0x80, 0x5b, 0x38, 0xe1, 0x15, 0xc6, 0xe9, 0xc4, 0xf1, 0x05, 0x92, 0xf1, - 0x13, 0x19, 0x20, 0xc9, 0x41, 0x25, 0x37, 0x60, 0x4c, 0x9d, 0x3a, 0x7e, 0xc1, 0xc4, 0x37, 0x14, - 0x65, 0x62, 0x4c, 0x15, 0x87, 0x54, 0x60, 0x08, 0x93, 0x21, 0x85, 0x0f, 0x62, 0xa9, 0x07, 0xc0, - 0x99, 0xc4, 0x01, 0x30, 0x84, 0xa9, 0x96, 0x4c, 0x4e, 0x6c, 0xfc, 0x4e, 0x06, 0x48, 0xf2, 0xd0, - 0x1c, 0xf8, 0x41, 0xfe, 0x75, 0xc5, 0x43, 0x55, 0x0d, 0x1f, 0x1e, 0xe6, 0x7e, 0x50, 0x2f, 0x4b, - 0x91, 0x2f, 0xeb, 0x65, 0xed, 0x72, 0xde, 0xdb, 0xad, 0xe9, 0x2a, 0x0c, 0x6d, 0x52, 0x6f, 0x5b, - 0x1a, 0xef, 0xa1, 0xc1, 0xcf, 0x43, 0x06, 0x50, 0x2f, 0xab, 0x88, 0x61, 0xfc, 0x71, 0x06, 0x66, - 0xd3, 0x24, 0xb9, 0x63, 0xbc, 0x8f, 0x8c, 0x98, 0xe3, 0x14, 0x3e, 0xc6, 0x73, 0x6b, 0xa0, 0xd0, - 0x5d, 0x6a, 0x1e, 0x86, 0x58, 0x67, 0xe5, 0x0c, 0xa3, 0xb2, 0x80, 0x8d, 0x86, 0x6f, 0x72, 0x38, - 0x43, 0xe0, 0x51, 0x8f, 0xf2, 0x18, 0xdc, 0x0a, 0x11, 0x50, 0x50, 0x30, 0x39, 0x9c, 0x21, 0xdc, - 0x77, 0x1b, 0x61, 0x06, 0x50, 0x44, 0x68, 0x31, 0x80, 0xc9, 0xe1, 0xe4, 0x32, 0x8c, 0xac, 0xb5, - 0x57, 0xa8, 0xfd, 0x50, 0xa6, 0xaf, 0x40, 0xe3, 0x01, 0xb7, 0x6d, 0x35, 0x19, 0xcc, 0x94, 0x85, - 0xc6, 0x77, 0x33, 0x30, 0x9d, 0x10, 0x22, 0x8f, 0x77, 0xb0, 0xea, 0xef, 0xe9, 0x30, 0x48, 0xff, - 0x78, 0xf3, 0xf3, 0xe9, 0xcd, 0x37, 0xfe, 0x8f, 0x3c, 0x9c, 0xe9, 0x71, 0xa7, 0x8f, 0x3c, 0xb1, - 0x32, 0xc7, 0x7a, 0x62, 0x7d, 0x95, 0xdd, 0xa1, 0x6d, 0xa7, 0xe5, 0x6f, 0xb8, 0x51, 0x8b, 0x23, - 0x83, 0x6e, 0x2c, 0x93, 0x49, 0x50, 0xa5, 0xe5, 0xef, 0x59, 0x9e, 0x88, 0xda, 0x0a, 0xdc, 0xa4, - 0x48, 0xa1, 0x31, 0x4b, 0xf8, 0x42, 0xe5, 0xfe, 0x82, 0xf8, 0x42, 0xe9, 0xd6, 0xf9, 0xf9, 0x27, - 0x6a, 0x9d, 0x9f, 0x6e, 0xd9, 0x37, 0xf4, 0x49, 0xec, 0x3c, 0xcb, 0x30, 0xc1, 0xad, 0x27, 0x4a, - 0x3e, 0x9f, 0xa4, 0xe1, 0x84, 0xc5, 0x85, 0xed, 0x27, 0xe7, 0x42, 0xa3, 0x21, 0xcb, 0xba, 0x25, - 0xf9, 0x08, 0xbe, 0xfa, 0x5c, 0xee, 0x6d, 0x29, 0xae, 0xbd, 0xf6, 0xaa, 0xa4, 0xc6, 0x77, 0xb3, - 0xba, 0xa3, 0xd4, 0x5f, 0xc4, 0x95, 0x77, 0x15, 0x86, 0xb6, 0xf6, 0xa8, 0x27, 0xf7, 0x3b, 0x6c, - 0xc8, 0x01, 0x03, 0xa8, 0x0d, 0x41, 0x0c, 0x72, 0x1b, 0x26, 0xd7, 0xf9, 0x4c, 0xc8, 0xe1, 0xcd, - 0x47, 0x57, 0xad, 0x8e, 0x50, 0x08, 0xa4, 0x8c, 0x6f, 0x8c, 0xca, 0xb8, 0x03, 0x17, 0xb4, 0x0f, - 0x52, 0x04, 0x76, 0xe0, 0x06, 0xdd, 0xfc, 0x44, 0x9c, 0x8c, 0x4c, 0xd8, 0xa3, 0xdd, 0xc3, 0x8c, - 0x41, 0x8d, 0x1d, 0x78, 0xae, 0x2f, 0x23, 0x76, 0x10, 0x41, 0x27, 0xfc, 0x15, 0xb3, 0x3a, 0xeb, - 0x4b, 0x6a, 0x2a, 0x74, 0xc6, 0x0f, 0xc2, 0xb8, 0x3a, 0xca, 0xb8, 0xa7, 0xb2, 0xdf, 0x62, 0x53, - 0xe3, 0x7b, 0x2a, 0x03, 0x98, 0x1c, 0x7e, 0x6c, 0xf2, 0xf8, 0x68, 0xfa, 0x73, 0xc7, 0x4d, 0x3f, - 0xab, 0x1c, 0x3f, 0x59, 0xa5, 0x72, 0xfc, 0xad, 0x56, 0x8e, 0x91, 0x1b, 0x4c, 0x0e, 0x7f, 0xa2, - 0x95, 0xff, 0xb6, 0x0c, 0xe2, 0x8f, 0xf6, 0xe2, 0xf2, 0x4e, 0x1c, 0xa5, 0xe8, 0x9c, 0x49, 0xbb, - 0xe9, 0x46, 0x98, 0xd1, 0x21, 0x99, 0x3d, 0xee, 0x90, 0x3c, 0xc9, 0x42, 0xbc, 0x0e, 0x23, 0x25, - 0xf1, 0x26, 0x9b, 0x8f, 0x04, 0x1b, 0x3b, 0xf1, 0x00, 0x2b, 0xb1, 0x8c, 0xef, 0x65, 0xe0, 0x54, - 0xaa, 0xaa, 0x8c, 0xd5, 0xca, 0x75, 0x72, 0xca, 0x77, 0x18, 0x57, 0xc8, 0x71, 0x8c, 0x93, 0xb8, - 0xed, 0x0e, 0xde, 0x17, 0xe3, 0x79, 0x18, 0x0d, 0x1f, 0x6a, 0xc8, 0xac, 0x9c, 0x3a, 0x34, 0xd4, - 0x91, 0xfa, 0xfe, 0x1a, 0x00, 0x6b, 0xc1, 0x13, 0x35, 0x2b, 0x33, 0x7e, 0x3b, 0xcb, 0x13, 0x3c, - 0x3d, 0xb5, 0xd1, 0xee, 0xd2, 0x6d, 0xc1, 0x58, 0x97, 0x7a, 0xc7, 0xb8, 0x23, 0x4b, 0x30, 0x5c, - 0x0b, 0xec, 0xa0, 0x2b, 0xbd, 0x8d, 0x67, 0x54, 0x32, 0x2c, 0xd8, 0x5c, 0x88, 0xfc, 0x4d, 0x7d, - 0x84, 0x68, 0x97, 0x03, 0x84, 0x28, 0x26, 0x65, 0x0e, 0x8c, 0xab, 0xb4, 0xe4, 0x7d, 0x98, 0x94, - 0x21, 0xbc, 0xb8, 0x0b, 0xb6, 0x78, 0x54, 0x92, 0xc6, 0x09, 0x32, 0x84, 0x97, 0xea, 0xb2, 0xad, - 0xe1, 0xab, 0x3b, 0x75, 0x47, 0x45, 0x36, 0xfe, 0x64, 0x98, 0xaf, 0x03, 0x11, 0x8b, 0x6f, 0x1b, - 0x26, 0xd7, 0xaa, 0x95, 0xb2, 0xa2, 0xf8, 0xd2, 0xd3, 0x2e, 0x2c, 0x3d, 0x0a, 0xa8, 0xd7, 0xb6, - 0x9b, 0x02, 0xe1, 0x30, 0x3a, 0x1b, 0x5c, 0xa7, 0x51, 0x4f, 0x57, 0x8a, 0xc5, 0x38, 0xb2, 0x3a, - 0xf8, 0xe5, 0x26, 0xac, 0x23, 0x3b, 0x60, 0x1d, 0xbe, 0xdd, 0x6a, 0xf6, 0xa8, 0x43, 0xe7, 0x48, - 0xf6, 0xa0, 0x78, 0x07, 0xe5, 0x18, 0xa5, 0x96, 0x5c, 0xff, 0x5a, 0x2e, 0x89, 0x5a, 0x9e, 0xe5, - 0x02, 0x50, 0x7a, 0x3d, 0x09, 0xae, 0xd1, 0x07, 0x9c, 0x3f, 0xf6, 0x03, 0xfe, 0xab, 0x19, 0x18, - 0xe6, 0x82, 0x92, 0x58, 0x5f, 0x3d, 0x44, 0xb1, 0xad, 0x27, 0x23, 0x8a, 0x15, 0x71, 0x03, 0xd7, - 0x56, 0x1a, 0x2f, 0x23, 0x95, 0xd8, 0x82, 0x95, 0x26, 0x8a, 0xa8, 0xc2, 0xe6, 0x25, 0xc7, 0xaf, - 0x57, 0x52, 0x8d, 0x5c, 0x73, 0x47, 0x8e, 0xf5, 0xfe, 0x92, 0xee, 0xcc, 0x23, 0xc2, 0x35, 0x57, - 0x77, 0xc8, 0x5d, 0x81, 0x51, 0xe1, 0xf0, 0xbb, 0x78, 0x28, 0x1e, 0xaa, 0x8a, 0xda, 0x33, 0x78, - 0x63, 0xf1, 0x30, 0x12, 0x02, 0x85, 0xcb, 0xb0, 0xb5, 0x7d, 0xa8, 0x25, 0xb2, 0x92, 0x88, 0x64, - 0x8d, 0x27, 0x78, 0xe1, 0xd1, 0x0a, 0xf5, 0x50, 0xc2, 0x21, 0x5c, 0x84, 0x12, 0x91, 0x5e, 0x83, - 0x29, 0xc1, 0x09, 0x23, 0x1e, 0x64, 0x05, 0x8a, 0x22, 0xf1, 0x3d, 0xb7, 0xa3, 0xa8, 0x56, 0xb8, - 0x53, 0xa9, 0x30, 0x7f, 0x93, 0x69, 0xf3, 0x85, 0x05, 0x86, 0xee, 0xcf, 0x91, 0xa0, 0x64, 0x17, - 0xb7, 0x62, 0x7c, 0xf5, 0x91, 0xb7, 0x60, 0x2c, 0x8c, 0x16, 0x19, 0x7a, 0x94, 0xa1, 0xc2, 0x3a, - 0x0a, 0x2f, 0xa9, 0xf9, 0x96, 0xa9, 0xe8, 0x64, 0x01, 0x0a, 0xec, 0x23, 0x8e, 0xa7, 0xd0, 0xea, - 0x0a, 0x98, 0x6a, 0x26, 0x2e, 0xf1, 0x48, 0x0d, 0x66, 0xd8, 0x47, 0x53, 0x73, 0xda, 0xbb, 0x4d, - 0xba, 0xe2, 0xee, 0xba, 0xdd, 0xe0, 0x81, 0xb9, 0x22, 0x36, 0x57, 0x2e, 0x2a, 0xdb, 0xad, 0xa6, - 0x56, 0xec, 0x69, 0x09, 0x52, 0x53, 0xa8, 0x95, 0x3d, 0xec, 0x0f, 0xb3, 0x30, 0xa6, 0xac, 0x27, - 0x72, 0x15, 0x0a, 0x55, 0x7f, 0xc5, 0xad, 0xef, 0x87, 0xb1, 0xa6, 0x26, 0x1e, 0x1f, 0xcd, 0x8f, - 0x3a, 0xbe, 0xd5, 0x44, 0xa0, 0x19, 0x16, 0x93, 0x45, 0x98, 0xe0, 0x7f, 0xc9, 0x88, 0xdb, 0xd9, - 0xc8, 0xda, 0x8d, 0x23, 0xcb, 0x58, 0xdb, 0xea, 0xbe, 0xa6, 0x91, 0x90, 0xaf, 0x01, 0x70, 0x00, - 0x7a, 0x27, 0xe6, 0x06, 0xf7, 0xab, 0x14, 0x15, 0xa4, 0xf8, 0x25, 0x2a, 0x0c, 0xc9, 0x37, 0x78, - 0x74, 0x49, 0xb9, 0xfe, 0xf3, 0x83, 0x3b, 0x86, 0x32, 0xfe, 0x56, 0xba, 0x7f, 0xba, 0xca, 0x52, - 0x84, 0xc5, 0x3b, 0x67, 0xd2, 0xba, 0xfb, 0x90, 0x7a, 0x87, 0xa5, 0x00, 0x11, 0x15, 0x0c, 0xe3, - 0xbf, 0xcb, 0x28, 0x5f, 0x0d, 0x59, 0xc5, 0xac, 0x6f, 0x7c, 0x45, 0x08, 0x9b, 0x8d, 0x50, 0x98, - 0x97, 0x70, 0x93, 0xee, 0x2c, 0x3e, 0x2b, 0x8c, 0x2d, 0x67, 0xc2, 0x75, 0x15, 0xcb, 0x06, 0xc7, - 0x81, 0xe4, 0x3d, 0xc8, 0xe3, 0xd0, 0x65, 0x8f, 0xed, 0x9a, 0x3c, 0x4f, 0xf3, 0x6c, 0xcc, 0xb0, - 0x23, 0x48, 0x49, 0x3e, 0x27, 0x3c, 0xbb, 0xf8, 0xe0, 0x4f, 0x2a, 0x87, 0x22, 0x6b, 0x47, 0x78, - 0x90, 0x46, 0x21, 0x0a, 0x94, 0xd5, 0xf3, 0xaf, 0x64, 0xa1, 0x18, 0xff, 0x56, 0xc9, 0xbb, 0x30, - 0x2e, 0x4f, 0x3a, 0x4c, 0x0b, 0xcc, 0x7a, 0x39, 0x2e, 0x42, 0x40, 0xcb, 0xe3, 0x2e, 0x9e, 0x15, - 0x58, 0x25, 0x60, 0x52, 0xc7, 0x86, 0x08, 0x19, 0xa4, 0x7c, 0x25, 0x81, 0x1b, 0x74, 0x62, 0x01, - 0x0a, 0x25, 0x1a, 0x79, 0x1d, 0x72, 0xf7, 0x6f, 0x97, 0x84, 0x1b, 0x81, 0xdc, 0x92, 0xee, 0xdf, - 0x2e, 0xf1, 0xaf, 0x99, 0x9b, 0x49, 0xe9, 0x46, 0x5b, 0x0c, 0x9f, 0xac, 0x28, 0xf1, 0x3f, 0x87, - 0xb5, 0x1c, 0x3d, 0x12, 0x1c, 0x76, 0xee, 0xf8, 0x40, 0xa0, 0x3c, 0xdf, 0xb0, 0x88, 0xb2, 0xf7, - 0x6f, 0xe4, 0x60, 0x34, 0xac, 0x9f, 0x10, 0x40, 0xa1, 0x4a, 0xdc, 0x64, 0xf0, 0x6f, 0x72, 0x16, - 0x0a, 0x52, 0x8e, 0x12, 0xde, 0x04, 0x23, 0xbe, 0x90, 0xa1, 0xe6, 0x40, 0x0a, 0x4c, 0xfc, 0x33, - 0x37, 0xe5, 0x4f, 0x72, 0x03, 0x42, 0x69, 0xa8, 0x97, 0xd8, 0x94, 0x67, 0x13, 0x66, 0x86, 0x68, - 0x64, 0x12, 0xb2, 0x0e, 0x8f, 0xdc, 0x32, 0x6a, 0x66, 0x9d, 0x06, 0x79, 0x17, 0x0a, 0x76, 0xa3, - 0x41, 0x1b, 0x96, 0x2d, 0x8d, 0x1f, 0xfa, 0x2d, 0x9a, 0x02, 0xe3, 0xc6, 0x0f, 0x01, 0xa4, 0x2a, - 0x05, 0xa4, 0x04, 0xa3, 0x4d, 0x9b, 0x1b, 0x52, 0x35, 0x06, 0x38, 0x51, 0x22, 0x0e, 0x05, 0x46, - 0xf6, 0xc0, 0xa7, 0x0d, 0xf2, 0x12, 0xe4, 0xd9, 0x6c, 0x8a, 0x23, 0x44, 0x8a, 0x6f, 0x6c, 0x32, - 0xf9, 0x80, 0x2d, 0x3f, 0x63, 0x22, 0x02, 0x79, 0x01, 0x72, 0xdd, 0x85, 0x1d, 0x71, 0x38, 0x14, - 0xa3, 0x58, 0xbc, 0x21, 0x1a, 0x2b, 0x26, 0x37, 0xa1, 0x70, 0xa0, 0x87, 0x71, 0x3d, 0x15, 0x9b, - 0xc6, 0x10, 0x3f, 0x44, 0x5c, 0x2c, 0xc0, 0x30, 0x3f, 0x08, 0x8c, 0xe7, 0x00, 0xa2, 0xaa, 0x93, - 0x4e, 0x1f, 0xc6, 0xd7, 0x60, 0x34, 0xac, 0x92, 0x5c, 0x00, 0xd8, 0xa7, 0x87, 0xd6, 0x9e, 0xdd, - 0x6e, 0x34, 0xb9, 0x7c, 0x37, 0x6e, 0x8e, 0xee, 0xd3, 0xc3, 0x65, 0x04, 0x90, 0x33, 0x30, 0xd2, - 0x61, 0xb3, 0x2a, 0x96, 0xee, 0xb8, 0x39, 0xdc, 0xe9, 0x6e, 0xb3, 0x15, 0x3a, 0x07, 0x23, 0xa8, - 0x79, 0x13, 0x1f, 0xda, 0x84, 0x29, 0x7f, 0x1a, 0xff, 0x71, 0x16, 0xd3, 0x0d, 0x28, 0xed, 0x24, - 0x97, 0x60, 0xa2, 0xee, 0x51, 0x3c, 0x73, 0x6c, 0x26, 0x49, 0x89, 0x7a, 0xc6, 0x23, 0x60, 0xb5, - 0x41, 0x2e, 0xc3, 0x94, 0x48, 0xb1, 0xcd, 0x1a, 0x54, 0xdf, 0x16, 0x31, 0x97, 0xc7, 0xcd, 0x09, - 0x0e, 0xbe, 0x47, 0x0f, 0xcb, 0xdb, 0x18, 0x71, 0xa8, 0xa8, 0x06, 0x8c, 0x0c, 0xc2, 0xcc, 0x88, - 0xe6, 0x94, 0x02, 0x47, 0x9b, 0xa6, 0xd3, 0x30, 0x6c, 0xdb, 0xbb, 0x5d, 0x87, 0x47, 0x06, 0x19, - 0x37, 0xc5, 0x2f, 0xf2, 0x0a, 0x4c, 0xfb, 0xce, 0x6e, 0xdb, 0x0e, 0xba, 0x9e, 0xc8, 0xf7, 0x40, - 0x3d, 0x5c, 0x52, 0x13, 0x66, 0x31, 0x2c, 0x28, 0x73, 0x38, 0x79, 0x0d, 0x88, 0x5a, 0x9f, 0xbb, - 0xfd, 0x21, 0xad, 0xf3, 0xa5, 0x36, 0x6e, 0x4e, 0x2b, 0x25, 0x6b, 0x58, 0x40, 0x9e, 0x87, 0x71, - 0x8f, 0xfa, 0x28, 0xc5, 0xe1, 0xb0, 0x61, 0x36, 0x1e, 0x73, 0x4c, 0xc2, 0xd8, 0xd8, 0x5d, 0x81, - 0xa2, 0x32, 0x1c, 0x18, 0x93, 0x93, 0x07, 0x1c, 0x36, 0x27, 0x23, 0xb8, 0xd9, 0xa9, 0x36, 0x8c, - 0x45, 0x98, 0x4e, 0x7c, 0xb9, 0x4a, 0x36, 0x5b, 0xbe, 0x13, 0xf5, 0xcf, 0x66, 0x6b, 0xb4, 0x61, - 0x5c, 0xdd, 0x89, 0x8f, 0x89, 0x7b, 0x7d, 0x1a, 0x3d, 0xcb, 0xf9, 0x36, 0x35, 0xfc, 0xf8, 0x68, - 0x3e, 0xeb, 0x34, 0xd0, 0x9f, 0xfc, 0x0a, 0x14, 0xa4, 0xd0, 0x20, 0xce, 0x6a, 0xd4, 0x9c, 0x0a, - 0x69, 0xf5, 0xd0, 0x0c, 0x4b, 0x8d, 0x97, 0x60, 0x44, 0x6c, 0xb6, 0xfd, 0xf5, 0xa5, 0xc6, 0x8f, - 0x65, 0x61, 0xca, 0xa4, 0x6c, 0x2b, 0xa0, 0x3c, 0xd8, 0xfd, 0x53, 0x7b, 0x7d, 0x4b, 0x8f, 0x4f, - 0xa6, 0xf5, 0xad, 0x4f, 0x98, 0xf9, 0xbf, 0x97, 0x81, 0x99, 0x14, 0xdc, 0x8f, 0x95, 0x12, 0xed, - 0x16, 0x8c, 0x56, 0x1c, 0xbb, 0x59, 0x6a, 0x34, 0x42, 0x37, 0x73, 0x14, 0x35, 0x1b, 0x6c, 0xa5, - 0xd9, 0x0c, 0xaa, 0x1e, 0xbb, 0x21, 0x2a, 0x79, 0x59, 0x2c, 0x8a, 0x28, 0x1d, 0x35, 0x2e, 0x8a, - 0x8f, 0x8e, 0xe6, 0x81, 0xb7, 0x29, 0x4a, 0xbb, 0x89, 0x31, 0x03, 0x39, 0x30, 0x32, 0x03, 0x7f, - 0x6a, 0xa7, 0x2e, 0x3d, 0x66, 0x60, 0xbc, 0x7b, 0x03, 0x45, 0x9a, 0xff, 0xc9, 0x2c, 0x9c, 0x4e, - 0x27, 0xfc, 0xb8, 0xd9, 0xed, 0x30, 0xc6, 0xbf, 0x12, 0xe7, 0x14, 0xb3, 0xdb, 0xf1, 0x84, 0x00, - 0x88, 0x1f, 0x21, 0x90, 0x1d, 0x98, 0x58, 0xb1, 0xfd, 0x60, 0x99, 0xda, 0x5e, 0xb0, 0x4d, 0xed, - 0x60, 0x00, 0xd9, 0xf3, 0x05, 0xf9, 0x2c, 0x89, 0xc7, 0xdf, 0x9e, 0xa4, 0x8c, 0x49, 0x87, 0x3a, - 0xdb, 0x70, 0xa1, 0xe4, 0x07, 0x58, 0x28, 0xdf, 0x84, 0xa9, 0x1a, 0x6d, 0xd9, 0x9d, 0x3d, 0xd7, - 0x93, 0x7e, 0x84, 0xd7, 0x60, 0x22, 0x04, 0xa5, 0xae, 0x16, 0xbd, 0x58, 0xc3, 0x57, 0x06, 0x22, - 0xda, 0x4a, 0xf4, 0x62, 0xe3, 0x6f, 0x66, 0xe1, 0x4c, 0xa9, 0x2e, 0xac, 0x85, 0x44, 0x81, 0x34, - 0x6a, 0xfc, 0x94, 0xeb, 0x26, 0xd7, 0x61, 0xf4, 0xbe, 0xfd, 0x68, 0x85, 0xda, 0x3e, 0xf5, 0x45, - 0x6e, 0x21, 0x2e, 0xa8, 0xd9, 0x8f, 0x22, 0x23, 0x1a, 0x33, 0xc2, 0x51, 0x6f, 0xb2, 0xf9, 0x4f, - 0x78, 0x93, 0x35, 0x60, 0x78, 0xd9, 0x6d, 0x36, 0xc4, 0x31, 0x26, 0x9e, 0xd7, 0xf6, 0x10, 0x62, - 0x8a, 0x12, 0x76, 0x01, 0x9c, 0x0c, 0x5b, 0x8c, 0x4d, 0xf8, 0xd4, 0x87, 0xe4, 0x32, 0x8c, 0x60, - 0x45, 0xd5, 0x8a, 0x7a, 0x68, 0x34, 0x29, 0x66, 0x88, 0x69, 0x98, 0xb2, 0x50, 0x1d, 0x89, 0xa1, - 0x4f, 0x36, 0x12, 0xc6, 0xbf, 0x89, 0x2f, 0x77, 0x6a, 0x2f, 0xd9, 0x49, 0xa4, 0x34, 0x24, 0x33, - 0x60, 0x43, 0xb2, 0x4f, 0x6c, 0x4a, 0x72, 0x3d, 0xa7, 0xe4, 0x3b, 0x59, 0x18, 0x0b, 0x1b, 0xfb, - 0x19, 0x0b, 0xb6, 0x1b, 0xf6, 0x6b, 0x20, 0xdf, 0xff, 0x9a, 0xb2, 0x57, 0x08, 0x17, 0xfb, 0xf7, - 0x60, 0x58, 0x7c, 0x4c, 0x99, 0x98, 0x71, 0x5f, 0x6c, 0x76, 0x17, 0x27, 0x05, 0xeb, 0x61, 0x9c, - 0x50, 0xdf, 0x14, 0x74, 0x18, 0x5c, 0x61, 0x8b, 0x6e, 0x8b, 0x87, 0xdc, 0xa7, 0xf6, 0x8c, 0x4a, - 0x0f, 0xae, 0x10, 0x75, 0x6c, 0xa0, 0xd3, 0xe9, 0xe7, 0x0b, 0x50, 0x8c, 0x93, 0x1c, 0x1f, 0xce, - 0x78, 0xbd, 0xbb, 0xcd, 0xa5, 0x70, 0x1e, 0xce, 0xb8, 0xd3, 0xdd, 0x36, 0x19, 0x0c, 0xed, 0x3c, - 0x3c, 0xe7, 0x21, 0xf6, 0x7a, 0x5c, 0xd8, 0x79, 0x78, 0xce, 0x43, 0xcd, 0xce, 0xc3, 0x73, 0x1e, - 0xe2, 0xd5, 0x77, 0xa5, 0x86, 0xfe, 0xa0, 0x28, 0x82, 0x8b, 0xab, 0x6f, 0xd3, 0x8f, 0xa7, 0x01, - 0x91, 0x68, 0xec, 0xa8, 0x5c, 0xa4, 0xb6, 0x27, 0x42, 0xef, 0x8a, 0xed, 0x0c, 0x8f, 0xca, 0x6d, - 0x04, 0xf3, 0x0c, 0xbb, 0xa6, 0x8a, 0x44, 0x9a, 0x40, 0x94, 0x9f, 0xf2, 0x03, 0x3e, 0xfe, 0x36, - 0x28, 0x0d, 0x73, 0x66, 0x55, 0xd6, 0x96, 0xfa, 0x35, 0xa7, 0xf0, 0x7d, 0x92, 0x0a, 0xc8, 0x75, - 0x11, 0x4f, 0x0c, 0x55, 0x1e, 0x85, 0x63, 0x99, 0x49, 0x87, 0x69, 0xe0, 0xf1, 0xc6, 0x42, 0xc5, - 0x47, 0xc4, 0x84, 0xbc, 0x03, 0x63, 0xaa, 0x97, 0x2f, 0xf7, 0x45, 0x3d, 0xcf, 0x43, 0x44, 0xf5, - 0x48, 0xf2, 0xa6, 0x12, 0x90, 0x6d, 0x38, 0x53, 0x76, 0xdb, 0x7e, 0xb7, 0x25, 0x83, 0x51, 0x45, - 0x21, 0x30, 0x21, 0x4c, 0xd2, 0xfe, 0x42, 0x5d, 0xa0, 0x08, 0xa7, 0x52, 0x69, 0x39, 0xad, 0x5f, - 0x40, 0x7a, 0x31, 0x22, 0x1b, 0x30, 0x86, 0x4a, 0x3c, 0x61, 0x9a, 0x35, 0xa6, 0x6f, 0x1b, 0x51, - 0x49, 0x85, 0x7d, 0x18, 0x3c, 0x9a, 0x8a, 0xdd, 0x6a, 0x4a, 0xc3, 0x5d, 0x55, 0x19, 0xa9, 0x20, - 0x93, 0xaf, 0xc1, 0x24, 0xbf, 0x6e, 0x6e, 0xd1, 0x6d, 0xbe, 0x76, 0xc6, 0xb5, 0xbb, 0xb3, 0x5e, - 0xc8, 0x1f, 0x7a, 0x85, 0xea, 0xf4, 0x80, 0x6e, 0xf3, 0xb9, 0xd7, 0xcc, 0xe6, 0x35, 0x7c, 0xf2, - 0x00, 0x66, 0x96, 0x6d, 0x9f, 0x03, 0x15, 0x77, 0xcd, 0x09, 0xd4, 0x29, 0xa2, 0x39, 0xe3, 0x9e, - 0xed, 0x4b, 0x5d, 0x6c, 0xaa, 0x7b, 0x66, 0x1a, 0x3d, 0xf9, 0xb1, 0x0c, 0xcc, 0x69, 0xaa, 0x5a, - 0x61, 0x54, 0xd3, 0xa2, 0xed, 0x00, 0xed, 0xe3, 0x27, 0xc3, 0xdc, 0xbe, 0xbd, 0xd0, 0xf8, 0x94, - 0xc4, 0xb4, 0xc1, 0x5e, 0x54, 0xae, 0xda, 0x09, 0xf6, 0xe2, 0x61, 0xdc, 0x8a, 0x8f, 0x9e, 0x50, - 0xb4, 0x64, 0x42, 0x45, 0xcb, 0x2c, 0x0c, 0xe1, 0x18, 0xc9, 0x58, 0x11, 0xf8, 0xc3, 0xf8, 0x9c, - 0xba, 0xab, 0x08, 0x21, 0xaf, 0xef, 0xae, 0x62, 0xfc, 0x57, 0xc3, 0x30, 0x15, 0x9b, 0x64, 0x71, - 0xeb, 0xcc, 0x24, 0x6e, 0x9d, 0x35, 0x00, 0xae, 0x6a, 0x1c, 0x50, 0x27, 0x28, 0x3d, 0x6d, 0xc6, - 0x84, 0xa7, 0x5a, 0xf8, 0x85, 0x28, 0x6c, 0x18, 0x53, 0xfe, 0xfd, 0x0d, 0xa8, 0xa3, 0x0d, 0x99, - 0xf2, 0x4f, 0x58, 0x61, 0x1a, 0xb1, 0x21, 0xf3, 0x30, 0x84, 0x01, 0xde, 0x54, 0x47, 0x27, 0x87, - 0x01, 0x4c, 0x0e, 0x27, 0x97, 0x60, 0x98, 0x89, 0x44, 0xd5, 0x8a, 0xd8, 0xd2, 0xf0, 0xa4, 0x60, - 0x32, 0x13, 0x93, 0x3f, 0x44, 0x11, 0xb9, 0x05, 0xe3, 0xfc, 0x2f, 0xe1, 0xe3, 0x3f, 0xac, 0xdb, - 0x6d, 0x59, 0x4e, 0x43, 0xba, 0xf9, 0x6b, 0x78, 0xec, 0xae, 0x50, 0xeb, 0x6e, 0xf3, 0x4c, 0xf3, - 0x22, 0x22, 0x28, 0xde, 0x15, 0x7c, 0x0e, 0xc4, 0x4c, 0xd8, 0x21, 0x02, 0x93, 0x4c, 0x84, 0xb9, - 0x71, 0x01, 0x6f, 0x88, 0x28, 0x99, 0x70, 0x33, 0x63, 0x53, 0x94, 0x90, 0xab, 0x5c, 0xb5, 0x8f, - 0x42, 0x1e, 0x4f, 0x62, 0x84, 0x7a, 0x73, 0x54, 0x33, 0xa0, 0xa4, 0x17, 0x16, 0xb3, 0xca, 0xd9, - 0xdf, 0x4b, 0x2d, 0xdb, 0x69, 0x8a, 0x4d, 0x02, 0x2b, 0x47, 0x5c, 0xca, 0xa0, 0x66, 0x84, 0x40, - 0xde, 0x82, 0x49, 0xf6, 0xa3, 0xec, 0xb6, 0x5a, 0x6e, 0x1b, 0xd9, 0x8f, 0x45, 0xe1, 0x62, 0x90, - 0xa4, 0x8e, 0x45, 0xbc, 0x96, 0x18, 0x2e, 0x3b, 0x1d, 0xf0, 0xd9, 0xb0, 0xcb, 0x1f, 0x1d, 0xc6, - 0xa3, 0xd3, 0x01, 0x49, 0x7d, 0x0e, 0x37, 0x55, 0x24, 0xf2, 0x06, 0x4c, 0xb0, 0x9f, 0x77, 0x9c, - 0x87, 0x94, 0x57, 0x38, 0x11, 0x3d, 0x64, 0x23, 0xd5, 0x2e, 0x2b, 0xe1, 0xf5, 0xe9, 0x98, 0xe4, - 0xcb, 0x70, 0x0a, 0x39, 0xd5, 0xdd, 0x0e, 0x6d, 0x94, 0x76, 0x76, 0x9c, 0xa6, 0xc3, 0x0d, 0x69, - 0xb8, 0x37, 0x3b, 0xea, 0x80, 0x79, 0xc5, 0x88, 0x61, 0xd9, 0x11, 0x8a, 0x99, 0x4e, 0x49, 0xb6, - 0xa0, 0x58, 0xee, 0xfa, 0x81, 0xdb, 0x2a, 0x05, 0x81, 0xe7, 0x6c, 0x77, 0x03, 0xea, 0xcf, 0x4d, - 0x69, 0x3e, 0xdf, 0xec, 0xe3, 0x08, 0x0b, 0xb9, 0x76, 0xa7, 0x8e, 0x14, 0x96, 0x1d, 0x92, 0x98, - 0x09, 0x26, 0xc6, 0x7f, 0x99, 0x81, 0x09, 0x8d, 0x94, 0xbc, 0x0e, 0xe3, 0xb7, 0x3d, 0x87, 0xb6, - 0x1b, 0xcd, 0x43, 0xe5, 0xda, 0x89, 0x77, 0x92, 0x1d, 0x01, 0xe7, 0xbd, 0xd6, 0xd0, 0x42, 0xad, - 0x4d, 0x36, 0xd5, 0xca, 0xed, 0x3a, 0xf7, 0xb7, 0x13, 0x0b, 0x34, 0x17, 0x05, 0xa1, 0xc0, 0x05, - 0x2a, 0x56, 0xa7, 0x82, 0x42, 0xde, 0x86, 0x61, 0xfe, 0xc0, 0x28, 0x4c, 0xae, 0xce, 0xa6, 0x75, - 0x93, 0xfb, 0x76, 0xe2, 0x42, 0x44, 0xf3, 0x0e, 0xdf, 0x14, 0x44, 0xc6, 0xcf, 0x66, 0x80, 0x24, - 0x51, 0x8f, 0xd1, 0x62, 0x1d, 0x6b, 0x36, 0xf2, 0x5e, 0xf8, 0x35, 0xe6, 0x34, 0x9d, 0x2d, 0xab, - 0x89, 0x17, 0xf0, 0x81, 0x17, 0x5f, 0x9d, 0xaa, 0x56, 0xe3, 0xc5, 0xc6, 0x5f, 0xc9, 0x02, 0x44, - 0xd8, 0xe4, 0x8b, 0x3c, 0x8f, 0xc6, 0x97, 0xbb, 0x76, 0xd3, 0xd9, 0x71, 0xf4, 0xc0, 0x72, 0xc8, - 0xe4, 0x9b, 0xb2, 0xc4, 0xd4, 0x11, 0xc9, 0xbb, 0x30, 0x55, 0x5b, 0xd7, 0x69, 0x95, 0x9c, 0x01, - 0x7e, 0xc7, 0x8a, 0x91, 0xc7, 0xb1, 0xd1, 0xb4, 0x52, 0x9d, 0x0d, 0x6e, 0x5a, 0xc9, 0x27, 0x42, - 0x94, 0xb0, 0x8d, 0xa5, 0xb6, 0x2e, 0xac, 0x79, 0x1b, 0xd5, 0x8a, 0xd8, 0xa5, 0xb0, 0x75, 0x7e, - 0xc7, 0xea, 0x08, 0x33, 0x5f, 0xb6, 0x4f, 0x68, 0x78, 0xd1, 0x40, 0x0e, 0xf5, 0xf0, 0xdf, 0xfc, - 0x39, 0x54, 0xe2, 0xb5, 0xdc, 0x80, 0x0a, 0xdd, 0xc5, 0x53, 0x7b, 0x8b, 0x89, 0x5e, 0xa7, 0x87, - 0x34, 0xb7, 0x34, 0xad, 0x77, 0xc2, 0x36, 0xe2, 0x66, 0x74, 0xe5, 0xe0, 0xef, 0xd4, 0x29, 0xd6, - 0x14, 0x7f, 0x27, 0x03, 0xa7, 0x52, 0x69, 0xc9, 0x35, 0x80, 0x48, 0x43, 0x24, 0x46, 0x09, 0x77, - 0xcc, 0x28, 0xf4, 0x82, 0xa9, 0x60, 0x90, 0xaf, 0xc6, 0x75, 0x3b, 0xc7, 0x1f, 0x84, 0xe7, 0x64, - 0x68, 0x1d, 0x5d, 0xb7, 0x93, 0xa2, 0xd1, 0x31, 0xfe, 0x5e, 0x0e, 0xa6, 0x95, 0xc8, 0x0e, 0xbc, - 0xad, 0xc7, 0x98, 0xba, 0xee, 0xc3, 0x38, 0xeb, 0x8d, 0x53, 0x17, 0xbe, 0x31, 0xdc, 0x92, 0xe2, - 0xe5, 0x84, 0x63, 0x91, 0xe0, 0x76, 0x4d, 0x45, 0xe6, 0x01, 0xaf, 0x70, 0xeb, 0x44, 0xcd, 0x79, - 0x3d, 0xe9, 0x23, 0xa3, 0x31, 0x27, 0x3e, 0x4c, 0x54, 0x0e, 0xdb, 0x76, 0x2b, 0xac, 0x8d, 0x5b, - 0x54, 0xbc, 0xd2, 0xb3, 0x36, 0x0d, 0x9b, 0x57, 0x17, 0x99, 0xe0, 0xf3, 0xb2, 0x14, 0xef, 0x4f, - 0x8d, 0xea, 0xdc, 0xbb, 0x30, 0x9d, 0x68, 0xf4, 0x89, 0x62, 0x6f, 0x6d, 0x01, 0x49, 0xb6, 0x23, - 0x85, 0xc3, 0x2b, 0x7a, 0x64, 0xb7, 0x53, 0xe1, 0xe3, 0x29, 0x66, 0xe0, 0xe5, 0xf6, 0x19, 0x0b, - 0x6a, 0x64, 0xae, 0x9f, 0xcb, 0xaa, 0xce, 0x5d, 0x4f, 0xfb, 0x57, 0xf7, 0x9e, 0x76, 0xb7, 0x7d, - 0xae, 0xd7, 0x9c, 0x0e, 0xa4, 0x43, 0xf8, 0x7e, 0x0e, 0xce, 0xf4, 0xa0, 0x24, 0x87, 0xf1, 0x45, - 0xc4, 0x75, 0x0a, 0x37, 0xfa, 0x57, 0xf8, 0x24, 0x96, 0x12, 0xf9, 0x22, 0x77, 0xef, 0xae, 0x63, - 0xe6, 0x58, 0x71, 0x9b, 0xe6, 0x49, 0xc7, 0x43, 0x68, 0xdc, 0xaf, 0x9b, 0x43, 0xc9, 0xbb, 0x30, - 0x84, 0x9e, 0x7d, 0xb1, 0xc8, 0x52, 0x0c, 0x03, 0xe1, 0x4a, 0x18, 0x2e, 0xf6, 0x53, 0x0b, 0xc3, - 0xc5, 0x00, 0xe4, 0x0b, 0x90, 0x2b, 0x6d, 0xd5, 0xc4, 0xbc, 0x4c, 0xaa, 0xe4, 0x5b, 0xb5, 0x28, - 0xfa, 0xb7, 0xad, 0x85, 0xe9, 0x66, 0x14, 0x8c, 0xf0, 0x4e, 0x79, 0x5d, 0xcc, 0x8a, 0x4a, 0x78, - 0xa7, 0xbc, 0x1e, 0x11, 0xee, 0xd6, 0xb5, 0x48, 0x1d, 0x77, 0xca, 0xeb, 0x9f, 0xde, 0xb2, 0xff, - 0xeb, 0x59, 0xee, 0x93, 0xce, 0x3b, 0xf6, 0x2e, 0x8c, 0x6b, 0x91, 0x37, 0x33, 0x91, 0x3c, 0x16, - 0x06, 0x38, 0x8d, 0x99, 0xa0, 0x68, 0x04, 0x32, 0x8e, 0x3e, 0xfb, 0x8d, 0x12, 0xaf, 0x6a, 0xec, - 0x11, 0x72, 0x40, 0x99, 0x38, 0x1e, 0x47, 0x3f, 0x24, 0x21, 0x37, 0xa1, 0xb0, 0x41, 0xdb, 0x76, - 0x3b, 0x08, 0xd5, 0x9b, 0x68, 0x46, 0x1a, 0x20, 0x4c, 0x97, 0x1a, 0x42, 0x44, 0x34, 0x79, 0xec, - 0x6e, 0xfb, 0x75, 0xcf, 0xc1, 0xd8, 0x15, 0xe1, 0x59, 0xcc, 0x4d, 0x1e, 0x95, 0x12, 0x9d, 0x41, - 0x8c, 0xc8, 0xf8, 0xb9, 0x0c, 0x8c, 0x88, 0x89, 0xe4, 0xf9, 0x4f, 0x76, 0xa3, 0xb3, 0x44, 0xe4, - 0x3f, 0xd9, 0x75, 0xe2, 0xf9, 0x4f, 0x76, 0x79, 0x80, 0x88, 0x51, 0xe1, 0x5e, 0x19, 0x3e, 0xf4, - 0xf1, 0x74, 0xd9, 0x1c, 0xa8, 0x57, 0x1b, 0xa1, 0x0e, 0xea, 0x4b, 0x62, 0xfc, 0x2d, 0xd1, 0xb2, - 0x3b, 0xe5, 0x75, 0xb2, 0x00, 0x85, 0x15, 0xb7, 0x6e, 0x2b, 0xe7, 0x1c, 0x6e, 0x3b, 0x4d, 0x01, - 0x53, 0x07, 0x48, 0xe2, 0xb1, 0xf6, 0xad, 0x7b, 0xae, 0xb8, 0xcb, 0x28, 0xed, 0xeb, 0x70, 0x60, - 0xac, 0x7d, 0x21, 0xea, 0xc0, 0xed, 0xa3, 0x29, 0x9b, 0xc4, 0xe6, 0x4d, 0x0c, 0x30, 0x7e, 0x57, - 0xf5, 0xd1, 0x11, 0x45, 0x72, 0xa7, 0x38, 0xd7, 0x6b, 0xa7, 0xd8, 0xbc, 0x69, 0xa6, 0x50, 0xe1, - 0x2b, 0x59, 0x04, 0xae, 0x51, 0xef, 0xe1, 0x53, 0xbc, 0x4b, 0xa7, 0xbf, 0x92, 0xc5, 0xbb, 0x37, - 0xd0, 0x26, 0xfd, 0x9f, 0x65, 0xe1, 0x74, 0x3a, 0xa1, 0xda, 0x97, 0x4c, 0x9f, 0xbe, 0x5c, 0x81, - 0xc2, 0xb2, 0xeb, 0x07, 0x8a, 0xd5, 0x19, 0x2a, 0xf3, 0xf7, 0x04, 0xcc, 0x0c, 0x4b, 0xd9, 0x9d, - 0x9b, 0xfd, 0x1d, 0x7e, 0x9e, 0xc8, 0x0f, 0x3d, 0xb1, 0xd9, 0x9d, 0x9b, 0x17, 0x91, 0x3b, 0x50, - 0x30, 0x85, 0x8f, 0x48, 0x6c, 0x68, 0x24, 0x38, 0x94, 0xa6, 0x88, 0x27, 0x20, 0x5a, 0x00, 0x54, - 0x01, 0x23, 0x25, 0x18, 0x11, 0xb3, 0x1f, 0x7b, 0x08, 0x4e, 0x59, 0x32, 0x7a, 0x4c, 0x62, 0x49, - 0xc7, 0x76, 0x14, 0x7c, 0xd2, 0xab, 0x56, 0xa4, 0xbb, 0x07, 0xee, 0x28, 0xfc, 0xc9, 0x4f, 0x37, - 0xf0, 0x0b, 0x11, 0x8d, 0x1f, 0xcb, 0x02, 0x48, 0xad, 0xcd, 0x53, 0xbb, 0xc2, 0xbe, 0xa0, 0xad, - 0x30, 0xc5, 0xde, 0x65, 0xf0, 0x7c, 0x7d, 0x6b, 0x68, 0x77, 0x32, 0x78, 0xb6, 0xbe, 0x79, 0x18, - 0xda, 0x88, 0x14, 0x5a, 0xc2, 0xf9, 0x00, 0x95, 0xcb, 0x1c, 0x6e, 0x6c, 0xc3, 0xec, 0x1d, 0x1a, - 0x44, 0xea, 0x2d, 0xf9, 0x90, 0xd8, 0x9f, 0xed, 0xab, 0x30, 0x2a, 0xf0, 0xc3, 0xfd, 0x8b, 0xeb, - 0x62, 0x44, 0x70, 0x03, 0xd4, 0xc5, 0x48, 0x04, 0xb6, 0x1b, 0x55, 0x68, 0x93, 0x06, 0xf4, 0xd3, - 0xad, 0xa6, 0x06, 0x84, 0x77, 0x05, 0x7b, 0x36, 0x58, 0x0d, 0xc7, 0x8e, 0xcf, 0x26, 0x9c, 0x0a, - 0xdb, 0xfe, 0x24, 0xf9, 0x5e, 0x67, 0x57, 0x4a, 0x11, 0xce, 0x37, 0xe2, 0xd8, 0xc7, 0x92, 0xe4, - 0x11, 0x9c, 0x93, 0x04, 0x5b, 0x4e, 0x68, 0xb8, 0x37, 0x10, 0x2d, 0x79, 0x0b, 0xc6, 0x14, 0x1a, - 0x11, 0x8e, 0x16, 0x95, 0xce, 0x07, 0x4e, 0xb0, 0x67, 0xf9, 0x1c, 0xae, 0x2a, 0x9d, 0x15, 0x74, - 0xe3, 0x03, 0x78, 0x36, 0x74, 0x10, 0x49, 0xa9, 0x3a, 0xc6, 0x3c, 0x73, 0x32, 0xe6, 0xab, 0x51, - 0xb7, 0xaa, 0xed, 0xd0, 0xa9, 0x53, 0xf2, 0x26, 0x6a, 0xb7, 0x44, 0x67, 0xce, 0x27, 0xdc, 0x44, - 0x15, 0x6f, 0x50, 0xe3, 0x4d, 0xa5, 0xb1, 0x29, 0x0c, 0x35, 0xe2, 0x4c, 0x9c, 0xf8, 0xc7, 0xb2, - 0x30, 0xb5, 0x56, 0xad, 0x94, 0x43, 0x5b, 0xa2, 0xcf, 0x58, 0x36, 0x41, 0xad, 0x6f, 0xbd, 0xf7, - 0x1b, 0xe3, 0x01, 0xcc, 0xc4, 0x86, 0x01, 0x45, 0x87, 0x77, 0xb8, 0x07, 0x43, 0x08, 0x96, 0x62, - 0xc3, 0xe9, 0x34, 0xf6, 0x9b, 0x37, 0xcd, 0x18, 0xb6, 0xf1, 0x8f, 0x47, 0x63, 0x7c, 0xc5, 0x16, - 0xf6, 0x2a, 0x8c, 0x56, 0x7d, 0xbf, 0x4b, 0xbd, 0x07, 0xe6, 0x8a, 0xaa, 0x2a, 0x70, 0x10, 0x68, - 0x75, 0xbd, 0xa6, 0x19, 0x21, 0x90, 0xab, 0x50, 0x10, 0x11, 0x5a, 0xe5, 0x9e, 0x80, 0x5a, 0xdb, - 0x30, 0xc0, 0xab, 0x19, 0x16, 0x93, 0xd7, 0x61, 0x9c, 0xff, 0xcd, 0x57, 0x9b, 0x18, 0x70, 0x54, - 0x0e, 0x0a, 0x74, 0xbe, 0x3a, 0x4d, 0x0d, 0x8d, 0xbc, 0x0c, 0xb9, 0x52, 0xd9, 0x14, 0xea, 0x20, - 0x21, 0x37, 0x62, 0x8e, 0xe0, 0x2e, 0xd5, 0x2f, 0x11, 0x65, 0x93, 0x49, 0x7f, 0xd2, 0x81, 0x5c, - 0x68, 0xb2, 0x79, 0x2a, 0x63, 0x01, 0x8b, 0x1d, 0x66, 0x08, 0x23, 0xd7, 0x61, 0xa4, 0xe2, 0xf8, - 0x9d, 0xa6, 0x7d, 0x28, 0xf4, 0xd8, 0x3c, 0x55, 0x0e, 0x07, 0x69, 0x7e, 0xe1, 0x1c, 0x44, 0xae, - 0xca, 0x14, 0x22, 0x85, 0xc8, 0x11, 0xa2, 0x47, 0x9e, 0x90, 0x57, 0x61, 0x58, 0xc4, 0x31, 0x1d, - 0x55, 0x22, 0x94, 0xc7, 0xe3, 0x97, 0x0a, 0x9c, 0xa4, 0xab, 0x22, 0x3c, 0x49, 0x57, 0xc5, 0x6d, - 0x38, 0x73, 0x07, 0xb5, 0x37, 0x7a, 0xc4, 0x93, 0x07, 0x66, 0x55, 0xe8, 0xc3, 0xf1, 0x51, 0x87, - 0x2b, 0x78, 0xe2, 0x41, 0x53, 0xac, 0xae, 0xa7, 0x66, 0x7e, 0xeb, 0xc5, 0x88, 0x7c, 0x05, 0x66, - 0xd3, 0x8a, 0x84, 0xd6, 0x1c, 0x63, 0x7b, 0xa4, 0x57, 0xa0, 0xc6, 0xf6, 0x48, 0xe3, 0x40, 0x56, - 0xa0, 0xc8, 0xe1, 0xa5, 0x46, 0xcb, 0x69, 0x73, 0xcd, 0x3f, 0xd7, 0xaa, 0xa3, 0x67, 0x82, 0xe0, - 0x6a, 0xb3, 0x42, 0xfe, 0x02, 0xa0, 0xf9, 0xb2, 0xc4, 0x28, 0xc9, 0x4f, 0x67, 0xd8, 0x6d, 0x8e, - 0x47, 0xfd, 0x7c, 0x60, 0xae, 0xf8, 0x22, 0x2e, 0xd4, 0xe9, 0xc8, 0x4d, 0xa5, 0x16, 0x78, 0x4e, - 0x7b, 0x57, 0xf8, 0xa9, 0x6c, 0x08, 0x3f, 0x95, 0xb7, 0x3e, 0x96, 0x9f, 0x0a, 0x67, 0xe5, 0x3f, - 0x3e, 0x9a, 0x1f, 0xf7, 0x44, 0x9d, 0xf8, 0x15, 0x69, 0x2d, 0xc0, 0xac, 0xe5, 0xcd, 0xa6, 0x7b, - 0xf0, 0xa0, 0xfd, 0x90, 0x7a, 0xce, 0x8e, 0x43, 0x1b, 0xbc, 0x93, 0x53, 0xb8, 0x83, 0xf3, 0xac, - 0xe5, 0x98, 0x87, 0xbf, 0x1b, 0x22, 0x24, 0x3a, 0x9a, 0xca, 0x81, 0x5d, 0x3c, 0xa5, 0x2f, 0x04, - 0xf7, 0xbb, 0x2c, 0x46, 0x17, 0x4f, 0xe9, 0x38, 0x61, 0xe1, 0x32, 0x52, 0x17, 0x8f, 0x46, 0x42, - 0xae, 0xc3, 0xf0, 0x7d, 0xfb, 0x51, 0x69, 0x97, 0x8a, 0xd4, 0x50, 0x13, 0x72, 0xfb, 0x43, 0xe0, - 0x62, 0xe1, 0xf7, 0xb9, 0xad, 0xfd, 0x33, 0xa6, 0x40, 0x23, 0xdf, 0xce, 0xc0, 0x69, 0xfe, 0x19, - 0xcb, 0x5e, 0xd6, 0x68, 0x10, 0xb0, 0x71, 0x10, 0x01, 0xa2, 0x64, 0x62, 0x85, 0x5a, 0x6d, 0x2d, - 0x1d, 0x8f, 0xe7, 0xd8, 0x16, 0x3b, 0x43, 0x38, 0x70, 0xbe, 0x28, 0xd5, 0xa2, 0x40, 0xa6, 0xd2, - 0x0b, 0x3b, 0xf2, 0x2f, 0xc8, 0x96, 0x93, 0xd7, 0x54, 0xf7, 0xc0, 0x1c, 0xca, 0xb9, 0x23, 0x2d, - 0xfb, 0x91, 0x65, 0xef, 0x52, 0xed, 0x75, 0x3a, 0xf4, 0x1b, 0x3c, 0xdb, 0xb3, 0x6d, 0xe4, 0x16, - 0x9c, 0x91, 0xd9, 0xd6, 0xf7, 0x82, 0xa0, 0xe3, 0x5b, 0xf2, 0x2e, 0x20, 0xfc, 0x09, 0xcd, 0x53, - 0xa2, 0x78, 0x99, 0x95, 0xca, 0xeb, 0x81, 0x6f, 0xfc, 0xd1, 0x28, 0x3f, 0xd3, 0x4a, 0xdd, 0x60, - 0x4f, 0x9e, 0x82, 0x0b, 0x69, 0x1e, 0x31, 0xdc, 0x54, 0x4f, 0xf1, 0x88, 0xd1, 0xfd, 0x60, 0xe4, - 0x63, 0x44, 0x36, 0xf5, 0x31, 0xe2, 0x55, 0x18, 0x2d, 0xef, 0xd1, 0xfa, 0x7e, 0xe8, 0x95, 0x50, - 0x10, 0xda, 0x5e, 0x06, 0xe4, 0x01, 0x42, 0x23, 0x04, 0x72, 0x1d, 0x00, 0x5d, 0xe4, 0xb8, 0x88, - 0xa4, 0x04, 0xf9, 0x46, 0x8f, 0x3a, 0x61, 0xfd, 0xa0, 0xa0, 0x20, 0xfb, 0x9a, 0x79, 0x5b, 0x35, - 0x97, 0xe0, 0xec, 0x7d, 0x6f, 0x47, 0xa0, 0x47, 0x08, 0xac, 0x7b, 0xca, 0x42, 0x17, 0xdb, 0x72, - 0x31, 0xf1, 0x35, 0xa8, 0x48, 0x68, 0x89, 0x28, 0x4d, 0xb0, 0x71, 0x57, 0x1e, 0x17, 0x96, 0x88, - 0xa1, 0xb9, 0xb6, 0x19, 0x21, 0x90, 0x2f, 0xc0, 0x48, 0x99, 0x7a, 0xc1, 0xc6, 0xc6, 0x0a, 0x5a, - 0x34, 0xf0, 0x48, 0xd8, 0x05, 0x8c, 0x5a, 0x1c, 0x04, 0xcd, 0x8f, 0x8e, 0xe6, 0x27, 0x02, 0xa7, - 0x45, 0xaf, 0x85, 0x13, 0x2c, 0xb1, 0xc9, 0x22, 0x14, 0xf9, 0x2b, 0x6d, 0x24, 0x0a, 0xe3, 0x46, - 0x5d, 0xe0, 0xc7, 0x86, 0x78, 0xd2, 0x3d, 0xa0, 0xdb, 0x61, 0xcc, 0xe6, 0x04, 0x3e, 0x59, 0x92, - 0xa1, 0xce, 0xd5, 0x4e, 0x42, 0xa4, 0x9b, 0x89, 0x2f, 0x60, 0xd6, 0xd7, 0x24, 0x05, 0x29, 0xc1, - 0x44, 0xd9, 0x6d, 0x75, 0xec, 0xc0, 0xc1, 0xbc, 0x41, 0x87, 0x62, 0x4f, 0x46, 0xfd, 0x52, 0x5d, - 0x2d, 0xd0, 0x36, 0x78, 0xb5, 0x80, 0xdc, 0x86, 0x49, 0xd3, 0xed, 0xb2, 0x49, 0x92, 0x97, 0x42, - 0xbe, 0xed, 0xa2, 0xdd, 0x81, 0xc7, 0x4a, 0xd8, 0x29, 0x21, 0x6e, 0x80, 0x5a, 0xc4, 0x39, 0x8d, - 0x8a, 0xac, 0xa6, 0x68, 0xe7, 0xd5, 0xbd, 0x56, 0x8d, 0xdc, 0x9c, 0x60, 0x96, 0xa2, 0xd8, 0xbf, - 0x09, 0x63, 0xb5, 0xda, 0xda, 0x06, 0xf5, 0x83, 0xdb, 0x4d, 0xf7, 0x00, 0xb7, 0xda, 0x82, 0xc8, - 0x68, 0xe1, 0xbb, 0x56, 0x40, 0xfd, 0xc0, 0xda, 0x69, 0xba, 0x07, 0xa6, 0x8a, 0x45, 0xbe, 0xce, - 0xc6, 0x43, 0x11, 0x4c, 0x44, 0x6c, 0xbd, 0x7e, 0xb2, 0x13, 0x6e, 0x68, 0xd1, 0x27, 0xc3, 0x24, - 0x28, 0x7d, 0xb0, 0x14, 0x74, 0x74, 0xb1, 0x61, 0xd7, 0xd9, 0x52, 0xa3, 0xe1, 0x51, 0xdf, 0x17, - 0x7b, 0x22, 0x77, 0xb1, 0xc1, 0xbb, 0xaf, 0xcd, 0x0b, 0x34, 0x17, 0x1b, 0x85, 0x80, 0x7c, 0x27, - 0x03, 0xa7, 0x54, 0x2b, 0x7d, 0xfc, 0x58, 0xd0, 0x86, 0x82, 0xef, 0x90, 0xaf, 0x5d, 0x93, 0x67, - 0xc2, 0x35, 0x05, 0xed, 0xda, 0xc3, 0x1b, 0xd7, 0x4a, 0xd1, 0xcf, 0x9a, 0x24, 0x12, 0xe1, 0xa9, - 0xd2, 0xf8, 0xa9, 0xfb, 0xbb, 0x9d, 0x42, 0x4a, 0xca, 0x4c, 0x6c, 0x60, 0xeb, 0x09, 0x6d, 0x72, - 0xaa, 0xeb, 0xb8, 0xc1, 0x0a, 0xf5, 0x9e, 0x58, 0x7d, 0xdc, 0x7a, 0xc7, 0xe9, 0xe8, 0xd2, 0x81, - 0x42, 0x43, 0xaa, 0x30, 0xc5, 0x01, 0x6c, 0x4b, 0xe0, 0xe9, 0x0e, 0x66, 0xa2, 0x90, 0xcb, 0x82, - 0x0d, 0x3e, 0x3c, 0x63, 0xca, 0x03, 0x35, 0x14, 0x5c, 0x8c, 0x0e, 0xe5, 0xf6, 0x5a, 0xe9, 0xfe, - 0x4a, 0x24, 0x7c, 0x7e, 0xb6, 0xac, 0xec, 0xb5, 0xbe, 0xf5, 0xb1, 0xb2, 0x7f, 0xc0, 0xfd, 0x0e, - 0x95, 0x61, 0x90, 0x72, 0xbb, 0x06, 0x8e, 0xcb, 0xed, 0x31, 0x1a, 0x33, 0x86, 0x6d, 0x7c, 0x54, - 0x88, 0xf1, 0x15, 0x96, 0x75, 0x06, 0x0c, 0x73, 0xb1, 0x5c, 0xcd, 0x9d, 0xcd, 0x85, 0x76, 0x53, - 0x94, 0x90, 0xb3, 0x90, 0xab, 0xd5, 0xd6, 0xc4, 0x20, 0xa3, 0x7d, 0x9d, 0xef, 0xbb, 0x26, 0x83, - 0xb1, 0x19, 0x42, 0xa3, 0x39, 0x25, 0xaa, 0x2e, 0xdb, 0x41, 0x4d, 0x84, 0xb2, 0xf1, 0x96, 0x42, - 0x72, 0x3e, 0x1a, 0x6f, 0x21, 0x24, 0x47, 0xa2, 0x71, 0x19, 0xe6, 0x4a, 0xbe, 0x4f, 0x3d, 0xb6, - 0x40, 0x85, 0x2d, 0x96, 0x27, 0x04, 0x39, 0x71, 0x50, 0x60, 0xa5, 0x76, 0xdd, 0x37, 0x7b, 0x22, - 0x92, 0x2b, 0x50, 0x28, 0x75, 0x1b, 0x0e, 0x6d, 0xd7, 0xb5, 0x90, 0x39, 0xb6, 0x80, 0x99, 0x61, - 0x29, 0xf9, 0x32, 0x9c, 0x8a, 0x85, 0x8d, 0x12, 0x23, 0x30, 0x12, 0x7d, 0xcd, 0x52, 0xd0, 0x8c, - 0x5e, 0x9c, 0xf9, 0x90, 0xa4, 0x53, 0x92, 0x12, 0x14, 0x97, 0xd0, 0xab, 0xa4, 0x42, 0xb9, 0xf2, - 0xdb, 0xf5, 0xb8, 0xa7, 0x0c, 0xbf, 0x16, 0x70, 0x8f, 0x13, 0xab, 0x11, 0x16, 0x9a, 0x09, 0x74, - 0x72, 0x0f, 0x66, 0xe2, 0x30, 0x76, 0x26, 0xf0, 0x1b, 0x00, 0x86, 0x75, 0x4c, 0x70, 0xc1, 0x53, - 0x21, 0x8d, 0x8a, 0x6c, 0xc3, 0x74, 0x64, 0x71, 0xa1, 0xdf, 0x0b, 0xa4, 0x59, 0x66, 0x58, 0x2e, - 0xef, 0x06, 0xcf, 0x8a, 0xc5, 0x38, 0x13, 0x59, 0x6f, 0x84, 0xf7, 0x03, 0x33, 0xc9, 0x8e, 0x34, - 0x60, 0xb2, 0xe6, 0xec, 0xb6, 0x9d, 0xf6, 0xee, 0x3d, 0x7a, 0xb8, 0x6e, 0x3b, 0x9e, 0x30, 0x90, - 0x93, 0xe6, 0xaf, 0x25, 0xff, 0xb0, 0xd5, 0xa2, 0x81, 0x87, 0xa7, 0x2d, 0x2b, 0x47, 0x27, 0x4f, - 0x26, 0xef, 0x9d, 0xf3, 0x39, 0x1d, 0x3a, 0x50, 0x75, 0x6c, 0x47, 0x3b, 0x56, 0x74, 0x9e, 0xda, - 0xdd, 0x6c, 0x7c, 0xc0, 0xbb, 0x59, 0x13, 0xa6, 0x97, 0xda, 0x75, 0xef, 0x10, 0xdf, 0x20, 0x64, - 0xe3, 0x26, 0x8e, 0x69, 0xdc, 0x0b, 0xa2, 0x71, 0xe7, 0x6d, 0xb9, 0xc2, 0xd2, 0x9a, 0x97, 0x64, - 0x4c, 0x6a, 0x30, 0x8d, 0x02, 0x74, 0xb5, 0xb2, 0x5e, 0x6d, 0x3b, 0x81, 0x83, 0x19, 0x9e, 0xf9, - 0x71, 0xf5, 0xa2, 0xe0, 0x79, 0x81, 0xcb, 0xe0, 0x4e, 0xa3, 0x63, 0x39, 0x12, 0x45, 0x65, 0x9a, - 0xa0, 0xef, 0x27, 0x08, 0x4f, 0xfd, 0xf3, 0x11, 0x84, 0x31, 0x07, 0x52, 0xcc, 0xf9, 0xb9, 0x18, - 0xed, 0xed, 0x3e, 0x16, 0xb1, 0x23, 0xc2, 0xed, 0xa2, 0x78, 0xa2, 0xe5, 0x40, 0xd2, 0xe9, 0x8c, - 0xef, 0x8c, 0xf2, 0xbd, 0x5d, 0x95, 0x5f, 0x7b, 0x99, 0xd2, 0xc5, 0xe4, 0xda, 0xec, 0x49, 0xe4, - 0xda, 0xdc, 0xf1, 0x72, 0x6d, 0xfe, 0x38, 0xb9, 0x36, 0x26, 0x78, 0x0e, 0x9d, 0x58, 0xf0, 0x1c, - 0x3e, 0x81, 0xe0, 0x39, 0x72, 0x22, 0xc1, 0x53, 0x93, 0xa0, 0x0b, 0xc7, 0x49, 0xd0, 0xff, 0xbf, - 0x98, 0xfa, 0xb4, 0x8a, 0xa9, 0x69, 0xa2, 0xc2, 0x89, 0xc4, 0xd4, 0xde, 0x52, 0x66, 0xf1, 0xcf, - 0x5b, 0xca, 0x9c, 0x7e, 0x32, 0x52, 0x26, 0xf9, 0x98, 0x52, 0xe6, 0x5f, 0x82, 0x62, 0xfc, 0xe0, - 0x3b, 0x3e, 0x5a, 0xde, 0x13, 0x8b, 0xec, 0xc4, 0x8e, 0xe5, 0xf8, 0xc1, 0xc3, 0x2e, 0xd2, 0xeb, - 0x9e, 0xf3, 0xd0, 0x0e, 0xe8, 0x3d, 0x69, 0x7a, 0x20, 0x22, 0x3d, 0x72, 0x28, 0x6e, 0x1f, 0x0a, - 0x4a, 0x28, 0x73, 0x65, 0xd3, 0x64, 0x2e, 0xe3, 0xc7, 0xb3, 0x30, 0xcd, 0xa3, 0xb0, 0x3c, 0xfd, - 0x1a, 0xf0, 0x77, 0x34, 0x49, 0x5a, 0x1a, 0xba, 0xc5, 0x7a, 0xd7, 0x47, 0x07, 0xfe, 0x35, 0x38, - 0x95, 0x18, 0x0a, 0x94, 0xa6, 0x2b, 0x32, 0xfe, 0x4d, 0x42, 0x9e, 0x9e, 0x4b, 0xaf, 0x64, 0xf3, - 0xa6, 0x99, 0xa0, 0x30, 0xfe, 0x69, 0x3e, 0xc1, 0x5f, 0x68, 0xc3, 0x55, 0xfd, 0x76, 0xe6, 0x64, - 0xfa, 0xed, 0xec, 0x60, 0xfa, 0xed, 0xd8, 0x31, 0x95, 0x1b, 0xe4, 0x98, 0xfa, 0x32, 0x4c, 0x6c, - 0x50, 0xbb, 0xe5, 0x6f, 0xb8, 0x22, 0x9c, 0x3b, 0x37, 0x74, 0x95, 0xe1, 0x6d, 0x58, 0x99, 0x14, - 0x06, 0x43, 0x83, 0x9d, 0x80, 0x11, 0xb0, 0xad, 0x95, 0xc7, 0x77, 0x37, 0x75, 0x0e, 0xaa, 0x84, - 0x3f, 0xd4, 0x47, 0xc2, 0xaf, 0xc1, 0xb8, 0xa0, 0x8b, 0x42, 0x04, 0x46, 0xa2, 0x28, 0x2b, 0x42, - 0xb8, 0xac, 0x3d, 0x4c, 0xb8, 0x17, 0xd6, 0xce, 0xa5, 0x50, 0x8d, 0x09, 0x1b, 0x82, 0xa5, 0x76, - 0xa3, 0xe3, 0x3a, 0x6d, 0x1c, 0x82, 0x91, 0x68, 0x08, 0xa8, 0x00, 0xf3, 0x21, 0x50, 0x90, 0xc8, - 0x5b, 0x30, 0x59, 0x5a, 0xaf, 0xaa, 0x64, 0x85, 0x48, 0xc5, 0x6e, 0x77, 0x1c, 0x4b, 0x23, 0x8d, - 0xe1, 0xf6, 0x93, 0xca, 0x46, 0xff, 0xf9, 0x48, 0x65, 0xc6, 0xb7, 0x47, 0xe5, 0xe7, 0xfd, 0xe9, - 0x2a, 0x03, 0x75, 0xf5, 0x5e, 0xee, 0x84, 0xea, 0xbd, 0xfc, 0x71, 0xc2, 0x89, 0x26, 0x31, 0x0d, - 0x9d, 0x40, 0x62, 0x1a, 0xfe, 0xc4, 0xaa, 0xba, 0x91, 0x13, 0xca, 0x40, 0xb1, 0x2f, 0xad, 0x30, - 0xc8, 0x97, 0x96, 0x2a, 0x37, 0x8d, 0x7e, 0x72, 0xb9, 0x09, 0x4e, 0x2c, 0x37, 0xd5, 0x22, 0x27, - 0xb0, 0xb1, 0x63, 0xad, 0x71, 0x2f, 0x88, 0xfb, 0xca, 0x74, 0x7a, 0x00, 0x9e, 0xd0, 0x1d, 0xec, - 0x33, 0x25, 0x8c, 0x7d, 0x23, 0x5d, 0x18, 0xeb, 0x7f, 0xda, 0xfc, 0x7f, 0x58, 0x1c, 0x33, 0x3c, - 0x1c, 0xe5, 0x2d, 0xdb, 0x6b, 0xe3, 0x3d, 0xf1, 0x3a, 0x8c, 0xc8, 0x40, 0x54, 0x99, 0x48, 0xe5, - 0x91, 0x8c, 0x40, 0x25, 0xb1, 0xd8, 0x95, 0x5e, 0x12, 0xab, 0x41, 0xb5, 0x0f, 0x04, 0x4c, 0x8b, - 0xf1, 0x23, 0x60, 0xc6, 0xdf, 0xcd, 0xcb, 0x2f, 0x99, 0xc9, 0x72, 0x22, 0x01, 0xf3, 0xa2, 0x32, - 0x73, 0x8a, 0x04, 0x17, 0x9b, 0x9b, 0x98, 0x71, 0x9d, 0x4e, 0xf2, 0xb1, 0x42, 0x83, 0x45, 0x89, - 0x9f, 0x72, 0x03, 0x24, 0x7e, 0x7a, 0x43, 0xcb, 0x9a, 0x94, 0x8f, 0xd2, 0x74, 0xb0, 0xd5, 0xdd, - 0x3f, 0x5f, 0xd2, 0x2d, 0x35, 0xbd, 0xd1, 0x50, 0x14, 0x25, 0x03, 0x29, 0xfb, 0x24, 0x36, 0x0a, - 0x45, 0xd2, 0xe1, 0x93, 0x04, 0xdd, 0x1b, 0xf9, 0x73, 0x0d, 0xba, 0xb7, 0x04, 0xa0, 0x24, 0xbd, - 0xe5, 0x2f, 0x32, 0x2f, 0xb2, 0x61, 0x3a, 0x3e, 0xe1, 0xad, 0x42, 0x68, 0xfc, 0x1e, 0x81, 0xe9, - 0x5a, 0x6d, 0xad, 0xe2, 0xd8, 0xbb, 0x6d, 0xd7, 0x0f, 0x9c, 0x7a, 0xb5, 0xbd, 0xe3, 0x32, 0x79, - 0x2c, 0xdc, 0x15, 0x94, 0xe8, 0x6a, 0xd1, 0x8e, 0x10, 0x16, 0x33, 0x79, 0x7f, 0xc9, 0xf3, 0x5c, - 0x4f, 0x95, 0xf7, 0x29, 0x03, 0x98, 0x1c, 0xce, 0x44, 0x9e, 0x5a, 0x97, 0x67, 0x2f, 0xe5, 0x8f, - 0x64, 0x28, 0xf2, 0xf8, 0x1c, 0x64, 0xca, 0x32, 0x42, 0x93, 0x0b, 0x56, 0x88, 0xc0, 0x67, 0xb4, - 0xd0, 0x7d, 0x51, 0x31, 0xdf, 0xf3, 0xc4, 0x99, 0x84, 0xd7, 0x99, 0x0e, 0xc2, 0xd5, 0x37, 0xe9, - 0xc4, 0x37, 0x70, 0x08, 0xa7, 0x34, 0xaf, 0xa3, 0x41, 0xb5, 0x7d, 0x2f, 0x0b, 0x11, 0xcb, 0x40, - 0x97, 0xd5, 0x14, 0x95, 0x9f, 0x9a, 0x66, 0x20, 0xb5, 0x06, 0xf2, 0xe3, 0x19, 0xb8, 0x90, 0x5a, - 0x12, 0x7e, 0xdd, 0x63, 0x5a, 0xf8, 0x44, 0x65, 0xd3, 0xe0, 0x09, 0x15, 0x7a, 0x55, 0x6d, 0xa5, - 0x6c, 0x05, 0xfd, 0x6b, 0x22, 0xbf, 0x91, 0x81, 0x33, 0x1a, 0x46, 0xb8, 0xe7, 0xf9, 0xa1, 0x7b, - 0x6d, 0xea, 0xba, 0xfe, 0xf0, 0xc9, 0xac, 0xeb, 0x4b, 0x7a, 0x5f, 0xa2, 0x2d, 0x59, 0xed, 0x43, - 0xaf, 0x16, 0x92, 0x87, 0x30, 0x8d, 0x45, 0x52, 0xf3, 0xc8, 0xd6, 0xac, 0x50, 0x58, 0xce, 0x46, - 0xcd, 0xe6, 0x9e, 0x74, 0x98, 0x14, 0x6f, 0xe1, 0xfb, 0x47, 0xf3, 0x13, 0x1a, 0xba, 0x0c, 0x48, - 0x68, 0x45, 0xea, 0x4b, 0xa7, 0xbd, 0xe3, 0xaa, 0xe7, 0x65, 0xa2, 0x0a, 0xf2, 0x1f, 0x64, 0x60, - 0x8e, 0x41, 0x79, 0x37, 0x6e, 0x7b, 0x6e, 0x2b, 0x2c, 0x97, 0xc6, 0x0d, 0x3d, 0x86, 0xad, 0xf9, - 0x64, 0x86, 0xed, 0x45, 0x6c, 0x32, 0xdf, 0x13, 0xac, 0x1d, 0xcf, 0x6d, 0x45, 0xcd, 0xd7, 0x92, - 0xba, 0xf6, 0x6a, 0x24, 0xf9, 0xe1, 0x0c, 0x9c, 0xd5, 0xd4, 0x25, 0x6a, 0xd8, 0x66, 0xe1, 0xaf, - 0x38, 0x13, 0xfa, 0x25, 0x47, 0x45, 0x8b, 0xd7, 0xc4, 0xfa, 0xbf, 0x8c, 0x2d, 0x88, 0x4e, 0x0b, - 0x6c, 0x8b, 0xd5, 0xe2, 0x58, 0x4a, 0x13, 0x7a, 0xd7, 0x42, 0x1c, 0x98, 0xc6, 0x87, 0x45, 0xcd, - 0x08, 0x67, 0xb6, 0xb7, 0x11, 0x4e, 0x98, 0xbc, 0x08, 0x63, 0xc2, 0xf6, 0xb6, 0xc4, 0x49, 0x72, - 0x25, 0x7f, 0x19, 0xce, 0x26, 0x80, 0xe1, 0xd7, 0x76, 0xaa, 0xe7, 0xd7, 0xf6, 0xca, 0xe3, 0xa3, - 0xf9, 0x97, 0xd2, 0x6a, 0x4b, 0xfb, 0xd2, 0x7a, 0xd7, 0x40, 0x6c, 0x80, 0xa8, 0x50, 0xe4, 0x86, - 0x4d, 0x5f, 0xa0, 0xaf, 0x88, 0xf5, 0xa1, 0xe0, 0xb3, 0xbd, 0x5c, 0x69, 0x83, 0x7a, 0xe4, 0x45, - 0x48, 0x84, 0xc2, 0xb8, 0x12, 0x0f, 0xf7, 0x10, 0x93, 0xc4, 0xf6, 0xac, 0xe4, 0xfb, 0x47, 0xf3, - 0x1a, 0x36, 0x93, 0x8b, 0xd5, 0x40, 0xbb, 0xaa, 0x5c, 0xac, 0x21, 0x92, 0x5f, 0xcb, 0xc0, 0x2c, - 0x03, 0x44, 0x8b, 0x4a, 0x74, 0x6a, 0xae, 0xdf, 0xaa, 0xdf, 0x7b, 0x32, 0xab, 0xfe, 0x79, 0x6c, - 0xa3, 0xba, 0xea, 0x13, 0x43, 0x92, 0xda, 0x38, 0x5c, 0xed, 0xda, 0x1b, 0xb6, 0xb6, 0xda, 0xcf, - 0x0e, 0xb0, 0xda, 0xf9, 0x04, 0x1c, 0xbf, 0xda, 0x7b, 0xd6, 0x42, 0x36, 0x60, 0x5c, 0x88, 0xc4, - 0x7c, 0xc0, 0x9e, 0xd3, 0x62, 0x69, 0xaa, 0x45, 0xfc, 0x9e, 0x22, 0xc2, 0x05, 0x27, 0x7a, 0xa8, - 0x71, 0x21, 0x6d, 0x98, 0xe1, 0xbf, 0x75, 0x05, 0xc5, 0x7c, 0x4f, 0x05, 0xc5, 0x15, 0xd1, 0xa3, - 0x8b, 0x82, 0x7f, 0x4c, 0x4f, 0xa1, 0x86, 0x33, 0x48, 0x61, 0x4c, 0x3a, 0x40, 0x34, 0x30, 0xff, - 0x68, 0x2f, 0xf6, 0x57, 0x4b, 0xbc, 0x24, 0xea, 0x9c, 0x8f, 0xd7, 0x19, 0xff, 0x72, 0x53, 0x78, - 0x13, 0x1b, 0xa6, 0x04, 0x94, 0x5d, 0x80, 0x71, 0x87, 0x7f, 0x5e, 0x0b, 0x28, 0x11, 0x2b, 0xe5, - 0xca, 0x4d, 0x59, 0x13, 0x06, 0xfc, 0x88, 0x6d, 0xe8, 0x71, 0x7e, 0x64, 0x0d, 0xa6, 0x4b, 0x9d, - 0x4e, 0xd3, 0xa1, 0x0d, 0xec, 0x25, 0xcf, 0xf3, 0x69, 0x44, 0xb9, 0x1d, 0x6c, 0x5e, 0x28, 0x44, - 0xfc, 0x78, 0x92, 0xcf, 0x24, 0xad, 0xf1, 0x9d, 0x4c, 0xa2, 0xd1, 0xec, 0xe6, 0x8e, 0x3f, 0x14, - 0xaf, 0x66, 0xbc, 0xb9, 0xf3, 0x26, 0xa2, 0x06, 0x21, 0x42, 0x60, 0xc2, 0x92, 0x1a, 0xa7, 0x28, - 0xc7, 0x85, 0x25, 0x71, 0xbd, 0x8c, 0x2e, 0x94, 0xf3, 0xd2, 0x38, 0x32, 0x17, 0x09, 0x5d, 0x68, - 0x1c, 0x29, 0x4c, 0x22, 0x8d, 0x1f, 0xce, 0xea, 0xcb, 0x8e, 0x5c, 0x51, 0xe4, 0x76, 0x25, 0x52, - 0x92, 0x94, 0xdb, 0x15, 0x69, 0xfd, 0xef, 0x64, 0x60, 0x66, 0xcd, 0xdb, 0xb5, 0xdb, 0xce, 0xb7, - 0x78, 0xc4, 0x45, 0x17, 0xe7, 0xa5, 0x7f, 0x9a, 0x9c, 0x27, 0x95, 0xee, 0xc3, 0x55, 0x2a, 0x66, - 0x2b, 0x05, 0x97, 0x8c, 0x99, 0xd6, 0x1e, 0x34, 0x37, 0xc7, 0x86, 0x29, 0x59, 0x57, 0x38, 0x3a, - 0x87, 0x1b, 0x3f, 0x99, 0x85, 0x31, 0xe5, 0x13, 0x20, 0x9f, 0x87, 0x71, 0x95, 0x8f, 0xaa, 0xf5, - 0x51, 0xab, 0x35, 0x35, 0x2c, 0x54, 0xfb, 0x50, 0xbb, 0xa5, 0xa9, 0x7d, 0xd8, 0x42, 0x47, 0xe8, - 0x09, 0xaf, 0x36, 0xef, 0xa6, 0x5c, 0x6d, 0x4e, 0x94, 0x10, 0xf6, 0xad, 0xe4, 0x05, 0x67, 0xf0, - 0xfc, 0xad, 0xc6, 0xcf, 0x64, 0xa0, 0x18, 0xff, 0x48, 0x3f, 0x95, 0x51, 0x39, 0x81, 0x8a, 0xff, - 0x27, 0xb2, 0x61, 0x30, 0x6c, 0xe9, 0x44, 0xf3, 0xb4, 0xda, 0xb1, 0xbc, 0xad, 0x69, 0xdf, 0x9f, - 0xd5, 0xa3, 0xbb, 0xa8, 0xee, 0xa7, 0xe9, 0x21, 0x9d, 0xf2, 0xdf, 0xfb, 0xc5, 0xf9, 0x67, 0x8c, - 0xf7, 0x61, 0x36, 0x3e, 0x1c, 0xa8, 0x81, 0x2f, 0xc1, 0x94, 0x0e, 0x8f, 0x87, 0xd2, 0x8f, 0x53, - 0x99, 0x71, 0x7c, 0xe3, 0xf7, 0xb3, 0x71, 0xde, 0xc2, 0xa6, 0x85, 0x6d, 0x3a, 0x6d, 0x7b, 0xbb, - 0x19, 0x86, 0xd2, 0xe6, 0x9b, 0x0e, 0x07, 0x99, 0xb2, 0xec, 0x24, 0xb9, 0x25, 0x42, 0x57, 0x90, - 0x5c, 0xba, 0x2b, 0x08, 0xb9, 0x15, 0x33, 0x0c, 0x53, 0xe2, 0x16, 0x1c, 0xd0, 0x6d, 0x2b, 0x32, - 0x0e, 0x8b, 0xd9, 0x83, 0x95, 0x61, 0x56, 0x0b, 0xa9, 0x29, 0xe9, 0x87, 0x22, 0x85, 0x6b, 0x80, - 0x05, 0x9c, 0x38, 0x15, 0x99, 0x2c, 0xc3, 0x08, 0x6b, 0xe6, 0x7d, 0xbb, 0x23, 0x14, 0xeb, 0x24, - 0x74, 0x0c, 0x6b, 0x86, 0x17, 0x3e, 0xc5, 0x37, 0xac, 0x49, 0xd9, 0x91, 0xaf, 0xe5, 0x53, 0xe6, - 0x88, 0xc6, 0x9f, 0x66, 0xd8, 0xf7, 0x5f, 0xdf, 0xff, 0x8c, 0x25, 0xa8, 0x60, 0x5d, 0xea, 0x63, - 0x72, 0xf5, 0x47, 0x59, 0x1e, 0x0d, 0x5d, 0x2c, 0x9f, 0x37, 0x60, 0x78, 0xc3, 0xf6, 0x76, 0x69, - 0x20, 0xe2, 0x84, 0xab, 0x5c, 0x78, 0x41, 0x14, 0x55, 0x21, 0xc0, 0xdf, 0xa6, 0x20, 0x50, 0x75, - 0x61, 0xd9, 0x81, 0x74, 0x61, 0x8a, 0x7a, 0x36, 0xf7, 0xc4, 0xd4, 0xb3, 0x3f, 0x10, 0x06, 0x3e, - 0x2f, 0x05, 0x03, 0x44, 0x6c, 0xbc, 0x18, 0x4f, 0x1c, 0x90, 0x88, 0xad, 0x19, 0xb1, 0x23, 0xb7, - 0xd4, 0x54, 0x04, 0x8a, 0x77, 0xc5, 0x31, 0x49, 0x07, 0x8c, 0x3f, 0xca, 0xf1, 0x31, 0x16, 0x03, - 0x75, 0x59, 0xf3, 0xbc, 0xc2, 0xef, 0x84, 0x6d, 0xf4, 0xaa, 0x13, 0x2c, 0x5a, 0x63, 0x5c, 0x86, - 0x3c, 0x5b, 0x9b, 0x62, 0x34, 0x11, 0x8f, 0xad, 0x5f, 0x15, 0x8f, 0x95, 0xb3, 0x6f, 0x19, 0xcf, - 0x24, 0x35, 0xf9, 0x0b, 0x1e, 0x5b, 0xea, 0xb7, 0x8c, 0x18, 0xe4, 0x0a, 0xe4, 0x57, 0xdd, 0x86, - 0x8c, 0x0c, 0x3a, 0x8b, 0xfe, 0xb7, 0x6e, 0x43, 0x61, 0x39, 0x97, 0x31, 0x11, 0x83, 0xf5, 0x35, - 0x8c, 0x25, 0xae, 0xf6, 0xb5, 0xb5, 0x63, 0x8b, 0xf0, 0x55, 0x6a, 0x5f, 0xa3, 0xb0, 0xe3, 0x4b, - 0x30, 0xa9, 0xa7, 0x7f, 0x14, 0x06, 0x69, 0xa8, 0x66, 0x8d, 0x65, 0x91, 0x54, 0xb5, 0xe3, 0x3a, - 0x11, 0x59, 0x84, 0x09, 0x2d, 0x22, 0x99, 0x78, 0xe1, 0x42, 0xf5, 0xa6, 0x1e, 0xcf, 0x4c, 0x55, - 0x6f, 0x6a, 0x24, 0xec, 0x3c, 0x17, 0xed, 0x57, 0xde, 0xb9, 0x12, 0x6d, 0x17, 0x38, 0xe4, 0x26, - 0x14, 0xb8, 0xa3, 0x6b, 0xb5, 0xa2, 0xbe, 0x56, 0xf8, 0x08, 0x8b, 0x39, 0x8a, 0x4b, 0x44, 0xc5, - 0xb1, 0xf1, 0x73, 0x50, 0x14, 0x5b, 0x52, 0x94, 0x68, 0xf1, 0x3c, 0xe4, 0xcb, 0xd5, 0x8a, 0xa9, - 0x6e, 0x23, 0x75, 0xa7, 0xe1, 0x99, 0x08, 0x35, 0xbe, 0x9b, 0x81, 0xb3, 0xab, 0x34, 0x38, 0x70, - 0xbd, 0x7d, 0x93, 0xfa, 0x81, 0xe7, 0xf0, 0xdc, 0x41, 0xf8, 0x21, 0x7e, 0x9e, 0xbc, 0x05, 0x43, - 0x68, 0x19, 0x15, 0x3b, 0x19, 0xe2, 0x75, 0x2c, 0x4e, 0x88, 0x05, 0x3c, 0x84, 0x66, 0x56, 0x26, - 0x27, 0x22, 0x6f, 0x40, 0xbe, 0x42, 0xdb, 0x87, 0xb1, 0xec, 0x29, 0x09, 0xe2, 0x70, 0x43, 0x68, - 0xd0, 0xf6, 0xa1, 0x89, 0x24, 0xc6, 0xcf, 0x64, 0xe1, 0x54, 0x4a, 0xb3, 0x36, 0x3f, 0xff, 0x94, - 0xee, 0x8a, 0x8b, 0xda, 0xae, 0x28, 0x1f, 0x29, 0x7b, 0x0e, 0x7c, 0xea, 0x26, 0xf9, 0xf3, 0x19, - 0x38, 0xa3, 0x2f, 0x50, 0x61, 0x0a, 0xb9, 0x79, 0x93, 0xbc, 0x09, 0xc3, 0xcb, 0xd4, 0x6e, 0x50, - 0x99, 0x59, 0xe1, 0x54, 0x18, 0x92, 0x86, 0x7b, 0xf1, 0xf1, 0x42, 0xce, 0x36, 0xf2, 0xf9, 0xe0, - 0x50, 0x52, 0x11, 0x8d, 0xe3, 0xf2, 0xb8, 0x21, 0x3d, 0x6a, 0xd3, 0xaa, 0xea, 0xf3, 0xd4, 0xff, - 0xfd, 0x0c, 0x3c, 0xdb, 0x87, 0x86, 0x4d, 0x1c, 0x9b, 0x7a, 0x75, 0xe2, 0xf0, 0x44, 0x45, 0x28, - 0x79, 0x07, 0xa6, 0x36, 0x84, 0x3c, 0x2f, 0xa7, 0x23, 0x1b, 0x7d, 0x2f, 0x52, 0xd4, 0xb7, 0xe4, - 0xbc, 0xc4, 0x91, 0x35, 0x57, 0xef, 0x5c, 0x5f, 0x57, 0x6f, 0xd5, 0x73, 0x3a, 0x3f, 0xa8, 0xe7, - 0xf4, 0xfb, 0xf1, 0xa4, 0xe9, 0x22, 0x80, 0x5d, 0xe4, 0x37, 0x9e, 0xe9, 0xed, 0x37, 0xde, 0x37, - 0x4c, 0x96, 0xf1, 0x93, 0x19, 0x28, 0xea, 0xbc, 0x3f, 0xe9, 0x7c, 0xbe, 0xad, 0xcd, 0xe7, 0xb3, - 0xe9, 0xf3, 0xd9, 0x7b, 0x22, 0xff, 0x97, 0x4c, 0xbc, 0xb3, 0x03, 0xcd, 0xa0, 0x01, 0xc3, 0x15, - 0xb7, 0x65, 0x3b, 0x6d, 0x35, 0x6f, 0x67, 0x03, 0x21, 0xa6, 0x28, 0x19, 0xcc, 0xcd, 0xfe, 0x22, - 0x0c, 0xad, 0xba, 0xed, 0x52, 0x45, 0x58, 0x0a, 0x22, 0x9f, 0xb6, 0xdb, 0xb6, 0xec, 0x86, 0xc9, - 0x0b, 0xc8, 0x0a, 0x40, 0xad, 0xee, 0x51, 0xda, 0xae, 0x39, 0xdf, 0xa2, 0x31, 0x49, 0x83, 0x8d, - 0x50, 0xb3, 0x8b, 0x1b, 0x0b, 0xbe, 0xf1, 0xf8, 0x88, 0x68, 0xf9, 0xce, 0xb7, 0xd4, 0xfd, 0x56, - 0xa1, 0x37, 0x28, 0x40, 0x44, 0x84, 0x49, 0xcc, 0x9c, 0x86, 0x48, 0x4c, 0x3b, 0x21, 0x92, 0x98, - 0x31, 0x80, 0x96, 0xc4, 0x8c, 0x01, 0xd8, 0xd6, 0xbe, 0x4c, 0x9d, 0xdd, 0x3d, 0x6e, 0x32, 0x32, - 0xc1, 0x97, 0xea, 0x1e, 0x42, 0xd4, 0xad, 0x9d, 0xe3, 0x18, 0x3f, 0x3e, 0x04, 0x67, 0x4d, 0xba, - 0xeb, 0x30, 0x31, 0xf9, 0x81, 0xef, 0xb4, 0x77, 0x35, 0x47, 0x68, 0x23, 0xb6, 0x90, 0x44, 0x0c, - 0x60, 0x06, 0x09, 0x07, 0xe6, 0x2a, 0x14, 0xd8, 0xa9, 0xa8, 0xac, 0x25, 0x7c, 0x43, 0xc1, 0xac, - 0xdb, 0x7c, 0x91, 0xcb, 0x62, 0xf2, 0xb2, 0x38, 0xb5, 0x95, 0x28, 0xed, 0xec, 0xd4, 0xfe, 0xe8, - 0x68, 0x1e, 0x6a, 0x87, 0x7e, 0x40, 0xf1, 0xc6, 0x26, 0x4e, 0xee, 0x50, 0xb4, 0xce, 0xf7, 0x10, - 0xad, 0xef, 0xc3, 0x6c, 0xa9, 0xc1, 0x37, 0x6b, 0xbb, 0xb9, 0xee, 0x39, 0xed, 0xba, 0xd3, 0xb1, - 0x9b, 0xf2, 0xba, 0x88, 0xa3, 0x6c, 0x87, 0xe5, 0x56, 0x27, 0x44, 0x30, 0x53, 0xc9, 0x58, 0x37, - 0x2a, 0xab, 0x35, 0xf4, 0x17, 0x16, 0xcf, 0x63, 0xd8, 0x8d, 0x46, 0xdb, 0xc7, 0x5e, 0xf8, 0x66, - 0x58, 0x8c, 0x42, 0x3d, 0xda, 0x20, 0x6c, 0xac, 0xd4, 0x22, 0x97, 0x22, 0x1e, 0x44, 0x96, 0xdb, - 0x29, 0x04, 0x4d, 0x1f, 0x6d, 0x15, 0x34, 0xbc, 0x88, 0xae, 0x56, 0x5b, 0x66, 0x74, 0x85, 0x04, - 0x9d, 0xef, 0xef, 0xa9, 0x74, 0x1c, 0x8f, 0x5c, 0x67, 0x4b, 0xa1, 0xe5, 0x06, 0x14, 0xd7, 0xf9, - 0x68, 0x74, 0x05, 0xf0, 0x10, 0xca, 0xaf, 0x00, 0x0a, 0x0a, 0x79, 0x0b, 0x66, 0x96, 0xca, 0x0b, - 0x52, 0xa9, 0x59, 0x71, 0xeb, 0x5d, 0x7c, 0x55, 0x06, 0xac, 0x0f, 0xe7, 0x90, 0xd6, 0x17, 0xd8, - 0xe2, 0x4e, 0x43, 0x23, 0x97, 0x61, 0xa4, 0x5a, 0xe1, 0x63, 0x3f, 0xa6, 0x66, 0x4a, 0x10, 0xd6, - 0x1a, 0xb2, 0x90, 0xac, 0x45, 0x32, 0xea, 0xf8, 0xb1, 0xc2, 0xe4, 0xd9, 0xe3, 0xe5, 0x53, 0x91, - 0x50, 0x81, 0x27, 0xee, 0x29, 0xbb, 0x0d, 0xea, 0x6f, 0xde, 0xf8, 0x8c, 0x25, 0x54, 0x50, 0xfa, - 0x86, 0xbb, 0xd7, 0x8d, 0xd4, 0xad, 0xee, 0x5f, 0xc5, 0x84, 0x0a, 0x09, 0x5c, 0xf2, 0x45, 0x18, - 0xc2, 0x9f, 0x42, 0xee, 0x99, 0x49, 0x61, 0x1b, 0xc9, 0x3c, 0x75, 0x9e, 0x77, 0x17, 0x09, 0x48, - 0x15, 0x46, 0x84, 0xc8, 0x7d, 0x92, 0xb0, 0xe0, 0x42, 0x76, 0xe7, 0x93, 0x24, 0xe8, 0x8d, 0x06, - 0x8c, 0xab, 0x15, 0xb2, 0xc5, 0xb9, 0x6c, 0xfb, 0x7b, 0xb4, 0xc1, 0x7e, 0x89, 0x8c, 0x1e, 0xb8, - 0x38, 0xf7, 0x10, 0x6a, 0xb1, 0x76, 0x98, 0x0a, 0x0a, 0xdb, 0x6d, 0xab, 0xfe, 0x03, 0x5f, 0x34, - 0x45, 0x5c, 0xc2, 0x1d, 0x54, 0xe8, 0x34, 0x4c, 0x51, 0x64, 0xfc, 0x00, 0xcc, 0xae, 0x76, 0x9b, - 0x4d, 0x76, 0x21, 0x97, 0x11, 0x9f, 0x03, 0x3b, 0xa0, 0x64, 0x11, 0x86, 0x6a, 0x4a, 0x26, 0xbf, - 0x99, 0x30, 0xa4, 0x76, 0x84, 0x83, 0x36, 0x6a, 0x19, 0x74, 0xa3, 0x8e, 0xe5, 0xf0, 0xe3, 0xa4, - 0xc6, 0xef, 0x46, 0x19, 0xa0, 0x37, 0x3c, 0xbb, 0xbe, 0x1f, 0x66, 0x73, 0x1c, 0x34, 0x99, 0xf5, - 0x5d, 0xd9, 0x08, 0xfd, 0x28, 0x4b, 0x6b, 0xf0, 0x71, 0x8d, 0x21, 0x6f, 0xc1, 0x98, 0x38, 0xce, - 0x94, 0xe0, 0x3f, 0x18, 0x61, 0x41, 0xa6, 0x93, 0x8f, 0x99, 0x1b, 0xa8, 0xe8, 0x78, 0x4a, 0xeb, - 0x5d, 0xd9, 0xbc, 0xf1, 0x69, 0x9c, 0xd2, 0x7a, 0x1d, 0x7d, 0x96, 0xee, 0x3f, 0x1c, 0x8b, 0x8f, - 0xad, 0x58, 0xbb, 0xb7, 0xd4, 0x70, 0x1f, 0x99, 0xe8, 0xce, 0x14, 0x85, 0xfb, 0x50, 0xef, 0x4c, - 0x21, 0x6a, 0x38, 0x27, 0xd9, 0x63, 0xe6, 0xe4, 0x1d, 0x39, 0x27, 0xb9, 0xde, 0x0b, 0x63, 0xa6, - 0xcf, 0x3c, 0xd4, 0xa2, 0x2f, 0x24, 0x3f, 0xd0, 0x85, 0xfb, 0x19, 0x8c, 0x6b, 0xca, 0x49, 0xe2, - 0x1b, 0x9a, 0xe0, 0xa4, 0xde, 0xe2, 0x87, 0x06, 0x67, 0x7a, 0xcc, 0x2d, 0xfe, 0x4b, 0x30, 0x5e, - 0x0a, 0x02, 0xbb, 0xbe, 0x47, 0x1b, 0x15, 0xb6, 0x3d, 0x29, 0x91, 0x09, 0x6c, 0x01, 0x57, 0x9f, - 0x53, 0x54, 0x5c, 0x1e, 0x69, 0xcb, 0xf6, 0x85, 0xb5, 0x5b, 0x18, 0x69, 0x8b, 0x41, 0xf4, 0x48, - 0x5b, 0x0c, 0x42, 0xae, 0xc3, 0x48, 0xb5, 0xfd, 0xd0, 0x61, 0x63, 0x52, 0x50, 0x72, 0xd6, 0x73, - 0x90, 0xba, 0xb9, 0x0a, 0x2c, 0xf2, 0x86, 0x22, 0xee, 0x8e, 0x46, 0x57, 0x5b, 0xae, 0x0c, 0x09, - 0x9d, 0x9a, 0x55, 0x51, 0x36, 0x94, 0x7f, 0x6f, 0xc1, 0x88, 0xd4, 0x71, 0x41, 0x74, 0x9d, 0x15, - 0x94, 0x49, 0xef, 0x49, 0x89, 0x8c, 0x09, 0x00, 0x95, 0xcc, 0x24, 0x63, 0x4a, 0x02, 0x40, 0x25, - 0x33, 0x89, 0x96, 0x00, 0x50, 0xc9, 0x51, 0x12, 0xaa, 0x07, 0xc6, 0x8f, 0x55, 0x0f, 0x6c, 0xc2, - 0xf8, 0xba, 0xed, 0x05, 0x0e, 0x13, 0x17, 0xda, 0x81, 0x3f, 0x37, 0xa1, 0x69, 0xd4, 0x94, 0xa2, - 0xc5, 0xe7, 0x64, 0xce, 0xba, 0x8e, 0x82, 0xaf, 0x27, 0x57, 0x8b, 0xe0, 0xe9, 0xb6, 0x6e, 0x93, - 0x9f, 0xc4, 0xd6, 0x0d, 0x07, 0x15, 0xb5, 0x28, 0x53, 0xd1, 0x5d, 0x1d, 0xc5, 0xd9, 0x98, 0x2a, - 0x25, 0x44, 0x24, 0x5f, 0x85, 0x71, 0xf6, 0x37, 0xa6, 0x89, 0x77, 0xa8, 0x3f, 0x57, 0xc4, 0xce, - 0x3d, 0x97, 0xfa, 0xf5, 0xf3, 0x5c, 0xf2, 0x35, 0x1a, 0xf0, 0x0f, 0x18, 0x19, 0xc7, 0xd5, 0xa3, - 0x1a, 0x37, 0xf2, 0x2e, 0x8c, 0xb3, 0xd5, 0xb7, 0x6d, 0xfb, 0x5c, 0x4a, 0x9c, 0x8e, 0xac, 0x15, - 0x1b, 0x02, 0x9e, 0x08, 0x76, 0xa7, 0x12, 0xb0, 0x63, 0xbe, 0xd4, 0xe1, 0x1b, 0x24, 0x51, 0x56, - 0x7b, 0x27, 0xb1, 0x39, 0x4a, 0x34, 0xf2, 0x1e, 0x8c, 0x97, 0x3a, 0x9d, 0x68, 0xc7, 0x99, 0x51, - 0x54, 0x24, 0x9d, 0x8e, 0x95, 0xba, 0xeb, 0x68, 0x14, 0xf1, 0x8d, 0x79, 0xf6, 0x44, 0x1b, 0x33, - 0x79, 0x2d, 0x14, 0x9c, 0x4f, 0x45, 0xfa, 0x3e, 0x71, 0xa5, 0xd0, 0xa4, 0x70, 0x2e, 0x43, 0x97, - 0x61, 0x82, 0x2b, 0xc0, 0xa4, 0x34, 0x73, 0x3a, 0xf1, 0xf5, 0xa4, 0x08, 0x35, 0x3a, 0x0d, 0x59, - 0x82, 0x49, 0xee, 0x28, 0xd6, 0x14, 0x51, 0x08, 0xe7, 0xce, 0x44, 0xc9, 0x88, 0xb9, 0x7f, 0x59, - 0x13, 0x83, 0x53, 0xdb, 0x1a, 0x97, 0x18, 0x91, 0xf1, 0xc7, 0x19, 0x38, 0xd3, 0x63, 0xc6, 0xc3, - 0x18, 0x75, 0x99, 0xfe, 0x31, 0xea, 0xd8, 0xce, 0xa1, 0xdf, 0x97, 0xb1, 0xff, 0x42, 0xca, 0x52, - 0xe7, 0x4b, 0xca, 0x5b, 0x2e, 0x10, 0x11, 0xcd, 0x5d, 0x54, 0x7d, 0xd7, 0x45, 0xa5, 0x5d, 0x2e, - 0x79, 0x08, 0x09, 0x3c, 0xde, 0xa8, 0x45, 0xe3, 0xf1, 0xd1, 0xfc, 0x73, 0x22, 0x58, 0x7c, 0x38, - 0xad, 0x1f, 0xba, 0xda, 0x17, 0x9c, 0xc2, 0xda, 0x38, 0xca, 0xc0, 0x98, 0xf2, 0x1d, 0x92, 0x8b, - 0x8a, 0xdb, 0x59, 0x91, 0xa7, 0x1b, 0x50, 0x38, 0x64, 0xf9, 0x49, 0x84, 0x1f, 0x55, 0xf6, 0x78, - 0xd5, 0xe4, 0x7d, 0x26, 0x0a, 0x29, 0x71, 0xfc, 0x5a, 0x9a, 0x1e, 0xd1, 0xc4, 0x72, 0x4c, 0xb5, - 0x69, 0xfb, 0x41, 0xa9, 0x1e, 0x38, 0x0f, 0xe9, 0x00, 0x87, 0x4e, 0x94, 0x6a, 0xd3, 0xf6, 0x03, - 0xcb, 0x46, 0xb2, 0x44, 0xaa, 0xcd, 0x90, 0xa1, 0xf1, 0x23, 0x19, 0x80, 0x07, 0xd5, 0x32, 0x06, - 0xe2, 0xfc, 0xa4, 0x42, 0x41, 0x7a, 0x70, 0x33, 0xc9, 0xbd, 0x8f, 0x38, 0xf0, 0x5f, 0x67, 0x60, - 0x52, 0x47, 0x23, 0xef, 0xc0, 0x54, 0xad, 0xee, 0xb9, 0xcd, 0xe6, 0xb6, 0x5d, 0xdf, 0x5f, 0x71, - 0xda, 0x94, 0x87, 0x95, 0x1a, 0xe2, 0x67, 0x91, 0x1f, 0x16, 0x59, 0x4d, 0x56, 0x66, 0xc6, 0x91, - 0xc9, 0x8f, 0x66, 0x60, 0xa2, 0xb6, 0xe7, 0x1e, 0x44, 0x19, 0xd0, 0xf9, 0x84, 0x7c, 0x8d, 0x7d, - 0xdb, 0xfe, 0x9e, 0x7b, 0x60, 0xa5, 0xa4, 0x41, 0xff, 0xe8, 0x68, 0xfe, 0xed, 0xc1, 0x5e, 0x6c, - 0xeb, 0x6e, 0xdb, 0x0f, 0xd8, 0xc6, 0x7c, 0x4d, 0xab, 0xc4, 0xd4, 0xeb, 0x34, 0xfe, 0x2c, 0x03, - 0x63, 0x55, 0x86, 0xd9, 0x6c, 0xa2, 0xcc, 0xf5, 0x59, 0x4a, 0x7c, 0x13, 0xf6, 0xab, 0xcf, 0xc4, - 0xbe, 0x0e, 0x53, 0x31, 0x34, 0x62, 0xc0, 0x70, 0x0d, 0x5d, 0x8d, 0x55, 0x5d, 0x01, 0x77, 0x3e, - 0x36, 0x45, 0x89, 0xb1, 0xa4, 0x90, 0x6d, 0xde, 0xc0, 0x07, 0xbf, 0x05, 0x00, 0x47, 0x82, 0xe4, - 0xcd, 0x86, 0xc4, 0x5b, 0xb2, 0x79, 0xc3, 0x54, 0xb0, 0x8c, 0x55, 0x18, 0xae, 0xb9, 0x5e, 0xb0, - 0x78, 0xc8, 0x2f, 0x13, 0x15, 0xea, 0xd7, 0xd5, 0x17, 0x3d, 0x07, 0xb5, 0xe8, 0x75, 0x53, 0x14, - 0x91, 0x79, 0x18, 0xba, 0xed, 0xd0, 0x66, 0x43, 0x35, 0xdd, 0xdc, 0x61, 0x00, 0x93, 0xc3, 0xd9, - 0x85, 0xeb, 0x74, 0x14, 0xaf, 0x3a, 0xb2, 0x11, 0xfd, 0xa4, 0xdf, 0x4d, 0x59, 0x1b, 0xdf, 0xe7, - 0xf5, 0xbc, 0xb2, 0x5a, 0x4d, 0x7d, 0x86, 0xfa, 0xdf, 0xc9, 0xc0, 0xb9, 0xde, 0x24, 0xaa, 0xd9, - 0x69, 0xa6, 0x8f, 0xd9, 0xe9, 0x8b, 0xf1, 0x17, 0x28, 0x44, 0x13, 0x2f, 0x50, 0xd1, 0xbb, 0x53, - 0x05, 0xad, 0x7e, 0xeb, 0x61, 0xda, 0xef, 0x8b, 0x7d, 0xda, 0x8c, 0x88, 0x7c, 0x9a, 0x03, 0xa4, - 0x31, 0x05, 0xad, 0xf1, 0x9b, 0x79, 0x38, 0xdb, 0x93, 0x82, 0x2c, 0x2b, 0xa1, 0xef, 0x27, 0xc3, - 0xa0, 0xdb, 0x3d, 0xf1, 0xaf, 0xe1, 0xbf, 0x68, 0xd8, 0x15, 0x77, 0x46, 0x59, 0x0b, 0x43, 0x9e, - 0x67, 0x91, 0xd7, 0x2b, 0xc7, 0xf2, 0xe2, 0xe8, 0xc8, 0x0c, 0x92, 0xd1, 0xcf, 0xd1, 0x6d, 0x89, - 0x06, 0xb6, 0xd3, 0xf4, 0xd5, 0xcf, 0xae, 0xc1, 0x41, 0xa6, 0x2c, 0x8b, 0x6c, 0x81, 0xf3, 0xe9, - 0xb6, 0xc0, 0xc6, 0xff, 0x9d, 0x81, 0xd1, 0xb0, 0xd9, 0xe4, 0x1c, 0x9c, 0xde, 0x30, 0x4b, 0xe5, - 0x25, 0x6b, 0xe3, 0xfd, 0xf5, 0x25, 0xeb, 0xc1, 0x6a, 0x6d, 0x7d, 0xa9, 0x5c, 0xbd, 0x5d, 0x5d, - 0xaa, 0x14, 0x9f, 0x21, 0xd3, 0x30, 0xf1, 0x60, 0xf5, 0xde, 0xea, 0xda, 0xd6, 0xaa, 0xb5, 0x64, - 0x9a, 0x6b, 0x66, 0x31, 0x43, 0x26, 0x60, 0xd4, 0x5c, 0x2c, 0x95, 0xad, 0xd5, 0xb5, 0xca, 0x52, - 0x31, 0x4b, 0x8a, 0x30, 0x5e, 0x5e, 0x5b, 0x5d, 0x5d, 0x2a, 0x6f, 0x54, 0x37, 0xab, 0x1b, 0xef, - 0x17, 0x73, 0x84, 0xc0, 0x24, 0x22, 0xac, 0x9b, 0xd5, 0xd5, 0x72, 0x75, 0xbd, 0xb4, 0x52, 0xcc, - 0x33, 0x18, 0xc3, 0x57, 0x60, 0x43, 0x21, 0xa3, 0x7b, 0x0f, 0x16, 0x97, 0x8a, 0xc3, 0x0c, 0x85, - 0xfd, 0xa5, 0xa0, 0x8c, 0xb0, 0xea, 0x11, 0xa5, 0x52, 0xda, 0x28, 0x2d, 0x96, 0x6a, 0x4b, 0xc5, - 0x02, 0x39, 0x03, 0x33, 0x1a, 0xc8, 0x5a, 0x59, 0xbb, 0x53, 0x5d, 0x2d, 0x8e, 0x92, 0x59, 0x28, - 0x86, 0xb0, 0xca, 0xa2, 0xf5, 0xa0, 0xb6, 0x64, 0x16, 0x21, 0x0e, 0x5d, 0x2d, 0xdd, 0x5f, 0x2a, - 0x8e, 0x19, 0x6f, 0x73, 0x37, 0x21, 0x3e, 0xd4, 0xe4, 0x34, 0x90, 0xda, 0x46, 0x69, 0xe3, 0x41, - 0x2d, 0xd6, 0xf9, 0x31, 0x18, 0xa9, 0x3d, 0x28, 0x97, 0x97, 0x6a, 0xb5, 0x62, 0x86, 0x00, 0x0c, - 0xdf, 0x2e, 0x55, 0x57, 0x96, 0x2a, 0xc5, 0xac, 0xf1, 0xd3, 0x19, 0x98, 0x96, 0x12, 0xa0, 0x7c, - 0x4e, 0xf8, 0x84, 0xdf, 0xe2, 0x3b, 0xda, 0xc5, 0x56, 0x7a, 0x71, 0xc4, 0x2a, 0xe9, 0xf3, 0x19, - 0x7a, 0x70, 0x2a, 0x15, 0x99, 0xbc, 0x0f, 0x45, 0xd9, 0x80, 0xfb, 0x76, 0x50, 0xdf, 0x8b, 0xb6, - 0xb1, 0xe7, 0x62, 0x95, 0xc4, 0xd0, 0xb8, 0x82, 0x31, 0xca, 0xac, 0x97, 0x60, 0x63, 0x7c, 0x2f, - 0x03, 0x67, 0x7a, 0x10, 0x93, 0x32, 0x0c, 0x87, 0x91, 0xc0, 0xfb, 0x18, 0x2c, 0xcd, 0x7e, 0xff, - 0x68, 0x5e, 0x20, 0x62, 0x82, 0x31, 0xfc, 0xcb, 0x1c, 0x0e, 0x43, 0x7b, 0x63, 0x7c, 0x6d, 0x3e, - 0x26, 0x67, 0x63, 0xc3, 0x29, 0x6a, 0x2a, 0x6d, 0xd5, 0x16, 0xc7, 0xc4, 0x80, 0xe4, 0xec, 0x03, - 0x1f, 0x03, 0x6c, 0x1b, 0xdf, 0xcd, 0x30, 0x89, 0x2d, 0x8e, 0xc8, 0x04, 0xd9, 0x92, 0xef, 0x77, - 0x5b, 0xd4, 0x74, 0x9b, 0xb4, 0x64, 0xae, 0x8a, 0xb3, 0x00, 0x45, 0x50, 0x1b, 0x0b, 0xf0, 0xae, - 0x60, 0xd9, 0x5e, 0x5b, 0x7b, 0x9c, 0x54, 0x69, 0xc8, 0x1b, 0x00, 0x61, 0xa2, 0x77, 0xe9, 0xe9, - 0xcf, 0x23, 0x5d, 0x08, 0xa8, 0x2e, 0x44, 0x2b, 0xc8, 0xc6, 0x5f, 0xcd, 0xc0, 0xb8, 0xb8, 0x09, - 0x95, 0x9a, 0xd4, 0x0b, 0x3e, 0xd9, 0x9a, 0x79, 0x43, 0x5b, 0x33, 0xa1, 0x7d, 0xbe, 0xc2, 0x9f, - 0x15, 0xa7, 0x2e, 0x97, 0xff, 0x34, 0x03, 0xc5, 0x38, 0x22, 0x79, 0x07, 0x0a, 0x35, 0xfa, 0x90, - 0x7a, 0x4e, 0x70, 0x28, 0x76, 0x3f, 0x99, 0x33, 0x85, 0xe3, 0x88, 0x32, 0xae, 0x70, 0xf5, 0xc5, - 0x2f, 0x33, 0xa4, 0x19, 0x74, 0x13, 0x57, 0x74, 0x19, 0xb9, 0x27, 0xa5, 0xcb, 0x30, 0xfe, 0x87, - 0x2c, 0x9c, 0xb9, 0x43, 0x03, 0xb5, 0x4f, 0xe1, 0x6b, 0xf2, 0xe7, 0x06, 0xeb, 0x97, 0xd2, 0x93, - 0x39, 0x18, 0xc1, 0x22, 0x39, 0xbf, 0xa6, 0xfc, 0x49, 0x16, 0xc3, 0x75, 0x9d, 0xd3, 0x92, 0x32, - 0xf4, 0xa8, 0xfb, 0x9a, 0x12, 0xa6, 0x3d, 0x5c, 0xd6, 0x97, 0x61, 0x12, 0xe3, 0x90, 0x76, 0xd9, - 0xe7, 0x40, 0x1b, 0x42, 0xa7, 0x53, 0x30, 0x63, 0x50, 0xf2, 0x32, 0x14, 0x19, 0xa4, 0x54, 0xdf, - 0x6f, 0xbb, 0x07, 0x4d, 0xda, 0xd8, 0xa5, 0x3c, 0x33, 0x77, 0xc1, 0x4c, 0xc0, 0x25, 0xcf, 0x07, - 0x6d, 0x7e, 0x1f, 0xa3, 0x0d, 0x54, 0xbc, 0x08, 0x9e, 0x11, 0xf4, 0xdc, 0x1b, 0x30, 0xf6, 0x31, - 0x53, 0x2e, 0x18, 0xff, 0x7d, 0x06, 0x66, 0xb1, 0x73, 0x4a, 0xc5, 0xa8, 0x91, 0xff, 0x5c, 0x34, - 0x5a, 0x4a, 0x14, 0x72, 0x9b, 0x81, 0xf4, 0x4f, 0x21, 0x1c, 0xc5, 0x48, 0xd1, 0x93, 0x1d, 0x40, - 0xd1, 0x53, 0x3b, 0x49, 0x22, 0xcf, 0x01, 0xf5, 0x54, 0x3c, 0xfd, 0x7a, 0x34, 0xe5, 0xc6, 0x8f, - 0x66, 0x61, 0xc4, 0xa4, 0x98, 0xe1, 0x90, 0x5c, 0x86, 0x91, 0x55, 0x37, 0xa0, 0xfe, 0x7d, 0x2d, - 0x9d, 0x65, 0x9b, 0x81, 0xac, 0x56, 0xc3, 0x94, 0x85, 0x6c, 0xc1, 0xaf, 0x7b, 0x6e, 0xa3, 0x5b, - 0x0f, 0xd4, 0x05, 0xdf, 0xe1, 0x20, 0x53, 0x96, 0x91, 0x57, 0x61, 0x54, 0x70, 0x0e, 0xdf, 0xf0, - 0xd0, 0xf6, 0xd4, 0xa3, 0x61, 0x86, 0xcc, 0x08, 0x01, 0x05, 0x55, 0x2e, 0x35, 0xe4, 0x15, 0x41, - 0x35, 0x21, 0x08, 0x48, 0xf9, 0x7b, 0xa8, 0x8f, 0xfc, 0xfd, 0x39, 0x18, 0x2e, 0xf9, 0x3e, 0x0d, - 0xa4, 0xe7, 0xf2, 0x78, 0x18, 0x46, 0xc6, 0xa7, 0x01, 0x67, 0x6c, 0x63, 0xb9, 0x29, 0xf0, 0x8c, - 0x3f, 0xcd, 0xc2, 0x10, 0xfe, 0x89, 0xef, 0x96, 0x5e, 0x7d, 0x4f, 0x7b, 0xb7, 0xf4, 0xea, 0x7b, - 0x26, 0x42, 0xc9, 0x0d, 0x54, 0x3f, 0xc8, 0x80, 0xf9, 0xa2, 0xf7, 0xa8, 0x57, 0x6f, 0x44, 0x60, - 0x53, 0xc5, 0x09, 0x1f, 0x74, 0x73, 0xa9, 0xf1, 0x0a, 0x4e, 0x43, 0x76, 0xad, 0x26, 0x7a, 0x8c, - 0x71, 0x55, 0x5c, 0xdf, 0xcc, 0xae, 0xd5, 0x70, 0x34, 0x96, 0x4b, 0x0b, 0xaf, 0xdf, 0x52, 0x33, - 0xaf, 0xfa, 0x7b, 0xf6, 0xc2, 0xeb, 0xb7, 0x4c, 0x51, 0xc2, 0xc6, 0x17, 0xdb, 0x8c, 0x0f, 0x9b, - 0xdc, 0xd3, 0x16, 0xc7, 0x17, 0xfb, 0x86, 0x8f, 0x98, 0x66, 0x84, 0x40, 0x16, 0x60, 0x4c, 0xf8, - 0x77, 0x23, 0xbe, 0xe2, 0x7f, 0x2d, 0xfc, 0xbf, 0x39, 0x85, 0x8a, 0xc4, 0x9f, 0xb8, 0xc4, 0x04, - 0xc9, 0xb4, 0x5e, 0xe2, 0x89, 0x4b, 0x4e, 0xa1, 0x6f, 0x2a, 0x28, 0x91, 0xa3, 0x70, 0xe4, 0x41, - 0xab, 0x3a, 0x0a, 0x63, 0x5c, 0xd9, 0x10, 0xc1, 0xf8, 0xe5, 0x2c, 0x14, 0xd6, 0x9b, 0xdd, 0x5d, - 0xa7, 0xbd, 0x79, 0xe3, 0xcf, 0x35, 0xfb, 0xff, 0x6b, 0x80, 0x87, 0x84, 0xb8, 0x11, 0x48, 0x2d, - 0x35, 0x6f, 0x9a, 0x10, 0x3e, 0x38, 0x09, 0xa2, 0x91, 0x9b, 0x20, 0x16, 0xa6, 0x48, 0x06, 0x79, - 0x4a, 0x27, 0xe0, 0x09, 0x79, 0x24, 0x89, 0x40, 0x25, 0x6f, 0xc1, 0x58, 0x94, 0x86, 0x3d, 0xca, - 0xf1, 0xa8, 0x52, 0x96, 0xa3, 0xf2, 0xcd, 0x1b, 0xa6, 0x8a, 0x6e, 0xfc, 0x47, 0xc3, 0x30, 0xae, - 0xb6, 0x87, 0x98, 0x30, 0xe3, 0x37, 0xd9, 0x85, 0x5c, 0xd8, 0x16, 0x75, 0xb0, 0x50, 0x1c, 0xa7, - 0x17, 0xf5, 0x06, 0x31, 0x3c, 0x6e, 0x68, 0x24, 0x1d, 0xd3, 0x97, 0x9f, 0x31, 0xa7, 0xfd, 0x08, - 0xcc, 0xf1, 0x48, 0x09, 0x0a, 0x6e, 0xc7, 0xdf, 0xa5, 0x6d, 0x47, 0x3e, 0xa2, 0x5c, 0xd2, 0x18, - 0xad, 0x89, 0xc2, 0x04, 0xaf, 0x90, 0x8c, 0xbc, 0x0e, 0xc3, 0x6e, 0x87, 0xb6, 0x6d, 0x47, 0x9c, - 0x71, 0xcf, 0xc6, 0x18, 0xd0, 0x76, 0xa9, 0xaa, 0x10, 0x0a, 0x64, 0x72, 0x1d, 0xf2, 0xee, 0x7e, - 0x38, 0x5f, 0x67, 0x75, 0xa2, 0xfd, 0xc0, 0x56, 0x48, 0x10, 0x91, 0x11, 0x7c, 0x68, 0xb7, 0x76, - 0xc4, 0x8c, 0xe9, 0x04, 0x77, 0xed, 0xd6, 0x8e, 0x4a, 0xc0, 0x10, 0xc9, 0xbb, 0x00, 0x1d, 0x7b, - 0x97, 0x7a, 0x56, 0xa3, 0x1b, 0x1c, 0x8a, 0x79, 0x7b, 0x4e, 0x23, 0x5b, 0x67, 0xc5, 0x95, 0x6e, - 0x70, 0xa8, 0xd0, 0x8e, 0x76, 0x24, 0x90, 0x94, 0x00, 0x5a, 0x76, 0x10, 0x50, 0xaf, 0xe5, 0x0a, - 0xe3, 0xae, 0xb1, 0x30, 0x87, 0x22, 0x67, 0x70, 0x3f, 0x2c, 0x56, 0x38, 0x28, 0x44, 0xd8, 0x68, - 0xc7, 0xb3, 0x45, 0x4a, 0xce, 0x58, 0xa3, 0x1d, 0x4f, 0xeb, 0x25, 0x43, 0x24, 0x5f, 0x84, 0x91, - 0x86, 0xe3, 0xd7, 0x5d, 0xaf, 0x21, 0x22, 0x16, 0x9c, 0xd7, 0x68, 0x2a, 0xbc, 0x4c, 0x21, 0x93, - 0xe8, 0xac, 0xb5, 0x22, 0x28, 0xda, 0xaa, 0x7b, 0x80, 0xba, 0xfb, 0x78, 0x6b, 0x6b, 0x61, 0xb1, - 0xda, 0xda, 0x88, 0x88, 0x4d, 0xe5, 0xae, 0x13, 0x34, 0xed, 0x6d, 0xf1, 0x8e, 0xac, 0x4f, 0xe5, - 0x1d, 0x2c, 0x52, 0xa7, 0x92, 0x23, 0x93, 0x37, 0xa0, 0x40, 0xdb, 0x81, 0x67, 0x5b, 0x4e, 0x43, - 0x38, 0xc5, 0xe9, 0x8d, 0x66, 0x07, 0xb0, 0x5d, 0xad, 0xa8, 0x8d, 0x46, 0xfc, 0x6a, 0x83, 0x8d, - 0x8f, 0x5f, 0x77, 0x5a, 0xc2, 0x97, 0x4d, 0x1f, 0x9f, 0x5a, 0xb9, 0x7a, 0x5f, 0x1d, 0x1f, 0x86, - 0x48, 0x9e, 0x03, 0xd8, 0xa5, 0x6d, 0xca, 0x1d, 0x4b, 0xf9, 0x2b, 0x83, 0xa9, 0x40, 0xbe, 0x94, - 0xff, 0x9f, 0x7e, 0x71, 0x3e, 0xb3, 0x08, 0x50, 0x90, 0x21, 0x1b, 0x8c, 0x15, 0x38, 0xdb, 0xf3, - 0xa3, 0x20, 0x57, 0xa1, 0xb8, 0x63, 0x0b, 0x3d, 0x57, 0x7d, 0xcf, 0x6e, 0xb7, 0x69, 0x53, 0x6c, - 0x47, 0x53, 0x12, 0x5e, 0xe6, 0x60, 0xce, 0xd9, 0x78, 0x17, 0x66, 0xd3, 0x46, 0x83, 0x3c, 0x0f, - 0xe3, 0x6a, 0x74, 0x0a, 0xc1, 0x64, 0xcc, 0xee, 0x38, 0x32, 0x3e, 0x85, 0x60, 0xf0, 0x1b, 0x19, - 0x38, 0xdf, 0xef, 0xdb, 0x22, 0xe7, 0xa0, 0xd0, 0xf1, 0x1c, 0x17, 0x65, 0x38, 0xbe, 0x03, 0x86, - 0xbf, 0xc9, 0x05, 0x00, 0x2e, 0x6c, 0x04, 0xf6, 0xae, 0x30, 0x76, 0x37, 0x47, 0x11, 0xb2, 0x61, - 0xef, 0xfa, 0xe4, 0x15, 0x98, 0x6e, 0xd0, 0x1d, 0xbb, 0xdb, 0x0c, 0x2c, 0xbf, 0xbe, 0x47, 0x1b, - 0xe8, 0x5f, 0x82, 0x46, 0x4c, 0x66, 0x51, 0x14, 0xd4, 0x24, 0x3c, 0xd1, 0xe2, 0xa1, 0x1e, 0x2d, - 0xbe, 0x9b, 0x2f, 0x64, 0x8a, 0x59, 0x13, 0x6d, 0x79, 0x8c, 0x6f, 0x67, 0x61, 0xae, 0xd7, 0x62, - 0x22, 0x6f, 0xa7, 0x8d, 0x01, 0x57, 0xd5, 0xab, 0x70, 0x55, 0x55, 0xaf, 0xd4, 0x46, 0x16, 0x20, - 0xf4, 0x0e, 0x39, 0xce, 0xd3, 0x5b, 0xc2, 0x18, 0x4d, 0xc7, 0xf6, 0xfd, 0x03, 0xf6, 0xbd, 0xe4, - 0x94, 0xe8, 0x73, 0x02, 0xa6, 0xd2, 0x48, 0x18, 0xf9, 0x02, 0x40, 0xbd, 0xe9, 0xfa, 0x14, 0x5f, - 0xc4, 0xc5, 0x41, 0xcc, 0x4d, 0x64, 0x43, 0xa8, 0xfa, 0x04, 0x8a, 0xd0, 0xb2, 0xdb, 0xa0, 0x62, - 0x02, 0x6d, 0x38, 0xd3, 0x63, 0xf7, 0x60, 0xd3, 0x13, 0xe5, 0xaa, 0x94, 0x91, 0xef, 0xbb, 0x61, - 0xc6, 0xca, 0xf8, 0x88, 0x67, 0x7b, 0xad, 0x91, 0x43, 0x20, 0xc9, 0x2d, 0x82, 0x71, 0x17, 0x86, - 0x9e, 0x5d, 0x2f, 0xe4, 0xce, 0x21, 0x0f, 0xbc, 0x26, 0x99, 0x87, 0x31, 0x99, 0xd9, 0x86, 0x09, - 0xba, 0x9c, 0x39, 0x08, 0xd0, 0x3d, 0x8a, 0x8b, 0x07, 0x83, 0x24, 0xa2, 0x0f, 0x90, 0x38, 0x42, - 0x47, 0x11, 0xb2, 0x71, 0xd8, 0x91, 0xbd, 0x3b, 0x2f, 0xd7, 0xb7, 0xbe, 0x71, 0x8b, 0xd2, 0x9f, - 0xcd, 0xc8, 0xe9, 0x4f, 0xee, 0x7c, 0xc7, 0xb5, 0x8f, 0x00, 0x7a, 0x6c, 0x88, 0x86, 0xe1, 0xdf, - 0xec, 0x48, 0x97, 0x5f, 0x9d, 0x38, 0xd2, 0xc5, 0x4f, 0x72, 0x19, 0xa6, 0x3c, 0x6e, 0xd3, 0x17, - 0xb8, 0x62, 0x3c, 0x71, 0xa6, 0xcc, 0x09, 0x0e, 0xde, 0x70, 0x71, 0x4c, 0x45, 0xbb, 0xee, 0x86, - 0x03, 0xa6, 0x1c, 0x04, 0xe4, 0x1a, 0x8c, 0xb2, 0x83, 0x00, 0x83, 0x3f, 0xc4, 0x4c, 0xc5, 0x11, - 0x0f, 0x8f, 0x55, 0xb3, 0xf0, 0xa1, 0xf8, 0x5b, 0xf0, 0xfa, 0x4f, 0x32, 0x92, 0x99, 0x7a, 0x0c, - 0x91, 0x33, 0x30, 0xe2, 0x7a, 0xbb, 0x4a, 0xd7, 0x86, 0x5d, 0x6f, 0x97, 0xf5, 0xeb, 0x0a, 0x14, - 0xb9, 0xe7, 0x02, 0x77, 0x09, 0xf7, 0x0f, 0xdb, 0xfc, 0x9e, 0x5a, 0x30, 0x27, 0x39, 0x1c, 0xd3, - 0x77, 0x1e, 0xb6, 0xeb, 0x0c, 0xd3, 0xf7, 0x5d, 0x4b, 0x8d, 0xf8, 0x22, 0xba, 0x3d, 0xe9, 0xfb, - 0x6e, 0x14, 0xfa, 0xa5, 0x41, 0x16, 0x61, 0x82, 0xf1, 0x09, 0xe3, 0xce, 0x88, 0x53, 0xf2, 0x42, - 0xf2, 0x94, 0x3c, 0x6c, 0xd7, 0x65, 0x13, 0xcd, 0x71, 0x5f, 0xf9, 0x25, 0x7a, 0xf3, 0x73, 0x59, - 0x38, 0x9d, 0x8e, 0x8e, 0xf3, 0xc5, 0x2a, 0x41, 0x07, 0x1e, 0xae, 0xb3, 0x34, 0x47, 0x19, 0x84, - 0xc7, 0x28, 0x48, 0x6b, 0x6d, 0x36, 0xb5, 0xb5, 0x2f, 0xc3, 0x34, 0x32, 0x12, 0x72, 0x49, 0xd3, - 0xf1, 0x03, 0xe1, 0x7a, 0x6f, 0x4e, 0xb1, 0x02, 0xbe, 0xc1, 0xad, 0x30, 0x30, 0x79, 0x11, 0x26, - 0xe5, 0x16, 0xe5, 0x1e, 0xb4, 0x59, 0xc5, 0x7c, 0x7f, 0x9a, 0x10, 0xd0, 0x35, 0x04, 0x92, 0x53, - 0x30, 0x6c, 0x77, 0x3a, 0xac, 0x4a, 0xbe, 0x2d, 0x0d, 0xd9, 0x9d, 0x4e, 0xb5, 0x41, 0x2e, 0xc1, - 0x04, 0xba, 0x2b, 0x59, 0x3b, 0x68, 0x28, 0x22, 0x0c, 0xc4, 0xcc, 0x71, 0x04, 0x72, 0xe3, 0x11, - 0x9f, 0x7d, 0x08, 0x8c, 0x56, 0xa2, 0x8c, 0x20, 0x0a, 0xd8, 0x1d, 0x89, 0x20, 0x46, 0xe6, 0x8b, - 0x30, 0x25, 0x4e, 0x53, 0xb1, 0xc3, 0x23, 0xa5, 0x58, 0x7f, 0x4c, 0xcc, 0x15, 0x21, 0xbf, 0x41, - 0x80, 0xaa, 0x0d, 0x49, 0xf9, 0x07, 0x19, 0x38, 0x95, 0x7a, 0x1c, 0x93, 0x6f, 0x00, 0xf7, 0xde, - 0x08, 0x5c, 0xcb, 0xa3, 0x75, 0xa7, 0xe3, 0xa0, 0x7f, 0x3b, 0x57, 0x42, 0x2d, 0xf4, 0x3b, 0xc8, - 0xd1, 0x13, 0x64, 0xc3, 0x35, 0x43, 0x22, 0x7e, 0x8f, 0x2e, 0x7a, 0x31, 0xf0, 0xb9, 0x0f, 0xe0, - 0x54, 0x2a, 0x6a, 0xca, 0xfd, 0xf6, 0x55, 0x3d, 0x33, 0x9a, 0x7c, 0x55, 0x88, 0x75, 0x5a, 0xb9, - 0xf7, 0x8a, 0xee, 0xfd, 0x56, 0xd8, 0xbd, 0xd8, 0xc1, 0x4d, 0x96, 0xe2, 0xcb, 0x32, 0x4d, 0xf6, - 0x94, 0x44, 0x3d, 0x57, 0x26, 0xf9, 0x00, 0x4e, 0x89, 0xa5, 0xb2, 0xeb, 0xd9, 0x9d, 0xbd, 0x88, - 0x1d, 0x6f, 0xe8, 0x4b, 0x69, 0xec, 0xf8, 0x1a, 0xba, 0xc3, 0xf0, 0x43, 0xae, 0x33, 0x76, 0x12, - 0x28, 0xfa, 0xe0, 0xc9, 0x43, 0x3f, 0xa5, 0x35, 0x29, 0x6b, 0x30, 0x93, 0xb6, 0x06, 0x07, 0xfe, - 0x00, 0x44, 0x9d, 0x3f, 0x9c, 0x81, 0x8b, 0xc7, 0xb5, 0x99, 0x6c, 0xc1, 0x69, 0x7c, 0xf7, 0xf6, - 0xdd, 0xb0, 0xdb, 0x56, 0xdd, 0xae, 0xef, 0x51, 0xb1, 0x4a, 0x8c, 0xd4, 0xce, 0x77, 0x3a, 0xb5, - 0xda, 0x9a, 0xd2, 0xef, 0x4e, 0xa7, 0xe6, 0xbb, 0xf2, 0x77, 0x99, 0x91, 0x8b, 0x36, 0x34, 0xe0, - 0xd9, 0x3e, 0x94, 0xca, 0x67, 0x95, 0x51, 0x3f, 0xab, 0x2b, 0x50, 0xdc, 0xa1, 0x0d, 0x26, 0x42, - 0xd1, 0x06, 0x36, 0xed, 0xe1, 0x02, 0x4f, 0x2f, 0x68, 0x4e, 0x86, 0xf0, 0x9a, 0xef, 0x6e, 0x2e, - 0x88, 0x5a, 0x5a, 0x72, 0x87, 0x54, 0x45, 0x34, 0x72, 0x0d, 0x66, 0x62, 0xbe, 0xfa, 0x91, 0xf3, - 0xa7, 0x39, 0xcd, 0x8a, 0xf4, 0xc8, 0x2e, 0xcf, 0xc3, 0xb8, 0x9c, 0x06, 0x2f, 0x74, 0x21, 0x31, - 0xc7, 0x04, 0x8c, 0xad, 0x72, 0x51, 0xdd, 0xdf, 0xcd, 0x4a, 0x91, 0x69, 0xd1, 0x75, 0x03, 0x3f, - 0xf0, 0xec, 0x8e, 0x76, 0x6f, 0x22, 0x2d, 0x38, 0xeb, 0xda, 0xdd, 0x60, 0x6f, 0xc1, 0x62, 0xff, - 0xba, 0x9e, 0xf4, 0xe7, 0xac, 0x4b, 0x4b, 0xb8, 0xb1, 0x85, 0xeb, 0xfa, 0xd6, 0x59, 0x62, 0xd8, - 0x25, 0x15, 0x99, 0x9d, 0xf0, 0x0a, 0xd7, 0xe5, 0x67, 0xcc, 0x33, 0x9c, 0x67, 0x02, 0x8b, 0x2c, - 0xc3, 0xb8, 0x9a, 0xe7, 0x3f, 0xf5, 0xe2, 0xa4, 0xa4, 0xfb, 0xd7, 0xb9, 0x8e, 0x6d, 0x47, 0x25, - 0xe4, 0x1d, 0x18, 0x75, 0x1a, 0x22, 0x7e, 0x9c, 0xb8, 0x3e, 0xe9, 0x22, 0x7b, 0xb5, 0xc1, 0xc3, - 0xc9, 0x45, 0x3c, 0xd8, 0xdd, 0xcb, 0x11, 0xd0, 0xc5, 0x09, 0xed, 0x86, 0x69, 0x2c, 0xca, 0xd3, - 0x39, 0x49, 0x96, 0xc8, 0xc2, 0x7e, 0x1a, 0x86, 0x7d, 0x25, 0xa0, 0x9d, 0x29, 0x7e, 0x19, 0x7f, - 0x09, 0xae, 0x0c, 0x3a, 0x46, 0xe4, 0x35, 0x20, 0x3d, 0x06, 0x7c, 0xd4, 0x9c, 0xb6, 0x13, 0xe3, - 0xf6, 0x3c, 0xa8, 0x11, 0xb9, 0x1c, 0x39, 0xe1, 0x12, 0xf6, 0xc0, 0x73, 0x8c, 0xff, 0x3c, 0x0b, - 0x93, 0xfa, 0x9d, 0x9a, 0xbc, 0x02, 0xf9, 0x90, 0xed, 0x64, 0xa8, 0xfb, 0x55, 0x91, 0x18, 0x73, - 0x13, 0x91, 0xd8, 0x01, 0x81, 0xef, 0x3f, 0x56, 0x4b, 0x55, 0xcf, 0x9a, 0xe3, 0x08, 0x94, 0x6a, - 0xd9, 0xbb, 0xc0, 0xb3, 0xd9, 0xe2, 0x5e, 0x16, 0x0c, 0x96, 0xbb, 0xbd, 0xc0, 0x6e, 0xf6, 0xa8, - 0x57, 0x1b, 0x67, 0xb4, 0x6c, 0x3f, 0xc1, 0x74, 0xed, 0xd1, 0x95, 0x29, 0xdf, 0xfb, 0xca, 0x24, - 0xba, 0xd2, 0xe3, 0xca, 0x34, 0xd4, 0xe7, 0xca, 0x14, 0x51, 0x86, 0x57, 0xa6, 0x17, 0x44, 0xeb, - 0x3d, 0xfb, 0xc0, 0xc2, 0x6e, 0x71, 0xc3, 0x33, 0xde, 0x2e, 0xd3, 0x3e, 0xc0, 0x87, 0xaf, 0xc5, - 0x51, 0x90, 0xaf, 0x65, 0xc6, 0xdf, 0xc8, 0xc4, 0xee, 0x2c, 0x72, 0x64, 0x5f, 0x84, 0x49, 0xa7, - 0xc5, 0x84, 0x29, 0xda, 0x50, 0x84, 0x80, 0x09, 0x73, 0x42, 0x42, 0xb9, 0x20, 0xf0, 0x12, 0x4c, - 0x85, 0x68, 0xdc, 0x59, 0x98, 0x1b, 0xb4, 0x9b, 0x21, 0xb5, 0x70, 0x16, 0x7e, 0x05, 0xa6, 0x43, - 0x44, 0x21, 0x77, 0x72, 0x39, 0x60, 0xc2, 0x2c, 0xca, 0x02, 0x91, 0x66, 0xd1, 0x37, 0x76, 0xe3, - 0x87, 0xcc, 0xa7, 0xd4, 0x2a, 0xe3, 0x9f, 0x64, 0x61, 0x26, 0x45, 0xd9, 0x42, 0x3e, 0x80, 0x19, - 0xb9, 0x69, 0xf0, 0xc3, 0x88, 0x7f, 0xcc, 0x7c, 0xbb, 0xb8, 0x9a, 0xb6, 0x5d, 0x20, 0x5a, 0xca, - 0x27, 0x3d, 0x2d, 0x36, 0x8a, 0xa8, 0xfc, 0x2f, 0xce, 0x16, 0x41, 0xde, 0x87, 0xd3, 0x22, 0x3b, - 0xb2, 0xb2, 0x53, 0x58, 0x1e, 0xdd, 0x11, 0x0b, 0xf6, 0xf9, 0xc4, 0x07, 0xe5, 0xd4, 0x95, 0xe6, - 0x98, 0x74, 0x67, 0xf9, 0x19, 0x73, 0xd6, 0x4f, 0x81, 0xc7, 0x77, 0x9f, 0x7f, 0x3b, 0x03, 0xc6, - 0xf1, 0xe3, 0x85, 0xb7, 0xa0, 0xf8, 0x80, 0xb3, 0x5b, 0x90, 0x32, 0x7a, 0x97, 0x60, 0xc2, 0xa3, - 0x3b, 0x1e, 0xf5, 0xf7, 0x94, 0xe1, 0x1b, 0x35, 0xc7, 0x05, 0x50, 0x0e, 0x8c, 0x0c, 0x53, 0x70, - 0xa2, 0xcf, 0x57, 0x12, 0x19, 0xb7, 0xc3, 0x43, 0x25, 0x75, 0x1e, 0xc8, 0x2c, 0x0c, 0xa9, 0x0d, - 0xe4, 0x3f, 0xee, 0xe6, 0x0b, 0xd9, 0x62, 0xce, 0x14, 0xc1, 0x14, 0x76, 0x9c, 0x26, 0x35, 0x7e, - 0x3d, 0x03, 0xe7, 0x7a, 0x0f, 0x1e, 0xf9, 0x40, 0x79, 0x1e, 0xcc, 0xf1, 0x58, 0x72, 0xc7, 0x8c, - 0xb7, 0xfa, 0x92, 0x22, 0xfc, 0xfb, 0xe3, 0x89, 0x81, 0x05, 0xcb, 0x4f, 0xf2, 0xc6, 0xf1, 0x86, - 0xd4, 0x2e, 0x32, 0xb9, 0x7c, 0xf3, 0x06, 0xb9, 0x0a, 0x23, 0x5c, 0xa1, 0x28, 0x1b, 0x3a, 0xa5, - 0x35, 0x74, 0xf3, 0x86, 0x29, 0xcb, 0x8d, 0xef, 0x65, 0x42, 0x95, 0x4a, 0xbc, 0xf9, 0x9b, 0x37, - 0xc8, 0x17, 0x06, 0x7b, 0xe8, 0x2b, 0xc8, 0x87, 0xbe, 0xf0, 0x91, 0xef, 0x8b, 0xda, 0x23, 0xdf, - 0x0b, 0xfd, 0xc7, 0x49, 0x5c, 0xde, 0xe2, 0xa9, 0x1b, 0xff, 0x59, 0x06, 0x2e, 0xf4, 0xa5, 0x20, - 0xe7, 0xa1, 0x50, 0x5a, 0xaf, 0x6e, 0x44, 0x33, 0xcb, 0xbe, 0x16, 0x09, 0x21, 0x77, 0x60, 0x74, - 0xd1, 0xf6, 0x9d, 0x3a, 0x5b, 0xc0, 0xa9, 0xe2, 0x68, 0x82, 0x6d, 0x88, 0xbe, 0xfc, 0x8c, 0x19, - 0xd1, 0x12, 0x0b, 0xa6, 0xf1, 0x2b, 0x48, 0xa4, 0x46, 0x8b, 0x8b, 0x22, 0x09, 0x86, 0x09, 0x32, - 0xb6, 0xc3, 0x24, 0x80, 0xf1, 0x8f, 0xef, 0xa1, 0x94, 0x3d, 0x7b, 0x37, 0xf0, 0x04, 0x21, 0x39, - 0xae, 0x40, 0x61, 0x5d, 0xaa, 0x55, 0x94, 0xcc, 0xa8, 0x52, 0x85, 0x62, 0x86, 0xa5, 0xc6, 0x5f, - 0xcf, 0x48, 0x79, 0xe1, 0xf8, 0x8e, 0x28, 0x51, 0x77, 0x1b, 0xfd, 0xa3, 0xee, 0x36, 0x3e, 0x66, - 0xd4, 0x5d, 0xe3, 0x97, 0x45, 0xc0, 0xac, 0x6a, 0x63, 0x3d, 0x96, 0x08, 0xe2, 0x93, 0x9a, 0x2d, - 0x2c, 0x69, 0xab, 0xf3, 0x92, 0x12, 0x09, 0x3c, 0x59, 0x57, 0x6f, 0xeb, 0x05, 0x65, 0xa9, 0xfe, - 0x93, 0x2c, 0x9c, 0xef, 0x47, 0x9e, 0x9a, 0xb3, 0x22, 0x73, 0xb2, 0x9c, 0x15, 0x57, 0xa1, 0xc0, - 0x61, 0x7a, 0x1a, 0x3f, 0x41, 0xca, 0x06, 0x5c, 0x16, 0x93, 0x4b, 0x30, 0x5c, 0x2a, 0xd7, 0xa2, - 0x50, 0xc5, 0xf8, 0xce, 0x66, 0xd7, 0x7d, 0x7c, 0xc1, 0x11, 0x45, 0xe4, 0xeb, 0xc9, 0xe8, 0xdc, - 0x22, 0x46, 0xf1, 0xb3, 0xca, 0x80, 0x24, 0x62, 0xd9, 0x61, 0x7b, 0xa3, 0xd8, 0x6b, 0x22, 0x9c, - 0x91, 0x99, 0x8c, 0xf4, 0x6d, 0xc0, 0xf0, 0xba, 0x47, 0x7d, 0x1a, 0xa8, 0x6f, 0x60, 0x1d, 0x84, - 0x98, 0xa2, 0x44, 0xbc, 0x50, 0xd9, 0x87, 0xdc, 0xcb, 0x60, 0x58, 0x75, 0xc2, 0xc2, 0x27, 0x2d, - 0x06, 0x36, 0x15, 0x14, 0xe3, 0x3b, 0x19, 0x98, 0x4d, 0x6b, 0x16, 0x39, 0x0f, 0xf9, 0x76, 0x6a, - 0x5c, 0xf1, 0x36, 0xb7, 0x75, 0x1e, 0xc3, 0x14, 0x6a, 0x3b, 0xae, 0xd7, 0xb2, 0x03, 0xf5, 0xe1, - 0x4f, 0x01, 0x9b, 0xc0, 0x7e, 0xdc, 0xc6, 0xbf, 0xc9, 0xbc, 0xdc, 0x6c, 0x73, 0x89, 0x48, 0xe4, - 0xf8, 0x9f, 0x51, 0x02, 0xa8, 0x36, 0xd6, 0xd7, 0x3a, 0x3c, 0x34, 0xda, 0x4d, 0xc8, 0xb3, 0x66, - 0xc5, 0x16, 0x23, 0x5b, 0x0e, 0xa5, 0xfb, 0x2b, 0x02, 0x89, 0xb7, 0x8a, 0xdd, 0x9d, 0x4c, 0x44, - 0x36, 0xb6, 0x60, 0x52, 0xc7, 0x20, 0x4b, 0x7a, 0x30, 0x8d, 0x28, 0xbb, 0xfb, 0xa2, 0xeb, 0x72, - 0xe3, 0x93, 0xc5, 0xb3, 0xdf, 0x3f, 0x9a, 0x07, 0xf6, 0x93, 0xd3, 0xa4, 0x05, 0xdb, 0x30, 0x7e, - 0x2a, 0x0b, 0xb3, 0x91, 0x11, 0xbb, 0xfc, 0x24, 0x9e, 0x5a, 0x8b, 0xca, 0x92, 0x66, 0xf1, 0x37, - 0x9f, 0x48, 0xa0, 0x2c, 0x3b, 0xd8, 0xc7, 0xd0, 0xe8, 0x0e, 0xcc, 0xf5, 0xc2, 0x27, 0xaf, 0x24, - 0x52, 0x9c, 0x0a, 0x67, 0xcb, 0x30, 0x17, 0xaa, 0x92, 0xf1, 0xf4, 0x1f, 0x65, 0xe0, 0x9c, 0x30, - 0x99, 0xb8, 0x6f, 0x3b, 0x6d, 0x4c, 0xeb, 0x5e, 0xa7, 0x4f, 0xc6, 0x22, 0xf8, 0x8e, 0xb6, 0x2d, - 0xbd, 0xa8, 0x5b, 0xc6, 0x24, 0x6a, 0xeb, 0xdd, 0x5b, 0x72, 0x15, 0xdd, 0x6a, 0xeb, 0x7c, 0xf1, - 0xe6, 0xb9, 0x07, 0x46, 0x9b, 0x01, 0x54, 0x0f, 0x0c, 0xc4, 0x30, 0x7e, 0x08, 0x9e, 0xeb, 0x5f, - 0x01, 0xf9, 0x1a, 0x4c, 0x60, 0x38, 0xff, 0x07, 0x9d, 0x5d, 0xcf, 0x6e, 0x50, 0xa9, 0x28, 0x92, - 0xef, 0x3b, 0x6a, 0x19, 0x77, 0x25, 0x16, 0x1e, 0x01, 0xbb, 0x98, 0x28, 0x40, 0x10, 0x69, 0x76, - 0x49, 0x2a, 0x37, 0xe3, 0xdb, 0x19, 0x20, 0x49, 0x1e, 0xe4, 0x16, 0x8c, 0x3f, 0xd8, 0x28, 0xd7, - 0x02, 0xdb, 0x0b, 0x96, 0xdd, 0xae, 0x27, 0x5c, 0x74, 0xb9, 0x81, 0x78, 0x50, 0x67, 0x3b, 0x83, - 0x17, 0x58, 0x7b, 0x6e, 0xd7, 0x33, 0x35, 0x3c, 0x8c, 0x77, 0x4b, 0xe9, 0x7e, 0xc3, 0x3e, 0xd4, - 0xe3, 0xdd, 0x0a, 0x98, 0x16, 0xef, 0x56, 0xc0, 0x8c, 0xbf, 0x9d, 0x81, 0x67, 0xe5, 0x5b, 0x4a, - 0x23, 0xa5, 0x2d, 0x65, 0x74, 0x83, 0xf2, 0x64, 0x88, 0x92, 0x7e, 0xb2, 0xe9, 0xb4, 0xf4, 0x14, - 0xc4, 0x06, 0xa2, 0x90, 0xca, 0x69, 0xc9, 0x7b, 0x90, 0xaf, 0x05, 0x6e, 0x67, 0x00, 0x57, 0xc1, - 0x62, 0x38, 0xa3, 0x81, 0xdb, 0x41, 0x16, 0x48, 0x69, 0x50, 0x98, 0x55, 0x1b, 0x27, 0x5b, 0x4c, - 0xee, 0xc3, 0x88, 0xf0, 0xe1, 0x8e, 0xe9, 0x9d, 0xfa, 0xf4, 0x69, 0x71, 0x4a, 0xfa, 0x23, 0x8a, - 0x10, 0x19, 0xa6, 0xe4, 0x61, 0xfc, 0x64, 0x06, 0xc6, 0x98, 0xf0, 0x80, 0x57, 0xae, 0x4f, 0xba, - 0xa4, 0x75, 0x39, 0x50, 0xaa, 0x2d, 0x43, 0xf6, 0x03, 0x1d, 0xae, 0xaf, 0xc3, 0x54, 0x8c, 0x80, - 0x18, 0xe8, 0x89, 0xd2, 0x74, 0xea, 0x36, 0x0f, 0x9f, 0xc9, 0x75, 0x7e, 0x1a, 0xcc, 0xf8, 0x97, - 0x32, 0x30, 0xbb, 0xb6, 0x1f, 0xd8, 0x55, 0xbc, 0x42, 0x9a, 0xdd, 0xa6, 0xfc, 0xde, 0x99, 0x40, - 0x24, 0x1f, 0xe5, 0xb8, 0x95, 0x3c, 0x17, 0x88, 0x04, 0xcc, 0x0c, 0x4b, 0xc9, 0x32, 0x14, 0xc4, - 0xf9, 0xe2, 0x8b, 0xc8, 0x16, 0xf2, 0xcd, 0x59, 0x67, 0x2c, 0x90, 0x58, 0x4f, 0x70, 0x0b, 0x13, - 0x34, 0x66, 0x48, 0x6d, 0xfc, 0x69, 0x06, 0xce, 0xf4, 0xa0, 0x21, 0x6f, 0xc3, 0x10, 0x1a, 0xfb, - 0x89, 0xd9, 0x3b, 0xdf, 0xa3, 0x8a, 0xa0, 0xbe, 0xb7, 0x79, 0x83, 0x1f, 0x44, 0x2d, 0xf6, 0xc3, - 0xe4, 0x54, 0xe4, 0x03, 0x18, 0x2d, 0x35, 0x1a, 0xe2, 0x5e, 0x92, 0xd5, 0xee, 0x25, 0x3d, 0x6a, - 0xbc, 0x16, 0xe2, 0xf3, 0x7b, 0x09, 0x37, 0x3b, 0x69, 0x34, 0x2c, 0x61, 0xc8, 0x18, 0xf1, 0x3b, - 0xf7, 0x16, 0x4c, 0xea, 0xc8, 0x27, 0xba, 0x97, 0x7c, 0x2f, 0x03, 0x45, 0xbd, 0x0d, 0x9f, 0x8e, - 0x27, 0x65, 0xda, 0x34, 0x1f, 0xb3, 0xa8, 0x7e, 0x26, 0x0b, 0xa7, 0x52, 0x47, 0x98, 0xbc, 0x06, - 0xc3, 0xa5, 0x4e, 0xa7, 0x5a, 0x11, 0xab, 0x4a, 0x08, 0x3c, 0xa8, 0x69, 0xd5, 0xae, 0x6d, 0x1c, - 0x89, 0xdc, 0x84, 0x02, 0xae, 0x4c, 0x46, 0x90, 0x8d, 0x62, 0x4c, 0xf0, 0xa7, 0x8d, 0x58, 0x8c, - 0x09, 0x89, 0x48, 0x6e, 0xc3, 0xa4, 0x70, 0xaa, 0x32, 0xe9, 0x2e, 0x7d, 0x14, 0x06, 0x3b, 0xc3, - 0x78, 0x6c, 0xd2, 0x05, 0xcb, 0xf2, 0x78, 0x99, 0xea, 0x56, 0xa4, 0x53, 0x61, 0xca, 0x5d, 0xc6, - 0x53, 0xe5, 0xc4, 0x03, 0x5d, 0xf0, 0x94, 0xbb, 0xd8, 0x88, 0x1e, 0xbc, 0x12, 0x94, 0xe1, 0x74, - 0x95, 0x7c, 0xdf, 0xd9, 0x6d, 0xb7, 0x68, 0x3b, 0xf8, 0xf4, 0xa6, 0x2b, 0xaa, 0x63, 0xa0, 0xe9, - 0xfa, 0x6e, 0x9e, 0x7f, 0xcc, 0x71, 0xb2, 0x63, 0xb2, 0xca, 0x57, 0x60, 0x84, 0xbb, 0x73, 0xc9, - 0x2f, 0xe3, 0x42, 0x6a, 0x13, 0x38, 0xce, 0xe6, 0x0d, 0x2e, 0xbe, 0x70, 0xab, 0x43, 0xdf, 0x94, - 0xa4, 0x64, 0x13, 0xc6, 0xca, 0x4d, 0x6a, 0xb7, 0xbb, 0x9d, 0x8d, 0xc1, 0x14, 0x8c, 0x73, 0xa2, - 0x2f, 0xe3, 0x75, 0x4e, 0x86, 0x8a, 0x49, 0xdc, 0xc9, 0x55, 0x46, 0x64, 0x23, 0x34, 0x44, 0xca, - 0xa3, 0x3e, 0xf4, 0x73, 0x7d, 0xc6, 0x27, 0x0e, 0x44, 0x3a, 0xdd, 0xca, 0x4e, 0x58, 0x2a, 0x59, - 0x30, 0xb9, 0x62, 0xfb, 0xc1, 0x86, 0x67, 0xb7, 0x7d, 0x8c, 0xc8, 0x30, 0x80, 0x9b, 0xac, 0x4c, - 0x47, 0x37, 0x85, 0xda, 0xc8, 0x20, 0x24, 0xc5, 0x36, 0xc7, 0xd8, 0x31, 0x79, 0xe9, 0xb6, 0xd3, - 0xb6, 0x9b, 0xce, 0xb7, 0xa4, 0xbd, 0x26, 0x97, 0x97, 0x76, 0x24, 0xd0, 0x8c, 0xca, 0x8d, 0xaf, - 0x26, 0xe6, 0x8d, 0xb7, 0x72, 0xec, 0xff, 0xa5, 0xee, 0x7a, 0x7e, 0xdc, 0x36, 0xae, 0xff, 0x92, - 0xd2, 0xae, 0x77, 0x9f, 0xf6, 0x07, 0x77, 0xe2, 0xac, 0xf7, 0xbb, 0xb6, 0xd7, 0xfe, 0xaa, 0xae, - 0x53, 0x33, 0x8d, 0xd3, 0xc4, 0x4d, 0x13, 0xbb, 0x48, 0x5d, 0xae, 0x34, 0x5a, 0xd1, 0x2b, 0x91, - 0x34, 0x49, 0x79, 0x63, 0xf7, 0x07, 0x21, 0xef, 0xd2, 0x6b, 0xb5, 0x32, 0xa5, 0xe8, 0x87, 0x5d, - 0xe7, 0xd6, 0x4b, 0x2e, 0x45, 0x80, 0x22, 0xd7, 0x16, 0x28, 0x0a, 0xe4, 0xbf, 0xe8, 0x3f, 0x10, - 0x20, 0x28, 0x90, 0x43, 0x6f, 0x05, 0x82, 0xd6, 0x40, 0x2f, 0xbd, 0xf7, 0x92, 0x53, 0x31, 0xbf, - 0xc8, 0x21, 0x29, 0x29, 0xbb, 0xb6, 0xd1, 0xa2, 0x37, 0xf1, 0xcd, 0x9b, 0xd1, 0x90, 0x33, 0xf3, - 0x66, 0xde, 0xbc, 0xf7, 0x3e, 0x0f, 0x4e, 0x71, 0x17, 0x7d, 0xe6, 0xb2, 0xee, 0x60, 0xab, 0x6a, - 0x5a, 0xbb, 0x9a, 0x82, 0x56, 0x01, 0x1c, 0xd7, 0xae, 0x60, 0xcf, 0x23, 0xcf, 0x2a, 0x79, 0xe6, - 0xfe, 0xec, 0xb5, 0x56, 0x43, 0x2b, 0x48, 0x2e, 0xed, 0xc5, 0xf2, 0x17, 0x0a, 0x6c, 0x4c, 0x1e, - 0x4a, 0xe4, 0x03, 0x0d, 0x6a, 0xe0, 0x57, 0xcd, 0x3f, 0x98, 0x39, 0xee, 0x13, 0xc9, 0xd9, 0xe0, - 0x88, 0x11, 0x73, 0xba, 0x57, 0x85, 0xe5, 0x28, 0x49, 0xa4, 0xd6, 0x39, 0x2c, 0x57, 0x60, 0x73, - 0x5a, 0x1b, 0xe9, 0x57, 0x5d, 0x83, 0x92, 0xe1, 0x38, 0x0d, 0xb3, 0x62, 0xf8, 0xa6, 0x6d, 0x69, - 0x0a, 0x5a, 0x82, 0xf9, 0x5d, 0xd7, 0x6e, 0x39, 0x9a, 0x5a, 0xfe, 0x54, 0x81, 0x15, 0x33, 0x1a, - 0x85, 0x47, 0xcc, 0xff, 0xe5, 0x45, 0x17, 0xdf, 0x8d, 0xd4, 0xe2, 0xdb, 0x8c, 0xc3, 0x7f, 0xe2, - 0x3f, 0x38, 0xd6, 0xca, 0xfb, 0x8b, 0x02, 0xeb, 0xb9, 0x3a, 0xc8, 0x83, 0x53, 0xc6, 0xbe, 0x67, - 0x9b, 0xd5, 0x0a, 0xef, 0x99, 0x38, 0x95, 0x73, 0x6a, 0xfe, 0x5f, 0x98, 0x77, 0xed, 0x93, 0x61, - 0xd0, 0xeb, 0x1c, 0x4a, 0xe9, 0x1b, 0xea, 0x73, 0xae, 0x68, 0x89, 0xee, 0x64, 0x1f, 0x8d, 0x07, - 0x21, 0x6d, 0x56, 0x4d, 0xdd, 0x68, 0xc6, 0xf4, 0x7c, 0xc3, 0x2c, 0xdf, 0x3c, 0x29, 0xcf, 0x37, - 0x9d, 0xb4, 0xb7, 0xb3, 0x02, 0x25, 0xae, 0xb5, 0x50, 0x85, 0xe0, 0x13, 0x05, 0x36, 0xa7, 0xf5, - 0x95, 0x28, 0x42, 0x69, 0x57, 0xfb, 0x8d, 0x18, 0xcb, 0x2f, 0xed, 0x63, 0x2f, 0xd8, 0xd0, 0x4d, - 0x28, 0xb1, 0xec, 0x94, 0xde, 0xb5, 0x96, 0x6b, 0xf2, 0x09, 0x72, 0xfe, 0x9f, 0x5f, 0x5d, 0x38, - 0xc3, 0x73, 0xf2, 0x0f, 0xaf, 0xa5, 0x13, 0xb4, 0x6f, 0x2a, 0xae, 0x5c, 0xa3, 0xfc, 0xb1, 0x02, - 0x5b, 0xd3, 0x5f, 0x92, 0xec, 0x32, 0x3e, 0x39, 0x9b, 0x27, 0xde, 0xca, 0x74, 0x97, 0xa1, 0xe7, - 0xf5, 0x8c, 0xbb, 0x72, 0xcc, 0x48, 0x2a, 0x65, 0x12, 0xff, 0xcb, 0xf9, 0x50, 0xd2, 0x95, 0x04, - 0x63, 0xf9, 0x77, 0x2a, 0x6c, 0x90, 0x09, 0xd4, 0x0d, 0x87, 0x43, 0x63, 0x3c, 0x7a, 0x18, 0x46, - 0x23, 0x7e, 0xa4, 0x42, 0xef, 0xc2, 0xc2, 0xc3, 0x93, 0xdd, 0x06, 0x32, 0x76, 0x84, 0x80, 0x0a, - 0x65, 0xe1, 0x2e, 0x42, 0x7e, 0xa3, 0xf3, 0x20, 0xe5, 0x9f, 0xa1, 0x32, 0x75, 0xd9, 0x5d, 0xea, - 0xc7, 0x59, 0x68, 0xde, 0x83, 0x79, 0xaa, 0xfd, 0x73, 0xd1, 0x28, 0x8e, 0xb4, 0x93, 0x7b, 0x46, - 0xef, 0x06, 0x5c, 0x56, 0x01, 0xbd, 0x09, 0x90, 0x60, 0xc6, 0x71, 0xd9, 0x27, 0xd4, 0xe8, 0x18, - 0x36, 0xce, 0x5d, 0x7a, 0xf4, 0xa0, 0xcd, 0x81, 0xd8, 0x74, 0x58, 0x17, 0x9f, 0xa4, 0x2f, 0xa2, - 0xe2, 0xb9, 0x1d, 0x66, 0x8d, 0x15, 0x98, 0x7d, 0x1e, 0x19, 0x5f, 0xfe, 0x87, 0x0a, 0x4b, 0xfb, - 0xe4, 0xa0, 0x40, 0xd5, 0xdf, 0xd9, 0xea, 0xf4, 0xdb, 0x50, 0x6a, 0xf4, 0xda, 0xfc, 0xee, 0x7e, - 0xc8, 0x81, 0x39, 0xa8, 0xcb, 0x6e, 0xb7, 0xd7, 0x16, 0x66, 0x80, 0xa1, 0x2b, 0x33, 0x7d, 0x83, - 0xbb, 0xf1, 0x2d, 0x58, 0x60, 0x7e, 0x0f, 0xfc, 0xa2, 0x46, 0x1c, 0x15, 0xe3, 0x1e, 0x5d, 0x65, - 0xc5, 0xd2, 0x75, 0x33, 0xf3, 0x9c, 0x90, 0xcf, 0x2d, 0x1c, 0x97, 0x43, 0x52, 0xf6, 0xe7, 0x8f, - 0xa7, 0xec, 0x4b, 0xf1, 0xc7, 0x0b, 0xc7, 0x89, 0x3f, 0xde, 0xba, 0x0e, 0x25, 0xa9, 0x3f, 0x27, - 0x3a, 0x39, 0xfe, 0x5a, 0x85, 0x15, 0xfa, 0x56, 0xb1, 0x29, 0xe9, 0x7f, 0xf3, 0xea, 0xe2, 0x46, - 0xea, 0xea, 0x62, 0x53, 0x1e, 0x2f, 0xf6, 0x66, 0x33, 0xee, 0x2c, 0x6e, 0xc1, 0x7a, 0x8e, 0x11, - 0xbd, 0x03, 0xf3, 0xa4, 0xfb, 0x42, 0xd5, 0xd3, 0xb2, 0x33, 0x20, 0xc1, 0xaa, 0x21, 0x2f, 0x3e, - 0x74, 0x19, 0x77, 0xf9, 0x5f, 0x0a, 0x2c, 0x73, 0x10, 0xc1, 0xe8, 0x41, 0xef, 0x1b, 0x3f, 0xe7, - 0xe5, 0xec, 0xe7, 0x64, 0xc1, 0x33, 0xfc, 0x73, 0xfe, 0xa7, 0x3f, 0xe2, 0xf5, 0xd4, 0x47, 0x3c, - 0x13, 0x47, 0xae, 0x8b, 0xd7, 0x99, 0xf1, 0x0d, 0xff, 0x44, 0xb1, 0x5c, 0xd2, 0x8c, 0xe8, 0xe7, - 0xb0, 0x64, 0x85, 0x4f, 0x52, 0x1a, 0xd3, 0xe5, 0x29, 0x8d, 0x5e, 0x8d, 0x19, 0xd9, 0x9a, 0xa2, - 0x9b, 0x4d, 0x14, 0x3e, 0x09, 0x72, 0x66, 0x9c, 0xa4, 0x49, 0xa2, 0x34, 0xa5, 0xab, 0x9d, 0x64, - 0xea, 0x73, 0x17, 0x4d, 0x1a, 0x0f, 0xf6, 0xc7, 0x22, 0x40, 0xe2, 0xdd, 0x46, 0x16, 0x60, 0x98, - 0x82, 0xda, 0xe5, 0x77, 0xc7, 0x94, 0x24, 0xcf, 0x71, 0x4e, 0x42, 0x97, 0xf9, 0xa5, 0xa8, 0x3a, - 0x1d, 0x59, 0x80, 0x5e, 0x8f, 0x56, 0xb8, 0xf7, 0xd8, 0x61, 0xd8, 0x6d, 0x33, 0x59, 0x5c, 0xd8, - 0xb9, 0x44, 0x81, 0x64, 0x62, 0xea, 0x94, 0x6c, 0x30, 0xd4, 0xc7, 0xac, 0x4a, 0x18, 0x72, 0x1e, - 0xa3, 0xc5, 0xe7, 0xf7, 0x18, 0x9d, 0x7f, 0x0e, 0x8f, 0xd1, 0x85, 0x63, 0x7a, 0x8c, 0x3a, 0xb0, - 0xd4, 0x89, 0x1e, 0x87, 0xd1, 0xa8, 0x37, 0x78, 0x4a, 0xfd, 0xc9, 0x92, 0xab, 0x2c, 0xf2, 0xa9, - 0x4d, 0x51, 0xc6, 0xc6, 0x9b, 0x6e, 0x98, 0x31, 0xbf, 0x3c, 0xdc, 0x31, 0x11, 0x7d, 0x1f, 0x12, - 0xab, 0x07, 0x47, 0xfe, 0x9c, 0xbe, 0xcf, 0x1e, 0x08, 0xa3, 0xc8, 0x8f, 0x21, 0x6d, 0xfc, 0xe0, - 0xf1, 0x16, 0x2c, 0xdd, 0x98, 0x5c, 0x20, 0x83, 0x69, 0x1c, 0x48, 0xf6, 0x11, 0xee, 0x50, 0xf3, - 0xb5, 0x0a, 0x28, 0xdf, 0x71, 0x74, 0x03, 0x4a, 0x4c, 0xf4, 0x07, 0x83, 0xe1, 0x87, 0xdc, 0xcd, - 0x91, 0xc5, 0xfb, 0x49, 0x64, 0x39, 0xde, 0x8f, 0x91, 0xdd, 0xe1, 0x87, 0x5d, 0xf4, 0x33, 0x78, - 0x85, 0x0e, 0x7c, 0x3f, 0x1c, 0x74, 0x7a, 0x87, 0x01, 0x45, 0x5c, 0x69, 0x77, 0x39, 0xa6, 0xfc, - 0x1b, 0x34, 0xf9, 0x49, 0xbe, 0x78, 0xca, 0x04, 0xa1, 0xde, 0x84, 0x0e, 0xe5, 0x74, 0x18, 0x23, - 0xf2, 0x41, 0x93, 0xeb, 0x3f, 0x18, 0x77, 0xbb, 0x7c, 0xce, 0xe9, 0x34, 0x5f, 0x75, 0xa6, 0x6c, - 0x4a, 0xc3, 0xab, 0x49, 0xc3, 0xb5, 0x71, 0xb7, 0x8b, 0xde, 0x05, 0xe8, 0x45, 0xc1, 0xa3, 0xce, - 0x70, 0xc8, 0x0c, 0x19, 0xb1, 0x27, 0x70, 0x42, 0x95, 0x87, 0xaf, 0x17, 0x35, 0x19, 0x91, 0x0c, - 0x5f, 0xbf, 0x7d, 0x14, 0xd2, 0xf8, 0x19, 0x3a, 0xf3, 0xe6, 0x39, 0x4a, 0xa4, 0x20, 0xa6, 0xa7, - 0xd1, 0x51, 0xe8, 0x75, 0x3e, 0x12, 0xde, 0x4c, 0xf7, 0x60, 0x9d, 0x3b, 0xa2, 0xec, 0x77, 0x46, - 0x0f, 0xf9, 0xb9, 0xfb, 0x45, 0x0e, 0xed, 0xd2, 0xc1, 0xfb, 0xaf, 0x45, 0x00, 0x63, 0xdf, 0x13, - 0xa1, 0xa9, 0x57, 0x60, 0x9e, 0x68, 0x13, 0xe2, 0x56, 0x82, 0xde, 0xe9, 0xd2, 0x76, 0xe5, 0x3b, - 0x5d, 0xca, 0x41, 0xe4, 0x84, 0x1b, 0x1e, 0xd1, 0x8b, 0x31, 0x35, 0xb9, 0xc2, 0x18, 0x30, 0x52, - 0xea, 0xf4, 0xca, 0x48, 0xa8, 0x01, 0x90, 0x04, 0x8b, 0x72, 0xfd, 0x76, 0x3d, 0x89, 0xba, 0xe2, - 0x05, 0x1c, 0xfe, 0x2f, 0x09, 0x38, 0x95, 0xa7, 0x4f, 0xc2, 0x86, 0xf6, 0xa0, 0xe8, 0xb7, 0x63, - 0x3f, 0xd7, 0x29, 0x21, 0xb4, 0x17, 0x39, 0xe6, 0x7f, 0x12, 0x46, 0xbb, 0x3a, 0x6a, 0xa7, 0x52, - 0xa3, 0xd0, 0x46, 0x10, 0x86, 0x05, 0x9e, 0xcf, 0x69, 0x0a, 0x9e, 0x02, 0x4f, 0xe7, 0xc4, 0x51, - 0x94, 0x28, 0x51, 0x3e, 0xed, 0xf0, 0xcc, 0x4d, 0x6f, 0x43, 0xc1, 0xf3, 0x9a, 0x3c, 0x70, 0x64, - 0x25, 0xd1, 0x55, 0x3c, 0xaf, 0x29, 0x72, 0xd6, 0x3d, 0x92, 0xaa, 0x11, 0x66, 0xf4, 0x43, 0x28, - 0x49, 0x07, 0x71, 0x1e, 0x72, 0x45, 0xbf, 0x41, 0x27, 0x21, 0xcb, 0xe2, 0x4c, 0xe2, 0x46, 0x0d, - 0xd0, 0xf6, 0xc6, 0xf7, 0x43, 0xa3, 0xdf, 0xa7, 0x3e, 0x9a, 0x8f, 0xc3, 0x01, 0x83, 0x26, 0x5c, - 0x4c, 0x00, 0x88, 0x82, 0x76, 0xbf, 0x1f, 0x1c, 0x8a, 0x52, 0xf9, 0x66, 0x26, 0x5b, 0x13, 0x39, - 0xb0, 0xee, 0x85, 0xa3, 0x71, 0x9f, 0xb9, 0x61, 0xd4, 0x7a, 0x03, 0xa2, 0x9a, 0x30, 0x81, 0x41, - 0xb1, 0x5a, 0x86, 0xa4, 0x50, 0xf8, 0xbe, 0x3c, 0xe8, 0x0d, 0x32, 0x6a, 0x4a, 0xbe, 0x72, 0x39, - 0x94, 0x87, 0x9c, 0xec, 0xf7, 0x69, 0x85, 0x87, 0xee, 0xf7, 0x42, 0xe1, 0x49, 0xd4, 0x9c, 0x37, - 0x27, 0x04, 0x11, 0x53, 0x33, 0x9a, 0x14, 0x44, 0x9c, 0x0a, 0x1d, 0xfe, 0xac, 0x28, 0x81, 0x53, - 0xf0, 0xb1, 0x78, 0x1f, 0xe0, 0x56, 0xaf, 0x13, 0x35, 0xc3, 0xd1, 0xc3, 0xde, 0xa1, 0x14, 0xcb, - 0x5c, 0xfa, 0x45, 0xaf, 0x13, 0x05, 0x8f, 0x28, 0xf9, 0xeb, 0xaf, 0x2e, 0x48, 0x4c, 0xae, 0xf4, - 0x1b, 0x7d, 0x17, 0x96, 0xc8, 0x93, 0x9f, 0x38, 0x93, 0xb0, 0x0b, 0x4c, 0x5a, 0x9b, 0xe7, 0xbe, - 0x8c, 0x19, 0xd0, 0x75, 0x8a, 0x1f, 0xda, 0xe9, 0x8f, 0xa4, 0x63, 0xb5, 0x00, 0x0b, 0xed, 0xf4, - 0x47, 0x59, 0xbc, 0x21, 0x89, 0x19, 0xd5, 0xe3, 0xae, 0x0b, 0x04, 0x5a, 0x0e, 0x53, 0x4a, 0x6f, - 0xe9, 0xf8, 0x5c, 0x0b, 0x04, 0xd0, 0x89, 0x9c, 0x2b, 0x24, 0x53, 0x8d, 0x76, 0xc2, 0xab, 0x57, - 0x99, 0x59, 0x85, 0xef, 0x6e, 0xac, 0x13, 0xc3, 0x87, 0x87, 0xc1, 0x01, 0x25, 0xa7, 0x3a, 0x11, - 0x33, 0xa3, 0x1d, 0x58, 0x63, 0x11, 0x77, 0x31, 0x92, 0x3d, 0xdf, 0xe9, 0xa8, 0x6c, 0x4b, 0xa0, - 0xee, 0xe5, 0xbf, 0xcf, 0x54, 0x40, 0x35, 0x98, 0xa7, 0xaa, 0x25, 0x0f, 0x7b, 0x3a, 0x2b, 0xeb, - 0xd4, 0xd9, 0x75, 0x44, 0xe5, 0x0a, 0xd5, 0xa6, 0x65, 0xb9, 0x42, 0x59, 0xd1, 0x07, 0x00, 0x38, - 0x1a, 0xf4, 0xba, 0x5d, 0x0a, 0xc5, 0xb3, 0x48, 0x15, 0xb3, 0xf3, 0xe9, 0xf5, 0x48, 0x5b, 0x49, - 0x98, 0x78, 0x84, 0x39, 0x7d, 0x0e, 0x32, 0x80, 0x3d, 0x52, 0x5b, 0x65, 0x13, 0x16, 0xd8, 0x62, - 0xa4, 0xb0, 0x56, 0x1c, 0x33, 0x53, 0x02, 0x45, 0x62, 0xb0, 0x56, 0x9c, 0x9e, 0x87, 0xb5, 0x92, - 0x2a, 0x94, 0xf7, 0xe0, 0xf4, 0xa4, 0x17, 0x4b, 0x29, 0xc3, 0xca, 0x71, 0x95, 0xe1, 0x3f, 0x14, - 0x60, 0x99, 0xb6, 0x26, 0xa4, 0xb0, 0x01, 0x2b, 0xde, 0xf8, 0x7e, 0x1c, 0x1e, 0x2a, 0xa4, 0x31, - 0xed, 0xdf, 0x50, 0x2e, 0x90, 0x0d, 0x5e, 0xa9, 0x1a, 0x08, 0xc3, 0xaa, 0xd8, 0x09, 0x76, 0x85, - 0xaf, 0x5b, 0x8c, 0x28, 0x25, 0x80, 0x0b, 0xf2, 0x99, 0x3c, 0x32, 0x95, 0x92, 0xfd, 0xa0, 0x70, - 0x92, 0xfd, 0xa0, 0x78, 0xac, 0xfd, 0xe0, 0x27, 0xb0, 0x2c, 0xfe, 0x8d, 0x4a, 0xf2, 0xf9, 0x17, - 0x93, 0xe4, 0xa9, 0xc6, 0x50, 0x23, 0x96, 0xe8, 0x0b, 0x33, 0x25, 0x3a, 0xb5, 0x22, 0x8a, 0x55, - 0x96, 0x4b, 0xce, 0xc7, 0xdb, 0xa0, 0x50, 0xf7, 0xbb, 0x15, 0xe7, 0x39, 0x76, 0xc9, 0x77, 0x60, - 0xa9, 0xd1, 0x13, 0x06, 0x24, 0xe9, 0xe6, 0xbe, 0x2b, 0x88, 0xf2, 0x71, 0x21, 0xe6, 0x8c, 0x77, - 0xb7, 0xc2, 0xcb, 0xd8, 0xdd, 0xae, 0x03, 0x70, 0x27, 0xca, 0x04, 0xa2, 0x9a, 0x2e, 0x19, 0x11, - 0xfd, 0x93, 0x36, 0x20, 0x48, 0xcc, 0x44, 0x3a, 0x71, 0x57, 0x13, 0xe3, 0xe0, 0xa0, 0x37, 0x8e, - 0x46, 0xa9, 0x9c, 0x2e, 0x3c, 0x10, 0x90, 0x6c, 0x09, 0xb4, 0x4c, 0x16, 0x0f, 0x99, 0x6a, 0x2f, - 0x77, 0x40, 0xd0, 0xed, 0xd8, 0x47, 0x6e, 0x66, 0x8a, 0xcb, 0x72, 0xee, 0x0b, 0x4d, 0xf5, 0x8c, - 0x2b, 0x7f, 0xa1, 0xc8, 0x70, 0x7e, 0xcf, 0x31, 0xd4, 0xef, 0x01, 0xc4, 0x16, 0x7c, 0x31, 0xd6, - 0x4c, 0x93, 0x8b, 0xa9, 0xf2, 0x57, 0x4e, 0x78, 0xa5, 0xb7, 0x29, 0xbc, 0xac, 0xb7, 0xf1, 0xa1, - 0x64, 0xff, 0x72, 0xd4, 0x4e, 0x5c, 0x3e, 0xc0, 0x8b, 0x4f, 0xb2, 0x54, 0x32, 0x89, 0x54, 0x9c, - 0xc9, 0x39, 0x78, 0x6a, 0x2a, 0xce, 0xb8, 0x62, 0xf9, 0x36, 0xac, 0xc9, 0x21, 0x0a, 0x4f, 0xa3, - 0x03, 0xf4, 0x23, 0x86, 0x43, 0xa2, 0xa4, 0x74, 0x1c, 0x89, 0x89, 0x48, 0xdc, 0xa7, 0xd1, 0x01, - 0x3b, 0xff, 0xb4, 0x9f, 0xc8, 0x7d, 0xa5, 0xda, 0xe7, 0x97, 0x0a, 0xa0, 0x3c, 0xbb, 0x2c, 0x4d, - 0x94, 0xff, 0xc2, 0xe9, 0x32, 0x73, 0x2a, 0x2b, 0x9e, 0xe4, 0x54, 0xa6, 0xff, 0x56, 0x81, 0x35, - 0xd3, 0x68, 0x72, 0xec, 0x3d, 0x66, 0x89, 0xf8, 0x7f, 0x38, 0x6f, 0x1a, 0xcd, 0xc0, 0xb1, 0x1b, - 0x66, 0xe5, 0x6e, 0x30, 0x11, 0x52, 0xe7, 0x3c, 0xfc, 0x5f, 0x9e, 0x25, 0xb1, 0x58, 0x9c, 0x83, - 0xcd, 0x7c, 0xb1, 0x80, 0xdd, 0x99, 0x5c, 0x59, 0x20, 0xf4, 0x14, 0xf4, 0x9b, 0xb0, 0x26, 0xd0, - 0x68, 0xfc, 0x86, 0x47, 0x41, 0xec, 0xd6, 0xa0, 0x74, 0x07, 0xbb, 0x66, 0xed, 0x6e, 0x50, 0x6b, - 0x35, 0x1a, 0xda, 0x1c, 0x5a, 0x81, 0x25, 0x4e, 0xa8, 0x18, 0x9a, 0x82, 0x96, 0x61, 0xd1, 0xb4, - 0x3c, 0x5c, 0x69, 0xb9, 0x58, 0x53, 0xf5, 0x9b, 0xb0, 0xea, 0x0c, 0x3a, 0x8f, 0xdb, 0xa3, 0x70, - 0x2f, 0x7c, 0x4a, 0x0d, 0x0e, 0xa7, 0xa0, 0xe0, 0x1a, 0xfb, 0xda, 0x1c, 0x02, 0x58, 0x70, 0xf6, - 0x2a, 0xde, 0x5b, 0x6f, 0x69, 0x0a, 0x2a, 0xc1, 0xa9, 0xdd, 0x8a, 0x13, 0xec, 0x35, 0x3d, 0x4d, - 0x25, 0x0f, 0xc6, 0xbe, 0x47, 0x1f, 0x0a, 0xfa, 0xf7, 0x60, 0x9d, 0x9e, 0x15, 0x1a, 0x9d, 0xe1, - 0x28, 0x8c, 0xc2, 0x01, 0xed, 0xc3, 0x32, 0x2c, 0x7a, 0x21, 0x59, 0xe4, 0xa3, 0x90, 0x75, 0xa0, - 0x39, 0xee, 0x8e, 0x3a, 0xfd, 0x6e, 0xf8, 0x2b, 0x4d, 0xd1, 0xaf, 0xc3, 0x9a, 0xdb, 0x1b, 0x8f, - 0x3a, 0xd1, 0x91, 0x37, 0x22, 0x1c, 0x47, 0x4f, 0xd1, 0xab, 0xb0, 0xde, 0xb2, 0x8c, 0xe6, 0x8e, - 0xb9, 0xdb, 0xb2, 0x5b, 0x5e, 0xd0, 0x34, 0xfc, 0x4a, 0x9d, 0x99, 0x3b, 0x9a, 0xb6, 0xe7, 0x07, - 0x2e, 0xae, 0x60, 0xcb, 0xd7, 0x14, 0xfd, 0x37, 0x0a, 0xac, 0xb6, 0x86, 0xdc, 0x45, 0xb7, 0x45, - 0x5d, 0xf8, 0x2f, 0xc2, 0xb9, 0x96, 0x87, 0xdd, 0xc0, 0xb7, 0xf7, 0xb0, 0x15, 0xb4, 0x3c, 0x63, - 0x37, 0x8b, 0xe7, 0x74, 0x01, 0xce, 0x4a, 0x1c, 0x2e, 0xae, 0xd8, 0x77, 0xb0, 0x1b, 0x38, 0x86, - 0xe7, 0xed, 0xdb, 0x6e, 0x55, 0x53, 0xd0, 0x16, 0x6c, 0x4c, 0x60, 0x68, 0xd6, 0x0c, 0x4d, 0xcd, - 0x95, 0x59, 0x78, 0xdf, 0x68, 0x04, 0x3b, 0xb6, 0xaf, 0x15, 0xf4, 0x26, 0xd9, 0xe8, 0x28, 0xe4, - 0x09, 0x03, 0xac, 0x5d, 0x84, 0xa2, 0x65, 0x5b, 0x38, 0x6b, 0x92, 0x5a, 0x86, 0x45, 0xc3, 0x71, - 0x5c, 0xfb, 0x0e, 0x1d, 0x50, 0x80, 0x85, 0x2a, 0xb6, 0x48, 0xcf, 0x0a, 0xa4, 0xc4, 0x71, 0xed, - 0xa6, 0xed, 0xe3, 0xaa, 0x56, 0xd4, 0x5d, 0xb1, 0x60, 0x44, 0xa3, 0x07, 0x3d, 0x66, 0xff, 0xa9, - 0xe2, 0x9a, 0xd1, 0x6a, 0xf8, 0xfc, 0x83, 0xdc, 0x0d, 0x5c, 0x7c, 0xbb, 0x85, 0x3d, 0xdf, 0xd3, - 0x14, 0xa4, 0xc1, 0xb2, 0x85, 0x71, 0xd5, 0x0b, 0x5c, 0x7c, 0xc7, 0xc4, 0xfb, 0x9a, 0x4a, 0xda, - 0x64, 0xbf, 0xc9, 0x3f, 0xe8, 0x9f, 0x29, 0x80, 0x18, 0x5c, 0x8c, 0x00, 0x16, 0xa5, 0xe3, 0xb3, - 0x0d, 0x5b, 0x75, 0xf2, 0x61, 0xe9, 0xab, 0x35, 0xed, 0x6a, 0xf6, 0x93, 0x6d, 0x00, 0xca, 0x94, - 0xdb, 0xb5, 0x9a, 0xa6, 0xa0, 0xb3, 0xf0, 0x4a, 0x86, 0x5e, 0x75, 0x6d, 0x47, 0x53, 0xb7, 0xd4, - 0x45, 0x05, 0x9d, 0xc9, 0x15, 0xee, 0x61, 0xec, 0x68, 0x05, 0x32, 0x44, 0x99, 0x02, 0x31, 0x01, - 0x59, 0xf5, 0xa2, 0xfe, 0xb1, 0x02, 0x1b, 0xac, 0x9b, 0x62, 0x36, 0xc7, 0x5d, 0x3d, 0x07, 0x9b, - 0x1c, 0xd9, 0x6a, 0x52, 0x47, 0x4f, 0x83, 0x96, 0x2a, 0x65, 0xdd, 0x7c, 0x15, 0xd6, 0x53, 0x54, - 0xda, 0x0f, 0x95, 0xac, 0xd5, 0x14, 0x79, 0x07, 0x7b, 0x7e, 0x80, 0x6b, 0x35, 0xdb, 0xf5, 0x59, - 0x47, 0x0a, 0x7a, 0x19, 0xd6, 0x2b, 0xe1, 0x60, 0x44, 0x74, 0x90, 0x68, 0xd8, 0xe9, 0x45, 0xb4, - 0x0b, 0x2b, 0xb0, 0x84, 0x3f, 0xf0, 0xb1, 0xe5, 0x99, 0xb6, 0xa5, 0xcd, 0xe9, 0xe7, 0x32, 0x3c, - 0x62, 0xd5, 0x78, 0x5e, 0x5d, 0x9b, 0xd3, 0xdb, 0xb0, 0x22, 0x5c, 0x62, 0xd9, 0xac, 0xd8, 0x86, - 0x2d, 0x31, 0xd7, 0xe8, 0xfa, 0xcd, 0xbe, 0xc2, 0x26, 0x9c, 0xce, 0x97, 0x63, 0x5f, 0x53, 0xc8, - 0x28, 0x64, 0x4a, 0x08, 0x5d, 0xd5, 0x7f, 0xaf, 0xc0, 0x26, 0xcf, 0xa6, 0xc5, 0xed, 0x11, 0x0c, - 0x4c, 0x93, 0x02, 0xd3, 0xe8, 0x70, 0xd9, 0x77, 0x5b, 0x9e, 0x8f, 0xab, 0x41, 0x15, 0xdf, 0x31, - 0x2b, 0x98, 0x4e, 0x17, 0xd3, 0xc5, 0x4d, 0x6c, 0xf9, 0x99, 0xbf, 0x7e, 0x1d, 0x5e, 0x9b, 0xc1, - 0x6b, 0xd9, 0xbe, 0x78, 0x26, 0xab, 0xe4, 0x35, 0xf8, 0xd6, 0x0c, 0xe6, 0x98, 0x51, 0xd5, 0x7f, - 0x0a, 0xcb, 0x29, 0x80, 0xf0, 0x33, 0xf0, 0x8a, 0xfc, 0xec, 0x84, 0xd1, 0x61, 0x27, 0x3a, 0xd2, - 0xe6, 0xb2, 0x05, 0xee, 0x38, 0x8a, 0x48, 0x01, 0x5d, 0x90, 0x72, 0x81, 0x1f, 0x0e, 0x1e, 0x75, - 0xa2, 0xf6, 0x28, 0x3c, 0xd4, 0x54, 0xfd, 0x2a, 0xac, 0xa4, 0x10, 0x8c, 0xc8, 0x97, 0x6f, 0xd8, - 0x5c, 0x5e, 0x35, 0x71, 0xd5, 0x6c, 0x35, 0xb5, 0x79, 0xb2, 0x14, 0xeb, 0xe6, 0x6e, 0x5d, 0x03, - 0xfd, 0x53, 0x85, 0x9c, 0x98, 0xe9, 0xf7, 0x69, 0xd6, 0x0c, 0x31, 0x56, 0x64, 0x9e, 0x30, 0xb0, - 0x33, 0xec, 0x79, 0xcc, 0x94, 0x7a, 0x0e, 0x36, 0xf9, 0x43, 0x60, 0x58, 0xd5, 0xa0, 0x6e, 0xb8, - 0xd5, 0x7d, 0xc3, 0x25, 0x93, 0xe7, 0xae, 0xa6, 0xd2, 0x15, 0x21, 0x51, 0x02, 0xdf, 0x6e, 0x55, - 0xea, 0x5a, 0x81, 0x4c, 0xc0, 0x14, 0xdd, 0x31, 0x2d, 0xad, 0x48, 0xd7, 0x57, 0x8e, 0x9b, 0x36, - 0x4b, 0xca, 0xe7, 0xf5, 0x0e, 0x68, 0xd9, 0xb0, 0xa5, 0x9c, 0x4d, 0xdb, 0x6d, 0x59, 0x16, 0x13, - 0x20, 0x6b, 0x50, 0xb2, 0xfd, 0x3a, 0x76, 0x39, 0x1c, 0x1d, 0xc5, 0x9f, 0x6b, 0x59, 0x46, 0xcb, - 0xaf, 0xdb, 0xae, 0x79, 0x8f, 0x4a, 0x92, 0x4d, 0x38, 0xed, 0x35, 0x8c, 0xca, 0x1e, 0x1d, 0x34, - 0xd3, 0x0a, 0x2a, 0x75, 0xc3, 0xb2, 0x70, 0x43, 0x03, 0xfd, 0xcf, 0x0a, 0x9c, 0x9d, 0x61, 0xf7, - 0x42, 0x6f, 0xc0, 0x95, 0x3a, 0x36, 0xaa, 0x0d, 0xec, 0x79, 0x01, 0x69, 0x12, 0x5b, 0x3e, 0x37, - 0x2f, 0x4f, 0x9c, 0xad, 0x57, 0xe0, 0xdb, 0xb3, 0xd9, 0x13, 0xb9, 0xf7, 0x1d, 0xb8, 0x34, 0x9b, - 0x95, 0xcb, 0x41, 0x95, 0xcc, 0xd9, 0xd9, 0x9c, 0xb1, 0xfc, 0x2c, 0xe8, 0x9f, 0x28, 0xb0, 0x31, - 0x59, 0x5d, 0x24, 0x7d, 0x33, 0x2d, 0xcf, 0x37, 0x1a, 0x8d, 0xc0, 0x31, 0x5c, 0xa3, 0x19, 0x60, - 0xcb, 0xb5, 0x1b, 0x8d, 0x49, 0x72, 0xe3, 0x12, 0x5c, 0x9c, 0xce, 0xea, 0x55, 0x5c, 0xd3, 0x21, - 0x0b, 0xb0, 0x0c, 0xdb, 0xd3, 0xb9, 0xb0, 0x59, 0xc1, 0x9a, 0xba, 0xf3, 0xfe, 0xe7, 0x7f, 0xdf, - 0x9e, 0xfb, 0xfc, 0xd9, 0xb6, 0xf2, 0xe5, 0xb3, 0x6d, 0xe5, 0x6f, 0xcf, 0xb6, 0x95, 0x7b, 0xaf, - 0x9f, 0x20, 0x11, 0xe5, 0xfd, 0x05, 0xea, 0x4f, 0x71, 0xed, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xc0, 0x23, 0xcc, 0xa0, 0xb0, 0x85, 0x01, 0x00, + // 26493 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xfd, 0x7b, 0x70, 0x1c, 0x49, + 0x7a, 0x20, 0x86, 0x4f, 0x3f, 0x00, 0x34, 0x3e, 0xbc, 0x1a, 0x09, 0x90, 0x04, 0x31, 0xe4, 0x80, + 0x53, 0x9c, 0xe1, 0x90, 0xf3, 0x20, 0x97, 0xe0, 0x0e, 0x77, 0x67, 0xe7, 0xd9, 0x78, 0x90, 0x68, + 0x12, 0x04, 0xb0, 0xd5, 0x20, 0xb1, 0xa3, 0xd9, 0xd9, 0xda, 0x42, 0x57, 0x02, 0xa8, 0x41, 0x77, + 0x57, 0x6f, 0x55, 0x35, 0x41, 0xac, 0xee, 0x7e, 0xa7, 0xc7, 0xe9, 0xf6, 0x27, 0xdf, 0xe9, 0xe5, + 0x5b, 0x59, 0x7b, 0x0e, 0x9d, 0x42, 0x21, 0xdf, 0x9d, 0xe5, 0xc7, 0x29, 0x1c, 0x92, 0x2e, 0x7c, + 0x0e, 0x85, 0xe5, 0x93, 0x43, 0x56, 0xc8, 0xba, 0x38, 0x5b, 0x0e, 0xbf, 0xd7, 0x0a, 0xc8, 0xb2, + 0x2e, 0x2e, 0x1c, 0x0c, 0xdb, 0xa1, 0xb3, 0x1c, 0x17, 0xf6, 0x38, 0x64, 0x3b, 0xf2, 0xcb, 0xcc, + 0xaa, 0xcc, 0xaa, 0xea, 0x46, 0x63, 0x86, 0x73, 0x27, 0x4e, 0xdc, 0x3f, 0x24, 0xfa, 0xcb, 0xef, + 0xfb, 0x32, 0x2b, 0x9f, 0x5f, 0x7e, 0xf9, 0x3d, 0xe0, 0xf9, 0x90, 0x36, 0x68, 0xdb, 0xf3, 0xc3, + 0x6b, 0x0d, 0xba, 0x6b, 0xd7, 0x0f, 0xaf, 0x85, 0x87, 0x6d, 0x1a, 0xf0, 0x7f, 0xaf, 0xb6, 0x7d, + 0x2f, 0xf4, 0xc8, 0x00, 0xfe, 0x98, 0x9d, 0xde, 0xf5, 0x76, 0x3d, 0x84, 0x5c, 0x63, 0x7f, 0xf1, + 0xc2, 0xd9, 0xb9, 0x5d, 0xcf, 0xdb, 0x6d, 0xd0, 0x6b, 0xf8, 0x6b, 0xbb, 0xb3, 0x73, 0x2d, 0x74, + 0x9b, 0x34, 0x08, 0xed, 0x66, 0x5b, 0x20, 0x5c, 0x89, 0x2a, 0xb0, 0xc3, 0x90, 0x95, 0x84, 0xae, + 0xd7, 0xba, 0xf6, 0xf0, 0xba, 0xfa, 0x53, 0xa0, 0xbe, 0x96, 0xdd, 0x96, 0x03, 0xdf, 0x6e, 0xb7, + 0xa9, 0x1f, 0xff, 0xc1, 0xd1, 0x8d, 0x5f, 0x28, 0xc0, 0xf0, 0x5d, 0x4a, 0xdb, 0x95, 0x86, 0xfb, + 0x90, 0x92, 0x8b, 0x50, 0x5c, 0xb3, 0x9b, 0x74, 0x26, 0x77, 0x21, 0x77, 0x79, 0x78, 0x61, 0xe2, + 0xf1, 0xd1, 0xdc, 0x48, 0x40, 0xfd, 0x87, 0xd4, 0xb7, 0x5a, 0x76, 0x93, 0x9a, 0x58, 0x48, 0x5e, + 0x81, 0x61, 0xf6, 0x7f, 0xd0, 0xb6, 0xeb, 0x74, 0x26, 0x8f, 0x98, 0x63, 0x8f, 0x8f, 0xe6, 0x86, + 0x5b, 0x12, 0x68, 0xc6, 0xe5, 0xa4, 0x0a, 0x43, 0xcb, 0x8f, 0xda, 0xae, 0x4f, 0x83, 0x99, 0xe2, + 0x85, 0xdc, 0xe5, 0x91, 0xf9, 0xd9, 0xab, 0xfc, 0x63, 0xaf, 0xca, 0x8f, 0xbd, 0xba, 0x29, 0x3f, + 0x76, 0x61, 0xea, 0x77, 0x8f, 0xe6, 0x9e, 0x79, 0x7c, 0x34, 0x37, 0x44, 0x39, 0xc9, 0x4f, 0xff, + 0xe1, 0x5c, 0xce, 0x94, 0xf4, 0xe4, 0x2d, 0x28, 0x6e, 0x1e, 0xb6, 0xe9, 0xcc, 0xf0, 0x85, 0xdc, + 0xe5, 0xf1, 0xf9, 0xe7, 0xae, 0xf2, 0xee, 0x8d, 0x1a, 0x1f, 0xff, 0xc5, 0xb0, 0x16, 0x4a, 0x8f, + 0x8f, 0xe6, 0x8a, 0x0c, 0xc5, 0x44, 0x2a, 0xf2, 0x1a, 0x0c, 0xae, 0x78, 0x41, 0x58, 0x5d, 0x9a, + 0x01, 0x6c, 0xf2, 0xa9, 0xc7, 0x47, 0x73, 0x93, 0x7b, 0x5e, 0x10, 0x5a, 0xae, 0xf3, 0xaa, 0xd7, + 0x74, 0x43, 0xda, 0x6c, 0x87, 0x87, 0xa6, 0x40, 0x32, 0x1e, 0xc1, 0x98, 0xc6, 0x8f, 0x8c, 0xc0, + 0xd0, 0xfd, 0xb5, 0xbb, 0x6b, 0xeb, 0x5b, 0x6b, 0xe5, 0x67, 0x48, 0x09, 0x8a, 0x6b, 0xeb, 0x4b, + 0xcb, 0xe5, 0x1c, 0x19, 0x82, 0x42, 0x65, 0x63, 0xa3, 0x9c, 0x27, 0xa3, 0x50, 0x5a, 0xaa, 0x6c, + 0x56, 0x16, 0x2a, 0xb5, 0xe5, 0x72, 0x81, 0x4c, 0xc1, 0xc4, 0x56, 0x75, 0x6d, 0x69, 0x7d, 0xab, + 0x66, 0x2d, 0x2d, 0xd7, 0xee, 0x6e, 0xae, 0x6f, 0x94, 0x8b, 0x64, 0x1c, 0xe0, 0xee, 0xfd, 0x85, + 0x65, 0x73, 0x6d, 0x79, 0x73, 0xb9, 0x56, 0x1e, 0x20, 0xd3, 0x50, 0x96, 0x24, 0x56, 0x6d, 0xd9, + 0x7c, 0x50, 0x5d, 0x5c, 0x2e, 0x0f, 0xde, 0x29, 0x96, 0x0a, 0xe5, 0xa2, 0x39, 0xb4, 0x4a, 0xed, + 0x80, 0x56, 0x97, 0x8c, 0x7f, 0xa3, 0x00, 0xa5, 0x7b, 0x34, 0xb4, 0x1d, 0x3b, 0xb4, 0xc9, 0x39, + 0x6d, 0x7c, 0xf0, 0x13, 0x95, 0x81, 0xb9, 0x98, 0x1e, 0x98, 0x81, 0xc7, 0x47, 0x73, 0xb9, 0xd7, + 0xd4, 0x01, 0x79, 0x13, 0x46, 0x96, 0x68, 0x50, 0xf7, 0xdd, 0x36, 0x9b, 0x34, 0x33, 0x05, 0x44, + 0x3b, 0xfb, 0xf8, 0x68, 0xee, 0x94, 0x13, 0x83, 0x95, 0x0e, 0x51, 0xb1, 0x49, 0x15, 0x06, 0x57, + 0xed, 0x6d, 0xda, 0x08, 0x66, 0x06, 0x2e, 0x14, 0x2e, 0x8f, 0xcc, 0x3f, 0x2b, 0x06, 0x41, 0x36, + 0xf0, 0x2a, 0x2f, 0x5d, 0x6e, 0x85, 0xfe, 0xe1, 0xc2, 0xf4, 0xe3, 0xa3, 0xb9, 0x72, 0x03, 0x01, + 0x6a, 0x07, 0x73, 0x14, 0x52, 0x8b, 0x27, 0xc6, 0xe0, 0xb1, 0x13, 0xe3, 0xfc, 0xef, 0x1e, 0xcd, + 0xe5, 0xd8, 0x80, 0x89, 0x89, 0x11, 0xf3, 0xd3, 0xa7, 0xc8, 0x3c, 0x94, 0x4c, 0xfa, 0xd0, 0x0d, + 0xd8, 0x97, 0x95, 0xf0, 0xcb, 0x4e, 0x3f, 0x3e, 0x9a, 0x23, 0xbe, 0x80, 0x29, 0xcd, 0x88, 0xf0, + 0x66, 0xdf, 0x80, 0x11, 0xa5, 0xd5, 0xa4, 0x0c, 0x85, 0x7d, 0x7a, 0xc8, 0x7b, 0xd8, 0x64, 0x7f, + 0x92, 0x69, 0x18, 0x78, 0x68, 0x37, 0x3a, 0xa2, 0x4b, 0x4d, 0xfe, 0xe3, 0x2b, 0xf9, 0x2f, 0xe7, + 0xee, 0x14, 0x4b, 0x43, 0xe5, 0x92, 0x99, 0xaf, 0x2e, 0x19, 0xff, 0x6a, 0x11, 0x4a, 0xa6, 0xc7, + 0x17, 0x22, 0xb9, 0x02, 0x03, 0xb5, 0xd0, 0x0e, 0xe5, 0x30, 0x4d, 0x3d, 0x3e, 0x9a, 0x9b, 0x60, + 0x8b, 0x94, 0x2a, 0xf5, 0x73, 0x0c, 0x86, 0xba, 0xb1, 0x67, 0x07, 0x72, 0xb8, 0x10, 0xb5, 0xcd, + 0x00, 0x2a, 0x2a, 0x62, 0x90, 0x4b, 0x50, 0xbc, 0xe7, 0x39, 0x54, 0x8c, 0x18, 0x79, 0x7c, 0x34, + 0x37, 0xde, 0xf4, 0x1c, 0x15, 0x11, 0xcb, 0xc9, 0xab, 0x30, 0xbc, 0xd8, 0xf1, 0x7d, 0xda, 0x62, + 0x73, 0xbd, 0x88, 0xc8, 0xe3, 0x8f, 0x8f, 0xe6, 0xa0, 0xce, 0x81, 0x96, 0xeb, 0x98, 0x31, 0x02, + 0x1b, 0x86, 0x5a, 0x68, 0xfb, 0x21, 0x75, 0x66, 0x06, 0xfa, 0x1a, 0x06, 0xb6, 0x3e, 0x27, 0x03, + 0x4e, 0x92, 0x1c, 0x06, 0xc1, 0x89, 0xac, 0xc0, 0xc8, 0x6d, 0xdf, 0xae, 0xd3, 0x0d, 0xea, 0xbb, + 0x9e, 0x83, 0xe3, 0x5b, 0x58, 0xb8, 0xf4, 0xf8, 0x68, 0xee, 0xf4, 0x2e, 0x03, 0x5b, 0x6d, 0x84, + 0xc7, 0xd4, 0x1f, 0x1f, 0xcd, 0x95, 0x96, 0x3a, 0x3e, 0xf6, 0x9e, 0xa9, 0x92, 0x92, 0x6f, 0xb2, + 0xc1, 0x09, 0x42, 0xec, 0x5a, 0xea, 0xcc, 0x0c, 0x1d, 0xdb, 0x44, 0x43, 0x34, 0xf1, 0x74, 0xc3, + 0x0e, 0x42, 0xcb, 0xe7, 0x74, 0x89, 0x76, 0xaa, 0x2c, 0xc9, 0x3a, 0x94, 0x6a, 0xf5, 0x3d, 0xea, + 0x74, 0x1a, 0x14, 0xa7, 0xcc, 0xc8, 0xfc, 0x19, 0x31, 0xa9, 0xe5, 0x78, 0xca, 0xe2, 0x85, 0x59, + 0xc1, 0x9b, 0x04, 0x02, 0xa2, 0xce, 0x27, 0x89, 0xf5, 0x95, 0xd2, 0xf7, 0x7e, 0x71, 0xee, 0x99, + 0x1f, 0xfa, 0x83, 0x0b, 0xcf, 0x18, 0xff, 0x7e, 0x1e, 0xca, 0x49, 0x26, 0x64, 0x07, 0xc6, 0xee, + 0xb7, 0x1d, 0x3b, 0xa4, 0x8b, 0x0d, 0x97, 0xb6, 0xc2, 0x00, 0x27, 0x49, 0xef, 0x6f, 0x7a, 0x41, + 0xd4, 0x3b, 0xd3, 0x41, 0x42, 0xab, 0xce, 0x29, 0x13, 0x5f, 0xa5, 0xb3, 0x8d, 0xeb, 0xa9, 0xe1, + 0x06, 0x1e, 0xe0, 0x0c, 0x3b, 0x59, 0x3d, 0x7c, 0xeb, 0xef, 0x52, 0x8f, 0x60, 0x2b, 0x26, 0x50, + 0xcb, 0xd9, 0x3e, 0xc4, 0x99, 0xd9, 0xff, 0x04, 0x62, 0x24, 0x19, 0x13, 0x88, 0x81, 0x8d, 0x7f, + 0x9c, 0x83, 0x71, 0x93, 0x06, 0x5e, 0xc7, 0xaf, 0xd3, 0x15, 0x6a, 0x3b, 0xd4, 0x67, 0xd3, 0xff, + 0xae, 0xdb, 0x72, 0xc4, 0x9a, 0xc2, 0xe9, 0xbf, 0xef, 0xb6, 0xd4, 0xad, 0x1b, 0xcb, 0xc9, 0x17, + 0x60, 0xa8, 0xd6, 0xd9, 0x46, 0xd4, 0x7c, 0xbc, 0x03, 0x04, 0x9d, 0x6d, 0x2b, 0x81, 0x2e, 0xd1, + 0xc8, 0x35, 0x18, 0x7a, 0x40, 0xfd, 0x20, 0xde, 0x0d, 0xf1, 0x68, 0x78, 0xc8, 0x41, 0x2a, 0x81, + 0xc0, 0x22, 0xb7, 0xe3, 0x1d, 0x59, 0x1c, 0x6a, 0x13, 0x89, 0x7d, 0x30, 0x9e, 0x2a, 0x4d, 0x01, + 0x51, 0xa7, 0x8a, 0xc4, 0x32, 0x7e, 0x26, 0x0f, 0xe5, 0x25, 0x3b, 0xb4, 0xb7, 0xed, 0x40, 0xf4, + 0xe7, 0x83, 0x1b, 0x6c, 0x8f, 0x57, 0x3e, 0x14, 0xf7, 0x78, 0xd6, 0xf2, 0x4f, 0xfc, 0x79, 0x2f, + 0x26, 0x3f, 0x6f, 0x84, 0x9d, 0xb0, 0xe2, 0xf3, 0xe2, 0x8f, 0x7a, 0xfb, 0xf8, 0x8f, 0x2a, 0x8b, + 0x8f, 0x2a, 0xc9, 0x8f, 0x8a, 0x3f, 0x85, 0xbc, 0x0d, 0xc5, 0x5a, 0x9b, 0xd6, 0xc5, 0x26, 0x22, + 0xcf, 0x05, 0xfd, 0xe3, 0x18, 0xc2, 0x83, 0x1b, 0x0b, 0xa3, 0x82, 0x4d, 0x31, 0x68, 0xd3, 0xba, + 0x89, 0x64, 0xca, 0xa2, 0xf9, 0xfb, 0x05, 0x98, 0xce, 0x22, 0x53, 0xbf, 0x63, 0xb0, 0xc7, 0x77, + 0x5c, 0x86, 0x12, 0x3b, 0xc2, 0xd9, 0xb1, 0x88, 0xdb, 0xc5, 0xf0, 0xc2, 0x28, 0x6b, 0xf2, 0x9e, + 0x80, 0x99, 0x51, 0x29, 0xb9, 0x18, 0x49, 0x04, 0xa5, 0x98, 0x9f, 0x90, 0x08, 0xa4, 0x1c, 0xc0, + 0xc6, 0x5a, 0x2e, 0x61, 0x14, 0x1c, 0xe2, 0x6e, 0x91, 0xe0, 0x78, 0xac, 0x7d, 0x01, 0xd1, 0x8e, + 0x19, 0x79, 0x28, 0x2c, 0x43, 0x49, 0x7e, 0xd6, 0xcc, 0x28, 0x32, 0x9a, 0x4c, 0x74, 0xd2, 0x83, + 0x1b, 0x7c, 0x30, 0x1d, 0xf1, 0x5b, 0x65, 0x23, 0x71, 0xc8, 0x0d, 0x28, 0x6d, 0xf8, 0xde, 0xa3, + 0xc3, 0xea, 0x52, 0x30, 0x33, 0x76, 0xa1, 0x70, 0x79, 0x78, 0xe1, 0xcc, 0xe3, 0xa3, 0xb9, 0xa9, + 0x36, 0x83, 0x59, 0xae, 0xa3, 0x9e, 0xb4, 0x11, 0xe2, 0x9d, 0x62, 0x29, 0x57, 0xce, 0xdf, 0x29, + 0x96, 0xf2, 0xe5, 0x02, 0x17, 0x2f, 0xee, 0x14, 0x4b, 0xc5, 0xf2, 0xc0, 0x9d, 0x62, 0x69, 0x00, + 0x05, 0x8e, 0xe1, 0x32, 0xdc, 0x29, 0x96, 0x46, 0xca, 0xa3, 0xda, 0x69, 0x8f, 0x0c, 0x42, 0xaf, + 0xee, 0x35, 0xcc, 0xc2, 0x7d, 0xb3, 0x6a, 0x0e, 0x2e, 0x56, 0x16, 0xa9, 0x1f, 0x9a, 0x85, 0xca, + 0x56, 0xcd, 0x1c, 0x5b, 0x3a, 0x6c, 0xd9, 0x4d, 0xb7, 0xce, 0x8f, 0x4e, 0xb3, 0x70, 0x7b, 0x71, + 0xc3, 0xa8, 0xc0, 0x78, 0xfc, 0x2d, 0xab, 0x6e, 0x10, 0x92, 0x6b, 0x30, 0x2c, 0x21, 0x6c, 0xa3, + 0x2b, 0x64, 0x7e, 0xb5, 0x19, 0xe3, 0x18, 0xbf, 0x93, 0x07, 0x88, 0x4b, 0x9e, 0xd2, 0xb5, 0xf0, + 0x25, 0x6d, 0x2d, 0x9c, 0x4a, 0xae, 0x85, 0xae, 0xab, 0x80, 0xbc, 0x0b, 0x83, 0x4c, 0x2c, 0xe8, + 0x48, 0x91, 0xe8, 0x4c, 0x92, 0x14, 0x0b, 0x1f, 0xdc, 0x58, 0x18, 0x17, 0xc4, 0x83, 0x01, 0x42, + 0x4c, 0x41, 0xa6, 0x2c, 0xa3, 0x5f, 0x18, 0x8a, 0x07, 0x43, 0x2c, 0xa0, 0xcb, 0x10, 0x0d, 0xa8, + 0xe8, 0x50, 0x5c, 0x19, 0x6d, 0x39, 0xc8, 0x51, 0x29, 0x39, 0x0b, 0x6c, 0xc0, 0x45, 0xa7, 0x0e, + 0x3d, 0x3e, 0x9a, 0x2b, 0x74, 0x7c, 0x17, 0x27, 0x01, 0xb9, 0x06, 0x62, 0x1a, 0x88, 0x0e, 0x64, + 0xb3, 0x6f, 0xb2, 0x6e, 0x5b, 0x75, 0xea, 0x87, 0x71, 0x8f, 0xcf, 0xe4, 0xe4, 0x6c, 0x21, 0x6d, + 0xd0, 0xa7, 0xca, 0x4c, 0x11, 0xa7, 0xc1, 0xe5, 0xcc, 0x5e, 0xb9, 0xaa, 0xa1, 0x72, 0x31, 0xf2, + 0x82, 0x3c, 0x95, 0x1c, 0x5e, 0x66, 0xa5, 0x44, 0x4a, 0xbd, 0x02, 0x72, 0x03, 0xd8, 0x0c, 0x15, + 0xbd, 0x0f, 0xa2, 0x9e, 0xca, 0x56, 0x6d, 0xe1, 0x94, 0xe0, 0x34, 0x66, 0x1f, 0xa8, 0xe4, 0x0c, + 0x9b, 0xbc, 0x09, 0x6c, 0x0a, 0x8b, 0x7e, 0x27, 0x82, 0xe8, 0xf6, 0xe2, 0xc6, 0x62, 0xc3, 0xeb, + 0x38, 0xb5, 0xaf, 0xae, 0xc6, 0xc4, 0xbb, 0xf5, 0xb6, 0x4a, 0x7c, 0x7b, 0x71, 0x83, 0xbc, 0x09, + 0x03, 0x95, 0x6f, 0x77, 0x7c, 0x2a, 0xe4, 0x93, 0x51, 0x59, 0x27, 0x83, 0x2d, 0x9c, 0x11, 0x84, + 0x13, 0x36, 0xfb, 0xa9, 0xca, 0x75, 0x58, 0xce, 0x6a, 0xde, 0x5c, 0xad, 0x09, 0xd9, 0x83, 0x24, + 0xba, 0x65, 0x73, 0x55, 0x69, 0x76, 0xa8, 0x7d, 0x35, 0xa3, 0x22, 0xd7, 0x20, 0x5f, 0x59, 0xc2, + 0x1b, 0xd1, 0xc8, 0xfc, 0xb0, 0xac, 0x76, 0x69, 0x61, 0x5a, 0x90, 0x8c, 0xda, 0xea, 0x32, 0xc8, + 0x57, 0x96, 0xc8, 0x02, 0x0c, 0xdc, 0x3b, 0xac, 0x7d, 0x75, 0x55, 0x6c, 0x66, 0x53, 0x72, 0x5e, + 0x33, 0xd8, 0x3a, 0x2e, 0xfb, 0x20, 0x6e, 0x71, 0xf3, 0x30, 0xf8, 0x56, 0x43, 0x6d, 0x31, 0xa2, + 0x91, 0x0d, 0x18, 0xae, 0x38, 0x4d, 0xb7, 0x75, 0x3f, 0xa0, 0xfe, 0xcc, 0x08, 0xf2, 0x99, 0x49, + 0xb4, 0x3b, 0x2a, 0x5f, 0x98, 0x79, 0x7c, 0x34, 0x37, 0x6d, 0xb3, 0x9f, 0x56, 0x27, 0xa0, 0xbe, + 0xc2, 0x2d, 0x66, 0x42, 0x36, 0x00, 0xee, 0x79, 0xad, 0x5d, 0xaf, 0x12, 0x36, 0xec, 0x20, 0xb1, + 0x3d, 0xc6, 0x05, 0x91, 0xf8, 0x70, 0xaa, 0xc9, 0x60, 0x96, 0xcd, 0x80, 0x0a, 0x43, 0x85, 0x07, + 0xb9, 0x05, 0x83, 0xeb, 0xbe, 0x5d, 0x6f, 0xd0, 0x99, 0x31, 0xe4, 0x36, 0x2d, 0xb8, 0x71, 0xa0, + 0xfc, 0xd2, 0x19, 0xc1, 0xb0, 0xec, 0x21, 0x58, 0xbd, 0xa6, 0x70, 0xc4, 0xd9, 0x2d, 0x20, 0xe9, + 0x39, 0x99, 0x71, 0x49, 0x78, 0x45, 0xbd, 0x24, 0xc4, 0x8b, 0x7e, 0xd1, 0x6b, 0x36, 0xed, 0x96, + 0x83, 0xb4, 0x0f, 0xe6, 0x95, 0xbb, 0x83, 0xf1, 0x2d, 0x98, 0x4c, 0x75, 0xd6, 0x31, 0xf7, 0xbb, + 0x77, 0x60, 0x62, 0x89, 0xee, 0xd8, 0x9d, 0x46, 0x18, 0x9d, 0x24, 0x7c, 0x89, 0xe2, 0x4d, 0xcb, + 0xe1, 0x45, 0x96, 0x3c, 0x3e, 0xcc, 0x24, 0xb2, 0xf1, 0x36, 0x8c, 0x69, 0x9f, 0xcf, 0xae, 0x0a, + 0x95, 0x8e, 0xe3, 0x86, 0x38, 0x90, 0xb9, 0xf8, 0xaa, 0x60, 0x33, 0x20, 0x0e, 0x97, 0x19, 0x23, + 0x18, 0x7f, 0x4b, 0x95, 0x56, 0xc4, 0x4e, 0xc4, 0xae, 0xd5, 0x62, 0x3f, 0xc8, 0xc5, 0xb2, 0x53, + 0x6a, 0x3f, 0x88, 0x76, 0x83, 0x2b, 0x7c, 0x6d, 0xe6, 0x53, 0x6b, 0x73, 0x44, 0x8c, 0x44, 0xc1, + 0x3e, 0x08, 0xf8, 0x8a, 0x8c, 0x66, 0x6a, 0xe1, 0x93, 0xcf, 0xd4, 0x77, 0x61, 0xf4, 0x9e, 0xdd, + 0xb2, 0x77, 0xa9, 0xc3, 0xbe, 0x80, 0xef, 0x3d, 0xc3, 0x0b, 0xcf, 0x3e, 0x3e, 0x9a, 0x3b, 0xd3, + 0xe4, 0x70, 0xfc, 0x4a, 0x75, 0x12, 0x69, 0x04, 0xe4, 0xba, 0x5c, 0xd9, 0x03, 0x19, 0x2b, 0x7b, + 0x4c, 0xd4, 0x3e, 0x80, 0x2b, 0x5b, 0xac, 0x67, 0xe3, 0xff, 0x28, 0xe1, 0x37, 0x92, 0x57, 0x61, + 0xd0, 0xa4, 0xbb, 0xec, 0xa8, 0xc9, 0xc5, 0x83, 0xe4, 0x23, 0x44, 0xed, 0x18, 0x8e, 0x83, 0x72, + 0x06, 0x75, 0x82, 0x3d, 0x77, 0x27, 0x14, 0xbd, 0x13, 0xc9, 0x19, 0x02, 0xac, 0xc8, 0x19, 0x02, + 0xa2, 0x5f, 0x67, 0x39, 0x8c, 0xed, 0x7e, 0xe6, 0x52, 0x4d, 0x74, 0x9a, 0xec, 0x61, 0x73, 0x49, + 0xd9, 0x46, 0x7c, 0x4d, 0x4a, 0x60, 0xd8, 0xe4, 0x26, 0x0c, 0x57, 0xea, 0x75, 0xaf, 0xa3, 0xdc, + 0x19, 0xf9, 0xba, 0xe5, 0x40, 0x5d, 0x45, 0x12, 0xa3, 0x92, 0x1a, 0x8c, 0x2c, 0xb3, 0x8b, 0x96, + 0xbb, 0x68, 0xd7, 0xf7, 0x64, 0x27, 0xc9, 0x3d, 0x4c, 0x29, 0x89, 0x57, 0x2e, 0x45, 0x60, 0x9d, + 0x01, 0x55, 0x25, 0x83, 0x82, 0x4b, 0x36, 0x61, 0xa4, 0x46, 0xeb, 0x3e, 0x0d, 0x6b, 0xa1, 0xe7, + 0xd3, 0xc4, 0x96, 0xac, 0x94, 0x2c, 0x3c, 0x27, 0xef, 0x7a, 0x01, 0x02, 0xad, 0x80, 0x41, 0x55, + 0xae, 0x0a, 0x32, 0x17, 0xda, 0x9b, 0x9e, 0x7f, 0xb8, 0xb4, 0x20, 0xb6, 0xe9, 0xf8, 0x4c, 0xe7, + 0x60, 0x55, 0x68, 0x67, 0x10, 0x67, 0x5b, 0x17, 0xda, 0x39, 0x16, 0x8e, 0xd4, 0x52, 0x0d, 0x65, + 0x2b, 0xb1, 0x69, 0x4f, 0xc4, 0xbd, 0x8c, 0x60, 0x65, 0xa4, 0x9c, 0x00, 0x25, 0x33, 0x6d, 0xa4, + 0x04, 0x16, 0x69, 0x03, 0x91, 0xa3, 0xc6, 0x05, 0xdd, 0x06, 0x0d, 0x02, 0xb1, 0x97, 0x9f, 0x4d, + 0x0c, 0x7e, 0x8c, 0xb0, 0xf0, 0xa2, 0x60, 0x7e, 0x5e, 0x4e, 0x03, 0x71, 0x4f, 0x63, 0x85, 0x4a, + 0x3d, 0x19, 0xbc, 0xc9, 0x1b, 0x00, 0xcb, 0x8f, 0x42, 0xea, 0xb7, 0xec, 0x46, 0xa4, 0x07, 0x43, + 0xd5, 0x0f, 0x15, 0x50, 0x7d, 0xa0, 0x15, 0x64, 0xb2, 0x08, 0x63, 0x95, 0x20, 0xe8, 0x34, 0xa9, + 0xe9, 0x35, 0x68, 0xc5, 0x5c, 0xc3, 0x7d, 0x7f, 0x78, 0xe1, 0xfc, 0xe3, 0xa3, 0xb9, 0xb3, 0x36, + 0x16, 0x58, 0xbe, 0xd7, 0xa0, 0x96, 0xed, 0xab, 0xb3, 0x5b, 0xa7, 0x21, 0xeb, 0x00, 0xeb, 0x6d, + 0xda, 0xaa, 0x51, 0xdb, 0xaf, 0xef, 0x25, 0xb6, 0xf9, 0xb8, 0x60, 0xe1, 0x9c, 0xf8, 0xc2, 0x69, + 0xaf, 0x4d, 0x5b, 0x01, 0xc2, 0xd4, 0x56, 0xc5, 0x98, 0x64, 0x0b, 0x26, 0xaa, 0x95, 0x7b, 0x1b, + 0x5e, 0xc3, 0xad, 0x1f, 0x0a, 0xc9, 0x69, 0x1c, 0xb5, 0x83, 0xa7, 0x05, 0xd7, 0x44, 0x29, 0xdf, + 0x9e, 0x5c, 0xbb, 0x69, 0xb5, 0x11, 0x6a, 0x09, 0xf9, 0x29, 0xc9, 0x85, 0xbc, 0xcf, 0xe6, 0x60, + 0xc0, 0x84, 0xc1, 0x4d, 0x7b, 0x37, 0x98, 0x99, 0xd0, 0xb4, 0x5d, 0x95, 0xad, 0xda, 0x55, 0xa5, + 0x94, 0x8b, 0x29, 0xb3, 0x7c, 0x22, 0x22, 0xd4, 0x0a, 0xed, 0xdd, 0x40, 0x9f, 0x88, 0x11, 0xf6, + 0xec, 0x3b, 0x50, 0x4e, 0x12, 0x9f, 0x50, 0xe9, 0x34, 0x56, 0x1e, 0x57, 0x5a, 0xbc, 0xfc, 0xc8, + 0x0d, 0xc2, 0xc0, 0xf8, 0x41, 0x6d, 0xd5, 0xb0, 0x15, 0x7d, 0x97, 0x1e, 0x6e, 0xf8, 0x74, 0xc7, + 0x7d, 0x24, 0x36, 0x20, 0x5c, 0xd1, 0xfb, 0xf4, 0xd0, 0x6a, 0x23, 0x54, 0x5d, 0xd1, 0x11, 0x2a, + 0xf9, 0x22, 0x94, 0xee, 0xde, 0xab, 0xdd, 0xa5, 0x87, 0xd5, 0x25, 0x71, 0xb8, 0x70, 0xb2, 0x66, + 0x60, 0x31, 0x52, 0x6d, 0x7e, 0x44, 0x98, 0xc6, 0x42, 0xbc, 0x7b, 0xb1, 0x9a, 0x17, 0x1b, 0x9d, + 0x20, 0xa4, 0x7e, 0x75, 0x49, 0xad, 0xb9, 0xce, 0x81, 0x89, 0xbd, 0x24, 0x42, 0x35, 0xfe, 0x7e, + 0x1e, 0x77, 0x2e, 0x36, 0x49, 0xab, 0xad, 0x20, 0xb4, 0x5b, 0x75, 0x1a, 0x31, 0xc0, 0x49, 0xea, + 0x0a, 0x68, 0x62, 0x92, 0xc6, 0xc8, 0x7a, 0xd5, 0xf9, 0xbe, 0xab, 0x66, 0x55, 0x4a, 0x6d, 0x43, + 0x75, 0x49, 0x55, 0x89, 0xfa, 0x02, 0x9a, 0xa8, 0x32, 0x46, 0x26, 0x97, 0x60, 0xa8, 0x5a, 0xb9, + 0x57, 0xe9, 0x84, 0x7b, 0xb8, 0x6f, 0x96, 0xb8, 0x4c, 0xcd, 0x66, 0x98, 0xdd, 0x09, 0xf7, 0x4c, + 0x59, 0x48, 0xae, 0xe1, 0x5d, 0xa5, 0x45, 0x43, 0xae, 0x3a, 0x15, 0x07, 0x65, 0xc0, 0x41, 0x89, + 0xab, 0x0a, 0x03, 0x91, 0x97, 0x61, 0xe0, 0xc1, 0xc6, 0x62, 0x75, 0x49, 0x5c, 0x76, 0xf1, 0xf4, + 0x78, 0xd8, 0xae, 0xeb, 0x2d, 0xe1, 0x28, 0xc6, 0x6f, 0xe5, 0xe2, 0x3d, 0x89, 0x5c, 0xd2, 0x64, + 0x08, 0x54, 0x94, 0x30, 0x19, 0x42, 0x55, 0x94, 0xa0, 0x34, 0x61, 0x02, 0x59, 0xec, 0x04, 0xa1, + 0xd7, 0x5c, 0x6e, 0x39, 0x6d, 0xcf, 0x6d, 0x85, 0x48, 0xc5, 0x7b, 0xcd, 0x78, 0x7c, 0x34, 0xf7, + 0x5c, 0x1d, 0x4b, 0x2d, 0x2a, 0x8a, 0xad, 0x04, 0x97, 0x0c, 0xea, 0x4f, 0xd1, 0x91, 0xc6, 0xef, + 0xe5, 0xb5, 0xb3, 0x84, 0x35, 0xcf, 0xa4, 0xed, 0x86, 0x5b, 0xc7, 0xeb, 0xf3, 0x6d, 0xdf, 0xeb, + 0xb4, 0xa3, 0xe9, 0x80, 0xcd, 0xf3, 0xe3, 0x52, 0x6b, 0x97, 0x15, 0xeb, 0xbc, 0x33, 0xa8, 0xc9, + 0x7b, 0x30, 0xca, 0x8e, 0x75, 0xf1, 0x33, 0x98, 0xc9, 0xe3, 0x48, 0x9c, 0x43, 0x95, 0x57, 0x40, + 0xfd, 0x88, 0x8d, 0x26, 0x0f, 0xa8, 0x14, 0xc4, 0x81, 0x99, 0x4d, 0xdf, 0x6e, 0x05, 0x6e, 0xb8, + 0xdc, 0xaa, 0xfb, 0x87, 0x28, 0x86, 0x2c, 0xb7, 0xec, 0xed, 0x06, 0x75, 0xf0, 0x73, 0x4b, 0x0b, + 0x97, 0x1f, 0x1f, 0xcd, 0xbd, 0x10, 0x72, 0x1c, 0x8b, 0x46, 0x48, 0x16, 0xe5, 0x58, 0x0a, 0xe7, + 0xae, 0x9c, 0x98, 0xd8, 0x22, 0xbb, 0x15, 0x5f, 0x3c, 0xf8, 0x89, 0x8c, 0x62, 0x4b, 0x34, 0x1a, + 0x6c, 0x2b, 0x52, 0x9b, 0xa9, 0x12, 0x18, 0xff, 0x2c, 0x17, 0x9f, 0x76, 0xe4, 0x2d, 0x18, 0x11, + 0x53, 0x5d, 0x99, 0x17, 0xb8, 0x5d, 0xc9, 0x75, 0x91, 0x18, 0x59, 0x15, 0x9d, 0x5d, 0xb2, 0x2b, + 0x8b, 0xab, 0xca, 0xdc, 0xc0, 0x4b, 0xb6, 0x5d, 0x6f, 0x24, 0xa9, 0x24, 0x1a, 0x9b, 0x04, 0x9b, + 0xab, 0x35, 0xbd, 0x57, 0x70, 0x12, 0x84, 0x8d, 0x20, 0xa3, 0x1b, 0x14, 0xe4, 0x4f, 0xff, 0xe1, + 0xff, 0x6d, 0x2e, 0xeb, 0x50, 0x25, 0x0b, 0x30, 0xb6, 0xe5, 0xf9, 0xfb, 0x38, 0xbe, 0x4a, 0x27, + 0xe0, 0xc8, 0x1f, 0xc8, 0x82, 0xe4, 0x07, 0xe9, 0x24, 0x6a, 0xdb, 0x94, 0xde, 0xd0, 0xdb, 0x96, + 0xe0, 0xa0, 0x11, 0xb0, 0x71, 0x88, 0x38, 0x46, 0xab, 0x03, 0xc7, 0x21, 0x6e, 0x82, 0x36, 0x85, + 0x55, 0x74, 0xe3, 0x3f, 0xcc, 0xa9, 0x87, 0x27, 0xeb, 0xe4, 0x25, 0xaf, 0x69, 0xbb, 0x2d, 0xe5, + 0x73, 0xf8, 0x2b, 0x0e, 0x42, 0x93, 0x2d, 0x51, 0x90, 0xc9, 0x0d, 0x28, 0xf1, 0x5f, 0xd1, 0x26, + 0x89, 0x2a, 0x24, 0x41, 0xa8, 0xef, 0xf0, 0x12, 0x31, 0x35, 0x32, 0x85, 0x93, 0x8e, 0xcc, 0x0f, + 0xe5, 0x60, 0x44, 0xb9, 0x4f, 0xb3, 0xbd, 0x7a, 0xc3, 0xf7, 0x3e, 0xa2, 0xf5, 0x50, 0x3f, 0x26, + 0xda, 0x1c, 0x98, 0xd8, 0xab, 0x23, 0xd4, 0xc4, 0xf1, 0x90, 0x3f, 0xc1, 0xf1, 0x60, 0xfc, 0xd3, + 0x9c, 0x90, 0xe6, 0xfb, 0xde, 0x23, 0xf5, 0xfd, 0x2c, 0x7f, 0x92, 0x83, 0xe1, 0x3d, 0x18, 0x30, + 0xa9, 0xe3, 0x06, 0x42, 0x12, 0x9f, 0x54, 0x6f, 0x0e, 0x58, 0x10, 0x5f, 0x5e, 0x7c, 0xf6, 0x53, + 0xdd, 0xd5, 0xb1, 0x9c, 0x89, 0x5c, 0xd5, 0xe0, 0x56, 0x83, 0x3e, 0x72, 0xf9, 0x4c, 0x16, 0x07, + 0x0c, 0x8a, 0x5c, 0x6e, 0x60, 0xed, 0xb0, 0x12, 0x21, 0xfb, 0xa9, 0xb3, 0x56, 0xa3, 0x31, 0xde, + 0x07, 0x88, 0xab, 0x24, 0x77, 0xa1, 0x2c, 0xd6, 0xb6, 0xdb, 0xda, 0xe5, 0xe2, 0x83, 0xe8, 0x83, + 0xb9, 0xc7, 0x47, 0x73, 0xcf, 0xd6, 0xa3, 0x32, 0x21, 0x1f, 0x29, 0x7c, 0x53, 0x84, 0xc6, 0xbf, + 0x99, 0x87, 0x7c, 0x05, 0x07, 0xe4, 0x2e, 0x3d, 0x0c, 0xed, 0xed, 0x5b, 0x6e, 0x43, 0x9b, 0x89, + 0xfb, 0x08, 0xb5, 0x76, 0x5c, 0xed, 0x62, 0xad, 0x20, 0xb3, 0x99, 0x78, 0xd7, 0xdf, 0x7e, 0x1d, + 0x09, 0x95, 0x99, 0xb8, 0xef, 0x6f, 0xbf, 0x9e, 0x24, 0x8b, 0x10, 0x89, 0x01, 0x83, 0x7c, 0x56, + 0x8a, 0x39, 0x08, 0x8f, 0x8f, 0xe6, 0x06, 0xf9, 0xe4, 0x35, 0x45, 0x09, 0x39, 0x0b, 0x85, 0xda, + 0xc6, 0x9a, 0xd8, 0x3e, 0x50, 0x81, 0x15, 0xb4, 0x5b, 0x26, 0x83, 0xb1, 0x3a, 0x57, 0x97, 0x2a, + 0x1b, 0x78, 0x65, 0x1d, 0x88, 0xeb, 0x6c, 0x38, 0x76, 0x3b, 0x79, 0x69, 0x8d, 0x10, 0xc9, 0xdb, + 0x30, 0x72, 0x77, 0x69, 0x71, 0xc5, 0x0b, 0xf8, 0xd2, 0x1f, 0x8c, 0x27, 0xff, 0xbe, 0x53, 0xb7, + 0x50, 0x67, 0x9c, 0xdc, 0x43, 0x15, 0x7c, 0xe3, 0xc7, 0xf2, 0x30, 0xa2, 0x68, 0x74, 0xc8, 0x17, + 0xc5, 0x53, 0x5e, 0x4e, 0x93, 0x55, 0x15, 0x0c, 0x56, 0xca, 0xaf, 0xff, 0x4d, 0xcf, 0xa1, 0xe2, + 0x61, 0x2f, 0xbe, 0x6a, 0xe7, 0xfb, 0xb9, 0x6a, 0xbf, 0x01, 0xc0, 0xe7, 0x00, 0x36, 0x59, 0x39, + 0x8b, 0x95, 0x17, 0x7d, 0x75, 0x5c, 0x62, 0x64, 0xf2, 0x00, 0xa6, 0x36, 0xfd, 0x4e, 0x10, 0xd6, + 0x0e, 0x83, 0x90, 0x36, 0x19, 0xb7, 0x0d, 0xcf, 0x6b, 0x88, 0xf9, 0xf7, 0xc2, 0xe3, 0xa3, 0xb9, + 0x0b, 0x21, 0x2b, 0xb6, 0x02, 0x2c, 0xc7, 0x06, 0x58, 0x6d, 0xcf, 0x53, 0x2f, 0xe0, 0x59, 0x0c, + 0x0c, 0x13, 0x46, 0xd5, 0xeb, 0x3b, 0xdb, 0x96, 0xc5, 0xb3, 0x87, 0x50, 0xca, 0x2a, 0xdb, 0xb2, + 0x68, 0x65, 0xfa, 0x19, 0x46, 0x27, 0x31, 0xbe, 0xa8, 0xaa, 0x8e, 0xfa, 0x5d, 0xd8, 0xc6, 0x8f, + 0xe4, 0xe2, 0x6d, 0xe4, 0xc1, 0x75, 0xf2, 0x26, 0x0c, 0xf2, 0x67, 0x26, 0xf1, 0x1a, 0x77, 0x2a, + 0xba, 0x7e, 0xa9, 0x6f, 0x50, 0x5c, 0x67, 0xfb, 0xfb, 0xfc, 0x29, 0xfa, 0x19, 0x53, 0x90, 0x44, + 0xea, 0x5e, 0x5d, 0xf3, 0x23, 0xb9, 0xa3, 0x62, 0xf3, 0x7a, 0x96, 0xba, 0xd7, 0xf8, 0xed, 0x22, + 0x8c, 0xeb, 0x68, 0xea, 0x5b, 0x54, 0xae, 0xaf, 0xb7, 0xa8, 0xf7, 0xa0, 0xc4, 0xfa, 0xc3, 0xad, + 0x53, 0x29, 0xce, 0xbc, 0x80, 0x4a, 0x70, 0x01, 0xd3, 0xde, 0x58, 0x81, 0x0f, 0x07, 0xbb, 0x8d, + 0x99, 0x11, 0x15, 0x99, 0x57, 0x1e, 0x4c, 0x0a, 0xf1, 0x09, 0x2f, 0x1f, 0x4c, 0xd4, 0xf5, 0x10, + 0x3d, 0x9d, 0xbc, 0x06, 0x83, 0x4c, 0xaa, 0x8d, 0x94, 0x05, 0xd8, 0x4a, 0x26, 0xf0, 0x26, 0x8c, + 0x29, 0x38, 0x12, 0xd9, 0x82, 0xd2, 0xaa, 0x1d, 0x84, 0x35, 0x4a, 0x5b, 0x7d, 0xbc, 0x32, 0xcf, + 0x89, 0xae, 0x9a, 0xc2, 0x27, 0xdc, 0x80, 0xd2, 0x56, 0xe2, 0x99, 0x30, 0x62, 0x46, 0x3e, 0x04, + 0x58, 0xf4, 0x5a, 0xa1, 0xef, 0x35, 0x56, 0xbd, 0xdd, 0x99, 0x41, 0xbc, 0xa5, 0x3d, 0x97, 0x18, + 0x80, 0x18, 0x81, 0x5f, 0xd4, 0x22, 0x55, 0x44, 0x9d, 0x17, 0x58, 0x0d, 0x6f, 0x57, 0x5d, 0x07, + 0x31, 0x3e, 0xb9, 0x05, 0x65, 0x79, 0x05, 0xbe, 0xdf, 0xde, 0xf5, 0x71, 0x82, 0x0c, 0xc5, 0xc7, + 0x36, 0x7d, 0x14, 0x5a, 0x1d, 0x01, 0x57, 0x77, 0xca, 0x24, 0x0d, 0xf9, 0x3a, 0x9c, 0x49, 0xc2, + 0xe4, 0x28, 0x97, 0x62, 0x81, 0x56, 0x65, 0x97, 0x31, 0xef, 0xbb, 0xb1, 0x30, 0x3e, 0xce, 0xc3, + 0x99, 0x2e, 0x1f, 0xcb, 0xd6, 0x03, 0x1e, 0xd7, 0xca, 0x7a, 0x48, 0x9c, 0xd2, 0xdc, 0x3a, 0xe6, + 0x02, 0xe4, 0xc5, 0x01, 0x57, 0x5c, 0x28, 0x3f, 0x3e, 0x9a, 0x1b, 0xd5, 0xc6, 0x31, 0x5f, 0x5d, + 0x22, 0x77, 0xa0, 0xc8, 0x86, 0xa8, 0x8f, 0x47, 0x5e, 0xa9, 0xfd, 0x18, 0x0f, 0x5d, 0x75, 0xfa, + 0xe0, 0xd0, 0x21, 0x0f, 0xf2, 0x45, 0x28, 0x6c, 0x6e, 0xae, 0xe2, 0xdc, 0x29, 0xe0, 0xb7, 0x8f, + 0x85, 0x61, 0x43, 0x9b, 0xaa, 0x63, 0x8c, 0xf6, 0x6a, 0x64, 0x13, 0xc0, 0xd0, 0xc9, 0xd7, 0x12, + 0xc6, 0x27, 0x2f, 0xf7, 0x1e, 0xe8, 0xfe, 0x6d, 0x51, 0x3e, 0x85, 0x09, 0x88, 0xf1, 0xf3, 0xf9, + 0x78, 0x0d, 0xdf, 0x72, 0x1b, 0x21, 0xf5, 0xc9, 0x2c, 0x5f, 0x92, 0xf1, 0xfd, 0xd7, 0x8c, 0x7e, + 0x93, 0x99, 0x78, 0x7d, 0x73, 0x56, 0xd1, 0x42, 0x7e, 0x59, 0x59, 0xc8, 0x05, 0x5c, 0xc8, 0xe3, + 0x5d, 0x97, 0xec, 0xcb, 0x19, 0xf3, 0x12, 0x17, 0x62, 0xc6, 0xdc, 0x7b, 0x01, 0xc6, 0xd6, 0xbc, + 0xe5, 0x47, 0x61, 0x84, 0xc8, 0x16, 0x60, 0xc9, 0xd4, 0x81, 0x8c, 0xe3, 0x7a, 0xc3, 0xa1, 0xfe, + 0xe6, 0x9e, 0xdd, 0xd2, 0x5e, 0x59, 0xcd, 0x14, 0x9c, 0xe1, 0xae, 0xd1, 0x03, 0x1d, 0x77, 0x88, + 0xe3, 0x26, 0xe1, 0xc6, 0x0f, 0xe7, 0x65, 0x67, 0x3c, 0x98, 0x7f, 0x4a, 0x5f, 0xf3, 0x5e, 0xd7, + 0x5e, 0xf3, 0xa6, 0x22, 0x3d, 0x64, 0xf4, 0x34, 0x3d, 0x7f, 0xcc, 0x8b, 0xf6, 0x7f, 0x37, 0x00, + 0xa3, 0x2a, 0x3a, 0xeb, 0x87, 0x8a, 0xe3, 0xf8, 0x6a, 0x3f, 0xd8, 0x8e, 0xe3, 0x9b, 0x08, 0xd5, + 0x1e, 0xb0, 0x0b, 0x3d, 0x1f, 0xb0, 0xbf, 0x01, 0xc3, 0x8b, 0x4d, 0x47, 0x7b, 0x56, 0x33, 0x32, + 0x9a, 0x77, 0x35, 0x42, 0xe2, 0x6b, 0x21, 0x52, 0xaf, 0xd5, 0x9b, 0x4e, 0xfa, 0x31, 0x2d, 0x66, + 0xa9, 0xbd, 0x7d, 0x0f, 0x7c, 0x9a, 0xb7, 0xef, 0x9b, 0x30, 0x7c, 0x3f, 0xa0, 0x9b, 0x9d, 0x56, + 0x8b, 0x36, 0x70, 0x5a, 0x95, 0xb8, 0xac, 0xdf, 0x09, 0xa8, 0x15, 0x22, 0x54, 0x6d, 0x40, 0x84, + 0xaa, 0x0e, 0xf0, 0x50, 0x8f, 0x01, 0xbe, 0x01, 0xa5, 0x0d, 0x4a, 0x7d, 0xec, 0xd3, 0x91, 0x58, + 0xa4, 0x6b, 0x53, 0xea, 0x5b, 0xac, 0x63, 0xb5, 0x37, 0x71, 0x81, 0xa8, 0x3d, 0xa4, 0x8f, 0xf6, + 0xf9, 0x90, 0x4e, 0x9e, 0x87, 0xd1, 0x76, 0x67, 0xbb, 0xe1, 0xd6, 0x91, 0xaf, 0x78, 0x81, 0x37, + 0x47, 0x38, 0x8c, 0xb1, 0x0d, 0xc8, 0xd7, 0x60, 0x0c, 0xef, 0x38, 0xd1, 0x94, 0x1b, 0xd7, 0xde, + 0x9f, 0xb4, 0x32, 0x2e, 0xe9, 0xd4, 0x19, 0xc8, 0xca, 0x30, 0x14, 0xd1, 0x19, 0xcd, 0xd6, 0x60, + 0x5c, 0x1f, 0xc9, 0x27, 0xf0, 0x0c, 0x15, 0x19, 0x05, 0x94, 0xca, 0xc3, 0x77, 0x8a, 0x25, 0x28, + 0x8f, 0x70, 0x73, 0x00, 0x13, 0x36, 0xa2, 0x6f, 0x32, 0xc9, 0xdd, 0xce, 0x36, 0xf5, 0x5b, 0x34, + 0xa4, 0x81, 0xb8, 0x04, 0x04, 0x66, 0xb1, 0xd2, 0x6e, 0x07, 0xc6, 0xaf, 0xe7, 0x61, 0xa8, 0xb2, + 0x55, 0xab, 0xb6, 0x76, 0x3c, 0x7c, 0x4c, 0x8a, 0xde, 0x10, 0xd4, 0xc7, 0xa4, 0xe8, 0x0d, 0x41, + 0x7d, 0x39, 0xb8, 0x96, 0x71, 0x8d, 0x43, 0x7b, 0x53, 0xe5, 0x1a, 0xa7, 0xe9, 0xf6, 0xe2, 0xe7, + 0x94, 0x42, 0x1f, 0xcf, 0x29, 0x91, 0xf6, 0xac, 0x78, 0xac, 0xf6, 0x8c, 0xbc, 0x09, 0x23, 0xd5, + 0x56, 0x48, 0x77, 0xfd, 0x78, 0xa6, 0x47, 0x57, 0xca, 0x08, 0xac, 0x8a, 0xf6, 0x0a, 0x36, 0x9b, + 0x46, 0x5c, 0x63, 0x17, 0x69, 0xea, 0x70, 0x1a, 0x71, 0xc5, 0x5e, 0xe2, 0x32, 0x2d, 0x11, 0x8d, + 0xa5, 0xc4, 0x1c, 0x91, 0x4f, 0xd6, 0x5c, 0xf8, 0x1c, 0x8f, 0xd5, 0xcc, 0xac, 0x63, 0x17, 0x26, + 0xb3, 0x9f, 0xac, 0x8d, 0xef, 0xe4, 0x61, 0xa4, 0xd2, 0x6e, 0x3f, 0xe5, 0x86, 0x43, 0x5f, 0xd6, + 0xb6, 0x57, 0x79, 0x17, 0x8a, 0xbe, 0xab, 0x2f, 0x9b, 0xa1, 0x5f, 0xc9, 0xc3, 0x44, 0x82, 0x42, + 0x6d, 0x7d, 0xae, 0x4f, 0x73, 0xa1, 0x7c, 0x9f, 0xe6, 0x42, 0x85, 0xfe, 0xcc, 0x85, 0x8a, 0x9f, + 0x66, 0xcb, 0x7c, 0x09, 0x0a, 0x95, 0x76, 0x3b, 0xf9, 0xec, 0xd8, 0x6e, 0x3f, 0xb8, 0xc1, 0xef, + 0xb3, 0x76, 0xbb, 0x6d, 0x32, 0x0c, 0x6d, 0x1f, 0x1b, 0xec, 0x73, 0x1f, 0x33, 0x5e, 0x83, 0x61, + 0xe4, 0x85, 0x46, 0x3a, 0x17, 0x00, 0x17, 0xb3, 0xb0, 0xcf, 0xd1, 0xea, 0x12, 0xcb, 0xfc, 0xff, + 0xce, 0xc1, 0x00, 0xfe, 0x7e, 0x4a, 0xe7, 0xd8, 0xbc, 0x36, 0xc7, 0xca, 0xca, 0x1c, 0xeb, 0x67, + 0x76, 0xfd, 0x6f, 0x45, 0xec, 0x2d, 0x31, 0xaf, 0x84, 0x6d, 0x4c, 0x2e, 0xc3, 0x36, 0xe6, 0x0d, + 0x50, 0x76, 0x4d, 0x55, 0x5b, 0xa4, 0x9c, 0x19, 0xea, 0x4d, 0x23, 0x46, 0x26, 0xfb, 0x49, 0x2b, + 0x99, 0x02, 0x0e, 0xc6, 0xc5, 0x64, 0x53, 0x9f, 0x88, 0x81, 0xcc, 0x0a, 0x90, 0x6a, 0x2b, 0xa0, + 0xf5, 0x8e, 0x4f, 0x6b, 0xfb, 0x6e, 0xfb, 0x01, 0xf5, 0xdd, 0x9d, 0x43, 0x71, 0xbb, 0xc7, 0x73, + 0xd9, 0x15, 0xa5, 0x56, 0xb0, 0xef, 0xb6, 0xd9, 0x55, 0xc4, 0xdd, 0x39, 0x34, 0x33, 0x68, 0xc8, + 0xbb, 0x30, 0x64, 0xd2, 0x03, 0xdf, 0x0d, 0xe5, 0xdb, 0xef, 0x78, 0x74, 0x71, 0x46, 0x28, 0xbf, + 0x18, 0xfa, 0xfc, 0x87, 0x3a, 0xfe, 0xa2, 0x9c, 0xcc, 0xf3, 0x8d, 0x8f, 0xbf, 0xf1, 0x8e, 0xc5, + 0x5f, 0x5b, 0xd9, 0xaa, 0x75, 0xdb, 0xf7, 0xc8, 0x15, 0x18, 0xc0, 0xdd, 0x53, 0xc8, 0x04, 0x68, + 0x33, 0x8d, 0x67, 0xa8, 0xba, 0xb5, 0x23, 0x06, 0x79, 0x0e, 0x20, 0x52, 0xdf, 0x07, 0x33, 0x25, + 0x3c, 0xad, 0x15, 0x48, 0x72, 0xeb, 0x1f, 0x3e, 0xc9, 0xd6, 0xff, 0xd9, 0x99, 0x86, 0xfc, 0x4a, + 0x1e, 0x2e, 0x46, 0xdb, 0xd9, 0xba, 0x5f, 0xab, 0xdc, 0x5b, 0xad, 0x3a, 0x1b, 0x42, 0xfa, 0xdf, + 0xf0, 0xbd, 0x87, 0x2e, 0xbb, 0xfd, 0x5d, 0x3f, 0x66, 0x31, 0xae, 0xf2, 0x59, 0xcb, 0x55, 0x87, + 0x79, 0xed, 0x11, 0x5d, 0x39, 0x35, 0xc4, 0x3b, 0x7f, 0xbb, 0x9d, 0xd2, 0x24, 0xae, 0x3c, 0x63, + 0xc6, 0x0c, 0xc8, 0x8f, 0xe4, 0xe0, 0x74, 0x76, 0x43, 0xc4, 0x8d, 0x70, 0x4e, 0x4a, 0x9e, 0x5d, + 0x5a, 0xbb, 0xf0, 0xd2, 0xe3, 0xa3, 0xb9, 0x8b, 0x81, 0xdd, 0x6c, 0x58, 0xae, 0xc3, 0x6b, 0x73, + 0xeb, 0xd4, 0x6a, 0x0b, 0x04, 0xad, 0xde, 0x2e, 0x35, 0x7d, 0x05, 0xe4, 0x9a, 0x9c, 0xc9, 0x2d, + 0x00, 0x94, 0xa4, 0x76, 0xc6, 0xf8, 0x7b, 0x39, 0x50, 0x66, 0x54, 0xc9, 0xa4, 0x8e, 0xeb, 0xd3, + 0x7a, 0x88, 0x3b, 0x5a, 0xe4, 0x02, 0xc0, 0x61, 0x09, 0x9b, 0x09, 0x84, 0x91, 0x77, 0x60, 0x88, + 0xeb, 0x72, 0xb8, 0x0e, 0x25, 0x9e, 0x89, 0x42, 0xef, 0xc3, 0x7d, 0x45, 0x38, 0x86, 0x3a, 0x8b, + 0x05, 0x11, 0x93, 0x6f, 0xef, 0x6c, 0x6d, 0x2e, 0x36, 0x6c, 0xb7, 0x19, 0x88, 0x7d, 0x0c, 0xbb, + 0xf5, 0xa3, 0x83, 0xd0, 0xaa, 0x23, 0x54, 0x95, 0x6f, 0x23, 0x54, 0xe3, 0xb6, 0x54, 0x3b, 0x1d, + 0x63, 0xf8, 0x33, 0x07, 0x03, 0x0f, 0xe2, 0xeb, 0xe7, 0xc2, 0xf0, 0xe3, 0xa3, 0x39, 0x3e, 0x5d, + 0x4c, 0x0e, 0x37, 0xfe, 0x6a, 0x0e, 0xc6, 0xf5, 0xf9, 0x44, 0xae, 0xc2, 0xa0, 0x30, 0xbf, 0xcf, + 0xe1, 0x35, 0x9b, 0xf5, 0xc2, 0x20, 0x37, 0xbc, 0xd7, 0xcc, 0xed, 0x05, 0x16, 0xdb, 0x89, 0x05, + 0x07, 0xa1, 0x47, 0xc2, 0x9d, 0xb8, 0xce, 0x41, 0xa6, 0x2c, 0x23, 0x06, 0x13, 0xc3, 0x82, 0x4e, + 0x23, 0x54, 0xb5, 0xaf, 0x3e, 0x42, 0x4c, 0x51, 0x62, 0x2c, 0xc2, 0x20, 0x5f, 0xc2, 0x09, 0x83, + 0x83, 0xdc, 0x09, 0x0c, 0x0e, 0x8c, 0xa3, 0x1c, 0x40, 0xad, 0xb6, 0x72, 0x97, 0x1e, 0x6e, 0xd8, + 0xae, 0x8f, 0xcf, 0x05, 0xb8, 0x5d, 0xde, 0x15, 0x8b, 0x6b, 0x54, 0x3c, 0x17, 0xf0, 0xad, 0x75, + 0x9f, 0x1e, 0x6a, 0xcf, 0x05, 0x12, 0x15, 0xf7, 0x64, 0xdf, 0x7d, 0x68, 0x87, 0x94, 0x11, 0xe6, + 0x91, 0x90, 0xef, 0xc9, 0x1c, 0x9a, 0xa0, 0x54, 0x90, 0xc9, 0x87, 0x30, 0x1e, 0xff, 0x8a, 0x1e, + 0x3d, 0xc6, 0xa3, 0x05, 0xac, 0x17, 0x2e, 0x3c, 0xf7, 0xf8, 0x68, 0x6e, 0x56, 0xe1, 0x9a, 0x7c, + 0x0e, 0x49, 0x30, 0x33, 0x7e, 0x29, 0x87, 0xef, 0x64, 0xf2, 0x03, 0x2f, 0x41, 0x31, 0x32, 0xa3, + 0x1a, 0xe5, 0x9a, 0x9a, 0x84, 0x62, 0x17, 0xcb, 0xc9, 0x45, 0x28, 0xc4, 0x5f, 0x82, 0x5b, 0xa4, + 0xfe, 0x05, 0xac, 0x94, 0xdc, 0x86, 0xa1, 0xbe, 0xda, 0x8c, 0x4b, 0x23, 0xa3, 0xad, 0x92, 0x1a, + 0x47, 0xe1, 0xce, 0xd6, 0xe6, 0xe7, 0x77, 0x14, 0x7e, 0x2a, 0x0f, 0x13, 0xac, 0x5f, 0x2b, 0x9d, + 0x70, 0xcf, 0xf3, 0xdd, 0xf0, 0xf0, 0xa9, 0xd5, 0x53, 0xbc, 0xa5, 0x09, 0x39, 0xb3, 0xf2, 0x94, + 0x51, 0xbf, 0xad, 0x2f, 0x75, 0xc5, 0xef, 0x0c, 0xc0, 0x54, 0x06, 0x15, 0x79, 0x55, 0x53, 0x25, + 0xce, 0x48, 0xf7, 0xba, 0x8f, 0x8f, 0xe6, 0x46, 0x25, 0xfa, 0x66, 0xec, 0x6e, 0x37, 0xaf, 0x3f, + 0x3a, 0xf3, 0x9e, 0x42, 0xcd, 0xa2, 0xfa, 0xe8, 0xac, 0x3f, 0x35, 0x5f, 0x81, 0x01, 0xd3, 0x6b, + 0x50, 0x69, 0x21, 0x81, 0x07, 0xbb, 0xcf, 0x00, 0xda, 0xdb, 0x18, 0x03, 0x90, 0x15, 0x18, 0x62, + 0x7f, 0xdc, 0xb3, 0xdb, 0x42, 0xeb, 0x4b, 0x22, 0x31, 0x1b, 0xa1, 0x6d, 0xb7, 0xb5, 0xab, 0x4a, + 0xda, 0x0d, 0x6a, 0x35, 0xed, 0xb6, 0x26, 0x81, 0x70, 0x44, 0x4d, 0x62, 0x2f, 0x75, 0x97, 0xd8, + 0x73, 0xc7, 0x4a, 0xec, 0x0e, 0x40, 0xcd, 0xdd, 0x6d, 0xb9, 0xad, 0xdd, 0x4a, 0x63, 0x57, 0x38, + 0x29, 0x5e, 0xe9, 0x3e, 0x0a, 0x57, 0x63, 0x64, 0x9c, 0xb8, 0xfc, 0x69, 0x86, 0xc3, 0x2c, 0xbb, + 0xa1, 0xa9, 0xa4, 0x63, 0x54, 0xb2, 0x06, 0x50, 0xa9, 0x87, 0xee, 0x43, 0x36, 0x81, 0x03, 0x61, + 0x7c, 0x2b, 0x1b, 0xbc, 0x58, 0xb9, 0x4b, 0x0f, 0x6b, 0x34, 0x8c, 0x55, 0xdc, 0x36, 0xa2, 0xb2, + 0x75, 0xa0, 0xd9, 0xc9, 0xc6, 0x1c, 0x48, 0x1b, 0x4e, 0x55, 0x1c, 0xc7, 0x65, 0x5f, 0x60, 0x37, + 0xf0, 0xcd, 0x86, 0x3a, 0xc8, 0x7a, 0x34, 0x9b, 0xf5, 0x15, 0xc1, 0xfa, 0x79, 0x3b, 0xa2, 0xb2, + 0x42, 0x4e, 0x96, 0xac, 0x26, 0x9b, 0xb1, 0xb1, 0x0e, 0xe3, 0xfa, 0xa7, 0xeb, 0xae, 0x95, 0xa3, + 0x50, 0x32, 0x6b, 0x15, 0xab, 0xb6, 0x52, 0xb9, 0x5e, 0xce, 0x91, 0x32, 0x8c, 0x8a, 0x5f, 0xf3, + 0xd6, 0xfc, 0xeb, 0x37, 0xcb, 0x79, 0x0d, 0xf2, 0xfa, 0xf5, 0xf9, 0x94, 0x47, 0xc3, 0x50, 0xb9, + 0xc4, 0x15, 0x19, 0xc6, 0xaf, 0xe6, 0xa0, 0x24, 0xdb, 0x4d, 0x6e, 0x42, 0xa1, 0x56, 0x5b, 0x49, + 0xf8, 0x20, 0xc4, 0xe7, 0x0b, 0xdf, 0x49, 0x83, 0x40, 0x35, 0x34, 0x63, 0x04, 0x8c, 0x6e, 0x73, + 0xb5, 0x26, 0xc4, 0x02, 0x49, 0x17, 0x6f, 0xdb, 0x9c, 0x2e, 0xc3, 0x30, 0xfb, 0x26, 0x14, 0xee, + 0x6c, 0x6d, 0x0a, 0x31, 0x5e, 0xd2, 0xc5, 0x3b, 0x29, 0xa7, 0xfb, 0xe8, 0x40, 0xdd, 0xdf, 0x19, + 0x81, 0x61, 0xc2, 0x88, 0x32, 0x85, 0xf9, 0x71, 0xdb, 0xf4, 0x22, 0x5f, 0x42, 0x71, 0xdc, 0x32, + 0x88, 0x29, 0x4a, 0x98, 0x74, 0xb0, 0xea, 0xd5, 0xed, 0x86, 0x38, 0xb7, 0x51, 0x3a, 0x68, 0x30, + 0x80, 0xc9, 0xe1, 0xc6, 0x6f, 0xe5, 0xa0, 0x8c, 0x32, 0x14, 0x1a, 0x9d, 0x79, 0xfb, 0xb4, 0xf5, + 0xe0, 0x3a, 0x79, 0x4d, 0x2e, 0xb6, 0x5c, 0x74, 0x69, 0x1c, 0xc0, 0xc5, 0x96, 0xd0, 0x3a, 0x8b, + 0x05, 0xa7, 0xb8, 0x6b, 0xe6, 0xfb, 0x77, 0xf3, 0x3a, 0xc6, 0x5d, 0x73, 0x0e, 0x06, 0xb0, 0x39, + 0x62, 0x5b, 0xc4, 0x96, 0x87, 0x0c, 0x60, 0x72, 0xb8, 0xb2, 0x2b, 0xfd, 0x4c, 0x3e, 0xf5, 0x0d, + 0xf3, 0x9f, 0x2b, 0x57, 0x29, 0xfd, 0xe3, 0xfa, 0xda, 0xa9, 0xdf, 0x87, 0xe9, 0x64, 0x97, 0xe0, + 0x85, 0xbe, 0x02, 0x13, 0x3a, 0x5c, 0xde, 0xed, 0xcf, 0x64, 0xd6, 0xf5, 0x60, 0xde, 0x4c, 0xe2, + 0x1b, 0xff, 0x53, 0x0e, 0x86, 0xf1, 0x4f, 0xb3, 0xd3, 0x40, 0x33, 0x88, 0xca, 0x56, 0x4d, 0x28, + 0xef, 0x54, 0x31, 0xce, 0x3e, 0x08, 0x2c, 0xa1, 0xdf, 0xd3, 0xf6, 0x97, 0x08, 0x59, 0x90, 0x72, + 0xad, 0x9c, 0x7c, 0xa1, 0x8c, 0x48, 0xb9, 0xfa, 0x2e, 0x48, 0x90, 0x0a, 0x64, 0xb4, 0x3c, 0xda, + 0xaa, 0xb1, 0xe9, 0xa7, 0xbe, 0x4b, 0x22, 0x9d, 0xd7, 0xd0, 0x2d, 0x8f, 0x38, 0x1a, 0x3e, 0x4b, + 0x6e, 0xd5, 0x2a, 0xe6, 0x9a, 0xf6, 0x2c, 0xc9, 0xda, 0xa8, 0x59, 0xa5, 0x0a, 0x24, 0xe3, 0x1f, + 0x0d, 0x27, 0x3b, 0x50, 0x1c, 0x75, 0x27, 0x5c, 0x1b, 0x6f, 0xc2, 0x40, 0xa5, 0xd1, 0xf0, 0x0e, + 0xc4, 0x2e, 0x21, 0xf5, 0x0b, 0x51, 0xff, 0xf1, 0x93, 0xcc, 0x66, 0x28, 0x9a, 0xfb, 0x07, 0x03, + 0x90, 0x45, 0x18, 0xae, 0x6c, 0xd5, 0xaa, 0xd5, 0xa5, 0xcd, 0x4d, 0x6e, 0xea, 0x5e, 0x58, 0x78, + 0x51, 0xf6, 0x8f, 0xeb, 0x3a, 0x56, 0xf2, 0x65, 0x2c, 0x96, 0xdc, 0x63, 0x3a, 0xf2, 0x36, 0xc0, + 0x1d, 0xcf, 0x6d, 0xdd, 0xa3, 0xe1, 0x9e, 0xe7, 0x88, 0x8f, 0x3f, 0xff, 0xf8, 0x68, 0x6e, 0xe4, + 0x23, 0xcf, 0x6d, 0x59, 0x4d, 0x04, 0xb3, 0xb6, 0xc7, 0x48, 0xa6, 0xf2, 0x37, 0xeb, 0xe9, 0x05, + 0x8f, 0x9b, 0x36, 0x0c, 0xc4, 0x3d, 0xbd, 0xed, 0xa5, 0xac, 0x1a, 0x24, 0x1a, 0x69, 0xc2, 0x44, + 0xad, 0xb3, 0xbb, 0x4b, 0xd9, 0xae, 0x2e, 0x34, 0x16, 0x83, 0xe2, 0x76, 0x1b, 0x05, 0x18, 0xe0, + 0x37, 0x11, 0x76, 0x3f, 0x09, 0x16, 0x5e, 0x65, 0x13, 0xf9, 0xfb, 0x47, 0x73, 0xe2, 0xc5, 0x8d, + 0x09, 0x69, 0x81, 0xa4, 0x4f, 0xeb, 0x2b, 0x92, 0xbc, 0xc9, 0x3a, 0x0c, 0xde, 0x76, 0xc3, 0x95, + 0xce, 0xb6, 0x30, 0xdd, 0x7e, 0xbe, 0xc7, 0xa2, 0xe1, 0x88, 0x5c, 0xe5, 0xbb, 0xeb, 0x86, 0x7b, + 0x1d, 0xd5, 0x8c, 0x5b, 0xb0, 0x21, 0x5b, 0x50, 0x5a, 0x74, 0xfd, 0x7a, 0x83, 0x2e, 0x56, 0xc5, + 0xa9, 0x7f, 0xb1, 0x07, 0x4b, 0x89, 0xca, 0xfb, 0xa5, 0x8e, 0xbf, 0xea, 0xae, 0x2a, 0x05, 0x48, + 0x0c, 0xf2, 0xd7, 0x73, 0xf0, 0x6c, 0xd4, 0xfa, 0xca, 0x2e, 0x6d, 0x85, 0xf7, 0xec, 0xb0, 0xbe, + 0x47, 0x7d, 0xd1, 0x4b, 0xc3, 0xbd, 0x7a, 0xe9, 0x2b, 0xa9, 0x5e, 0xba, 0x1c, 0xf7, 0x92, 0xcd, + 0x98, 0x59, 0x4d, 0xce, 0x2d, 0xdd, 0x67, 0xbd, 0x6a, 0x25, 0x16, 0x40, 0xac, 0xc3, 0x17, 0xae, + 0x3f, 0x2f, 0xf6, 0xf8, 0xe0, 0x18, 0x59, 0x98, 0xff, 0x46, 0xbf, 0x35, 0x4b, 0x9e, 0x08, 0x4a, + 0xee, 0x4a, 0x3f, 0x09, 0x2e, 0x91, 0x5c, 0xe8, 0xc1, 0x9b, 0xfb, 0x4e, 0x4c, 0xf5, 0xf0, 0x88, + 0xe2, 0xa3, 0xbd, 0x6a, 0x6f, 0x0b, 0x21, 0xe4, 0x98, 0xd1, 0x5e, 0xb5, 0xe3, 0xd1, 0x6e, 0xd8, + 0xc9, 0xd1, 0x5e, 0xb5, 0xb7, 0xc9, 0x22, 0x77, 0xee, 0xe2, 0x9e, 0x40, 0xcf, 0xf5, 0xe2, 0xb6, + 0xb8, 0xc1, 0x4f, 0xe6, 0x0c, 0x27, 0xaf, 0x0f, 0x60, 0xb8, 0xd6, 0xb6, 0xeb, 0xb4, 0xe1, 0xee, + 0x84, 0xe2, 0x51, 0xe7, 0x85, 0x1e, 0xac, 0x22, 0x5c, 0xf1, 0x20, 0x20, 0x7f, 0xaa, 0x17, 0xa4, + 0x08, 0x87, 0xb5, 0x70, 0x73, 0xe3, 0xde, 0xcc, 0xc4, 0xb1, 0x2d, 0xdc, 0xdc, 0xb8, 0x27, 0x64, + 0x8e, 0x76, 0x53, 0x93, 0x39, 0x36, 0xee, 0x19, 0xbf, 0x51, 0x80, 0x33, 0x5d, 0x68, 0xc8, 0x9a, + 0xdc, 0xa3, 0x72, 0x9a, 0x62, 0xb1, 0x0b, 0xfa, 0xd5, 0x63, 0xb7, 0xad, 0x55, 0x28, 0x2f, 0xdf, + 0x45, 0xb1, 0x96, 0xfd, 0xa4, 0xce, 0x62, 0x45, 0xee, 0xee, 0x17, 0x1e, 0x1f, 0xcd, 0x9d, 0xa3, + 0xfb, 0x68, 0x14, 0x64, 0xf3, 0x42, 0xab, 0xae, 0xf9, 0x69, 0xa5, 0x28, 0x67, 0x7f, 0x38, 0x0f, + 0x45, 0x3c, 0x69, 0x12, 0xd1, 0x29, 0x72, 0x27, 0x8a, 0x4e, 0xf1, 0x1e, 0x8c, 0x2e, 0xdf, 0xe5, + 0x97, 0xce, 0x15, 0x3b, 0xd8, 0x13, 0xfb, 0x20, 0xbe, 0xb1, 0xd1, 0x7d, 0x4b, 0xdc, 0x51, 0xf7, + 0x6c, 0x4d, 0xc8, 0xd3, 0x28, 0xc8, 0x7d, 0x98, 0xe2, 0x6d, 0x73, 0x77, 0xdc, 0x3a, 0x77, 0x72, + 0x77, 0xed, 0x86, 0xd8, 0x14, 0x2f, 0x3e, 0x3e, 0x9a, 0x9b, 0xa3, 0xfb, 0x68, 0xee, 0x24, 0xca, + 0xad, 0x00, 0x11, 0x54, 0xbb, 0xa7, 0x0c, 0x7a, 0xd5, 0xf3, 0xd6, 0x1c, 0xc6, 0x0a, 0x59, 0x6d, + 0xac, 0x6e, 0x86, 0xcb, 0x91, 0x8c, 0xbf, 0x37, 0x00, 0xb3, 0xdd, 0xf7, 0x33, 0xf2, 0x55, 0x7d, + 0x00, 0x2f, 0x1d, 0xbb, 0x03, 0x1e, 0x3f, 0x86, 0x5f, 0x83, 0xe9, 0xe5, 0x56, 0x48, 0xfd, 0xb6, + 0xef, 0x4a, 0x5f, 0xeb, 0x15, 0x2f, 0x90, 0xe6, 0x65, 0x68, 0xe7, 0x45, 0xa3, 0x72, 0xa1, 0x1f, + 0x44, 0x63, 0x37, 0x85, 0x55, 0x26, 0x07, 0xb2, 0x0c, 0xe3, 0x0a, 0xbc, 0xd1, 0xd9, 0x15, 0x27, + 0x38, 0xda, 0x2e, 0xaa, 0x3c, 0x1b, 0x1d, 0xf5, 0xa2, 0x93, 0x20, 0x9a, 0xfd, 0xa5, 0x82, 0x98, + 0x16, 0x17, 0xa1, 0x50, 0xeb, 0x6c, 0x8b, 0xe9, 0xc0, 0x45, 0x75, 0x6d, 0x5b, 0x67, 0xa5, 0xe4, + 0xcb, 0x00, 0x26, 0x6d, 0x7b, 0x81, 0x1b, 0x7a, 0xfe, 0xa1, 0x6a, 0xfe, 0xef, 0x47, 0x50, 0xdd, + 0x56, 0x53, 0x42, 0xc9, 0x0a, 0x4c, 0xc4, 0xbf, 0xd6, 0x0f, 0x5a, 0x42, 0xa9, 0x39, 0xcc, 0xb5, + 0x09, 0x31, 0xb9, 0xe5, 0xb1, 0x32, 0xf5, 0xa0, 0x4a, 0x90, 0x91, 0x79, 0x28, 0x6d, 0x79, 0xfe, + 0xfe, 0x0e, 0x1b, 0xa8, 0x62, 0x7c, 0x94, 0x1e, 0x08, 0x98, 0x7a, 0x64, 0x48, 0x3c, 0x36, 0xe7, + 0x97, 0x5b, 0x0f, 0x5d, 0xdf, 0x6b, 0x35, 0x69, 0x2b, 0x54, 0xdf, 0x1f, 0x69, 0x0c, 0xd6, 0x9c, + 0xa5, 0x62, 0x30, 0xbb, 0x33, 0x57, 0xea, 0xa1, 0xe7, 0x8b, 0xc7, 0x47, 0x3e, 0xdc, 0x0c, 0xa0, + 0x0d, 0x37, 0x03, 0xb0, 0x4e, 0x34, 0xe9, 0x8e, 0xd0, 0x9a, 0x63, 0x27, 0xfa, 0x74, 0x47, 0xf3, + 0x04, 0xa3, 0x3b, 0x4c, 0x14, 0x30, 0xe9, 0x0e, 0x5e, 0xf4, 0xb5, 0x00, 0x2a, 0x3b, 0x29, 0x15, + 0x91, 0x40, 0x33, 0x7e, 0x77, 0xb8, 0xeb, 0xbc, 0x65, 0x7b, 0xef, 0xc9, 0xe6, 0xed, 0xaa, 0xdd, + 0xc7, 0xbc, 0x7d, 0x35, 0xb2, 0x00, 0x55, 0xdd, 0x1f, 0x11, 0xa2, 0x6e, 0xfe, 0x1c, 0x67, 0xf6, + 0x97, 0x4b, 0x27, 0x99, 0x44, 0xa2, 0x93, 0xf2, 0xfd, 0x76, 0x52, 0xa1, 0xaf, 0x4e, 0x22, 0x0b, + 0x30, 0x16, 0x85, 0xe0, 0xd9, 0xb0, 0x43, 0x6d, 0x6f, 0x8a, 0xe2, 0x26, 0x59, 0x6d, 0x3b, 0x54, + 0xf7, 0x26, 0x9d, 0x84, 0xbc, 0x05, 0x23, 0xc2, 0x0c, 0x1a, 0x39, 0x0c, 0xc4, 0x86, 0x68, 0xd2, + 0x66, 0x3a, 0x41, 0xaf, 0xa2, 0xb3, 0x25, 0xb9, 0xe1, 0xb6, 0x69, 0xc3, 0x6d, 0xd1, 0x1a, 0x6a, + 0xcd, 0xc5, 0x8c, 0xc1, 0x25, 0xd9, 0x16, 0x25, 0x16, 0x57, 0xa8, 0x6b, 0xfa, 0x32, 0x8d, 0x28, + 0x39, 0x59, 0x87, 0x4e, 0x34, 0x59, 0xb9, 0x1d, 0x88, 0xbf, 0xea, 0xed, 0xba, 0xd2, 0xf2, 0x4d, + 0xda, 0x81, 0xf8, 0x56, 0x83, 0x41, 0x13, 0x76, 0x20, 0x1c, 0x95, 0xc9, 0xf5, 0xec, 0x47, 0x75, + 0x49, 0xbc, 0xd0, 0xa0, 0x5c, 0x8f, 0x44, 0xba, 0xb9, 0x21, 0x47, 0x92, 0xd5, 0x2c, 0x37, 0x6d, + 0xb7, 0x21, 0xbc, 0xdc, 0xe2, 0x6a, 0x28, 0x83, 0x26, 0xab, 0x41, 0x54, 0x52, 0x87, 0x51, 0x93, + 0xee, 0x6c, 0xf8, 0x5e, 0x48, 0xeb, 0x21, 0x75, 0x84, 0x2c, 0x23, 0xc5, 0xf9, 0x05, 0xcf, 0xe3, + 0x72, 0xda, 0xc2, 0x6b, 0xbf, 0x7b, 0x34, 0x97, 0xfb, 0xfe, 0xd1, 0x1c, 0x30, 0x10, 0xb7, 0x65, + 0x7d, 0x7c, 0x34, 0x77, 0x86, 0x8d, 0x7f, 0x5b, 0x12, 0xab, 0x47, 0x8c, 0xca, 0x94, 0xfc, 0x20, + 0xdb, 0x74, 0xa3, 0x2e, 0x89, 0x2b, 0x1b, 0xed, 0x52, 0xd9, 0xeb, 0x99, 0x95, 0xcd, 0x29, 0xbd, + 0x9d, 0x59, 0x69, 0x66, 0x25, 0xe4, 0x6d, 0x18, 0x59, 0xac, 0x2e, 0x7a, 0xad, 0x1d, 0x77, 0xb7, + 0xb6, 0x52, 0x41, 0x81, 0x48, 0xd8, 0x31, 0xd7, 0x5d, 0xab, 0x8e, 0x70, 0x2b, 0xd8, 0xb3, 0x35, + 0x5f, 0x90, 0x18, 0x9f, 0xdc, 0x86, 0x71, 0xf9, 0xd3, 0xa4, 0x3b, 0xf7, 0xcd, 0x2a, 0xca, 0x41, + 0xd2, 0x78, 0x3c, 0xe2, 0xc0, 0x3a, 0xa2, 0xe3, 0xab, 0xf2, 0x71, 0x82, 0x8c, 0x4d, 0xc6, 0x25, + 0xda, 0x6e, 0x78, 0x87, 0xac, 0x79, 0x9b, 0x2e, 0xf5, 0x51, 0xf2, 0x11, 0x93, 0xd1, 0x89, 0x4a, + 0xac, 0xd0, 0xd5, 0xb6, 0xdb, 0x04, 0x11, 0x59, 0x83, 0x49, 0x31, 0xc5, 0x1f, 0xb8, 0x81, 0xbb, + 0xed, 0x36, 0xdc, 0xf0, 0x70, 0xa6, 0x8c, 0x9c, 0x50, 0x0a, 0x91, 0xeb, 0xe2, 0x61, 0x54, 0xaa, + 0x30, 0x4b, 0x93, 0x1a, 0xbf, 0x9a, 0x87, 0x73, 0xbd, 0xe4, 0x7f, 0x52, 0xd3, 0x37, 0xb3, 0xcb, + 0x7d, 0xdc, 0x19, 0x8e, 0xdf, 0xce, 0x96, 0x61, 0x7c, 0xdd, 0xdf, 0xb5, 0x5b, 0xee, 0xb7, 0xf1, + 0x5e, 0x17, 0x99, 0xc3, 0x60, 0x67, 0x78, 0x4a, 0x89, 0x3e, 0xdb, 0x13, 0x44, 0xb3, 0x0f, 0xc5, + 0x36, 0xf7, 0x49, 0x1d, 0x2b, 0x6e, 0xc2, 0xf0, 0xa2, 0xd7, 0x0a, 0xe9, 0xa3, 0x30, 0xe1, 0x3c, + 0xc7, 0x81, 0x49, 0xe7, 0x39, 0x89, 0x6a, 0xfc, 0xbf, 0x79, 0x38, 0xdf, 0x53, 0x00, 0x26, 0x9b, + 0x7a, 0xaf, 0x5d, 0xe9, 0x47, 0x6a, 0x3e, 0xbe, 0xdb, 0xe6, 0x53, 0x96, 0x1b, 0xc7, 0xda, 0x2d, + 0xcf, 0xfe, 0x97, 0x39, 0xd1, 0x49, 0x5f, 0x80, 0x21, 0xac, 0x2a, 0xea, 0x22, 0xae, 0x1b, 0xc2, + 0x5d, 0xd8, 0xd5, 0x75, 0x43, 0x1c, 0x8d, 0xdc, 0x80, 0xd2, 0xa2, 0xdd, 0x68, 0x28, 0xae, 0x85, + 0x28, 0xd7, 0xd7, 0x11, 0x96, 0x30, 0xf4, 0x91, 0x88, 0xe4, 0x0d, 0x00, 0xfe, 0xb7, 0x72, 0x56, + 0xe0, 0x66, 0x29, 0xc8, 0x12, 0xc7, 0x85, 0x82, 0x8c, 0x41, 0xc4, 0xea, 0x5e, 0xe4, 0x03, 0xc5, + 0x83, 0x88, 0x31, 0x80, 0x16, 0x44, 0x8c, 0x01, 0x8c, 0x5f, 0x2b, 0xc0, 0x73, 0xbd, 0x6f, 0x71, + 0xe4, 0xbe, 0x3e, 0x04, 0x2f, 0xf7, 0x75, 0xf7, 0x3b, 0x7e, 0x0c, 0x64, 0x48, 0x3e, 0xde, 0x21, + 0x97, 0xd3, 0xe6, 0xc5, 0x1f, 0x1f, 0xcd, 0x29, 0xd6, 0x63, 0x77, 0x3c, 0xb7, 0xa5, 0xbc, 0x11, + 0x7c, 0x0b, 0xa0, 0x16, 0xda, 0xa1, 0x5b, 0xbf, 0xb3, 0x75, 0x57, 0x7a, 0xac, 0xdf, 0xec, 0xaf, + 0x65, 0x31, 0x1d, 0xdf, 0x57, 0x84, 0xfa, 0x1c, 0xa1, 0xd6, 0x47, 0x07, 0xfb, 0xda, 0x3d, 0x35, + 0x46, 0x9e, 0xfd, 0x0a, 0x94, 0x93, 0xa4, 0xe4, 0x12, 0x14, 0xb1, 0x01, 0x8a, 0x8d, 0x74, 0x82, + 0x03, 0x96, 0xcf, 0xde, 0x13, 0x73, 0x67, 0x19, 0xc6, 0xc5, 0xc3, 0xb4, 0xae, 0x11, 0xc3, 0xf5, + 0x2a, 0xdf, 0xb5, 0xd3, 0x5a, 0xb1, 0x04, 0x91, 0xf1, 0x67, 0x39, 0x38, 0xdb, 0xf5, 0x7e, 0x4c, + 0x36, 0xf4, 0x01, 0x7b, 0xf1, 0xb8, 0x0b, 0xf5, 0xb1, 0x63, 0x35, 0xfb, 0x13, 0x72, 0xee, 0xbf, + 0x03, 0xa3, 0xb5, 0xce, 0x76, 0xf2, 0x92, 0xc5, 0xfd, 0x97, 0x15, 0xb8, 0x7a, 0x82, 0xa9, 0xf8, + 0xec, 0xfb, 0xe5, 0xcb, 0xbb, 0x30, 0xac, 0xe0, 0x17, 0x3f, 0xfc, 0xfe, 0xc8, 0x31, 0x0a, 0xfd, + 0xd6, 0xd4, 0x4e, 0x4c, 0x10, 0x19, 0xbf, 0x92, 0xcf, 0xbe, 0xad, 0xb2, 0xbb, 0xf6, 0x09, 0x6e, + 0xab, 0xb7, 0x17, 0x37, 0x8e, 0xff, 0xf6, 0xff, 0x58, 0x7e, 0x3b, 0x3e, 0x44, 0x8a, 0x1d, 0x4f, + 0xaa, 0xf7, 0xc4, 0x43, 0xa4, 0xdc, 0x1d, 0x03, 0xfd, 0x21, 0x52, 0x22, 0x93, 0xd7, 0x61, 0x78, + 0xd5, 0xe3, 0xfe, 0xa4, 0xf2, 0x8b, 0xb9, 0xe7, 0x90, 0x04, 0xaa, 0xdb, 0x63, 0x84, 0xc9, 0xee, + 0x16, 0xfa, 0xc0, 0x4b, 0xf3, 0x6e, 0xbc, 0x5b, 0x24, 0xa6, 0x8b, 0xae, 0x04, 0xd3, 0xc9, 0x8c, + 0x9f, 0xc8, 0xc3, 0x38, 0x9f, 0xbc, 0x5c, 0x49, 0xfb, 0xd4, 0x2a, 0xc0, 0xdf, 0xd4, 0x14, 0xe0, + 0x32, 0xd4, 0x81, 0xfa, 0x69, 0x7d, 0xa9, 0xbf, 0xf7, 0x80, 0xa4, 0x69, 0x88, 0x09, 0xa3, 0x2a, + 0xb4, 0xb7, 0xe6, 0xfb, 0x7a, 0x1c, 0x15, 0x43, 0xec, 0x1d, 0xf8, 0xfc, 0x10, 0x98, 0x1a, 0x0f, + 0xe3, 0xaf, 0xe6, 0x61, 0x4c, 0x79, 0xa8, 0x7c, 0x6a, 0x3b, 0xfe, 0x2b, 0x5a, 0xc7, 0xcf, 0x44, + 0x26, 0xc9, 0xd1, 0x97, 0xf5, 0xd5, 0xef, 0x1d, 0x98, 0x4c, 0x91, 0x24, 0xdf, 0x7b, 0x73, 0xfd, + 0xbc, 0xf7, 0xbe, 0x9a, 0x76, 0xd7, 0xe7, 0x91, 0x2a, 0x23, 0x77, 0x7d, 0x35, 0x3e, 0xc0, 0x4f, + 0xe5, 0x61, 0x5a, 0xfc, 0xc2, 0x98, 0x34, 0x7c, 0xf7, 0x7e, 0x6a, 0xc7, 0xa2, 0xa2, 0x8d, 0xc5, + 0x9c, 0x3e, 0x16, 0xca, 0x07, 0x76, 0x1f, 0x12, 0xe3, 0x2f, 0x03, 0xcc, 0x74, 0x23, 0xe8, 0xdb, + 0xf3, 0x27, 0xb6, 0xab, 0xce, 0xf7, 0x61, 0x57, 0xbd, 0x0a, 0x65, 0xac, 0x4a, 0x44, 0xb0, 0x08, + 0xd8, 0x1d, 0xa0, 0x10, 0x0b, 0xdc, 0x3c, 0x70, 0x90, 0x88, 0x82, 0x11, 0x24, 0x2e, 0x01, 0x29, + 0x4a, 0xf2, 0x4b, 0x39, 0x18, 0x47, 0xe0, 0xf2, 0x43, 0xda, 0x0a, 0x91, 0x59, 0x51, 0x98, 0x01, + 0x47, 0xfa, 0xf1, 0x5a, 0xe8, 0xbb, 0xad, 0x5d, 0xa1, 0x20, 0xdf, 0x16, 0x0a, 0xf2, 0xb7, 0xb8, + 0x62, 0xff, 0x6a, 0xdd, 0x6b, 0x5e, 0xdb, 0xf5, 0xed, 0x87, 0x2e, 0x7f, 0x83, 0xb7, 0x1b, 0xd7, + 0xe2, 0x40, 0xc9, 0x6d, 0x37, 0x11, 0xfa, 0x58, 0xb0, 0xc2, 0xc7, 0x07, 0xde, 0x50, 0x8a, 0xd5, + 0x26, 0xef, 0x2a, 0x7a, 0x8b, 0xc8, 0x0f, 0xc0, 0x19, 0xee, 0x9e, 0xce, 0x44, 0x5e, 0xb7, 0xd5, + 0xf1, 0x3a, 0xc1, 0x82, 0x5d, 0xdf, 0x67, 0xe7, 0x1e, 0x77, 0x65, 0xc0, 0x2f, 0xaf, 0x47, 0x85, + 0xd6, 0x36, 0x2f, 0xd5, 0x5c, 0xb7, 0xb2, 0x19, 0x90, 0x15, 0x98, 0xe4, 0x45, 0x95, 0x4e, 0xe8, + 0xd5, 0xea, 0x76, 0xc3, 0x6d, 0xed, 0xe2, 0x9d, 0xba, 0xc4, 0xcf, 0x63, 0xbb, 0x13, 0x7a, 0x56, + 0xc0, 0xe1, 0xea, 0xd5, 0x25, 0x45, 0x44, 0xaa, 0x30, 0x61, 0x52, 0xdb, 0xb9, 0x67, 0x3f, 0x5a, + 0xb4, 0xdb, 0x76, 0x9d, 0x5d, 0x84, 0x4a, 0xf8, 0x98, 0x84, 0x77, 0x33, 0x9f, 0xda, 0x8e, 0xd5, + 0xb4, 0x1f, 0x59, 0x75, 0x51, 0xa8, 0xeb, 0xb0, 0x34, 0xba, 0x88, 0x95, 0xdb, 0x8a, 0x58, 0x0d, + 0x27, 0x59, 0xb9, 0xad, 0xee, 0xac, 0x62, 0x3a, 0xc9, 0x6a, 0xd3, 0xf6, 0x77, 0x69, 0xc8, 0x4d, + 0xd8, 0xd8, 0x7d, 0x3c, 0xa7, 0xb0, 0x0a, 0xb1, 0xcc, 0x42, 0x73, 0xb6, 0x24, 0x2b, 0x85, 0x8e, + 0xcd, 0xbc, 0x2d, 0xdf, 0x0d, 0xa9, 0xfa, 0x85, 0x23, 0xd8, 0x2c, 0xec, 0x7f, 0x34, 0xfe, 0xeb, + 0xf6, 0x89, 0x29, 0xca, 0x98, 0x9b, 0xf2, 0x91, 0xa3, 0x29, 0x6e, 0xd9, 0x5f, 0x99, 0xa2, 0x8c, + 0xb8, 0xa9, 0xdf, 0x39, 0x86, 0xdf, 0xa9, 0x70, 0xeb, 0xf2, 0xa1, 0x29, 0x4a, 0xb2, 0xc6, 0x3a, + 0x2d, 0xa4, 0x2d, 0x36, 0xa3, 0x85, 0x09, 0xdf, 0x38, 0x36, 0xed, 0x05, 0x61, 0x87, 0x52, 0xf6, + 0x65, 0xb1, 0x95, 0x61, 0xd0, 0x97, 0x24, 0x26, 0x7f, 0x01, 0x26, 0xee, 0x07, 0xf4, 0x56, 0x75, + 0xa3, 0x26, 0x1d, 0xf2, 0xf1, 0xb6, 0x3d, 0x3e, 0x7f, 0xfd, 0x98, 0x4d, 0xe7, 0xaa, 0x4a, 0x83, + 0xf1, 0x8a, 0xf9, 0xb8, 0x75, 0x02, 0x6a, 0xed, 0xb8, 0xed, 0x20, 0x0a, 0x0d, 0xa2, 0x8e, 0x5b, + 0xa2, 0x2a, 0x63, 0x05, 0x26, 0x53, 0x6c, 0xc8, 0x38, 0x00, 0x03, 0x5a, 0xf7, 0xd7, 0x6a, 0xcb, + 0x9b, 0xe5, 0x67, 0x48, 0x19, 0x46, 0xf1, 0xf7, 0xf2, 0x5a, 0x65, 0x61, 0x75, 0x79, 0xa9, 0x9c, + 0x23, 0x93, 0x30, 0x86, 0x90, 0xa5, 0x6a, 0x8d, 0x83, 0xf2, 0x3c, 0x5a, 0xa5, 0x59, 0xe6, 0x4b, + 0x37, 0x64, 0x0b, 0x00, 0xcf, 0x14, 0xe3, 0x6f, 0xe4, 0xe1, 0xac, 0x3c, 0x56, 0x68, 0x78, 0xe0, + 0xf9, 0xfb, 0x6e, 0x6b, 0xf7, 0x29, 0x3f, 0x1d, 0x6e, 0x69, 0xa7, 0xc3, 0x0b, 0x89, 0x93, 0x3a, + 0xf1, 0x95, 0x3d, 0x8e, 0x88, 0xff, 0xa5, 0x04, 0xe7, 0x7b, 0x52, 0x91, 0xaf, 0xb2, 0xd3, 0xdc, + 0xa5, 0xad, 0xb0, 0xea, 0x34, 0xe8, 0xa6, 0xdb, 0xa4, 0x5e, 0x27, 0x14, 0x26, 0xa3, 0x17, 0xf1, + 0x82, 0x8b, 0x85, 0x96, 0xeb, 0x34, 0xa8, 0x15, 0xf2, 0x62, 0x6d, 0xba, 0xa5, 0xa9, 0x19, 0xcb, + 0x28, 0x76, 0x7a, 0xb5, 0x15, 0x52, 0xff, 0x21, 0x1a, 0xa7, 0x44, 0x2c, 0xf7, 0x29, 0x6d, 0x5b, + 0x36, 0x2b, 0xb5, 0x5c, 0x51, 0xac, 0xb3, 0x4c, 0x51, 0x93, 0x5b, 0x0a, 0xcb, 0x45, 0x26, 0x0e, + 0xdf, 0xb3, 0x1f, 0x89, 0xd7, 0x72, 0x11, 0xd6, 0x28, 0x62, 0xc9, 0xbd, 0x8d, 0x9a, 0xf6, 0x23, + 0x33, 0x4d, 0x42, 0x3e, 0x84, 0x53, 0xe2, 0x00, 0x12, 0xde, 0xa2, 0xf2, 0x8b, 0xb9, 0x2f, 0xea, + 0x4b, 0x8f, 0x8f, 0xe6, 0xce, 0xc8, 0x20, 0x4e, 0xd2, 0x3f, 0x38, 0xeb, 0xab, 0xb3, 0xb9, 0x90, + 0x4d, 0x76, 0x20, 0x27, 0xba, 0xe3, 0x1e, 0x0d, 0x02, 0x7b, 0x57, 0xbe, 0xac, 0x73, 0xfb, 0x7a, + 0xa5, 0x33, 0xad, 0x26, 0x2f, 0x37, 0xbb, 0x52, 0x92, 0x15, 0x18, 0xdf, 0xa2, 0xdb, 0xea, 0xf8, + 0x0c, 0x46, 0x5b, 0x55, 0xf9, 0x80, 0x6e, 0x77, 0x1f, 0x9c, 0x04, 0x1d, 0x71, 0x51, 0x61, 0xf6, + 0xe8, 0x70, 0xd5, 0x0d, 0x42, 0xda, 0xa2, 0x3e, 0x46, 0x21, 0x18, 0xc2, 0xcd, 0x60, 0x26, 0x96, + 0x90, 0xf5, 0xf2, 0x85, 0xe7, 0x1f, 0x1f, 0xcd, 0x9d, 0xe7, 0xfe, 0x24, 0x0d, 0x01, 0xb7, 0x12, + 0x91, 0xc7, 0xd3, 0x5c, 0xc9, 0x37, 0x61, 0xc2, 0xf4, 0x3a, 0xa1, 0xdb, 0xda, 0xad, 0x85, 0xbe, + 0x1d, 0xd2, 0x5d, 0x7e, 0x20, 0xc5, 0xe1, 0x0e, 0x12, 0xa5, 0xe2, 0xad, 0x85, 0x03, 0xad, 0x40, + 0x40, 0xb5, 0x13, 0x41, 0x27, 0x20, 0xdf, 0x80, 0x71, 0xee, 0x27, 0x18, 0x55, 0x30, 0xac, 0x45, + 0x4d, 0xd5, 0x0b, 0x1f, 0x5c, 0xe7, 0x17, 0x54, 0xee, 0x6f, 0x98, 0x55, 0x41, 0x82, 0x1b, 0xf9, + 0x40, 0x74, 0xd6, 0x86, 0xdb, 0xda, 0x8d, 0xa6, 0x31, 0x60, 0xcf, 0xbf, 0x16, 0x77, 0x49, 0x9b, + 0x35, 0x57, 0x4e, 0xe3, 0x2e, 0x96, 0x1a, 0x69, 0x3e, 0x24, 0x84, 0xf3, 0x95, 0x20, 0x70, 0x83, + 0x50, 0x18, 0x56, 0x2f, 0x3f, 0xa2, 0xf5, 0x0e, 0x43, 0xde, 0xf2, 0xfc, 0x7d, 0xea, 0x73, 0xd3, + 0xbe, 0x81, 0x85, 0xab, 0x8f, 0x8f, 0xe6, 0x5e, 0xb6, 0x11, 0xd1, 0x12, 0xb6, 0xd8, 0x16, 0x95, + 0xa8, 0xd6, 0x01, 0xc7, 0x55, 0xbe, 0xa1, 0x37, 0x53, 0xf2, 0x0d, 0x38, 0xbd, 0x68, 0x07, 0xb4, + 0xda, 0x0a, 0x68, 0x2b, 0x70, 0x43, 0xf7, 0x21, 0x15, 0x9d, 0x8a, 0x87, 0x5f, 0x09, 0x63, 0xb4, + 0x1b, 0x75, 0x3b, 0x60, 0x0b, 0x33, 0x42, 0xb1, 0xc4, 0xa0, 0x28, 0xd5, 0x74, 0xe1, 0x62, 0x1c, + 0xe5, 0xa0, 0x9c, 0xec, 0x76, 0xf2, 0x35, 0x18, 0xe6, 0x26, 0x09, 0x34, 0xd8, 0x13, 0x2e, 0x6e, + 0xf2, 0x85, 0x3b, 0x82, 0xeb, 0x44, 0xc2, 0x29, 0x81, 0x1b, 0x3c, 0x50, 0xf5, 0xbd, 0x16, 0x9d, + 0x12, 0x24, 0x11, 0x71, 0x60, 0x94, 0xf7, 0x2c, 0xc5, 0xb8, 0x24, 0xc2, 0x32, 0xed, 0x79, 0x75, + 0x26, 0x8b, 0xa2, 0x04, 0x7f, 0x54, 0x79, 0x8b, 0xf1, 0xe3, 0x08, 0x5a, 0x15, 0x1a, 0xd7, 0x05, + 0x80, 0x92, 0x24, 0x34, 0xce, 0xc2, 0x99, 0x2e, 0x6d, 0x36, 0x1e, 0xe2, 0x33, 0x58, 0x97, 0x1a, + 0xc9, 0xd7, 0x60, 0x1a, 0x09, 0x17, 0xbd, 0x56, 0x8b, 0xd6, 0x43, 0xdc, 0x3a, 0xa4, 0xea, 0xa8, + 0xc0, 0xdf, 0x5a, 0xf9, 0xf7, 0xd6, 0x23, 0x04, 0x2b, 0xa9, 0x41, 0xca, 0xe4, 0x60, 0xfc, 0x5c, + 0x1e, 0x66, 0xc4, 0x6e, 0x64, 0xd2, 0xba, 0xe7, 0x3b, 0x4f, 0xff, 0xe9, 0xb7, 0xac, 0x9d, 0x7e, + 0x17, 0x23, 0x9f, 0xe6, 0xac, 0x8f, 0xec, 0x71, 0xf8, 0xfd, 0x4a, 0x0e, 0xce, 0xf5, 0x22, 0x62, + 0xbd, 0x13, 0xc5, 0x61, 0x19, 0x4e, 0xc5, 0x5b, 0x69, 0xc3, 0x14, 0x0e, 0xe8, 0xe2, 0x1e, 0xad, + 0xef, 0x07, 0x2b, 0x5e, 0x10, 0xa2, 0x61, 0x6c, 0xbe, 0xcb, 0x43, 0xcd, 0xab, 0x99, 0x0f, 0x35, + 0xa7, 0xf9, 0x2c, 0xab, 0x23, 0x0f, 0x1e, 0x29, 0x66, 0x9f, 0x1e, 0x06, 0x66, 0x16, 0x6b, 0x34, + 0x72, 0xac, 0x74, 0xc2, 0xbd, 0x0d, 0x9f, 0xee, 0x50, 0x9f, 0xb6, 0xea, 0xf4, 0x73, 0x66, 0xe4, + 0xa8, 0x7f, 0x5c, 0x5f, 0xda, 0x86, 0x5f, 0x19, 0x85, 0xe9, 0x2c, 0x32, 0xd6, 0x2f, 0xca, 0x05, + 0x37, 0x99, 0xee, 0xe5, 0x47, 0x73, 0x30, 0x5a, 0xa3, 0x75, 0xaf, 0xe5, 0xdc, 0xc2, 0xe7, 0x70, + 0xd1, 0x3b, 0x16, 0x3f, 0xe0, 0x19, 0xdc, 0xda, 0x49, 0xbc, 0x93, 0x7f, 0x7c, 0x34, 0xf7, 0x5e, + 0x7f, 0xf7, 0xca, 0xba, 0x87, 0x7e, 0xc9, 0x21, 0x86, 0x23, 0x8d, 0xaa, 0x40, 0xcd, 0xb6, 0x56, + 0x29, 0x59, 0x80, 0x31, 0xb1, 0x5c, 0x3d, 0x35, 0x0c, 0x0f, 0x77, 0xfb, 0x96, 0x05, 0xa9, 0xb8, + 0x63, 0x1a, 0x09, 0xb9, 0x01, 0x85, 0xfb, 0xf3, 0xb7, 0xc4, 0x18, 0xc8, 0x80, 0xae, 0xf7, 0xe7, + 0x6f, 0xa1, 0xea, 0x8a, 0x5d, 0x07, 0xc6, 0x3a, 0xf3, 0xda, 0x0b, 0xf5, 0xfd, 0xf9, 0x5b, 0xe4, + 0x2f, 0xc1, 0xa9, 0x25, 0x37, 0x10, 0x55, 0x70, 0x73, 0x5b, 0x07, 0xdd, 0x4b, 0x06, 0xbb, 0xcc, + 0xde, 0x2f, 0x65, 0xce, 0xde, 0xe7, 0x9d, 0x88, 0x89, 0xc5, 0x6d, 0x79, 0x9d, 0x64, 0xb8, 0xa1, + 0xec, 0x7a, 0xc8, 0x47, 0x30, 0x8e, 0xaa, 0x57, 0xb4, 0x40, 0xc6, 0xf0, 0x88, 0x43, 0x5d, 0x6a, + 0xfe, 0x42, 0x66, 0xcd, 0xb3, 0xa8, 0xc9, 0xb5, 0xd0, 0x8e, 0x19, 0x43, 0x29, 0x6a, 0x37, 0x74, + 0x8d, 0x33, 0xb9, 0x03, 0x13, 0x42, 0x54, 0x5a, 0xdf, 0xd9, 0xdc, 0xa3, 0x4b, 0xf6, 0xa1, 0x78, + 0x5c, 0xc6, 0xdb, 0x97, 0x90, 0xaf, 0x2c, 0x6f, 0xc7, 0x0a, 0xf7, 0xa8, 0xe5, 0xd8, 0x9a, 0x50, + 0x91, 0x20, 0x24, 0x3f, 0x08, 0x23, 0xab, 0x5e, 0x9d, 0x49, 0xc9, 0xb8, 0x33, 0xf0, 0xf7, 0xe6, + 0xf7, 0x31, 0xa1, 0x08, 0x07, 0x27, 0x44, 0x9f, 0x8f, 0x8f, 0xe6, 0xde, 0x3c, 0xe9, 0xa4, 0x51, + 0x2a, 0x30, 0xd5, 0xda, 0xc8, 0x22, 0x94, 0xb6, 0xe8, 0x36, 0xfb, 0xda, 0x64, 0xb2, 0x01, 0x09, + 0x16, 0xe6, 0x24, 0xe2, 0x97, 0x66, 0x4e, 0x22, 0x60, 0xc4, 0x87, 0x49, 0xec, 0x9f, 0x0d, 0x3b, + 0x08, 0x0e, 0x3c, 0xdf, 0xc1, 0xa8, 0xb2, 0xdd, 0x9e, 0xb2, 0xe7, 0x33, 0x3b, 0xff, 0x1c, 0xef, + 0xfc, 0xb6, 0xc2, 0x41, 0x15, 0xf6, 0x52, 0xec, 0xc9, 0x37, 0x61, 0xdc, 0xa4, 0xdf, 0xea, 0xb8, + 0x3e, 0xbd, 0x77, 0xab, 0x82, 0xab, 0x72, 0x54, 0x73, 0xd2, 0xd1, 0x0b, 0xb9, 0x44, 0xe9, 0x73, + 0x98, 0xd4, 0x16, 0x59, 0xcd, 0x1d, 0x5b, 0x7f, 0x2d, 0x50, 0x49, 0xc8, 0x06, 0x8c, 0x2c, 0xd1, + 0x87, 0x6e, 0x9d, 0xa2, 0x2b, 0x81, 0x30, 0xe5, 0x8b, 0xa2, 0xa5, 0xc7, 0x25, 0x5c, 0x6f, 0xe2, + 0x20, 0x80, 0x3b, 0x26, 0xe8, 0xd6, 0x62, 0x11, 0x22, 0xb9, 0x09, 0x85, 0xea, 0xd2, 0x86, 0xb0, + 0xe4, 0x93, 0x16, 0xfa, 0x55, 0x67, 0x43, 0xc6, 0x96, 0x46, 0xe3, 0x0f, 0xd7, 0xd1, 0xec, 0x00, + 0xab, 0x4b, 0x1b, 0x64, 0x07, 0xc6, 0xb0, 0x03, 0x56, 0xa8, 0xcd, 0xfb, 0x76, 0xa2, 0x4b, 0xdf, + 0x5e, 0xcd, 0xec, 0xdb, 0x19, 0xde, 0xb7, 0x7b, 0x82, 0x5a, 0x0b, 0x96, 0xab, 0xb2, 0x65, 0xe2, + 0xa7, 0x08, 0xe0, 0x2d, 0xc3, 0xc5, 0x6e, 0xae, 0xe2, 0xe3, 0xb6, 0x10, 0x3f, 0x65, 0xbc, 0xef, + 0x28, 0xe6, 0x6c, 0x57, 0x43, 0xe1, 0x34, 0x1f, 0xf2, 0x15, 0x28, 0xae, 0xef, 0x87, 0xf6, 0xcc, + 0xa4, 0xd6, 0x8f, 0x0c, 0x24, 0x3f, 0x1f, 0x35, 0x86, 0xde, 0xbe, 0x16, 0x90, 0x02, 0x69, 0xc8, + 0x3c, 0x0c, 0x6d, 0x54, 0x1f, 0xd4, 0x1a, 0x5e, 0x38, 0x43, 0xa2, 0x3b, 0x0d, 0x69, 0xbb, 0x0f, + 0xad, 0xa0, 0xe1, 0xe9, 0x49, 0x00, 0x24, 0x22, 0x1b, 0xbe, 0x15, 0xdb, 0x77, 0x0e, 0x6c, 0x1f, + 0x3d, 0xc0, 0xa6, 0xb4, 0x6a, 0x95, 0x12, 0x3e, 0x7c, 0x7b, 0x02, 0x90, 0x70, 0x0b, 0x53, 0x59, + 0x08, 0x6d, 0xc0, 0xa4, 0x98, 0x26, 0xe2, 0xd3, 0xee, 0xdd, 0xaa, 0x18, 0xff, 0x41, 0x0e, 0x37, + 0x4c, 0xf2, 0x32, 0xfa, 0xac, 0x47, 0x0f, 0xbc, 0xa8, 0xd7, 0xb4, 0xdb, 0x89, 0x10, 0x8b, 0x1c, + 0x85, 0xbc, 0x0a, 0x83, 0xb7, 0xec, 0x3a, 0x0d, 0xe5, 0xc3, 0x0e, 0x22, 0xef, 0x20, 0x44, 0x55, + 0x82, 0x72, 0x1c, 0x26, 0xcb, 0xf1, 0x89, 0x54, 0x89, 0xb3, 0xaf, 0x2d, 0x56, 0xe4, 0xbb, 0x0e, + 0xca, 0x72, 0x62, 0x02, 0x2a, 0xe9, 0xd9, 0x12, 0x36, 0x90, 0x99, 0x1c, 0x8c, 0x3f, 0xc9, 0xc5, + 0x3b, 0x00, 0x79, 0x09, 0x8a, 0xe6, 0x46, 0xd4, 0x7e, 0xee, 0x0d, 0x95, 0x68, 0x3e, 0x22, 0x90, + 0x0f, 0xe0, 0x94, 0xc2, 0x27, 0x65, 0x90, 0xf9, 0x22, 0xba, 0xeb, 0x28, 0x2d, 0xc9, 0xb6, 0xca, + 0xcc, 0xe6, 0x81, 0x82, 0x6b, 0x5c, 0xb0, 0x44, 0x5b, 0x2e, 0xe7, 0xad, 0x7c, 0xac, 0xca, 0xdb, + 0x41, 0x84, 0xe4, 0xc7, 0x66, 0x71, 0xe0, 0x1e, 0x3b, 0xc6, 0x6f, 0xe6, 0xb4, 0x95, 0x1d, 0xa5, + 0xb9, 0xca, 0x1d, 0x93, 0xe6, 0xea, 0x0d, 0x80, 0x4a, 0x27, 0xf4, 0x96, 0x5b, 0xbe, 0xd7, 0xe0, + 0xda, 0x05, 0x11, 0x65, 0x14, 0x75, 0xa6, 0x14, 0xc1, 0x9a, 0x63, 0x41, 0x84, 0x9c, 0x69, 0xbb, + 0x5a, 0xf8, 0xa4, 0xb6, 0xab, 0xc6, 0xef, 0xe5, 0xb4, 0xb9, 0xcd, 0x24, 0x32, 0xb9, 0x3c, 0x14, + 0xd3, 0x82, 0xf4, 0xf2, 0x88, 0x17, 0xc7, 0xff, 0x3f, 0x07, 0xa7, 0xb9, 0x11, 0xe8, 0x5a, 0xa7, + 0xb9, 0x4d, 0xfd, 0x07, 0x76, 0xc3, 0x75, 0xb8, 0x47, 0x1a, 0x17, 0x36, 0x2f, 0xa7, 0x17, 0x4a, + 0x36, 0x3e, 0xbf, 0xc0, 0x71, 0xa3, 0x54, 0xab, 0x85, 0x85, 0xd6, 0xc3, 0xa8, 0x54, 0xbd, 0xc0, + 0x65, 0xd3, 0x1b, 0xbf, 0x9a, 0x83, 0xe7, 0x8f, 0xad, 0x85, 0x5c, 0x83, 0x21, 0x19, 0xde, 0x35, + 0x87, 0x1d, 0x8f, 0x06, 0x59, 0xe9, 0xd0, 0xae, 0x12, 0x8b, 0x7c, 0x1d, 0x4e, 0xa9, 0xac, 0x36, + 0x7d, 0xdb, 0x55, 0x83, 0xa8, 0x66, 0xb4, 0x3a, 0x64, 0x28, 0x49, 0xc9, 0x28, 0x9b, 0x89, 0xf1, + 0x7f, 0xe5, 0x94, 0xc4, 0x77, 0x4f, 0xa9, 0xbc, 0x7c, 0x53, 0x93, 0x97, 0x65, 0xb4, 0xa0, 0xe8, + 0xab, 0x58, 0x59, 0xe6, 0x1d, 0x67, 0x42, 0x31, 0x2c, 0x44, 0xc0, 0x77, 0xf2, 0x30, 0x72, 0x3f, + 0xa0, 0x3e, 0x7f, 0xe0, 0xfc, 0x7c, 0x45, 0x85, 0x89, 0xbe, 0xab, 0xaf, 0xb8, 0x1d, 0x7f, 0x94, + 0x43, 0xc5, 0xb7, 0x4a, 0xc1, 0x7a, 0x43, 0x49, 0x76, 0x81, 0xbd, 0x81, 0x69, 0x2e, 0x10, 0xca, + 0x63, 0x7b, 0xac, 0xea, 0x79, 0x6f, 0x30, 0xf9, 0xd1, 0x2a, 0x79, 0x0f, 0x06, 0xee, 0xa3, 0x1a, + 0x4f, 0xf7, 0x3e, 0x8e, 0xf8, 0x63, 0x21, 0xdf, 0xa4, 0x3b, 0xec, 0x4f, 0xf5, 0x8c, 0xc1, 0x32, + 0x52, 0x83, 0xa1, 0x45, 0x9f, 0x62, 0x1a, 0xbb, 0x62, 0xff, 0x1e, 0x74, 0x75, 0x4e, 0x92, 0xf4, + 0xa0, 0x13, 0x9c, 0x8c, 0x9f, 0xcd, 0x03, 0x89, 0xbf, 0x11, 0xe3, 0xbf, 0x07, 0x4f, 0xed, 0xa0, + 0xbf, 0xab, 0x0d, 0xfa, 0xf9, 0xd4, 0xa0, 0xf3, 0xcf, 0xeb, 0x6b, 0xec, 0x7f, 0x2b, 0x07, 0xa7, + 0xb3, 0x09, 0xc9, 0x45, 0x18, 0x5c, 0xdf, 0xdc, 0x90, 0x0e, 0xec, 0xe2, 0x53, 0xbc, 0x36, 0xde, + 0xcb, 0x4d, 0x51, 0x44, 0x5e, 0x83, 0xc1, 0xaf, 0x9a, 0x8b, 0xec, 0x1c, 0x52, 0x62, 0xad, 0x7e, + 0xcb, 0xb7, 0xea, 0xfa, 0x51, 0x24, 0x90, 0xd4, 0xb1, 0x2d, 0x3c, 0xb1, 0xb1, 0xfd, 0xa9, 0x3c, + 0x4c, 0x54, 0xea, 0x75, 0x1a, 0x04, 0x4c, 0xc8, 0xa1, 0x41, 0xf8, 0xd4, 0x0e, 0x6c, 0xb6, 0x6b, + 0xba, 0xf6, 0x6d, 0x7d, 0x8d, 0xea, 0xef, 0xe4, 0xe0, 0x94, 0xa4, 0x7a, 0xe8, 0xd2, 0x83, 0xcd, + 0x3d, 0x9f, 0x06, 0x7b, 0x5e, 0xc3, 0xe9, 0x3b, 0xa0, 0x33, 0x13, 0xf4, 0x30, 0x4a, 0xa3, 0xfa, + 0xda, 0xbd, 0x83, 0x10, 0x4d, 0xd0, 0xe3, 0x91, 0x1c, 0xaf, 0xc1, 0x50, 0xa5, 0xdd, 0xf6, 0xbd, + 0x87, 0x7c, 0xd9, 0x8f, 0x09, 0x87, 0x42, 0x0e, 0xd2, 0x1c, 0x10, 0x39, 0x88, 0x35, 0x63, 0x89, + 0xb6, 0x78, 0x2c, 0x9d, 0x31, 0xde, 0x0c, 0x87, 0xb6, 0x54, 0x19, 0x16, 0xcb, 0x8d, 0x1a, 0x90, + 0x0d, 0xdf, 0x6b, 0x7a, 0x21, 0x75, 0xf8, 0xf7, 0xa0, 0xdf, 0xe6, 0xb1, 0x41, 0x40, 0x36, 0xdd, + 0xb0, 0xa1, 0x05, 0x01, 0x09, 0x19, 0xc0, 0xe4, 0x70, 0xe3, 0x7f, 0x1f, 0x80, 0x51, 0xb5, 0x77, + 0x88, 0xc1, 0xa3, 0xb4, 0x7a, 0xbe, 0xea, 0x3c, 0x6c, 0x23, 0xc4, 0x14, 0x25, 0xb1, 0xcf, 0x7d, + 0xfe, 0x58, 0x9f, 0xfb, 0x2d, 0x18, 0xdb, 0xf0, 0xbd, 0xb6, 0x17, 0x50, 0x87, 0xa7, 0x37, 0xe5, + 0x5b, 0xe1, 0x94, 0x72, 0xc7, 0x63, 0x03, 0x89, 0xef, 0x84, 0xa8, 0xe1, 0x68, 0x0b, 0x6c, 0x2b, + 0x99, 0xfc, 0x54, 0xe7, 0xc3, 0x4d, 0x10, 0xec, 0x40, 0x84, 0xcc, 0x8a, 0x4c, 0x10, 0x18, 0x44, + 0x37, 0x41, 0x60, 0x10, 0x75, 0xad, 0x0d, 0x3c, 0xa9, 0xb5, 0x46, 0x7e, 0x36, 0x07, 0x23, 0x95, + 0x56, 0x4b, 0xf8, 0xf2, 0x1f, 0xe3, 0xcc, 0xf8, 0x75, 0x61, 0x85, 0xf0, 0xe6, 0x27, 0xb2, 0x42, + 0x40, 0xb9, 0x25, 0x40, 0x49, 0x35, 0xae, 0x50, 0xbd, 0xe5, 0x28, 0xed, 0x20, 0x6f, 0x42, 0x39, + 0x9a, 0xe4, 0xd5, 0x96, 0x43, 0x1f, 0xd1, 0x60, 0x66, 0xe8, 0x42, 0xe1, 0xf2, 0x98, 0x08, 0x96, + 0xa7, 0x4a, 0xa6, 0x49, 0x44, 0xb2, 0x09, 0x60, 0x47, 0xb3, 0x2b, 0x91, 0x58, 0x26, 0x3d, 0xfd, + 0x84, 0xf4, 0x8c, 0xbf, 0xf1, 0xa1, 0x47, 0x95, 0x9e, 0x63, 0x3e, 0xa4, 0x09, 0x13, 0x3c, 0xab, + 0x0b, 0x66, 0x7b, 0xc5, 0x98, 0xb0, 0x70, 0xec, 0x38, 0xbc, 0x24, 0x74, 0x55, 0xcf, 0x8a, 0x5c, + 0x31, 0x98, 0x40, 0xd6, 0xca, 0x08, 0x10, 0x9b, 0xe4, 0xcd, 0x43, 0x13, 0x9a, 0x67, 0xd2, 0xed, + 0xe5, 0x93, 0xfe, 0xa7, 0x72, 0x70, 0x5a, 0x9d, 0xf4, 0xb5, 0xce, 0x76, 0xd3, 0xc5, 0xbb, 0x20, + 0xb9, 0x0a, 0xc3, 0x62, 0x4e, 0x46, 0x97, 0xa8, 0x74, 0x68, 0xdb, 0x18, 0x85, 0x2c, 0xb3, 0x69, + 0xc8, 0x78, 0x08, 0xa9, 0x7b, 0x2a, 0xb1, 0x4f, 0xb1, 0xa2, 0x38, 0x63, 0x98, 0x8f, 0xbf, 0xf5, + 0xf9, 0xc9, 0x20, 0xc6, 0x3b, 0x30, 0xa9, 0x8f, 0x44, 0x8d, 0x86, 0xe4, 0x0a, 0x0c, 0xc9, 0xe1, + 0xcb, 0x65, 0x0f, 0x9f, 0x2c, 0x37, 0xb6, 0x80, 0xa4, 0xe8, 0x03, 0x34, 0x17, 0xa2, 0xa1, 0x34, + 0x67, 0x93, 0x8f, 0x75, 0x29, 0xc4, 0x28, 0x85, 0xf6, 0x88, 0x66, 0xbf, 0xca, 0x48, 0x8d, 0x3f, + 0x19, 0x87, 0xa9, 0x8c, 0x3d, 0xf7, 0x18, 0x99, 0x68, 0x4e, 0xdf, 0x20, 0x86, 0x23, 0x5f, 0x68, + 0xb9, 0x2d, 0xbc, 0x23, 0xb3, 0x1d, 0xf7, 0xd8, 0x0e, 0x7a, 0xa5, 0x40, 0xfe, 0x2c, 0xe4, 0x22, + 0x35, 0x5c, 0xc1, 0xc0, 0x13, 0x0b, 0x57, 0xb0, 0x00, 0x63, 0xe2, 0xab, 0xc4, 0x76, 0x35, 0x18, + 0x6b, 0x73, 0x7d, 0x5e, 0x60, 0xa5, 0xb6, 0x2d, 0x9d, 0x84, 0xf3, 0x08, 0xbc, 0xc6, 0x43, 0x2a, + 0x78, 0x0c, 0xa9, 0x3c, 0xb0, 0x20, 0x93, 0x87, 0x42, 0x42, 0xfe, 0x1d, 0x4c, 0x72, 0x81, 0x10, + 0x75, 0xcf, 0x2a, 0xf5, 0xda, 0xb3, 0x9c, 0x27, 0xb3, 0x67, 0x9d, 0x97, 0x6d, 0xcc, 0xde, 0xbb, + 0x32, 0x9a, 0x45, 0x7e, 0x39, 0x07, 0x93, 0xdc, 0x67, 0x5e, 0x6d, 0x6c, 0x4f, 0x3f, 0xe8, 0xfa, + 0x93, 0x69, 0xec, 0x39, 0x11, 0x9f, 0x3e, 0xbb, 0xad, 0xe9, 0x46, 0x91, 0x1f, 0x00, 0x88, 0x56, + 0x54, 0x30, 0x03, 0xb8, 0xd4, 0xce, 0x65, 0xec, 0x02, 0x11, 0x52, 0x1c, 0x4b, 0x37, 0x8c, 0xe8, + 0xb4, 0xd4, 0x26, 0x11, 0x94, 0xfc, 0x25, 0x98, 0x66, 0xeb, 0x25, 0x82, 0x88, 0x08, 0x1f, 0x33, + 0x23, 0x58, 0xcb, 0x17, 0xbb, 0xcb, 0x44, 0x57, 0xb3, 0xc8, 0x78, 0xe4, 0xbf, 0x38, 0xa5, 0x5b, + 0xa8, 0x3a, 0x03, 0x67, 0x56, 0x84, 0x21, 0x73, 0xb0, 0xf5, 0x3c, 0xde, 0x6d, 0x97, 0xfd, 0xed, + 0xac, 0x5c, 0x0b, 0x7c, 0x7f, 0x0b, 0x74, 0x67, 0x36, 0x04, 0x91, 0xaf, 0x02, 0x89, 0x9c, 0xcd, + 0x39, 0x8c, 0xca, 0x58, 0xb8, 0x5c, 0xb5, 0x1b, 0x3b, 0xad, 0xfb, 0xb2, 0x58, 0x9d, 0x24, 0x69, + 0x62, 0x42, 0x61, 0x5a, 0x7c, 0x34, 0x83, 0xca, 0x24, 0x1a, 0xc1, 0xcc, 0xb8, 0x16, 0x3f, 0x25, + 0x2e, 0x89, 0x73, 0xbf, 0x29, 0x99, 0x38, 0x34, 0x95, 0x53, 0x16, 0x3b, 0x72, 0x13, 0x86, 0xd1, + 0xa3, 0x6c, 0x45, 0x1a, 0x41, 0x09, 0x83, 0x0c, 0xf4, 0x3d, 0xb3, 0xf6, 0x74, 0x53, 0xa6, 0x18, + 0x95, 0x5d, 0x07, 0x96, 0xfc, 0x43, 0xb3, 0xd3, 0x42, 0x05, 0xac, 0xd0, 0x77, 0x38, 0xfe, 0xa1, + 0xe5, 0x77, 0x74, 0x97, 0x43, 0x44, 0x22, 0xdf, 0x84, 0x91, 0x7b, 0xf6, 0x23, 0xa9, 0x7f, 0x15, + 0x4a, 0xd6, 0xbe, 0xb2, 0x96, 0x37, 0xed, 0x47, 0x96, 0xd3, 0x49, 0xc6, 0x1d, 0xe4, 0x59, 0xcb, + 0x15, 0x96, 0xe4, 0x43, 0x00, 0x45, 0x2b, 0x4c, 0x8e, 0xad, 0xe0, 0x79, 0x19, 0x11, 0x28, 0x53, + 0x5b, 0x8c, 0xfc, 0x15, 0x86, 0x09, 0xc9, 0x61, 0xfa, 0xb3, 0x93, 0x1c, 0x4e, 0x7d, 0x76, 0x92, + 0xc3, 0xec, 0x36, 0x9c, 0xed, 0xba, 0x74, 0x32, 0xc2, 0x34, 0x5e, 0xd3, 0xc3, 0x34, 0x9e, 0xed, + 0x76, 0xc4, 0x06, 0x7a, 0xf8, 0xe4, 0xa9, 0xf2, 0x74, 0x77, 0xe9, 0xe4, 0xfb, 0xf9, 0xc4, 0x91, + 0x2b, 0x2e, 0x16, 0x3c, 0xdc, 0x7e, 0x37, 0x99, 0x24, 0x8f, 0x79, 0xc5, 0xf8, 0xa1, 0x9c, 0x8f, + 0x2f, 0x34, 0x89, 0xf4, 0xa9, 0xfc, 0x78, 0xfe, 0xb4, 0xa7, 0xef, 0x5b, 0x30, 0xce, 0x33, 0x0a, + 0xdd, 0xa5, 0x87, 0x07, 0x9e, 0xef, 0xc8, 0x1c, 0x99, 0x28, 0x83, 0xa7, 0x72, 0xef, 0x25, 0x70, + 0xc9, 0x92, 0x74, 0x52, 0x1a, 0xc0, 0xda, 0xcf, 0x66, 0xee, 0x62, 0x0c, 0xa1, 0x97, 0xff, 0x12, + 0x79, 0x3d, 0x12, 0xd4, 0xa8, 0xaf, 0x06, 0x51, 0xf6, 0x25, 0x30, 0x43, 0x5e, 0xa3, 0xbe, 0xf1, + 0x07, 0x05, 0x20, 0xbc, 0xa6, 0x45, 0xbb, 0x6d, 0xa3, 0x0b, 0x9f, 0x8b, 0xa1, 0x28, 0xca, 0x02, + 0xc7, 0xde, 0x6e, 0x50, 0x35, 0x8e, 0x8b, 0x30, 0x3a, 0x8d, 0xca, 0xac, 0xe4, 0x45, 0x27, 0x45, + 0xd8, 0x65, 0xab, 0xcb, 0x7f, 0x9a, 0xad, 0xee, 0x9b, 0xf0, 0x6c, 0xa5, 0x8d, 0xa9, 0xc9, 0x64, + 0x2d, 0xb7, 0x3c, 0x5f, 0x6e, 0x52, 0x9a, 0x73, 0x88, 0x1d, 0xa1, 0xa5, 0x5a, 0xda, 0x8b, 0x85, + 0x22, 0xa7, 0xb0, 0x79, 0xd9, 0x0e, 0x55, 0x67, 0x63, 0x29, 0xa7, 0xb4, 0xb1, 0x24, 0x43, 0x4e, + 0xe1, 0x24, 0x92, 0x87, 0xeb, 0x4b, 0x39, 0x05, 0xd3, 0x06, 0xc4, 0x3c, 0x5c, 0x9f, 0x76, 0x91, + 0x75, 0x22, 0x12, 0xf2, 0x16, 0x8c, 0x54, 0x3a, 0xa1, 0x27, 0x18, 0x0b, 0x6b, 0xe9, 0xd8, 0xae, + 0x59, 0x34, 0x45, 0xbb, 0xfa, 0xc4, 0xe8, 0xc6, 0x1f, 0x17, 0xe0, 0x6c, 0x7a, 0x78, 0x45, 0x69, + 0xb4, 0x3e, 0x72, 0xc7, 0xac, 0x8f, 0xac, 0xd9, 0xc0, 0x1f, 0x0b, 0x9e, 0xd8, 0x6c, 0xe0, 0x19, + 0xce, 0x3e, 0xe1, 0x6c, 0xa8, 0xc1, 0x88, 0x7a, 0xde, 0x15, 0x3f, 0xe9, 0x79, 0xa7, 0x72, 0x61, + 0x97, 0x7a, 0xee, 0x63, 0x3d, 0x10, 0x3f, 0x1d, 0x25, 0xdd, 0xab, 0x39, 0x06, 0xf9, 0xff, 0xc1, + 0x05, 0xbe, 0x27, 0x25, 0x3f, 0x76, 0xe1, 0x50, 0x72, 0x14, 0x03, 0x37, 0xff, 0xf8, 0x68, 0xee, + 0x2a, 0x57, 0x95, 0x58, 0xa9, 0x6e, 0xb3, 0xb6, 0x0f, 0x2d, 0xd9, 0x32, 0xa5, 0x92, 0x63, 0x79, + 0x63, 0x5a, 0x33, 0x25, 0x6b, 0xd6, 0x6b, 0x59, 0x6e, 0x24, 0x3c, 0x12, 0x29, 0x07, 0xeb, 0x1e, + 0x24, 0x52, 0x1d, 0x96, 0xcf, 0x54, 0x87, 0x49, 0x7d, 0x4a, 0x21, 0x53, 0x9f, 0xb2, 0x04, 0x13, + 0xb5, 0xce, 0xb6, 0xac, 0x1b, 0x11, 0x8b, 0x9a, 0x27, 0x5c, 0xd6, 0x07, 0x25, 0x49, 0x8c, 0x1f, + 0xcf, 0xc3, 0xe8, 0x46, 0xa3, 0xb3, 0xeb, 0xb6, 0x96, 0xec, 0xd0, 0x7e, 0x6a, 0x35, 0x74, 0x6f, + 0x68, 0x1a, 0xba, 0xc8, 0x5b, 0x2a, 0xfa, 0xb0, 0xbe, 0xd4, 0x73, 0xdf, 0xcd, 0xc1, 0x44, 0x4c, + 0xc2, 0xcf, 0xd9, 0x15, 0x28, 0xb2, 0x1f, 0xe2, 0xde, 0x7a, 0x21, 0xc5, 0x98, 0xa7, 0x6a, 0x89, + 0xfe, 0x12, 0x3a, 0x33, 0x3d, 0x0f, 0x02, 0x72, 0x98, 0xfd, 0x12, 0x0c, 0xc7, 0x6c, 0x4f, 0x92, + 0xa2, 0xe5, 0xd7, 0x72, 0x50, 0x4e, 0x7e, 0x09, 0xb9, 0x0b, 0x43, 0x8c, 0x93, 0x4b, 0xe5, 0x95, + 0xfa, 0x85, 0x2e, 0xdf, 0x7c, 0x55, 0xa0, 0xf1, 0xe6, 0x61, 0xe7, 0x53, 0x0e, 0x31, 0x25, 0x87, + 0x59, 0x13, 0x46, 0x55, 0xac, 0x8c, 0xd6, 0xbd, 0xaa, 0x0b, 0x17, 0xa7, 0xb3, 0xfb, 0x41, 0x4b, + 0x2c, 0xa3, 0xb5, 0x5a, 0xc8, 0x0d, 0x97, 0xb4, 0xc9, 0x85, 0x7d, 0x95, 0x98, 0x37, 0x7c, 0x9a, + 0xcd, 0xc7, 0xc1, 0x91, 0xd5, 0x79, 0x96, 0x31, 0xa1, 0x23, 0x3c, 0xf2, 0x2a, 0x0c, 0xf2, 0xfa, + 0xd4, 0x04, 0x0b, 0x6d, 0x84, 0xa8, 0x22, 0x2e, 0xc7, 0x31, 0xfe, 0x66, 0x01, 0x4e, 0xc7, 0xcd, + 0xbb, 0xdf, 0x76, 0xec, 0x90, 0x6e, 0xd8, 0xbe, 0xdd, 0x0c, 0x8e, 0x59, 0x01, 0x97, 0x53, 0x4d, + 0xc3, 0x80, 0xfb, 0xb2, 0x69, 0x4a, 0x83, 0x8c, 0x44, 0x83, 0x50, 0x7d, 0xc9, 0x1b, 0x24, 0x9b, + 0x41, 0xee, 0x42, 0xa1, 0x46, 0x43, 0xb1, 0x6d, 0x5e, 0x4a, 0xf5, 0xaa, 0xda, 0xae, 0xab, 0x35, + 0x1a, 0xf2, 0x41, 0xe4, 0xb1, 0x3f, 0xa8, 0x16, 0x7b, 0xb1, 0x46, 0x43, 0xb2, 0x05, 0x83, 0xcb, + 0x8f, 0xda, 0xb4, 0x1e, 0x8a, 0x04, 0x43, 0x57, 0x7a, 0xf3, 0xe3, 0xb8, 0x4a, 0x7e, 0x21, 0x8a, + 0x00, 0xb5, 0xb3, 0x38, 0xca, 0xec, 0x4d, 0x28, 0xc9, 0xca, 0x4f, 0x32, 0x73, 0x67, 0xdf, 0x80, + 0x11, 0xa5, 0x92, 0x13, 0x4d, 0xfa, 0x5f, 0x60, 0xfb, 0xaa, 0xd7, 0x90, 0x39, 0x89, 0x96, 0x53, + 0x62, 0x5e, 0x2e, 0xf6, 0xd9, 0xe5, 0x62, 0x9e, 0xb5, 0x2f, 0x8a, 0x7a, 0xc8, 0x7b, 0x55, 0x98, + 0xa8, 0xed, 0xbb, 0xed, 0x38, 0x04, 0x9e, 0x76, 0x98, 0x62, 0xb4, 0x78, 0x71, 0xe7, 0x4e, 0x1e, + 0xa6, 0x49, 0x3a, 0xe3, 0xcf, 0x72, 0x30, 0xc8, 0xfe, 0x7a, 0x70, 0xf3, 0x29, 0xdd, 0x32, 0x6f, + 0x68, 0x5b, 0xe6, 0xa4, 0x12, 0x7f, 0x16, 0x37, 0x8e, 0x9b, 0xc7, 0x6c, 0x96, 0x47, 0x62, 0x80, + 0x38, 0x32, 0xb9, 0x0d, 0x43, 0xc2, 0xf2, 0x46, 0x98, 0x48, 0xab, 0x01, 0x6d, 0xa5, 0x4d, 0x4e, + 0x74, 0x39, 0xf7, 0xda, 0x49, 0x6d, 0x86, 0xa4, 0x66, 0x22, 0xb9, 0x0c, 0x46, 0xa8, 0x65, 0xb2, + 0xf3, 0xd0, 0xff, 0x8c, 0x07, 0x64, 0x55, 0x72, 0x4f, 0x76, 0x71, 0xec, 0xaf, 0x88, 0x87, 0x8c, + 0x42, 0x2f, 0x26, 0xa7, 0x65, 0xa2, 0xaf, 0xcc, 0x37, 0x8e, 0x3f, 0x9c, 0xe2, 0xa1, 0x4c, 0x65, + 0xc3, 0xde, 0x86, 0xd1, 0x5b, 0x9e, 0x7f, 0x60, 0xfb, 0x3c, 0x40, 0x9d, 0xb0, 0x1c, 0x60, 0x57, + 0xc7, 0xb1, 0x1d, 0x0e, 0xe7, 0x21, 0xee, 0x3e, 0x3e, 0x9a, 0x2b, 0x2e, 0x78, 0x5e, 0xc3, 0xd4, + 0xd0, 0xc9, 0x3a, 0x8c, 0xdd, 0xb3, 0x1f, 0x29, 0x97, 0x5e, 0xee, 0x50, 0x72, 0x85, 0x4d, 0x60, + 0x76, 0x6b, 0x3e, 0xde, 0x0c, 0x4a, 0xa7, 0x27, 0x2e, 0x8c, 0x6f, 0x78, 0x7e, 0x28, 0x2a, 0x71, + 0x5b, 0xbb, 0xe2, 0x63, 0xd3, 0x86, 0x5c, 0xd7, 0x32, 0x0d, 0xb9, 0xce, 0xb6, 0x3d, 0x3f, 0xb4, + 0x76, 0x22, 0x72, 0x2d, 0x68, 0x8e, 0xc6, 0x98, 0xbc, 0x0d, 0x93, 0x4a, 0x50, 0xb0, 0x5b, 0x9e, + 0xdf, 0xb4, 0xa5, 0x50, 0x8e, 0x7a, 0x60, 0xb4, 0x37, 0xd9, 0x41, 0xb0, 0x99, 0xc6, 0x24, 0x1f, + 0x64, 0xb9, 0xe8, 0x0c, 0xc4, 0x96, 0x60, 0x19, 0x2e, 0x3a, 0xdd, 0x2c, 0xc1, 0xd2, 0xce, 0x3a, + 0xbb, 0xbd, 0x2c, 0x45, 0x4b, 0x0b, 0xd7, 0xc5, 0xf5, 0xfb, 0x78, 0x4b, 0xd0, 0x68, 0xdc, 0xba, + 0x58, 0x84, 0xce, 0x43, 0x61, 0x61, 0xe3, 0x16, 0xbe, 0x5e, 0x48, 0x43, 0x9b, 0xd6, 0x9e, 0xdd, + 0xaa, 0xa3, 0xb0, 0x2c, 0xac, 0xb3, 0xd5, 0x1d, 0x79, 0x61, 0xe3, 0x16, 0xb1, 0x61, 0x6a, 0x83, + 0xfa, 0x4d, 0x37, 0xfc, 0xda, 0xf5, 0xeb, 0xca, 0x40, 0x95, 0xb0, 0x69, 0xd7, 0x44, 0xd3, 0xe6, + 0xda, 0x88, 0x62, 0x3d, 0xba, 0x7e, 0x3d, 0x73, 0x38, 0xa2, 0x86, 0x65, 0xf1, 0x62, 0x3b, 0xe3, + 0x3d, 0xfb, 0x51, 0x6c, 0x54, 0x1f, 0x08, 0x67, 0xc7, 0xf3, 0x72, 0x62, 0xc5, 0x06, 0xf9, 0xda, + 0xce, 0xa8, 0x13, 0xb1, 0xbb, 0x4e, 0x3c, 0xbd, 0x02, 0xe1, 0x26, 0x32, 0x2b, 0x55, 0x3a, 0xd2, + 0x23, 0x56, 0x15, 0xd8, 0x15, 0x74, 0x72, 0x3f, 0xba, 0xb1, 0xf1, 0x1b, 0x8f, 0x48, 0x63, 0x75, + 0x4d, 0xbd, 0xb1, 0x71, 0x45, 0x8a, 0xf6, 0x59, 0x13, 0xd1, 0x35, 0x9f, 0x7b, 0x19, 0x98, 0x3a, + 0x97, 0xf4, 0x45, 0x70, 0xf4, 0xe4, 0x17, 0x41, 0x0a, 0xc5, 0x55, 0xaf, 0xbe, 0x2f, 0x22, 0xfd, + 0x7c, 0x95, 0x2d, 0xf7, 0x86, 0x57, 0xdf, 0x7f, 0x72, 0x16, 0xb0, 0xc8, 0x9e, 0xac, 0xb1, 0xa6, + 0xb2, 0x59, 0x20, 0xfa, 0x44, 0x58, 0x55, 0x4e, 0x47, 0x37, 0x21, 0xa5, 0x8c, 0x0b, 0x3e, 0x7c, + 0xd2, 0xc8, 0xae, 0x35, 0x75, 0x72, 0x42, 0xa1, 0xbc, 0x44, 0x83, 0xfd, 0xd0, 0x6b, 0x2f, 0x36, + 0xdc, 0xf6, 0xb6, 0x67, 0xfb, 0x0e, 0xea, 0xee, 0xb2, 0xd6, 0xf7, 0x4b, 0x99, 0xeb, 0x7b, 0xd2, + 0xe1, 0xf4, 0x56, 0x5d, 0x32, 0x30, 0x53, 0x2c, 0xc9, 0x07, 0x30, 0xce, 0x26, 0xf7, 0xf2, 0xa3, + 0x90, 0xb6, 0xf8, 0xc8, 0x4f, 0xa2, 0xe8, 0x30, 0xad, 0x04, 0xfe, 0x8e, 0x0a, 0xf9, 0x9c, 0xc2, + 0xc5, 0x4e, 0x23, 0x02, 0x2d, 0x4a, 0x92, 0xc6, 0x8a, 0x38, 0x30, 0x73, 0xcf, 0x7e, 0xa4, 0x24, + 0xdf, 0x52, 0x26, 0x29, 0xc1, 0x09, 0x86, 0xc9, 0xc6, 0xd9, 0x04, 0x8b, 0x03, 0x74, 0x76, 0x99, + 0xaf, 0x5d, 0x39, 0x91, 0x1f, 0x84, 0x33, 0xe2, 0xb3, 0x96, 0x30, 0x1b, 0x86, 0xe7, 0x1f, 0xd6, + 0xf6, 0x6c, 0xf4, 0xa7, 0x99, 0x3a, 0xd9, 0x86, 0x28, 0x3b, 0xcc, 0x91, 0x7c, 0xac, 0x80, 0x33, + 0x32, 0xbb, 0xd5, 0x40, 0x3e, 0x82, 0x71, 0xfe, 0x64, 0xb3, 0xe2, 0x05, 0x21, 0x5e, 0xe8, 0xa7, + 0x4f, 0x66, 0x26, 0xce, 0xdf, 0x81, 0xb8, 0x63, 0x45, 0x42, 0x01, 0x90, 0xe0, 0x4c, 0xde, 0x84, + 0x91, 0x0d, 0xb7, 0xc5, 0xe3, 0x98, 0x55, 0x37, 0x50, 0xf5, 0x28, 0xce, 0x9f, 0xb6, 0xdb, 0xb2, + 0xe4, 0xad, 0xba, 0x1d, 0x6d, 0x17, 0x2a, 0x36, 0xd9, 0x82, 0x91, 0x5a, 0x6d, 0xe5, 0x96, 0xcb, + 0x0e, 0xc0, 0xf6, 0xe1, 0xcc, 0xe9, 0x2e, 0xad, 0xbc, 0x98, 0xd9, 0xca, 0xb1, 0x20, 0xd8, 0xc3, + 0x84, 0xc6, 0x56, 0xdd, 0x6b, 0x1f, 0x9a, 0x2a, 0xa7, 0x0c, 0xd3, 0xe9, 0x33, 0x4f, 0xd8, 0x74, + 0xba, 0x0a, 0x13, 0x8a, 0x81, 0x25, 0x1a, 0x57, 0xce, 0xc4, 0x61, 0xbb, 0x54, 0x53, 0xe9, 0xa4, + 0x5b, 0x5f, 0x92, 0x4e, 0xda, 0x4c, 0x9f, 0x3d, 0xa9, 0xcd, 0xb4, 0x0b, 0x93, 0x7c, 0x30, 0xc4, + 0x3c, 0xc0, 0x91, 0x9e, 0xed, 0xd2, 0x87, 0x57, 0x32, 0xfb, 0x70, 0x4a, 0x8c, 0xb4, 0x9c, 0x64, + 0xf8, 0x44, 0x99, 0xe6, 0x4a, 0x76, 0x80, 0x08, 0xa0, 0x48, 0xa7, 0x8c, 0x75, 0x3d, 0xdb, 0xa5, + 0xae, 0x17, 0x32, 0xeb, 0x1a, 0x97, 0x75, 0x6d, 0xf3, 0x6a, 0x32, 0x38, 0x92, 0x96, 0xac, 0x47, + 0xce, 0x2f, 0xec, 0xd8, 0x73, 0x9a, 0x1e, 0x34, 0x8d, 0xc0, 0x83, 0x88, 0x26, 0x27, 0x6d, 0xb2, + 0xdf, 0x33, 0x38, 0x93, 0x47, 0x70, 0x3a, 0xdd, 0x0a, 0xac, 0xf3, 0x3c, 0xd6, 0x79, 0x5e, 0xab, + 0x33, 0x89, 0xc4, 0xe7, 0x8d, 0xfe, 0x59, 0xc9, 0x5a, 0xbb, 0xf0, 0xbf, 0x53, 0x2c, 0x8d, 0x95, + 0xc7, 0xb3, 0x2c, 0xad, 0xff, 0x41, 0x3e, 0xb1, 0x69, 0x93, 0x2a, 0x0c, 0x89, 0xb1, 0x10, 0x52, + 0x6c, 0xba, 0xc7, 0xcf, 0x67, 0xf6, 0xf8, 0x90, 0x18, 0x56, 0x53, 0xd2, 0x93, 0x03, 0xc6, 0x0a, + 0xcd, 0xd6, 0x85, 0xd8, 0xff, 0x21, 0xdf, 0x93, 0x11, 0xa4, 0x9d, 0x3e, 0x4b, 0x27, 0x77, 0xda, + 0xd1, 0x7d, 0xc2, 0xf0, 0x18, 0x92, 0xb5, 0x91, 0x7d, 0x9e, 0x29, 0xa0, 0x10, 0x79, 0x7e, 0xe8, + 0x69, 0x01, 0x9e, 0x58, 0x85, 0xac, 0x16, 0xe3, 0x37, 0x73, 0x30, 0xa6, 0xed, 0xfa, 0xe4, 0xa6, + 0xe2, 0xd6, 0x14, 0x7b, 0xe5, 0x6a, 0x38, 0xb8, 0x11, 0x24, 0x1d, 0x9e, 0x6e, 0x0a, 0xbb, 0xe9, + 0x7c, 0x77, 0xba, 0xcc, 0xac, 0xe2, 0xbd, 0x95, 0x64, 0x51, 0xe6, 0xa1, 0x62, 0x97, 0xcc, 0x43, + 0xbf, 0xfe, 0x2c, 0x8c, 0xeb, 0xd7, 0x02, 0xf2, 0x2a, 0x0c, 0xa2, 0x6e, 0x51, 0xde, 0x31, 0x79, + 0xee, 0x5d, 0x84, 0x68, 0xb9, 0x77, 0x11, 0x42, 0x5e, 0x04, 0x88, 0x0c, 0x58, 0xa5, 0x66, 0x7d, + 0xe0, 0xf1, 0xd1, 0x5c, 0xee, 0x35, 0x53, 0x29, 0x20, 0xdf, 0x00, 0x58, 0xf3, 0x1c, 0x1a, 0x65, + 0x47, 0xeb, 0xf1, 0x7a, 0xfc, 0x52, 0x2a, 0x8a, 0xf6, 0xa9, 0x96, 0xe7, 0xd0, 0x74, 0xc8, 0x6c, + 0x85, 0x23, 0xf9, 0x0a, 0x0c, 0x98, 0x1d, 0x76, 0x9f, 0xe5, 0xaa, 0x84, 0x11, 0xb9, 0xfb, 0x76, + 0x1a, 0x54, 0x49, 0xd4, 0xdf, 0x49, 0x1a, 0x46, 0x31, 0x00, 0x79, 0x97, 0x47, 0xd7, 0x16, 0xc1, + 0xb0, 0x06, 0xe2, 0xb7, 0x06, 0xe5, 0x54, 0x4e, 0x85, 0xc3, 0x52, 0x48, 0xc8, 0x3a, 0x0c, 0xa9, + 0x4a, 0x72, 0xc5, 0x3f, 0x56, 0x7d, 0x48, 0x51, 0x6e, 0x5e, 0x22, 0xad, 0x5a, 0x52, 0x7f, 0x2e, + 0xb9, 0x90, 0xb7, 0x60, 0x98, 0xb1, 0x67, 0x4b, 0x38, 0x10, 0x12, 0x37, 0xbe, 0x28, 0x28, 0x0d, + 0x62, 0x3b, 0x80, 0x16, 0xb2, 0x2a, 0x22, 0x20, 0x1f, 0x60, 0xe6, 0x30, 0xd1, 0xd5, 0x3d, 0xad, + 0x0a, 0x2e, 0xa5, 0xba, 0x1a, 0x53, 0x89, 0xa5, 0x93, 0xca, 0x46, 0xfc, 0xc8, 0x6e, 0x14, 0x4a, + 0xa9, 0x9f, 0x88, 0xe8, 0x2f, 0xa7, 0x2a, 0x98, 0x91, 0xd1, 0x81, 0xd2, 0x59, 0xee, 0x34, 0xbe, + 0xa4, 0x0d, 0xe5, 0x58, 0xe0, 0x11, 0x75, 0x41, 0xaf, 0xba, 0x5e, 0x4b, 0xd5, 0xa5, 0x0e, 0x60, + 0xaa, 0xba, 0x14, 0x77, 0xe2, 0xc0, 0xb8, 0xdc, 0x3c, 0x45, 0x7d, 0x23, 0xbd, 0xea, 0x7b, 0x31, + 0x55, 0xdf, 0x94, 0xb3, 0x9d, 0xae, 0x27, 0xc1, 0x93, 0xbc, 0x05, 0x63, 0x12, 0x82, 0xeb, 0x43, + 0x64, 0xaf, 0x45, 0xad, 0x88, 0xb3, 0x8d, 0x26, 0xf3, 0x7a, 0xee, 0x3f, 0x15, 0x59, 0xa5, 0xe6, + 0xb3, 0x63, 0x4c, 0xa3, 0x4e, 0xce, 0x0a, 0x1d, 0x99, 0xbc, 0x0f, 0x23, 0xd5, 0x26, 0xfb, 0x10, + 0xaf, 0x65, 0x87, 0x54, 0xf8, 0x4e, 0x49, 0x0b, 0x09, 0xa5, 0x44, 0x99, 0xaa, 0x3c, 0x9b, 0x5e, + 0x5c, 0xa4, 0x65, 0xd3, 0x8b, 0xc1, 0xac, 0xf3, 0xf8, 0xab, 0x88, 0x98, 0xc3, 0xd2, 0xaf, 0xea, + 0x7c, 0x86, 0x95, 0x82, 0xc2, 0x5e, 0x04, 0x9d, 0x63, 0x50, 0xf9, 0x2a, 0x91, 0x08, 0x3a, 0xa7, + 0xf2, 0x24, 0x6f, 0xc3, 0x88, 0x48, 0x16, 0x51, 0x31, 0xd7, 0x82, 0x99, 0x32, 0x7e, 0x3c, 0x7a, + 0x83, 0xcb, 0xbc, 0x12, 0x96, 0xed, 0x27, 0xcc, 0xf1, 0x62, 0x7c, 0xf2, 0x35, 0x98, 0xde, 0x72, + 0x5b, 0x8e, 0x77, 0x10, 0x88, 0x63, 0x4a, 0x6c, 0x74, 0x93, 0xb1, 0x33, 0xcc, 0x01, 0x2f, 0x8f, + 0xe4, 0x94, 0xd4, 0xc6, 0x97, 0xc9, 0x81, 0xfc, 0xc5, 0x14, 0x67, 0x3e, 0x83, 0x48, 0xaf, 0x19, + 0x34, 0x9f, 0x9a, 0x41, 0xe9, 0xea, 0x93, 0xd3, 0x29, 0xb3, 0x1a, 0xe2, 0x01, 0xd1, 0xcf, 0xf7, + 0x3b, 0x9e, 0xdb, 0x9a, 0x99, 0xc2, 0xbd, 0xf0, 0xd9, 0xa4, 0xff, 0x35, 0xe2, 0x6d, 0x78, 0x0d, + 0xb7, 0x7e, 0xc8, 0x33, 0xd7, 0x27, 0xe5, 0xd1, 0x8f, 0x3c, 0x4d, 0x67, 0x9c, 0xc1, 0x9a, 0xbc, + 0x0f, 0xa3, 0xec, 0xff, 0xe8, 0xc2, 0x3c, 0xad, 0xd9, 0xb5, 0x29, 0x98, 0xa2, 0x1e, 0x1c, 0x23, + 0xcc, 0x66, 0x91, 0x71, 0x97, 0xd6, 0x58, 0x91, 0x37, 0x00, 0x98, 0xe4, 0x24, 0xb6, 0xe3, 0x53, + 0x71, 0x8c, 0x3f, 0x94, 0xb7, 0xd2, 0x1b, 0x71, 0x8c, 0xcc, 0x6e, 0xf1, 0xec, 0x57, 0xad, 0xe3, + 0x78, 0x6c, 0x6d, 0x9c, 0x46, 0x5a, 0xee, 0x92, 0xc6, 0x68, 0x03, 0x0e, 0xd7, 0x5c, 0xd2, 0x62, + 0x74, 0xb2, 0x02, 0x13, 0x18, 0x8b, 0xb1, 0xea, 0xd0, 0x56, 0x88, 0xaf, 0x95, 0x33, 0x67, 0x94, + 0xd7, 0x5c, 0x56, 0x64, 0xb9, 0x51, 0x99, 0x2a, 0x67, 0x27, 0xc8, 0x48, 0x00, 0x53, 0xf1, 0xee, + 0x12, 0xbf, 0x0d, 0xcf, 0x60, 0x27, 0x49, 0xe9, 0x32, 0x8d, 0xc1, 0xf7, 0x63, 0x36, 0x22, 0xca, + 0xc6, 0x25, 0x35, 0xeb, 0x6a, 0x85, 0x59, 0xdc, 0x89, 0x09, 0xe4, 0xf6, 0xe2, 0x46, 0x32, 0x58, + 0xe1, 0x59, 0xfc, 0x02, 0x1c, 0xe6, 0xdd, 0x7a, 0x9c, 0xb7, 0x31, 0x23, 0x60, 0x61, 0x06, 0x35, + 0xf9, 0x36, 0x9c, 0x92, 0x3b, 0x88, 0x28, 0x12, 0xf3, 0x7a, 0xf6, 0x84, 0x3b, 0xb1, 0xb3, 0x1d, + 0x55, 0x9d, 0x9a, 0xd2, 0xd9, 0x55, 0x10, 0x1b, 0x46, 0x70, 0x58, 0x45, 0x8d, 0xcf, 0xf6, 0xaa, + 0xf1, 0x72, 0xaa, 0xc6, 0xd3, 0x38, 0x51, 0xd2, 0x95, 0xa9, 0x3c, 0xc9, 0x02, 0x8c, 0x89, 0x75, + 0x24, 0x66, 0xdb, 0x39, 0xec, 0x2d, 0x54, 0xb0, 0xc8, 0x15, 0x98, 0x9a, 0x70, 0x3a, 0x89, 0xba, + 0x23, 0x73, 0x8d, 0xfa, 0x79, 0x6d, 0x47, 0x4e, 0x2a, 0xd2, 0x75, 0x64, 0xb6, 0x23, 0xc5, 0x52, + 0xcc, 0xf2, 0xa3, 0xb6, 0x2f, 0xd4, 0x27, 0xcf, 0xc5, 0x31, 0xfc, 0x15, 0xe1, 0xc7, 0xa2, 0x11, + 0x86, 0xba, 0x25, 0x64, 0x71, 0x20, 0xf7, 0x61, 0x2a, 0x3a, 0xb5, 0x15, 0xc6, 0x73, 0x71, 0x2e, + 0x84, 0xf8, 0xa8, 0xcf, 0xe6, 0x9b, 0x45, 0x4f, 0x6c, 0x38, 0xa3, 0x9d, 0xd3, 0x0a, 0xeb, 0x0b, + 0xc8, 0x1a, 0xf3, 0x84, 0xea, 0x87, 0x7c, 0x36, 0xfb, 0x6e, 0x7c, 0xc8, 0x47, 0x30, 0x9b, 0x3c, + 0x9b, 0x95, 0x5a, 0x9e, 0xc7, 0x5a, 0x5e, 0x7e, 0x7c, 0x34, 0x77, 0x29, 0x75, 0xbc, 0x67, 0x57, + 0xd4, 0x83, 0x1b, 0xf9, 0x06, 0xcc, 0xe8, 0xe7, 0xb3, 0x52, 0x93, 0x81, 0x35, 0xe1, 0xd2, 0x89, + 0x0e, 0xf6, 0xec, 0x1a, 0xba, 0xf2, 0x20, 0x21, 0xcc, 0x65, 0xce, 0x6e, 0xa5, 0x9a, 0x8b, 0xf1, + 0x07, 0xa5, 0x56, 0x49, 0x76, 0x75, 0xc7, 0xb1, 0x24, 0x07, 0xf0, 0x5c, 0xd6, 0x31, 0xa1, 0x54, + 0xfa, 0x42, 0xa4, 0xa0, 0x7c, 0x25, 0xfb, 0xc8, 0xc9, 0xae, 0xf9, 0x18, 0xb6, 0xe4, 0x03, 0x38, + 0xa5, 0xac, 0x2f, 0xa5, 0xbe, 0x17, 0xb1, 0x3e, 0x74, 0x65, 0x55, 0x17, 0x66, 0x76, 0x2d, 0xd9, + 0x3c, 0x48, 0x13, 0xa6, 0xe4, 0x87, 0xa3, 0x26, 0x58, 0x1c, 0x3d, 0x97, 0xb4, 0x5d, 0x35, 0x8d, + 0xa1, 0x24, 0x58, 0xde, 0xb6, 0xda, 0x31, 0xa1, 0x3a, 0xd3, 0x33, 0xf8, 0x92, 0x15, 0x18, 0xac, + 0x6d, 0x54, 0x6f, 0xdd, 0x5a, 0x9e, 0x79, 0x09, 0x6b, 0x90, 0x7e, 0x2f, 0x1c, 0xa8, 0x5d, 0x9a, + 0x84, 0xb9, 0x55, 0xdb, 0xdd, 0xd9, 0xd1, 0xdc, 0x8b, 0x38, 0xea, 0x9d, 0x62, 0xe9, 0x72, 0xf9, + 0xca, 0x9d, 0x62, 0xe9, 0x4a, 0xf9, 0x65, 0xf3, 0x5c, 0x76, 0x6e, 0x5c, 0xfe, 0xb1, 0xe6, 0xa5, + 0x5e, 0xa5, 0x71, 0x57, 0x18, 0xbf, 0x90, 0x83, 0xa9, 0x8c, 0x76, 0x90, 0x4b, 0x50, 0xc4, 0xe4, + 0x02, 0xca, 0x03, 0x73, 0x22, 0xa9, 0x00, 0x96, 0x93, 0x2f, 0xc0, 0xd0, 0xd2, 0x5a, 0xad, 0x56, + 0x59, 0x93, 0x57, 0x36, 0xbe, 0x5d, 0xb5, 0x02, 0x2b, 0xb0, 0xf5, 0x77, 0x29, 0x81, 0x46, 0x5e, + 0x83, 0xc1, 0xea, 0x06, 0x12, 0x70, 0x0b, 0x27, 0xbc, 0xc2, 0xb8, 0xed, 0x24, 0xbe, 0x40, 0x32, + 0x7e, 0x22, 0x07, 0x24, 0xdd, 0xa9, 0xe4, 0x3a, 0x8c, 0xa8, 0x43, 0xc7, 0x2f, 0x98, 0xf8, 0x86, + 0xa2, 0x0c, 0x8c, 0xa9, 0xe2, 0x90, 0x25, 0x18, 0xc0, 0x64, 0x48, 0xd1, 0x83, 0x58, 0xe6, 0x01, + 0x70, 0x26, 0x75, 0x00, 0x0c, 0x60, 0xaa, 0x25, 0x93, 0x13, 0x1b, 0xbf, 0x93, 0x03, 0x92, 0x3e, + 0x34, 0xfb, 0x7e, 0x90, 0x7f, 0x5d, 0xf1, 0x50, 0x55, 0xc3, 0x87, 0x47, 0xb9, 0x1f, 0xd4, 0xcb, + 0x52, 0xec, 0xcb, 0x7a, 0x49, 0xbb, 0x9c, 0x77, 0x77, 0x6b, 0xba, 0x02, 0x03, 0x0f, 0xa8, 0xbf, + 0x2d, 0x8d, 0xf7, 0xd0, 0xe0, 0xe7, 0x21, 0x03, 0xa8, 0x97, 0x55, 0xc4, 0x30, 0xfe, 0x38, 0x07, + 0xd3, 0x59, 0x92, 0xdc, 0x31, 0xde, 0x47, 0x46, 0xc2, 0x71, 0x0a, 0x1f, 0xe3, 0xb9, 0x35, 0x50, + 0xe4, 0x2e, 0x35, 0x07, 0x03, 0xec, 0x63, 0xe5, 0x08, 0xa3, 0xb2, 0x80, 0xf5, 0x46, 0x60, 0x72, + 0x38, 0x43, 0xe0, 0x51, 0x8f, 0x8a, 0x18, 0xdc, 0x0a, 0x11, 0x50, 0x50, 0x30, 0x39, 0x9c, 0x21, + 0xdc, 0xf3, 0x9c, 0x28, 0x03, 0x28, 0x22, 0x34, 0x19, 0xc0, 0xe4, 0x70, 0x72, 0x09, 0x86, 0xd6, + 0x5b, 0xab, 0xd4, 0x7e, 0x28, 0xd3, 0x57, 0xa0, 0xf1, 0x80, 0xd7, 0xb2, 0x1a, 0x0c, 0x66, 0xca, + 0x42, 0xe3, 0xbb, 0x39, 0x98, 0x4c, 0x09, 0x91, 0xc7, 0x3b, 0x58, 0xf5, 0xf6, 0x74, 0xe8, 0xe7, + 0xfb, 0x78, 0xf3, 0x8b, 0xd9, 0xcd, 0x37, 0xfe, 0xcf, 0x22, 0x9c, 0xe9, 0x72, 0xa7, 0x8f, 0x3d, + 0xb1, 0x72, 0xc7, 0x7a, 0x62, 0x7d, 0x9d, 0xdd, 0xa1, 0x6d, 0xb7, 0x19, 0x6c, 0x7a, 0x71, 0x8b, + 0x63, 0x83, 0x6e, 0x2c, 0x93, 0x49, 0x50, 0xa5, 0xe5, 0xef, 0x59, 0x9e, 0x88, 0xda, 0x0a, 0xbd, + 0xb4, 0x48, 0xa1, 0x31, 0x4b, 0xf9, 0x42, 0x15, 0xfe, 0x9c, 0xf8, 0x42, 0xe9, 0xd6, 0xf9, 0xc5, + 0x27, 0x6a, 0x9d, 0x9f, 0x6d, 0xd9, 0x37, 0xf0, 0x69, 0xec, 0x3c, 0x17, 0x61, 0x8c, 0x5b, 0x4f, + 0x54, 0x02, 0x3e, 0x48, 0x83, 0x29, 0x8b, 0x0b, 0x3b, 0x48, 0x8f, 0x85, 0x46, 0x43, 0x56, 0x74, + 0x4b, 0xf2, 0x21, 0x7c, 0xf5, 0xb9, 0xd4, 0xdd, 0x52, 0x5c, 0x7b, 0xed, 0x55, 0x49, 0x8d, 0xef, + 0xe6, 0x75, 0x47, 0xa9, 0x3f, 0x8f, 0x33, 0xef, 0x0a, 0x0c, 0x6c, 0xed, 0x51, 0x5f, 0xee, 0x77, + 0xd8, 0x90, 0x03, 0x06, 0x50, 0x1b, 0x82, 0x18, 0xe4, 0x16, 0x8c, 0x6f, 0xf0, 0x91, 0x90, 0xdd, + 0x5b, 0x8c, 0xaf, 0x5a, 0x6d, 0xa1, 0x10, 0xc8, 0xe8, 0xdf, 0x04, 0x95, 0x71, 0x1b, 0xce, 0x6b, + 0x0b, 0x52, 0x04, 0x76, 0xe0, 0x06, 0xdd, 0xfc, 0x44, 0x1c, 0x8f, 0x4d, 0xd8, 0xe3, 0xdd, 0xc3, + 0x4c, 0x40, 0x8d, 0x1d, 0x78, 0xae, 0x27, 0x23, 0x76, 0x10, 0x41, 0x3b, 0xfa, 0x95, 0xb0, 0x3a, + 0xeb, 0x49, 0x6a, 0x2a, 0x74, 0xc6, 0x0f, 0xc2, 0xa8, 0xda, 0xcb, 0xb8, 0xa7, 0xb2, 0xdf, 0x62, + 0x53, 0xe3, 0x7b, 0x2a, 0x03, 0x98, 0x1c, 0x7e, 0x6c, 0xf2, 0xf8, 0x78, 0xf8, 0x0b, 0xc7, 0x0d, + 0x3f, 0xab, 0x1c, 0x97, 0xac, 0x52, 0x39, 0xfe, 0x56, 0x2b, 0xc7, 0xc8, 0x0d, 0x26, 0x87, 0x3f, + 0xd1, 0xca, 0x7f, 0x5b, 0x06, 0xf1, 0x47, 0x7b, 0x71, 0x79, 0x27, 0x8e, 0x53, 0x74, 0x4e, 0x65, + 0xdd, 0x74, 0x63, 0xcc, 0xf8, 0x90, 0xcc, 0x1f, 0x77, 0x48, 0x9e, 0x64, 0x22, 0x5e, 0x83, 0xa1, + 0x8a, 0x78, 0x93, 0x2d, 0xc6, 0x82, 0x8d, 0x9d, 0x7a, 0x80, 0x95, 0x58, 0xc6, 0xf7, 0x72, 0x70, + 0x2a, 0x53, 0x55, 0xc6, 0x6a, 0xe5, 0x3a, 0x39, 0x65, 0x1d, 0x26, 0x15, 0x72, 0x1c, 0xe3, 0x24, + 0x6e, 0xbb, 0xfd, 0x7f, 0x8b, 0xf1, 0x3c, 0x0c, 0x47, 0x0f, 0x35, 0x64, 0x5a, 0x0e, 0x1d, 0x1a, + 0xea, 0x48, 0x7d, 0x7f, 0x0d, 0x80, 0xb5, 0xe0, 0x89, 0x9a, 0x95, 0x19, 0xbf, 0x9d, 0xe7, 0x09, + 0x9e, 0x9e, 0xda, 0x68, 0x77, 0xd9, 0xb6, 0x60, 0xec, 0x93, 0xba, 0xc7, 0xb8, 0x23, 0xcb, 0x30, + 0x58, 0x0b, 0xed, 0xb0, 0x23, 0xbd, 0x8d, 0xa7, 0x54, 0x32, 0x2c, 0x78, 0x30, 0x1f, 0xfb, 0x9b, + 0x06, 0x08, 0xd1, 0x2e, 0x07, 0x08, 0x51, 0x4c, 0xca, 0x5c, 0x18, 0x55, 0x69, 0xc9, 0xfb, 0x30, + 0x2e, 0x43, 0x78, 0x71, 0x17, 0x6c, 0xf1, 0xa8, 0x24, 0x8d, 0x13, 0x64, 0x08, 0x2f, 0xd5, 0x65, + 0x5b, 0xc3, 0x57, 0x77, 0xea, 0xb6, 0x8a, 0x6c, 0xfc, 0xc9, 0x20, 0x9f, 0x07, 0x22, 0x16, 0xdf, + 0x36, 0x8c, 0xaf, 0x57, 0x97, 0x16, 0x15, 0xc5, 0x97, 0x9e, 0x76, 0x61, 0xf9, 0x51, 0x48, 0xfd, + 0x96, 0xdd, 0x10, 0x08, 0x87, 0xf1, 0xd9, 0xe0, 0xb9, 0x4e, 0x3d, 0x5b, 0x29, 0x96, 0xe0, 0xc8, + 0xea, 0xe0, 0x97, 0x9b, 0xa8, 0x8e, 0x7c, 0x9f, 0x75, 0x04, 0x76, 0xb3, 0xd1, 0xa5, 0x0e, 0x9d, + 0x23, 0xd9, 0x83, 0xf2, 0x6d, 0x94, 0x63, 0x94, 0x5a, 0x0a, 0xbd, 0x6b, 0xb9, 0x28, 0x6a, 0x79, + 0x96, 0x0b, 0x40, 0xd9, 0xf5, 0xa4, 0xb8, 0xc6, 0x0b, 0xb8, 0x78, 0xec, 0x02, 0xfe, 0x2b, 0x39, + 0x18, 0xe4, 0x82, 0x92, 0x98, 0x5f, 0x5d, 0x44, 0xb1, 0xad, 0x27, 0x23, 0x8a, 0x95, 0x71, 0x03, + 0xd7, 0x66, 0x1a, 0x2f, 0x23, 0x4b, 0x89, 0x09, 0x2b, 0x4d, 0x14, 0x51, 0x85, 0xcd, 0x4b, 0x8e, + 0x9f, 0xaf, 0xa4, 0x1a, 0xbb, 0xe6, 0x0e, 0x1d, 0xeb, 0xfd, 0x25, 0xdd, 0x99, 0x87, 0x84, 0x6b, + 0xae, 0xee, 0x90, 0xbb, 0x0a, 0xc3, 0xc2, 0xe1, 0x77, 0xe1, 0x50, 0x3c, 0x54, 0x95, 0xb5, 0x67, + 0x70, 0x67, 0xe1, 0x30, 0x16, 0x02, 0x85, 0xcb, 0xb0, 0xb5, 0x7d, 0xa8, 0x25, 0xb2, 0x92, 0x88, + 0x64, 0x9d, 0x27, 0x78, 0xe1, 0xd1, 0x0a, 0xf5, 0x50, 0xc2, 0x11, 0x5c, 0x84, 0x12, 0x91, 0x5e, + 0x83, 0x19, 0xc1, 0x09, 0x63, 0x1e, 0x64, 0x15, 0xca, 0x22, 0xf1, 0x3d, 0xb7, 0xa3, 0xa8, 0x2e, + 0x71, 0xa7, 0x52, 0x61, 0xfe, 0x26, 0xd3, 0xe6, 0x0b, 0x0b, 0x0c, 0xdd, 0x9f, 0x23, 0x45, 0xc9, + 0x2e, 0x6e, 0xe5, 0xe4, 0xec, 0x23, 0x6f, 0xc1, 0x48, 0x14, 0x2d, 0x32, 0xf2, 0x28, 0x43, 0x85, + 0x75, 0x1c, 0x5e, 0x52, 0xf3, 0x2d, 0x53, 0xd1, 0xc9, 0x3c, 0x94, 0xd8, 0x22, 0x4e, 0xa6, 0xd0, + 0xea, 0x08, 0x98, 0x6a, 0x26, 0x2e, 0xf1, 0x48, 0x0d, 0xa6, 0xd8, 0xa2, 0xa9, 0xb9, 0xad, 0xdd, + 0x06, 0x5d, 0xf5, 0x76, 0xbd, 0x4e, 0x78, 0xdf, 0x5c, 0x15, 0x9b, 0x2b, 0x17, 0x95, 0xed, 0x66, + 0x43, 0x2b, 0xf6, 0xb5, 0x04, 0xa9, 0x19, 0xd4, 0xca, 0x1e, 0xf6, 0x87, 0x79, 0x18, 0x51, 0xe6, + 0x13, 0xb9, 0x02, 0xa5, 0x6a, 0xb0, 0xea, 0xd5, 0xf7, 0xa3, 0x58, 0x53, 0x63, 0x8f, 0x8f, 0xe6, + 0x86, 0xdd, 0xc0, 0x6a, 0x20, 0xd0, 0x8c, 0x8a, 0xc9, 0x02, 0x8c, 0xf1, 0xbf, 0x64, 0xc4, 0xed, + 0x7c, 0x6c, 0xed, 0xc6, 0x91, 0x65, 0xac, 0x6d, 0x75, 0x5f, 0xd3, 0x48, 0xc8, 0x87, 0x00, 0x1c, + 0x80, 0xde, 0x89, 0x85, 0xfe, 0xfd, 0x2a, 0x45, 0x05, 0x19, 0x7e, 0x89, 0x0a, 0x43, 0xf2, 0x4d, + 0x1e, 0x5d, 0x52, 0xce, 0xff, 0x62, 0xff, 0x8e, 0xa1, 0x8c, 0xbf, 0x95, 0xed, 0x9f, 0xae, 0xb2, + 0x14, 0x61, 0xf1, 0x66, 0x4d, 0x5a, 0xf7, 0x1e, 0x52, 0xff, 0xb0, 0x12, 0x22, 0xa2, 0x82, 0x61, + 0xfc, 0xf7, 0x39, 0x65, 0xd5, 0x90, 0x35, 0xcc, 0xfa, 0xc6, 0x67, 0x84, 0xb0, 0xd9, 0x88, 0x84, + 0x79, 0x09, 0x37, 0xe9, 0xce, 0xc2, 0xb3, 0xc2, 0xd8, 0x72, 0x2a, 0x9a, 0x57, 0x89, 0x6c, 0x70, + 0x1c, 0x48, 0xde, 0x83, 0x22, 0x76, 0x5d, 0xfe, 0xd8, 0x4f, 0x93, 0xe7, 0x69, 0x91, 0xf5, 0x19, + 0x7e, 0x08, 0x52, 0x92, 0x2f, 0x08, 0xcf, 0x2e, 0xde, 0xf9, 0xe3, 0xca, 0xa1, 0xc8, 0xda, 0x11, + 0x1d, 0xa4, 0x71, 0x88, 0x02, 0x65, 0xf6, 0xfc, 0x6b, 0x79, 0x28, 0x27, 0xd7, 0x2a, 0x79, 0x17, + 0x46, 0xe5, 0x49, 0x87, 0x69, 0x81, 0xd9, 0x57, 0x8e, 0x8a, 0x10, 0xd0, 0xf2, 0xb8, 0x4b, 0x66, + 0x05, 0x56, 0x09, 0x98, 0xd4, 0xb1, 0x29, 0x42, 0x06, 0x29, 0xab, 0x24, 0xf4, 0xc2, 0x76, 0x22, + 0x40, 0xa1, 0x44, 0x23, 0xaf, 0x43, 0xe1, 0xde, 0xad, 0x8a, 0x70, 0x23, 0x90, 0x5b, 0xd2, 0xbd, + 0x5b, 0x15, 0xbe, 0x9a, 0xb9, 0x99, 0x94, 0x6e, 0xb4, 0xc5, 0xf0, 0xc9, 0xaa, 0x12, 0xff, 0x73, + 0x50, 0xcb, 0xd1, 0x23, 0xc1, 0xd1, 0xc7, 0x1d, 0x1f, 0x08, 0x94, 0xe7, 0x1b, 0x16, 0x51, 0xf6, + 0xfe, 0xad, 0x02, 0x0c, 0x47, 0xf5, 0x13, 0x02, 0x28, 0x54, 0x89, 0x9b, 0x0c, 0xfe, 0x4d, 0xce, + 0x42, 0x49, 0xca, 0x51, 0xc2, 0x9b, 0x60, 0x28, 0x10, 0x32, 0xd4, 0x0c, 0x48, 0x81, 0x89, 0x2f, + 0x73, 0x53, 0xfe, 0x24, 0xd7, 0x21, 0x92, 0x86, 0xba, 0x89, 0x4d, 0x45, 0x36, 0x60, 0x66, 0x84, + 0x46, 0xc6, 0x21, 0xef, 0xf2, 0xc8, 0x2d, 0xc3, 0x66, 0xde, 0x75, 0xc8, 0xbb, 0x50, 0xb2, 0x1d, + 0x87, 0x3a, 0x96, 0x2d, 0x8d, 0x1f, 0x7a, 0x4d, 0x9a, 0x12, 0xe3, 0xc6, 0x0f, 0x01, 0xa4, 0xaa, + 0x84, 0xa4, 0x02, 0xc3, 0x0d, 0x9b, 0x1b, 0x52, 0x39, 0x7d, 0x9c, 0x28, 0x31, 0x87, 0x12, 0x23, + 0xbb, 0x1f, 0x50, 0x87, 0xbc, 0x04, 0x45, 0x36, 0x9a, 0xe2, 0x08, 0x91, 0xe2, 0x1b, 0x1b, 0x4c, + 0xde, 0x61, 0x2b, 0xcf, 0x98, 0x88, 0x40, 0x5e, 0x80, 0x42, 0x67, 0x7e, 0x47, 0x1c, 0x0e, 0xe5, + 0x38, 0x16, 0x6f, 0x84, 0xc6, 0x8a, 0xc9, 0x0d, 0x28, 0x1d, 0xe8, 0x61, 0x5c, 0x4f, 0x25, 0x86, + 0x31, 0xc2, 0x8f, 0x10, 0x17, 0x4a, 0x30, 0xc8, 0x0f, 0x02, 0xe3, 0x39, 0x80, 0xb8, 0xea, 0xb4, + 0xd3, 0x87, 0xf1, 0x21, 0x0c, 0x47, 0x55, 0x92, 0xf3, 0x00, 0xfb, 0xf4, 0xd0, 0xda, 0xb3, 0x5b, + 0x4e, 0x83, 0xcb, 0x77, 0xa3, 0xe6, 0xf0, 0x3e, 0x3d, 0x5c, 0x41, 0x00, 0x39, 0x03, 0x43, 0x6d, + 0x36, 0xaa, 0x62, 0xea, 0x8e, 0x9a, 0x83, 0xed, 0xce, 0x36, 0x9b, 0xa1, 0x33, 0x30, 0x84, 0x9a, + 0x37, 0xb1, 0xd0, 0xc6, 0x4c, 0xf9, 0xd3, 0xf8, 0x4f, 0xf3, 0x98, 0x6e, 0x40, 0x69, 0x27, 0xb9, + 0x08, 0x63, 0x75, 0x9f, 0xe2, 0x99, 0x63, 0x33, 0x49, 0x4a, 0xd4, 0x33, 0x1a, 0x03, 0xab, 0x0e, + 0xb9, 0x04, 0x13, 0x22, 0xc5, 0x36, 0x6b, 0x50, 0x7d, 0x5b, 0xc4, 0x5c, 0x1e, 0x35, 0xc7, 0x38, + 0xf8, 0x2e, 0x3d, 0x5c, 0xdc, 0xc6, 0x88, 0x43, 0x65, 0x35, 0x60, 0x64, 0x18, 0x65, 0x46, 0x34, + 0x27, 0x14, 0x38, 0xda, 0x34, 0x9d, 0x86, 0x41, 0xdb, 0xde, 0xed, 0xb8, 0x3c, 0x32, 0xc8, 0xa8, + 0x29, 0x7e, 0x91, 0x57, 0x60, 0x32, 0x70, 0x77, 0x5b, 0x76, 0xd8, 0xf1, 0x45, 0xbe, 0x07, 0xea, + 0xe3, 0x94, 0x1a, 0x33, 0xcb, 0x51, 0xc1, 0x22, 0x87, 0x93, 0xd7, 0x80, 0xa8, 0xf5, 0x79, 0xdb, + 0x1f, 0xd1, 0x3a, 0x9f, 0x6a, 0xa3, 0xe6, 0xa4, 0x52, 0xb2, 0x8e, 0x05, 0xe4, 0x79, 0x18, 0xf5, + 0x69, 0x80, 0x52, 0x1c, 0x76, 0x1b, 0x66, 0xe3, 0x31, 0x47, 0x24, 0x8c, 0xf5, 0xdd, 0x65, 0x28, + 0x2b, 0xdd, 0x81, 0x31, 0x39, 0x79, 0xc0, 0x61, 0x73, 0x3c, 0x86, 0x9b, 0xed, 0xaa, 0x63, 0x2c, + 0xc0, 0x64, 0x6a, 0xe5, 0x2a, 0xd9, 0x6c, 0xf9, 0x4e, 0xd4, 0x3b, 0x9b, 0xad, 0xd1, 0x82, 0x51, + 0x75, 0x27, 0x3e, 0x26, 0xee, 0xf5, 0x69, 0xf4, 0x2c, 0xe7, 0xdb, 0xd4, 0xe0, 0xe3, 0xa3, 0xb9, + 0xbc, 0xeb, 0xa0, 0x3f, 0xf9, 0x65, 0x28, 0x49, 0xa1, 0x41, 0x9c, 0xd5, 0xa8, 0x39, 0x15, 0xd2, + 0xea, 0xa1, 0x19, 0x95, 0x1a, 0x2f, 0xc1, 0x90, 0xd8, 0x6c, 0x7b, 0xeb, 0x4b, 0x8d, 0x1f, 0xcb, + 0xc3, 0x84, 0x49, 0xd9, 0x56, 0x40, 0x79, 0xb0, 0xfb, 0xa7, 0xf6, 0xfa, 0x96, 0x1d, 0x9f, 0x4c, + 0xfb, 0xb6, 0x1e, 0x61, 0xe6, 0xff, 0x6e, 0x0e, 0xa6, 0x32, 0x70, 0x3f, 0x51, 0x4a, 0xb4, 0x9b, + 0x30, 0xbc, 0xe4, 0xda, 0x8d, 0x8a, 0xe3, 0x44, 0x6e, 0xe6, 0x28, 0x6a, 0x3a, 0x6c, 0xa6, 0xd9, + 0x0c, 0xaa, 0x1e, 0xbb, 0x11, 0x2a, 0x79, 0x59, 0x4c, 0x8a, 0x38, 0x1d, 0x35, 0x4e, 0x8a, 0x8f, + 0x8f, 0xe6, 0x80, 0xb7, 0x29, 0x4e, 0xbb, 0x89, 0x31, 0x03, 0x39, 0x30, 0x36, 0x03, 0x7f, 0x6a, + 0x87, 0x2e, 0x3b, 0x66, 0x60, 0xf2, 0xf3, 0xfa, 0x8a, 0x34, 0xff, 0x93, 0x79, 0x38, 0x9d, 0x4d, + 0xf8, 0x49, 0xb3, 0xdb, 0x61, 0x8c, 0x7f, 0x25, 0xce, 0x29, 0x66, 0xb7, 0xe3, 0x09, 0x01, 0x10, + 0x3f, 0x46, 0x20, 0x3b, 0x30, 0xb6, 0x6a, 0x07, 0xe1, 0x0a, 0xb5, 0xfd, 0x70, 0x9b, 0xda, 0x61, + 0x1f, 0xb2, 0xe7, 0x0b, 0xf2, 0x59, 0x12, 0x8f, 0xbf, 0x3d, 0x49, 0x99, 0x90, 0x0e, 0x75, 0xb6, + 0xd1, 0x44, 0x29, 0xf6, 0x31, 0x51, 0xbe, 0x05, 0x13, 0x35, 0xda, 0xb4, 0xdb, 0x7b, 0x9e, 0x2f, + 0xfd, 0x08, 0xaf, 0xc2, 0x58, 0x04, 0xca, 0x9c, 0x2d, 0x7a, 0xb1, 0x86, 0xaf, 0x74, 0x44, 0xbc, + 0x95, 0xe8, 0xc5, 0xc6, 0xdf, 0xc8, 0xc3, 0x99, 0x4a, 0x5d, 0x58, 0x0b, 0x89, 0x02, 0x69, 0xd4, + 0xf8, 0x19, 0xd7, 0x4d, 0xae, 0xc1, 0xf0, 0x3d, 0xfb, 0xd1, 0x2a, 0xb5, 0x03, 0x1a, 0x88, 0xdc, + 0x42, 0x5c, 0x50, 0xb3, 0x1f, 0xc5, 0x46, 0x34, 0x66, 0x8c, 0xa3, 0xde, 0x64, 0x8b, 0x9f, 0xf2, + 0x26, 0x6b, 0xc0, 0xe0, 0x8a, 0xd7, 0x70, 0xc4, 0x31, 0x26, 0x9e, 0xd7, 0xf6, 0x10, 0x62, 0x8a, + 0x12, 0x76, 0x01, 0x1c, 0x8f, 0x5a, 0x8c, 0x4d, 0xf8, 0xcc, 0xbb, 0xe4, 0x12, 0x0c, 0x61, 0x45, + 0xd5, 0x25, 0xf5, 0xd0, 0x68, 0x50, 0xcc, 0x10, 0xe3, 0x98, 0xb2, 0x50, 0xed, 0x89, 0x81, 0x4f, + 0xd7, 0x13, 0xc6, 0xbf, 0x8d, 0x2f, 0x77, 0xea, 0x57, 0xb2, 0x93, 0x48, 0x69, 0x48, 0xae, 0xcf, + 0x86, 0xe4, 0x9f, 0xd8, 0x90, 0x14, 0xba, 0x0e, 0xc9, 0x77, 0xf2, 0x30, 0x12, 0x35, 0xf6, 0x73, + 0x16, 0x6c, 0x37, 0xfa, 0xae, 0xbe, 0x7c, 0xff, 0x6b, 0xca, 0x5e, 0x21, 0x5c, 0xec, 0xdf, 0x83, + 0x41, 0xb1, 0x98, 0x72, 0x09, 0xe3, 0xbe, 0xc4, 0xe8, 0x2e, 0x8c, 0x0b, 0xd6, 0x83, 0x38, 0xa0, + 0x81, 0x29, 0xe8, 0x30, 0xb8, 0xc2, 0x16, 0xdd, 0x16, 0x0f, 0xb9, 0x4f, 0xed, 0x19, 0x95, 0x1d, + 0x5c, 0x21, 0xfe, 0xb0, 0xbe, 0x4e, 0xa7, 0x9f, 0x2f, 0x41, 0x39, 0x49, 0x72, 0x7c, 0x38, 0xe3, + 0x8d, 0xce, 0x36, 0x97, 0xc2, 0x79, 0x38, 0xe3, 0x76, 0x67, 0xdb, 0x64, 0x30, 0xb4, 0xf3, 0xf0, + 0xdd, 0x87, 0xf8, 0xd5, 0xa3, 0xc2, 0xce, 0xc3, 0x77, 0x1f, 0x6a, 0x76, 0x1e, 0xbe, 0xfb, 0x10, + 0xaf, 0xbe, 0xab, 0x35, 0xf4, 0x07, 0x45, 0x11, 0x5c, 0x5c, 0x7d, 0x1b, 0x41, 0x32, 0x0d, 0x88, + 0x44, 0x63, 0x47, 0xe5, 0x02, 0xb5, 0x7d, 0x11, 0x7a, 0x57, 0x6c, 0x67, 0x78, 0x54, 0x6e, 0x23, + 0x98, 0x67, 0xd8, 0x35, 0x55, 0x24, 0xd2, 0x00, 0xa2, 0xfc, 0x94, 0x0b, 0xf8, 0xf8, 0xdb, 0xa0, + 0x34, 0xcc, 0x99, 0x56, 0x59, 0x5b, 0xea, 0x6a, 0xce, 0xe0, 0xfb, 0x24, 0x15, 0x90, 0x1b, 0x22, + 0x9e, 0x18, 0xaa, 0x3c, 0x4a, 0xc7, 0x32, 0x93, 0x0e, 0xd3, 0xc0, 0xe3, 0x8d, 0x45, 0x8a, 0x8f, + 0x98, 0x09, 0x79, 0x07, 0x46, 0x54, 0x2f, 0x5f, 0xee, 0x8b, 0x7a, 0x8e, 0x87, 0x88, 0xea, 0x92, + 0xe4, 0x4d, 0x25, 0x20, 0xdb, 0x70, 0x66, 0xd1, 0x6b, 0x05, 0x9d, 0xa6, 0x0c, 0x46, 0x15, 0x87, + 0xc0, 0x84, 0x28, 0x49, 0xfb, 0x0b, 0x75, 0x81, 0x22, 0x9c, 0x4a, 0xa5, 0xe5, 0xb4, 0x7e, 0x01, + 0xe9, 0xc6, 0x88, 0x6c, 0xc2, 0x08, 0x2a, 0xf1, 0x84, 0x69, 0xd6, 0x88, 0xbe, 0x6d, 0xc4, 0x25, + 0x4b, 0x6c, 0x61, 0xf0, 0x68, 0x2a, 0x76, 0xb3, 0x21, 0x0d, 0x77, 0x55, 0x65, 0xa4, 0x82, 0x4c, + 0x3e, 0x84, 0x71, 0x7e, 0xdd, 0xdc, 0xa2, 0xdb, 0x7c, 0xee, 0x8c, 0x6a, 0x77, 0x67, 0xbd, 0x90, + 0x3f, 0xf4, 0x0a, 0xd5, 0xe9, 0x01, 0xdd, 0xe6, 0x63, 0xaf, 0x99, 0xcd, 0x6b, 0xf8, 0xe4, 0x3e, + 0x4c, 0xad, 0xd8, 0x01, 0x07, 0x2a, 0xee, 0x9a, 0x63, 0xa8, 0x53, 0x44, 0x73, 0xc6, 0x3d, 0x3b, + 0x90, 0xba, 0xd8, 0x4c, 0xf7, 0xcc, 0x2c, 0x7a, 0xf2, 0x63, 0x39, 0x98, 0xd1, 0x54, 0xb5, 0xc2, + 0xa8, 0xa6, 0x49, 0x5b, 0x21, 0xda, 0xc7, 0x8f, 0x47, 0xb9, 0x7d, 0xbb, 0xa1, 0xf1, 0x21, 0x49, + 0x68, 0x83, 0xfd, 0xb8, 0x5c, 0xb5, 0x13, 0xec, 0xc6, 0xc3, 0xb8, 0x99, 0xec, 0x3d, 0xa1, 0x68, + 0xc9, 0x45, 0x8a, 0x96, 0x69, 0x18, 0xc0, 0x3e, 0x92, 0xb1, 0x22, 0xf0, 0x87, 0xf1, 0x05, 0x75, + 0x57, 0x11, 0x42, 0x5e, 0xcf, 0x5d, 0xc5, 0xf8, 0xaf, 0x07, 0x61, 0x22, 0x31, 0xc8, 0xe2, 0xd6, + 0x99, 0x4b, 0xdd, 0x3a, 0x6b, 0x00, 0x5c, 0xd5, 0xd8, 0xa7, 0x4e, 0x50, 0x7a, 0xda, 0x8c, 0x08, + 0x4f, 0xb5, 0x68, 0x85, 0x28, 0x6c, 0x18, 0x53, 0xbe, 0xfe, 0xfa, 0xd4, 0xd1, 0x46, 0x4c, 0xf9, + 0x12, 0x56, 0x98, 0xc6, 0x6c, 0xc8, 0x1c, 0x0c, 0x60, 0x80, 0x37, 0xd5, 0xd1, 0xc9, 0x65, 0x00, + 0x93, 0xc3, 0xc9, 0x45, 0x18, 0x64, 0x22, 0x51, 0x75, 0x49, 0x6c, 0x69, 0x78, 0x52, 0x30, 0x99, + 0x89, 0xc9, 0x1f, 0xa2, 0x88, 0xdc, 0x84, 0x51, 0xfe, 0x97, 0xf0, 0xf1, 0x1f, 0xd4, 0xed, 0xb6, + 0x2c, 0xd7, 0x91, 0x6e, 0xfe, 0x1a, 0x1e, 0xbb, 0x2b, 0xd4, 0x3a, 0xdb, 0x3c, 0xd3, 0xbc, 0x88, + 0x08, 0x8a, 0x77, 0x85, 0x80, 0x03, 0x31, 0x13, 0x76, 0x84, 0xc0, 0x24, 0x13, 0x61, 0x6e, 0x5c, + 0xc2, 0x1b, 0x22, 0x4a, 0x26, 0xdc, 0xcc, 0xd8, 0x14, 0x25, 0xe4, 0x0a, 0x57, 0xed, 0xa3, 0x90, + 0xc7, 0x93, 0x18, 0xa1, 0xde, 0x1c, 0xd5, 0x0c, 0x28, 0xe9, 0x45, 0xc5, 0xac, 0x72, 0xf6, 0xf7, + 0x72, 0xd3, 0x76, 0x1b, 0x62, 0x93, 0xc0, 0xca, 0x11, 0x97, 0x32, 0xa8, 0x19, 0x23, 0x90, 0xb7, + 0x60, 0x9c, 0xfd, 0x58, 0xf4, 0x9a, 0x4d, 0xaf, 0x85, 0xec, 0x47, 0xe2, 0x70, 0x31, 0x48, 0x52, + 0xc7, 0x22, 0x5e, 0x4b, 0x02, 0x97, 0x9d, 0x0e, 0xf8, 0x6c, 0xd8, 0xe1, 0x8f, 0x0e, 0xa3, 0xf1, + 0xe9, 0x80, 0xa4, 0x01, 0x87, 0x9b, 0x2a, 0x12, 0x79, 0x03, 0xc6, 0xd8, 0xcf, 0xdb, 0xee, 0x43, + 0xca, 0x2b, 0x1c, 0x8b, 0x1f, 0xb2, 0x91, 0x6a, 0x97, 0x95, 0xf0, 0xfa, 0x74, 0x4c, 0xf2, 0x55, + 0x38, 0x85, 0x9c, 0xea, 0x5e, 0x9b, 0x3a, 0x95, 0x9d, 0x1d, 0xb7, 0xe1, 0x72, 0x43, 0x1a, 0xee, + 0xcd, 0x8e, 0x3a, 0x60, 0x5e, 0x31, 0x62, 0x58, 0x76, 0x8c, 0x62, 0x66, 0x53, 0x92, 0x2d, 0x28, + 0x2f, 0x76, 0x82, 0xd0, 0x6b, 0x56, 0xc2, 0xd0, 0x77, 0xb7, 0x3b, 0x21, 0x0d, 0x66, 0x26, 0x34, + 0x9f, 0x6f, 0xb6, 0x38, 0xa2, 0x42, 0xae, 0xdd, 0xa9, 0x23, 0x85, 0x65, 0x47, 0x24, 0x66, 0x8a, + 0x89, 0xf1, 0x5f, 0xe5, 0x60, 0x4c, 0x23, 0x25, 0xaf, 0xc3, 0xe8, 0x2d, 0xdf, 0xa5, 0x2d, 0xa7, + 0x71, 0xa8, 0x5c, 0x3b, 0xf1, 0x4e, 0xb2, 0x23, 0xe0, 0xfc, 0xab, 0x35, 0xb4, 0x48, 0x6b, 0x93, + 0xcf, 0xb4, 0x72, 0xbb, 0xc6, 0xfd, 0xed, 0xc4, 0x04, 0x2d, 0xc4, 0x41, 0x28, 0x70, 0x82, 0x8a, + 0xd9, 0xa9, 0xa0, 0x90, 0xb7, 0x61, 0x90, 0x3f, 0x30, 0x0a, 0x93, 0xab, 0xb3, 0x59, 0x9f, 0xc9, + 0x7d, 0x3b, 0x71, 0x22, 0xa2, 0x79, 0x47, 0x60, 0x0a, 0x22, 0xe3, 0x67, 0x73, 0x40, 0xd2, 0xa8, + 0xc7, 0x68, 0xb1, 0x8e, 0x35, 0x1b, 0x79, 0x2f, 0x5a, 0x8d, 0x05, 0x4d, 0x67, 0xcb, 0x6a, 0xe2, + 0x05, 0xbc, 0xe3, 0xc5, 0xaa, 0x53, 0xd5, 0x6a, 0xbc, 0xd8, 0xf8, 0xcb, 0x79, 0x80, 0x18, 0x9b, + 0x7c, 0x99, 0xe7, 0xd1, 0xf8, 0x6a, 0xc7, 0x6e, 0xb8, 0x3b, 0xae, 0x1e, 0x58, 0x0e, 0x99, 0x7c, + 0x4b, 0x96, 0x98, 0x3a, 0x22, 0x79, 0x17, 0x26, 0x6a, 0x1b, 0x3a, 0xad, 0x92, 0x33, 0x20, 0x68, + 0x5b, 0x09, 0xf2, 0x24, 0x36, 0x9a, 0x56, 0xaa, 0xa3, 0xc1, 0x4d, 0x2b, 0xf9, 0x40, 0x88, 0x12, + 0xb6, 0xb1, 0xd4, 0x36, 0x84, 0x35, 0xaf, 0x53, 0x5d, 0x12, 0xbb, 0x14, 0xb6, 0x2e, 0x68, 0x5b, + 0x6d, 0x61, 0xe6, 0xcb, 0xf6, 0x09, 0x0d, 0x2f, 0xee, 0xc8, 0x81, 0x2e, 0xfe, 0x9b, 0x3f, 0x87, + 0x4a, 0xbc, 0xa6, 0x17, 0x52, 0xa1, 0xbb, 0x78, 0x6a, 0x6f, 0x31, 0xf1, 0xeb, 0xf4, 0x80, 0xe6, + 0x96, 0xa6, 0x7d, 0x9d, 0xb0, 0x8d, 0xb8, 0x11, 0x5f, 0x39, 0xf8, 0x3b, 0x75, 0x86, 0x35, 0xc5, + 0xdf, 0xce, 0xc1, 0xa9, 0x4c, 0x5a, 0x72, 0x15, 0x20, 0xd6, 0x10, 0x89, 0x5e, 0xc2, 0x1d, 0x33, + 0x0e, 0xbd, 0x60, 0x2a, 0x18, 0xe4, 0xeb, 0x49, 0xdd, 0xce, 0xf1, 0x07, 0xe1, 0xac, 0x0c, 0xad, + 0xa3, 0xeb, 0x76, 0x32, 0x34, 0x3a, 0xc6, 0xdf, 0x2d, 0xc0, 0xa4, 0x12, 0xd9, 0x81, 0xb7, 0xf5, + 0x18, 0x53, 0xd7, 0x7d, 0x18, 0x65, 0x5f, 0xe3, 0xd6, 0x85, 0x6f, 0x0c, 0xb7, 0xa4, 0x78, 0x39, + 0xe5, 0x58, 0x24, 0xb8, 0x5d, 0x55, 0x91, 0x79, 0xc0, 0x2b, 0xdc, 0x3a, 0x51, 0x73, 0x5e, 0x4f, + 0xfb, 0xc8, 0x68, 0xcc, 0x49, 0x00, 0x63, 0x4b, 0x87, 0x2d, 0xbb, 0x19, 0xd5, 0xc6, 0x2d, 0x2a, + 0x5e, 0xe9, 0x5a, 0x9b, 0x86, 0xcd, 0xab, 0x8b, 0x4d, 0xf0, 0x79, 0x59, 0x86, 0xf7, 0xa7, 0x46, + 0x35, 0xfb, 0x2e, 0x4c, 0xa6, 0x1a, 0x7d, 0xa2, 0xd8, 0x5b, 0x5b, 0x40, 0xd2, 0xed, 0xc8, 0xe0, + 0xf0, 0x8a, 0x1e, 0xd9, 0xed, 0x54, 0xf4, 0x78, 0x8a, 0x19, 0x78, 0xb9, 0x7d, 0xc6, 0xbc, 0x1a, + 0x99, 0xeb, 0xe7, 0xf2, 0xaa, 0x73, 0xd7, 0xd3, 0xbe, 0xea, 0xde, 0xd3, 0xee, 0xb6, 0xcf, 0x75, + 0x1b, 0xd3, 0xbe, 0x74, 0x08, 0xdf, 0x2f, 0xc0, 0x99, 0x2e, 0x94, 0xe4, 0x30, 0x39, 0x89, 0xb8, + 0x4e, 0xe1, 0x7a, 0xef, 0x0a, 0x9f, 0xc4, 0x54, 0x22, 0x5f, 0xe6, 0xee, 0xdd, 0x75, 0xcc, 0x1c, + 0x2b, 0x6e, 0xd3, 0x3c, 0xe9, 0x78, 0x04, 0x4d, 0xfa, 0x75, 0x73, 0x28, 0x79, 0x17, 0x06, 0xd0, + 0xb3, 0x2f, 0x11, 0x59, 0x8a, 0x61, 0x20, 0x5c, 0x09, 0xc3, 0xc5, 0x7e, 0x6a, 0x61, 0xb8, 0x18, + 0x80, 0x7c, 0x09, 0x0a, 0x95, 0xad, 0x9a, 0x18, 0x97, 0x71, 0x95, 0x7c, 0xab, 0x16, 0x47, 0xff, + 0xb6, 0xb5, 0x30, 0xdd, 0x8c, 0x82, 0x11, 0xde, 0x5e, 0xdc, 0x10, 0xa3, 0xa2, 0x12, 0xde, 0x5e, + 0xdc, 0x88, 0x09, 0x77, 0xeb, 0x5a, 0xa4, 0x8e, 0xdb, 0x8b, 0x1b, 0x9f, 0xdd, 0xb4, 0xff, 0x6b, + 0x79, 0xee, 0x93, 0xce, 0x3f, 0xec, 0x5d, 0x18, 0xd5, 0x22, 0x6f, 0xe6, 0x62, 0x79, 0x2c, 0x0a, + 0x70, 0x9a, 0x30, 0x41, 0xd1, 0x08, 0x64, 0x1c, 0x7d, 0xf6, 0x1b, 0x25, 0x5e, 0xd5, 0xd8, 0x23, + 0xe2, 0x80, 0x32, 0x71, 0x32, 0x8e, 0x7e, 0x44, 0x42, 0x6e, 0x40, 0x69, 0x93, 0xb6, 0xec, 0x56, + 0x18, 0xa9, 0x37, 0xd1, 0x8c, 0x34, 0x44, 0x98, 0x2e, 0x35, 0x44, 0x88, 0x68, 0xf2, 0xd8, 0xd9, + 0x0e, 0xea, 0xbe, 0x8b, 0xb1, 0x2b, 0xa2, 0xb3, 0x98, 0x9b, 0x3c, 0x2a, 0x25, 0x3a, 0x83, 0x04, + 0x91, 0xf1, 0x73, 0x39, 0x18, 0x12, 0x03, 0xc9, 0xf3, 0x9f, 0xec, 0xc6, 0x67, 0x89, 0xc8, 0x7f, + 0xb2, 0xeb, 0x26, 0xf3, 0x9f, 0xec, 0xf2, 0x00, 0x11, 0xc3, 0xc2, 0xbd, 0x32, 0x7a, 0xe8, 0xe3, + 0xe9, 0xb2, 0x39, 0x50, 0xaf, 0x36, 0x46, 0xed, 0xd7, 0x97, 0xc4, 0xf8, 0x9b, 0xa2, 0x65, 0xb7, + 0x17, 0x37, 0xc8, 0x3c, 0x94, 0x56, 0xbd, 0xba, 0xad, 0x9c, 0x73, 0xb8, 0xed, 0x34, 0x04, 0x4c, + 0xed, 0x20, 0x89, 0xc7, 0xda, 0xb7, 0xe1, 0x7b, 0xe2, 0x2e, 0xa3, 0xb4, 0xaf, 0xcd, 0x81, 0x89, + 0xf6, 0x45, 0xa8, 0x7d, 0xb7, 0x8f, 0x66, 0x6c, 0x12, 0x0f, 0x6e, 0x60, 0x80, 0xf1, 0x3b, 0xaa, + 0x8f, 0x8e, 0x28, 0x92, 0x3b, 0xc5, 0x6c, 0xb7, 0x9d, 0xe2, 0xc1, 0x0d, 0x33, 0x83, 0x0a, 0x5f, + 0xc9, 0x62, 0x70, 0x8d, 0xfa, 0x0f, 0x9f, 0xe2, 0x5d, 0x3a, 0xfb, 0x95, 0x2c, 0xf9, 0x79, 0x7d, + 0x6d, 0xd2, 0xff, 0x79, 0x1e, 0x4e, 0x67, 0x13, 0xaa, 0xdf, 0x92, 0xeb, 0xf1, 0x2d, 0x97, 0xa1, + 0xb4, 0xe2, 0x05, 0xa1, 0x62, 0x75, 0x86, 0xca, 0xfc, 0x3d, 0x01, 0x33, 0xa3, 0x52, 0x76, 0xe7, + 0x66, 0x7f, 0x47, 0xcb, 0x13, 0xf9, 0xa1, 0x27, 0x36, 0xbb, 0x73, 0xf3, 0x22, 0x72, 0x1b, 0x4a, + 0xa6, 0xf0, 0x11, 0x49, 0x74, 0x8d, 0x04, 0x47, 0xd2, 0x14, 0xf1, 0x05, 0x44, 0x0b, 0x80, 0x2a, + 0x60, 0xa4, 0x02, 0x43, 0x62, 0xf4, 0x13, 0x0f, 0xc1, 0x19, 0x53, 0x46, 0x8f, 0x49, 0x2c, 0xe9, + 0xd8, 0x8e, 0x82, 0x4f, 0x7a, 0xd5, 0x25, 0xe9, 0xee, 0x81, 0x3b, 0x0a, 0x7f, 0xf2, 0xd3, 0x0d, + 0xfc, 0x22, 0x44, 0xe3, 0xc7, 0xf2, 0x00, 0x52, 0x6b, 0xf3, 0xd4, 0xce, 0xb0, 0x2f, 0x69, 0x33, + 0x4c, 0xb1, 0x77, 0xe9, 0x3f, 0x5f, 0xdf, 0x3a, 0xda, 0x9d, 0xf4, 0x9f, 0xad, 0x6f, 0x0e, 0x06, + 0x36, 0x63, 0x85, 0x96, 0x70, 0x3e, 0x40, 0xe5, 0x32, 0x87, 0x1b, 0xdb, 0x30, 0x7d, 0x9b, 0x86, + 0xb1, 0x7a, 0x4b, 0x3e, 0x24, 0xf6, 0x66, 0xfb, 0x2a, 0x0c, 0x0b, 0xfc, 0x68, 0xff, 0xe2, 0xba, + 0x18, 0x11, 0xdc, 0x00, 0x75, 0x31, 0x12, 0x81, 0xed, 0x46, 0x4b, 0xb4, 0x41, 0x43, 0xfa, 0xd9, + 0x56, 0x53, 0x03, 0xc2, 0x3f, 0x05, 0xbf, 0xac, 0xbf, 0x1a, 0x8e, 0xed, 0x9f, 0x07, 0x70, 0x2a, + 0x6a, 0xfb, 0x93, 0xe4, 0x7b, 0x8d, 0x5d, 0x29, 0x45, 0x38, 0xdf, 0x98, 0x63, 0x0f, 0x4b, 0x92, + 0x47, 0x30, 0x2b, 0x09, 0xb6, 0xdc, 0xc8, 0x70, 0xaf, 0x2f, 0x5a, 0xf2, 0x16, 0x8c, 0x28, 0x34, + 0x22, 0x1c, 0x2d, 0x2a, 0x9d, 0x0f, 0xdc, 0x70, 0xcf, 0x0a, 0x38, 0x5c, 0x55, 0x3a, 0x2b, 0xe8, + 0xc6, 0x07, 0xf0, 0x6c, 0xe4, 0x20, 0x92, 0x51, 0x75, 0x82, 0x79, 0xee, 0x64, 0xcc, 0xd7, 0xe2, + 0xcf, 0xaa, 0xb6, 0x22, 0xa7, 0x4e, 0xc9, 0x9b, 0xa8, 0x9f, 0x25, 0x3e, 0xe6, 0x5c, 0xca, 0x4d, + 0x54, 0xf1, 0x06, 0x35, 0xde, 0x54, 0x1a, 0x9b, 0xc1, 0x50, 0x23, 0xce, 0x25, 0x89, 0x7f, 0x2c, + 0x0f, 0x13, 0xeb, 0xd5, 0xa5, 0xc5, 0xc8, 0x96, 0xe8, 0x73, 0x96, 0x4d, 0x50, 0xfb, 0xb6, 0xee, + 0xfb, 0x8d, 0x71, 0x1f, 0xa6, 0x12, 0xdd, 0x80, 0xa2, 0xc3, 0x3b, 0xdc, 0x83, 0x21, 0x02, 0x4b, + 0xb1, 0xe1, 0x74, 0x16, 0xfb, 0x07, 0x37, 0xcc, 0x04, 0xb6, 0xf1, 0x8f, 0x87, 0x13, 0x7c, 0xc5, + 0x16, 0xf6, 0x2a, 0x0c, 0x57, 0x83, 0xa0, 0x43, 0xfd, 0xfb, 0xe6, 0xaa, 0xaa, 0x2a, 0x70, 0x11, + 0x68, 0x75, 0xfc, 0x86, 0x19, 0x23, 0x90, 0x2b, 0x50, 0x12, 0x11, 0x5a, 0xe5, 0x9e, 0x80, 0x5a, + 0xdb, 0x28, 0xc0, 0xab, 0x19, 0x15, 0x93, 0xd7, 0x61, 0x94, 0xff, 0xcd, 0x67, 0x9b, 0xe8, 0x70, + 0x54, 0x0e, 0x0a, 0x74, 0x3e, 0x3b, 0x4d, 0x0d, 0x8d, 0xbc, 0x0c, 0x85, 0xca, 0xa2, 0x29, 0xd4, + 0x41, 0x42, 0x6e, 0xc4, 0x1c, 0xc1, 0x1d, 0xaa, 0x5f, 0x22, 0x16, 0x4d, 0x26, 0xfd, 0x49, 0x07, + 0x72, 0xa1, 0xc9, 0xe6, 0xa9, 0x8c, 0x05, 0x2c, 0x71, 0x98, 0x21, 0x8c, 0x5c, 0x83, 0xa1, 0x25, + 0x37, 0x68, 0x37, 0xec, 0x43, 0xa1, 0xc7, 0xe6, 0xa9, 0x72, 0x38, 0x48, 0xf3, 0x0b, 0xe7, 0x20, + 0x72, 0x45, 0xa6, 0x10, 0x29, 0xc5, 0x8e, 0x10, 0x5d, 0xf2, 0x84, 0xbc, 0x0a, 0x83, 0x22, 0x8e, + 0xe9, 0xb0, 0x12, 0xa1, 0x3c, 0x19, 0xbf, 0x54, 0xe0, 0xa4, 0x5d, 0x15, 0xe1, 0x49, 0xba, 0x2a, + 0x6e, 0xc3, 0x99, 0xdb, 0xa8, 0xbd, 0xd1, 0x23, 0x9e, 0xdc, 0x37, 0xab, 0x42, 0x1f, 0x8e, 0x8f, + 0x3a, 0x5c, 0xc1, 0x93, 0x0c, 0x9a, 0x62, 0x75, 0x7c, 0x35, 0xf3, 0x5b, 0x37, 0x46, 0xe4, 0x6b, + 0x30, 0x9d, 0x55, 0x24, 0xb4, 0xe6, 0x18, 0xdb, 0x23, 0xbb, 0x02, 0x35, 0xb6, 0x47, 0x16, 0x07, + 0xb2, 0x0a, 0x65, 0x0e, 0xaf, 0x38, 0x4d, 0xb7, 0xc5, 0x35, 0xff, 0x5c, 0xab, 0x8e, 0x9e, 0x09, + 0x82, 0xab, 0xcd, 0x0a, 0xf9, 0x0b, 0x80, 0xe6, 0xcb, 0x92, 0xa0, 0x24, 0x3f, 0x9d, 0x63, 0xb7, + 0x39, 0x1e, 0xf5, 0xf3, 0xbe, 0xb9, 0x1a, 0x88, 0xb8, 0x50, 0xa7, 0x63, 0x37, 0x95, 0x5a, 0xe8, + 0xbb, 0xad, 0x5d, 0xe1, 0xa7, 0xb2, 0x29, 0xfc, 0x54, 0xde, 0xfa, 0x44, 0x7e, 0x2a, 0x9c, 0x55, + 0xf0, 0xf8, 0x68, 0x6e, 0xd4, 0x17, 0x75, 0xe2, 0x2a, 0xd2, 0x5a, 0x80, 0x59, 0xcb, 0x1b, 0x0d, + 0xef, 0xe0, 0x7e, 0xeb, 0x21, 0xf5, 0xdd, 0x1d, 0x97, 0x3a, 0xfc, 0x23, 0x27, 0x70, 0x07, 0xe7, + 0x59, 0xcb, 0x31, 0x0f, 0x7f, 0x27, 0x42, 0x48, 0x7d, 0x68, 0x26, 0x07, 0x76, 0xf1, 0x94, 0xbe, + 0x10, 0xdc, 0xef, 0xb2, 0x1c, 0x5f, 0x3c, 0xa5, 0xe3, 0x84, 0x85, 0xd3, 0x48, 0x9d, 0x3c, 0x1a, + 0x09, 0xb9, 0x06, 0x83, 0xf7, 0xec, 0x47, 0x95, 0x5d, 0x2a, 0x52, 0x43, 0x8d, 0xc9, 0xed, 0x0f, + 0x81, 0x0b, 0xa5, 0xdf, 0xe7, 0xb6, 0xf6, 0xcf, 0x98, 0x02, 0x8d, 0xfc, 0x50, 0x0e, 0x4e, 0xf3, + 0x65, 0x2c, 0xbf, 0xb2, 0x46, 0xc3, 0x90, 0xf5, 0x83, 0x08, 0x10, 0x25, 0x13, 0x2b, 0xd4, 0x6a, + 0xeb, 0xd9, 0x78, 0x3c, 0xc7, 0xb6, 0xd8, 0x19, 0xa2, 0x8e, 0x0b, 0x44, 0xa9, 0x16, 0x05, 0x32, + 0x93, 0x5e, 0xd8, 0x91, 0x7f, 0x49, 0xb6, 0x9c, 0xbc, 0xa6, 0xba, 0x07, 0x16, 0x50, 0xce, 0x1d, + 0x6a, 0xda, 0x8f, 0x2c, 0x7b, 0x97, 0x6a, 0xaf, 0xd3, 0x42, 0xcf, 0xfc, 0xdd, 0x1c, 0x9c, 0xed, + 0xda, 0x38, 0x72, 0x13, 0xce, 0xc8, 0x74, 0xeb, 0x7b, 0x61, 0xd8, 0x0e, 0x2c, 0x79, 0x19, 0x10, + 0x0e, 0x85, 0xe6, 0x29, 0x51, 0xbc, 0xc2, 0x4a, 0xe5, 0xfd, 0x20, 0x20, 0xef, 0xc2, 0x39, 0xb7, + 0x15, 0xd0, 0x7a, 0xc7, 0xa7, 0x71, 0xbe, 0x76, 0xd7, 0xf1, 0x2d, 0xdf, 0x6e, 0xed, 0x4a, 0xef, + 0x48, 0xf3, 0xac, 0xc4, 0x91, 0x59, 0xdb, 0x5d, 0xc7, 0x37, 0x11, 0xc1, 0xf8, 0xa3, 0x61, 0x7e, + 0x2a, 0x56, 0x3a, 0xe1, 0x9e, 0x3c, 0x47, 0xe7, 0xb3, 0x7c, 0x6a, 0xb8, 0xb1, 0x9f, 0xe2, 0x53, + 0xa3, 0x7b, 0xd2, 0xc8, 0xe7, 0x8c, 0x7c, 0xe6, 0x73, 0xc6, 0xab, 0x30, 0xbc, 0xb8, 0x47, 0xeb, + 0xfb, 0x91, 0x5f, 0x43, 0x49, 0xe8, 0x8b, 0x19, 0x90, 0x87, 0x18, 0x8d, 0x11, 0xc8, 0x35, 0x00, + 0x74, 0xb2, 0xe3, 0x42, 0x96, 0x12, 0x26, 0x1c, 0x7d, 0xf2, 0x84, 0xfd, 0x84, 0x82, 0x82, 0xec, + 0x6b, 0xe6, 0x2d, 0xd5, 0xe0, 0x82, 0xb3, 0x0f, 0xfc, 0x1d, 0x81, 0x1e, 0x23, 0xb0, 0xcf, 0x53, + 0x96, 0x8a, 0xd8, 0xd8, 0xcb, 0xa9, 0xf5, 0xa4, 0x22, 0xa1, 0x2d, 0xa3, 0x34, 0xe2, 0xc6, 0x7d, + 0x7d, 0x54, 0xd8, 0x32, 0x46, 0x06, 0xdf, 0x66, 0x8c, 0x40, 0xbe, 0x04, 0x43, 0x8b, 0xd4, 0x0f, + 0x37, 0x37, 0x57, 0xd1, 0x26, 0x82, 0xc7, 0xd2, 0x2e, 0x61, 0xdc, 0xe3, 0x30, 0x6c, 0x7c, 0x7c, + 0x34, 0x37, 0x16, 0xba, 0x4d, 0x7a, 0x35, 0x9a, 0x22, 0x12, 0x9b, 0x2c, 0x40, 0x99, 0xbf, 0xf3, + 0xc6, 0xc2, 0x34, 0x6e, 0xf5, 0x25, 0x7e, 0xf0, 0x88, 0x47, 0xe1, 0x03, 0xba, 0x1d, 0x45, 0x7d, + 0x4e, 0xe1, 0x93, 0x65, 0x19, 0x2c, 0x5d, 0xfd, 0x48, 0x88, 0xb5, 0x3b, 0xc9, 0x25, 0xc0, 0xbe, + 0x35, 0x4d, 0x41, 0x2a, 0x30, 0xb6, 0xe8, 0x35, 0xdb, 0x76, 0xe8, 0x62, 0xe6, 0xa1, 0x43, 0xb1, + 0xab, 0xa3, 0x86, 0xaa, 0xae, 0x16, 0x68, 0x47, 0x84, 0x5a, 0x40, 0x6e, 0xc1, 0xb8, 0xe9, 0x75, + 0xd8, 0x20, 0xc9, 0x6b, 0x25, 0xdf, 0xb8, 0xd1, 0x72, 0xc1, 0x67, 0x25, 0xec, 0x9c, 0x11, 0x77, + 0x48, 0x2d, 0x66, 0x9d, 0x46, 0x45, 0xd6, 0x32, 0xf4, 0xfb, 0xea, 0x6e, 0xad, 0xc6, 0x7e, 0x4e, + 0x31, 0xcb, 0x78, 0x1a, 0xb8, 0x01, 0x23, 0xb5, 0xda, 0xfa, 0x26, 0x0d, 0xc2, 0x5b, 0x0d, 0xef, + 0x00, 0x37, 0xeb, 0x92, 0xc8, 0x89, 0x11, 0x78, 0x56, 0x48, 0x83, 0xd0, 0xda, 0x69, 0x78, 0x07, + 0xa6, 0x8a, 0x45, 0xbe, 0xc1, 0xfa, 0x43, 0x11, 0x6d, 0x44, 0x74, 0xbe, 0x5e, 0xd2, 0x17, 0x6e, + 0x89, 0xf1, 0x92, 0x61, 0x32, 0x98, 0xde, 0x59, 0x0a, 0x3a, 0x3a, 0xe9, 0xb0, 0x0b, 0x71, 0xc5, + 0x71, 0x7c, 0x1a, 0x04, 0x62, 0x57, 0xe5, 0x4e, 0x3a, 0x78, 0x7b, 0xb6, 0x79, 0x81, 0xe6, 0xa4, + 0xa3, 0x10, 0x90, 0xef, 0xe4, 0xe0, 0x94, 0x6a, 0xe7, 0x8f, 0x8b, 0x05, 0xad, 0x30, 0xf8, 0x1e, + 0xfb, 0xda, 0x55, 0x79, 0xaa, 0x5c, 0x55, 0xd0, 0xae, 0x3e, 0xbc, 0x7e, 0xb5, 0x12, 0xff, 0xac, + 0x49, 0x22, 0x11, 0xe0, 0x2a, 0x8b, 0x9f, 0x7a, 0x42, 0xd8, 0x19, 0xa4, 0x64, 0x91, 0x09, 0x1e, + 0x6c, 0x3e, 0xa1, 0x55, 0x4f, 0x75, 0x03, 0xb7, 0x68, 0xa1, 0x20, 0x14, 0xb3, 0x8f, 0xdb, 0xff, + 0xb8, 0x6d, 0x5d, 0xbe, 0x50, 0x68, 0x48, 0x15, 0x26, 0x38, 0x80, 0x6d, 0x09, 0x3c, 0x61, 0xc2, + 0x54, 0x1c, 0xb4, 0x59, 0xb0, 0xc1, 0xa7, 0x6b, 0x4c, 0x9a, 0xa0, 0x06, 0x93, 0x4b, 0xd0, 0xa1, + 0xe4, 0x5f, 0xab, 0xdc, 0x5b, 0x8d, 0xc5, 0xd7, 0xcf, 0x97, 0x9d, 0xbe, 0xf6, 0x6d, 0x3d, 0xec, + 0xf4, 0xef, 0x73, 0xcf, 0x45, 0xa5, 0x1b, 0xa4, 0xe4, 0xaf, 0x81, 0x93, 0x92, 0x7f, 0x82, 0xc6, + 0x4c, 0x60, 0x1b, 0x1f, 0x97, 0x12, 0x7c, 0x85, 0x6d, 0x9e, 0x01, 0x83, 0x5c, 0xb0, 0x57, 0xb3, + 0x6f, 0x73, 0xb1, 0xdf, 0x14, 0x25, 0xe4, 0x2c, 0x14, 0x6a, 0xb5, 0x75, 0xd1, 0xc9, 0x68, 0xa1, + 0x17, 0x04, 0x9e, 0xc9, 0x60, 0x6c, 0x84, 0xd0, 0xec, 0x4e, 0x89, 0xcb, 0xcb, 0x76, 0x50, 0x13, + 0xa1, 0xac, 0xbf, 0xa5, 0x98, 0x5d, 0x8c, 0xfb, 0x5b, 0x88, 0xd9, 0xb1, 0x70, 0xbd, 0x08, 0x33, + 0x95, 0x20, 0xa0, 0x3e, 0x9b, 0xa0, 0xc2, 0x9a, 0xcb, 0x17, 0xa2, 0xa0, 0x38, 0x28, 0xb0, 0x52, + 0xbb, 0x1e, 0x98, 0x5d, 0x11, 0xc9, 0x65, 0x28, 0x55, 0x3a, 0x8e, 0x4b, 0x5b, 0x75, 0x2d, 0xe8, + 0x8e, 0x2d, 0x60, 0x66, 0x54, 0x4a, 0xbe, 0x0a, 0xa7, 0x12, 0x81, 0xa7, 0x44, 0x0f, 0x0c, 0xc5, + 0xab, 0x59, 0x8a, 0xaa, 0xf1, 0x9b, 0x35, 0xef, 0x92, 0x6c, 0x4a, 0x52, 0x81, 0xf2, 0x32, 0xfa, + 0xa5, 0x2c, 0x51, 0xae, 0x3e, 0xf7, 0x7c, 0xee, 0x6b, 0xc3, 0x2f, 0x16, 0xdc, 0x67, 0xc5, 0x72, + 0xa2, 0x42, 0x33, 0x85, 0x4e, 0xee, 0xc2, 0x54, 0x12, 0xc6, 0xce, 0x04, 0x7e, 0x87, 0xc0, 0xc0, + 0x90, 0x29, 0x2e, 0x78, 0x2a, 0x64, 0x51, 0x91, 0x6d, 0x98, 0x8c, 0x6d, 0x36, 0xf4, 0x9b, 0x85, + 0x34, 0xec, 0x8c, 0xca, 0xe5, 0xed, 0xe2, 0x59, 0x31, 0x19, 0xa7, 0x62, 0xfb, 0x8f, 0xe8, 0x86, + 0x61, 0xa6, 0xd9, 0x11, 0x07, 0xc6, 0x6b, 0xee, 0x6e, 0xcb, 0x6d, 0xed, 0xde, 0xa5, 0x87, 0x1b, + 0xb6, 0xeb, 0x0b, 0x13, 0x3b, 0x69, 0x40, 0x5b, 0x09, 0x0e, 0x9b, 0x4d, 0x1a, 0xfa, 0x78, 0xda, + 0xb2, 0x72, 0x74, 0x13, 0x65, 0x12, 0xe3, 0x6c, 0xc0, 0xe9, 0xd0, 0x05, 0xab, 0x6d, 0xbb, 0xda, + 0xb1, 0xa2, 0xf3, 0xd4, 0x6e, 0x77, 0xa3, 0x7d, 0xde, 0xee, 0x1a, 0x30, 0xb9, 0xdc, 0xaa, 0xfb, + 0x87, 0xf8, 0x8a, 0x21, 0x1b, 0x37, 0x76, 0x4c, 0xe3, 0x5e, 0x10, 0x8d, 0x3b, 0x67, 0xcb, 0x19, + 0x96, 0xd5, 0xbc, 0x34, 0x63, 0x52, 0x83, 0x49, 0x94, 0xd8, 0xaa, 0x4b, 0x1b, 0xd5, 0x96, 0x1b, + 0xba, 0x98, 0x23, 0x9a, 0x1f, 0x57, 0x2f, 0x0a, 0x9e, 0xe7, 0xb9, 0x14, 0xef, 0x3a, 0x6d, 0xcb, + 0x95, 0x28, 0x2a, 0xd3, 0x14, 0x7d, 0x2f, 0x51, 0x7a, 0xe2, 0x9f, 0x8f, 0x28, 0x8d, 0x59, 0x94, + 0x12, 0xee, 0xd3, 0xe5, 0x78, 0x6f, 0x0f, 0xb0, 0x88, 0x1d, 0x11, 0x5e, 0x07, 0xc5, 0x13, 0x2d, + 0x8b, 0x92, 0x4e, 0x67, 0x7c, 0x67, 0x98, 0xef, 0xed, 0xaa, 0xfc, 0xda, 0xcd, 0x18, 0x2f, 0x21, + 0xd7, 0xe6, 0x4f, 0x22, 0xd7, 0x16, 0x8e, 0x97, 0x6b, 0x8b, 0xc7, 0xc9, 0xb5, 0x09, 0xc1, 0x73, + 0xe0, 0xc4, 0x82, 0xe7, 0xe0, 0x09, 0x04, 0xcf, 0xa1, 0x13, 0x09, 0x9e, 0x9a, 0x04, 0x5d, 0x3a, + 0x4e, 0x82, 0xfe, 0x97, 0x62, 0xea, 0xd3, 0x2a, 0xa6, 0x66, 0x89, 0x0a, 0x27, 0x12, 0x53, 0xbb, + 0x4b, 0x99, 0xe5, 0x7f, 0xd1, 0x52, 0xe6, 0xe4, 0x93, 0x91, 0x32, 0xc9, 0x27, 0x94, 0x32, 0xff, + 0x02, 0x94, 0x93, 0x07, 0xdf, 0xf1, 0xf1, 0xf6, 0x9e, 0x58, 0x6c, 0x28, 0x76, 0x2c, 0x27, 0x0f, + 0x1e, 0x76, 0x91, 0xde, 0xf0, 0xdd, 0x87, 0x76, 0x48, 0xef, 0x4a, 0xe3, 0x05, 0x11, 0x2b, 0x92, + 0x43, 0x71, 0xfb, 0x50, 0x50, 0x22, 0x99, 0x2b, 0x9f, 0x25, 0x73, 0x19, 0x3f, 0x9e, 0x87, 0x49, + 0x1e, 0xc7, 0xe5, 0xe9, 0xd7, 0xa1, 0xbf, 0xa3, 0x49, 0xd2, 0xd2, 0x54, 0x2e, 0xf1, 0x75, 0x3d, + 0xb4, 0xe8, 0x1f, 0xc2, 0xa9, 0x54, 0x57, 0xa0, 0x34, 0xbd, 0x24, 0x23, 0xe8, 0xa4, 0xe4, 0xe9, + 0x99, 0xec, 0x4a, 0x1e, 0xdc, 0x30, 0x53, 0x14, 0xc6, 0x3f, 0x2d, 0xa6, 0xf8, 0x0b, 0x7d, 0xba, + 0xaa, 0x21, 0xcf, 0x9d, 0x4c, 0x43, 0x9e, 0xef, 0x4f, 0x43, 0x9e, 0x38, 0xa6, 0x0a, 0xfd, 0x1c, + 0x53, 0x5f, 0x85, 0xb1, 0x4d, 0x6a, 0x37, 0x83, 0x4d, 0x4f, 0x04, 0x84, 0xe7, 0xa6, 0xb2, 0x32, + 0x40, 0x0e, 0x2b, 0x93, 0xc2, 0x60, 0x64, 0xf2, 0x13, 0x32, 0x02, 0xb6, 0xb5, 0xf2, 0x08, 0xf1, + 0xa6, 0xce, 0x41, 0x95, 0xf0, 0x07, 0x7a, 0x48, 0xf8, 0x35, 0x18, 0x15, 0x74, 0x71, 0x90, 0xc1, + 0x58, 0x14, 0x65, 0x45, 0x08, 0x97, 0xb5, 0x47, 0x29, 0xfb, 0xa2, 0xda, 0xb9, 0x14, 0xaa, 0x31, + 0x61, 0x5d, 0xb0, 0xdc, 0x72, 0xda, 0x9e, 0xdb, 0xc2, 0x2e, 0x18, 0x8a, 0xbb, 0x80, 0x0a, 0x30, + 0xef, 0x02, 0x05, 0x89, 0xbc, 0x05, 0xe3, 0x95, 0x8d, 0xaa, 0x4a, 0x56, 0x8a, 0x95, 0xf4, 0x76, + 0xdb, 0xb5, 0x34, 0xd2, 0x04, 0x6e, 0x2f, 0xa9, 0x6c, 0xf8, 0x9f, 0x8f, 0x54, 0x66, 0xfc, 0xc3, + 0x61, 0xb9, 0xbc, 0x3f, 0x5b, 0x65, 0xa0, 0xae, 0xde, 0x2b, 0x9c, 0x50, 0xbd, 0x57, 0x3c, 0x4e, + 0x38, 0xd1, 0x24, 0xa6, 0x81, 0x13, 0x48, 0x4c, 0x83, 0x9f, 0x5a, 0x55, 0x37, 0x74, 0x42, 0x19, + 0x28, 0xb1, 0xd2, 0x4a, 0xfd, 0xac, 0xb4, 0x4c, 0xb9, 0x69, 0xf8, 0xd3, 0xcb, 0x4d, 0x70, 0x62, + 0xb9, 0xa9, 0x16, 0xbb, 0x91, 0x8d, 0x1c, 0x6b, 0xcf, 0x7b, 0x5e, 0xdc, 0x57, 0x26, 0xb3, 0x43, + 0xf8, 0x44, 0x0e, 0x65, 0x9f, 0x2b, 0x61, 0xec, 0x9b, 0xd9, 0xc2, 0x58, 0xef, 0xd3, 0xe6, 0x5f, + 0x8a, 0x63, 0x4f, 0x44, 0x1c, 0xf3, 0x71, 0xc0, 0xb6, 0x6c, 0xbf, 0x85, 0x57, 0xce, 0x6b, 0x30, + 0x24, 0xa3, 0x62, 0xe5, 0x62, 0xed, 0x49, 0x3a, 0x1c, 0x96, 0xc4, 0x22, 0xf3, 0x50, 0x92, 0xc4, + 0x6a, 0x84, 0xef, 0x03, 0x01, 0xd3, 0x02, 0x0e, 0x09, 0x98, 0xf1, 0x77, 0x8a, 0x72, 0x53, 0x60, + 0xed, 0x10, 0xd9, 0xa0, 0x17, 0x94, 0x49, 0xa0, 0x08, 0x83, 0x89, 0x61, 0x4e, 0x58, 0xfa, 0xe9, + 0x24, 0x9f, 0x28, 0x4e, 0x59, 0x9c, 0x85, 0xaa, 0xd0, 0x47, 0x16, 0xaa, 0x37, 0xb4, 0x14, 0x4e, + 0xc5, 0x38, 0x67, 0x08, 0x5b, 0x28, 0xbd, 0x93, 0x37, 0xdd, 0x54, 0x73, 0x2d, 0x0d, 0xc4, 0x21, + 0x3b, 0x90, 0xb2, 0x47, 0x96, 0xa5, 0x48, 0xba, 0x1d, 0x3c, 0x49, 0x04, 0xc0, 0xa1, 0x7f, 0xa1, + 0x11, 0x00, 0x97, 0x01, 0x94, 0x0c, 0xbc, 0xfc, 0x71, 0xe7, 0x45, 0xd6, 0x4d, 0xc7, 0x67, 0xdf, + 0x55, 0x08, 0x8d, 0xdf, 0x23, 0x30, 0x59, 0xab, 0xad, 0x2f, 0xb9, 0xf6, 0x6e, 0xcb, 0x0b, 0x42, + 0xb7, 0x5e, 0x6d, 0xed, 0x78, 0x4c, 0xb4, 0x8b, 0x36, 0x18, 0x25, 0xd4, 0x5b, 0xbc, 0xb9, 0x44, + 0xc5, 0xec, 0xea, 0xb0, 0xec, 0xfb, 0x9e, 0xaf, 0x5e, 0x1d, 0x28, 0x03, 0x98, 0x1c, 0xce, 0xa4, + 0xa7, 0x5a, 0x87, 0xa7, 0x52, 0xe5, 0xef, 0x6d, 0x28, 0x3d, 0x05, 0x1c, 0x64, 0xca, 0x32, 0x42, + 0xd3, 0x13, 0x56, 0x48, 0xd3, 0x67, 0xb4, 0x38, 0x82, 0x71, 0x31, 0xdf, 0x3e, 0xc5, 0xf1, 0x86, + 0x4b, 0xb1, 0x8d, 0x70, 0xf5, 0x81, 0x3c, 0xb5, 0x06, 0x0e, 0xe1, 0x94, 0xe6, 0x02, 0xd5, 0xaf, + 0xe2, 0xf0, 0x65, 0x21, 0xad, 0x19, 0xe8, 0x3f, 0x9b, 0xa1, 0x3d, 0x54, 0x73, 0x1e, 0x64, 0xd6, + 0x40, 0x7e, 0x3c, 0x07, 0xe7, 0x33, 0x4b, 0xa2, 0xd5, 0x3d, 0xa2, 0xc5, 0x72, 0x54, 0x36, 0x0d, + 0x9e, 0xdd, 0xa1, 0x5b, 0xd5, 0x56, 0xc6, 0x56, 0xd0, 0xbb, 0x26, 0xf2, 0x1b, 0x39, 0x38, 0xa3, + 0x61, 0x44, 0xdb, 0x67, 0x10, 0xf9, 0xfa, 0x66, 0xce, 0xeb, 0x8f, 0x9e, 0xcc, 0xbc, 0xbe, 0xa8, + 0x7f, 0x4b, 0xbc, 0xbb, 0xab, 0xdf, 0xd0, 0xad, 0x85, 0xe4, 0x21, 0x4c, 0x62, 0x91, 0x54, 0x62, + 0xb2, 0x39, 0x2b, 0x74, 0x9f, 0xd3, 0x71, 0xb3, 0xb9, 0x5b, 0x1f, 0x66, 0xe8, 0x9b, 0xff, 0xfe, + 0xd1, 0xdc, 0x98, 0x86, 0x2e, 0xa3, 0x23, 0x5a, 0xb1, 0x26, 0xd4, 0x6d, 0xed, 0x78, 0xea, 0xd1, + 0x9b, 0xaa, 0x82, 0xfc, 0x47, 0x39, 0x98, 0x61, 0x50, 0xfe, 0x19, 0xb7, 0x7c, 0xaf, 0x19, 0x95, + 0x4b, 0x4b, 0x8b, 0x2e, 0xdd, 0xd6, 0x78, 0x32, 0xdd, 0xf6, 0x22, 0x36, 0x99, 0xef, 0x09, 0xd6, + 0x8e, 0xef, 0x35, 0xe3, 0xe6, 0x6b, 0x19, 0x66, 0xbb, 0x35, 0x92, 0xfc, 0x70, 0x0e, 0xce, 0x6a, + 0x9a, 0x17, 0x35, 0x86, 0xb4, 0x70, 0x9e, 0x9c, 0x8a, 0x9c, 0xa4, 0xe3, 0xa2, 0x85, 0xab, 0x62, + 0xfe, 0x5f, 0xc2, 0x16, 0xc4, 0xa7, 0x05, 0xb6, 0xc5, 0x6a, 0x72, 0x2c, 0xa5, 0x09, 0xdd, 0x6b, + 0x21, 0x2e, 0x4c, 0xe2, 0x1b, 0xa5, 0x66, 0x11, 0x34, 0xdd, 0xdd, 0x22, 0x28, 0xca, 0xa4, 0x84, + 0x01, 0x6a, 0xbb, 0x9b, 0x05, 0xa5, 0xb9, 0x92, 0xbf, 0x08, 0x67, 0x53, 0xc0, 0x68, 0xb5, 0x9d, + 0xea, 0xba, 0xda, 0x5e, 0x79, 0x7c, 0x34, 0xf7, 0x52, 0x56, 0x6d, 0x59, 0x2b, 0xad, 0x7b, 0x0d, + 0xc4, 0x06, 0x88, 0x0b, 0x45, 0xa2, 0xda, 0xec, 0x09, 0xfa, 0x8a, 0x98, 0x1f, 0x0a, 0x3e, 0xdb, + 0xcb, 0x95, 0x36, 0xa8, 0x47, 0x5e, 0x8c, 0x44, 0x28, 0x8c, 0x2a, 0xc1, 0x79, 0x0f, 0x31, 0x63, + 0x6d, 0xd7, 0x4a, 0xbe, 0x7f, 0x34, 0xa7, 0x61, 0x33, 0x11, 0x5b, 0x8d, 0xfa, 0xab, 0x8a, 0xd8, + 0x1a, 0x22, 0xf9, 0xb5, 0x1c, 0x4c, 0x33, 0x40, 0x3c, 0xa9, 0xc4, 0x47, 0xcd, 0xf4, 0x9a, 0xf5, + 0x7b, 0x4f, 0x66, 0xd6, 0x3f, 0x8f, 0x6d, 0x54, 0x67, 0x7d, 0xaa, 0x4b, 0x32, 0x1b, 0x87, 0xb3, + 0x5d, 0x7b, 0x0e, 0xd7, 0x66, 0xfb, 0xd9, 0x3e, 0x66, 0x3b, 0x1f, 0x80, 0xe3, 0x67, 0x7b, 0xd7, + 0x5a, 0xc8, 0x26, 0x8c, 0x0a, 0xe9, 0x9a, 0x77, 0xd8, 0x73, 0x5a, 0x60, 0x4f, 0xb5, 0x88, 0x5f, + 0x79, 0x44, 0xec, 0xe2, 0xd4, 0x17, 0x6a, 0x5c, 0x48, 0x0b, 0xa6, 0xf8, 0x6f, 0x5d, 0xd7, 0x31, + 0xd7, 0x55, 0xd7, 0x71, 0x59, 0x7c, 0xd1, 0x05, 0xc1, 0x3f, 0xa1, 0xf2, 0x50, 0x63, 0x2b, 0x64, + 0x30, 0x26, 0x6d, 0x20, 0x1a, 0x98, 0x2f, 0xda, 0x0b, 0xbd, 0x35, 0x1c, 0x2f, 0x89, 0x3a, 0xe7, + 0x92, 0x75, 0x26, 0x57, 0x6e, 0x06, 0x6f, 0x62, 0xc3, 0x84, 0x80, 0xb2, 0xbb, 0x34, 0xee, 0xf0, + 0xcf, 0x6b, 0xd1, 0x2d, 0x12, 0xa5, 0x5c, 0x30, 0x97, 0x35, 0x61, 0xf4, 0x91, 0xc4, 0x86, 0x9e, + 0xe4, 0x47, 0xd6, 0x61, 0xb2, 0xd2, 0x6e, 0x37, 0x5c, 0xea, 0xe0, 0x57, 0xf2, 0xa4, 0xa3, 0x46, + 0x9c, 0x68, 0xc2, 0xe6, 0x85, 0xe2, 0xb6, 0x90, 0xcc, 0x38, 0x9a, 0xa6, 0x35, 0xbe, 0x93, 0x4b, + 0x35, 0x9a, 0xbc, 0x0a, 0xc3, 0xf8, 0x43, 0x71, 0xb1, 0x46, 0x25, 0x00, 0x6f, 0x22, 0x2a, 0x23, + 0x62, 0x04, 0x26, 0x2c, 0xa9, 0x41, 0x93, 0x0a, 0x5c, 0x58, 0x12, 0x37, 0xd5, 0xf8, 0x6e, 0x3a, + 0x27, 0x2d, 0x35, 0x0b, 0xb1, 0xd0, 0x85, 0x96, 0x9a, 0xc2, 0x3e, 0xd3, 0xf8, 0xe1, 0xbc, 0x3e, + 0xed, 0xc8, 0x65, 0x45, 0x6e, 0x57, 0xc2, 0x36, 0x49, 0xb9, 0x5d, 0x91, 0xd6, 0xff, 0x76, 0x0e, + 0xa6, 0xd6, 0xfd, 0x5d, 0xbb, 0xe5, 0x7e, 0x9b, 0x87, 0x7f, 0xf4, 0x70, 0x5c, 0x7a, 0xe7, 0xec, + 0x79, 0x52, 0xb9, 0x47, 0x3c, 0xa5, 0x62, 0x36, 0x53, 0x70, 0xca, 0x98, 0x59, 0xed, 0x41, 0xdb, + 0x77, 0x6c, 0x98, 0x92, 0x02, 0x86, 0xa3, 0x73, 0xb8, 0xf1, 0x93, 0x79, 0x18, 0x51, 0x96, 0x00, + 0xf9, 0x22, 0x8c, 0xaa, 0x7c, 0x54, 0x05, 0x92, 0x5a, 0xad, 0xa9, 0x61, 0xa1, 0x06, 0x89, 0xda, + 0x4d, 0x4d, 0x83, 0xc4, 0x26, 0x3a, 0x42, 0x4f, 0x78, 0xb5, 0x79, 0x37, 0xe3, 0x6a, 0x73, 0xa2, + 0xec, 0xb4, 0x6f, 0xa5, 0x2f, 0x38, 0xfd, 0x27, 0x93, 0x35, 0x7e, 0x26, 0x07, 0xe5, 0xe4, 0x22, + 0xfd, 0x4c, 0x7a, 0xe5, 0x04, 0xaf, 0x05, 0x3f, 0x91, 0x8f, 0x22, 0x73, 0x4b, 0x8f, 0x9e, 0xa7, + 0xd5, 0x24, 0xe6, 0x6d, 0x4d, 0x91, 0xff, 0xac, 0x1e, 0x6a, 0x46, 0xf5, 0x85, 0xcd, 0x8e, 0x2f, + 0x55, 0xfc, 0xde, 0x2f, 0xce, 0x3d, 0x63, 0xbc, 0x0f, 0xd3, 0xc9, 0xee, 0x40, 0x65, 0x7e, 0x05, + 0x26, 0x74, 0x78, 0x32, 0xae, 0x7f, 0x92, 0xca, 0x4c, 0xe2, 0x1b, 0xbf, 0x9f, 0x4f, 0xf2, 0x16, + 0xe6, 0x31, 0x6c, 0xd3, 0x69, 0xd9, 0xdb, 0x8d, 0x28, 0xae, 0x37, 0xdf, 0x74, 0x38, 0xc8, 0x94, + 0x65, 0x27, 0x49, 0x74, 0x11, 0xf9, 0xa5, 0x14, 0xb2, 0xfd, 0x52, 0xc8, 0xcd, 0x84, 0x8d, 0x99, + 0x12, 0x44, 0xe1, 0x80, 0x6e, 0x5b, 0xb1, 0x9d, 0x59, 0xc2, 0xb4, 0x6c, 0x11, 0xa6, 0xb5, 0xf8, + 0x9e, 0x92, 0x7e, 0x20, 0xd6, 0xdd, 0x86, 0x58, 0xc0, 0x89, 0x33, 0x91, 0xc9, 0x0a, 0x0c, 0xb1, + 0x66, 0xde, 0xb3, 0xdb, 0x42, 0x47, 0x4f, 0x22, 0x2f, 0xb5, 0x46, 0x74, 0xe1, 0x53, 0x1c, 0xd5, + 0x1a, 0x94, 0x1d, 0xf9, 0x5a, 0x72, 0x67, 0x8e, 0x68, 0xfc, 0x69, 0x8e, 0xad, 0xff, 0xfa, 0xfe, + 0xe7, 0x2c, 0x5b, 0x06, 0xfb, 0xa4, 0x1e, 0xd6, 0x5b, 0x7f, 0x94, 0xe7, 0xa1, 0xd9, 0xc5, 0xf4, + 0x79, 0x03, 0x06, 0x37, 0x6d, 0x7f, 0x97, 0x86, 0x22, 0x68, 0xb9, 0xca, 0x85, 0x17, 0xc4, 0x21, + 0x1e, 0x42, 0xfc, 0x6d, 0x0a, 0x02, 0x55, 0x17, 0x96, 0xef, 0x4b, 0x17, 0xa6, 0x68, 0x7a, 0x0b, + 0x4f, 0x4c, 0xd3, 0xfb, 0x03, 0x51, 0x14, 0xf6, 0x4a, 0xd8, 0x47, 0xf8, 0xc8, 0x0b, 0xc9, 0x2c, + 0x06, 0xa9, 0x40, 0x9f, 0x31, 0x3b, 0x72, 0x53, 0xcd, 0x8b, 0xa0, 0xb8, 0x7a, 0x1c, 0x93, 0x01, + 0xc1, 0xf8, 0xa3, 0x02, 0xef, 0x63, 0xd1, 0x51, 0x97, 0x34, 0x37, 0x30, 0x5c, 0x27, 0x6c, 0xa3, + 0x57, 0x3d, 0x72, 0xd1, 0xb0, 0xe3, 0x12, 0x14, 0xd9, 0xdc, 0x14, 0xbd, 0x89, 0x78, 0x6c, 0xfe, + 0xaa, 0x78, 0xac, 0x9c, 0xad, 0x65, 0x3c, 0x93, 0xd4, 0x4c, 0x34, 0x78, 0x6c, 0xa9, 0x6b, 0x19, + 0x31, 0xc8, 0x65, 0x28, 0xae, 0x79, 0x8e, 0x0c, 0x53, 0x3a, 0x8d, 0xce, 0xc0, 0x9e, 0xa3, 0xb0, + 0x9c, 0xc9, 0x99, 0x88, 0xc1, 0xbe, 0x35, 0x0a, 0x6c, 0xae, 0x7e, 0x6b, 0x73, 0xc7, 0x16, 0xb1, + 0xb4, 0xd4, 0x6f, 0x8d, 0x63, 0xa0, 0x2f, 0xc3, 0xb8, 0x9e, 0x8b, 0x52, 0xd8, 0xb6, 0xa1, 0xc6, + 0x36, 0x91, 0xd2, 0x52, 0x55, 0xb4, 0xeb, 0x44, 0x64, 0x01, 0xc6, 0xb4, 0xf0, 0x68, 0xe2, 0xb1, + 0x0c, 0xd5, 0x9b, 0x7a, 0x70, 0x35, 0x55, 0xbd, 0xa9, 0x91, 0xb0, 0xf3, 0x5c, 0xb4, 0x5f, 0x79, + 0x32, 0x4b, 0xb5, 0x5d, 0xe0, 0x90, 0x1b, 0x50, 0xe2, 0x5e, 0xb7, 0xd5, 0x25, 0xf5, 0xe1, 0x23, + 0x40, 0x58, 0xc2, 0x6b, 0x5d, 0x22, 0x2a, 0x5e, 0x96, 0x5f, 0x80, 0xb2, 0xd8, 0x92, 0xe2, 0xac, + 0x8f, 0xe7, 0xa0, 0xb8, 0x58, 0x5d, 0x32, 0xd5, 0x6d, 0xa4, 0xee, 0x3a, 0xbe, 0x89, 0x50, 0x34, + 0xdd, 0x5f, 0xa3, 0xe1, 0x81, 0xe7, 0xef, 0x9b, 0x34, 0x08, 0x7d, 0x97, 0x27, 0x32, 0xc2, 0x85, + 0xf8, 0x45, 0xf2, 0x16, 0x0c, 0xa0, 0x91, 0x55, 0xe2, 0x64, 0x48, 0xd6, 0xb1, 0x30, 0x26, 0x26, + 0xf0, 0x00, 0x5a, 0x6c, 0x99, 0x9c, 0x88, 0xbc, 0x01, 0xc5, 0x25, 0xda, 0x3a, 0x4c, 0xa4, 0x72, + 0x49, 0x11, 0x47, 0x1b, 0x82, 0x43, 0x5b, 0x87, 0x26, 0x92, 0x18, 0x3f, 0x93, 0x87, 0x53, 0x19, + 0xcd, 0x7a, 0xf0, 0xc5, 0xa7, 0x74, 0x57, 0x5c, 0xd0, 0x76, 0x45, 0xf9, 0xde, 0xd9, 0xb5, 0xe3, + 0x33, 0x37, 0xc9, 0x9f, 0xcf, 0xc1, 0x19, 0x7d, 0x82, 0x0a, 0xab, 0xca, 0x07, 0x37, 0xc8, 0x9b, + 0x30, 0xb8, 0x42, 0x6d, 0x87, 0xca, 0x34, 0x0f, 0xa7, 0xa2, 0xf8, 0x38, 0xdc, 0xa5, 0x90, 0x17, + 0x72, 0xb6, 0xb1, 0x03, 0x0a, 0x87, 0x92, 0x25, 0xd1, 0x38, 0x2e, 0x8f, 0x1b, 0xd2, 0xbd, 0x37, + 0xab, 0xaa, 0x1e, 0x56, 0x03, 0xdf, 0xcf, 0xc1, 0xb3, 0x3d, 0x68, 0xd8, 0xc0, 0xb1, 0xa1, 0x57, + 0x07, 0x0e, 0x4f, 0x54, 0x84, 0x92, 0x77, 0x60, 0x62, 0x53, 0xc8, 0xf3, 0x72, 0x38, 0xf2, 0xf1, + 0x7a, 0x91, 0xa2, 0xbe, 0x25, 0xc7, 0x25, 0x89, 0xac, 0xf9, 0x9d, 0x17, 0x7a, 0xfa, 0x9d, 0xab, + 0x6e, 0xdc, 0xc5, 0x7e, 0xdd, 0xb8, 0xdf, 0x4f, 0x66, 0x70, 0x17, 0xd1, 0xf4, 0x62, 0x27, 0xf6, + 0x5c, 0x77, 0x27, 0xf6, 0x9e, 0x31, 0xbb, 0x8c, 0x9f, 0xcc, 0x41, 0x59, 0xe7, 0xfd, 0x69, 0xc7, + 0xf3, 0x6d, 0x6d, 0x3c, 0x9f, 0xcd, 0x1e, 0xcf, 0xee, 0x03, 0xf9, 0xbf, 0xe6, 0x92, 0x1f, 0xdb, + 0xd7, 0x08, 0x1a, 0x30, 0xb8, 0xe4, 0x35, 0x6d, 0xb7, 0xa5, 0x26, 0x11, 0x75, 0x10, 0x62, 0x8a, + 0x92, 0xfe, 0x7c, 0xfe, 0x2f, 0xc0, 0xc0, 0x9a, 0xd7, 0xaa, 0x2c, 0x09, 0xa3, 0x43, 0xe4, 0xd3, + 0xf2, 0x5a, 0x96, 0xed, 0x98, 0xbc, 0x80, 0xac, 0x02, 0xd4, 0xea, 0x3e, 0xa5, 0xad, 0x9a, 0xfb, + 0x6d, 0x9a, 0x90, 0x34, 0x58, 0x0f, 0x35, 0x3a, 0xb8, 0xb1, 0xe0, 0x1b, 0x4f, 0x80, 0x88, 0x56, + 0xe0, 0x7e, 0x5b, 0xdd, 0x6f, 0x15, 0x7a, 0x83, 0x02, 0xc4, 0x44, 0x98, 0x51, 0xcd, 0x75, 0x44, + 0x96, 0xdc, 0x31, 0x91, 0x51, 0x8d, 0x01, 0xb4, 0x8c, 0x6a, 0x0c, 0xc0, 0xb6, 0xf6, 0x15, 0xea, + 0xee, 0xee, 0x71, 0xeb, 0x93, 0x31, 0x3e, 0x55, 0xf7, 0x10, 0xa2, 0x6e, 0xed, 0x1c, 0xc7, 0xf8, + 0xf1, 0x01, 0x38, 0x6b, 0xd2, 0x5d, 0x97, 0x89, 0xc9, 0xf7, 0x03, 0xb7, 0xb5, 0xab, 0x79, 0x65, + 0x1b, 0x89, 0x89, 0x24, 0x02, 0x12, 0x33, 0x48, 0xd4, 0x31, 0x57, 0xa0, 0xc4, 0x4e, 0x45, 0x65, + 0x2e, 0xe1, 0x1b, 0x0a, 0xa6, 0x00, 0xe7, 0x93, 0x5c, 0x16, 0x93, 0x97, 0xc5, 0xa9, 0xad, 0x84, + 0x8c, 0x67, 0xa7, 0xf6, 0xc7, 0x47, 0x73, 0x50, 0x3b, 0x0c, 0x42, 0x8a, 0x37, 0x36, 0x71, 0x72, + 0x47, 0xa2, 0x75, 0xb1, 0x8b, 0x68, 0x7d, 0x0f, 0xa6, 0x2b, 0x0e, 0xdf, 0xac, 0xed, 0xc6, 0x86, + 0xef, 0xb6, 0xea, 0x6e, 0xdb, 0x6e, 0xc8, 0xeb, 0x22, 0xf6, 0xb2, 0x1d, 0x95, 0x5b, 0xed, 0x08, + 0xc1, 0xcc, 0x24, 0x63, 0x9f, 0xb1, 0xb4, 0x56, 0x43, 0xe7, 0x65, 0xf1, 0x3c, 0x86, 0x9f, 0xe1, + 0xb4, 0x02, 0xfc, 0x8a, 0xc0, 0x8c, 0x8a, 0x51, 0xa8, 0x47, 0x73, 0x86, 0xcd, 0xd5, 0x5a, 0xec, + 0x9d, 0xc4, 0x23, 0xda, 0x72, 0x93, 0x87, 0xb0, 0x11, 0xa0, 0xd9, 0x83, 0x86, 0x17, 0xd3, 0xd5, + 0x6a, 0x2b, 0x8c, 0xae, 0x94, 0xa2, 0x0b, 0x82, 0x3d, 0x95, 0x8e, 0xe3, 0x91, 0x6b, 0x6c, 0x2a, + 0x34, 0xbd, 0x90, 0xe2, 0x3c, 0x1f, 0x8e, 0xaf, 0x00, 0x3e, 0x42, 0xf9, 0x15, 0x40, 0x41, 0x21, + 0x6f, 0xc1, 0xd4, 0xf2, 0xe2, 0xbc, 0x54, 0x6a, 0x2e, 0x79, 0xf5, 0x0e, 0x3e, 0x50, 0x03, 0xd6, + 0x87, 0x63, 0x48, 0xeb, 0xf3, 0x6c, 0x72, 0x67, 0xa1, 0x91, 0x4b, 0x30, 0x54, 0x5d, 0xe2, 0x7d, + 0x3f, 0xa2, 0xa6, 0x6d, 0x10, 0x86, 0x1f, 0xb2, 0x90, 0xac, 0xc7, 0x32, 0xea, 0xe8, 0xb1, 0xc2, + 0xe4, 0xd9, 0xe3, 0xe5, 0x53, 0x91, 0xdd, 0x81, 0x67, 0x11, 0x5a, 0xf4, 0x1c, 0x1a, 0x3c, 0xb8, + 0xfe, 0x39, 0xcb, 0xee, 0xa0, 0x7c, 0x1b, 0xee, 0x5e, 0xd7, 0x33, 0xb7, 0xba, 0x7f, 0x1d, 0xb3, + 0x3b, 0xa4, 0x70, 0xc9, 0x97, 0x61, 0x00, 0x7f, 0x0a, 0xb9, 0x67, 0x2a, 0x83, 0x6d, 0x2c, 0xf3, + 0xd4, 0x79, 0x12, 0x60, 0x24, 0x20, 0x55, 0x18, 0x12, 0x22, 0xf7, 0x49, 0x62, 0x94, 0x0b, 0xd9, + 0x9d, 0x0f, 0x92, 0xa0, 0x37, 0x1c, 0x18, 0x55, 0x2b, 0x64, 0x93, 0x73, 0xc5, 0x0e, 0xf6, 0xa8, + 0xc3, 0x7e, 0x89, 0xf4, 0x22, 0x38, 0x39, 0xf7, 0x10, 0x6a, 0xb1, 0x76, 0x98, 0x0a, 0x0a, 0xdb, + 0x6d, 0xab, 0xc1, 0xfd, 0x40, 0x34, 0x45, 0x5c, 0xc2, 0x5d, 0x54, 0xe8, 0x38, 0xa6, 0x28, 0x32, + 0x7e, 0x00, 0xa6, 0xd7, 0x3a, 0x8d, 0x06, 0xbb, 0x90, 0xcb, 0xf0, 0xd3, 0xa1, 0x1d, 0x52, 0xb2, + 0x00, 0x03, 0x35, 0x25, 0xad, 0xe0, 0x54, 0x14, 0xdf, 0x3b, 0xc6, 0x41, 0x73, 0xb7, 0x1c, 0xfa, + 0x74, 0x27, 0x12, 0x0a, 0x72, 0x52, 0xe3, 0x77, 0xe3, 0x74, 0xd4, 0x9b, 0xbe, 0x5d, 0xdf, 0x8f, + 0x52, 0x4b, 0xf6, 0x9b, 0x59, 0xfb, 0x8e, 0x6c, 0x84, 0x7e, 0x94, 0x65, 0x35, 0xf8, 0xb8, 0xc6, + 0x90, 0xb7, 0x60, 0x44, 0x1c, 0x67, 0x4a, 0x24, 0x22, 0x0c, 0xf7, 0x20, 0x73, 0xdb, 0x27, 0xcc, + 0x0d, 0x54, 0x74, 0x3c, 0xa5, 0xf5, 0x4f, 0x79, 0x70, 0xfd, 0xb3, 0x38, 0xa5, 0xf5, 0x3a, 0x7a, + 0x4c, 0xdd, 0x7f, 0x30, 0x92, 0xec, 0x5b, 0x31, 0x77, 0x6f, 0xaa, 0xb1, 0x47, 0x72, 0xf1, 0x9d, + 0x29, 0x8e, 0x3d, 0xa2, 0xde, 0x99, 0x22, 0xd4, 0x68, 0x4c, 0xf2, 0xc7, 0x8c, 0xc9, 0x3b, 0x72, + 0x4c, 0x0a, 0xdd, 0x27, 0xc6, 0x54, 0x8f, 0x71, 0xa8, 0xc5, 0x2b, 0xa4, 0xd8, 0xd7, 0x85, 0xfb, + 0x19, 0x0c, 0xb2, 0xca, 0x49, 0x92, 0x1b, 0x9a, 0xe0, 0xa4, 0xde, 0xe2, 0x07, 0xfa, 0x67, 0x7a, + 0xcc, 0x2d, 0xfe, 0x2b, 0x30, 0x5a, 0x09, 0x43, 0xbb, 0xbe, 0x47, 0x9d, 0x25, 0xb6, 0x3d, 0x29, + 0x61, 0x12, 0x6c, 0x01, 0x57, 0x9f, 0x53, 0x54, 0x5c, 0x1e, 0xf6, 0xcb, 0x0e, 0x84, 0xe1, 0x5c, + 0x14, 0xf6, 0x8b, 0x41, 0xf4, 0xb0, 0x5f, 0x0c, 0x42, 0xae, 0xc1, 0x50, 0xb5, 0xf5, 0xd0, 0x65, + 0x7d, 0x52, 0x52, 0x12, 0xe8, 0x73, 0x90, 0xba, 0xb9, 0x0a, 0x2c, 0xf2, 0x86, 0x22, 0xee, 0x0e, + 0xc7, 0x57, 0x5b, 0xae, 0x0c, 0x89, 0x1c, 0xac, 0x55, 0x51, 0x36, 0x92, 0x7f, 0x6f, 0xc2, 0x90, + 0xd4, 0x71, 0x41, 0x7c, 0x9d, 0x15, 0x94, 0x69, 0x47, 0x4c, 0x89, 0x8c, 0xd9, 0x08, 0x95, 0x34, + 0x29, 0x23, 0x4a, 0x36, 0x42, 0x25, 0x4d, 0x8a, 0x96, 0x8d, 0x50, 0x49, 0x98, 0x12, 0xa9, 0x07, + 0x46, 0x8f, 0x55, 0x0f, 0x3c, 0x80, 0xd1, 0x0d, 0xdb, 0x0f, 0x5d, 0x26, 0x2e, 0xb4, 0xc2, 0x60, + 0x66, 0x4c, 0xd3, 0xa8, 0x29, 0x45, 0x0b, 0xcf, 0xc9, 0x04, 0x7a, 0x6d, 0x05, 0x5f, 0xcf, 0xf4, + 0x16, 0xc3, 0xb3, 0xcd, 0xe6, 0xc6, 0x3f, 0x8d, 0xd9, 0x1c, 0x76, 0x2a, 0x6a, 0x51, 0x26, 0xe2, + 0xbb, 0x3a, 0x8a, 0xb3, 0x09, 0x55, 0x4a, 0x84, 0x48, 0xbe, 0x0e, 0xa3, 0xec, 0x6f, 0xcc, 0x59, + 0xef, 0xd2, 0x60, 0xa6, 0x8c, 0x1f, 0xf7, 0x5c, 0xe6, 0xea, 0xe7, 0x89, 0xed, 0x6b, 0x34, 0xe4, + 0x0b, 0x18, 0x19, 0x27, 0xd5, 0xa3, 0x1a, 0x37, 0xf2, 0x2e, 0x8c, 0xb2, 0xd9, 0xb7, 0x6d, 0x07, + 0x5c, 0x4a, 0x9c, 0x8c, 0x0d, 0x1f, 0x1d, 0x01, 0x4f, 0x45, 0xde, 0x53, 0x09, 0xd8, 0x31, 0x5f, + 0x69, 0xf3, 0x0d, 0x92, 0x28, 0xb3, 0xbd, 0x9d, 0xda, 0x1c, 0x25, 0x1a, 0x79, 0x0f, 0x46, 0x2b, + 0xed, 0x76, 0xbc, 0xe3, 0x4c, 0x29, 0x2a, 0x92, 0x76, 0xdb, 0xca, 0xdc, 0x75, 0x34, 0x8a, 0xe4, + 0xc6, 0x3c, 0x7d, 0xa2, 0x8d, 0x99, 0xbc, 0x16, 0x09, 0xce, 0xa7, 0x62, 0x7d, 0x9f, 0xb8, 0x52, + 0x68, 0x52, 0x38, 0x97, 0xa1, 0x17, 0x61, 0x8c, 0x2b, 0xc0, 0xa4, 0x34, 0x73, 0x3a, 0xb5, 0x7a, + 0x32, 0x84, 0x1a, 0x9d, 0x86, 0x2c, 0xc3, 0x38, 0xf7, 0x39, 0x6b, 0x88, 0x90, 0x88, 0x33, 0x67, + 0xe2, 0xcc, 0xc8, 0xdc, 0x55, 0xad, 0x81, 0x91, 0xb2, 0x6d, 0x8d, 0x4b, 0x82, 0xc8, 0xf8, 0xe3, + 0x1c, 0x9c, 0xe9, 0x32, 0xe2, 0x51, 0xc0, 0xbc, 0x5c, 0xef, 0x80, 0x79, 0x6c, 0xe7, 0xd0, 0xef, + 0xcb, 0xf8, 0xfd, 0x42, 0xca, 0x52, 0xc7, 0x4b, 0xca, 0x5b, 0x1e, 0x10, 0x11, 0x5a, 0x5e, 0x54, + 0x7d, 0xc7, 0x43, 0xa5, 0x5d, 0x21, 0x7d, 0x08, 0x09, 0x3c, 0xde, 0xa8, 0x05, 0xe3, 0xf1, 0xd1, + 0xdc, 0x73, 0x22, 0x72, 0x7d, 0x34, 0xac, 0x1f, 0x79, 0xda, 0x0a, 0xce, 0x60, 0x6d, 0x1c, 0xe5, + 0x60, 0x44, 0x59, 0x87, 0xe4, 0x82, 0xe2, 0xc1, 0x56, 0xe6, 0xb9, 0x0f, 0x14, 0x0e, 0x79, 0x7e, + 0x12, 0xe1, 0xa2, 0xca, 0x1f, 0xaf, 0x9a, 0xbc, 0xc7, 0x44, 0x21, 0x25, 0xa8, 0x60, 0x53, 0xd3, + 0x23, 0x9a, 0x58, 0x8e, 0x79, 0x3f, 0xed, 0x20, 0xac, 0xd4, 0x43, 0xf7, 0x21, 0xed, 0xe3, 0xd0, + 0x89, 0xf3, 0x7e, 0xda, 0x41, 0x68, 0xd9, 0x48, 0x96, 0xca, 0xfb, 0x19, 0x31, 0x34, 0x7e, 0x24, + 0x07, 0x70, 0xbf, 0xba, 0x88, 0x51, 0x41, 0x3f, 0xad, 0x50, 0x90, 0x1d, 0x69, 0x4d, 0x72, 0xef, + 0x21, 0x0e, 0xfc, 0x37, 0x39, 0x18, 0xd7, 0xd1, 0xc8, 0x3b, 0x30, 0x51, 0xab, 0xfb, 0x5e, 0xa3, + 0xb1, 0x6d, 0xd7, 0xf7, 0x57, 0xdd, 0x16, 0xe5, 0x31, 0xae, 0x06, 0xf8, 0x59, 0x14, 0x44, 0x45, + 0x56, 0x83, 0x95, 0x99, 0x49, 0x64, 0xf2, 0xa3, 0x39, 0x18, 0xab, 0xed, 0x79, 0x07, 0x71, 0x3a, + 0x76, 0x3e, 0x20, 0x1f, 0xb2, 0xb5, 0x1d, 0xec, 0x79, 0x07, 0x56, 0x46, 0x4e, 0xf6, 0x8f, 0x8f, + 0xe6, 0xde, 0xee, 0xef, 0xc5, 0xb6, 0xee, 0xb5, 0x82, 0x90, 0x6d, 0xcc, 0x57, 0xb5, 0x4a, 0x4c, + 0xbd, 0x4e, 0xe3, 0xcf, 0x72, 0x30, 0x52, 0x65, 0x98, 0x8d, 0x06, 0xca, 0x5c, 0x9f, 0xa7, 0x2c, + 0x3c, 0xd1, 0x77, 0xf5, 0x18, 0xd8, 0xd7, 0x61, 0x22, 0x81, 0x46, 0x0c, 0x18, 0xac, 0xa1, 0xd7, + 0xb2, 0xaa, 0x2b, 0xe0, 0x7e, 0xcc, 0xa6, 0x28, 0x31, 0x96, 0x15, 0xb2, 0x07, 0xd7, 0xf1, 0xc1, + 0x6f, 0x1e, 0xc0, 0x95, 0x20, 0x79, 0xb3, 0x21, 0xc9, 0x96, 0x3c, 0xb8, 0x6e, 0x2a, 0x58, 0xc6, + 0x1a, 0x0c, 0xd6, 0x3c, 0x3f, 0x5c, 0x38, 0xe4, 0x97, 0x89, 0x25, 0x1a, 0xd4, 0xd5, 0x17, 0x3d, + 0x17, 0xb5, 0xe8, 0x75, 0x53, 0x14, 0x91, 0x39, 0x18, 0xb8, 0xe5, 0xd2, 0x86, 0xa3, 0x9a, 0x6e, + 0xee, 0x30, 0x80, 0xc9, 0xe1, 0xec, 0xc2, 0x75, 0x3a, 0x0e, 0x9e, 0x1d, 0xdb, 0x88, 0x7e, 0xda, + 0x75, 0xb3, 0xa8, 0xf5, 0xef, 0xf3, 0x7a, 0x92, 0x5b, 0xad, 0xa6, 0x1e, 0x5d, 0xfd, 0xef, 0xe5, + 0x60, 0xb6, 0x3b, 0x89, 0x6a, 0x76, 0x9a, 0xeb, 0x61, 0x76, 0xfa, 0x62, 0xf2, 0x05, 0x0a, 0xd1, + 0xc4, 0x0b, 0x54, 0xfc, 0xee, 0xb4, 0x84, 0x56, 0xbf, 0xf5, 0x28, 0x07, 0xf9, 0x85, 0x1e, 0x6d, + 0x46, 0x44, 0x3e, 0xcc, 0x21, 0xd2, 0x98, 0x82, 0xd6, 0xf8, 0xcd, 0x22, 0x9c, 0xed, 0x4a, 0x41, + 0x56, 0x94, 0x38, 0xfc, 0xe3, 0x51, 0x04, 0xf0, 0xae, 0xf8, 0x57, 0xf1, 0x5f, 0x34, 0xec, 0x4a, + 0xfa, 0xb5, 0xac, 0x47, 0xf1, 0xd7, 0xf3, 0xc8, 0xeb, 0x95, 0x63, 0x79, 0x71, 0x74, 0x64, 0x06, + 0xe9, 0x50, 0xec, 0xe8, 0x01, 0x45, 0x43, 0xdb, 0x6d, 0x04, 0xea, 0xb2, 0x73, 0x38, 0xc8, 0x94, + 0x65, 0xb1, 0x2d, 0x70, 0x31, 0xdb, 0x16, 0xd8, 0xf8, 0x7f, 0x72, 0x30, 0x1c, 0x35, 0x9b, 0xcc, + 0xc2, 0xe9, 0x4d, 0xb3, 0xb2, 0xb8, 0x6c, 0x6d, 0xbe, 0xbf, 0xb1, 0x6c, 0xdd, 0x5f, 0xab, 0x6d, + 0x2c, 0x2f, 0x56, 0x6f, 0x55, 0x97, 0x97, 0xca, 0xcf, 0x90, 0x49, 0x18, 0xbb, 0xbf, 0x76, 0x77, + 0x6d, 0x7d, 0x6b, 0xcd, 0x5a, 0x36, 0xcd, 0x75, 0xb3, 0x9c, 0x23, 0x63, 0x30, 0x6c, 0x2e, 0x54, + 0x16, 0xad, 0xb5, 0xf5, 0xa5, 0xe5, 0x72, 0x9e, 0x94, 0x61, 0x74, 0x71, 0x7d, 0x6d, 0x6d, 0x79, + 0x71, 0xb3, 0xfa, 0xa0, 0xba, 0xf9, 0x7e, 0xb9, 0x40, 0x08, 0x8c, 0x23, 0xc2, 0x86, 0x59, 0x5d, + 0x5b, 0xac, 0x6e, 0x54, 0x56, 0xcb, 0x45, 0x06, 0x63, 0xf8, 0x0a, 0x6c, 0x20, 0x62, 0x74, 0xf7, + 0xfe, 0xc2, 0x72, 0x79, 0x90, 0xa1, 0xb0, 0xbf, 0x14, 0x94, 0x21, 0x56, 0x3d, 0xa2, 0x2c, 0x55, + 0x36, 0x2b, 0x0b, 0x95, 0xda, 0x72, 0xb9, 0x44, 0xce, 0xc0, 0x94, 0x06, 0xb2, 0x56, 0xd7, 0x6f, + 0x57, 0xd7, 0xca, 0xc3, 0x64, 0x1a, 0xca, 0x11, 0x6c, 0x69, 0xc1, 0xba, 0x5f, 0x5b, 0x36, 0xcb, + 0x90, 0x84, 0xae, 0x55, 0xee, 0x2d, 0x97, 0x47, 0x8c, 0xb7, 0xb9, 0xc7, 0x11, 0xef, 0x6a, 0x72, + 0x1a, 0x48, 0x6d, 0xb3, 0xb2, 0x79, 0xbf, 0x96, 0xf8, 0xf8, 0x11, 0x18, 0xaa, 0xdd, 0x5f, 0x5c, + 0x5c, 0xae, 0xd5, 0xca, 0x39, 0x02, 0x30, 0x78, 0xab, 0x52, 0x5d, 0x5d, 0x5e, 0x2a, 0xe7, 0x8d, + 0x9f, 0xce, 0xc1, 0xa4, 0x94, 0x00, 0xe5, 0x73, 0xc2, 0xa7, 0x5c, 0x8b, 0xef, 0x68, 0x17, 0x5b, + 0xe9, 0x10, 0x92, 0xa8, 0xa4, 0xc7, 0x32, 0xf4, 0xe1, 0x54, 0x26, 0x32, 0x79, 0x1f, 0xca, 0xb2, + 0x01, 0xf7, 0xec, 0xb0, 0xbe, 0x17, 0x6f, 0x63, 0xcf, 0x25, 0x2a, 0x49, 0xa0, 0x71, 0x05, 0x63, + 0x9c, 0xe6, 0x2f, 0xc5, 0xc6, 0xf8, 0x5e, 0x0e, 0xce, 0x74, 0x21, 0x26, 0x8b, 0x30, 0x18, 0x85, + 0x25, 0xef, 0x61, 0xb0, 0x34, 0xfd, 0xfd, 0xa3, 0x39, 0x81, 0x88, 0xd9, 0xce, 0xf0, 0x2f, 0x73, + 0x30, 0x8a, 0x33, 0x8e, 0xc1, 0xbe, 0x79, 0x9f, 0x9c, 0x4d, 0x74, 0xa7, 0xa8, 0xa9, 0xb2, 0x55, + 0x5b, 0x18, 0x11, 0x1d, 0x52, 0xb0, 0x0f, 0x02, 0x8c, 0xf6, 0x6d, 0x7c, 0x37, 0xc7, 0x24, 0xb6, + 0x24, 0x22, 0x13, 0x64, 0x2b, 0x41, 0xd0, 0x69, 0x52, 0xd3, 0x6b, 0xd0, 0x8a, 0xb9, 0x26, 0xce, + 0x02, 0x14, 0x41, 0x6d, 0x2c, 0xc0, 0xbb, 0x82, 0x65, 0xfb, 0x2d, 0xed, 0x71, 0x52, 0xa5, 0x21, + 0x6f, 0x00, 0x44, 0x59, 0xe7, 0x65, 0xd0, 0x00, 0x1e, 0x34, 0x43, 0x40, 0x75, 0x21, 0x5a, 0x41, + 0x36, 0xfe, 0x4a, 0x0e, 0x46, 0xc5, 0x4d, 0xa8, 0xd2, 0xa0, 0x7e, 0xf8, 0xe9, 0xe6, 0xcc, 0x1b, + 0xda, 0x9c, 0x89, 0xec, 0xf3, 0x15, 0xfe, 0xac, 0x38, 0x73, 0xba, 0xfc, 0x67, 0x39, 0x28, 0x27, + 0x11, 0xc9, 0x3b, 0x50, 0xaa, 0xd1, 0x87, 0xd4, 0x77, 0xc3, 0x43, 0xb1, 0xfb, 0xc9, 0x04, 0x2e, + 0x1c, 0x47, 0x94, 0x71, 0x85, 0x6b, 0x20, 0x7e, 0x99, 0x11, 0x4d, 0xbf, 0x9b, 0xb8, 0xa2, 0xcb, + 0x28, 0x3c, 0x29, 0x5d, 0x86, 0xf1, 0x3f, 0xe6, 0xe1, 0xcc, 0x6d, 0x1a, 0xaa, 0xdf, 0x14, 0xbd, + 0x26, 0x7f, 0xa1, 0xbf, 0xef, 0x52, 0xbe, 0x64, 0x06, 0x86, 0xb0, 0x48, 0x8e, 0xaf, 0x29, 0x7f, + 0x92, 0x85, 0x68, 0x5e, 0x17, 0xb4, 0x0c, 0x11, 0x5d, 0xea, 0xbe, 0xaa, 0xc4, 0x8c, 0x8f, 0xa6, + 0xf5, 0x25, 0x18, 0xc7, 0xa0, 0xa8, 0x1d, 0xb6, 0x1c, 0xa8, 0x23, 0x74, 0x3a, 0x25, 0x33, 0x01, + 0x25, 0x2f, 0x43, 0x99, 0x41, 0x2a, 0xf5, 0xfd, 0x96, 0x77, 0xd0, 0xa0, 0xce, 0x2e, 0xe5, 0x69, + 0xc2, 0x4b, 0x66, 0x0a, 0x2e, 0x79, 0xde, 0x6f, 0xf1, 0xfb, 0x18, 0x75, 0x50, 0xf1, 0x22, 0x78, + 0xc6, 0xd0, 0xd9, 0x37, 0x60, 0xe4, 0x13, 0xe6, 0x7f, 0x30, 0xfe, 0x87, 0x1c, 0x4c, 0xe3, 0xc7, + 0x29, 0x15, 0xa3, 0x46, 0xfe, 0x0b, 0x71, 0x6f, 0x29, 0x21, 0xd1, 0x6d, 0x06, 0xd2, 0x97, 0x42, + 0xd4, 0x8b, 0xb1, 0xa2, 0x27, 0xdf, 0x87, 0xa2, 0xa7, 0x76, 0x92, 0xac, 0xa2, 0x7d, 0xea, 0xa9, + 0x78, 0x2e, 0xf8, 0x78, 0xc8, 0x8d, 0x1f, 0xcd, 0xc3, 0x90, 0x49, 0x31, 0xdd, 0x22, 0xb9, 0x04, + 0x43, 0x6b, 0x5e, 0x48, 0x83, 0x7b, 0x5a, 0x6e, 0xcd, 0x16, 0x03, 0x59, 0x4d, 0xc7, 0x94, 0x85, + 0x6c, 0xc2, 0x6f, 0xf8, 0x9e, 0xd3, 0xa9, 0x87, 0xea, 0x84, 0x6f, 0x73, 0x90, 0x29, 0xcb, 0xc8, + 0xab, 0x30, 0x2c, 0x38, 0x47, 0x6f, 0x78, 0x68, 0x7b, 0xea, 0xd3, 0x28, 0x5d, 0x67, 0x8c, 0x80, + 0x82, 0x2a, 0x97, 0x1a, 0x8a, 0x8a, 0xa0, 0x9a, 0x12, 0x04, 0xa4, 0xfc, 0x3d, 0xd0, 0x43, 0xfe, + 0xfe, 0x02, 0x0c, 0x56, 0x82, 0x80, 0x86, 0xd2, 0x09, 0x7a, 0x34, 0x8a, 0x48, 0x13, 0xd0, 0x90, + 0x33, 0xb6, 0xb1, 0xdc, 0x14, 0x78, 0xc6, 0x9f, 0xe6, 0x61, 0x00, 0xff, 0xc4, 0x77, 0x4b, 0xbf, + 0xbe, 0xa7, 0xbd, 0x5b, 0xfa, 0xf5, 0x3d, 0x13, 0xa1, 0xe4, 0x3a, 0xaa, 0x1f, 0x64, 0xf4, 0x7e, + 0xf1, 0xf5, 0xa8, 0x57, 0x77, 0x62, 0xb0, 0xa9, 0xe2, 0x44, 0x0f, 0xba, 0x85, 0xcc, 0xd0, 0x07, + 0xa7, 0x21, 0xbf, 0x5e, 0x13, 0x5f, 0x8c, 0x21, 0x5a, 0xbc, 0xc0, 0xcc, 0xaf, 0xd7, 0xb0, 0x37, + 0x56, 0x2a, 0xf3, 0xaf, 0xdf, 0x54, 0xd3, 0xc0, 0x06, 0x7b, 0xf6, 0xfc, 0xeb, 0x37, 0x4d, 0x51, + 0xc2, 0xfa, 0x17, 0xdb, 0x8c, 0x0f, 0x9b, 0xdc, 0x69, 0x17, 0xfb, 0x17, 0xbf, 0x0d, 0x1f, 0x31, + 0xcd, 0x18, 0x81, 0xcc, 0xc3, 0x88, 0x70, 0x15, 0x47, 0x7c, 0xc5, 0x95, 0x5b, 0xb8, 0x92, 0x73, + 0x0a, 0x15, 0x89, 0x3f, 0x71, 0x89, 0x01, 0x92, 0x39, 0xc6, 0xc4, 0x13, 0x97, 0x1c, 0xc2, 0xc0, + 0x54, 0x50, 0x62, 0x9f, 0xe3, 0xd8, 0x19, 0x57, 0xf5, 0x39, 0xc6, 0x20, 0xb7, 0x11, 0x82, 0xf1, + 0xcb, 0x79, 0x28, 0x6d, 0x34, 0x3a, 0xbb, 0x6e, 0xeb, 0xc1, 0x75, 0x42, 0x00, 0xef, 0x66, 0x32, + 0x0a, 0x32, 0xfb, 0x9b, 0x9c, 0x85, 0x92, 0xbc, 0x8e, 0xc9, 0x0d, 0x29, 0x10, 0x57, 0xb1, 0x19, + 0x90, 0xe3, 0x2e, 0x72, 0xc6, 0xcb, 0x9f, 0xe4, 0x3a, 0x44, 0x97, 0xaa, 0x6e, 0xb7, 0xaf, 0x22, + 0x5b, 0x2c, 0x66, 0x84, 0x46, 0x5e, 0x03, 0x3c, 0x24, 0xc4, 0x8d, 0x40, 0x6a, 0xa9, 0x79, 0xd3, + 0x84, 0xf0, 0xc1, 0x49, 0x10, 0x8d, 0xdc, 0x00, 0x31, 0x31, 0x45, 0x66, 0xca, 0x53, 0x3a, 0x01, + 0xcf, 0x0e, 0x24, 0x49, 0x04, 0x2a, 0x79, 0x0b, 0x46, 0xe2, 0x9c, 0xf0, 0x71, 0xc2, 0x49, 0x95, + 0x72, 0x31, 0x2e, 0x7f, 0x70, 0xdd, 0x54, 0xd1, 0x8d, 0xff, 0x64, 0x10, 0x46, 0xd5, 0xf6, 0x10, + 0x13, 0xa6, 0x82, 0x06, 0xbb, 0x90, 0x0b, 0xdb, 0xa2, 0x36, 0x16, 0x8a, 0xe3, 0xf4, 0x82, 0xde, + 0x20, 0x86, 0xc7, 0x0d, 0x8d, 0xa4, 0x8f, 0xfb, 0xca, 0x33, 0xe6, 0x64, 0x10, 0x83, 0x39, 0x1e, + 0xa9, 0x40, 0xc9, 0x6b, 0x07, 0xbb, 0xb4, 0xe5, 0xca, 0x47, 0x94, 0x8b, 0x1a, 0xa3, 0x75, 0x51, + 0x98, 0xe2, 0x15, 0x91, 0x91, 0xd7, 0x61, 0xd0, 0x6b, 0xd3, 0x96, 0xed, 0x8a, 0x33, 0xee, 0xd9, + 0x04, 0x03, 0xda, 0xaa, 0x54, 0x15, 0x42, 0x81, 0x4c, 0xae, 0x41, 0xd1, 0xdb, 0x8f, 0xc6, 0xeb, + 0xac, 0x4e, 0xb4, 0x1f, 0xda, 0x0a, 0x09, 0x22, 0x32, 0x82, 0x8f, 0xec, 0xe6, 0x8e, 0x18, 0x31, + 0x9d, 0xe0, 0x8e, 0xdd, 0xdc, 0x51, 0x09, 0x18, 0x22, 0x79, 0x17, 0xa0, 0x6d, 0xef, 0x52, 0xdf, + 0x72, 0x3a, 0xe1, 0xa1, 0x18, 0xb7, 0xe7, 0x34, 0xb2, 0x0d, 0x56, 0xbc, 0xd4, 0x09, 0x0f, 0x15, + 0xda, 0xe1, 0xb6, 0x04, 0x92, 0x0a, 0x40, 0xd3, 0x0e, 0x43, 0xea, 0x37, 0x3d, 0x61, 0xdc, 0x35, + 0x12, 0x25, 0x74, 0xe4, 0x0c, 0xee, 0x45, 0xc5, 0x0a, 0x07, 0x85, 0x08, 0x1b, 0xed, 0xfa, 0xb6, + 0xc8, 0x0f, 0x9a, 0x68, 0xb4, 0xeb, 0x6b, 0x5f, 0xc9, 0x10, 0xc9, 0x97, 0x61, 0xc8, 0x71, 0x83, + 0xba, 0xe7, 0x3b, 0x22, 0xf8, 0xc1, 0x39, 0x8d, 0x66, 0x89, 0x97, 0x29, 0x64, 0x12, 0x9d, 0xb5, + 0x56, 0xc4, 0x57, 0x5b, 0xf3, 0x0e, 0x50, 0x77, 0x9f, 0x6c, 0x6d, 0x2d, 0x2a, 0x56, 0x5b, 0x1b, + 0x13, 0xb1, 0xa1, 0xdc, 0x75, 0xc3, 0x86, 0xbd, 0x2d, 0xde, 0x91, 0xf5, 0xa1, 0xbc, 0x8d, 0x45, + 0xea, 0x50, 0x72, 0x64, 0xf2, 0x06, 0x94, 0x68, 0x2b, 0xf4, 0x6d, 0xcb, 0x75, 0x84, 0x53, 0x9c, + 0xde, 0x68, 0x76, 0x00, 0xdb, 0xd5, 0x25, 0xb5, 0xd1, 0x88, 0x5f, 0x75, 0x58, 0xff, 0x04, 0x75, + 0xb7, 0x29, 0x7c, 0xd9, 0xf4, 0xfe, 0xa9, 0x2d, 0x56, 0xef, 0xa9, 0xfd, 0xc3, 0x10, 0xc9, 0x73, + 0x00, 0xbb, 0xb4, 0x45, 0xb9, 0x63, 0x29, 0x7f, 0x65, 0x30, 0x15, 0xc8, 0x57, 0x8a, 0xff, 0xf3, + 0x2f, 0xce, 0xe5, 0x16, 0x00, 0x4a, 0x32, 0xfa, 0x83, 0xb1, 0x0a, 0x67, 0xbb, 0x2e, 0x0a, 0x72, + 0x05, 0xca, 0x3b, 0xb6, 0xd0, 0x73, 0xd5, 0xf7, 0xec, 0x56, 0x8b, 0x36, 0xc4, 0x76, 0x34, 0x21, + 0xe1, 0x8b, 0x1c, 0xcc, 0x39, 0x1b, 0xef, 0xc2, 0x74, 0x56, 0x6f, 0x90, 0xe7, 0x61, 0x54, 0x0d, + 0x74, 0x21, 0x98, 0x8c, 0xd8, 0x6d, 0x57, 0x86, 0xba, 0x10, 0x0c, 0x7e, 0x23, 0x07, 0xe7, 0x7a, + 0xad, 0x2d, 0x32, 0x0b, 0xa5, 0xb6, 0xef, 0x7a, 0x28, 0xc3, 0xf1, 0x1d, 0x30, 0xfa, 0x4d, 0xce, + 0x03, 0x70, 0x61, 0x23, 0xb4, 0x77, 0x85, 0xb1, 0xbb, 0x39, 0x8c, 0x90, 0x4d, 0x7b, 0x37, 0x20, + 0xaf, 0xc0, 0xa4, 0x43, 0x77, 0xec, 0x4e, 0x23, 0xb4, 0x82, 0xfa, 0x1e, 0x75, 0xd0, 0xbf, 0x04, + 0x8d, 0x98, 0xcc, 0xb2, 0x28, 0xa8, 0x49, 0x78, 0xaa, 0xc5, 0x03, 0x5d, 0x5a, 0x7c, 0xa7, 0x58, + 0xca, 0x95, 0xf3, 0x26, 0xda, 0xf2, 0x18, 0x3f, 0x94, 0x87, 0x99, 0x6e, 0x93, 0x89, 0xbc, 0x9d, + 0xd5, 0x07, 0x5c, 0x55, 0xaf, 0xc2, 0x55, 0x55, 0xbd, 0x52, 0x1b, 0x99, 0x87, 0xc8, 0x3b, 0xe4, + 0x38, 0x4f, 0x6f, 0x09, 0x63, 0x34, 0x6d, 0x3b, 0x08, 0x0e, 0xd8, 0x7a, 0x29, 0x28, 0x81, 0xec, + 0x04, 0x4c, 0xa5, 0x91, 0x30, 0xf2, 0x25, 0x80, 0x7a, 0xc3, 0x0b, 0x28, 0xbe, 0x88, 0x8b, 0x83, + 0x98, 0x9b, 0xc8, 0x46, 0x50, 0xf5, 0x09, 0x14, 0xa1, 0x8b, 0x9e, 0x43, 0xc5, 0x00, 0xda, 0x70, + 0xa6, 0xcb, 0xee, 0xc1, 0x86, 0x27, 0x4e, 0x9c, 0x29, 0xc3, 0xf0, 0x77, 0xa2, 0xf4, 0x99, 0xc9, + 0x1e, 0xcf, 0x77, 0x9b, 0x23, 0x87, 0x40, 0xd2, 0x5b, 0x04, 0xe3, 0x2e, 0x0c, 0x3d, 0x3b, 0x7e, + 0xc4, 0x9d, 0x43, 0xee, 0xfb, 0x0d, 0x32, 0x07, 0x23, 0x32, 0xcd, 0x0e, 0x13, 0x74, 0x39, 0x73, + 0x10, 0xa0, 0xbb, 0x14, 0x27, 0x0f, 0xc6, 0x5b, 0x44, 0x1f, 0x20, 0x71, 0x84, 0x0e, 0x23, 0x64, + 0xf3, 0xb0, 0x2d, 0xbf, 0xee, 0x9c, 0x9c, 0xdf, 0xfa, 0xc6, 0x2d, 0x4a, 0x7f, 0x36, 0x27, 0x87, + 0x3f, 0xbd, 0xf3, 0x1d, 0xd7, 0x3e, 0x02, 0xe8, 0xb1, 0x21, 0x1a, 0x86, 0x7f, 0xb3, 0x23, 0x5d, + 0xae, 0x3a, 0x71, 0xa4, 0x8b, 0x9f, 0xe4, 0x12, 0x4c, 0xf8, 0xdc, 0xa6, 0x2f, 0xf4, 0x44, 0x7f, + 0xe2, 0x48, 0x99, 0x63, 0x1c, 0xbc, 0xe9, 0x61, 0x9f, 0x8a, 0x76, 0xdd, 0x89, 0x3a, 0x4c, 0x39, + 0x08, 0xc8, 0x55, 0x18, 0x66, 0x07, 0x01, 0xc6, 0x91, 0x48, 0x98, 0x8a, 0x23, 0x1e, 0x1e, 0xab, + 0x66, 0xe9, 0x23, 0xf1, 0xb7, 0xe0, 0xf5, 0x0f, 0x73, 0x92, 0x99, 0x7a, 0x0c, 0x91, 0x33, 0x30, + 0xe4, 0xf9, 0xbb, 0xca, 0xa7, 0x0d, 0x7a, 0xfe, 0x2e, 0xfb, 0xae, 0xcb, 0x50, 0xe6, 0x9e, 0x0b, + 0xdc, 0x25, 0x3c, 0x38, 0x6c, 0xf1, 0x7b, 0x6a, 0xc9, 0x1c, 0xe7, 0x70, 0xcc, 0x25, 0x7a, 0xd8, + 0xaa, 0x33, 0xcc, 0x20, 0xf0, 0x2c, 0x35, 0x78, 0x8c, 0xf8, 0xec, 0xf1, 0x20, 0xf0, 0xe2, 0x28, + 0x32, 0x0e, 0x59, 0x80, 0x31, 0xc6, 0x27, 0x0a, 0x61, 0x23, 0x4e, 0xc9, 0xf3, 0xe9, 0x53, 0xf2, + 0xb0, 0x55, 0x97, 0x4d, 0x34, 0x47, 0x03, 0xe5, 0x97, 0xf8, 0x9a, 0x9f, 0xcb, 0xc3, 0xe9, 0x6c, + 0x74, 0x1c, 0x2f, 0x56, 0x09, 0x3a, 0xf0, 0x70, 0x9d, 0xa5, 0x39, 0xcc, 0x20, 0x3c, 0x46, 0x41, + 0x56, 0x6b, 0xf3, 0x99, 0xad, 0x7d, 0x19, 0x26, 0x91, 0x91, 0x90, 0x4b, 0x1a, 0x6e, 0x10, 0x0a, + 0xd7, 0x7b, 0x73, 0x82, 0x15, 0xf0, 0x0d, 0x6e, 0x95, 0x81, 0xc9, 0x8b, 0x30, 0x2e, 0xb7, 0x28, + 0xef, 0xa0, 0xc5, 0x2a, 0xe6, 0xfb, 0xd3, 0x98, 0x80, 0xae, 0x23, 0x90, 0x9c, 0x82, 0x41, 0xbb, + 0xdd, 0x66, 0x55, 0xf2, 0x6d, 0x69, 0xc0, 0x6e, 0xb7, 0xab, 0x0e, 0xb9, 0x08, 0x63, 0xe8, 0xae, + 0x64, 0xed, 0xa0, 0xa1, 0x88, 0x30, 0x10, 0x33, 0x47, 0x11, 0xc8, 0x8d, 0x47, 0x02, 0xb6, 0x10, + 0x18, 0xad, 0x44, 0x19, 0x42, 0x14, 0xb0, 0xdb, 0x12, 0x41, 0xf4, 0xcc, 0x97, 0x61, 0x42, 0x9c, + 0xa6, 0x62, 0x87, 0x47, 0x4a, 0x31, 0xff, 0x98, 0x98, 0x2b, 0xc2, 0x8f, 0x83, 0x00, 0x55, 0x1d, + 0x49, 0xf9, 0x07, 0x39, 0x38, 0x95, 0x79, 0x1c, 0x93, 0x6f, 0x02, 0xf7, 0xde, 0x08, 0x3d, 0xcb, + 0xa7, 0x75, 0xb7, 0xed, 0xa2, 0x7f, 0x3b, 0x57, 0x42, 0xcd, 0xf7, 0x3a, 0xc8, 0xd1, 0x13, 0x64, + 0xd3, 0x33, 0x23, 0x22, 0x7e, 0x8f, 0x2e, 0xfb, 0x09, 0xf0, 0xec, 0x07, 0x70, 0x2a, 0x13, 0x35, + 0xe3, 0x7e, 0xfb, 0xaa, 0x9e, 0xa6, 0x4d, 0xbe, 0x2a, 0x24, 0x3e, 0x5a, 0xb9, 0xf7, 0x8a, 0xcf, + 0xfb, 0xad, 0xe8, 0xf3, 0x12, 0x07, 0x37, 0x59, 0x4e, 0x4e, 0xcb, 0x2c, 0xd9, 0x53, 0x12, 0x75, + 0x9d, 0x99, 0xe4, 0x03, 0x38, 0x25, 0xa6, 0xca, 0xae, 0x6f, 0xb7, 0xf7, 0x62, 0x76, 0xbc, 0xa1, + 0x2f, 0x65, 0xb1, 0xe3, 0x73, 0xe8, 0x36, 0xc3, 0x8f, 0xb8, 0x4e, 0xd9, 0x69, 0xa0, 0xf8, 0x06, + 0x5f, 0x1e, 0xfa, 0x19, 0xad, 0xc9, 0x98, 0x83, 0xb9, 0xac, 0x39, 0xd8, 0xf7, 0x02, 0x10, 0x75, + 0xfe, 0x70, 0x0e, 0x2e, 0x1c, 0xd7, 0x66, 0xb2, 0x05, 0xa7, 0xf1, 0xdd, 0x3b, 0xf0, 0xa2, 0xcf, + 0xb6, 0xea, 0x76, 0x7d, 0x8f, 0x8a, 0x59, 0x62, 0x64, 0x7e, 0x7c, 0xbb, 0x5d, 0xab, 0xad, 0x2b, + 0xdf, 0xdd, 0x6e, 0xd7, 0x02, 0x4f, 0xfe, 0x5e, 0x64, 0xe4, 0xa2, 0x0d, 0x0e, 0x3c, 0xdb, 0x83, + 0x52, 0x59, 0x56, 0x39, 0x75, 0x59, 0x5d, 0x86, 0xf2, 0x0e, 0x75, 0x98, 0x08, 0x45, 0x1d, 0x6c, + 0xda, 0xc3, 0x79, 0x9e, 0xeb, 0xd0, 0x1c, 0x8f, 0xe0, 0xb5, 0xc0, 0x7b, 0x30, 0x2f, 0x6a, 0x69, + 0xca, 0x1d, 0x52, 0x15, 0xd1, 0xc8, 0x55, 0x98, 0x4a, 0xf8, 0xea, 0xc7, 0xce, 0x9f, 0xe6, 0x24, + 0x2b, 0xd2, 0x23, 0xbb, 0x3c, 0x0f, 0xa3, 0x72, 0x18, 0xfc, 0xc8, 0x85, 0xc4, 0x1c, 0x11, 0x30, + 0x36, 0xcb, 0x45, 0x75, 0x7f, 0x27, 0x2f, 0x45, 0xa6, 0x05, 0xcf, 0x0b, 0x83, 0xd0, 0xb7, 0xdb, + 0xda, 0xbd, 0x89, 0x34, 0xe1, 0xac, 0x67, 0x77, 0xc2, 0xbd, 0x79, 0x8b, 0xfd, 0xeb, 0xf9, 0xd2, + 0x9f, 0xb3, 0x2e, 0x2d, 0xe1, 0x46, 0xe6, 0xaf, 0xe9, 0x5b, 0x67, 0x85, 0x61, 0x57, 0x54, 0x64, + 0x76, 0xc2, 0x2b, 0x5c, 0x57, 0x9e, 0x31, 0xcf, 0x70, 0x9e, 0x29, 0x2c, 0xb2, 0x02, 0xa3, 0xdb, + 0xd4, 0xf6, 0xa9, 0x6f, 0xc5, 0x49, 0xd5, 0x93, 0x17, 0xa7, 0x05, 0x44, 0x40, 0xfb, 0x4c, 0x9d, + 0xeb, 0xc8, 0x76, 0x5c, 0x42, 0xde, 0x81, 0x61, 0xd7, 0x11, 0xa1, 0xe8, 0xc4, 0xf5, 0x49, 0x17, + 0xd9, 0xab, 0x0e, 0x8f, 0x4c, 0x17, 0xf3, 0x60, 0x77, 0x2f, 0x57, 0x40, 0x17, 0xc6, 0xb4, 0x1b, + 0xa6, 0xb1, 0x20, 0x4f, 0xe7, 0x34, 0x59, 0x2a, 0x25, 0xfc, 0x69, 0x18, 0x0c, 0x94, 0xd8, 0x78, + 0xa6, 0xf8, 0x65, 0xfc, 0x05, 0xb8, 0xdc, 0x6f, 0x1f, 0x91, 0xd7, 0x80, 0x74, 0xe9, 0xf0, 0x61, + 0x73, 0xd2, 0x4e, 0xf5, 0xdb, 0xf3, 0xa0, 0x06, 0xf7, 0x72, 0xe5, 0x80, 0x4b, 0xd8, 0x7d, 0xdf, + 0x35, 0xfe, 0x8b, 0x3c, 0x8c, 0xeb, 0x77, 0x6a, 0xf2, 0x0a, 0x14, 0x23, 0xb6, 0xe3, 0x91, 0xee, + 0x57, 0x45, 0x62, 0xcc, 0x4d, 0x44, 0x62, 0x07, 0x04, 0xbe, 0xff, 0x58, 0x4d, 0x55, 0x3d, 0x6b, + 0x8e, 0x22, 0x50, 0xaa, 0x65, 0xef, 0x00, 0x4f, 0xad, 0x8b, 0x7b, 0x59, 0xd8, 0x5f, 0x22, 0xf9, + 0x12, 0xbb, 0xd9, 0xa3, 0x5e, 0x6d, 0x94, 0xd1, 0xb2, 0xfd, 0x04, 0x73, 0xc7, 0xc7, 0x57, 0xa6, + 0x62, 0xf7, 0x2b, 0x93, 0xf8, 0x94, 0x2e, 0x57, 0xa6, 0x81, 0x1e, 0x57, 0xa6, 0x98, 0x32, 0xba, + 0x32, 0xbd, 0x20, 0x5a, 0xef, 0xdb, 0x07, 0x16, 0x7e, 0x16, 0x37, 0x3c, 0xe3, 0xed, 0x32, 0xed, + 0x03, 0x7c, 0xf8, 0x5a, 0x18, 0x06, 0xf9, 0x5a, 0x66, 0xfc, 0xf5, 0x5c, 0xe2, 0xce, 0x22, 0x7b, + 0xf6, 0x45, 0x18, 0x77, 0x9b, 0x4c, 0x98, 0xa2, 0x8e, 0x22, 0x04, 0x8c, 0x99, 0x63, 0x12, 0xca, + 0x05, 0x81, 0x97, 0x60, 0x22, 0x42, 0xe3, 0xce, 0xc2, 0xdc, 0xa0, 0xdd, 0x8c, 0xa8, 0x85, 0xb3, + 0xf0, 0x2b, 0x30, 0x19, 0x21, 0x0a, 0xb9, 0x93, 0xcb, 0x01, 0x63, 0x66, 0x59, 0x16, 0x88, 0x9c, + 0x8f, 0x81, 0xb1, 0x9b, 0x3c, 0x64, 0x3e, 0xa3, 0x56, 0x19, 0xff, 0x24, 0x0f, 0x53, 0x19, 0xca, + 0x16, 0xf2, 0x01, 0x4c, 0xc9, 0x4d, 0x83, 0x1f, 0x46, 0x7c, 0x31, 0xf3, 0xed, 0xe2, 0x4a, 0xd6, + 0x76, 0x81, 0x68, 0x19, 0x4b, 0x7a, 0x52, 0x6c, 0x14, 0x71, 0xf9, 0x9f, 0x9f, 0x2d, 0x82, 0xbc, + 0x0f, 0xa7, 0x45, 0xaa, 0x66, 0x65, 0xa7, 0xb0, 0x7c, 0xba, 0x23, 0x26, 0xec, 0xf3, 0xa9, 0x05, + 0xe5, 0xd6, 0x95, 0xe6, 0x98, 0x74, 0x67, 0xe5, 0x19, 0x73, 0x3a, 0xc8, 0x80, 0x27, 0x77, 0x9f, + 0x7f, 0x37, 0x07, 0xc6, 0xf1, 0xfd, 0x85, 0xb7, 0xa0, 0x64, 0x87, 0xb3, 0x5b, 0x90, 0xd2, 0x7b, + 0x17, 0x61, 0xcc, 0xa7, 0x3b, 0x3e, 0x0d, 0xf6, 0x94, 0xee, 0x1b, 0x36, 0x47, 0x05, 0x50, 0x76, + 0x8c, 0x0c, 0x53, 0x70, 0xa2, 0xe5, 0x2b, 0x89, 0x8c, 0x5b, 0xd1, 0xa1, 0x92, 0x39, 0x0e, 0x64, + 0x1a, 0x06, 0xd4, 0x06, 0xf2, 0x1f, 0x77, 0x8a, 0xa5, 0x7c, 0xb9, 0x60, 0x8a, 0x60, 0x0a, 0x3b, + 0x6e, 0x83, 0x1a, 0xbf, 0x9e, 0x83, 0xd9, 0xee, 0x9d, 0x47, 0x3e, 0x50, 0x9e, 0x07, 0x0b, 0x3c, + 0x2c, 0xdd, 0x31, 0xfd, 0xad, 0xbe, 0xa4, 0x08, 0xff, 0xfe, 0x64, 0x96, 0x62, 0xc1, 0xf2, 0xd3, + 0xbc, 0x71, 0xbc, 0x21, 0xb5, 0x8b, 0x4c, 0x2e, 0x7f, 0x70, 0x9d, 0x5c, 0x81, 0x21, 0xae, 0x50, + 0x94, 0x0d, 0x9d, 0xd0, 0x1a, 0xfa, 0xe0, 0xba, 0x29, 0xcb, 0x8d, 0xef, 0xe5, 0x22, 0x95, 0x4a, + 0xb2, 0xf9, 0x0f, 0xae, 0x93, 0x2f, 0xf5, 0xf7, 0xd0, 0x57, 0x92, 0x0f, 0x7d, 0xd1, 0x23, 0xdf, + 0x97, 0xb5, 0x47, 0xbe, 0x17, 0x7a, 0xf7, 0x93, 0xb8, 0xbc, 0x25, 0xf3, 0x48, 0xfe, 0xb3, 0x1c, + 0x9c, 0xef, 0x49, 0x41, 0xce, 0x41, 0xa9, 0xb2, 0x51, 0xdd, 0x8c, 0x47, 0x96, 0xad, 0x16, 0x09, + 0x21, 0xb7, 0x61, 0x78, 0xc1, 0x0e, 0xdc, 0x3a, 0x9b, 0xc0, 0x99, 0xe2, 0x68, 0x8a, 0x6d, 0x84, + 0xbe, 0xf2, 0x8c, 0x19, 0xd3, 0x12, 0x0b, 0x26, 0x71, 0x15, 0xa4, 0xf2, 0xb4, 0x25, 0x45, 0x91, + 0x14, 0xc3, 0x14, 0x19, 0xdb, 0x61, 0x52, 0xc0, 0xe4, 0xe2, 0x7b, 0x28, 0x65, 0xcf, 0xee, 0x0d, + 0x3c, 0x41, 0x48, 0x8e, 0xcb, 0x50, 0xda, 0x90, 0x6a, 0x15, 0x25, 0x4d, 0xab, 0x54, 0xa1, 0x98, + 0x51, 0xa9, 0xf1, 0xd7, 0x72, 0x52, 0x5e, 0x38, 0xfe, 0x43, 0x94, 0x00, 0xbe, 0x4e, 0xef, 0x00, + 0xbe, 0xce, 0x27, 0x0c, 0xe0, 0x6b, 0xfc, 0xb2, 0x08, 0x98, 0x55, 0x75, 0x36, 0x12, 0x39, 0x25, + 0x3e, 0xad, 0xd9, 0xc2, 0xb2, 0x36, 0x3b, 0x2f, 0x2a, 0x41, 0xc5, 0xd3, 0x75, 0x75, 0xb7, 0x5e, + 0x50, 0xa6, 0xea, 0x3f, 0xc9, 0xc3, 0xb9, 0x5e, 0xe4, 0x99, 0xe9, 0x2f, 0x72, 0x27, 0x4b, 0x7f, + 0x71, 0x05, 0x4a, 0x1c, 0xa6, 0xe7, 0x14, 0x14, 0xa4, 0xac, 0xc3, 0x65, 0x31, 0xb9, 0x08, 0x83, + 0x95, 0xc5, 0x5a, 0x1c, 0xf5, 0x18, 0xdf, 0xd9, 0xec, 0x7a, 0x80, 0x2f, 0x38, 0xa2, 0x88, 0x7c, + 0x23, 0x1d, 0xe8, 0x5b, 0x84, 0x3b, 0x7e, 0x56, 0xe9, 0x90, 0x54, 0x2c, 0x3b, 0x6c, 0x6f, 0x1c, + 0x7b, 0x4d, 0x84, 0x33, 0x32, 0xd3, 0x41, 0xc3, 0x0d, 0x18, 0xdc, 0xf0, 0x69, 0x40, 0x43, 0xf5, + 0x0d, 0xac, 0x8d, 0x10, 0x53, 0x94, 0x88, 0x17, 0x2a, 0xfb, 0x90, 0x7b, 0x19, 0x0c, 0xaa, 0x4e, + 0x58, 0xf8, 0xa4, 0xc5, 0xc0, 0xa6, 0x82, 0x62, 0x7c, 0x27, 0x07, 0xd3, 0x59, 0xcd, 0x22, 0xe7, + 0xa0, 0xd8, 0xca, 0x0c, 0x51, 0xde, 0xe2, 0xb6, 0xce, 0x23, 0x98, 0xcf, 0x6d, 0xc7, 0xf3, 0x9b, + 0x76, 0xa8, 0x3e, 0xfc, 0x29, 0x60, 0x13, 0xd8, 0x8f, 0x5b, 0xf8, 0x37, 0x99, 0x93, 0x9b, 0x6d, + 0x21, 0x15, 0xd4, 0x1c, 0xff, 0x33, 0x2a, 0x00, 0x55, 0x67, 0x63, 0xbd, 0xcd, 0x43, 0xa3, 0xdd, + 0x80, 0x22, 0x6b, 0x56, 0x62, 0x32, 0xb2, 0xe9, 0x50, 0xb9, 0xb7, 0x2a, 0x90, 0x78, 0xab, 0xd8, + 0xdd, 0xc9, 0x44, 0x64, 0x63, 0x0b, 0xc6, 0x75, 0x0c, 0xb2, 0xac, 0x07, 0xd3, 0x88, 0x53, 0xcd, + 0x2f, 0x78, 0x1e, 0x37, 0x3e, 0x59, 0x38, 0xfb, 0xfd, 0xa3, 0x39, 0x60, 0x3f, 0x39, 0x4d, 0x56, + 0xb0, 0x0d, 0xe3, 0xa7, 0xf2, 0x30, 0x1d, 0x1b, 0xb1, 0xcb, 0x25, 0xf1, 0xd4, 0x5a, 0x54, 0x56, + 0x34, 0x8b, 0xbf, 0xb9, 0x54, 0x36, 0x67, 0xf9, 0x81, 0x3d, 0x0c, 0x8d, 0x6e, 0xc3, 0x4c, 0x37, + 0x7c, 0xf2, 0x4a, 0x2a, 0xdf, 0xaa, 0x70, 0xb6, 0x8c, 0x12, 0xb3, 0x2a, 0xe9, 0x57, 0xff, 0x51, + 0x0e, 0x66, 0x85, 0xc9, 0xc4, 0x3d, 0xdb, 0x6d, 0x61, 0x8e, 0xf9, 0x3a, 0x7d, 0x32, 0x16, 0xc1, + 0xb7, 0xb5, 0x6d, 0xe9, 0x45, 0xdd, 0x32, 0x26, 0x55, 0x5b, 0xf7, 0xaf, 0x25, 0x57, 0xd0, 0xad, + 0xb6, 0xce, 0x27, 0x6f, 0x91, 0x7b, 0x60, 0xb4, 0x18, 0x40, 0xf5, 0xc0, 0x40, 0x0c, 0xe3, 0x2f, + 0xc1, 0x73, 0xbd, 0x2b, 0x20, 0x1f, 0xc2, 0x18, 0x86, 0xa2, 0xbd, 0xdf, 0xde, 0xf5, 0x6d, 0x87, + 0x4a, 0x45, 0x91, 0x7c, 0xdf, 0x51, 0xcb, 0xb8, 0x2b, 0xb1, 0xf0, 0x08, 0xd8, 0xc5, 0x20, 0xb7, + 0x82, 0x48, 0xb3, 0x4b, 0x52, 0xb9, 0x19, 0x3f, 0x94, 0x03, 0x92, 0xe6, 0x41, 0x6e, 0xc2, 0xe8, + 0xfd, 0xcd, 0xc5, 0x5a, 0x68, 0xfb, 0xe1, 0x8a, 0xd7, 0xf1, 0x85, 0x8b, 0x2e, 0x37, 0x10, 0x0f, + 0xeb, 0x6c, 0x67, 0xf0, 0x43, 0x6b, 0xcf, 0xeb, 0xf8, 0xa6, 0x86, 0x87, 0xf1, 0x6e, 0x29, 0xdd, + 0x77, 0xec, 0x43, 0x3d, 0xde, 0xad, 0x80, 0x69, 0xf1, 0x6e, 0x05, 0xcc, 0xf8, 0x5b, 0x39, 0x78, + 0x56, 0xbe, 0xa5, 0x38, 0x19, 0x6d, 0x59, 0x44, 0x37, 0x28, 0x5f, 0x86, 0x28, 0xe9, 0x25, 0x9b, + 0x4e, 0x4a, 0x4f, 0x41, 0x6c, 0x20, 0x0a, 0xa9, 0x9c, 0x96, 0xbc, 0x07, 0xc5, 0x5a, 0xe8, 0xb5, + 0xfb, 0x70, 0x15, 0x2c, 0x47, 0x23, 0x1a, 0x7a, 0x6d, 0x64, 0x81, 0x94, 0x06, 0x85, 0x69, 0xb5, + 0x71, 0xb2, 0xc5, 0xe4, 0x1e, 0x0c, 0x09, 0x1f, 0xee, 0x84, 0xde, 0xa9, 0xc7, 0x37, 0x2d, 0x4c, + 0x48, 0x7f, 0x44, 0x11, 0x22, 0xc3, 0x94, 0x3c, 0x8c, 0x9f, 0xcc, 0xc1, 0x08, 0x13, 0x1e, 0xf0, + 0xca, 0xf5, 0x69, 0xa7, 0xb4, 0x2e, 0x07, 0x4a, 0xb5, 0x65, 0xc4, 0xbe, 0xaf, 0xc3, 0xf5, 0x75, + 0x98, 0x48, 0x10, 0x10, 0x03, 0x3d, 0x51, 0x1a, 0x6e, 0xdd, 0xe6, 0xe1, 0x33, 0xb9, 0xce, 0x4f, + 0x83, 0x19, 0xff, 0x4a, 0x0e, 0xa6, 0xd7, 0xf7, 0x43, 0xbb, 0x8a, 0x57, 0x48, 0xb3, 0xd3, 0x90, + 0xeb, 0x9d, 0x09, 0x44, 0xf2, 0x51, 0x8e, 0x5b, 0xc9, 0x73, 0x81, 0x48, 0xc0, 0xcc, 0xa8, 0x94, + 0xac, 0x40, 0x49, 0x9c, 0x2f, 0x81, 0x88, 0x6c, 0x21, 0xdf, 0x9c, 0x75, 0xc6, 0x02, 0x89, 0x7d, + 0x09, 0x6e, 0x61, 0x82, 0xc6, 0x8c, 0xa8, 0x8d, 0x3f, 0xcd, 0xc1, 0x99, 0x2e, 0x34, 0xe4, 0x6d, + 0x18, 0x40, 0x63, 0x3f, 0x31, 0x7a, 0xe7, 0xba, 0x54, 0x11, 0xd6, 0xf7, 0x1e, 0x5c, 0xe7, 0x07, + 0x51, 0x93, 0xfd, 0x30, 0x39, 0x15, 0xf9, 0x00, 0x86, 0x2b, 0x8e, 0x23, 0xee, 0x25, 0x79, 0xed, + 0x5e, 0xd2, 0xa5, 0xc6, 0xab, 0x11, 0x3e, 0xbf, 0x97, 0x70, 0xb3, 0x13, 0xc7, 0xb1, 0x84, 0x21, + 0x63, 0xcc, 0x6f, 0xf6, 0x2d, 0x18, 0xd7, 0x91, 0x4f, 0x74, 0x2f, 0xf9, 0x5e, 0x0e, 0xca, 0x7a, + 0x1b, 0x3e, 0x1b, 0x4f, 0xca, 0xac, 0x61, 0x3e, 0x66, 0x52, 0xfd, 0x4c, 0x1e, 0x4e, 0x65, 0xf6, + 0x30, 0x79, 0x0d, 0x06, 0x2b, 0xed, 0x76, 0x75, 0x49, 0xcc, 0x2a, 0x21, 0xf0, 0xa0, 0xa6, 0x55, + 0xbb, 0xb6, 0x71, 0x24, 0x72, 0x03, 0x4a, 0x38, 0x33, 0x19, 0x41, 0x3e, 0x8e, 0x31, 0xc1, 0x9f, + 0x36, 0x12, 0x31, 0x26, 0x24, 0x22, 0xb9, 0x05, 0xe3, 0xc2, 0xa9, 0xca, 0xa4, 0xbb, 0xf4, 0x51, + 0x14, 0xec, 0x0c, 0xe3, 0xb1, 0x49, 0x17, 0x2c, 0xcb, 0xe7, 0x65, 0xaa, 0x5b, 0x91, 0x4e, 0x85, + 0xf9, 0x7f, 0x19, 0x4f, 0x95, 0x13, 0x0f, 0x74, 0xc1, 0xf3, 0xff, 0x62, 0x23, 0xba, 0xf0, 0x4a, + 0x51, 0x46, 0xc3, 0x55, 0x09, 0x02, 0x77, 0xb7, 0xd5, 0xa4, 0xad, 0xf0, 0xb3, 0x1b, 0xae, 0xb8, + 0x8e, 0xbe, 0x86, 0xeb, 0xbb, 0x45, 0xbe, 0x98, 0x93, 0x64, 0xc7, 0xa4, 0xb8, 0x5f, 0x82, 0x21, + 0xee, 0xce, 0x25, 0x57, 0xc6, 0xf9, 0xcc, 0x26, 0x70, 0x9c, 0x07, 0xd7, 0xb9, 0xf8, 0xc2, 0xad, + 0x0e, 0x03, 0xf3, 0xff, 0xa3, 0xee, 0x7a, 0x7e, 0x1b, 0x37, 0xae, 0xbf, 0x49, 0xc9, 0x5e, 0xfb, + 0xc9, 0x3f, 0xe8, 0xc9, 0xc6, 0xab, 0xaf, 0x77, 0xd7, 0xc9, 0x57, 0x4d, 0x37, 0x8d, 0xd2, 0xfc, + 0x6e, 0x9a, 0x6c, 0x8a, 0x34, 0xa5, 0x25, 0xca, 0x62, 0x2c, 0x91, 0x0c, 0x49, 0xd9, 0xd9, 0x34, + 0x2d, 0xa1, 0xd8, 0x5c, 0xaf, 0x5a, 0x2d, 0xa5, 0xe8, 0x47, 0xb6, 0x9b, 0x5b, 0x2f, 0xb9, 0x14, + 0x01, 0x8a, 0x5c, 0x5b, 0xa0, 0x28, 0x90, 0xff, 0xa2, 0xff, 0x40, 0x80, 0xa0, 0x40, 0x0e, 0xbd, + 0x15, 0x08, 0xda, 0x00, 0xbd, 0xf4, 0xde, 0x4b, 0x4e, 0xc5, 0xbc, 0x99, 0x21, 0x87, 0xa4, 0xa4, + 0xd8, 0x9b, 0x45, 0x8b, 0xde, 0xc4, 0x37, 0x6f, 0x46, 0xf3, 0xf3, 0xcd, 0xbc, 0x99, 0xf7, 0x3e, + 0x4f, 0x64, 0x25, 0x47, 0x50, 0xaa, 0xf5, 0xc3, 0x6e, 0x34, 0x1d, 0xfa, 0xe7, 0xbb, 0x60, 0x2c, + 0xf3, 0xb6, 0xac, 0x9f, 0xb0, 0x6c, 0x78, 0x31, 0x89, 0x92, 0x5c, 0x2e, 0x88, 0xf8, 0xb1, 0x21, + 0x52, 0x11, 0xef, 0x43, 0x9f, 0x5f, 0xd0, 0x3f, 0x59, 0x22, 0xe6, 0x4b, 0x5b, 0xd9, 0x71, 0x4b, + 0xa5, 0x00, 0x36, 0x5b, 0xdd, 0xf1, 0xc4, 0x1f, 0x75, 0xa3, 0x31, 0x22, 0x32, 0x9c, 0xc3, 0x4d, + 0x56, 0x44, 0xb6, 0xdb, 0xc2, 0xdb, 0xc8, 0x49, 0x9c, 0x15, 0xeb, 0x9c, 0x29, 0x8e, 0x9e, 0x97, + 0x1a, 0xbd, 0xa8, 0xdb, 0xef, 0x7d, 0x28, 0xec, 0x35, 0xd9, 0x79, 0xe9, 0xb6, 0x20, 0xba, 0x49, + 0x7a, 0xe5, 0xdd, 0xdc, 0xb8, 0xb1, 0x5a, 0x96, 0xe0, 0x12, 0x37, 0xd1, 0x67, 0x26, 0xeb, 0x8e, + 0x61, 0xd5, 0x4d, 0xeb, 0x40, 0x53, 0xc8, 0x26, 0x80, 0xe3, 0xda, 0x35, 0xc3, 0xf3, 0xe8, 0xb7, + 0x4a, 0xbf, 0xb9, 0x3d, 0x7b, 0xa3, 0xd3, 0xd2, 0x0a, 0x92, 0x49, 0x7b, 0xb1, 0xf2, 0xb9, 0x02, + 0x3b, 0xb3, 0x87, 0x92, 0xf8, 0x80, 0x4e, 0x0d, 0xfc, 0xaa, 0xf9, 0x87, 0x0b, 0xc7, 0x7d, 0x26, + 0x39, 0xeb, 0x1c, 0x31, 0x61, 0x46, 0xf7, 0xaa, 0x78, 0x39, 0x4a, 0x62, 0xb2, 0xf5, 0x4e, 0x2b, + 0x35, 0x28, 0xcf, 0x2b, 0x23, 0xdd, 0xd4, 0x2d, 0x28, 0xe9, 0x8e, 0xd3, 0x32, 0x6b, 0xba, 0x6f, + 0xda, 0x96, 0xa6, 0x90, 0x35, 0x58, 0x3e, 0x70, 0xed, 0x8e, 0xa3, 0xa9, 0x95, 0x4f, 0x14, 0xd8, + 0x30, 0xa3, 0x49, 0x78, 0xc6, 0xec, 0x5f, 0xbe, 0xed, 0xe2, 0x7b, 0x2d, 0xb5, 0xf8, 0xca, 0xb1, + 0xfb, 0x4f, 0xfc, 0x07, 0xe7, 0x5a, 0x79, 0x7f, 0x51, 0x60, 0x3b, 0x97, 0x87, 0x78, 0x70, 0x49, + 0x3f, 0xf6, 0x6c, 0xb3, 0x5e, 0xe3, 0x35, 0x13, 0xa7, 0x72, 0x4e, 0xcd, 0xff, 0x0b, 0xb3, 0xae, + 0xbd, 0x37, 0x0e, 0x06, 0xbd, 0x53, 0x29, 0x12, 0x44, 0x73, 0xc9, 0x15, 0x25, 0xe1, 0x4e, 0xf6, + 0xe1, 0x74, 0x14, 0x62, 0xb1, 0x6a, 0xea, 0x46, 0x33, 0xa6, 0xe7, 0x0b, 0x66, 0xc1, 0xef, 0x69, + 0x7a, 0xbe, 0xe8, 0xa4, 0xbc, 0xfd, 0x0d, 0x28, 0x71, 0xad, 0x05, 0x15, 0x82, 0x8f, 0x15, 0x28, + 0xcf, 0xab, 0x2b, 0x55, 0x84, 0xd2, 0xa6, 0xf6, 0x3b, 0x31, 0x96, 0x5f, 0xda, 0xc6, 0x5e, 0xb0, + 0x91, 0x37, 0xa0, 0xc4, 0x02, 0x5d, 0x7a, 0x2f, 0x75, 0x5c, 0x93, 0x4f, 0x90, 0xeb, 0xff, 0xfc, + 0xf2, 0xb1, 0x2b, 0x2c, 0x2c, 0x66, 0x30, 0x7e, 0x29, 0x1d, 0x2d, 0xbe, 0xac, 0xb8, 0x72, 0x8e, + 0xca, 0x47, 0x0a, 0xec, 0xce, 0x6f, 0x24, 0xdd, 0x65, 0x7c, 0x7a, 0x36, 0x4f, 0xac, 0x95, 0x71, + 0x97, 0xc1, 0xf3, 0x7a, 0xc6, 0x5c, 0x39, 0x66, 0xa4, 0x99, 0xe2, 0x18, 0x4b, 0x6a, 0x2e, 0xb4, + 0x4a, 0x3a, 0x93, 0x60, 0xac, 0xfc, 0x4e, 0x85, 0x1d, 0x3a, 0x81, 0xfa, 0xe1, 0x78, 0xac, 0x4f, + 0x27, 0x77, 0xc2, 0x68, 0xc2, 0x8f, 0x54, 0xe4, 0x15, 0x58, 0xb9, 0x73, 0xb1, 0xdb, 0x40, 0xc6, + 0x4e, 0x08, 0xa0, 0x50, 0x16, 0xe6, 0x22, 0xf4, 0x37, 0xb9, 0x0e, 0x52, 0x28, 0x1b, 0x94, 0xa9, + 0xeb, 0xee, 0xda, 0x30, 0x0e, 0x68, 0xf3, 0x2a, 0x2c, 0xa3, 0xf6, 0xcf, 0x45, 0xa3, 0x38, 0xd2, + 0xce, 0xae, 0x19, 0xde, 0x0d, 0xb8, 0x2c, 0x03, 0x79, 0x0e, 0x20, 0xc1, 0x8c, 0xe3, 0xb2, 0x4f, + 0xa8, 0xd1, 0x31, 0x6c, 0x9c, 0xbb, 0x76, 0xf7, 0x76, 0x97, 0x03, 0xb1, 0x55, 0x61, 0x5b, 0x74, + 0xc9, 0x50, 0x78, 0xc5, 0xf3, 0x77, 0x98, 0x2d, 0x96, 0x60, 0x0e, 0xb9, 0x67, 0x7c, 0xe5, 0x1f, + 0x2a, 0xac, 0x1d, 0xd3, 0x83, 0x02, 0xaa, 0xbf, 0x8b, 0xd5, 0xe9, 0x17, 0xa1, 0xd4, 0x1a, 0x74, + 0xf9, 0xdd, 0xfd, 0x98, 0x03, 0x73, 0xa0, 0xc9, 0x6e, 0x7f, 0xd0, 0x15, 0xcf, 0x00, 0x63, 0x57, + 0x66, 0xfa, 0x06, 0x73, 0xe3, 0x37, 0x61, 0x85, 0xd9, 0x3d, 0xf0, 0x8b, 0x1a, 0x71, 0x54, 0x8c, + 0x6b, 0xf4, 0x2c, 0x4b, 0x96, 0xae, 0x9b, 0x99, 0xe5, 0x84, 0x7c, 0x6e, 0xe1, 0xb8, 0x1c, 0x92, + 0xb2, 0xbf, 0x7c, 0x3e, 0x65, 0x5f, 0xf2, 0x3f, 0x5e, 0x39, 0x8f, 0xff, 0xf1, 0xee, 0x4d, 0x28, + 0x49, 0xf5, 0xb9, 0xd0, 0xc9, 0xf1, 0xd7, 0x2a, 0x6c, 0x60, 0xab, 0xe2, 0xa7, 0xa4, 0xff, 0xcd, + 0xab, 0x8b, 0xd7, 0x52, 0x57, 0x17, 0x65, 0x79, 0xbc, 0x58, 0xcb, 0x16, 0xdc, 0x59, 0xbc, 0x09, + 0xdb, 0x39, 0x46, 0xf2, 0x32, 0x2c, 0xd3, 0xea, 0x0b, 0x55, 0x4f, 0xcb, 0xce, 0x80, 0x04, 0xab, + 0x86, 0x36, 0x7c, 0xec, 0x32, 0xee, 0xca, 0xbf, 0x14, 0x58, 0xe7, 0x20, 0x82, 0xd1, 0xed, 0xc1, + 0x37, 0x76, 0xe7, 0x8d, 0x6c, 0x77, 0x32, 0xe7, 0x19, 0xde, 0x9d, 0xff, 0xe9, 0x4e, 0xbc, 0x99, + 0xea, 0xc4, 0x2b, 0xb1, 0xe7, 0xba, 0x68, 0xce, 0x82, 0x3e, 0xfc, 0x13, 0x62, 0xb9, 0xa4, 0x19, + 0xc9, 0xcf, 0x61, 0xcd, 0x0a, 0xef, 0xa5, 0x34, 0xa6, 0x1b, 0x73, 0x0a, 0x7d, 0x36, 0x66, 0x64, + 0x6b, 0x0a, 0x37, 0x9b, 0x28, 0xbc, 0x17, 0xe4, 0x9e, 0x71, 0x92, 0x22, 0xa9, 0xd2, 0x94, 0xce, + 0x76, 0x91, 0xa9, 0xcf, 0x4d, 0x34, 0xd1, 0x1f, 0xec, 0x8f, 0x45, 0x80, 0xc4, 0xba, 0x8d, 0x2e, + 0xc0, 0x30, 0x05, 0xb5, 0xcb, 0xef, 0x8e, 0x91, 0x24, 0xcf, 0x71, 0x4e, 0x22, 0x37, 0xf8, 0xa5, + 0xa8, 0x3a, 0x1f, 0x59, 0x00, 0xaf, 0x47, 0x6b, 0xdc, 0x7a, 0xec, 0x34, 0xec, 0x77, 0x99, 0x2c, + 0x2e, 0xec, 0x3f, 0x81, 0x40, 0x32, 0x31, 0x75, 0x4e, 0x34, 0x18, 0xb4, 0x31, 0xab, 0x53, 0x86, + 0x9c, 0xc5, 0x68, 0xf1, 0xc1, 0x2d, 0x46, 0x97, 0x1f, 0xc0, 0x62, 0x74, 0xe5, 0x9c, 0x16, 0xa3, + 0x0e, 0xac, 0xf5, 0xa2, 0x0f, 0xc2, 0x68, 0x32, 0x18, 0xdd, 0x47, 0x7b, 0xb2, 0xe4, 0x2a, 0x8b, + 0x76, 0xb5, 0x29, 0xd2, 0xd8, 0x78, 0xe3, 0x86, 0x19, 0xf3, 0xcb, 0xc3, 0x1d, 0x13, 0xc9, 0x0f, + 0x20, 0x79, 0xf5, 0xe0, 0xc8, 0x9f, 0xf3, 0xf7, 0xd9, 0x13, 0xf1, 0x28, 0xf2, 0x13, 0x48, 0x3f, + 0x7e, 0x70, 0x7f, 0x0b, 0x16, 0xb9, 0x4c, 0x4e, 0x90, 0xc1, 0x34, 0x4e, 0xa4, 0xf7, 0x11, 0x6e, + 0x50, 0xf3, 0xb5, 0x0a, 0x24, 0x5f, 0x71, 0xf2, 0x1a, 0x94, 0x98, 0xe8, 0x0f, 0x46, 0xe3, 0xf7, + 0xb9, 0x99, 0x23, 0xf3, 0xf7, 0x93, 0xc8, 0xb2, 0xbf, 0x1f, 0x23, 0xbb, 0xe3, 0xf7, 0xfb, 0xe4, + 0x67, 0xf0, 0x08, 0x0e, 0xfc, 0x30, 0x1c, 0xf5, 0x06, 0xa7, 0x01, 0x22, 0xae, 0x74, 0xfb, 0x1c, + 0x53, 0xfe, 0x19, 0x0c, 0x7e, 0x92, 0x4f, 0x9e, 0x33, 0x41, 0xd0, 0x9a, 0xd0, 0x41, 0x4e, 0x87, + 0x31, 0x12, 0x1f, 0x34, 0x39, 0xff, 0xed, 0x69, 0xbf, 0xcf, 0xe7, 0x5c, 0x15, 0x43, 0x5f, 0x67, + 0xd2, 0xe6, 0x14, 0xbc, 0x99, 0x14, 0xdc, 0x98, 0xf6, 0xfb, 0xe4, 0x15, 0x80, 0x41, 0x14, 0xdc, + 0xed, 0x8d, 0xc7, 0xec, 0x21, 0x23, 0xb6, 0x04, 0x4e, 0xa8, 0xf2, 0xf0, 0x0d, 0xa2, 0x36, 0x23, + 0xd2, 0xe1, 0x1b, 0x76, 0xcf, 0x42, 0xf4, 0x9f, 0xc1, 0x99, 0xb7, 0xcc, 0x51, 0x22, 0x05, 0x31, + 0x3d, 0x8d, 0xce, 0x42, 0xaf, 0xf7, 0xa1, 0xb0, 0x66, 0x7a, 0x07, 0xb6, 0xb9, 0x21, 0xca, 0x71, + 0x6f, 0x72, 0x87, 0x9f, 0xbb, 0xbf, 0xcd, 0xa1, 0x5d, 0x3a, 0x78, 0xff, 0xb5, 0x08, 0xa0, 0x1f, + 0x7b, 0xc2, 0x35, 0xf5, 0x29, 0x58, 0xa6, 0xda, 0x84, 0xb8, 0x95, 0xc0, 0x3b, 0x5d, 0x2c, 0x57, + 0xbe, 0xd3, 0x45, 0x0e, 0x2a, 0x27, 0xdc, 0xf0, 0x0c, 0x2f, 0xc6, 0xd4, 0xe4, 0x0a, 0x63, 0xc4, + 0x48, 0xa9, 0xd3, 0x2b, 0x23, 0x91, 0x16, 0x40, 0xe2, 0x2c, 0xca, 0xf5, 0xdb, 0xed, 0xc4, 0xeb, + 0x8a, 0x27, 0x70, 0xf8, 0xbf, 0xc4, 0xe1, 0x54, 0x9e, 0x3e, 0x09, 0x1b, 0x39, 0x84, 0xa2, 0xdf, + 0x8d, 0xed, 0x5c, 0xe7, 0xb8, 0xd0, 0x3e, 0xce, 0x31, 0xff, 0x13, 0x37, 0xda, 0xcd, 0x49, 0x37, + 0x15, 0x1a, 0x05, 0x0b, 0x21, 0x06, 0xac, 0xf0, 0x78, 0x4e, 0x73, 0xf0, 0x14, 0x78, 0x38, 0x27, + 0x8e, 0xa2, 0x84, 0x44, 0xf9, 0xb4, 0xc3, 0x23, 0x37, 0xbd, 0x08, 0x05, 0xcf, 0x6b, 0x73, 0xc7, + 0x91, 0x8d, 0x44, 0x57, 0xf1, 0xbc, 0xb6, 0x08, 0x7f, 0x77, 0x57, 0xca, 0x46, 0x99, 0xc9, 0x8f, + 0xa0, 0x24, 0x1d, 0xc4, 0xb9, 0xcb, 0x15, 0xf6, 0x41, 0x2f, 0x21, 0xcb, 0xe2, 0x4c, 0xe2, 0x26, + 0x2d, 0xd0, 0x0e, 0xa7, 0xef, 0x85, 0xfa, 0x70, 0x88, 0x36, 0x9a, 0x1f, 0x84, 0x23, 0x06, 0x4d, + 0xb8, 0x9a, 0x00, 0x10, 0x05, 0xdd, 0xe1, 0x30, 0x38, 0x15, 0xa9, 0xf2, 0xcd, 0x4c, 0x36, 0x27, + 0x71, 0x60, 0xdb, 0x0b, 0x27, 0xd3, 0x21, 0x33, 0xc3, 0x68, 0x0c, 0x46, 0x54, 0x35, 0x61, 0x02, + 0x03, 0xb1, 0x5a, 0xc6, 0x34, 0x51, 0xd8, 0xbe, 0xdc, 0x1e, 0x8c, 0x32, 0x6a, 0x4a, 0x3e, 0x73, + 0x25, 0x94, 0x87, 0x9c, 0xee, 0xf7, 0x69, 0x85, 0x07, 0xf7, 0x7b, 0xa1, 0xf0, 0x24, 0x6a, 0xce, + 0x73, 0x33, 0x9c, 0x88, 0xf1, 0x19, 0x4d, 0x72, 0x22, 0x4e, 0xb9, 0x0e, 0x7f, 0x5a, 0x94, 0xc0, + 0x29, 0xf8, 0x58, 0xbc, 0x0e, 0xf0, 0xe6, 0xa0, 0x17, 0xb5, 0xc3, 0xc9, 0x9d, 0xc1, 0xa9, 0xe4, + 0xcb, 0x5c, 0xfa, 0xc5, 0xa0, 0x17, 0x05, 0x77, 0x91, 0xfc, 0xf5, 0x97, 0x8f, 0x49, 0x4c, 0xae, + 0xf4, 0x9b, 0x7c, 0x1f, 0xd6, 0xe8, 0x97, 0x9f, 0x18, 0x93, 0xb0, 0x0b, 0x4c, 0xcc, 0xcd, 0xc3, + 0x68, 0xc6, 0x0c, 0xe4, 0x26, 0xe2, 0x87, 0xf6, 0x86, 0x13, 0xe9, 0x58, 0x2d, 0xc0, 0x42, 0x7b, + 0xc3, 0x49, 0x16, 0x6f, 0x48, 0x62, 0x26, 0xcd, 0xb8, 0xea, 0x02, 0x81, 0x96, 0xc3, 0x94, 0xe2, + 0x2d, 0x1d, 0x9f, 0x6b, 0x81, 0x00, 0x3a, 0x91, 0x63, 0x85, 0x64, 0xb2, 0x61, 0x25, 0xbc, 0x66, + 0x9d, 0x3d, 0xab, 0xf0, 0xdd, 0x8d, 0x55, 0x62, 0x7c, 0xe7, 0x34, 0x38, 0x41, 0x72, 0xaa, 0x12, + 0x31, 0x33, 0xd9, 0x87, 0x2d, 0xe6, 0x71, 0x17, 0x23, 0xd9, 0xf3, 0x9d, 0x0e, 0x65, 0x5b, 0x02, + 0x75, 0x2f, 0xff, 0x7d, 0x26, 0x03, 0x69, 0xc0, 0x32, 0xaa, 0x96, 0xdc, 0xed, 0xe9, 0xaa, 0xac, + 0x53, 0x67, 0xd7, 0x11, 0xca, 0x15, 0xd4, 0xa6, 0x65, 0xb9, 0x82, 0xac, 0xe4, 0x6d, 0x00, 0x23, + 0x1a, 0x0d, 0xfa, 0x7d, 0x84, 0xe2, 0x59, 0x45, 0xc5, 0xec, 0x7a, 0x7a, 0x3d, 0x62, 0x29, 0x09, + 0x13, 0xf7, 0x30, 0xc7, 0xef, 0x20, 0x03, 0xd8, 0x23, 0x95, 0x55, 0x31, 0x61, 0x85, 0x2d, 0x46, + 0x84, 0xb5, 0xe2, 0x98, 0x99, 0x12, 0x28, 0x12, 0x83, 0xb5, 0xe2, 0xf4, 0x3c, 0xac, 0x95, 0x94, + 0xa1, 0x72, 0x08, 0x97, 0x67, 0x35, 0x2c, 0xa5, 0x0c, 0x2b, 0xe7, 0x55, 0x86, 0xff, 0x50, 0x80, + 0x75, 0x2c, 0x4d, 0x48, 0x61, 0x1d, 0x36, 0xbc, 0xe9, 0x7b, 0xb1, 0x7b, 0xa8, 0x90, 0xc6, 0x58, + 0xbf, 0xb1, 0x9c, 0x20, 0x3f, 0x78, 0xa5, 0x72, 0x10, 0x03, 0x36, 0xc5, 0x4e, 0x70, 0x20, 0x6c, + 0xdd, 0x62, 0x44, 0x29, 0x01, 0x5c, 0x90, 0x8f, 0xe4, 0x91, 0xc9, 0x94, 0xec, 0x07, 0x85, 0x8b, + 0xec, 0x07, 0xc5, 0x73, 0xed, 0x07, 0x3f, 0x85, 0x75, 0xf1, 0x6f, 0x28, 0xc9, 0x97, 0xbf, 0x9d, + 0x24, 0x4f, 0x15, 0x46, 0x5a, 0xb1, 0x44, 0x5f, 0x59, 0x28, 0xd1, 0xf1, 0x15, 0x51, 0xac, 0xb2, + 0x5c, 0x70, 0x3e, 0x5e, 0x06, 0x42, 0xdd, 0x1f, 0xd4, 0x9c, 0x07, 0xd8, 0x25, 0x5f, 0x86, 0xb5, + 0xd6, 0x40, 0x3c, 0x20, 0x49, 0x37, 0xf7, 0x7d, 0x41, 0x94, 0x8f, 0x0b, 0x31, 0x67, 0xbc, 0xbb, + 0x15, 0x1e, 0xc6, 0xee, 0x76, 0x13, 0x80, 0x1b, 0x51, 0x26, 0x10, 0xd5, 0xb8, 0x64, 0x84, 0xf7, + 0x4f, 0xfa, 0x01, 0x41, 0x62, 0xa6, 0xd2, 0x89, 0x9b, 0x9a, 0xe8, 0x27, 0x27, 0x83, 0x69, 0x34, + 0x49, 0xc5, 0x74, 0xe1, 0x8e, 0x80, 0x74, 0x4b, 0xc0, 0x34, 0x59, 0x3c, 0x64, 0xb2, 0x3d, 0xdc, + 0x01, 0x21, 0x6f, 0xc5, 0x36, 0x72, 0x0b, 0x43, 0x5c, 0x56, 0x72, 0x3d, 0x34, 0xd7, 0x32, 0xae, + 0xf2, 0xb9, 0x22, 0xc3, 0xf9, 0x3d, 0xc0, 0x50, 0xbf, 0x0a, 0x10, 0xbf, 0xe0, 0x8b, 0xb1, 0x66, + 0x9a, 0x5c, 0x4c, 0x95, 0x7b, 0x39, 0xe1, 0x95, 0x5a, 0x53, 0x78, 0x58, 0xad, 0xf1, 0xa1, 0x64, + 0xff, 0x72, 0xd2, 0x4d, 0x4c, 0x3e, 0xc0, 0x8b, 0x4f, 0xb2, 0x28, 0x99, 0x44, 0x28, 0xce, 0xe4, + 0x1c, 0x3c, 0x37, 0x14, 0x67, 0x9c, 0xb1, 0xf2, 0x16, 0x6c, 0xc9, 0x2e, 0x0a, 0xf7, 0xa3, 0x13, + 0xf2, 0x63, 0x86, 0x43, 0xa2, 0xa4, 0x74, 0x1c, 0x89, 0x89, 0x4a, 0xdc, 0xfb, 0xd1, 0x09, 0x3b, + 0xff, 0x74, 0xef, 0xc9, 0x75, 0x45, 0xed, 0xf3, 0x0b, 0x05, 0x48, 0x9e, 0x5d, 0x96, 0x26, 0xca, + 0x7f, 0xe1, 0x74, 0x99, 0x39, 0x95, 0x15, 0x2f, 0x72, 0x2a, 0xab, 0xfe, 0x56, 0x81, 0x2d, 0x53, + 0x6f, 0x73, 0xec, 0x3d, 0xf6, 0x12, 0xf1, 0xff, 0x70, 0xdd, 0xd4, 0xdb, 0x81, 0x63, 0xb7, 0xcc, + 0xda, 0xad, 0x60, 0x26, 0xa4, 0xce, 0x75, 0xf8, 0xbf, 0x3c, 0x4b, 0xf2, 0x62, 0x71, 0x0d, 0xca, + 0xf9, 0x64, 0x01, 0xbb, 0x33, 0x3b, 0xb3, 0x40, 0xe8, 0x29, 0x54, 0xdf, 0x80, 0x2d, 0x81, 0x46, + 0xe3, 0xb7, 0x3c, 0x04, 0xb1, 0xdb, 0x82, 0xd2, 0x91, 0xe1, 0x9a, 0x8d, 0x5b, 0x41, 0xa3, 0xd3, + 0x6a, 0x69, 0x4b, 0x64, 0x03, 0xd6, 0x38, 0xa1, 0xa6, 0x6b, 0x0a, 0x59, 0x87, 0x55, 0xd3, 0xf2, + 0x8c, 0x5a, 0xc7, 0x35, 0x34, 0xb5, 0xfa, 0x06, 0x6c, 0x3a, 0xa3, 0xde, 0x07, 0xdd, 0x49, 0x78, + 0x18, 0xde, 0xc7, 0x07, 0x87, 0x4b, 0x50, 0x70, 0xf5, 0x63, 0x6d, 0x89, 0x00, 0xac, 0x38, 0x87, + 0x35, 0xef, 0x85, 0x17, 0x34, 0x85, 0x94, 0xe0, 0xd2, 0x41, 0xcd, 0x09, 0x0e, 0xdb, 0x9e, 0xa6, + 0xd2, 0x0f, 0xfd, 0xd8, 0xc3, 0x8f, 0x42, 0xf5, 0x79, 0xd8, 0xc6, 0xb3, 0x42, 0xab, 0x37, 0x9e, + 0x84, 0x51, 0x38, 0xc2, 0x3a, 0xac, 0xc3, 0xaa, 0x17, 0xd2, 0x45, 0x3e, 0x09, 0x59, 0x05, 0xda, + 0xd3, 0xfe, 0xa4, 0x37, 0xec, 0x87, 0xbf, 0xd2, 0x94, 0xea, 0x4d, 0xd8, 0x72, 0x07, 0xd3, 0x49, + 0x2f, 0x3a, 0xf3, 0x26, 0x94, 0xe3, 0xec, 0x3e, 0x79, 0x14, 0xb6, 0x3b, 0x96, 0xde, 0xde, 0x37, + 0x0f, 0x3a, 0x76, 0xc7, 0x0b, 0xda, 0xba, 0x5f, 0x6b, 0xb2, 0xe7, 0x8e, 0xb6, 0xed, 0xf9, 0x81, + 0x6b, 0xd4, 0x0c, 0xcb, 0xd7, 0x94, 0xea, 0x6f, 0x14, 0xd8, 0xec, 0x8c, 0xb9, 0x89, 0x6e, 0x07, + 0x4d, 0xf8, 0x1f, 0x87, 0x6b, 0x1d, 0xcf, 0x70, 0x03, 0xdf, 0x3e, 0x34, 0xac, 0xa0, 0xe3, 0xe9, + 0x07, 0x59, 0x3c, 0xa7, 0xc7, 0xe0, 0xaa, 0xc4, 0xe1, 0x1a, 0x35, 0xfb, 0xc8, 0x70, 0x03, 0x47, + 0xf7, 0xbc, 0x63, 0xdb, 0xad, 0x6b, 0x0a, 0xd9, 0x85, 0x9d, 0x19, 0x0c, 0xed, 0x86, 0xae, 0xa9, + 0xb9, 0x34, 0xcb, 0x38, 0xd6, 0x5b, 0xc1, 0xbe, 0xed, 0x6b, 0x85, 0x6a, 0x9b, 0x6e, 0x74, 0x08, + 0x79, 0xc2, 0x00, 0x6b, 0x57, 0xa1, 0x68, 0xd9, 0x96, 0x91, 0x7d, 0x92, 0x5a, 0x87, 0x55, 0xdd, + 0x71, 0x5c, 0xfb, 0x08, 0x07, 0x14, 0x60, 0xa5, 0x6e, 0x58, 0xb4, 0x66, 0x05, 0x9a, 0xe2, 0xb8, + 0x76, 0xdb, 0xf6, 0x8d, 0xba, 0x56, 0xac, 0xba, 0x62, 0xc1, 0x88, 0x42, 0x4f, 0x06, 0xec, 0xfd, + 0xa7, 0x6e, 0x34, 0xf4, 0x4e, 0xcb, 0xe7, 0x1d, 0x72, 0x2b, 0x70, 0x8d, 0xb7, 0x3a, 0x86, 0xe7, + 0x7b, 0x9a, 0x42, 0x34, 0x58, 0xb7, 0x0c, 0xa3, 0xee, 0x05, 0xae, 0x71, 0x64, 0x1a, 0xc7, 0x9a, + 0x4a, 0xcb, 0x64, 0xbf, 0xe9, 0x3f, 0x54, 0x3f, 0x55, 0x80, 0x30, 0xb8, 0x18, 0x01, 0x2c, 0x8a, + 0xe3, 0xb3, 0x07, 0xbb, 0x4d, 0xda, 0xb1, 0xd8, 0xb4, 0xb6, 0x5d, 0xcf, 0x76, 0xd9, 0x0e, 0x90, + 0x4c, 0xba, 0xdd, 0x68, 0x68, 0x0a, 0xb9, 0x0a, 0x8f, 0x64, 0xe8, 0x75, 0xd7, 0x76, 0x34, 0x75, + 0x57, 0x5d, 0x55, 0xc8, 0x95, 0x5c, 0xe2, 0xa1, 0x61, 0x38, 0x5a, 0x81, 0x0e, 0x51, 0x26, 0x41, + 0x4c, 0x40, 0x96, 0xbd, 0x58, 0xfd, 0x48, 0x81, 0x1d, 0x56, 0x4d, 0x31, 0x9b, 0xe3, 0xaa, 0x5e, + 0x83, 0x32, 0x47, 0xb6, 0x9a, 0x55, 0xd1, 0xcb, 0xa0, 0xa5, 0x52, 0x59, 0x35, 0x1f, 0x85, 0xed, + 0x14, 0x15, 0xeb, 0xa1, 0xd2, 0xb5, 0x9a, 0x22, 0xef, 0x1b, 0x9e, 0x1f, 0x18, 0x8d, 0x86, 0xed, + 0xfa, 0xac, 0x22, 0x85, 0x6a, 0x05, 0xb6, 0x6b, 0xe1, 0x68, 0x42, 0x75, 0x90, 0x68, 0xdc, 0x1b, + 0x44, 0x58, 0x85, 0x0d, 0x58, 0x33, 0xde, 0xf6, 0x0d, 0xcb, 0x33, 0x6d, 0x4b, 0x5b, 0xaa, 0x5e, + 0xcb, 0xf0, 0x88, 0x55, 0xe3, 0x79, 0x4d, 0x6d, 0xa9, 0xda, 0x85, 0x0d, 0x61, 0x12, 0xcb, 0x66, + 0xc5, 0x1e, 0xec, 0x8a, 0xb9, 0x86, 0xeb, 0x37, 0xdb, 0x84, 0x32, 0x5c, 0xce, 0xa7, 0x1b, 0xbe, + 0xa6, 0xd0, 0x51, 0xc8, 0xa4, 0x50, 0xba, 0x5a, 0xfd, 0xbd, 0x02, 0x65, 0x1e, 0x4d, 0x8b, 0xbf, + 0x47, 0x30, 0x30, 0x4d, 0x04, 0xa6, 0xa9, 0xc2, 0x0d, 0xdf, 0xed, 0x78, 0xbe, 0x51, 0x0f, 0xea, + 0xc6, 0x91, 0x59, 0x33, 0x70, 0xba, 0x98, 0xae, 0xd1, 0x36, 0x2c, 0x3f, 0xf3, 0xd7, 0x4f, 0xc3, + 0x93, 0x0b, 0x78, 0x2d, 0xdb, 0x17, 0xdf, 0x74, 0x95, 0x3c, 0x09, 0xdf, 0x59, 0xc0, 0x1c, 0x33, + 0xaa, 0xd5, 0x77, 0x61, 0x3d, 0x05, 0x10, 0x7e, 0x05, 0x1e, 0x91, 0xbf, 0x9d, 0x30, 0x3a, 0xed, + 0x45, 0x67, 0xda, 0x52, 0x36, 0xc1, 0x9d, 0x46, 0x11, 0x4d, 0xc0, 0x05, 0x29, 0x27, 0xf8, 0xe1, + 0xe8, 0x6e, 0x2f, 0xea, 0x4e, 0xc2, 0x53, 0x4d, 0xad, 0x3e, 0x0b, 0x1b, 0x29, 0x04, 0x23, 0xda, + 0xf3, 0x2d, 0x9b, 0xcb, 0xab, 0xb6, 0x51, 0x37, 0x3b, 0x6d, 0x6d, 0x99, 0x2e, 0xc5, 0xa6, 0x79, + 0xd0, 0xd4, 0xa0, 0xfa, 0x89, 0x42, 0x4f, 0xcc, 0xd8, 0x3f, 0xed, 0x86, 0x2e, 0xc6, 0x8a, 0xce, + 0x13, 0x06, 0x76, 0x66, 0x78, 0x1e, 0x7b, 0x4a, 0xbd, 0x06, 0x65, 0xfe, 0x11, 0xe8, 0x56, 0x3d, + 0x68, 0xea, 0x6e, 0xfd, 0x58, 0x77, 0xe9, 0xe4, 0xb9, 0xa5, 0xa9, 0xb8, 0x22, 0x24, 0x4a, 0xe0, + 0xdb, 0x9d, 0x5a, 0x53, 0x2b, 0xd0, 0x09, 0x98, 0xa2, 0x3b, 0xa6, 0xa5, 0x15, 0x71, 0x7d, 0xe5, + 0xb8, 0xb1, 0x58, 0x9a, 0xbe, 0x5c, 0xed, 0x81, 0x96, 0x75, 0x5b, 0xca, 0xbd, 0x69, 0xbb, 0x1d, + 0xcb, 0x62, 0x02, 0x64, 0x0b, 0x4a, 0xb6, 0xdf, 0x34, 0x5c, 0x0e, 0x47, 0x87, 0xf8, 0x73, 0x1d, + 0x4b, 0xef, 0xf8, 0x4d, 0xdb, 0x35, 0xdf, 0x41, 0x49, 0x52, 0x86, 0xcb, 0x5e, 0x4b, 0xaf, 0x1d, + 0xe2, 0xa0, 0x99, 0x56, 0x50, 0x6b, 0xea, 0x96, 0x65, 0xb4, 0x34, 0xa8, 0xfe, 0x59, 0x81, 0xab, + 0x0b, 0xde, 0xbd, 0xc8, 0x33, 0xf0, 0x54, 0xd3, 0xd0, 0xeb, 0x2d, 0xc3, 0xf3, 0x02, 0x5a, 0xa4, + 0x61, 0xf9, 0xfc, 0x79, 0x79, 0xe6, 0x6c, 0x7d, 0x0a, 0xbe, 0xbb, 0x98, 0x3d, 0x91, 0x7b, 0xdf, + 0x83, 0x27, 0x16, 0xb3, 0x72, 0x39, 0xa8, 0xd2, 0x39, 0xbb, 0x98, 0x33, 0x96, 0x9f, 0x85, 0xea, + 0xc7, 0x0a, 0xec, 0xcc, 0x56, 0x17, 0x69, 0xdd, 0x4c, 0xcb, 0xf3, 0xf5, 0x56, 0x2b, 0x70, 0x74, + 0x57, 0x6f, 0x07, 0x86, 0xe5, 0xda, 0xad, 0xd6, 0x2c, 0xb9, 0xf1, 0x04, 0x3c, 0x3e, 0x9f, 0xd5, + 0xab, 0xb9, 0xa6, 0x43, 0x17, 0x60, 0x05, 0xf6, 0xe6, 0x73, 0x19, 0x66, 0xcd, 0xd0, 0xd4, 0xfd, + 0xd7, 0x3f, 0xfb, 0xfb, 0xde, 0xd2, 0x67, 0x5f, 0xed, 0x29, 0x5f, 0x7c, 0xb5, 0xa7, 0xfc, 0xed, + 0xab, 0x3d, 0xe5, 0x9d, 0xa7, 0x2f, 0x10, 0x88, 0xf2, 0xbd, 0x15, 0xb4, 0xa7, 0x78, 0xe9, 0xdf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xb0, 0xf8, 0xd2, 0x3d, 0x86, 0x01, 0x00, } func (this *PluginSpecV1) Equal(that interface{}) bool { @@ -35110,6 +35124,15 @@ func (m *SSOClientRedirectSettings) MarshalToSizedBuffer(dAtA []byte) (int, erro i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.InsecureAllowedCidrRanges) > 0 { + for iNdEx := len(m.InsecureAllowedCidrRanges) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.InsecureAllowedCidrRanges[iNdEx]) + copy(dAtA[i:], m.InsecureAllowedCidrRanges[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.InsecureAllowedCidrRanges[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } if len(m.AllowedHttpsHostnames) > 0 { for iNdEx := len(m.AllowedHttpsHostnames) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowedHttpsHostnames[iNdEx]) @@ -36091,6 +36114,15 @@ func (m *GithubAuthRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ClientUserAgent) > 0 { + i -= len(m.ClientUserAgent) + copy(dAtA[i:], m.ClientUserAgent) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ClientUserAgent))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } if len(m.ClientLoginIP) > 0 { i -= len(m.ClientLoginIP) copy(dAtA[i:], m.ClientLoginIP) @@ -50036,6 +50068,12 @@ func (m *SSOClientRedirectSettings) Size() (n int) { n += 1 + l + sovTypes(uint64(l)) } } + if len(m.InsecureAllowedCidrRanges) > 0 { + for _, s := range m.InsecureAllowedCidrRanges { + l = len(s) + n += 1 + l + sovTypes(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -50544,6 +50582,10 @@ func (m *GithubAuthRequest) Size() (n int) { if l > 0 { n += 2 + l + sovTypes(uint64(l)) } + l = len(m.ClientUserAgent) + if l > 0 { + n += 2 + l + sovTypes(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -93291,6 +93333,38 @@ func (m *SSOClientRedirectSettings) Unmarshal(dAtA []byte) error { } m.AllowedHttpsHostnames = append(m.AllowedHttpsHostnames, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InsecureAllowedCidrRanges", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InsecureAllowedCidrRanges = append(m.InsecureAllowedCidrRanges, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -96841,6 +96915,38 @@ func (m *GithubAuthRequest) Unmarshal(dAtA []byte) error { } m.ClientLoginIP = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ClientUserAgent", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ClientUserAgent = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/api/version.go b/api/version.go index dbdfbfb47adb7..7b4f3de93291a 100644 --- a/api/version.go +++ b/api/version.go @@ -3,6 +3,6 @@ package api import "github.com/coreos/go-semver/semver" -const Version = "16.1.0" +const Version = "16.1.4" var SemVersion = semver.New(Version) diff --git a/buf-gogo.gen.yaml b/buf-gogo.gen.yaml index be4708733309e..65a70e364414d 100644 --- a/buf-gogo.gen.yaml +++ b/buf-gogo.gen.yaml @@ -2,4 +2,10 @@ version: v1 plugins: - name: gogofast out: ./gogogen - opt: plugins=grpc + opt: + - Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types + - Mgoogle/protobuf/duration.proto=github.com/gogo/protobuf/types + - Mgoogle/protobuf/struct.proto=github.com/gogo/protobuf/types + - Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types + - Mgoogle/protobuf/wrappers.proto=github.com/gogo/protobuf/types + - plugins=grpc diff --git a/build.assets/macos/tsh/tsh.app/Contents/Info.plist b/build.assets/macos/tsh/tsh.app/Contents/Info.plist index 2b7afbd72fde2..583b41de33c03 100644 --- a/build.assets/macos/tsh/tsh.app/Contents/Info.plist +++ b/build.assets/macos/tsh/tsh.app/Contents/Info.plist @@ -19,13 +19,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 16.1.0 + 16.1.4 CFBundleSupportedPlatforms MacOSX CFBundleVersion - 16.1.0 + 16.1.4 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild diff --git a/build.assets/macos/tshdev/tsh.app/Contents/Info.plist b/build.assets/macos/tshdev/tsh.app/Contents/Info.plist index 9959b89a2abe1..455951cc0e1ad 100644 --- a/build.assets/macos/tshdev/tsh.app/Contents/Info.plist +++ b/build.assets/macos/tshdev/tsh.app/Contents/Info.plist @@ -17,13 +17,13 @@ CFBundlePackageType APPL CFBundleShortVersionString - 16.1.0 + 16.1.4 CFBundleSupportedPlatforms MacOSX CFBundleVersion - 16.1.0 + 16.1.4 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild diff --git a/build.assets/tooling/go.mod b/build.assets/tooling/go.mod index 9fd458855809e..a87982eff201a 100644 --- a/build.assets/tooling/go.mod +++ b/build.assets/tooling/go.mod @@ -1,8 +1,6 @@ module github.com/gravitational/teleport/build.assets/tooling -go 1.22.0 - -toolchain go1.22.5 +go 1.22.6 require ( github.com/Masterminds/sprig/v3 v3.2.3 diff --git a/build.assets/versions.mk b/build.assets/versions.mk index 97ed484afcb20..b009717daa1a8 100644 --- a/build.assets/versions.mk +++ b/build.assets/versions.mk @@ -3,7 +3,7 @@ # Keep versions in sync with devbox.json, when applicable. # Sync with devbox.json. -GOLANG_VERSION ?= go1.22.5 +GOLANG_VERSION ?= go1.22.6 GOLANGCI_LINT_VERSION ?= v1.59.1 NODE_VERSION ?= 20.14.0 @@ -17,7 +17,7 @@ LIBPCSCLITE_VERSION ?= 1.9.9-teleport DEVTOOLSET ?= devtoolset-12 # Protogen related versions. -BUF_VERSION ?= v1.35.1 +BUF_VERSION ?= v1.36.0 # Keep in sync with api/proto/buf.yaml (and buf.lock). GOGO_PROTO_TAG ?= v1.3.2 NODE_GRPC_TOOLS_VERSION ?= 1.12.4 diff --git a/docs/config.json b/docs/config.json index 908e9ef4eb148..c8ac333cea077 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1614,17 +1614,18 @@ "teleport": { "git": "api/14.0.0-gd1e081e", "major_version": "16", - "version": "16.1.0", + "version": "16.1.4", "url": "teleport.example.com", "golang": "1.22", "plugin": { - "version": "16.1.0" + "version": "16.1.4" }, "helm_repo_url": "https://charts.releases.teleport.dev", - "latest_oss_docker_image": "public.ecr.aws/gravitational/teleport-distroless:16.1.0", - "latest_oss_debug_docker_image": "public.ecr.aws/gravitational/teleport-distroless-debug:16.1.0", - "latest_ent_docker_image": "public.ecr.aws/gravitational/teleport-ent-distroless:16.1.0", - "latest_ent_debug_docker_image": "public.ecr.aws/gravitational/teleport-ent-distroless-debug:16.1.0" + "latest_oss_docker_image": "public.ecr.aws/gravitational/teleport-distroless:16.1.4", + "latest_oss_debug_docker_image": "public.ecr.aws/gravitational/teleport-distroless-debug:16.1.4", + "latest_ent_docker_image": "public.ecr.aws/gravitational/teleport-ent-distroless:16.1.4", + "latest_ent_debug_docker_image": "public.ecr.aws/gravitational/teleport-ent-distroless-debug:16.1.4", + "teleport_install_script_url": "https://cdn.teleport.dev/install-v16.1.4.sh" }, "terraform": { "version": "1.0.0" @@ -2821,6 +2822,11 @@ "destination": "/deploy-a-cluster/linux-demo/", "permanent": true }, + { + "source": "/getting-started/", + "destination": "/deploy-a-cluster/linux-demo/", + "permanent": true + }, { "source": "/database-access/guides/snowflake/", "destination": "/enroll-resources/database-access/enroll-managed-databases/snowflake/", @@ -2955,6 +2961,11 @@ "source": "/user-manual/", "destination": "/", "permanent": true + }, + { + "source": "/architecture/overview/", + "destination": "/architecture/introduction/", + "permanent": true } ] } diff --git a/docs/cspell.json b/docs/cspell.json index 34e99df55ff2e..9d5fb1b66b94c 100644 --- a/docs/cspell.json +++ b/docs/cspell.json @@ -192,6 +192,7 @@ "SECURITYADMIN", "SIEM", "SIGINT", + "SIGUSR", "SLAVEOF", "SLES", "SLOWLOG", @@ -958,6 +959,7 @@ "winadj", "windowsaccountname", "windowsdesktop", + "winpty", "winscp", "winserver", "workgroups", @@ -984,5 +986,7 @@ "flagWords": [ "hte" ], - "ignorePaths": ["**/reference/terraform-provider/**"] -} + "ignorePaths": [ + "**/reference/terraform-provider/**" + ] +} \ No newline at end of file diff --git a/docs/img/use-teleport/vnet-starting@2x.png b/docs/img/use-teleport/vnet-starting@2x.png index 2d59067e99fe4..67e321dfc6a1c 100644 Binary files a/docs/img/use-teleport/vnet-starting@2x.png and b/docs/img/use-teleport/vnet-starting@2x.png differ diff --git a/docs/pages/access-controls/access-request-plugins/ssh-approval-pagerduty.mdx b/docs/pages/access-controls/access-request-plugins/ssh-approval-pagerduty.mdx index cbd8dbaf83db7..135755d1026dc 100644 --- a/docs/pages/access-controls/access-request-plugins/ssh-approval-pagerduty.mdx +++ b/docs/pages/access-controls/access-request-plugins/ssh-approval-pagerduty.mdx @@ -56,7 +56,7 @@ Access Request Notifications` service when certain users create an Access Request. For users on the on-call team for `My Critical Service` (in this case, your -PagerDuty user), we will configure the PagerDuy plugin to approve Access +PagerDuty user), we will configure the PagerDuty plugin to approve Access Requests automatically, letting them investigate incidents on the service quickly. diff --git a/docs/pages/access-controls/device-trust/device-management.mdx b/docs/pages/access-controls/device-trust/device-management.mdx index 583dc122c71bf..34a249103701a 100644 --- a/docs/pages/access-controls/device-trust/device-management.mdx +++ b/docs/pages/access-controls/device-trust/device-management.mdx @@ -144,6 +144,11 @@ integration, like the [Jamf Pro integration](./jamf-integration.mdx). - Auto-enrollment must be enabled in the cluster setting. - User must have either preset `editor` or `device-enroll` (available v13.3.6+) role assigned to them. + + Since Teleport v16.1.1 users don't need the device/enroll permission to + benefit from auto-enrollment. + + Enable auto-enrollment in your cluster settings: @@ -179,9 +184,8 @@ After saving the changes, restart the Teleport service. -Once enabled, user's with their device registered in Teleport and with the required permission -(preset `editor` or `device-enroll` role) will have their device enrolled to Teleport in -their next login. +Once enabled, users with their device registered in Teleport will have their +device enrolled to Teleport in their next login. ```code $ tsh logout diff --git a/docs/pages/access-controls/getting-started.mdx b/docs/pages/access-controls/getting-started.mdx index 33cb5224b410b..0bc74d3710db5 100644 --- a/docs/pages/access-controls/getting-started.mdx +++ b/docs/pages/access-controls/getting-started.mdx @@ -20,18 +20,9 @@ wrap up with creating your own role. ## Step 1/3. Add local users with preset roles -Teleport provides several preset roles: `editor`, `auditor`, and `access`. +Teleport provides several preset roles: -- The `editor` role authorizes users to modify cluster configuration. -- The `auditor` role authorizes users to view audit logs. -- The `access` role authorizes users to access cluster resources. - -
-Teleport Enterprise contains two additional preset roles: `reviewer` and `requester`. - -- The `reviewer` role authorizes users to review Access Requests. -- The `requester` role authorizes users to request resources. -
+(!docs/pages/includes/preset-roles-table.mdx!) diff --git a/docs/pages/access-controls/guides/locking.mdx b/docs/pages/access-controls/guides/locking.mdx index 02d67087d10d6..cf2cd01c65eec 100644 --- a/docs/pages/access-controls/guides/locking.mdx +++ b/docs/pages/access-controls/guides/locking.mdx @@ -8,7 +8,7 @@ prevent access during cluster maintenance—by placing a lock on a session, user or host identity. Teleport will reject new API requests and terminate active -connections to SSH, database, desktop, and Kubernetes sessions +connections to SSH, application, database, desktop, and Kubernetes sessions matching the lock's target. A lock can target the following objects or attributes: diff --git a/docs/pages/access-controls/guides/passwordless.mdx b/docs/pages/access-controls/guides/passwordless.mdx index 3affe077ea202..73904b3dc249a 100644 --- a/docs/pages/access-controls/guides/passwordless.mdx +++ b/docs/pages/access-controls/guides/passwordless.mdx @@ -19,8 +19,8 @@ usernameless authentication for Teleport. - A web browser with WebAuthn support. To see if your browser supports WebAuthn, check the [WebAuthn Compatibility](https://developers.yubico.com/WebAuthn/WebAuthn_Browser_Support/) page. -- A signed and notarized version of `tsh` is required for Touch ID. This precludes - versions installed from Homebrew. [Download the macOS tsh installer](../../installation.mdx#macos). +- A signed and notarized version of `tsh` is required for Touch ID. This means versions + installed from Homebrew or compiled from source will not work. [Download the macOS tsh installer](../../installation.mdx#macos). - (!docs/pages/includes/tctl.mdx!) A Teleport cluster capable of WebAuthn is automatically capable of passwordless. diff --git a/docs/pages/access-controls/guides/webauthn.mdx b/docs/pages/access-controls/guides/webauthn.mdx index 66316faaf0ef0..46c9114fc9b64 100644 --- a/docs/pages/access-controls/guides/webauthn.mdx +++ b/docs/pages/access-controls/guides/webauthn.mdx @@ -387,6 +387,11 @@ integration, like the [Jamf Pro integration](../device-trust/jamf-integration.md - Auto-enrollment must be enabled in the cluster setting. - User must have either preset `editor` or `device-enroll` (available v13.3.6+) role assigned to them. + + Since Teleport v16.1.1 users don't need the device/enroll permission to + benefit from auto-enrollment. + + ### Step 1/2. Enable auto-enrollment in your cluster settings Modify the dynamic config resource using `tctl edit cluster_auth_preference`: @@ -405,9 +410,8 @@ spec: ### Step 2/2. Log out and back in -Once enabled, user's with their device registered in Teleport and with the required permission -(preset `editor` or `device-enroll` role) will have their device enrolled to Teleport in -their next login. +Once enabled, users with their device registered in Teleport will have their +device enrolled to Teleport in their next login. ```code $ tsh logout diff --git a/docs/pages/access-controls/idps/saml-reference.mdx b/docs/pages/access-controls/idps/saml-reference.mdx index c6a629cf9ce7b..207e51f0d8acc 100644 --- a/docs/pages/access-controls/idps/saml-reference.mdx +++ b/docs/pages/access-controls/idps/saml-reference.mdx @@ -138,11 +138,6 @@ version: v2 This will disable access to the SAML identity provider for all users regardless of their role level permissions. -## Notes - -The SAML identity provider supports [HSM](../../choose-an-edition/teleport-enterprise/hsm.mdx). -in 12.2.5 and later. - ## Troubleshooting ### `Bad Request` when logging into an external application diff --git a/docs/pages/access-controls/reference.mdx b/docs/pages/access-controls/reference.mdx index ccdc012592432..68432fd468ff9 100644 --- a/docs/pages/access-controls/reference.mdx +++ b/docs/pages/access-controls/reference.mdx @@ -74,15 +74,9 @@ user: ## Preset roles -Teleport provides several pre-defined roles out-of-the-box: - -| Role | Description | -| --- | --- | -| `editor` | Allows editing of cluster configuration settings. | -| `auditor`| Allows reading cluster events, audit logs, and playing back session records. | -| `access`| Allows access to cluster resources. | -| `requester`| Enterprise-only role that allows a user to create Access Requests. | -| `reviewer`| Enterprise-only role that allows review of Access Requests. | +Teleport provides several preset roles: + +(!docs/pages/includes/preset-roles-table.mdx!) ### Role versions diff --git a/docs/pages/access-controls/sso.mdx b/docs/pages/access-controls/sso.mdx index 1eb2efea3546e..1c3a89ac235c1 100644 --- a/docs/pages/access-controls/sso.mdx +++ b/docs/pages/access-controls/sso.mdx @@ -197,6 +197,35 @@ authentication succeeds, Teleport will retrieve SSH and X.509 certificates and store them in the `~/.tsh/keys/` directory. The tool will also will add SSH cert to an SSH agent if there's one running. +### Changing Callback Address + +The callback address can be changed if calling back to a remote machine +instead of the local machine is required: + +```code +# --bind-addr sets the host and port tsh will listen on, and --callback changes +# what link is displayed to the user +$ tsh login --proxy=proxy.example.com --auth=github --bind-addr=localhost:1234 --callback https://remote.machine:1234 +``` + +For this to work the hostname or CIDR of the remote machine that will be used for +the callback will need to be allowed via`spec.client_redirect_settings`: + +```code +spec: + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' +``` + ## Configuring SSO Teleport works with SSO providers by relying on the concept of an diff --git a/docs/pages/access-controls/sso/one-login.mdx b/docs/pages/access-controls/sso/one-login.mdx index dc18423316adc..71ad9a6070eca 100644 --- a/docs/pages/access-controls/sso/one-login.mdx +++ b/docs/pages/access-controls/sso/one-login.mdx @@ -25,69 +25,76 @@ to define policies like: ## Step 1/3. Create Teleport application in OneLogin -In the OneLogin control panel's main menu navigate to **Applications** -> -**Add App**. Using the search box, select "SAML Custom Connector (SP Shibboleth)": +1. In the OneLogin control panel's main menu navigate to **Applications** -> + **Add App**. Using the search box, select "SAML Custom Connector (SP + Shibboleth)": -![SAML Custom Connector (SP Shibboleth)](../../../img/sso/onelogin/onelogin-saml-1.png) + ![SAML Custom Connector (SP Shibboleth)](../../../img/sso/onelogin/onelogin-saml-1.png) -Define the new application: +1. Define the new application: -![SAML Config](../../../img/sso/onelogin/onelogin-saml-1a.png) + ![SAML Config](../../../img/sso/onelogin/onelogin-saml-1a.png) -You can find Teleport icons to upload from the following links: + You can find Teleport icons to upload from the following links: -- [Square Icon](../../../img/sso/onelogin/teleport.png) -- [Rectangular Icon](../../../img/sso/onelogin/teleportlogo@2x.png) + - [Square Icon](../../../img/sso/onelogin/teleport.png) + - [Rectangular Icon](../../../img/sso/onelogin/teleportlogo@2x.png) -From the application's **Configuration** page, set the following values: +1. From the application's **Configuration** page, set the following values: - -Set -here with your Teleport Proxy Service address and port, or Teleport Enterprise -Cloud tenant (e.g. `company.teleport.sh:443`) to fill out the values below. - + + Set + here with your Teleport Proxy Service address and port, or Teleport Enterprise + Cloud tenant (e.g. `company.teleport.sh:443`) to fill out the values below. + + + - **Login URL**: + - `https://``/web/login` + - **ACS (Consumer) URL**, **SAML Recipient**, **ACS (Consumer) URL Validator**, & **Audience**: + - `https://``/v1/webapi/saml/acs/onelogin` -- **Login URL**: - - `https://``/web/login` -- **ACS (Consumer) URL**, **SAML Recipient**, **ACS (Consumer) URL Validator**, & **Audience**: - - `https://``/v1/webapi/saml/acs/onelogin` + ![Configure SAML](../../../img/sso/onelogin/onelogin-saml-2.png) -![Configure SAML](../../../img/sso/onelogin/onelogin-saml-2.png) +1. Teleport needs to assign groups to users. From the **Parameters** page, + configure the application with some parameters exposed as SAML attribute + statements: -Teleport needs to assign groups to users. From the **Parameters** page, configure -the application with some parameters exposed as SAML attribute statements: + ![New Field](../../../img/sso/onelogin/onelogin-saml-3.png) + + ![New Field Group](../../../img/sso/onelogin/onelogin-saml-4.png) + + + Make sure to check `Include in SAML assertion` checkbox. + -![New Field](../../../img/sso/onelogin/onelogin-saml-3.png) +1. Add users to the application: -![New Field Group](../../../img/sso/onelogin/onelogin-saml-4.png) + ![Add User](../../../img/sso/onelogin/onelogin-saml-5.png) - - Make sure to check `Include in SAML assertion` checkbox. - +1. Obtain SAML metadata for your authentication connector. Once the application + is set up, navigate to the the **More Actions** menu and find the **SAML + Metadata** option: -Add users to the application: + ![Download XML](../../../img/sso/onelogin/saml-download.png) -![Add User](../../../img/sso/onelogin/onelogin-saml-5.png) - -### Download SAML XML metadata - -Once the application is set up, download `SAML Metadata` from the -**More Actions** menu: - -![Download XML](../../../img/sso/onelogin/saml-download.png) + You can either left-click the option and download the XML document as a local + file or right-click the option and copy the link address. The Teleport Auth + Service either reads the provided document or queries the address to obtain + SAML metadata. We recommend copying the address so the Auth Service can use + the most up-to-date information. ## Step 2/3. Create a SAML connector -Create a SAML connector using `tctl`. Update - with the path to the XML metadata -file downloaded in the previous step: +Create a SAML connector using `tctl`. Update to the URL +of the XML document that you copied in the previous step. If you downloaded the +XML document instead, use the path to the XML metadata file: ```code $ tctl sso configure saml --preset onelogin \ ---entity-descriptor \ +--entity-descriptor \ --attributes-to-roles groups,admin,editor \ --attributes-to-roles groups,dev,access > onelogin.yaml ``` diff --git a/docs/pages/access-controls/teleport-policy/policy-integrations.mdx b/docs/pages/access-controls/teleport-policy/policy-integrations.mdx index b8ff579c55cae..007f2d1a02fda 100644 --- a/docs/pages/access-controls/teleport-policy/policy-integrations.mdx +++ b/docs/pages/access-controls/teleport-policy/policy-integrations.mdx @@ -67,7 +67,8 @@ spec: The preset `editor` role has the required permissions by default. -Teleport can also import and grant access to resources from an Okta organizations, such as user profiles, groups and applications. You can view connection data in Access Graph. Follow the steps here to add an (../../enroll-resources/application-access/okta/hosted-guide.mdx) in your cluster. +Teleport can also import and grant access to resources from Okta organizations, such as user profiles, groups and applications. You can view connection data in Access Graph. Follow the steps here to add an [Okta +integration](../../enroll-resources/application-access/okta/hosted-guide.mdx) in your cluster. ## Next steps - Explore [connections and resource paths](./policy-connections.mdx) with Teleport Policy. diff --git a/docs/pages/choose-an-edition/migrate-to-cloud.mdx b/docs/pages/choose-an-edition/migrate-to-cloud.mdx index 7af5cabcd6988..e2c4068cba9da 100644 --- a/docs/pages/choose-an-edition/migrate-to-cloud.mdx +++ b/docs/pages/choose-an-edition/migrate-to-cloud.mdx @@ -318,7 +318,7 @@ your new Teleport cluster, ensure that the setup is complete. List all registered Windows desktops: ```code - $ tctl get windows_desktop + $ tctl desktop ls ``` 1. Ensure that end users have the expected SSO access to your infrastructure. diff --git a/docs/pages/choose-an-edition/teleport-enterprise/gcp-kms.mdx b/docs/pages/choose-an-edition/teleport-enterprise/gcp-kms.mdx index 2727c7aa75e86..665e16ef31a56 100644 --- a/docs/pages/choose-an-edition/teleport-enterprise/gcp-kms.mdx +++ b/docs/pages/choose-an-edition/teleport-enterprise/gcp-kms.mdx @@ -211,7 +211,7 @@ auth_service: # ... ca_key_params: gcp_kms: - keyring: "projects//locations//keyRing/" + keyring: "projects//locations//keyRings/" protection_level: "SOFTWARE" ``` diff --git a/docs/pages/connect-your-client/teleport-connect.mdx b/docs/pages/connect-your-client/teleport-connect.mdx index 30c974cf86495..72f2f8ad058c0 100644 --- a/docs/pages/connect-your-client/teleport-connect.mdx +++ b/docs/pages/connect-your-client/teleport-connect.mdx @@ -446,11 +446,16 @@ Below is the list of the supported config properties. | `theme` | `system` | Color theme for the app. Available modes: `light`, `dark`, `system`. | | `terminal.fontFamily` | `Menlo, Monaco, monospace` on macOS
`Consolas, monospace` on Windows
`'Droid Sans Mono', monospace` on Linux | Font family for the terminal. | | `terminal.fontSize` | 15 | Font size for the terminal. | +| `terminal.windowsBackend` | `auto` | `auto` uses modern [ConPTY](https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/) system if available, which requires Windows 10 (19H1) or above. Set to `winpty` to use winpty even if ConPTY is available. | +| `terminal.rightClick` | `menu` on macOS/Linux
`copyPaste` on Windows | `paste` pastes clipboard content, `copyPaste` copies if text is selected, otherwise pastes, `menu` shows context menu. | +| `terminal.copyOnSelect` | false | Automatically copies selected text to the clipboard. | | `usageReporting.enabled` | `false` | Enables collecting anonymous usage data (see [Telemetry](#telemetry)). | | `keymap.tab1` - `keymap.tab9` | `Command+1` - `Command+9` on macOS
`Ctrl+1` - `Ctrl+9` on Windows
`Alt+1` - `Alt+9` on Linux | Shortcut to open tab 1–9. | | `keymap.closeTab` | `Command+W` on macOS
`Ctrl+Shift+W` on Windows/Linux | Shortcut to close a tab. | | `keymap.newTab` | `Command+T` on macOS
`Ctrl+Shift+T` on Windows/Linux | Shortcut to open a new tab. | | `keymap.newTerminalTab` | `` Control+Shift+` `` on macOS
`` Ctrl+Shift+` `` on Windows/Linux | Shortcut to open a new terminal tab. | +| `keymap.terminalCopy` | `Command+C` on macOS
`Ctrl+Shift+C` on Windows/Linux | Shortcut to copy text in the terminal. | +| `keymap.terminalPaste` | `Command+V` on macOS
`Ctrl+Shift+V` on Windows/Linux | Shortcut to paste text in the terminal. | | `keymap.previousTab` | `Control+Shift+Tab` on macOS
`Ctrl+Shift+Tab` on Windows/Linux | Shortcut to go to the previous tab. | | `keymap.nextTab` | `Control+Tab` on macOS
`Ctrl+Tab` on Windows/Linux | Shortcut to go to the next tab. | | `keymap.openConnections` | `Command+P` on macOS
`Ctrl+Shift+P` on Windows/Linux | Shortcut to open the connection list. | @@ -458,6 +463,7 @@ Below is the list of the supported config properties. | `keymap.openProfiles` | `Command+I` on macOS
`Ctrl+Shift+I` on Windows/Linux | Shortcut to open the profile selector. | | `keymap.openSearchBar` | `Command+K` on macOS
`Ctrl+Shift+K` on Windows/Linux | Shortcut to open the search bar. | | `headless.skipConfirm` | false | Skips the confirmation prompt for Headless WebAuthn approval and instead prompts for WebAuthn immediately. | +| `ssh.noResume` | false | Disables SSH connection resumption. | General > Login Items and look for +tsh.app under "Allow in the Background". ![VNet starting up](../../img/use-teleport/vnet-starting@2x.png) diff --git a/docs/pages/deploy-a-cluster/linux-demo.mdx b/docs/pages/deploy-a-cluster/linux-demo.mdx index 2632218545855..4e3c751d5a9e8 100644 --- a/docs/pages/deploy-a-cluster/linux-demo.mdx +++ b/docs/pages/deploy-a-cluster/linux-demo.mdx @@ -88,7 +88,7 @@ set up records for: On your Linux host, run the following command to install the Teleport binary: ```code -$ curl https://goteleport.com/static/install.sh | bash -s (=teleport.version=) +$ curl (=teleport.teleport_install_script_url=) | bash -s (=teleport.version=) ``` ### Configure Teleport diff --git a/docs/pages/enroll-resources/application-access/cloud-apis/aws-console.mdx b/docs/pages/enroll-resources/application-access/cloud-apis/aws-console.mdx index 2fed857f5a061..2416b5b611964 100644 --- a/docs/pages/enroll-resources/application-access/cloud-apis/aws-console.mdx +++ b/docs/pages/enroll-resources/application-access/cloud-apis/aws-console.mdx @@ -77,95 +77,7 @@ You will create the following resources: |`AssumeRole`|IAM policy|Allows the Application Service to assume other roles in order to proxy user requests to AWS.| |`TeleportAWSAccess` (for EC2 deployments) |EC2 instance profile|Associates the `TeleportAWSAccess` role with your EC2 instance.| -### Configure a role for Teleport users to request - -In this section, you will create a role that Teleport users can request access -to when making requests to AWS APIs. The Teleport Application Service assumes -this role when proxying requests: - -1. Obtain AWS credentials for the account where you will run the Teleport - Application Service and make them available to your terminal shell. - -1. Create a trust policy document, which authorizes an entity to assume the role - you want to protect access to. To do so, create a file called - `ro-access.json` with the following content, replacing with the ID of the AWS account where you will - run the Teleport Application Service: - - ```json - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam:::role/TeleportAWSAccess" - }, - "Action": "sts:AssumeRole" - } - ] - } - ``` - - In the setup we show in this guide, the Teleport Application Service assumes - the `TeleportAWSAccess` role, then uses that role to assume the - `ExampleReadOnlyAccess` role. With the trust policy above, AWS authorizes - this operation. (We will create the `TeleportAWSAccess` role later in this - guide.) - -
- - If you are configuring the Application Service to proxy access to IAM roles - in another AWS account, we recommend checking the external ID of the AWS - account where the Application Service runs. Add the external ID to the trust - policy as follows, assigning to the external ID: - - ```json - { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam:::role/TeleportAWSAccess" - }, - "Action": "sts:AssumeRole", - "Condition": { - "StringEquals": { - "sts:ExternalId": "" - } - } - } - ] - } - ``` - - See the [AWS - documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) - for details on external IDs. -
- -1. Run the following commands to create the `ExampleReadOnlyAccess` role: - - ```code - $ aws iam create-role --role-name "ExampleReadOnlyAccess" \ - --assume-role-policy-document file://ro-access.json - ``` - -1. Get the ARN of the AWS-managed `ReadOnlyAccess` policy so you can attach it - to your role: - - ```code - $ ARN=$(aws iam list-policies --output text --query "Policies[?PolicyName=='ReadOnlyAccess'].Arn") - ``` - -1. Attach the `ReadOnlyAccess` policy to the role: - - ```code - $ aws iam attach-role-policy --role-name ExampleReadOnlyAccess --policy-arn $ARN - ``` - -### Give the Teleport Application Service permissions to assume other roles +### Create a role for the Teleport Application Service In this section, you will create an IAM role that allows the Teleport Application Service to assume other IAM roles in order to proxy user traffic to @@ -243,9 +155,7 @@ AWS APIs.
-1. Create a role for the Teleport Application Service (this is the - `TeleportAWSAccess` role we authorized earlier to access the - `ExampleReadOnlyAccess` role): +1. Create a role for the Teleport Application Service: ```code $ aws iam create-role --role-name "TeleportAWSAccess" \ @@ -280,6 +190,93 @@ AWS APIs. --policy-arn ${POLICY_ARN} ``` +### Configure a role for Teleport users to request + +In this section, you will create a role that Teleport users can request access +to when making requests to AWS APIs. The Teleport Application Service assumes +this role when proxying requests: + +1. Obtain AWS credentials for the account where you will run the Teleport + Application Service and make them available to your terminal shell. + +1. Create a trust policy document, which authorizes an entity to assume the role + you want to protect access to. To do so, create a file called + `ro-access.json` with the following content, replacing with the ID of the AWS account where you will + run the Teleport Application Service: + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::role/TeleportAWSAccess" + }, + "Action": "sts:AssumeRole" + } + ] + } + ``` + + In the setup we show in this guide, the Teleport Application Service assumes + the `TeleportAWSAccess` role, then uses that role to assume the + `ExampleReadOnlyAccess` role. With the trust policy above, AWS authorizes + this operation. + +
+ + If you are configuring the Application Service to proxy access to IAM roles + in another AWS account, we recommend checking the external ID of the AWS + account where the Application Service runs. Add the external ID to the trust + policy as follows, assigning to the external ID: + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::role/TeleportAWSAccess" + }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "" + } + } + } + ] + } + ``` + + See the [AWS + documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html) + for details on external IDs. +
+ +1. Run the following commands to create the `ExampleReadOnlyAccess` role: + + ```code + $ aws iam create-role --role-name "ExampleReadOnlyAccess" \ + --assume-role-policy-document file://ro-access.json + ``` + +1. Get the ARN of the AWS-managed `ReadOnlyAccess` policy so you can attach it + to your role: + + ```code + $ ARN=$(aws iam list-policies --output text --query "Policies[?PolicyName=='ReadOnlyAccess'].Arn") + ``` + +1. Attach the `ReadOnlyAccess` policy to the role: + + ```code + $ aws iam attach-role-policy --role-name ExampleReadOnlyAccess --policy-arn $ARN + ``` + ### Associate a role with the Teleport Application Service Now that you have created a role for the Teleport Application Service, associate diff --git a/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx b/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx index 9670c961a4408..0f546f1ebdddc 100644 --- a/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx +++ b/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx @@ -2,31 +2,13 @@ title: Web Application Access description: In this getting started guide, learn how to connect an application to your Teleport cluster by running the Teleport Application Service. --- +## Prerequisites -Download the latest version of Teleport for your platform from the [downloads page](https://goteleport.com/download) -and follow the installation [instructions](../../../installation.mdx). +(!docs/pages/includes/edition-prereqs-tabs.mdx!) -## Start Auth/Proxy service - -Create a configuration file for a Teleport service that will be running -the Auth and Proxy Services: - -```yaml -teleport: - data_dir: /var/lib/teleport -auth_service: - enabled: "yes" -proxy_service: - enabled: "yes" - # Set public address proxy will be reachable at. - public_addr: teleport.example.com:3080 -ssh_service: - enabled: "no" -``` - -(!docs/pages/includes/permission-warning.mdx!) - -(!docs/pages/includes/start-teleport.mdx!) +- (!docs/pages/includes/tctl.mdx!) +- Web application to connect to such as Grafana. +- Host where you will run the Teleport Application Service. ### Generate a token @@ -36,8 +18,6 @@ in `/tmp/token`: ```code # Log in to your cluster with tsh so you can use tctl from your local machine. -# You can also run tctl on your Auth Service host without running "tsh login" -# first. $ tsh login --user= --proxy= $ tctl tokens add \ --type=app \ @@ -70,7 +50,7 @@ A Teleport user needs their role's permission to access an application. Teleport comes with a built-in `access` role that grants access to all apps: ```code -$ tctl --config=/path/to/teleport.yaml users add --roles=access appuser +$ tctl users add --roles=access appuser ``` ## Start the Application Service with CLI flags diff --git a/docs/pages/enroll-resources/desktop-access/active-directory.mdx b/docs/pages/enroll-resources/desktop-access/active-directory.mdx index b4496fafdad34..9f092ef4e89da 100644 --- a/docs/pages/enroll-resources/desktop-access/active-directory.mdx +++ b/docs/pages/enroll-resources/desktop-access/active-directory.mdx @@ -2,6 +2,7 @@ title: Configure access for Active Directory manually description: Explains how to manually connect Teleport to an Active Directory domain. videoBanner: YvMqgcq0MTQ +tocDepth: 3 --- This guide demonstrates how to connect an Active Directory domain and how to log diff --git a/docs/pages/enroll-resources/desktop-access/getting-started.mdx b/docs/pages/enroll-resources/desktop-access/getting-started.mdx index 9aeee4468fdbf..040bb796e51f9 100644 --- a/docs/pages/enroll-resources/desktop-access/getting-started.mdx +++ b/docs/pages/enroll-resources/desktop-access/getting-started.mdx @@ -285,6 +285,10 @@ Windows login to use for the connection. To view the recording, select **Management** in the Teleport Web UI, then click **Session Recordings** in the Activity section. +## Uninstall + +(!docs/pages/includes/uninstall-windows-auth.mdx!) + ## Next steps For more general information about how to create, assign, and update roles, see [Access Controls diff --git a/docs/pages/enroll-resources/machine-id/access-guides/applications.mdx b/docs/pages/enroll-resources/machine-id/access-guides/applications.mdx index ca514e3c7c007..edffac5e66dfa 100644 --- a/docs/pages/enroll-resources/machine-id/access-guides/applications.mdx +++ b/docs/pages/enroll-resources/machine-id/access-guides/applications.mdx @@ -56,16 +56,53 @@ with the name of the role you just created: $ tctl bots update example --add-roles example-role ``` -## Step 2/3. Configure an application `tbot` output +## Step 2/3. Configure `tbot` + +There are two implementation options available when using `tbot` to grant +a client access to an application. The option you choose will depend on your +specific needs. + +The first option is the `application-tunnel` service. This operates a local +proxy that your client can connect to. The service will automatically attach +the credentials to the connection, meaning that the client does not need to +support client certificates. However, this does mean that the `tbot` process +must be running for the client to access the application. + +The second option is the `application` output. This will write TLS credentials +to a destination where your client will read them from. The client must support +client certificates and reloading them from disk when they are renewed. In +addition, this option is not compatible with a TLS-terminating load-balancer +between the client and the Teleport Proxy service. Unlike the +`application-tunnel`, the `tbot` process does not need to be running for the +client to access the application - this can be ideal for CI/CD pipelines. + +If you aren't sure which to use, we recommend starting with the +`application-tunnel` service as this is compatible with more clients. + + + +To configure the `application-tunnel` service, first determine where you want +the listener to bind to. As any client that can connect to the service listener +will be able to access the application, it is recommended to bind to the +loopback interface (e.g `127.0.0.1`) as this will prevent access from other +hosts. + +Modify your `tbot` configuration to add an `application-tunnel` service: -Now, `tbot` needs to be configured with an output to produce the -credentials needed to access applications in your infrastructure. To do this, the `application` output -type is used. +```yaml +services: +- type: application-tunnel + app_name: dumper + listen: tcp://127.0.0.1:1234 +``` -The application you want the credentials to have access to must be specified -using the `app_name` field. In this example, the debug application (`dumper`) -will be used. +Replace: +- `dumper` with the name of the application you registered in Teleport. +- `listen` with the address and port you wish the service to bind to. +Restart `tbot` to apply the new configuration. + + Outputs must be configured with a destination. In this example, the `directory` destination will be used. This will write artifacts to a specified directory on disk. Ensure that this directory can be written to by the Linux user that @@ -93,9 +130,23 @@ Teleport. If operating `tbot` as a background service, restart it. If running `tbot` in one-shot mode, it must be executed before you attempt to use the credentials. + + ## Step 3/3. Connect to your web application with the Machine ID identity + + +Once the `application-tunnel` service has been configured, you can connect to +the application using the listen address you specified. + +For example, to access the application using `curl`: + +```code +$ curl http://127.0.0.1:1234/ +``` + + Once `tbot` has been run, credentials will be output to the directory specified in the destination. Using the example of `/opt/machine-id`: @@ -113,9 +164,9 @@ For example, to access the application using `curl`: ```code $ curl \ - --cert /opt/machine-id/tlscert \ - --key /opt/machine-id/key \ - https://dumper.example.teleport.sh/ +--cert /opt/machine-id/tlscert \ +--key /opt/machine-id/key \ +https://dumper.example.teleport.sh/ ``` No CA certificate needs to be specified so long as your Teleport Proxy is @@ -124,31 +175,8 @@ certificate authority. Note that if the certificates are invalid or otherwise misconfigured, clients will be redirected to the Teleport login page when attempting to access the app. - -### Authenticated tunnel - -For cases where the client you wish to use to connect to the application does not -support client certificates, it is possible to open an authenticated tunnel. -This will listen on a local port and automatically attach the credentials, -meaning that the client itself does not need to support them. - -To open an authenticated tunnel to the `dumper` application on port 1234, run: - -```code -$ tbot proxy --destination-dir=/opt/machine-id --proxy=example.teleport.sh:443 app --port=1234 dumper -``` - -Whilst this command is running, you can connect to the app at -`http://localhost:1234`: - -```code -$ curl http://localhost:1234/ -``` - -The tunnel listens only on the loopback interface, meaning that this port -cannot be used from other hosts. Care should still be taken though, as any -process running on that host will be able to connect to the application without -authentication through this port. + + ## Troubleshooting diff --git a/docs/pages/enroll-resources/machine-id/faq.mdx b/docs/pages/enroll-resources/machine-id/faq.mdx index 48b6099956cb8..49d2ae61b5390 100644 --- a/docs/pages/enroll-resources/machine-id/faq.mdx +++ b/docs/pages/enroll-resources/machine-id/faq.mdx @@ -69,4 +69,22 @@ credentials produced by Machine ID from being used to connect to resources. As a work-around, configure Device Trust enforcement on a role-by-role basis and ensure that it is not required for roles that you will impersonate using -Machine ID. \ No newline at end of file +Machine ID. + +## Can Machine ID be used to generate long-lived certificates? + +Machine ID cannot currently be used to generate certificates valid for longer +than 24 hours, and requests for longer certificates using the `certificate_ttl` +parameter will be reduced to this 24 hour limit. + +This limit serves multiple purposes. For one, it encourages security best +practices by only ever issuing very short lived certificates. Additionally, as +Machine ID allows for certificate renewal, this limit helps to prevent further +exploitation should a Machine ID identity be compromised: an attacker could use +a stolen renewable certificate to request very long lived certificates and +maintain access for a much longer period. + +If your use case absolutely requires long-lived certificates, +[`tctl auth sign`](../../reference/cli/tctl.mdx#tctl-auth-sign) can +alternatively be used, however this loses the security benefits of Machine ID's +short-lived renewable certificates. diff --git a/docs/pages/enroll-resources/machine-id/reference/configuration.mdx b/docs/pages/enroll-resources/machine-id/reference/configuration.mdx index 3ba11f0878b01..54a5e15b780db 100644 --- a/docs/pages/enroll-resources/machine-id/reference/configuration.mdx +++ b/docs/pages/enroll-resources/machine-id/reference/configuration.mdx @@ -49,6 +49,7 @@ proxy_server: "teleport.example.com:443" # or "example.teleport.sh:443" for Tele # certificate_ttl specifies how long certificates generated by `tbot` should # live for. It should be a positive, numeric value with an `m` (for minutes) or # `h` (for hours) suffix. By default, this value is `1h`. +# This has a maximum value of `24h`. certificate_ttl: "1h" # renewal_interval specifies how often `tbot` should aim to renew the @@ -90,6 +91,7 @@ onboarding: # - `ec2` # - `kubernetes` # - `spacelift` + # - `tpm` join_method: "token" # ca_pins are used to validate the identity of the Teleport Auth Service on @@ -451,6 +453,34 @@ database: postgres username: postgres ``` +#### `application-tunnel` + +The `application-tunnel` service opens a listener that tunnels connections to +an application in Teleport. It supports both HTTP and TCP applications. This is +useful for applications which cannot be configured to use client certificates, +when using TCP application or where using a L7 load-balancer in front of your +Teleport proxies. + +The tunnel authenticates connections for the client, meaning that any +client that connects to the listener will be able to access the application. +For this reason, ensure that the listener is only accessible by the intended +clients by using the Unix socket listener or binding to `127.0.0.1`. + +```yaml +# type specifies the type of the service. For the application tunnel service, +# this will always be `application-tunnel`. +type: application-tunnel +# listen specifies the address that the service should listen on. +# +# Two types of listener are supported: +# - TCP: `tcp://
:` +# - Unix socket: `unix:///` +listen: tcp://127.0.0.1:8084 +# app_name is the name of the application, as configured in Teleport, that +# the service should open a tunnel to. +app_name: my-application +``` + #### `ssh-multiplexer` The `ssh-multiplexer` service opens a listener for a high-performance local @@ -675,7 +705,7 @@ appropriate. #### `directory` The `directory` destination type stores artifacts as files in a specified -directory. +directory. ```yaml # type specifies the type of the destination. For the directory destination, diff --git a/docs/pages/enroll-resources/machine-id/workload-identity/getting-started.mdx b/docs/pages/enroll-resources/machine-id/workload-identity/getting-started.mdx index 0a409b33b2d59..1d24e185471b5 100644 --- a/docs/pages/enroll-resources/machine-id/workload-identity/getting-started.mdx +++ b/docs/pages/enroll-resources/machine-id/workload-identity/getting-started.mdx @@ -45,7 +45,7 @@ Create a new file named `spiffe-issuer-role.yaml`: kind: role version: v6 metadata: - name: svid-issuer + name: spiffe-issuer spec: allow: spiffe: @@ -202,4 +202,4 @@ Workload Identity. - [Best Practices](./best-practices.mdx): Best practices for using Workload Identity in Production. - Read the [configuration reference](../reference/configuration.mdx) to explore -all the available configuration options. \ No newline at end of file +all the available configuration options. diff --git a/docs/pages/enroll-resources/server-access/getting-started.mdx b/docs/pages/enroll-resources/server-access/getting-started.mdx index 576e6dab49a85..dc8e08c29e774 100644 --- a/docs/pages/enroll-resources/server-access/getting-started.mdx +++ b/docs/pages/enroll-resources/server-access/getting-started.mdx @@ -67,25 +67,11 @@ that a user intends to access. On your local workstation, create a join token so you can add the server to your Teleport cluster: - - - -```code -Let's save the token to a file -$ tctl tokens add --type=node --format=text > token.file -``` - - - - ```code Let's save the token to a file $ tctl tokens add --type=node --format=text > token.file ``` - - - `--type=node` specifies that the Teleport process will act and join as an SSH server. diff --git a/docs/pages/enroll-resources/server-access/guides/ansible.mdx b/docs/pages/enroll-resources/server-access/guides/ansible.mdx index 8a1b8bc203058..0d3d239fd4ba5 100644 --- a/docs/pages/enroll-resources/server-access/guides/ansible.mdx +++ b/docs/pages/enroll-resources/server-access/guides/ansible.mdx @@ -43,6 +43,8 @@ Create a folder `ansible` where we will collect all generated files: ```code $ mkdir -p ansible +# Copy the openssh configuration from the previous step to the ansible dir +$ cp ssh.cfg ansible/ $ cd ansible ``` diff --git a/docs/pages/includes/device-trust/prereqs.mdx b/docs/pages/includes/device-trust/prereqs.mdx index 3eab789b4cdf9..046cfd9fbcc1d 100644 --- a/docs/pages/includes/device-trust/prereqs.mdx +++ b/docs/pages/includes/device-trust/prereqs.mdx @@ -1,5 +1,5 @@ - To enroll a macOS device, you need: - - A signed and notarized `tsh` binary, v12.0.0 or newer. + - A signed and notarized `tsh` binary. [Download the macOS tsh installer](../../installation.mdx#macos). - To enroll a Windows device, you need: - A device with TPM 2.0. diff --git a/docs/pages/includes/diagnostics/teleport-debug-config.mdx b/docs/pages/includes/diagnostics/teleport-debug-config.mdx index 44e470774fb10..18d6bf50ba472 100644 --- a/docs/pages/includes/diagnostics/teleport-debug-config.mdx +++ b/docs/pages/includes/diagnostics/teleport-debug-config.mdx @@ -1,6 +1,6 @@ If your Teleport configuration is not placed on the default path -(`/var/lib/teleport`), you must to specify its location to the CLI command +(`/etc/teleport.yaml`), you must specify its location to the CLI command using the `-c/--config` flag. diff --git a/docs/pages/includes/install-linux-oss.mdx b/docs/pages/includes/install-linux-oss.mdx index a14d4c32c61be..d63d205e9cc28 100644 --- a/docs/pages/includes/install-linux-oss.mdx +++ b/docs/pages/includes/install-linux-oss.mdx @@ -2,6 +2,6 @@ The following command updates the repository for the package manager on the local operating system and installs the provided Teleport version: ```code -$ curl https://goteleport.com/static/install.sh | bash -s (=teleport.version=) +$ curl (=teleport.teleport_install_script_url=) | bash -s (=teleport.version=) ``` diff --git a/docs/pages/includes/install-linux.mdx b/docs/pages/includes/install-linux.mdx index 28a1b1804a4e5..e7091bb737b52 100644 --- a/docs/pages/includes/install-linux.mdx +++ b/docs/pages/includes/install-linux.mdx @@ -28,7 +28,7 @@ Install Teleport on your Linux server: 1. Install Teleport on your Linux server: ```code - $ curl https://goteleport.com/static/install.sh | bash -s ${TELEPORT_VERSION} + $ curl (=teleport.teleport_install_script_url=) | bash -s ${TELEPORT_VERSION} ``` The installation script detects the package manager on your Linux server and diff --git a/docs/pages/includes/install-tsh.mdx b/docs/pages/includes/install-tsh.mdx index b77a95bf4346b..39eb755811923 100644 --- a/docs/pages/includes/install-tsh.mdx +++ b/docs/pages/includes/install-tsh.mdx @@ -9,18 +9,13 @@ - ```code - $ brew install teleport - ``` - - - The Teleport package in Homebrew is not maintained by Teleport and we can't - guarantee its reliability or security. We recommend the use of our [own Teleport packages](https://goteleport.com/download?os=mac). + + Using Homebrew to install Teleport is not supported. The Teleport package in + Homebrew is not maintained by Teleport and we can't guarantee its reliability or + security. - If you choose to use Homebrew, you must verify that the versions of `tsh` and - `tctl` are compatible with the versions you run server-side. Homebrew usually - ships the latest release of Teleport, which may be incompatible with older - versions. See our [compatibility policy](../upgrading/overview.mdx) for details. + We recommend the use of our [own Teleport packages](https://goteleport.com/download?os=mac) + for any installations on macOS. diff --git a/docs/pages/includes/preset-roles-table.mdx b/docs/pages/includes/preset-roles-table.mdx new file mode 100644 index 0000000000000..5d757ff8e2e00 --- /dev/null +++ b/docs/pages/includes/preset-roles-table.mdx @@ -0,0 +1,13 @@ +| Role | Description | +| --- | --- | +| `access`| Allows access to cluster resources. | +| `editor` | Allows editing of cluster configuration settings. | +| `auditor`| Allows reading cluster events, audit logs, and playing back session records. | +| `requester`| Enterprise-only role that allows a user to create Access Requests. | +| `reviewer`| Enterprise-only role that allows review of Access Requests. | +| `group-access`| Allows access to all user groups. | +| `device-admin`| Used to manage trusted devices. | +| `device-enroll`| Used to grant device enrollment powers to users. | +| `require-trusted-device`| Requires trusted device access to resources. | +| `terraform-provider`| Allows the Teleport Terraform provider to configure all of its supported Teleport resources. | + diff --git a/docs/pages/includes/role-spec.mdx b/docs/pages/includes/role-spec.mdx index dd672ff19a0cd..f743f2bbbb7d3 100644 --- a/docs/pages/includes/role-spec.mdx +++ b/docs/pages/includes/role-spec.mdx @@ -3,6 +3,7 @@ kind: role version: v7 metadata: name: example + description: This is an example role. spec: # options specify connection, in case if user has multiple non-default # conflicting options, teleport chooses the least permissive value. diff --git a/docs/pages/includes/tctl.mdx b/docs/pages/includes/tctl.mdx index 3944936f36935..87915700bd659 100644 --- a/docs/pages/includes/tctl.mdx +++ b/docs/pages/includes/tctl.mdx @@ -1,6 +1,5 @@ To check that you can connect to your Teleport cluster, sign in with `tsh login`, then verify that you can run `tctl` commands using your current credentials. -`tctl` is supported on macOS and Linux machines. For example: diff --git a/docs/pages/includes/uninstall-windows-auth.mdx b/docs/pages/includes/uninstall-windows-auth.mdx new file mode 100644 index 0000000000000..76e1ed1d8cf2e --- /dev/null +++ b/docs/pages/includes/uninstall-windows-auth.mdx @@ -0,0 +1,8 @@ +If you are using Teleport's Windows auth package to provide passwordless logins for local users, +you can remove it by running the setup program from an administrative command prompt: + +``` +> teleport-windows-auth-setup.exe uninstall +``` + +A reboot is necessary after the uninstall completes in order to fully remove the package. diff --git a/docs/pages/installation.mdx b/docs/pages/installation.mdx index 4b851ef016523..7abefdf5850fb 100644 --- a/docs/pages/installation.mdx +++ b/docs/pages/installation.mdx @@ -34,7 +34,7 @@ running Teleport on UNIX variants other than Linux \[1]. | - | - | - | - | - | - | | Linux v2.6.23+ (RHEL/CentOS 7+, Amazon Linux 2+, Amazon Linux 2023+, Ubuntu 16.04+, Debian 9+, SLES 12 SP 5+, and SLES 15 SP 5+) \[3] | yes | yes | yes | yes | yes | | macOS v10.15+ (Catalina)| yes | yes | yes | yes | yes | -| Windows 10+ (rev. 1607) \[4] | no | no | yes | yes | no | +| Windows 10+ (rev. 1607) \[4] | no | yes | yes | yes | no | \[1] *Teleport is written in Go and many of these system requirements are due to the requirements of the [Go toolchain](https://github.com/golang/go/wiki/MinimumRequirements)*. @@ -126,7 +126,7 @@ Download and run the installation script on the server where you want to install Teleport: ```code -$ curl https://goteleport.com/static/install.sh | bash -s ${TELEPORT_VERSION?} ${TELEPORT_EDITION?} +$ curl (=teleport.teleport_install_script_url=) | bash -s ${TELEPORT_VERSION?} ${TELEPORT_EDITION?} ``` ### Package repositories @@ -757,7 +757,7 @@ chart. |Chart|Included Services|Values Reference| |-|-|-| |`teleport-cluster`|Auth Service
Proxy Service
Other Teleport services if using a custom configuration|[Reference](reference/helm-reference/teleport-cluster.mdx) -|`teleport-kube-agent`|Kubernetes Service
Application Service
Database Service|[Reference](reference/helm-reference/teleport-kube-agent.mdx)| +|`teleport-kube-agent`|Kubernetes Service
Application Service
Database Service
Discovery Service
Jamf Service|[Reference](reference/helm-reference/teleport-kube-agent.mdx)| ## macOS diff --git a/docs/pages/management/admin/uninstall-teleport.mdx b/docs/pages/management/admin/uninstall-teleport.mdx index 52531ec9ff59c..7e810d9b613ee 100644 --- a/docs/pages/management/admin/uninstall-teleport.mdx +++ b/docs/pages/management/admin/uninstall-teleport.mdx @@ -152,7 +152,6 @@ Follow the instructions for your Linux distribution: - ### macOS @@ -180,13 +179,16 @@ Follow the instructions for your Linux distribution: ### Windows - Remove the `tsh.exe` binary from the machine: + Remove the `tsh.exe` and `tctl.exe` binaries from the machine: ```code $ del C:\Path\To\tsh.exe + $ del C:\Path\To\tctl.exe ``` (!docs/pages/includes/uninstall-teleport-connect-windows.mdx!) +(!docs/pages/includes/uninstall-windows-auth.mdx!) + ## Step 3/3. Remove Teleport data and configuration files diff --git a/docs/pages/management/diagnostics.mdx b/docs/pages/management/diagnostics.mdx index a708bde9818e4..f1ecb5095ab76 100644 --- a/docs/pages/management/diagnostics.mdx +++ b/docs/pages/management/diagnostics.mdx @@ -1,10 +1,286 @@ --- title: Monitoring your Cluster description: Monitoring your Teleport deployment -layout: tocless-doc --- -- [Health Monitoring](./diagnostics/monitoring.mdx): How to monitor the health of a Teleport instance. -- [Metrics](./diagnostics/metrics.mdx): How to enable exporting Prometheus metrics. -- [Collecting Profiles](./diagnostics/profiles.mdx): How to collect runtime profiling data from a Teleport instance. -- [Distributed Tracing](./diagnostics/tracing.mdx): How to enable distributed tracing for a Teleport instance. \ No newline at end of file +Teleport provides health checking mechanisms in order to verify that it is healthy and ready to serve traffic. +Metrics, tracing, and profiling provide in-depth data, tracking cluster performance and responsiveness. + +## Enable health monitoring + +How to monitor the health of a Teleport instance. + +(!docs/pages/includes/diagnostics/diag-addr-prereqs-tabs.mdx!) + +Now you can collect monitoring information from several endpoints. These can be used by things like +Kubernetes probes to monitor the health of a Teleport process. + +## `/healthz` + +The `http://127.0.0.1:3000/healthz` endpoint responds with a body of +`{"status":"ok"}` and an HTTP 200 OK status code if the process is running. + +This is a check to determine if the Teleport process is still running. + +## `/readyz` + +The `http://127.0.0.1:3000/readyz` endpoint is similar to `/healthz`, but its +response includes information about the state of the process. + +The response body is a JSON object of the form: + +``` +{ "status": "a status message here"} +``` + +### `/readyz` and heartbeats + +If a Teleport component fails to execute its heartbeat procedure, it will enter +a degraded state. Teleport will begin recovering from this state when a +heartbeat completes successfully. + +The first successful heartbeat will transition Teleport into a recovering state. A second consecutive +successful heartbeat will cause Teleport to transition to the OK state. + +Teleport heartbeats run approximately every 60 seconds when healthy, and failed +heartbeats are retried approximately every 5 seconds. This means that depending +on the timing of heartbeats, it can take 60-70 seconds after connectivity is +restored for `/readyz` to start reporting healthy again. + +### Status codes + +The status code of the response can be one of: + +- HTTP 200 OK: Teleport is operating normally +- HTTP 503 Service Unavailable: Teleport has encountered a connection error and + is running in a degraded state. This happens when a Teleport heartbeat fails. +- HTTP 400 Bad Request: Teleport is either entering its initial startup phase or + has begun recovering from a degraded state. + +The same state information is also available via the `process_state` metric +under the `/metrics` endpoint. + +## Metrics + +Teleport exposes metrics for all of its components, helping you get insight +into the state of your cluster. This guide explains the metrics that you can +collect from your Teleport cluster. + +## Enabling metrics + +(!docs/pages/includes/diagnostics/diag-addr-prereqs-tabs.mdx!) + +This will enable the `http://127.0.0.1:3000/metrics` endpoint, which serves the +metrics that Teleport tracks. It is compatible with [Prometheus](https://prometheus.io/) collectors. + +The following metrics are available: + + + + Teleport Enterprise (cloud-hosted) does not expose monitoring endpoints for the Auth Service and Proxy Service. + + + +(!docs/pages/includes/metrics.mdx!) + + +## Distributed tracing + +How to enable distributed tracing for a Teleport instance. + +Teleport leverages [OpenTelemetry](https://opentelemetry.io/) to generate traces +and export them to any [OpenTelemetry Protocol (OTLP)](https://opentelemetry.io/docs/reference/specification/protocol/otlp/) +capable exporter. In the event that your telemetry backend doesn't support receiving OTLP traces, you may be able to +leverage the [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) to proxy traces from OTLP +to a format that your telemetry backend accepts. + +## Configure Teleport + +In order to enable tracing for a `teleport` instance, add the following section to that instance's configuration file (`/etc/teleport.yaml`). +For a detailed description of these configuration fields, see the [configuration reference](../reference/config.mdx) page. + +```yaml +tracing_service: + enabled: yes + exporter_url: grpc://collector.example.com:4317 + sampling_rate_per_million: 1000000 +``` + +### Sampling rate + +It is important to choose the sampling rate wisely. Sampling at a rate of 100% could have a negative impact on the +performance of your cluster. Teleport honors the sampling rate included in any incoming requests, which means +that even when the `tracing_service` is enabled and the sampling rate is 0, if Teleport receives a request that has a span which is +sampled, then Teleport will sample and export all spans that are generated in response to that request. + +### Exporter URL + +The `exporter_url` setting indicates where Teleport should send spans to. Supported schemes are `grpc://`, `http://`, +`https://`, and `file://` (if no scheme is provided, then `grpc://` is used). + +When using `file://`, the url must be a path to a directory that Teleport has write permissions for. Spans will be saved to files within +the provided directory, each file containing one proto encoded span per line. Files are rotated after exceeding 100MB, in order to +override the default limit add `?limit=` to the `exporter_url` (i.e. `file:///var/lib/teleport/traces?limit=100`). + +By default the connection to the exporter is insecure, to support TLS add the following to the `tracing_service` configuration: + +```yaml + # Optional path to CA certificates are used to validate the exporter. + ca_certs: + - /var/lib/teleport/exporter_ca.pem + # Optional path tp TLS certificates are used to enable mTLS for the exporter + https_keypairs: + - key_file: /var/lib/teleport/exporter_key.pem + cert_file: /var/lib/teleport/exporter_cert.pem +```` + +After updating `teleport.yaml`, start your `teleport` instance to apply the new configuration. + +## tsh + +To capture traces from `tsh` add the `--trace` flag to your command. All traces generated by `tsh --trace` will be +proxied to the `exporter_url` defined for the Auth Service of the cluster the command is being run on. + +```code +$ tsh --trace ssh root@myserver +$ tsh --trace ls +``` + +Exporting traces from `tsh` to a different exporter than the one defined in the Auth Service config +is also possible via the `--trace-exporter` flag. A URL must be provided that adheres to the same +format as the `exporter_url` of the `tracing_service`. + +```code +$ tsh --trace --trace-exporter=grpc://collector.example.com:4317 ssh root@myserver +$ tsh --trace --trace-exporter=file:///var/lib/teleport/traces ls +``` + +## Collecting profiles + +How to collect runtime profiling data from a Teleport instance. + +Teleport leverages Go's diagnostic capabilities to collect and export +profiling data. Profiles can help identify the cause of spikes in CPU, +the source of memory leaks, or the reason for a deadlock. + +## Using the Debug Service + +The Teleport Debug Service enables administrators to collect diagnostic profiles +without enabling pprof endpoints at startup. The service, enabled by default, +ensures local-only access and must be consumed from inside the same instance. + +`teleport debug profile` collects a list of pprof profiles. It outputs a +compressed tarball (`.tar.gz`) to STDOUT. You decompress it using `tar` or +direct the result to a file. + +By default, it collects `goroutine`, `heap` and `profile` profiles. + +Each profile collected will have a correspondent file inside the tarball. For +example, collecting `goroutine,trace,heap` will result in `goroutine.pprof`, +`trace.pprof`, and `heap.pprof` files. + +```code +# Collect default profiles and save to a file. +$ teleport debug profile > pprof.tar.gz +$ tar xvf pprof.tar.gz + +# Collect default profiles and decompress it. +$ teleport debug profile | tar xzv -C ./ + +# Collect "trace" and "mutex" profiles and save to a file. +$ teleport debug profile trace,mutex > pprof.tar.gz + +# Collect profiles setting the profiling time in seconds +$ teleport debug profile -s 20 trace > pprof.tar.gz +``` + +(!docs/pages/includes/diagnostics/teleport-debug-config.mdx!) + +If you're running Teleport on a Kubernetes cluster you can directly collect +profiles to a local directory without an interactive session: + +```code +$ kubectl -n teleport exec my-pod -- teleport debug profile > pprof.tar.gz +``` + +After extracting the contents, you can use `go tool` commands to explore and +visualize them: + +```code +# Opens the terminal interactive explorer +$ go tool pprof heap.pprof + +# Opens the web visualizer +$ go tool pprof -http : heap.pprof + +# Visualize trace profiles +$ go tool trace trace.pprof +``` + +## Using diagnostics endpoints + +The profiling endpoint is only enabled if the `--debug` flag is supplied. + +(!docs/pages/includes/diagnostics/diag-addr-prereqs-tabs.mdx flags="--debug" !) + +### Collecting profiles + +Go's standard profiling endpoints are served at `http://127.0.0.1:3000/debug/pprof/`. +Retrieving a profile requires sending a request to the endpoint corresponding +to the desired profile type. When debugging an issue it is helpful to collect +a series of profiles over a period of time. + +#### CPU +CPU profile show execution statistics gathered over a user specified period: + +``` code +# Download the profile into a file: +$ curl -o cpu.profile http://127.0.0.1:3000/debug/pprof/profile?seconds=30 + +# Visualize the profile +$ go tool pprof -http : cpu.profile +``` + +#### Goroutine + +Goroutine profiles show the stack traces for all running goroutines in the system: + +``` code +# Download the profile into a file: +$ curl -o goroutine.profile http://127.0.0.1:3000/debug/pprof/goroutine + +# Visualize the profile +$ go tool pprof -http : goroutine.profile +``` + +#### Heap + +Heap profiles show allocated objects in the system: + +```code +# Download the profile into a file: +$ curl -o heap.profile http://127.0.0.1:3000/debug/pprof/heap + +# Visualize the profile +$ go tool pprof -http : heap.profile +``` + +#### Trace + +Trace profiles capture scheduling, system calls, garbage collections, heap size, and other events that are collected by the Go runtime +over a user specified period of time: + +```code +# Download the profile into a file: +$ curl -o trace.out http://127.0.0.1:3000/debug/pprof/trace?seconds=5 + +# Visualize the profile +$ go tool trace trace.out +``` + +## Further Reading + +- More information about diagnostics in the Go ecosystem: https://go.dev/doc/diagnostics +- Go's profiling endpoints: https://golang.org/pkg/net/http/pprof/ +- A deep dive on profiling Go programs: https://go.dev/blog/pprof + diff --git a/docs/pages/management/dynamic-resources/teleport-operator.mdx b/docs/pages/management/dynamic-resources/teleport-operator.mdx index e4ab426ee9ccd..9b2fc860b306d 100644 --- a/docs/pages/management/dynamic-resources/teleport-operator.mdx +++ b/docs/pages/management/dynamic-resources/teleport-operator.mdx @@ -45,6 +45,33 @@ follow [the guide for Helm-deployed clusters](./teleport-operator-helm.mdx). If you are hosting Teleport out of Kubernetes (Teleport Cloud, Terraform, ...), follow [the standalone operator guide](./teleport-operator-standalone.mdx). +### Control reconciliation with annotations + +The operator supports two annotations on CRs: + +#### `teleport.dev/keep` + +This annotation instructs the operator to keep the Teleport resource if the CR is deleted. +This is useful if you want to migrate between two resource versions. + +For example, to migrate from `TeleportRoleV6` to `TeleportRoleV7`: +- Annotate the existing `TeleportRoleV6` resource with `teleport.dev/keep: "true"` +- Delete the `TeleportRoleV6` CR, the operator won't delete the associated Teleport role +- Create a `TeleportRoleV7` CR with the same name, the operator will find the existing v6 role and adopt it. + +Possible values are `"true"` or `"false"` (those are strings, as Booleans are not valid label values in Kubernetes). + +#### `teleport.dev/ignore` + +This annotation instructs the operator to ignore the CR when reconciling. +This means the resource will not be created, updated, or deleted in Teleport. + +This also means the operator will not remove its finalizer if you try to delete an ignored CR. +The finalizer will stay and the deletion be blocked until you patch the resource to remove the +finalizer or remove the ignore annotation. + +Possible values are `"true"` or `"false"` (those are strings, as Booleans are not valid label values in Kubernetes). + ### Troubleshooting (!docs/pages/includes/diagnostics/kubernetes-operator-troubleshooting.mdx!) diff --git a/docs/pages/management/export-audit-events.mdx b/docs/pages/management/export-audit-events.mdx index c287f63bb8c91..fac23f189c4cd 100644 --- a/docs/pages/management/export-audit-events.mdx +++ b/docs/pages/management/export-audit-events.mdx @@ -22,6 +22,9 @@ events to your solution of choice: Stack](./export-audit-events/elastic-stack.mdx): How to configure the Event Handler plugin to forward Teleport audit logs to Logstash for ingestion in Elasticsearch so you can explore them in Kibana. +- [Monitor Teleport Audit Events with Panther](./export-audit-events/panther.mdx): + How to configure the Event Handler plugin to send logs to Panther via Fluentd + so you can explore your audit events in Panther. - [Monitor Teleport Audit Events with Splunk](./export-audit-events/splunk.mdx): How to configure the Event Handler plugin to send logs to Splunk's Universal Forwarder so you can explore your audit events in Splunk. diff --git a/docs/pages/management/operations/backup-restore.mdx b/docs/pages/management/operations/backup-restore.mdx index fd6b3ad71b568..165b65de5f4f3 100644 --- a/docs/pages/management/operations/backup-restore.mdx +++ b/docs/pages/management/operations/backup-restore.mdx @@ -95,9 +95,9 @@ If you're running Teleport at scale, your teams need to have an automated way to -As of version v4.1, you can now quickly export a collection of resources from -Teleport. This feature was designed to help customers migrate from local storage -to etcd. +You can export a collection of resources from +Teleport using the below command. This feature helps for migrating +from one backend to another. Using `tctl get all --with-secrets` will retrieve the below items: @@ -162,9 +162,9 @@ also apply to a new cluster being bootstrapped from the state of an old cluster: -As of version v4.1, you can now quickly export a collection of resources from -Teleport. This feature was designed to help customers migrate from local storage -to etcd. +You can export a collection of resources from +Teleport using the below command. This feature helps for migrating +from one backend to another. Using `tctl get all --with-secrets` will retrieve the below items: diff --git a/docs/pages/reference/backends.mdx b/docs/pages/reference/backends.mdx index 310aee9d1a578..faf52ea888e62 100644 --- a/docs/pages/reference/backends.mdx +++ b/docs/pages/reference/backends.mdx @@ -10,12 +10,12 @@ For self-hosted Teleport deployments, you can configure Teleport to integrate with other storage types based on the nature of the stored data (size, read/write ratio, mutability, etc.). -| Data type | Description | Supported storage backends | -| - | - | - | -| core cluster state | Cluster configuration (e.g. users, roles, auth connectors) and identity (e.g. certificate authorities, registered nodes, trusted clusters). | Local directory (SQLite), etcd, PostgreSQL, Amazon DynamoDB, GCP Firestore, CockroachDB | -| audit events | JSON-encoded events from the audit log (e.g. user logins, RBAC changes) | Local directory, PostgreSQL, AWS DynamoDB, GCP Firestore | -| session recordings | Raw terminal recordings of interactive user sessions | Local directory, AWS S3 (and any S3-compatible product), GCP Cloud Storage, Azure Blob Storage | -| teleport instance state | ID and credentials of a non-auth teleport instance (e.g. node, proxy) | Local directory, Kubernetes Secret | +| Data type | Description | Supported storage backends | +|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| core cluster state | Cluster configuration (e.g. users, roles, auth connectors) and identity (e.g. certificate authorities, registered nodes, trusted clusters). | Local directory (SQLite), etcd, PostgreSQL, Amazon DynamoDB, GCP Firestore, CockroachDB | +| audit events | JSON-encoded events from the audit log (e.g. user logins, RBAC changes) | Local directory, PostgreSQL, CockroachDB, Amazon DynamoDB, GCP Firestore | +| session recordings | Raw terminal recordings of interactive user sessions | Local directory, AWS S3 (and any S3-compatible product), GCP Cloud Storage, Azure Blob Storage | +| teleport instance state | ID and credentials of a non-auth teleport instance (e.g. node, proxy) | Local directory, Kubernetes Secret | ## Cluster state @@ -209,6 +209,13 @@ its repository. The plugin is pre-installed with no extra steps to take in [Azure Database for PostgreSQL](https://azure.microsoft.com/en-us/products/postgresql). + +CockroachDB can be used as a PostgreSQL drop-in replacement to store audit events (requires Teleport version >= 15.4.2). + +Teleport can store the cluster state in CockroachDB but this require CockroachDB-specific configuration. +See the [CockroachDB backend section](#cockroachdb) for more details. + + Teleport needs separate databases for the cluster state and the audit log, and it will attempt to create them if given permissions to do so; it will also set up the database schemas as needed, so we recommend giving the user @@ -1453,15 +1460,6 @@ to achieve high availability and survive regional failures. You must take steps protect access to CockroachDB in this configuration because that is where Teleport secrets like keys and user records will be stored. - - CockroachDB can currently only be used to store Teleport's cluster state. - It cannot be used for Teleport's audit log in the same way that - [DynamoDB](#dynamodb) or [Firestore](#firestore) can. - - At a minimum you must configure CockroachDB to allow Teleport to create tables. Teleport will create the database if given permission to do so but this is not required if the database already exists. diff --git a/docs/pages/reference/cli/tsh.mdx b/docs/pages/reference/cli/tsh.mdx index 7cab1a0c50870..35609874c562e 100644 --- a/docs/pages/reference/cli/tsh.mdx +++ b/docs/pages/reference/cli/tsh.mdx @@ -26,6 +26,7 @@ Environment variables configure your tsh client and can help you avoid using fla | TELEPORT_USE_LOCAL_SSH_AGENT | Disable or enable local SSH agent integration | true, false | | TELEPORT_GLOBAL_TSH_CONFIG | Override location of global `tsh` config file from default `/etc/tsh.yaml` | /opt/teleport/tsh.yaml | | TELEPORT_HEADLESS | Use headless authentication | true, false, 1, 0 | +| TELEPORT_IDENTITY_FILE | File path to identity file | /opt/identity | ## tsh global flags @@ -316,6 +317,7 @@ $ tsh login [] [] | Name | Default Value(s) | Allowed Value(s) | Description | | - | - | - | - | | `--bind-addr` | none | host:port | Address in the form of host:port to bind to for login command webhook | +| `--callback` | none | host:port | Override the base URL (host:port) of the link shown when opening a browser for cluster logins. Must be used with --bind-addr. | `-o, --out` | none | filepath | Identity output filepath | | `--format` | `file` | `file`, `openssh` or `kubernetes` | Identity format: file, openssh (for OpenSSH compatibility) or kubernetes (for kubeconfig) | | `--browser` | none | `none` | Set to 'none' to suppress opening system default browser for `tsh login` commands | diff --git a/docs/pages/reference/join-methods.mdx b/docs/pages/reference/join-methods.mdx index 51daab28fa040..7a1b4c91abc46 100644 --- a/docs/pages/reference/join-methods.mdx +++ b/docs/pages/reference/join-methods.mdx @@ -87,7 +87,7 @@ for an instance to join the cluster. Secret-based join methods are universal: Teleport service can use a secret-based join method regardless of the platform/cloud provider it runs on. The joining instance -sends the secret and the Auth Service validates that it matches the one it +sends the secret and the Auth Service validates that it matches the one it knows. Those joining methods are inherently prone to secret exfiltration and the delegated join methods should be preferred when available. If you have to use a secret-based join method, it is recommended to use short-lived tokens @@ -138,7 +138,7 @@ Renewable join-methods are: - [static `token`](#static-tokens) - [`ec2`](#aws-ec2-identity-document-ec2) -Nodes with non-renewable certificates must join again in order to get a new +Nodes with non-renewable certificates must join again in order to get a new certificate before expiry. The instance will have to prove again that it is legitimate. The non-renewable join methods guarantee that an attacker stealing the instance certificates will not be able to maintain access to the Teleport cluster. @@ -172,7 +172,7 @@ spec: # - edit the token to update the roles (e.g. add "App") # - un-register the Teleport instance # - modify its configuration to enable the new service (here "app_service.enabled") - # - have the instance join again + # - have the instance join again # # You should use the minimal set of system roles required. # Common roles are: @@ -184,7 +184,7 @@ spec: # - "WindowsDesktop" for Windows Desktop Service # - "Discovery" for Discovery Service # - "Bot" for MachineID (when set, "spec.bot_name" must be set in the token) - roles: + roles: - Node - App join_method: gcp @@ -408,7 +408,7 @@ The Kubernetes JWKS join method is available in Teleport 14+. After rotating the Kubernetes CA, you must update the Kubernetes JWKS tokens -to contain the new Kubernetes singing keys (update the +to contain the new Kubernetes signing keys (update the `spec.kubernetes.static_jwks.jwks` field). diff --git a/docs/pages/reference/terraform-provider/data-sources/github_connector.mdx b/docs/pages/reference/terraform-provider/data-sources/github_connector.mdx index faf4d97151e53..3a38d3bd7f01b 100644 --- a/docs/pages/reference/terraform-provider/data-sources/github_connector.mdx +++ b/docs/pages/reference/terraform-provider/data-sources/github_connector.mdx @@ -45,6 +45,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs ### Nested Schema for `spec.teams_to_logins` diff --git a/docs/pages/reference/terraform-provider/data-sources/oidc_connector.mdx b/docs/pages/reference/terraform-provider/data-sources/oidc_connector.mdx index 57b7098854dec..81a214a6b4c6c 100644 --- a/docs/pages/reference/terraform-provider/data-sources/oidc_connector.mdx +++ b/docs/pages/reference/terraform-provider/data-sources/oidc_connector.mdx @@ -59,6 +59,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs diff --git a/docs/pages/reference/terraform-provider/data-sources/saml_connector.mdx b/docs/pages/reference/terraform-provider/data-sources/saml_connector.mdx index bcf70b19659a3..937a064e99baf 100644 --- a/docs/pages/reference/terraform-provider/data-sources/saml_connector.mdx +++ b/docs/pages/reference/terraform-provider/data-sources/saml_connector.mdx @@ -69,6 +69,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs ### Nested Schema for `spec.signing_key_pair` diff --git a/docs/pages/reference/terraform-provider/data-sources/user.mdx b/docs/pages/reference/terraform-provider/data-sources/user.mdx index b2b12619f9268..67f8e507b287e 100644 --- a/docs/pages/reference/terraform-provider/data-sources/user.mdx +++ b/docs/pages/reference/terraform-provider/data-sources/user.mdx @@ -46,7 +46,7 @@ Optional: - `roles` (List of String) Roles is a list of roles assigned to user - `saml_identities` (Attributes List) SAMLIdentities lists associated SAML identities that let user log in using externally verified identity (see [below for nested schema](#nested-schema-for-specsaml_identities)) - `traits` (Map of List of String) -- `trusted_device_ids` (List of String) TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Managed by the Device Trust subsystem, avoid manual edits. +- `trusted_device_ids` (List of String) TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Note that SSO users are transient and thus may contain an empty TrustedDeviceIDs field, even though the user->device association exists under the Device Trust subsystem. Do not rely on this field to determine device associations or ownership, it exists for legacy/informative purposes only. Managed by the Device Trust subsystem, avoid manual edits. ### Nested Schema for `spec.github_identities` diff --git a/docs/pages/reference/terraform-provider/resources/github_connector.mdx b/docs/pages/reference/terraform-provider/resources/github_connector.mdx index 6b532e77edb2c..6db1290d5850b 100644 --- a/docs/pages/reference/terraform-provider/resources/github_connector.mdx +++ b/docs/pages/reference/terraform-provider/resources/github_connector.mdx @@ -76,6 +76,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs ### Nested Schema for `spec.teams_to_logins` diff --git a/docs/pages/reference/terraform-provider/resources/oidc_connector.mdx b/docs/pages/reference/terraform-provider/resources/oidc_connector.mdx index 463818acf2fcc..0fe2cf61d32b1 100644 --- a/docs/pages/reference/terraform-provider/resources/oidc_connector.mdx +++ b/docs/pages/reference/terraform-provider/resources/oidc_connector.mdx @@ -89,6 +89,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs diff --git a/docs/pages/reference/terraform-provider/resources/saml_connector.mdx b/docs/pages/reference/terraform-provider/resources/saml_connector.mdx index 35a33e15e4244..5c7dd6474ad9e 100644 --- a/docs/pages/reference/terraform-provider/resources/saml_connector.mdx +++ b/docs/pages/reference/terraform-provider/resources/saml_connector.mdx @@ -115,6 +115,7 @@ Optional: Optional: - `allowed_https_hostnames` (List of String) a list of hostnames allowed for https client redirect URLs +- `insecure_allowed_cidr_ranges` (List of String) a list of CIDRs allowed for HTTP or HTTPS client redirect URLs ### Nested Schema for `spec.signing_key_pair` diff --git a/docs/pages/reference/terraform-provider/resources/user.mdx b/docs/pages/reference/terraform-provider/resources/user.mdx index f65fd9bb950db..989c39616ab6d 100644 --- a/docs/pages/reference/terraform-provider/resources/user.mdx +++ b/docs/pages/reference/terraform-provider/resources/user.mdx @@ -92,7 +92,7 @@ Optional: - `roles` (List of String) Roles is a list of roles assigned to user - `saml_identities` (Attributes List) SAMLIdentities lists associated SAML identities that let user log in using externally verified identity (see [below for nested schema](#nested-schema-for-specsaml_identities)) - `traits` (Map of List of String) -- `trusted_device_ids` (List of String) TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Managed by the Device Trust subsystem, avoid manual edits. +- `trusted_device_ids` (List of String) TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Note that SSO users are transient and thus may contain an empty TrustedDeviceIDs field, even though the user->device association exists under the Device Trust subsystem. Do not rely on this field to determine device associations or ownership, it exists for legacy/informative purposes only. Managed by the Device Trust subsystem, avoid manual edits. ### Nested Schema for `spec.github_identities` diff --git a/docs/pages/upcoming-releases.mdx b/docs/pages/upcoming-releases.mdx index 27e3170e37a06..e7e0445044b71 100644 --- a/docs/pages/upcoming-releases.mdx +++ b/docs/pages/upcoming-releases.mdx @@ -15,11 +15,6 @@ The Teleport team delivers a new major release roughly every 4 months. ### 16.2.0 -#### Nested Access Lists - -Teleport admins and Access List owners will be able to add Access Lists as -members in other Access Lists. - #### NLA Support Teleport will support Network Level Authentication (NLA) when connecting to @@ -44,8 +39,26 @@ to the `tctl tokens` commands. Teleport will support secure joining via Terraform Cloud, allowing Machine ID workflows to run on Terraform Cloud without shared secrets. +#### Nested Access Lists + +Teleport admins and Access List owners will be able to add Access Lists as +members in other Access Lists. + +*Delayed from Teleport 16.2.0.* + +#### Hardware Key support for Teleport Connect + +Teleport's support for [hardware-backed private +keys](access-controls/guides/hardware-key-support.mdx) will be extended to +Teleport Connect. + ### 17.0.0 +#### New Nav + +Teleport 17 will include navigation updates to enhance usability and +scalability of the web UI. + #### Modern Signature Algorithms Teleport admins will have to option to use elliptic curve cryptography for the @@ -58,14 +71,41 @@ Teleport will integrate with AWS Identity Center to allow users to sync and manage AWS IC group and their members and allow them to request access to AWS IC permission sets. +#### Out-of-band user creation + +Cluster administrators will be able to configure Teleport's `ssh_service` to +ensure that certain host users exist on the machine without the need to start +an SSH session. + +## Teleport Policy + +| Version | Date | +|---------|----------------| +| 1.24.0 | Aug 30th, 2024 | + +### 1.24.0 + +#### New UI + +Access Graph will include navigation updates to enhance the usability and +scalability of the web UI. + +### Crown Jewels + +Access Graph will allow marking the most critical resources as "Crown Jewels," +providing enhanced traceability and auditing capabilities for them. + + ## Teleport Cloud The key deliverables for Teleport Cloud in the next quarter: -| Week of | Description | -|-----------------|--------------------------------------------------------------| -| August 19, 2024 | Teleport 16.2 will begin rollout on Cloud. | -| August 19, 2024 | Teleport 16.2 agents will begin rollout to eligible tenants. | +| Week of | Description | +|--------------------|--------------------------------------------------------------| +| August 19, 2024 | Teleport 16.2 will begin rollout on Cloud. | +| August 19, 2024 | Teleport 16.2 agents will begin rollout to eligible tenants. | +| September 16, 2024 | Teleport 16.3 will begin rollout on Cloud. | +| September 16, 2024 | Teleport 16.3 agents will begin rollout to eligible tenants. | ## Production readiness diff --git a/docs/pages/upgrading/automatic-agent-updates.mdx b/docs/pages/upgrading/automatic-agent-updates.mdx index ba6eb626da644..269b37b917800 100644 --- a/docs/pages/upgrading/automatic-agent-updates.mdx +++ b/docs/pages/upgrading/automatic-agent-updates.mdx @@ -84,7 +84,7 @@ Teleport cluster that agents use to determine when to check for upgrades. 1. Add the role to your Teleport user: - (!docs/pages/includes/add-role-to-user.mdx!) + (!docs/pages/includes/add-role-to-user.mdx role="cmc-editor"!) 1. Create a cluster maintenance config in a file called `cmc.yaml`. The following example allows maintenance on Monday, Wednesday and Friday between @@ -183,15 +183,22 @@ Server ID Hostname Services Version Upgrader ```code - $ curl https://goteleport.com/static/install.sh | bash -s ${TELEPORT_VERSION?} cloud + $ curl (=teleport.teleport_install_script_url=) | bash -s ${TELEPORT_VERSION?} cloud ``` - ```code - $ curl https://goteleport.com/static/install.sh | bash -s ${TELEPORT_VERSION?} enterprise - ``` + 1. Follow the instructions in the Teleport [installation + guide](../installation.mdx#package-repositories) to install the `teleport` + binary on your Linux server for your package manager. + + 1. Using your package manager, install `teleport-ent-updater` on the + server where you installed `teleport`. For example: + + ```code + $ apt-get install -y teleport-ent-updater + ``` diff --git a/docs/pages/upgrading/reference.mdx b/docs/pages/upgrading/reference.mdx index 5ed1618a08e84..d6635b32442e1 100644 --- a/docs/pages/upgrading/reference.mdx +++ b/docs/pages/upgrading/reference.mdx @@ -327,7 +327,7 @@ Service, then on each of your agents: 1. Install the new Teleport version on your Linux server: ```code - $ curl https://goteleport.com/static/install.sh | bash -s + $ curl (=teleport.teleport_install_script_url=) | bash -s ``` The installation script detects the package manager on your Linux server and diff --git a/e b/e index 90a05a1286e7d..73aad61d4c7f4 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 90a05a1286e7d6538b00de6e31cde6b7140dce07 +Subproject commit 73aad61d4c7f4a036de361ce009bd284d883377d diff --git a/entitlements/entitlements.go b/entitlements/entitlements.go new file mode 100644 index 0000000000000..afde35c8c4f12 --- /dev/null +++ b/entitlements/entitlements.go @@ -0,0 +1,58 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package entitlements + +type EntitlementKind string + +// The EntitlementKind list should be 1:1 with the Features & FeatureStrings in salescenter/product/product.go, +// except CustomTheme which is dropped. CustomTheme entitlement only toggles the ability to "set" a theme; +// the value of that theme, if set, is stored and accessed outside of entitlements. +// +// All EntitlementKinds added here should also be added to AllEntitlements below and defaultEntitlements in +// web/packages/teleport/src/entitlement.ts. +const ( + AccessLists EntitlementKind = "AccessLists" + AccessMonitoring EntitlementKind = "AccessMonitoring" + AccessRequests EntitlementKind = "AccessRequests" + App EntitlementKind = "App" + CloudAuditLogRetention EntitlementKind = "CloudAuditLogRetention" + DB EntitlementKind = "DB" + Desktop EntitlementKind = "Desktop" + DeviceTrust EntitlementKind = "DeviceTrust" + ExternalAuditStorage EntitlementKind = "ExternalAuditStorage" + FeatureHiding EntitlementKind = "FeatureHiding" + HSM EntitlementKind = "HSM" + Identity EntitlementKind = "Identity" + JoinActiveSessions EntitlementKind = "JoinActiveSessions" + K8s EntitlementKind = "K8s" + MobileDeviceManagement EntitlementKind = "MobileDeviceManagement" + OIDC EntitlementKind = "OIDC" + OktaSCIM EntitlementKind = "OktaSCIM" + OktaUserSync EntitlementKind = "OktaUserSync" + Policy EntitlementKind = "Policy" + SAML EntitlementKind = "SAML" + SessionLocks EntitlementKind = "SessionLocks" + UpsellAlert EntitlementKind = "UpsellAlert" + UsageReporting EntitlementKind = "UsageReporting" +) + +// AllEntitlements returns all Entitlements; should be 1:1 with the const declared above. +var AllEntitlements = []EntitlementKind{ + AccessLists, AccessMonitoring, AccessRequests, App, CloudAuditLogRetention, DB, Desktop, DeviceTrust, + ExternalAuditStorage, FeatureHiding, HSM, Identity, JoinActiveSessions, K8s, MobileDeviceManagement, OIDC, OktaSCIM, + OktaUserSync, Policy, SAML, SessionLocks, UpsellAlert, UsageReporting, +} diff --git a/examples/agent-pool-terraform/teleport/userdata b/examples/agent-pool-terraform/teleport/userdata index b68110177dc46..c417d6119e6cf 100644 --- a/examples/agent-pool-terraform/teleport/userdata +++ b/examples/agent-pool-terraform/teleport/userdata @@ -1,6 +1,6 @@ #!/bin/bash -curl https://goteleport.com/static/install.sh | bash -s ${teleport_version} ${teleport_edition} +curl https://cdn.teleport.dev/install-v${teleport_version}.sh | bash -s ${teleport_version} ${teleport_edition} echo ${token} > /var/lib/teleport/token cat</etc/teleport.yaml diff --git a/examples/athena/variables.tf b/examples/athena/variables.tf index e0bd51db529f8..21827d3b713e8 100644 --- a/examples/athena/variables.tf +++ b/examples/athena/variables.tf @@ -53,7 +53,7 @@ variable "workgroup_max_scanned_bytes_per_query" { # search events API to prevent increasing costs in case of aggressive use of API. # In current version Athena Audit logger is not prepared for polling of API. # Burst=20, time=1m and amount=5, means that you can do 20 requests without any -# throtling, next requests will be thottled, and tokens will be filled to +# throttling, next requests will be throttled, and tokens will be filled to # rate limit bucket at amount 5 every 1m. variable "search_event_limiter_burst" { description = "Number of tokens available for rate limit used on top of search event API" diff --git a/examples/chart/access/discord/Chart.yaml b/examples/chart/access/discord/Chart.yaml index 11e09eacf7d07..0469f3b1635a0 100644 --- a/examples/chart/access/discord/Chart.yaml +++ b/examples/chart/access/discord/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-discord diff --git a/examples/chart/access/discord/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/discord/tests/__snapshot__/configmap_test.yaml.snap index 13d96442bc257..3f74ba83a328a 100644 --- a/examples/chart/access/discord/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/discord/tests/__snapshot__/configmap_test.yaml.snap @@ -24,6 +24,6 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-discord - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-discord-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-discord-16.1.4 name: RELEASE-NAME-teleport-plugin-discord diff --git a/examples/chart/access/discord/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/discord/tests/__snapshot__/deployment_test.yaml.snap index ca874d0ff6d62..cb1dbda3786ce 100644 --- a/examples/chart/access/discord/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/discord/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-discord - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-discord-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-discord-16.1.4 name: RELEASE-NAME-teleport-plugin-discord spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-discord - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-discord-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-discord-16.1.4 spec: containers: - command: diff --git a/examples/chart/access/email/Chart.yaml b/examples/chart/access/email/Chart.yaml index a009c6b61dd1f..7301efa2dd8ba 100644 --- a/examples/chart/access/email/Chart.yaml +++ b/examples/chart/access/email/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-email diff --git a/examples/chart/access/email/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/email/tests/__snapshot__/configmap_test.yaml.snap index 88cf268fcb68d..4a005a29163cc 100644 --- a/examples/chart/access/email/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/email/tests/__snapshot__/configmap_test.yaml.snap @@ -26,8 +26,8 @@ should match the snapshot (mailgun on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email should match the snapshot (smtp on): 1: | @@ -59,8 +59,8 @@ should match the snapshot (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email should match the snapshot (smtp on, no starttls): 1: | @@ -92,8 +92,8 @@ should match the snapshot (smtp on, no starttls): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email should match the snapshot (smtp on, password file): 1: | @@ -125,8 +125,8 @@ should match the snapshot (smtp on, password file): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email should match the snapshot (smtp on, roleToRecipients set): 1: | @@ -161,8 +161,8 @@ should match the snapshot (smtp on, roleToRecipients set): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email should match the snapshot (smtp on, starttls disabled): 1: | @@ -194,6 +194,6 @@ should match the snapshot (smtp on, starttls disabled): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email diff --git a/examples/chart/access/email/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/email/tests/__snapshot__/deployment_test.yaml.snap index 2b3c50e16a486..99cd2e8b8deb9 100644 --- a/examples/chart/access/email/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/email/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should be possible to override volume name (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -22,8 +22,8 @@ should be possible to override volume name (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -34,7 +34,7 @@ should be possible to override volume name (smtp on): env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-email ports: @@ -75,8 +75,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -90,8 +90,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -136,8 +136,8 @@ should match the snapshot (mailgun on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -151,8 +151,8 @@ should match the snapshot (mailgun on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -163,7 +163,7 @@ should match the snapshot (mailgun on): env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-email ports: @@ -204,8 +204,8 @@ should match the snapshot (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -219,8 +219,8 @@ should match the snapshot (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -231,7 +231,7 @@ should match the snapshot (smtp on): env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-email ports: @@ -272,8 +272,8 @@ should mount external secret (mailgun on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -287,8 +287,8 @@ should mount external secret (mailgun on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -299,7 +299,7 @@ should mount external secret (mailgun on): env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-email ports: @@ -340,8 +340,8 @@ should mount external secret (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 name: RELEASE-NAME-teleport-plugin-email spec: replicas: 1 @@ -355,8 +355,8 @@ should mount external secret (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-email - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-email-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-email-16.1.4 spec: containers: - command: @@ -367,7 +367,7 @@ should mount external secret (smtp on): env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-email:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-email ports: diff --git a/examples/chart/access/jira/Chart.yaml b/examples/chart/access/jira/Chart.yaml index f5c67a6790b40..41787ccc4c9ee 100644 --- a/examples/chart/access/jira/Chart.yaml +++ b/examples/chart/access/jira/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-jira diff --git a/examples/chart/access/jira/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/jira/tests/__snapshot__/configmap_test.yaml.snap index 3cbb8dacc4895..6ca6e1874255e 100644 --- a/examples/chart/access/jira/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/jira/tests/__snapshot__/configmap_test.yaml.snap @@ -32,6 +32,6 @@ should match the snapshot (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-jira - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-jira-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-jira-16.1.4 name: RELEASE-NAME-teleport-plugin-jira diff --git a/examples/chart/access/jira/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/jira/tests/__snapshot__/deployment_test.yaml.snap index 1bad9867adfeb..e5b20083022e5 100644 --- a/examples/chart/access/jira/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/jira/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-jira - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-jira-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-jira-16.1.4 name: RELEASE-NAME-teleport-plugin-jira spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-jira - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-jira-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-jira-16.1.4 spec: containers: - command: diff --git a/examples/chart/access/mattermost/Chart.yaml b/examples/chart/access/mattermost/Chart.yaml index 85666fc718dd0..8e2ddd337afe1 100644 --- a/examples/chart/access/mattermost/Chart.yaml +++ b/examples/chart/access/mattermost/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-mattermost diff --git a/examples/chart/access/mattermost/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/mattermost/tests/__snapshot__/configmap_test.yaml.snap index a6129ff1d0066..70098a95e6604 100644 --- a/examples/chart/access/mattermost/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/mattermost/tests/__snapshot__/configmap_test.yaml.snap @@ -22,6 +22,6 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 name: RELEASE-NAME-teleport-plugin-mattermost diff --git a/examples/chart/access/mattermost/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/mattermost/tests/__snapshot__/deployment_test.yaml.snap index bd30ce31912de..0da7cda5bd7ac 100644 --- a/examples/chart/access/mattermost/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/mattermost/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 name: RELEASE-NAME-teleport-plugin-mattermost spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 spec: containers: - command: @@ -75,8 +75,8 @@ should mount external secret: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 name: RELEASE-NAME-teleport-plugin-mattermost spec: replicas: 1 @@ -90,8 +90,8 @@ should mount external secret: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 spec: containers: - command: @@ -102,7 +102,7 @@ should mount external secret: env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-mattermost:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-mattermost:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-mattermost ports: @@ -143,8 +143,8 @@ should override volume name: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 name: RELEASE-NAME-teleport-plugin-mattermost spec: replicas: 1 @@ -158,8 +158,8 @@ should override volume name: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-mattermost - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-mattermost-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-mattermost-16.1.4 spec: containers: - command: @@ -170,7 +170,7 @@ should override volume name: env: - name: TELEPORT_PLUGIN_FAIL_FAST value: "true" - image: public.ecr.aws/gravitational/teleport-plugin-mattermost:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-mattermost:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-mattermost ports: diff --git a/examples/chart/access/msteams/Chart.yaml b/examples/chart/access/msteams/Chart.yaml index f84fe2255f9a5..bf3b2bfc41a62 100644 --- a/examples/chart/access/msteams/Chart.yaml +++ b/examples/chart/access/msteams/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-msteams diff --git a/examples/chart/access/msteams/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/msteams/tests/__snapshot__/configmap_test.yaml.snap index 6c0d07ffd0c11..788ff06ced168 100644 --- a/examples/chart/access/msteams/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/msteams/tests/__snapshot__/configmap_test.yaml.snap @@ -29,6 +29,6 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-msteams - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-msteams-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-msteams-16.1.4 name: RELEASE-NAME-teleport-plugin-msteams diff --git a/examples/chart/access/msteams/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/msteams/tests/__snapshot__/deployment_test.yaml.snap index 009c0ecd8c26c..31d99267aae41 100644 --- a/examples/chart/access/msteams/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/msteams/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-msteams - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-msteams-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-msteams-16.1.4 name: RELEASE-NAME-teleport-plugin-msteams spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-msteams - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-msteams-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-msteams-16.1.4 spec: containers: - command: diff --git a/examples/chart/access/pagerduty/Chart.yaml b/examples/chart/access/pagerduty/Chart.yaml index c0a19d8217e1d..74fb027bab36e 100644 --- a/examples/chart/access/pagerduty/Chart.yaml +++ b/examples/chart/access/pagerduty/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-pagerduty diff --git a/examples/chart/access/pagerduty/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/pagerduty/tests/__snapshot__/configmap_test.yaml.snap index 085936482996b..aec6384b7fa54 100644 --- a/examples/chart/access/pagerduty/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/pagerduty/tests/__snapshot__/configmap_test.yaml.snap @@ -21,6 +21,6 @@ should match the snapshot (smtp on): app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-pagerduty - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-pagerduty-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-pagerduty-16.1.4 name: RELEASE-NAME-teleport-plugin-pagerduty diff --git a/examples/chart/access/pagerduty/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/pagerduty/tests/__snapshot__/deployment_test.yaml.snap index 18853163538fd..27e7e5acf7703 100644 --- a/examples/chart/access/pagerduty/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/pagerduty/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-pagerduty - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-pagerduty-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-pagerduty-16.1.4 name: RELEASE-NAME-teleport-plugin-pagerduty spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-pagerduty - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-pagerduty-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-pagerduty-16.1.4 spec: containers: - command: diff --git a/examples/chart/access/slack/Chart.yaml b/examples/chart/access/slack/Chart.yaml index f118992f2bc49..4c3b4118abfdd 100644 --- a/examples/chart/access/slack/Chart.yaml +++ b/examples/chart/access/slack/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-slack diff --git a/examples/chart/access/slack/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/access/slack/tests/__snapshot__/configmap_test.yaml.snap index 923f889917bfa..880a8e6d9d1ad 100644 --- a/examples/chart/access/slack/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/access/slack/tests/__snapshot__/configmap_test.yaml.snap @@ -24,6 +24,6 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-slack - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-slack-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-slack-16.1.4 name: RELEASE-NAME-teleport-plugin-slack diff --git a/examples/chart/access/slack/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/access/slack/tests/__snapshot__/deployment_test.yaml.snap index cd78c254df165..1d7da9e578662 100644 --- a/examples/chart/access/slack/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/access/slack/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-slack - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-slack-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-slack-16.1.4 name: RELEASE-NAME-teleport-plugin-slack spec: replicas: 1 @@ -22,8 +22,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-slack - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-slack-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-slack-16.1.4 spec: containers: - command: diff --git a/examples/chart/event-handler/Chart.yaml b/examples/chart/event-handler/Chart.yaml index fe0ac320dda9c..aefda72e4bdad 100644 --- a/examples/chart/event-handler/Chart.yaml +++ b/examples/chart/event-handler/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" apiVersion: v2 name: teleport-plugin-event-handler diff --git a/examples/chart/event-handler/templates/deployment.yaml b/examples/chart/event-handler/templates/deployment.yaml index 2cc2b8bc705cf..368b0015ab7a1 100644 --- a/examples/chart/event-handler/templates/deployment.yaml +++ b/examples/chart/event-handler/templates/deployment.yaml @@ -35,7 +35,7 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: - - /usr/local/bin/teleport-event-handler + - /usr/local/bin/teleport-plugin - start - "--config" - "/etc/teleport-event-handler.toml" diff --git a/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap b/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap index eda11a25e447e..66dea478bfd3d 100644 --- a/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap +++ b/examples/chart/event-handler/tests/__snapshot__/configmap_test.yaml.snap @@ -26,6 +26,6 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-event-handler - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-event-handler-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-event-handler-16.1.4 name: RELEASE-NAME-teleport-plugin-event-handler diff --git a/examples/chart/event-handler/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/event-handler/tests/__snapshot__/deployment_test.yaml.snap index 48cd1306b809a..f7eb578686b28 100644 --- a/examples/chart/event-handler/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/event-handler/tests/__snapshot__/deployment_test.yaml.snap @@ -7,8 +7,8 @@ should match the snapshot: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-plugin-event-handler - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-plugin-event-handler-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-plugin-event-handler-16.1.4 name: RELEASE-NAME-teleport-plugin-event-handler spec: replicas: 1 @@ -24,7 +24,7 @@ should match the snapshot: spec: containers: - command: - - /usr/local/bin/teleport-event-handler + - /usr/local/bin/teleport-plugin - start - --config - /etc/teleport-event-handler.toml @@ -73,7 +73,7 @@ should mount tls.existingCASecretName and set environment when set in values: 1: | containers: - command: - - /usr/local/bin/teleport-event-handler + - /usr/local/bin/teleport-plugin - start - --config - /etc/teleport-event-handler.toml @@ -82,7 +82,7 @@ should mount tls.existingCASecretName and set environment when set in values: value: "true" - name: SSL_CERT_FILE value: /etc/teleport-tls-ca/ca.pem - image: public.ecr.aws/gravitational/teleport-plugin-event-handler:16.1.0 + image: public.ecr.aws/gravitational/teleport-plugin-event-handler:16.1.4 imagePullPolicy: IfNotPresent name: teleport-plugin-event-handler ports: diff --git a/examples/chart/teleport-cluster/Chart.yaml b/examples/chart/teleport-cluster/Chart.yaml index d136d72ff0895..22e62598c331c 100644 --- a/examples/chart/teleport-cluster/Chart.yaml +++ b/examples/chart/teleport-cluster/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" name: teleport-cluster apiVersion: v2 diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/Chart.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/Chart.yaml index ce72967aafdb9..13777a99be719 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/Chart.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" name: teleport-operator apiVersion: v2 diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_githubconnectors.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_githubconnectors.yaml index 78f55c60cda1f..a92d5dbf5eff8 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_githubconnectors.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_githubconnectors.yaml @@ -55,6 +55,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object client_secret: description: ClientSecret is the Github OAuth app client secret. diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_oidcconnectors.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_oidcconnectors.yaml index aa3486d5ae3e4..b801cf6db84f4 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_oidcconnectors.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_oidcconnectors.yaml @@ -80,6 +80,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object client_secret: description: ClientSecret is used to authenticate the client. diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_samlconnectors.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_samlconnectors.yaml index 4ffda895f0cd0..a4437220e61cb 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_samlconnectors.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_samlconnectors.yaml @@ -95,6 +95,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object display: description: Display controls how this connector is displayed. diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_users.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_users.yaml index f8720f714d3c9..0c5221f64b369 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_users.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/operator-crds/resources.teleport.dev_users.yaml @@ -119,8 +119,12 @@ spec: type: object trusted_device_ids: description: TrustedDeviceIDs contains the IDs of trusted devices - enrolled by the user. Managed by the Device Trust subsystem, avoid - manual edits. + enrolled by the user. Note that SSO users are transient and thus + may contain an empty TrustedDeviceIDs field, even though the user->device + association exists under the Device Trust subsystem. Do not rely + on this field to determine device associations or ownership, it + exists for legacy/informative purposes only. Managed by the Device + Trust subsystem, avoid manual edits. items: type: string nullable: true diff --git a/examples/chart/teleport-cluster/charts/teleport-operator/templates/crds.yaml b/examples/chart/teleport-cluster/charts/teleport-operator/templates/crds.yaml index 5217aaac84c40..feacc38b749c2 100644 --- a/examples/chart/teleport-cluster/charts/teleport-operator/templates/crds.yaml +++ b/examples/chart/teleport-cluster/charts/teleport-operator/templates/crds.yaml @@ -2,7 +2,7 @@ and creates them if needed. It also adds common labels, like any other Helm-deployed resource. -We cannot rely on the "crds/" Helm directory as Helm's startegy is "fire and forget". +We cannot rely on the "crds/" Helm directory as Helm's strategy is "fire and forget". We have no way to update the CRDs after the initial deployment. As Teleport keeps adding new field to existing CRs, we need a deployment strategy that supports updating CRDs. diff --git a/examples/chart/teleport-cluster/tests/__snapshot__/auth_clusterrole_test.yaml.snap b/examples/chart/teleport-cluster/tests/__snapshot__/auth_clusterrole_test.yaml.snap index a40d4d0a3f347..22e19a142ef26 100644 --- a/examples/chart/teleport-cluster/tests/__snapshot__/auth_clusterrole_test.yaml.snap +++ b/examples/chart/teleport-cluster/tests/__snapshot__/auth_clusterrole_test.yaml.snap @@ -8,8 +8,8 @@ adds operator permissions to ClusterRole: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-cluster - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-cluster-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-cluster-16.1.4 teleport.dev/majorVersion: "16" name: RELEASE-NAME rules: diff --git a/examples/chart/teleport-cluster/tests/__snapshot__/auth_config_test.yaml.snap b/examples/chart/teleport-cluster/tests/__snapshot__/auth_config_test.yaml.snap index 76815f52b5ab5..81aef259bf341 100644 --- a/examples/chart/teleport-cluster/tests/__snapshot__/auth_config_test.yaml.snap +++ b/examples/chart/teleport-cluster/tests/__snapshot__/auth_config_test.yaml.snap @@ -1848,8 +1848,8 @@ sets clusterDomain on Configmap: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-cluster - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-cluster-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-cluster-16.1.4 teleport.dev/majorVersion: "16" name: RELEASE-NAME-auth namespace: NAMESPACE diff --git a/examples/chart/teleport-cluster/tests/__snapshot__/auth_deployment_test.yaml.snap b/examples/chart/teleport-cluster/tests/__snapshot__/auth_deployment_test.yaml.snap index 8038f289b5373..02e4945189bc6 100644 --- a/examples/chart/teleport-cluster/tests/__snapshot__/auth_deployment_test.yaml.snap +++ b/examples/chart/teleport-cluster/tests/__snapshot__/auth_deployment_test.yaml.snap @@ -8,7 +8,7 @@ - args: - --diag-addr=0.0.0.0:3000 - --apply-on-startup=/etc/teleport/apply-on-startup.yaml - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -141,7 +141,7 @@ should set nodeSelector when set in values: - args: - --diag-addr=0.0.0.0:3000 - --apply-on-startup=/etc/teleport/apply-on-startup.yaml - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -238,7 +238,7 @@ should set resources when set in values: - args: - --diag-addr=0.0.0.0:3000 - --apply-on-startup=/etc/teleport/apply-on-startup.yaml - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -324,7 +324,7 @@ should set securityContext when set in values: - args: - --diag-addr=0.0.0.0:3000 - --apply-on-startup=/etc/teleport/apply-on-startup.yaml - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: diff --git a/examples/chart/teleport-cluster/tests/__snapshot__/proxy_config_test.yaml.snap b/examples/chart/teleport-cluster/tests/__snapshot__/proxy_config_test.yaml.snap index 921bb26bbf0df..3d1ed52723f2d 100644 --- a/examples/chart/teleport-cluster/tests/__snapshot__/proxy_config_test.yaml.snap +++ b/examples/chart/teleport-cluster/tests/__snapshot__/proxy_config_test.yaml.snap @@ -567,8 +567,8 @@ sets clusterDomain on Configmap: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-cluster - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-cluster-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-cluster-16.1.4 teleport.dev/majorVersion: "16" name: RELEASE-NAME-proxy namespace: NAMESPACE diff --git a/examples/chart/teleport-cluster/tests/__snapshot__/proxy_deployment_test.yaml.snap b/examples/chart/teleport-cluster/tests/__snapshot__/proxy_deployment_test.yaml.snap index ae75e82108945..9bd8c23cca769 100644 --- a/examples/chart/teleport-cluster/tests/__snapshot__/proxy_deployment_test.yaml.snap +++ b/examples/chart/teleport-cluster/tests/__snapshot__/proxy_deployment_test.yaml.snap @@ -11,8 +11,8 @@ sets clusterDomain on Deployment Pods: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-cluster - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-cluster-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-cluster-16.1.4 teleport.dev/majorVersion: "16" name: RELEASE-NAME-proxy namespace: NAMESPACE @@ -26,7 +26,7 @@ sets clusterDomain on Deployment Pods: template: metadata: annotations: - checksum/config: 77797663ab04d615b921cf993092cf34694ce91db18e0e88196049e73b051d5e + checksum/config: f678f6cb77c35c70e794df5c213ac929462ee77b924b77492d82fd799dab5943 kubernetes.io/pod: test-annotation kubernetes.io/pod-different: 4 labels: @@ -34,8 +34,8 @@ sets clusterDomain on Deployment Pods: app.kubernetes.io/instance: RELEASE-NAME app.kubernetes.io/managed-by: Helm app.kubernetes.io/name: teleport-cluster - app.kubernetes.io/version: 16.1.0 - helm.sh/chart: teleport-cluster-16.1.0 + app.kubernetes.io/version: 16.1.4 + helm.sh/chart: teleport-cluster-16.1.4 teleport.dev/majorVersion: "16" spec: affinity: @@ -44,7 +44,7 @@ sets clusterDomain on Deployment Pods: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -105,7 +105,7 @@ sets clusterDomain on Deployment Pods: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.test.com - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update serviceAccountName: RELEASE-NAME-proxy terminationGracePeriodSeconds: 60 @@ -137,7 +137,7 @@ should provision initContainer correctly when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update resources: limits: @@ -201,7 +201,7 @@ should set nodeSelector when set in values: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -262,7 +262,7 @@ should set nodeSelector when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update nodeSelector: environment: security @@ -313,7 +313,7 @@ should set resources for wait-auth-update initContainer when set in values: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -381,7 +381,7 @@ should set resources for wait-auth-update initContainer when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update resources: limits: @@ -421,7 +421,7 @@ should set resources when set in values: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -489,7 +489,7 @@ should set resources when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update resources: limits: @@ -529,7 +529,7 @@ should set securityContext for initContainers when set in values: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -597,7 +597,7 @@ should set securityContext for initContainers when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update securityContext: allowPrivilegeEscalation: false @@ -637,7 +637,7 @@ should set securityContext when set in values: containers: - args: - --diag-addr=0.0.0.0:3000 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -705,7 +705,7 @@ should set securityContext when set in values: - wait - no-resolve - RELEASE-NAME-auth-v15.NAMESPACE.svc.cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 name: wait-auth-update securityContext: allowPrivilegeEscalation: false diff --git a/examples/chart/teleport-cluster/values.yaml b/examples/chart/teleport-cluster/values.yaml index d4b70bec775e0..526f1ed85518b 100644 --- a/examples/chart/teleport-cluster/values.yaml +++ b/examples/chart/teleport-cluster/values.yaml @@ -287,7 +287,7 @@ global: clusterDomain: cluster.local # Labels is a map of key-value pairs about this cluster. Those labels are used -# in Teleport to access the Kuebrnetes cluster. They must not be confused with +# in Teleport to access the Kubernetes cluster. They must not be confused with # `extraLabels` which are additional labels to add on Kubernetes resources # created by the Helm chart. labels: {} diff --git a/examples/chart/teleport-kube-agent/Chart.yaml b/examples/chart/teleport-kube-agent/Chart.yaml index fdb785214d7f9..44e8f099d3563 100644 --- a/examples/chart/teleport-kube-agent/Chart.yaml +++ b/examples/chart/teleport-kube-agent/Chart.yaml @@ -1,4 +1,4 @@ -.version: &version "16.1.0" +.version: &version "16.1.4" name: teleport-kube-agent apiVersion: v2 diff --git a/examples/chart/teleport-kube-agent/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/teleport-kube-agent/tests/__snapshot__/deployment_test.yaml.snap index e23333cb6ac15..d8bd30b1b78f0 100644 --- a/examples/chart/teleport-kube-agent/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/teleport-kube-agent/tests/__snapshot__/deployment_test.yaml.snap @@ -32,7 +32,7 @@ sets Deployment annotations when specified if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -109,7 +109,7 @@ sets Deployment labels when specified if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -173,7 +173,7 @@ sets Pod annotations when specified if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -237,7 +237,7 @@ sets Pod labels when specified if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -322,7 +322,7 @@ should add emptyDir for data when existingDataVolume is not set if action is Upg value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -387,7 +387,7 @@ should add insecureSkipProxyTLSVerify to args when set in values if action is Up value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -451,7 +451,7 @@ should correctly configure existingDataVolume when set if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -513,7 +513,7 @@ should expose diag port if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -589,7 +589,7 @@ should have multiple replicas when replicaCount is set (using .replicaCount, dep value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -665,7 +665,7 @@ should have multiple replicas when replicaCount is set (using highAvailability.r value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -729,7 +729,7 @@ should have one replica when replicaCount is not set if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -793,7 +793,7 @@ should mount extraVolumes and extraVolumeMounts if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -862,7 +862,7 @@ should mount jamfCredentialsSecret if it already exists and when role is jamf an value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -932,7 +932,7 @@ should mount jamfCredentialsSecret.name when role is jamf and action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1004,7 +1004,7 @@ should mount tls.existingCASecretName and set environment when set in values if value: cluster.local - name: SSL_CERT_FILE value: /etc/teleport-tls-ca/ca.pem - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1078,7 +1078,7 @@ should mount tls.existingCASecretName and set extra environment when set in valu value: http://username:password@my.proxy.host:3128 - name: SSL_CERT_FILE value: /etc/teleport-tls-ca/ca.pem - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1148,7 +1148,7 @@ should provision initContainer correctly when set in values if action is Upgrade value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1270,7 +1270,7 @@ should set affinity when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1334,7 +1334,7 @@ should set default serviceAccountName when not set in values if action is Upgrad value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1411,7 +1411,7 @@ should set environment when extraEnv set in values if action is Upgrade: value: cluster.local - name: HTTPS_PROXY value: http://username:password@my.proxy.host:3128 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1539,7 +1539,7 @@ should set imagePullPolicy when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: Always livenessProbe: failureThreshold: 6 @@ -1603,7 +1603,7 @@ should set nodeSelector if set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1669,7 +1669,7 @@ should set not set priorityClassName when not set in values if action is Upgrade value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1745,7 +1745,7 @@ should set preferred affinity when more than one replica is used if action is Up value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1809,7 +1809,7 @@ should set priorityClassName when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1874,7 +1874,7 @@ should set probeTimeoutSeconds when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1948,7 +1948,7 @@ should set required affinity when highAvailability.requireAntiAffinity is set if value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2012,7 +2012,7 @@ should set resources when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2083,7 +2083,7 @@ should set serviceAccountName when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2147,7 +2147,7 @@ should set tolerations when set in values if action is Upgrade: value: "true" - name: TELEPORT_KUBE_CLUSTER_DOMAIN value: cluster.local - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 diff --git a/examples/chart/teleport-kube-agent/tests/__snapshot__/job_test.yaml.snap b/examples/chart/teleport-kube-agent/tests/__snapshot__/job_test.yaml.snap index 82105dc401c82..4fc21e36aaa82 100644 --- a/examples/chart/teleport-kube-agent/tests/__snapshot__/job_test.yaml.snap +++ b/examples/chart/teleport-kube-agent/tests/__snapshot__/job_test.yaml.snap @@ -25,7 +25,7 @@ should create ServiceAccount for post-delete hook by default: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent name: post-delete-job securityContext: @@ -106,7 +106,7 @@ should not create ServiceAccount for post-delete hook if serviceAccount.create i fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent name: post-delete-job securityContext: @@ -136,7 +136,7 @@ should not create ServiceAccount, Role or RoleBinding for post-delete hook if se fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent name: post-delete-job securityContext: @@ -166,7 +166,7 @@ should set nodeSelector in post-delete hook: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent name: post-delete-job securityContext: diff --git a/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap b/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap index e668ef11fc4bd..5ca864660946a 100644 --- a/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap +++ b/examples/chart/teleport-kube-agent/tests/__snapshot__/statefulset_test.yaml.snap @@ -16,7 +16,7 @@ sets Pod annotations when specified: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -86,7 +86,7 @@ sets Pod labels when specified: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -180,7 +180,7 @@ sets StatefulSet labels when specified: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -282,7 +282,7 @@ should add insecureSkipProxyTLSVerify to args when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -352,7 +352,7 @@ should add volumeClaimTemplate for data volume when using StatefulSet and action fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -442,7 +442,7 @@ should add volumeClaimTemplate for data volume when using StatefulSet and is Fre fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -522,7 +522,7 @@ should add volumeMount for data volume when using StatefulSet: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -592,7 +592,7 @@ should expose diag port: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -662,7 +662,7 @@ should generate Statefulset when storage is disabled and mode is a Upgrade: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -746,7 +746,7 @@ should have multiple replicas when replicaCount is set (using .replicaCount, dep fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -828,7 +828,7 @@ should have multiple replicas when replicaCount is set (using highAvailability.r fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -898,7 +898,7 @@ should have one replica when replicaCount is not set: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -968,7 +968,7 @@ should install Statefulset when storage is disabled and mode is a Fresh Install: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1040,7 +1040,7 @@ should mount extraVolumes and extraVolumeMounts: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1115,7 +1115,7 @@ should mount jamfCredentialsSecret if it already exists and when role is jamf: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1193,7 +1193,7 @@ should mount jamfCredentialsSecret.name when role is jamf: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1273,7 +1273,7 @@ should mount tls.existingCASecretName and set environment when set in values: value: RELEASE-NAME - name: SSL_CERT_FILE value: /etc/teleport-tls-ca/ca.pem - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1355,7 +1355,7 @@ should mount tls.existingCASecretName and set extra environment when set in valu value: /etc/teleport-tls-ca/ca.pem - name: HTTPS_PROXY value: http://username:password@my.proxy.host:3128 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1433,7 +1433,7 @@ should not add emptyDir for data when using StatefulSet: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1503,7 +1503,7 @@ should provision initContainer correctly when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1631,7 +1631,7 @@ should set affinity when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1701,7 +1701,7 @@ should set default serviceAccountName when not set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1784,7 +1784,7 @@ should set environment when extraEnv set in values: value: RELEASE-NAME - name: HTTPS_PROXY value: http://username:password@my.proxy.host:3128 - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -1924,7 +1924,7 @@ should set imagePullPolicy when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: Always livenessProbe: failureThreshold: 6 @@ -1994,7 +1994,7 @@ should set nodeSelector if set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2078,7 +2078,7 @@ should set preferred affinity when more than one replica is used: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2148,7 +2148,7 @@ should set probeTimeoutSeconds when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2228,7 +2228,7 @@ should set required affinity when highAvailability.requireAntiAffinity is set: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2298,7 +2298,7 @@ should set resources when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2375,7 +2375,7 @@ should set serviceAccountName when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2445,7 +2445,7 @@ should set storage.requests when set in values and action is an Upgrade: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2515,7 +2515,7 @@ should set storage.storageClassName when set in values and action is an Upgrade: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -2585,7 +2585,7 @@ should set tolerations when set in values: fieldPath: metadata.namespace - name: RELEASE_NAME value: RELEASE-NAME - image: public.ecr.aws/gravitational/teleport-distroless:16.1.0 + image: public.ecr.aws/gravitational/teleport-distroless:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 diff --git a/examples/chart/teleport-kube-agent/tests/__snapshot__/updater_deployment_test.yaml.snap b/examples/chart/teleport-kube-agent/tests/__snapshot__/updater_deployment_test.yaml.snap index 326ca9952cced..c9ffe3a1f9fe1 100644 --- a/examples/chart/teleport-kube-agent/tests/__snapshot__/updater_deployment_test.yaml.snap +++ b/examples/chart/teleport-kube-agent/tests/__snapshot__/updater_deployment_test.yaml.snap @@ -27,7 +27,7 @@ sets the affinity: - --base-image=public.ecr.aws/gravitational/teleport-distroless - --version-server=https://my-custom-version-server/v1 - --version-channel=custom/preview - image: public.ecr.aws/gravitational/teleport-kube-agent-updater:16.1.0 + image: public.ecr.aws/gravitational/teleport-kube-agent-updater:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 @@ -73,7 +73,7 @@ sets the tolerations: - --base-image=public.ecr.aws/gravitational/teleport-distroless - --version-server=https://my-custom-version-server/v1 - --version-channel=custom/preview - image: public.ecr.aws/gravitational/teleport-kube-agent-updater:16.1.0 + image: public.ecr.aws/gravitational/teleport-kube-agent-updater:16.1.4 imagePullPolicy: IfNotPresent livenessProbe: failureThreshold: 6 diff --git a/examples/resources/adfs-connector.yaml b/examples/resources/adfs-connector.yaml index 98efa8e19d1a8..2fe06392411cd 100644 --- a/examples/resources/adfs-connector.yaml +++ b/examples/resources/adfs-connector.yaml @@ -62,3 +62,15 @@ spec: - name: "http://schemas.xmlsoap.org/claims/Group" value: "Users" roles: ["access"] + + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' diff --git a/examples/resources/github.yaml b/examples/resources/github.yaml index 38fa67072a2d1..7cc0d197dc443 100644 --- a/examples/resources/github.yaml +++ b/examples/resources/github.yaml @@ -20,3 +20,14 @@ spec: - editor organization: team: + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' diff --git a/examples/resources/gworkspace-connector-inline.yaml b/examples/resources/gworkspace-connector-inline.yaml index f1ea91b7d2ea2..d69997c40b5ce 100644 --- a/examples/resources/gworkspace-connector-inline.yaml +++ b/examples/resources/gworkspace-connector-inline.yaml @@ -33,4 +33,15 @@ spec: scope: - openid - email + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' version: v3 diff --git a/examples/resources/gworkspace-connector.yaml b/examples/resources/gworkspace-connector.yaml index 5e31b8b6b5148..5b1d0bc83575a 100644 --- a/examples/resources/gworkspace-connector.yaml +++ b/examples/resources/gworkspace-connector.yaml @@ -21,4 +21,15 @@ spec: scope: - openid - email + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' version: v3 diff --git a/examples/resources/oidc-connector.yaml b/examples/resources/oidc-connector.yaml index 33dfb5e28d8f2..5cb0ca0658fc1 100644 --- a/examples/resources/oidc-connector.yaml +++ b/examples/resources/oidc-connector.yaml @@ -16,4 +16,15 @@ spec: issuer_url: https://idp.example.com/ redirect_url: https://mytenant.teleport.sh:443/v1/webapi/oidc/callback max_age: 24h + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' version: v3 diff --git a/examples/resources/onelogin-connector.yaml b/examples/resources/onelogin-connector.yaml index cb88657208eaa..3e6e37aa76101 100644 --- a/examples/resources/onelogin-connector.yaml +++ b/examples/resources/onelogin-connector.yaml @@ -23,4 +23,15 @@ spec: issuer: "" service_provider_issuer: https://teleport.example.com:443/v1/webapi/saml/acs/onelogin sso: "" + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' version: v2 \ No newline at end of file diff --git a/examples/resources/saml-connector.yaml b/examples/resources/saml-connector.yaml index 43e94f227004a..d439adbfcda49 100644 --- a/examples/resources/saml-connector.yaml +++ b/examples/resources/saml-connector.yaml @@ -31,4 +31,15 @@ spec: # Optional SAML Single Logout endpoint. If set, logging out of Teleport # will also log the user out of the SAML provider session. single_logout_url: https://example.okta.com/app/your-app-id/slo/saml + client_redirect_settings: + # a list of hostnames allowed for HTTPS client redirect URLs + # can be a regex pattern + allowed_https_hostnames: + - remote.machine + - '*.app.github.dev' + - '^\d+-[a-zA-Z0-9]+\.foo.internal$' + # a list of CIDRs allowed for HTTP or HTTPS client redirect URLs + insecure_allowed_cidr_ranges: + - '192.168.1.0/24' + - '2001:db8::/96' \ No newline at end of file diff --git a/examples/service-discovery-api-client/go.mod b/examples/service-discovery-api-client/go.mod index b391f9995a84f..f39e5c1b89e5e 100644 --- a/examples/service-discovery-api-client/go.mod +++ b/examples/service-discovery-api-client/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.2 require ( - github.com/docker/docker v26.0.2+incompatible + github.com/docker/docker v26.1.5+incompatible github.com/gravitational/teleport/api v0.0.0-20240220221413-126de63e7e40 github.com/gravitational/trace v1.3.1 google.golang.org/grpc v1.63.0 diff --git a/examples/service-discovery-api-client/go.sum b/examples/service-discovery-api-client/go.sum index ec18cb6c8a9dc..dddb385e9e1eb 100644 --- a/examples/service-discovery-api-client/go.sum +++ b/examples/service-discovery-api-client/go.sum @@ -37,8 +37,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE= -github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= diff --git a/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go b/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go index cec9257d5e554..c7992b01c7f86 100644 --- a/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go @@ -48,6 +48,7 @@ const ( BackgroundItemStatus_BACKGROUND_ITEM_STATUS_ENABLED BackgroundItemStatus = 2 BackgroundItemStatus_BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL BackgroundItemStatus = 3 BackgroundItemStatus_BACKGROUND_ITEM_STATUS_NOT_FOUND BackgroundItemStatus = 4 + BackgroundItemStatus_BACKGROUND_ITEM_STATUS_NOT_SUPPORTED BackgroundItemStatus = 5 ) // Enum value maps for BackgroundItemStatus. @@ -58,6 +59,7 @@ var ( 2: "BACKGROUND_ITEM_STATUS_ENABLED", 3: "BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL", 4: "BACKGROUND_ITEM_STATUS_NOT_FOUND", + 5: "BACKGROUND_ITEM_STATUS_NOT_SUPPORTED", } BackgroundItemStatus_value = map[string]int32{ "BACKGROUND_ITEM_STATUS_UNSPECIFIED": 0, @@ -65,6 +67,7 @@ var ( "BACKGROUND_ITEM_STATUS_ENABLED": 2, "BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL": 3, "BACKGROUND_ITEM_STATUS_NOT_FOUND": 4, + "BACKGROUND_ITEM_STATUS_NOT_SUPPORTED": 5, } ) @@ -452,7 +455,7 @@ var file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDesc = []byte{ 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, - 0xe1, 0x01, 0x0a, 0x14, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, + 0x8b, 0x02, 0x0a, 0x14, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x26, 0x0a, 0x22, 0x42, 0x41, 0x43, 0x4b, 0x47, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, @@ -466,43 +469,46 @@ var file_teleport_lib_teleterm_vnet_v1_vnet_service_proto_rawDesc = []byte{ 0x45, 0x53, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x42, 0x41, 0x43, 0x4b, 0x47, 0x52, 0x4f, 0x55, 0x4e, 0x44, 0x5f, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x46, 0x4f, 0x55, 0x4e, - 0x44, 0x10, 0x04, 0x32, 0xe6, 0x03, 0x0a, 0x0b, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2b, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x44, 0x10, 0x04, 0x12, 0x28, 0x0a, 0x24, 0x42, 0x41, 0x43, 0x4b, 0x47, 0x52, 0x4f, 0x55, 0x4e, + 0x44, 0x5f, 0x49, 0x54, 0x45, 0x4d, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, 0x4f, + 0x54, 0x5f, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x05, 0x32, 0xe6, 0x03, + 0x0a, 0x0b, 0x56, 0x6e, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, + 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5f, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, - 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x12, - 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x77, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, - 0x44, 0x4e, 0x53, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, - 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x4e, 0x53, - 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x44, 0x4e, 0x53, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x98, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, - 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3d, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x55, 0x5a, 0x53, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x6e, 0x65, - 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, + 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x77, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x4e, 0x53, 0x5a, 0x6f, 0x6e, + 0x65, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6c, 0x69, + 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, 0x6e, 0x65, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x4e, 0x53, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x4e, 0x53, 0x5a, 0x6f, + 0x6e, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x98, 0x01, 0x0a, 0x17, + 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, + 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, + 0x76, 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, + 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2e, 0x76, + 0x6e, 0x65, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x67, 0x72, + 0x6f, 0x75, 0x6e, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x55, 0x5a, 0x53, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x2f, 0x76, + 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x76, 0x6e, 0x65, 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gen/proto/ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb.ts b/gen/proto/ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb.ts index 4943b89350b34..c9a8b7aa6bea2 100644 --- a/gen/proto/ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb.ts +++ b/gen/proto/ts/teleport/lib/teleterm/vnet/v1/vnet_service_pb.ts @@ -125,7 +125,11 @@ export enum BackgroundItemStatus { /** * @generated from protobuf enum value: BACKGROUND_ITEM_STATUS_NOT_FOUND = 4; */ - NOT_FOUND = 4 + NOT_FOUND = 4, + /** + * @generated from protobuf enum value: BACKGROUND_ITEM_STATUS_NOT_SUPPORTED = 5; + */ + NOT_SUPPORTED = 5 } // @generated message type with reflection information, may provide speed optimized methods class StartRequest$Type extends MessageType { diff --git a/go.mod b/go.mod index 35aab3a2177db..b33b44a5843cc 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/gravitational/teleport -go 1.22.0 - -toolchain go1.22.5 +go 1.22.6 require ( cloud.google.com/go/cloudsqlconn v1.9.0 @@ -164,6 +162,7 @@ require ( github.com/schollz/progressbar/v3 v3.14.2 github.com/scim2/filter-parser/v2 v2.2.0 github.com/segmentio/parquet-go v0.0.0-20230712180008-5d42db8f0d47 + github.com/shirou/gopsutil/v4 v4.24.6 github.com/sigstore/cosign/v2 v2.2.4 github.com/sigstore/sigstore v1.8.3 github.com/sijms/go-ora/v2 v2.8.10 @@ -301,7 +300,7 @@ require ( github.com/dmarkham/enumer v1.5.9 // indirect github.com/docker/cli v25.0.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v26.0.2+incompatible // indirect + github.com/docker/docker v26.1.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect @@ -330,6 +329,7 @@ require ( github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/analysis v0.23.0 // indirect github.com/go-openapi/errors v0.22.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -408,6 +408,7 @@ require ( github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lithammer/dedent v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect @@ -452,6 +453,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pkg/xattr v0.4.9 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/prometheus/procfs v0.13.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect @@ -469,6 +471,7 @@ require ( github.com/segmentio/encoding v0.4.0 // indirect github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect @@ -485,6 +488,8 @@ require ( github.com/thales-e-security/pool v0.0.2 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/weppos/publicsuffix-go v0.30.1-0.20230620154423-38c92ad2d5c6 // indirect @@ -499,6 +504,7 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/yuin/gopher-lua v1.1.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zeebo/errs v1.3.0 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect @@ -522,7 +528,7 @@ require ( k8s.io/component-helpers v0.29.3 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/metrics v0.29.3 // indirect - k8s.io/utils v0.0.0-20240102154912-e7106e64919e // indirect + k8s.io/utils v0.0.0-20240102154912-e7106e64919e mvdan.cc/sh/v3 v3.7.0 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect @@ -536,6 +542,7 @@ require ( replace ( github.com/alecthomas/kingpin/v2 => github.com/gravitational/kingpin/v2 v2.1.11-0.20230515143221-4ec6b70ecd33 github.com/coreos/go-oidc => github.com/gravitational/go-oidc v0.1.1 + github.com/crewjam/saml => github.com/gravitational/saml v0.4.15-teleport.1 github.com/datastax/go-cassandra-native-protocol => github.com/gravitational/go-cassandra-native-protocol v0.0.0-20221005103706-b9e66c056e90 github.com/go-mysql-org/go-mysql => github.com/gravitational/go-mysql v1.5.0-teleport.1 github.com/gogo/protobuf => github.com/gravitational/protobuf v1.3.2-teleport.1 diff --git a/go.sum b/go.sum index 4aeb6f8d9c316..3588e1d39cfe2 100644 --- a/go.sum +++ b/go.sum @@ -1054,8 +1054,6 @@ github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo= github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= -github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= -github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= @@ -1101,8 +1099,8 @@ github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbT github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE= -github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -1242,6 +1240,8 @@ 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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= @@ -1540,6 +1540,8 @@ github.com/gravitational/redis/v9 v9.0.2-teleport.2 h1:br9gSGJLpfrIoKsF5N99zWgjP github.com/gravitational/redis/v9 v9.0.2-teleport.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= github.com/gravitational/roundtrip v1.0.2 h1:eOCY0NEKKaB0ksJmvhO6lPMFz1pIIef+vyPBTBROQ5c= github.com/gravitational/roundtrip v1.0.2/go.mod h1:fuI1booM2hLRA/B/m5MRAPOU6mBZNYcNycono2UuTw0= +github.com/gravitational/saml v0.4.15-teleport.1 h1:kYSLpxEBEc7JLJJ+VjsZU8PbWI4gWxdCgll5cq1/rGU= +github.com/gravitational/saml v0.4.15-teleport.1/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= github.com/gravitational/spdystream v0.0.0-20230512133543-4e46862ca9bf h1:aXnqDSit8L1qhI0+QdbJh+MTUFKXG7qbkZXnfr7L96A= github.com/gravitational/spdystream v0.0.0-20230512133543-4e46862ca9bf/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/gravitational/trace v1.4.0 h1:TtTeMElVwMX21Udb1nmK2tpWYAAMJoyjevzKOaxIFZQ= @@ -1797,6 +1799,8 @@ github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffkt github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= @@ -2029,6 +2033,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= @@ -2131,6 +2137,12 @@ github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df h1:S77Pf5fIG github.com/shabbyrobe/gocovmerge v0.0.0-20230507112040-c3350d9342df/go.mod h1:dcuzJZ83w/SqN9k4eQqwKYMgmKWzg/KzJAURBhRL1tc= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= +github.com/shirou/gopsutil/v4 v4.24.6 h1:9qqCSYF2pgOU+t+NgJtp7Co5+5mHF/HyKBUckySQL64= +github.com/shirou/gopsutil/v4 v4.24.6/go.mod h1:aoebb2vxetJ/yIDZISmduFvVNPHqXQ9SEJwRXxkf0RA= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= @@ -2227,6 +2239,10 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= @@ -2277,6 +2293,8 @@ github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= @@ -2618,6 +2636,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2647,6 +2666,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2704,6 +2724,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/integration/appaccess/appaccess_test.go b/integration/appaccess/appaccess_test.go index 928b0f039a6f7..0b4b1965dbd18 100644 --- a/integration/appaccess/appaccess_test.go +++ b/integration/appaccess/appaccess_test.go @@ -40,6 +40,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib/reverseproxy" @@ -265,7 +266,9 @@ func testClientCert(p *Pack, t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - App: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.App: {Enabled: true}, + }, }, }) evilUser, _ := p.CreateUser(t) diff --git a/integration/db/db_integration_test.go b/integration/db/db_integration_test.go index 21870f54b6611..ee87900db716d 100644 --- a/integration/db/db_integration_test.go +++ b/integration/db/db_integration_test.go @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" @@ -108,7 +109,11 @@ func TestDatabaseAccessSeparateListeners(t *testing.T) { func (p *DatabasePack) testIPPinning(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, - TestFeatures: modules.Features{DB: true}, + TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.DB: {Enabled: true}, + }, + }, }) type testCase struct { diff --git a/integration/hsm/hsm_test.go b/integration/hsm/hsm_test.go index f5556ad724595..5c7427b06a148 100644 --- a/integration/hsm/hsm_test.go +++ b/integration/hsm/hsm_test.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport/api/breaker" "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/keystore" "github.com/gravitational/teleport/lib/auth/state" @@ -56,7 +57,9 @@ func TestMain(m *testing.M) { modules.SetModules(&modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - HSM: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.HSM: {Enabled: true}, + }, }, }) diff --git a/integration/integration_test.go b/integration/integration_test.go index 233e0609c48bb..592379d74f945 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -491,7 +491,7 @@ func testAuditOn(t *testing.T, suite *integrationTestSuite) { // wait until we've found the session in the audit log getSession := func(site authclient.ClientI) (types.SessionTracker, error) { - timeout, cancel := context.WithTimeout(context.Background(), 10*time.Second) + timeout, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() sessions, err := waitForSessionToBeEstablished(timeout, defaults.Namespace, site) if err != nil { @@ -519,7 +519,7 @@ func testAuditOn(t *testing.T, suite *integrationTestSuite) { select { case err := <-endC: require.NoError(t, err) - case <-time.After(10 * time.Second): + case <-time.After(15 * time.Second): t.Fatalf("%s: Timeout waiting for session to finish.", tt.comment) } @@ -1250,7 +1250,7 @@ func testLeafProxySessionRecording(t *testing.T, suite *integrationTestSuite) { return } sessionID = trackers[0].GetSessionID() - }, time.Second*5, time.Millisecond*100) + }, time.Second*15, time.Millisecond*100) // Send stuff to the session. term.Type("echo Hello\n\r") @@ -1264,7 +1264,7 @@ func testLeafProxySessionRecording(t *testing.T, suite *integrationTestSuite) { // Wait for the session to terminate without error. term.Type("exit\n\r") - require.NoError(t, waitForError(errCh, 5*time.Second)) + require.NoError(t, waitForError(errCh, 15*time.Second)) // Wait for the session recording to be uploaded and available var uploaded bool @@ -1284,7 +1284,7 @@ func testLeafProxySessionRecording(t *testing.T, suite *integrationTestSuite) { events, err := authSrv.GetSessionEvents(defaults.Namespace, session.ID(sessionID), 0) assert.NoError(t, err) assert.NotEmpty(t, events) - }, 5*time.Second, 200*time.Millisecond) + }, 15*time.Second, 200*time.Millisecond) }) } } @@ -1896,7 +1896,7 @@ func testShutdown(t *testing.T, suite *integrationTestSuite) { select { case err := <-sshErr: require.NoError(t, err) - case <-time.After(5 * time.Second): + case <-time.After(15 * time.Second): require.FailNow(t, "failed to shutdown ssh session") } @@ -8548,7 +8548,7 @@ func TestConnectivityWithoutAuth(t *testing.T) { select { case err := <-errChan: require.NoError(t, err) - case <-time.After(5 * time.Second): + case <-time.After(15 * time.Second): t.Fatal("timeout waiting for session to exit") } require.Contains(t, term.AllOutput(), "hi") @@ -8580,7 +8580,7 @@ func TestConnectivityWithoutAuth(t *testing.T) { if !authRunning { require.Empty(t, term.AllOutput()) } - case <-time.After(5 * time.Second): + case <-time.After(15 * time.Second): t.Fatal("timeout waiting for session to exit") } }, diff --git a/integration/kube_integration_test.go b/integration/kube_integration_test.go index bcf21232a6062..5f4761a96a870 100644 --- a/integration/kube_integration_test.go +++ b/integration/kube_integration_test.go @@ -72,6 +72,7 @@ import ( apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/profile" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/integration/kube" "github.com/gravitational/teleport/lib" @@ -1345,7 +1346,9 @@ func testKubeEphemeralContainers(t *testing.T, suite *KubeSuite) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - Kubernetes: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + }, }, }) diff --git a/integration/proxy/proxy_tunnel_strategy_test.go b/integration/proxy/proxy_tunnel_strategy_test.go index 3030534d17efc..bf89cf46506e9 100644 --- a/integration/proxy/proxy_tunnel_strategy_test.go +++ b/integration/proxy/proxy_tunnel_strategy_test.go @@ -33,6 +33,7 @@ import ( apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" @@ -158,7 +159,11 @@ func TestProxyTunnelStrategyProxyPeering(t *testing.T) { // This test cannot run in parallel as set module changes the global state. modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, - TestFeatures: modules.Features{DB: true}, + TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.DB: {Enabled: true}, + }, + }, }) p := newProxyTunnelStrategy(t, "proxy-tunnel-proxy-peer", diff --git a/integrations/access/accesslist/app_test.go b/integrations/access/accesslist/app_test.go index ebb8a1fb3d084..6d4eab0ada7d6 100644 --- a/integrations/access/accesslist/app_test.go +++ b/integrations/access/accesslist/app_test.go @@ -33,6 +33,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integrations/access/common" "github.com/gravitational/teleport/integrations/access/common/teleport" "github.com/gravitational/teleport/lib/auth" @@ -204,7 +205,9 @@ func TestAccessListReminders_Single(t *testing.T) { func TestAccessListReminders_Batched(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - IdentityGovernanceSecurity: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.AccessLists: {Enabled: true}, + }, }, }) diff --git a/integrations/access/common.mk b/integrations/access/common.mk index ac3f39f158219..ee77ce7fa380a 100644 --- a/integrations/access/common.mk +++ b/integrations/access/common.mk @@ -6,7 +6,7 @@ VERSION ?= $(shell go run ../../hack/get-version/get-version.go) BUILDDIR ?= build BINARY = $(BUILDDIR)/teleport-$(ACCESS_PLUGIN) ADDFLAGS ?= -BUILDFLAGS ?= $(ADDFLAGS) -ldflags "-w -s" +BUILDFLAGS ?= $(ADDFLAGS) -trimpath -ldflags "-w -s" CGOFLAG ?= CGO_ENABLED=0 OS ?= $(shell go env GOOS) diff --git a/integrations/access/msteams/msapi/graph_client.go b/integrations/access/msteams/msapi/graph_client.go index 4c7c66da889ee..0b142b0d9242e 100644 --- a/integrations/access/msteams/msapi/graph_client.go +++ b/integrations/access/msteams/msapi/graph_client.go @@ -101,8 +101,8 @@ func (e graphError) Error() string { // GetErrorCode returns the func GetErrorCode(err error) string { - var graphErr *graphError - ok := errors.As(err, graphErr) + var graphErr graphError + ok := errors.As(err, &graphErr) if !ok { return "" } diff --git a/integrations/event-handler/Makefile b/integrations/event-handler/Makefile index 1cb18389d8002..f4fd8850d1a1e 100644 --- a/integrations/event-handler/Makefile +++ b/integrations/event-handler/Makefile @@ -17,7 +17,7 @@ BINARY = $(BUILDDIR)/teleport-event-handler GITREF ?= $(shell git describe --dirty --long --tags --match '$(VERSION)') ADDFLAGS ?= -BUILDFLAGS ?= $(ADDFLAGS) -ldflags "-w -s -X main.Gitref=$(GITREF) -X main.Version=$(VERSION)" +BUILDFLAGS ?= $(ADDFLAGS) -trimpath -ldflags "-w -s -X main.Gitref=$(GITREF) -X main.Version=$(VERSION)" CGOFLAG ?= CGO_ENABLED=0 PASS ?= 1234 @@ -58,7 +58,7 @@ release: build tar -czf $(RELEASE).tar.gz $(RELEASE_NAME) rm -rf $(RELEASE_NAME)/ @echo "---> Created $(RELEASE).tar.gz." - + .PHONY: clean clean: @@ -96,7 +96,7 @@ configure: build .PHONY: fluentd fluentd: - docker run -p 8888:8888 -v $(LOCALDIR)tmp:/keys -v $(LOCALDIR)tmp/fluent.conf:/fluentd/etc/fluent.conf fluent/fluentd:edge + docker run -p 8888:8888 -v $(LOCALDIR)tmp:/keys -v $(LOCALDIR)tmp/fluent.conf:/fluentd/etc/fluent.conf fluent/fluentd:edge .PHONY: example example: build diff --git a/integrations/event-handler/events_job.go b/integrations/event-handler/events_job.go index 3362cb19b2c5a..54229b1daf563 100644 --- a/integrations/event-handler/events_job.go +++ b/integrations/event-handler/events_job.go @@ -16,6 +16,7 @@ package main import ( "context" + "time" "github.com/gravitational/trace" limiter "github.com/sethvargo/go-limiter" @@ -91,6 +92,11 @@ func (j *EventsJob) runPolling(ctx context.Context) error { evtCh, errCh := j.app.EventWatcher.Events(ctx) + logTicker := time.NewTicker(time.Minute) + defer logTicker.Stop() + + var eventsProcessed int + for { select { case err := <-errCh: @@ -107,6 +113,10 @@ func (j *EventsJob) runPolling(ctx context.Context) error { return trace.Wrap(err) } + eventsProcessed++ + case <-logTicker.C: + log.WithField("events_per_minute", eventsProcessed).Info("event processing rate") + eventsProcessed = 0 case <-ctx.Done(): return ctx.Err() } diff --git a/integrations/event-handler/go.mod b/integrations/event-handler/go.mod index fb652fab3ad3e..a89fbc2679b07 100644 --- a/integrations/event-handler/go.mod +++ b/integrations/event-handler/go.mod @@ -1,8 +1,6 @@ module github.com/gravitational/teleport/integrations/event-handler -go 1.22.0 - -toolchain go1.22.5 +go 1.22.6 require ( github.com/alecthomas/kong v0.9.0 @@ -18,6 +16,7 @@ require ( github.com/sethvargo/go-limiter v1.0.0 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 + golang.org/x/time v0.5.0 google.golang.org/protobuf v1.34.1 ) @@ -115,7 +114,7 @@ require ( github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v25.0.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v26.0.2+incompatible // indirect + github.com/docker/docker v26.1.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect @@ -281,7 +280,6 @@ require ( golang.org/x/sys v0.21.0 // indirect golang.org/x/term v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.177.0 // indirect google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6 // indirect diff --git a/integrations/event-handler/go.sum b/integrations/event-handler/go.sum index 44d41a98ea244..9b1400d62fa62 100644 --- a/integrations/event-handler/go.sum +++ b/integrations/event-handler/go.sum @@ -884,8 +884,8 @@ github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbT github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE= -github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= diff --git a/integrations/event-handler/teleport_events_watcher.go b/integrations/event-handler/teleport_events_watcher.go index d35680523fa2f..0221b44aaefaf 100644 --- a/integrations/event-handler/teleport_events_watcher.go +++ b/integrations/event-handler/teleport_events_watcher.go @@ -24,6 +24,7 @@ import ( "github.com/gravitational/trace" log "github.com/sirupsen/logrus" + "golang.org/x/time/rate" "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/proto" @@ -304,13 +305,15 @@ func (t *TeleportEventsWatcher) pause(ctx context.Context) error { // Next returns next event from a batch or requests next batch if it has been ended func (t *TeleportEventsWatcher) Events(ctx context.Context) (chan *TeleportEvent, chan error) { - ch := make(chan *TeleportEvent) + ch := make(chan *TeleportEvent, t.config.BatchSize) e := make(chan error, 1) go func() { defer close(ch) defer close(e) + logLimiter := rate.NewLimiter(rate.Every(time.Minute), 6) + for { // If there is nothing in the batch, request if len(t.batch) == 0 { @@ -372,6 +375,18 @@ func (t *TeleportEventsWatcher) Events(ctx context.Context) (chan *TeleportEvent t.pos++ t.id = event.ID + // attempt non-blocking send first, falling back to blocking send + // if we encounter backpressure. + select { + case ch <- event: + continue + default: + } + + if logLimiter.Allow() { + log.Warn("encountering backpressure from outbound event processing") + } + select { case ch <- event: case <-ctx.Done(): diff --git a/integrations/operator/Dockerfile b/integrations/operator/Dockerfile index 7b3177df67613..9c7652003b75e 100644 --- a/integrations/operator/Dockerfile +++ b/integrations/operator/Dockerfile @@ -58,6 +58,7 @@ RUN go mod download COPY *.go ./ COPY lib/ lib/ COPY gen/ gen/ +COPY entitlements/ entitlements/ COPY integrations/lib/embeddedtbot/ integrations/lib/embeddedtbot/ COPY integrations/operator/apis/ integrations/operator/apis/ COPY integrations/operator/controllers/ integrations/operator/controllers/ diff --git a/integrations/operator/Dockerfile.gha b/integrations/operator/Dockerfile.gha index e3810c4232f5b..dba764f0beed3 100644 --- a/integrations/operator/Dockerfile.gha +++ b/integrations/operator/Dockerfile.gha @@ -75,6 +75,7 @@ RUN go mod download COPY *.go ./ COPY lib/ lib/ COPY gen/ gen/ +COPY entitlements/ entitlements/ COPY integrations/lib/embeddedtbot/ integrations/lib/embeddedtbot/ COPY integrations/operator/apis/ integrations/operator/apis/ COPY integrations/operator/controllers/ integrations/operator/controllers/ diff --git a/integrations/operator/Makefile b/integrations/operator/Makefile index cfecfdf34410a..c27a2ac19ac85 100644 --- a/integrations/operator/Makefile +++ b/integrations/operator/Makefile @@ -127,7 +127,7 @@ crdgen-test: ## Run crdgen tests. .PHONY: build build: generate fmt vet ## Build manager binary. - go build -o bin/manager main.go namespace.go config.go + go build -trimpath -o bin/manager main.go namespace.go config.go .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. diff --git a/integrations/operator/config/crd/bases/resources.teleport.dev_githubconnectors.yaml b/integrations/operator/config/crd/bases/resources.teleport.dev_githubconnectors.yaml index 78f55c60cda1f..a92d5dbf5eff8 100644 --- a/integrations/operator/config/crd/bases/resources.teleport.dev_githubconnectors.yaml +++ b/integrations/operator/config/crd/bases/resources.teleport.dev_githubconnectors.yaml @@ -55,6 +55,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object client_secret: description: ClientSecret is the Github OAuth app client secret. diff --git a/integrations/operator/config/crd/bases/resources.teleport.dev_oidcconnectors.yaml b/integrations/operator/config/crd/bases/resources.teleport.dev_oidcconnectors.yaml index aa3486d5ae3e4..b801cf6db84f4 100644 --- a/integrations/operator/config/crd/bases/resources.teleport.dev_oidcconnectors.yaml +++ b/integrations/operator/config/crd/bases/resources.teleport.dev_oidcconnectors.yaml @@ -80,6 +80,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object client_secret: description: ClientSecret is used to authenticate the client. diff --git a/integrations/operator/config/crd/bases/resources.teleport.dev_samlconnectors.yaml b/integrations/operator/config/crd/bases/resources.teleport.dev_samlconnectors.yaml index 4ffda895f0cd0..a4437220e61cb 100644 --- a/integrations/operator/config/crd/bases/resources.teleport.dev_samlconnectors.yaml +++ b/integrations/operator/config/crd/bases/resources.teleport.dev_samlconnectors.yaml @@ -95,6 +95,13 @@ spec: type: string nullable: true type: array + insecure_allowed_cidr_ranges: + description: a list of CIDRs allowed for HTTP or HTTPS client + redirect URLs + items: + type: string + nullable: true + type: array type: object display: description: Display controls how this connector is displayed. diff --git a/integrations/operator/config/crd/bases/resources.teleport.dev_users.yaml b/integrations/operator/config/crd/bases/resources.teleport.dev_users.yaml index f8720f714d3c9..0c5221f64b369 100644 --- a/integrations/operator/config/crd/bases/resources.teleport.dev_users.yaml +++ b/integrations/operator/config/crd/bases/resources.teleport.dev_users.yaml @@ -119,8 +119,12 @@ spec: type: object trusted_device_ids: description: TrustedDeviceIDs contains the IDs of trusted devices - enrolled by the user. Managed by the Device Trust subsystem, avoid - manual edits. + enrolled by the user. Note that SSO users are transient and thus + may contain an empty TrustedDeviceIDs field, even though the user->device + association exists under the Device Trust subsystem. Do not rely + on this field to determine device associations or ownership, it + exists for legacy/informative purposes only. Managed by the Device + Trust subsystem, avoid manual edits. items: type: string nullable: true diff --git a/integrations/operator/controllers/resources/setup.go b/integrations/operator/controllers/resources/setup.go index 174206857ffa9..4b97e6f95cc35 100644 --- a/integrations/operator/controllers/resources/setup.go +++ b/integrations/operator/controllers/resources/setup.go @@ -26,7 +26,9 @@ import ( "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/proto" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integrations/operator/controllers" + "github.com/gravitational/teleport/lib/modules" ) type reconcilerFactory struct { @@ -48,20 +50,23 @@ func SetupAllControllers(log logr.Logger, mgr manager.Manager, teleportClient *c {"TeleportOpenSSHEICEServerV2", NewOpenSSHEICEServerV2Reconciler}, } - if features.GetOIDC() { + oidc := modules.GetProtoEntitlement(features, entitlements.OIDC) + saml := modules.GetProtoEntitlement(features, entitlements.SAML) + + if oidc.Enabled { reconcilers = append(reconcilers, reconcilerFactory{"TeleportOIDCConnector", NewOIDCConnectorReconciler}) } else { log.Info("OIDC connectors are only available in Teleport Enterprise edition. TeleportOIDCConnector resources won't be reconciled") } - if features.GetSAML() { + if saml.Enabled { reconcilers = append(reconcilers, reconcilerFactory{"TeleportSAMLConnector", NewSAMLConnectorReconciler}) } else { log.Info("SAML connectors are only available in Teleport Enterprise edition. TeleportSAMLConnector resources won't be reconciled") } // Login Rules are enterprise-only but there is no specific feature flag for them. - if features.GetOIDC() || features.GetSAML() { + if oidc.Enabled || saml.Enabled { reconcilers = append(reconcilers, reconcilerFactory{"TeleportLoginRule", NewLoginRuleReconciler}) } else { log.Info("Login Rules are only available in Teleport Enterprise edition. TeleportLoginRule resources won't be reconciled") diff --git a/integrations/operator/controllers/resources/testlib/env.go b/integrations/operator/controllers/resources/testlib/env.go index 4f0dc33470c85..03b201b0b5946 100644 --- a/integrations/operator/controllers/resources/testlib/env.go +++ b/integrations/operator/controllers/resources/testlib/env.go @@ -46,6 +46,7 @@ import ( "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" resourcesv1 "github.com/gravitational/teleport/integrations/operator/apis/resources/v1" resourcesv2 "github.com/gravitational/teleport/integrations/operator/apis/resources/v2" @@ -99,8 +100,10 @@ func defaultTeleportServiceConfig(t *testing.T) (*helpers.TeleInstance, string) modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - OIDC: true, - SAML: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.OIDC: {Enabled: true}, + entitlements.SAML: {Enabled: true}, + }, }, }) diff --git a/integrations/operator/crdgen/testdata/protofiles/teleport/legacy/types/events/events.proto b/integrations/operator/crdgen/testdata/protofiles/teleport/legacy/types/events/events.proto index a47222154eaa8..704e84c47d7a8 100644 --- a/integrations/operator/crdgen/testdata/protofiles/teleport/legacy/types/events/events.proto +++ b/integrations/operator/crdgen/testdata/protofiles/teleport/legacy/types/events/events.proto @@ -3562,6 +3562,8 @@ message RouteToApp { string AzureIdentity = 6 [(gogoproto.jsontag) = "azure_identity,omitempty"]; // GCPServiceAccount is the GCP service account to assume when accessing GCP API. string GCPServiceAccount = 7 [(gogoproto.jsontag) = "gcp_service_account,omitempty"]; + // URI is the application URI. + string URI = 8 [(gogoproto.jsontag) = "uri,omitempty"]; } // RouteToDatabase combines parameters for database service routing information. diff --git a/integrations/teleport-spacelift-runner/Dockerfile b/integrations/teleport-spacelift-runner/Dockerfile index 6482e96742079..54624ab280e8e 100644 --- a/integrations/teleport-spacelift-runner/Dockerfile +++ b/integrations/teleport-spacelift-runner/Dockerfile @@ -20,6 +20,7 @@ COPY lib/ lib/ COPY api/ api/ COPY gen/ gen/ COPY build.assets/ build.assets/ +COPY entitlements/ entitlements/ COPY *.go ./ COPY Makefile Makefile COPY darwin-signing.mk darwin-signing.mk diff --git a/integrations/terraform/Makefile b/integrations/terraform/Makefile index d835003c1afc9..6e4a7ef7f7ac5 100644 --- a/integrations/terraform/Makefile +++ b/integrations/terraform/Makefile @@ -7,7 +7,8 @@ BUILDDIR ?= build TFDIR ?= example ADDFLAGS ?= -BUILDFLAGS ?= $(ADDFLAGS) -ldflags '-w -s' +BUILDFLAGS ?= $(ADDFLAGS) -trimpath -ldflags '-w -s' +# CGO must NOT be enabled as hashicorp cloud does not support running providers using on CGO. CGOFLAG ?= CGO_ENABLED=0 RELEASE = terraform-provider-teleport-v$(VERSION)-$(OS)-$(ARCH)-bin @@ -166,4 +167,4 @@ $(LOCALBIN): bin/tfplugindocs: go.mod $(LOCALBIN) mkdir -p bin - GOBIN=$(LOCALBIN) go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs \ No newline at end of file + GOBIN=$(LOCALBIN) go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs diff --git a/integrations/terraform/go.mod b/integrations/terraform/go.mod index 3f039a0a084c1..da4331cc79e5d 100644 --- a/integrations/terraform/go.mod +++ b/integrations/terraform/go.mod @@ -1,8 +1,6 @@ module github.com/gravitational/teleport/integrations/terraform -go 1.22.0 - -toolchain go1.22.5 +go 1.22.6 // Doc generation tooling require github.com/hashicorp/terraform-plugin-docs v0.0.0 // replaced @@ -130,7 +128,7 @@ require ( github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v25.0.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v26.0.2+incompatible // indirect + github.com/docker/docker v26.1.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect diff --git a/integrations/terraform/go.sum b/integrations/terraform/go.sum index d16c6ac592237..79f3cdcfc0a64 100644 --- a/integrations/terraform/go.sum +++ b/integrations/terraform/go.sum @@ -958,8 +958,8 @@ github.com/docker/cli v25.0.1+incompatible h1:mFpqnrS6Hsm3v1k7Wa/BO23oz0k121MTbT github.com/docker/cli v25.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v26.0.2+incompatible h1:yGVmKUFGgcxA6PXWAokO0sQL22BrQ67cgVjko8tGdXE= -github.com/docker/docker v26.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -1062,6 +1062,8 @@ github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= +github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= @@ -1829,6 +1831,8 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spiffe/go-spiffe/v2 v2.2.0 h1:9Vf06UsvsDbLYK/zJ4sYsIsHmMFknUD+feA7IYoWMQY= +github.com/spiffe/go-spiffe/v2 v2.2.0/go.mod h1:Urzb779b3+IwDJD2ZbN8fVl3Aa8G4N/PiUe6iXC0XxU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -1920,6 +1924,8 @@ github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8 github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= +github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= +github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= diff --git a/integrations/terraform/testlib/device_trust_test.go b/integrations/terraform/testlib/device_trust_test.go index e61d6e721ac3c..2d27ecd257e68 100644 --- a/integrations/terraform/testlib/device_trust_test.go +++ b/integrations/terraform/testlib/device_trust_test.go @@ -25,13 +25,15 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/stretchr/testify/require" - // devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/modules" ) func (s *TerraformSuiteEnterprise) TestTrustedDevices() { + deviceTrust := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.DeviceTrust) require.True(s.T(), - s.teleportFeatures.GetDeviceTrust().GetEnabled(), + deviceTrust.Enabled, "Test requires Device Trust", ) @@ -92,8 +94,9 @@ func (s *TerraformSuiteEnterprise) TestTrustedDevices() { } func (s *TerraformSuiteEnterprise) TestImportTrustedDevices() { + deviceTrust := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.DeviceTrust) require.True(s.T(), - s.teleportFeatures.GetDeviceTrust().GetEnabled(), + deviceTrust.Enabled, "Test requires Device Trust", ) diff --git a/integrations/terraform/testlib/loginrule_test.go b/integrations/terraform/testlib/loginrule_test.go index 84e7fc080d8be..07057c24ed57f 100644 --- a/integrations/terraform/testlib/loginrule_test.go +++ b/integrations/terraform/testlib/loginrule_test.go @@ -25,11 +25,15 @@ import ( loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/modules" ) func (s *TerraformSuiteEnterprise) TestLoginRule() { + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetOIDC() || s.teleportFeatures.GetSAML(), + oidc.Enabled || saml.Enabled, "Test requires enterprise version of teleport", ) @@ -108,9 +112,11 @@ func (s *TerraformSuiteEnterprise) TestLoginRule() { } func (s *TerraformSuiteEnterprise) TestImportLoginRule() { + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetOIDC() || s.teleportFeatures.GetSAML(), - "Test requires OIDC or SAML", + oidc.Enabled || saml.Enabled, + "Test requires enterprise version of teleport", ) ctx := context.Background() diff --git a/integrations/terraform/testlib/oidc_connector_test.go b/integrations/terraform/testlib/oidc_connector_test.go index 95e0c4d7ff315..95930313bc685 100644 --- a/integrations/terraform/testlib/oidc_connector_test.go +++ b/integrations/terraform/testlib/oidc_connector_test.go @@ -27,10 +27,16 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/wrappers" + "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/modules" ) func (s *TerraformSuiteEnterprise) TestOIDCConnector() { - require.True(s.T(), s.teleportFeatures.GetOIDC(), "Test requires OIDC") + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + require.True(s.T(), + oidc.Enabled, + "Test requires OIDC", + ) ctx, cancel := context.WithCancel(context.Background()) s.T().Cleanup(cancel) @@ -84,7 +90,11 @@ func (s *TerraformSuiteEnterprise) TestOIDCConnector() { } func (s *TerraformSuiteEnterprise) TestImportOIDCConnector() { - require.True(s.T(), s.teleportFeatures.GetOIDC(), "Test requires OIDC") + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + require.True(s.T(), + oidc.Enabled, + "Test requires OIDC", + ) ctx, cancel := context.WithCancel(context.Background()) s.T().Cleanup(cancel) @@ -144,7 +154,11 @@ func (s *TerraformSuiteEnterprise) TestImportOIDCConnector() { } func (s *TerraformSuiteEnterprise) TestOIDCConnectorWithoutMaxAge() { - require.True(s.T(), s.teleportFeatures.GetOIDC(), "Test requires OIDC") + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + require.True(s.T(), + oidc.Enabled, + "Test requires OIDC", + ) ctx, cancel := context.WithCancel(context.Background()) s.T().Cleanup(cancel) @@ -187,7 +201,11 @@ func (s *TerraformSuiteEnterprise) TestOIDCConnectorWithoutMaxAge() { } func (s *TerraformSuiteEnterprise) TestImportOIDCConnectorWithoutMaxAge() { - require.True(s.T(), s.teleportFeatures.GetOIDC(), "Test requires OIDC") + oidc := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.OIDC) + require.True(s.T(), + oidc.Enabled, + "Test requires OIDC", + ) ctx, cancel := context.WithCancel(context.Background()) s.T().Cleanup(cancel) diff --git a/integrations/terraform/testlib/saml_connector_test.go b/integrations/terraform/testlib/saml_connector_test.go index 223b91c61dfd8..6a3859b1c3ecb 100644 --- a/integrations/terraform/testlib/saml_connector_test.go +++ b/integrations/terraform/testlib/saml_connector_test.go @@ -29,11 +29,14 @@ import ( "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" + "github.com/gravitational/teleport/lib/modules" ) func (s *TerraformSuiteEnterprise) TestSAMLConnector() { + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetSAML(), + saml.Enabled, "Test requires SAML", ) @@ -88,8 +91,9 @@ func (s *TerraformSuiteEnterprise) TestSAMLConnector() { } func (s *TerraformSuiteEnterprise) TestImportSAMLConnector() { + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetSAML(), + saml.Enabled, "Test requires SAML", ) @@ -166,8 +170,9 @@ func (s *TerraformSuiteEnterprise) TestImportSAMLConnector() { } func (s *TerraformSuiteEnterprise) TestSAMLConnectorWithEntityDescriptorURL() { + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetSAML(), + saml.Enabled, "Test requires SAML", ) @@ -187,8 +192,9 @@ func (s *TerraformSuiteEnterprise) TestSAMLConnectorWithEntityDescriptorURL() { } func (s *TerraformSuiteEnterprise) TestSAMLConnectorWithoutEntityDescriptor() { + saml := modules.GetProtoEntitlement(s.teleportFeatures, entitlements.SAML) require.True(s.T(), - s.teleportFeatures.GetSAML(), + saml.Enabled, "Test requires SAML", ) diff --git a/integrations/terraform/tfschema/types_terraform.go b/integrations/terraform/tfschema/types_terraform.go index ffa073542eb50..5b77cc5b1dbf5 100644 --- a/integrations/terraform/tfschema/types_terraform.go +++ b/integrations/terraform/tfschema/types_terraform.go @@ -2556,7 +2556,7 @@ func GenSchemaUserV2(ctx context.Context) (github_com_hashicorp_terraform_plugin }, "traits": GenSchemaTraits(ctx), "trusted_device_ids": { - Description: "TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Managed by the Device Trust subsystem, avoid manual edits.", + Description: "TrustedDeviceIDs contains the IDs of trusted devices enrolled by the user. Note that SSO users are transient and thus may contain an empty TrustedDeviceIDs field, even though the user->device association exists under the Device Trust subsystem. Do not rely on this field to determine device associations or ownership, it exists for legacy/informative purposes only. Managed by the Device Trust subsystem, avoid manual edits.", Optional: true, Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, }, @@ -2683,11 +2683,18 @@ func GenSchemaOIDCConnectorV3(ctx context.Context) (github_com_hashicorp_terrafo Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, }, "client_redirect_settings": { - Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allowed_https_hostnames": { - Description: "a list of hostnames allowed for https client redirect URLs", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, - }}), + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "allowed_https_hostnames": { + Description: "a list of hostnames allowed for https client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "insecure_allowed_cidr_ranges": { + Description: "a list of CIDRs allowed for HTTP or HTTPS client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + }), Description: "ClientRedirectSettings defines which client redirect URLs are allowed for non-browser SSO logins other than the standard localhost ones.", Optional: true, }, @@ -2892,11 +2899,18 @@ func GenSchemaSAMLConnectorV2(ctx context.Context) (github_com_hashicorp_terrafo Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, }, "client_redirect_settings": { - Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allowed_https_hostnames": { - Description: "a list of hostnames allowed for https client redirect URLs", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, - }}), + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "allowed_https_hostnames": { + Description: "a list of hostnames allowed for https client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "insecure_allowed_cidr_ranges": { + Description: "a list of CIDRs allowed for HTTP or HTTPS client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + }), Description: "ClientRedirectSettings defines which client redirect URLs are allowed for non-browser SSO logins other than the standard localhost ones.", Optional: true, }, @@ -3059,11 +3073,18 @@ func GenSchemaGithubConnectorV3(ctx context.Context) (github_com_hashicorp_terra Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, }, "client_redirect_settings": { - Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allowed_https_hostnames": { - Description: "a list of hostnames allowed for https client redirect URLs", - Optional: true, - Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, - }}), + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "allowed_https_hostnames": { + Description: "a list of hostnames allowed for https client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "insecure_allowed_cidr_ranges": { + Description: "a list of CIDRs allowed for HTTP or HTTPS client redirect URLs", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.ListType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + }), Description: "ClientRedirectSettings defines which client redirect URLs are allowed for non-browser SSO logins other than the standard localhost ones.", Optional: true, }, @@ -27925,6 +27946,33 @@ func CopyOIDCConnectorV3FromTerraform(_ context.Context, tf github_com_hashicorp } } } + { + a, ok := tf.Attrs["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrReadMissingDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.InsecureAllowedCidrRanges = make([]string, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.InsecureAllowedCidrRanges[k] = t + } + } + } + } + } + } } } } @@ -28813,6 +28861,59 @@ func CopyOIDCConnectorV3ToTerraform(ctx context.Context, obj *github_com_gravita } } } + { + a, ok := tf.AttrTypes["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrWriteMissingDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + } + if obj.InsecureAllowedCidrRanges != nil { + t := o.ElemType + if len(obj.InsecureAllowedCidrRanges) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + for k, a := range obj.InsecureAllowedCidrRanges { + v, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"OIDCConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.InsecureAllowedCidrRanges) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["insecure_allowed_cidr_ranges"] = c + } + } + } } v.Unknown = false tf.Attrs["client_redirect_settings"] = v @@ -29446,6 +29547,33 @@ func CopySAMLConnectorV2FromTerraform(_ context.Context, tf github_com_hashicorp } } } + { + a, ok := tf.Attrs["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrReadMissingDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.InsecureAllowedCidrRanges = make([]string, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.InsecureAllowedCidrRanges[k] = t + } + } + } + } + } + } } } } @@ -30393,6 +30521,59 @@ func CopySAMLConnectorV2ToTerraform(ctx context.Context, obj *github_com_gravita } } } + { + a, ok := tf.AttrTypes["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrWriteMissingDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + } + if obj.InsecureAllowedCidrRanges != nil { + t := o.ElemType + if len(obj.InsecureAllowedCidrRanges) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + for k, a := range obj.InsecureAllowedCidrRanges { + v, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"SAMLConnectorV2.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.InsecureAllowedCidrRanges) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["insecure_allowed_cidr_ranges"] = c + } + } + } } v.Unknown = false tf.Attrs["client_redirect_settings"] = v @@ -31002,6 +31183,33 @@ func CopyGithubConnectorV3FromTerraform(_ context.Context, tf github_com_hashico } } } + { + a, ok := tf.Attrs["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrReadMissingDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.InsecureAllowedCidrRanges = make([]string, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.InsecureAllowedCidrRanges[k] = t + } + } + } + } + } + } } } } @@ -31929,6 +32137,59 @@ func CopyGithubConnectorV3ToTerraform(ctx context.Context, obj *github_com_gravi } } } + { + a, ok := tf.AttrTypes["insecure_allowed_cidr_ranges"] + if !ok { + diags.Append(attrWriteMissingDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + } + if obj.InsecureAllowedCidrRanges != nil { + t := o.ElemType + if len(obj.InsecureAllowedCidrRanges) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.InsecureAllowedCidrRanges)) + } + for k, a := range obj.InsecureAllowedCidrRanges { + v, ok := tf.Attrs["insecure_allowed_cidr_ranges"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"GithubConnectorV3.Spec.ClientRedirectSettings.insecure_allowed_cidr_ranges", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(a) == "" + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.InsecureAllowedCidrRanges) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["insecure_allowed_cidr_ranges"] = c + } + } + } } v.Unknown = false tf.Attrs["client_redirect_settings"] = v diff --git a/lib/auth/access.go b/lib/auth/access.go index 02551de0ecbeb..7284c82ed7586 100644 --- a/lib/auth/access.go +++ b/lib/auth/access.go @@ -142,7 +142,7 @@ func (a *Server) DeleteRole(ctx context.Context, name string) error { for { var accessLists []*accesslist.AccessList var err error - accessLists, nextToken, err = a.Services.AccessListClient().ListAccessLists(ctx, 0 /* default page size */, nextToken) + accessLists, nextToken, err = a.Services.AccessLists.ListAccessLists(ctx, 0 /* default page size */, nextToken) if err != nil { return trace.Wrap(err) } diff --git a/lib/auth/access_request_test.go b/lib/auth/access_request_test.go index 982c59b7804c9..faf59345a5bbf 100644 --- a/lib/auth/access_request_test.go +++ b/lib/auth/access_request_test.go @@ -44,6 +44,7 @@ import ( "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/backend/memory" @@ -1543,7 +1544,9 @@ func TestUpdateAccessRequestWithAdditionalReviewers(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - IdentityGovernanceSecurity: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Identity: {Enabled: true}, + }, }, }) diff --git a/lib/auth/accesspoint/accesspoint.go b/lib/auth/accesspoint/accesspoint.go index 9ed7fb66097c4..a526a239802f4 100644 --- a/lib/auth/accesspoint/accesspoint.go +++ b/lib/auth/accesspoint/accesspoint.go @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -// package accesspoint provides helpers for configuring caches in the context of +// Package accesspoint provides helpers for configuring caches in the context of // setting up service-level auth access points. this logic has been moved out of // lib/service in order to facilitate better testing practices. package accesspoint @@ -31,6 +31,7 @@ import ( oteltrace "go.opentelemetry.io/otel/trace" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/backend/memory" "github.com/gravitational/teleport/lib/cache" @@ -38,22 +39,19 @@ import ( "github.com/gravitational/teleport/lib/services" ) -// AccessCacheConfig holds parameters used to confiure a cache to +// Config holds parameters used to configure a cache to // serve as an auth access point for a teleport service. -type AccessCacheConfig struct { +type Config struct { // Context is the base context used to propagate closure to // cache components. Context context.Context - // Services is a collection of upstream services from which - // the access cache will derive its state. - Services services.Services // Setup is a function that takes cache configuration and // modifies it to support a specific teleport service. Setup cache.SetupConfigFn // CacheName identifies the cache in logs. CacheName []string - // Events is true if cache should have the events system enabled. - Events bool + // EventsSystem is true if cache should have the events system enabled. + EventsSystem bool // Unstarted is true if the cache should not be started. Unstarted bool // MaxRetryPeriod is the max retry period between connection attempts @@ -65,12 +63,47 @@ type AccessCacheConfig struct { // TracingProvider is the provider to be used for exporting // traces. No-op tracers will be used if no provider is set. TracingProvider *tracing.Provider + + // The following services are provided to the Cache to allow it to + // populate its resource collections. They will either be the local service + // directly or a client that can be used to fetch the resources from the + // remote service. + + Access services.Access + AccessLists services.AccessLists + AccessMonitoringRules services.AccessMonitoringRules + AppSession services.AppSession + Apps services.Apps + ClusterConfig services.ClusterConfiguration + CrownJewels services.CrownJewels + DatabaseObjects services.DatabaseObjects + DatabaseServices services.DatabaseServices + Databases services.Databases + DiscoveryConfigs services.DiscoveryConfigs + DynamicAccess services.DynamicAccessCore + Events types.Events + Integrations services.Integrations + KubeWaitingContainers services.KubeWaitingContainer + Kubernetes services.Kubernetes + Notifications services.Notifications + Okta services.Okta + Presence services.Presence + Provisioner services.Provisioner + Restrictions services.Restrictions + SAMLIdPServiceProviders services.SAMLIdPServiceProviders + SAMLIdPSession services.SAMLIdPSession + SecReports services.SecReports + SnowflakeSession services.SnowflakeSession + Trust services.Trust + UserGroups services.UserGroups + UserLoginStates services.UserLoginStates + Users services.UsersService + WebSession types.WebSessionInterface + WebToken types.WebTokenInterface + WindowsDesktops services.WindowsDesktops } -func (c *AccessCacheConfig) CheckAndSetDefaults() error { - if c.Services == nil { - return trace.BadParameter("missing parameter Services") - } +func (c *Config) CheckAndSetDefaults() error { if c.Setup == nil { return trace.BadParameter("missing parameter Setup") } @@ -83,16 +116,14 @@ func (c *AccessCacheConfig) CheckAndSetDefaults() error { return nil } -// NewAccessCache builds a cache.Cache instance for a teleport service. This logic has been -// broken out of lib/service in order to support easier unit testing of process components. -func NewAccessCache(cfg AccessCacheConfig) (*cache.Cache, error) { +func NewCache(cfg Config) (*cache.Cache, error) { if err := cfg.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } log.Debugf("Creating in-memory backend for %v.", cfg.CacheName) mem, err := memory.New(memory.Config{ Context: cfg.Context, - EventsOff: !cfg.Events, + EventsOff: !cfg.EventsSystem, Mirror: true, }) if err != nil { @@ -119,45 +150,48 @@ func NewAccessCache(cfg AccessCacheConfig) (*cache.Cache, error) { component = append(component, teleport.ComponentCache) metricComponent := append(slices.Clone(cfg.CacheName), teleport.ComponentCache) - return cache.New(cfg.Setup(cache.Config{ - Context: cfg.Context, - Backend: reporter, - Events: cfg.Services, - ClusterConfig: cfg.Services, - Provisioner: cfg.Services, - Trust: cfg.Services, - Users: cfg.Services, - Access: cfg.Services, - DynamicAccess: cfg.Services, - Presence: cfg.Services, - Restrictions: cfg.Services, - Apps: cfg.Services, - Kubernetes: cfg.Services, - CrownJewels: cfg.Services.CrownJewelClient(), - DatabaseServices: cfg.Services, - Databases: cfg.Services, - DatabaseObjects: cfg.Services.DatabaseObjectsClient(), - AppSession: cfg.Services, - SnowflakeSession: cfg.Services, - SAMLIdPSession: cfg.Services, - WindowsDesktops: cfg.Services, - SAMLIdPServiceProviders: cfg.Services, - UserGroups: cfg.Services, - Notifications: cfg.Services, - Okta: cfg.Services.OktaClient(), - AccessLists: cfg.Services.AccessListClient(), - AccessMonitoringRules: cfg.Services.AccessMonitoringRuleClient(), - SecReports: cfg.Services.SecReportsClient(), - UserLoginStates: cfg.Services.UserLoginStateClient(), - Integrations: cfg.Services, - DiscoveryConfigs: cfg.Services.DiscoveryConfigClient(), - WebSession: cfg.Services.WebSessions(), - WebToken: cfg.Services.WebTokens(), - KubeWaitingContainers: cfg.Services, - Component: teleport.Component(component...), - MetricComponent: teleport.Component(metricComponent...), - Tracer: tracer, - MaxRetryPeriod: cfg.MaxRetryPeriod, - Unstarted: cfg.Unstarted, - })) + cacheCfg := &cache.Config{ + Context: cfg.Context, + Backend: reporter, + Component: teleport.Component(component...), + MetricComponent: teleport.Component(metricComponent...), + Tracer: tracer, + MaxRetryPeriod: cfg.MaxRetryPeriod, + Unstarted: cfg.Unstarted, + + Access: cfg.Access, + AccessLists: cfg.AccessLists, + AccessMonitoringRules: cfg.AccessMonitoringRules, + AppSession: cfg.AppSession, + Apps: cfg.Apps, + ClusterConfig: cfg.ClusterConfig, + CrownJewels: cfg.CrownJewels, + DatabaseObjects: cfg.DatabaseObjects, + DatabaseServices: cfg.DatabaseServices, + Databases: cfg.Databases, + DiscoveryConfigs: cfg.DiscoveryConfigs, + DynamicAccess: cfg.DynamicAccess, + Events: cfg.Events, + Integrations: cfg.Integrations, + KubeWaitingContainers: cfg.KubeWaitingContainers, + Kubernetes: cfg.Kubernetes, + Notifications: cfg.Notifications, + Okta: cfg.Okta, + Presence: cfg.Presence, + Provisioner: cfg.Provisioner, + Restrictions: cfg.Restrictions, + SAMLIdPServiceProviders: cfg.SAMLIdPServiceProviders, + SAMLIdPSession: cfg.SAMLIdPSession, + SecReports: cfg.SecReports, + SnowflakeSession: cfg.SnowflakeSession, + Trust: cfg.Trust, + UserGroups: cfg.UserGroups, + UserLoginStates: cfg.UserLoginStates, + Users: cfg.Users, + WebSession: cfg.WebSession, + WebToken: cfg.WebToken, + WindowsDesktops: cfg.WindowsDesktops, + } + + return cache.New(cfg.Setup(*cacheCfg)) } diff --git a/lib/auth/auth.go b/lib/auth/auth.go index a806f8c9fe8a5..67a4f8531f8a4 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -46,7 +46,6 @@ import ( "time" "github.com/coreos/go-oidc/oauth2" - "github.com/coreos/go-semver/semver" "github.com/google/uuid" liblicense "github.com/gravitational/license" "github.com/gravitational/trace" @@ -63,7 +62,6 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/proto" - "github.com/gravitational/teleport/api/client/secreport" "github.com/gravitational/teleport/api/constants" apidefaults "github.com/gravitational/teleport/api/defaults" devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1" @@ -79,6 +77,7 @@ import ( "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/api/utils/retryutils" apisshutils "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/keystore" "github.com/gravitational/teleport/lib/auth/native" @@ -347,15 +346,15 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { CloudClients: cfg.CloudClients, } if cfg.KeyStoreConfig.PKCS11 != (servicecfg.PKCS11Config{}) { - if !modules.GetModules().Features().HSM { + if !modules.GetModules().Features().GetEntitlement(entitlements.HSM).Enabled { return nil, fmt.Errorf("PKCS11 HSM support requires a license with the HSM feature enabled: %w", ErrRequiresEnterprise) } } else if cfg.KeyStoreConfig.GCPKMS != (servicecfg.GCPKMSConfig{}) { - if !modules.GetModules().Features().HSM { + if !modules.GetModules().Features().GetEntitlement(entitlements.HSM).Enabled { return nil, fmt.Errorf("Google Cloud KMS support requires a license with the HSM feature enabled: %w", ErrRequiresEnterprise) } } else if cfg.KeyStoreConfig.AWSKMS != (servicecfg.AWSKMSConfig{}) { - if !modules.GetModules().Features().HSM { + if !modules.GetModules().Features().GetEntitlement(entitlements.HSM).Enabled { return nil, fmt.Errorf("AWS KMS support requires a license with the HSM feature enabled: %w", ErrRequiresEnterprise) } } else { @@ -567,6 +566,11 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { return &as, nil } +// Services is a collection of services that are used by the auth server. +// Avoid using this type as a dependency and instead depend on the actual +// methods/services you need. It should really only be necessary to directly +// reference this type on auth.Server itself and on code that manages +// the lifecycle of the auth server. type Services struct { services.TrustInternal services.PresenceInternal @@ -609,11 +613,6 @@ type Services struct { services.DevicesGetter } -// SecReportsClient returns the security reports client. -func (r *Services) SecReportsClient() *secreport.Client { - return nil -} - // GetWebSession returns existing web session described by req. // Implements ReadAccessPoint func (r *Services) GetWebSession(ctx context.Context, req types.GetWebSessionRequest) (types.WebSession, error) { @@ -631,64 +630,6 @@ func (r *Services) GenerateAWSOIDCToken(ctx context.Context, integration string) return r.IntegrationsTokenGenerator.GenerateAWSOIDCToken(ctx, integration) } -// OktaClient returns the okta client. -func (r *Services) OktaClient() services.Okta { - return r -} - -// SCIMClient returns a client for the SCIM service. Note that in an OSS -// Teleport cluster, or an Enterprise cluster with IGS disabled, the SCIM -// service on the other end will return "NotImplemented" for every call. -func (r *Services) SCIMClient() services.SCIM { - return r.SCIM -} - -// AccessListClient returns the access list client. -func (r *Services) AccessListClient() services.AccessLists { - return r -} - -// AccessMonitoringRuleClient returns the access monitoring rules client. -func (r *Services) AccessMonitoringRuleClient() services.AccessMonitoringRules { - return r -} - -// DiscoveryConfigClient returns the DiscoveryConfig client. -func (r *Services) DiscoveryConfigClient() services.DiscoveryConfigs { - return r -} - -// CrownJewelClient returns the CrownJewels client. -func (r *Services) CrownJewelClient() services.CrownJewels { - return r -} - -// UserLoginStateClient returns the user login state client. -func (r *Services) UserLoginStateClient() services.UserLoginStates { - return r -} - -// KubernetesWaitingContainerClient returns the Kubernetes waiting -// container client. -func (r *Services) KubernetesWaitingContainerClient() services.KubeWaitingContainer { - return r -} - -// DatabaseObjectsClient returns the database objects client. -func (r *Services) DatabaseObjectsClient() services.DatabaseObjects { - return r -} - -// GetAccessGraphSecretsGetter returns the AccessGraph secrets service. -func (r *Services) GetAccessGraphSecretsGetter() services.AccessGraphSecretsGetter { - return r.AccessGraphSecretsGetter -} - -// GetDevicesGetter returns the trusted devices service. -func (r *Services) GetDevicesGetter() services.DevicesGetter { - return r.DevicesGetter -} - var ( generateRequestsCount = prometheus.NewCounter( prometheus.CounterOpts{ @@ -2020,6 +1961,8 @@ type certRequest struct { appClusterName string // appName is the name of the application to generate cert for. appName string + // appURI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + appURI string // awsRoleARN is the role ARN to generate certificate for. awsRoleARN string // azureIdentity is the Azure identity to generate certificate for. @@ -3083,6 +3026,7 @@ func generateCert(ctx context.Context, a *Server, req certRequest, caType types. KubernetesUsers: kubeUsers, RouteToApp: tlsca.RouteToApp{ SessionID: req.appSessionID, + URI: req.appURI, PublicAddr: req.appPublicAddr, ClusterName: req.appClusterName, Name: req.appName, @@ -4145,7 +4089,7 @@ func (a *Server) ExtendWebSession(ctx context.Context, req authclient.WebSession } sessionTTL := utils.ToTTL(a.clock, expiresAt) - sess, err := a.newWebSession(ctx, NewWebSessionRequest{ + sess, _, err := a.newWebSession(ctx, NewWebSessionRequest{ User: req.User, LoginIP: identity.LoginIP, Roles: roles, @@ -4965,7 +4909,7 @@ func (a *Server) CreateAccessRequestV2(ctx context.Context, req types.AccessRequ if req.GetDryRun() { _, promotions := a.generateAccessRequestPromotions(ctx, req) // update the request with additional reviewers if possible. - updateAccessRequestWithAdditionalReviewers(ctx, req, a.AccessListClient(), promotions) + updateAccessRequestWithAdditionalReviewers(ctx, req, a.AccessLists, promotions) // Made it this far with no errors, return before creating the request // if this is a dry run. return req, nil @@ -5437,7 +5381,7 @@ func (a *Server) UpsertNode(ctx context.Context, server types.Server) (*types.Ke func enforceLicense(t string) error { switch t { case types.KindKubeServer, types.KindKubernetesCluster: - if !modules.GetModules().Features().Kubernetes { + if !modules.GetModules().Features().GetEntitlement(entitlements.K8s).Enabled { return trace.AccessDenied( "this Teleport cluster is not licensed for Kubernetes, please contact the cluster administrator") } @@ -6055,10 +5999,6 @@ func (a *Server) Ping(ctx context.Context) (proto.PingResponse, error) { } features := modules.GetModules().Features().ToProto() - // DELETE IN 16.0 and the [func setAccessMonitoringFeatureForOlderClients] - // (no other changes necessary) - setAccessMonitoringFeatureForOlderClients(ctx, features, a.accessMonitoringEnabled) - return proto.PingResponse{ ClusterName: cn.GetClusterName(), ServerVersion: teleport.Version, @@ -6069,24 +6009,6 @@ func (a *Server) Ping(ctx context.Context) (proto.PingResponse, error) { }, nil } -// DELETE IN 16.0 -func setAccessMonitoringFeatureForOlderClients(ctx context.Context, features *proto.Features, accessMonitoringEnabled bool) { - clientVersionString, versionExists := metadata.ClientVersionFromContext(ctx) - - // Older proxies <= 14.2.0 will read from [Features.IdentityGovernance] to determine - // if access monitoring is enabled. - if versionExists { - clientVersion := semver.New(clientVersionString) - supportedVersion := semver.New("14.2.1") - if clientVersion.LessThan(*supportedVersion) { - features.IdentityGovernance = accessMonitoringEnabled - } - } - - // Newer proxies will read from new field [Features.AccessMonitoring.Enabled] - // which will be already set from startup, so nothing else to do here. -} - type maintenanceWindowCacheKey struct { key string } @@ -6943,10 +6865,13 @@ func (a *Server) getAccessRequestMonthlyUsage(ctx context.Context) (int, error) // If so, it returns an error. This is only applicable on usage-based billing plans. func (a *Server) verifyAccessRequestMonthlyLimit(ctx context.Context) error { f := modules.GetModules().Features() - if f.IsLegacy() || f.IGSEnabled() { - return nil // unlimited + accessRequestsEntitlement := f.GetEntitlement(entitlements.AccessRequests) + + if accessRequestsEntitlement.Limit == 0 { + return nil // unlimited access } - monthlyLimit := f.AccessRequests.MonthlyRequestLimit + + monthlyLimit := accessRequestsEntitlement.Limit const limitReachedMessage = "cluster has reached its monthly access request limit, please contact the cluster administrator" @@ -6954,7 +6879,7 @@ func (a *Server) verifyAccessRequestMonthlyLimit(ctx context.Context) error { if err != nil { return trace.Wrap(err) } - if usage >= monthlyLimit { + if usage >= int(monthlyLimit) { return trace.AccessDenied(limitReachedMessage) } diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index 092debe7a2e88..bdcf55bffb4a7 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -3012,7 +3012,7 @@ func TestNewWebSession(t *testing.T) { } bearerTokenTTL := min(req.SessionTTL, defaults.BearerTokenTTL) - ws, err := p.a.newWebSession(ctx, req, nil /* opts */) + ws, _, err := p.a.newWebSession(ctx, req, nil /* opts */) require.NoError(t, err) require.Equal(t, user.GetName(), ws.GetUser()) require.Equal(t, duration, ws.GetIdleTimeout()) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 6085711cc821b..21c4be9854dbb 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -45,6 +45,7 @@ import ( "github.com/gravitational/teleport/api/types/wrappers" apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/clusterconfig/clusterconfigv1" "github.com/gravitational/teleport/lib/auth/okta" @@ -3185,6 +3186,8 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC GCPServiceAccount: req.RouteToApp.GCPServiceAccount, MFAVerified: verifiedMFADeviceID, DeviceExtensions: DeviceExtensions(a.context.Identity.GetIdentity().DeviceExtensions), + AppName: req.RouteToApp.Name, + AppURI: req.RouteToApp.URI, }) if err != nil { return nil, trace.Wrap(err) @@ -3236,6 +3239,7 @@ func (a *ServerWithRoles) generateUserCerts(ctx context.Context, req proto.UserC appSessionID: appSessionID, appName: req.RouteToApp.Name, appPublicAddr: req.RouteToApp.PublicAddr, + appURI: req.RouteToApp.URI, appClusterName: req.RouteToApp.ClusterName, awsRoleARN: req.RouteToApp.AWSRoleARN, azureIdentity: req.RouteToApp.AzureIdentity, @@ -3487,7 +3491,7 @@ func (a *ServerWithRoles) UpsertOIDCConnector(ctx context.Context, connector typ if err := a.authConnectorAction(apidefaults.Namespace, types.KindOIDC, types.VerbUpdate); err != nil { return nil, trace.Wrap(err) } - if !modules.GetModules().Features().OIDC { + if !modules.GetModules().Features().GetEntitlement(entitlements.OIDC).Enabled { // TODO(zmb3): ideally we would wrap ErrRequiresEnterprise here, but // we can't currently propagate wrapped errors across the gRPC boundary, // and we want tctl to display a clean user-facing message in this case @@ -3508,7 +3512,7 @@ func (a *ServerWithRoles) UpdateOIDCConnector(ctx context.Context, connector typ if err := a.authConnectorAction(apidefaults.Namespace, types.KindOIDC, types.VerbUpdate); err != nil { return nil, trace.Wrap(err) } - if !modules.GetModules().Features().OIDC { + if !modules.GetModules().Features().GetEntitlement(entitlements.OIDC).Enabled { // TODO(zmb3): ideally we would wrap ErrRequiresEnterprise here, but // we can't currently propagate wrapped errors across the gRPC boundary, // and we want tctl to display a clean user-facing message in this case @@ -3528,7 +3532,7 @@ func (a *ServerWithRoles) CreateOIDCConnector(ctx context.Context, connector typ if err := a.authConnectorAction(apidefaults.Namespace, types.KindOIDC, types.VerbCreate); err != nil { return nil, trace.Wrap(err) } - if !modules.GetModules().Features().OIDC { + if !modules.GetModules().Features().GetEntitlement(entitlements.OIDC).Enabled { // TODO(zmb3): ideally we would wrap ErrRequiresEnterprise here, but // we can't currently propagate wrapped errors across the gRPC boundary, // and we want tctl to display a clean user-facing message in this case @@ -3572,7 +3576,7 @@ func (a *ServerWithRoles) GetOIDCConnectors(ctx context.Context, withSecrets boo } func (a *ServerWithRoles) CreateOIDCAuthRequest(ctx context.Context, req types.OIDCAuthRequest) (*types.OIDCAuthRequest, error) { - if !modules.GetModules().Features().OIDC { + if !modules.GetModules().Features().GetEntitlement(entitlements.OIDC).Enabled { // TODO(zmb3): ideally we would wrap ErrRequiresEnterprise here, but // we can't currently propagate wrapped errors across the gRPC boundary, // and we want tctl to display a clean user-facing message in this case @@ -3646,7 +3650,7 @@ func (a *ServerWithRoles) DeleteOIDCConnector(ctx context.Context, connectorID s // UpsertSAMLConnector creates or updates a SAML connector. func (a *ServerWithRoles) UpsertSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) { - if !modules.GetModules().Features().SAML { + if !modules.GetModules().Features().GetEntitlement(entitlements.SAML).Enabled { return nil, trace.Wrap(ErrSAMLRequiresEnterprise) } @@ -3669,7 +3673,7 @@ func (a *ServerWithRoles) UpsertSAMLConnector(ctx context.Context, connector typ // CreateSAMLConnector creates a new SAML connector. func (a *ServerWithRoles) CreateSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) { - if !modules.GetModules().Features().SAML { + if !modules.GetModules().Features().GetEntitlement(entitlements.SAML).Enabled { return nil, trace.Wrap(ErrSAMLRequiresEnterprise) } @@ -3687,7 +3691,7 @@ func (a *ServerWithRoles) CreateSAMLConnector(ctx context.Context, connector typ // UpdateSAMLConnector updates an existing SAML connector func (a *ServerWithRoles) UpdateSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) { - if !modules.GetModules().Features().SAML { + if !modules.GetModules().Features().GetEntitlement(entitlements.SAML).Enabled { return nil, trace.Wrap(ErrSAMLRequiresEnterprise) } @@ -3733,7 +3737,7 @@ func (a *ServerWithRoles) GetSAMLConnectors(ctx context.Context, withSecrets boo } func (a *ServerWithRoles) CreateSAMLAuthRequest(ctx context.Context, req types.SAMLAuthRequest) (*types.SAMLAuthRequest, error) { - if !modules.GetModules().Features().SAML { + if !modules.GetModules().Features().GetEntitlement(entitlements.SAML).Enabled { return nil, trace.Wrap(ErrSAMLRequiresEnterprise) } diff --git a/lib/auth/authclient/clt.go b/lib/auth/authclient/clt.go index 8be2817fd9af1..0fbf9115f425c 100644 --- a/lib/auth/authclient/clt.go +++ b/lib/auth/authclient/clt.go @@ -1762,6 +1762,8 @@ func TryCreateAppSessionForClientCertV15(ctx context.Context, client CreateAppSe AWSRoleARN: routeToApp.AWSRoleARN, AzureIdentity: routeToApp.AzureIdentity, GCPServiceAccount: routeToApp.GCPServiceAccount, + URI: routeToApp.URI, + AppName: routeToApp.Name, }) if err != nil { return "", trace.Wrap(err) diff --git a/lib/auth/clusterconfig/clusterconfigv1/service.go b/lib/auth/clusterconfig/clusterconfigv1/service.go index 8edecb8757bea..cb1caab964876 100644 --- a/lib/auth/clusterconfig/clusterconfigv1/service.go +++ b/lib/auth/clusterconfig/clusterconfigv1/service.go @@ -27,6 +27,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/clusterconfig" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/authz" dtconfig "github.com/gravitational/teleport/lib/devicetrust/config" "github.com/gravitational/teleport/lib/events" @@ -929,7 +930,7 @@ func (s *Service) GetClusterAccessGraphConfig(ctx context.Context, _ *clustercon } // If the policy feature is disabled in the license, return a disabled response. - if !modules.GetModules().Features().Policy.Enabled && !modules.GetModules().Features().AccessGraph { + if !modules.GetModules().Features().GetEntitlement(entitlements.Policy).Enabled && !modules.GetModules().Features().AccessGraph { return &clusterconfigpb.GetClusterAccessGraphConfigResponse{ AccessGraph: &clusterconfigpb.AccessGraphConfig{ Enabled: false, @@ -1030,7 +1031,8 @@ func (s *Service) UpdateAccessGraphSettings(ctx context.Context, req *clustercon return nil, trace.Wrap(err) } - if !modules.GetModules().Features().Policy.Enabled && !modules.GetModules().Features().AccessGraph { + features := modules.GetProtoEntitlement(modules.GetModules().Features().ToProto(), entitlements.Policy) + if !features.Enabled && !modules.GetModules().Features().AccessGraph { return nil, trace.AccessDenied("access graph is feature isn't enabled") } @@ -1074,7 +1076,8 @@ func (s *Service) UpsertAccessGraphSettings(ctx context.Context, req *clustercon return nil, trace.Wrap(err) } - if !modules.GetModules().Features().Policy.Enabled && !modules.GetModules().Features().AccessGraph { + features := modules.GetProtoEntitlement(modules.GetModules().Features().ToProto(), entitlements.Policy) + if !features.Enabled && !modules.GetModules().Features().AccessGraph { return nil, trace.AccessDenied("access graph is feature isn't enabled") } @@ -1118,7 +1121,8 @@ func (s *Service) ResetAccessGraphSettings(ctx context.Context, _ *clusterconfig return nil, trace.Wrap(err) } - if !modules.GetModules().Features().Policy.Enabled && !modules.GetModules().Features().AccessGraph { + features := modules.GetProtoEntitlement(modules.GetModules().Features().ToProto(), entitlements.Policy) + if !features.Enabled && !modules.GetModules().Features().AccessGraph { return nil, trace.AccessDenied("access graph is feature isn't enabled") } diff --git a/lib/auth/clusterconfig/clusterconfigv1/service_test.go b/lib/auth/clusterconfig/clusterconfigv1/service_test.go index b3ac67e1cc342..02cb3821646fb 100644 --- a/lib/auth/clusterconfig/clusterconfigv1/service_test.go +++ b/lib/auth/clusterconfig/clusterconfigv1/service_test.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/clusterconfig" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/clusterconfig/clusterconfigv1" "github.com/gravitational/teleport/lib/authz" "github.com/gravitational/teleport/lib/backend/memory" @@ -1852,8 +1853,8 @@ func TestGetAccessGraphConfig(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } @@ -1877,8 +1878,8 @@ func TestGetAccessGraphConfig(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } @@ -1902,8 +1903,8 @@ func TestGetAccessGraphConfig(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } @@ -2060,8 +2061,8 @@ func TestUpdateAccessGraphSettings(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } @@ -2185,8 +2186,8 @@ func TestUpsertAccessGraphSettings(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } @@ -2279,8 +2280,8 @@ func TestResetAccessGraphSettings(t *testing.T) { testSetup: func(t *testing.T) { m := modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, } diff --git a/lib/auth/crownjewel/object.go b/lib/auth/crownjewel/object.go index 8dd3d99506678..2d7b4f5d55318 100644 --- a/lib/auth/crownjewel/object.go +++ b/lib/auth/crownjewel/object.go @@ -60,7 +60,7 @@ func ValidateCrownJewel(jewel *crownjewelv1.CrownJewel) error { return trace.BadParameter("crown jewel name is empty") case jewel.Spec == nil: return trace.BadParameter("crown jewel spec is nil") - case len(jewel.Spec.TeleportMatchers) == 0 && len(jewel.Spec.AwsMatchers) == 0: + case len(jewel.Spec.TeleportMatchers) == 0 && len(jewel.Spec.AwsMatchers) == 0 && jewel.Spec.Query == "": return trace.BadParameter("crown jewel must have at least one matcher") } diff --git a/lib/auth/crownjewel/object_test.go b/lib/auth/crownjewel/object_test.go index 748b0890b5cec..db1c23bbb2687 100644 --- a/lib/auth/crownjewel/object_test.go +++ b/lib/auth/crownjewel/object_test.go @@ -78,6 +78,18 @@ func TestValidateCrownJewel(t *testing.T) { }, wantErr: require.NoError, }, + { + name: "ValidCrownJewelWithQuery", + jewel: &crownjewelv1.CrownJewel{ + Metadata: &headerv1.Metadata{ + Name: "test", + }, + Spec: &crownjewelv1.CrownJewelSpec{ + Query: "SELECT * FROM nodes", + }, + }, + wantErr: require.NoError, + }, { name: "MissingMatchers", jewel: &crownjewelv1.CrownJewel{ diff --git a/lib/auth/db.go b/lib/auth/db.go index 1716f5a2d91c5..40533a0120596 100644 --- a/lib/auth/db.go +++ b/lib/auth/db.go @@ -38,6 +38,7 @@ import ( apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/keystore" "github.com/gravitational/teleport/lib/jwt" "github.com/gravitational/teleport/lib/modules" @@ -201,7 +202,7 @@ func getServerNames(req *proto.DatabaseCertRequest) []string { // SignDatabaseCSR generates a client certificate used by proxy when talking // to a remote database service. func (a *Server) SignDatabaseCSR(ctx context.Context, req *proto.DatabaseCSRRequest) (*proto.DatabaseCSRResponse, error) { - if !modules.GetModules().Features().DB { + if !modules.GetModules().Features().GetEntitlement(entitlements.DB).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for database access, please contact the cluster administrator") } @@ -290,7 +291,7 @@ func (a *Server) SignDatabaseCSR(ctx context.Context, req *proto.DatabaseCSRRequ // GenerateSnowflakeJWT generates JWT in the format required by Snowflake. func (a *Server) GenerateSnowflakeJWT(ctx context.Context, req *proto.SnowflakeJWTRequest) (*proto.SnowflakeJWTResponse, error) { - if !modules.GetModules().Features().DB { + if !modules.GetModules().Features().GetEntitlement(entitlements.DB).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for database access, please contact the cluster administrator") } diff --git a/lib/auth/desktop.go b/lib/auth/desktop.go index 835c97b6a93f5..39542b953a8a5 100644 --- a/lib/auth/desktop.go +++ b/lib/auth/desktop.go @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -43,7 +44,7 @@ import ( // GenerateWindowsDesktopCert generates client certificate for Windows RDP // authentication. func (a *Server) GenerateWindowsDesktopCert(ctx context.Context, req *proto.WindowsDesktopCertRequest) (*proto.WindowsDesktopCertResponse, error) { - if !modules.GetModules().Features().Desktop { + if !modules.GetModules().Features().GetEntitlement(entitlements.Desktop).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for desktop access, please contact the cluster administrator") } diff --git a/lib/auth/desktop_test.go b/lib/auth/desktop_test.go index c9eb6b4c31830..0a6fcb2eb597f 100644 --- a/lib/auth/desktop_test.go +++ b/lib/auth/desktop_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/client/proto" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/modules" ) @@ -33,7 +34,9 @@ import ( func TestDesktopAccessDisabled(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Desktop: false, // Explicily turn off desktop access. + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Desktop: {Enabled: false}, // Explicitly turn off desktop access. + }, }, }) diff --git a/lib/auth/github.go b/lib/auth/github.go index 7f535a935b8eb..dc679f234615c 100644 --- a/lib/auth/github.go +++ b/lib/auth/github.go @@ -24,8 +24,11 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" + "net/netip" "net/url" + "slices" "strings" "time" @@ -713,13 +716,15 @@ func (a *Server) validateGithubAuthCallback(ctx context.Context, diagCtx *SSODia // If the request is coming from a browser, create a web session. if req.CreateWebSession { session, err := a.CreateWebSessionFromReq(ctx, NewWebSessionRequest{ - User: userState.GetName(), - Roles: userState.GetRoles(), - Traits: userState.GetTraits(), - SessionTTL: params.SessionTTL, - LoginTime: a.clock.Now().UTC(), - LoginIP: req.ClientLoginIP, - AttestWebSession: true, + User: userState.GetName(), + Roles: userState.GetRoles(), + Traits: userState.GetTraits(), + SessionTTL: params.SessionTTL, + LoginTime: a.clock.Now().UTC(), + LoginIP: req.ClientLoginIP, + LoginUserAgent: req.ClientUserAgent, + AttestWebSession: true, + CreateDeviceWebToken: true, }) if err != nil { return nil, trace.Wrap(err, "Failed to create web session.") @@ -907,6 +912,8 @@ func (a *Server) createGithubUser(ctx context.Context, p *CreateUserParams, dryR return user, nil } +const unknownRedirectHostnameErrMsg = "unknown custom client redirect URL hostname" + // ValidateClientRedirect checks a desktop client redirect URL for SSO logins // against some (potentially nil) settings from an auth connector; in the // current implementation, that means either "http" schema with a hostname of @@ -914,7 +921,10 @@ func (a *Server) createGithubUser(ctx context.Context, p *CreateUserParams, dryR // or "https" schema with a hostname that matches one in the https_hostname // list, a path of "/callback" and either an empty port or explicitly 443. The // settings are ignored and only localhost URLs are allowed if we're using an -// ephemeral connector (in the SSO testing flow). +// ephemeral connector (in the SSO testing flow). If the insecure_allowed_cidr_ranges +// list is non-empty URLs in both the "http" and "https" schema are allowed +// if the hostname is an IP address that is contained in a specified CIDR +// range on any port. func ValidateClientRedirect(clientRedirect string, ssoTestFlow bool, settings *types.SSOClientRedirectSettings) error { if clientRedirect == "" { // empty redirects are non-functional and harmless, so we allow them as @@ -944,45 +954,61 @@ func ValidateClientRedirect(clientRedirect string, ssoTestFlow bool, settings *t } // we checked everything but u.Scheme and u.Host now - - switch u.Scheme { - default: + if u.Scheme != "http" && u.Scheme != "https" { return trace.BadParameter("invalid scheme in client redirect URL") + } - case "http": - switch u.Hostname() { - default: - return trace.BadParameter("invalid hostname in client redirect URL") - case "localhost", "127.0.0.1", "::1": - return nil - } + // allow HTTP redirects to local addresses + allowedHTTPLocalAddrs := []string{"localhost", "127.0.0.1", "::1"} + if u.Scheme == "http" && slices.Contains(allowedHTTPLocalAddrs, u.Hostname()) { + return nil + } + + if ssoTestFlow { + return trace.AccessDenied("custom client redirect URLs are not allowed in SSO test") + } + + if settings == nil { + return trace.AccessDenied(unknownRedirectHostnameErrMsg) + } + + // allow HTTP or HTTPS redirects from IPs in specified CIDR ranges + hostIP, err := netip.ParseAddr(u.Hostname()) + if err == nil { + hostIP = hostIP.Unmap() - case "https": - if ssoTestFlow { - return trace.AccessDenied("custom client redirect URLs are not allowed in SSO test") + for _, cidrStr := range settings.InsecureAllowedCidrRanges { + cidr, err := netip.ParsePrefix(cidrStr) + if err != nil { + slog.WarnContext(context.Background(), "error parsing OIDC connector CIDR prefix", "cidr", cidrStr, "err", err) + continue + } + if cidr.Contains(hostIP) { + return nil + } } + } + if u.Scheme == "https" { switch u.Port() { default: return trace.BadParameter("invalid port in client redirect URL") case "", "443": } - var allowedHostnames []string - if settings != nil { - allowedHostnames = settings.AllowedHttpsHostnames - } - - ok, err := utils.SliceMatchesRegex(u.Hostname(), allowedHostnames) - if err != nil { - return trace.Wrap(err, "matching custom client redirect URL hostname") - } - if !ok { - return trace.AccessDenied("unknown custom client redirect URL hostname") + for _, expression := range settings.AllowedHttpsHostnames { + ok, err := utils.MatchString(u.Hostname(), expression) + if err != nil { + slog.WarnContext(context.Background(), "error compiling OIDC connector allowed HTTPS hostname regex", "regex", expression, "err", err) + continue + } + if ok { + return nil + } } - - return nil } + + return trace.AccessDenied(unknownRedirectHostnameErrMsg) } // populateGithubClaims builds a GithubClaims using queried diff --git a/lib/auth/github_test.go b/lib/auth/github_test.go index c06d771d76f37..26e059c18d2d9 100644 --- a/lib/auth/github_test.go +++ b/lib/auth/github_test.go @@ -643,6 +643,9 @@ func TestValidateClientRedirect(t *testing.T) { "https://127.0.0.1:12345/callback", "https://localhost:12345/callback", "https://localhost/callback", + "ftp://localhost/callback", + "ftp://127.0.0.1/callback", + "ftp://[::1]/callback", } { const ssoTestFlowFalse = false var defaultSettings *types.SSOClientRedirectSettings @@ -699,6 +702,60 @@ func TestValidateClientRedirect(t *testing.T) { } }) + t.Run("InsecureAllowedCidrRanges", func(t *testing.T) { + for _, goodURL := range []string{ + "http://192.168.0.27/callback", + "https://192.168.0.27/callback", + "http://192.168.0.27:1337/callback", + "https://192.168.0.27:1337/callback", + "http://[2001:db8::aaaa:bbbb]/callback", + "https://[2001:db8::aaaa:bbbb]/callback", + "http://[2001:db8::aaaa:bbbb]:1337/callback", + "https://[2001:db8::aaaa:bbbb]:1337/callback", + "http://[2001:db8::1]/callback", + "https://[2001:db8::1]/callback", + "http://[2001:db8::1]:1337/callback", + "https://[2001:db8::1]:1337/callback", + } { + const ssoTestFlowFalse = false + settings := &types.SSOClientRedirectSettings{ + InsecureAllowedCidrRanges: []string{ + "192.168.0.0/24", + "2001:db8::/96", + }, + } + require.NoError(t, ValidateClientRedirect(goodURL+"?secret_key=", ssoTestFlowFalse, settings)) + } + + for _, badURL := range []string{ + "http://192.168.1.1/callback", + "https://192.168.1.1/callback", + "http://192.168.1.1:80/callback", + "https://192.168.1.1:443/callback", + "http://[2001:db8::1:aaaa:bbbb]/callback", + "https://[2001:db8::1:aaaa:bbbb]/callback", + "http://[2001:db8::1:aaaa:bbbb]:80/callback", + "https://[2001:db8::1:aaaa:bbbb]:443/callback", + "http://[2001:db9::]/callback", + "https://[2001:db9::]/callback", + "http://not.an.ip/callback", + "https://not.an.ip/callback", + "http://192.168.0.27/nocallback", + "https://192.168.0.27/nocallback", + "http://[2001:db8::1]/notacallback", + "https://[2001:db8::1]/notacallback", + } { + const ssoTestFlowFalse = false + settings := &types.SSOClientRedirectSettings{ + InsecureAllowedCidrRanges: []string{ + "192.168.0.0/24", + "2001:db8::/96", + }, + } + require.Error(t, ValidateClientRedirect(badURL+"?secret_key=", ssoTestFlowFalse, settings)) + } + }) + t.Run("SSOTestFlow", func(t *testing.T) { for _, goodURL := range []string{ "http://127.0.0.1:12345/callback", diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index e74fba8ffbe58..1689965c686ec 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -64,6 +64,7 @@ import ( "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/mocku2f" "github.com/gravitational/teleport/lib/auth/testauthority" @@ -856,7 +857,9 @@ func TestGenerateUserCerts_deviceAuthz(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, // required for Device Trust. TestFeatures: modules.Features{ - App: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.App: {Enabled: true}, + }, }, }) @@ -4188,7 +4191,11 @@ func TestExport(t *testing.T) { // a SAML connector. func TestSAMLValidation(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ - TestFeatures: modules.Features{SAML: true}, + TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.SAML: {Enabled: true}, + }, + }, }) // minimal entity_descriptor to pass validation. not actually valid @@ -4460,8 +4467,8 @@ func TestUpsertApplicationServerOrigin(t *testing.T) { func TestGetAccessGraphConfig(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Policy: modules.PolicyFeature{ - Enabled: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Policy: {Enabled: true}, }, }, }) diff --git a/lib/auth/helpers.go b/lib/auth/helpers.go index f4410a22eddd1..2e020bbab2248 100644 --- a/lib/auth/helpers.go +++ b/lib/auth/helpers.go @@ -309,13 +309,46 @@ func NewTestAuthServer(cfg TestAuthServerConfig) (*TestAuthServer, error) { srv.AuthServer.bcryptCostOverride = &minCost if cfg.CacheEnabled { - srv.AuthServer.Cache, err = accesspoint.NewAccessCache(accesspoint.AccessCacheConfig{ - Context: srv.AuthServer.CloseContext(), - Services: srv.AuthServer.Services, - Setup: cache.ForAuth, - CacheName: []string{teleport.ComponentAuth}, - Events: true, - Unstarted: true, + svces := srv.AuthServer.Services + srv.AuthServer.Cache, err = accesspoint.NewCache(accesspoint.Config{ + Context: srv.AuthServer.CloseContext(), + Setup: cache.ForAuth, + CacheName: []string{teleport.ComponentAuth}, + EventsSystem: true, + Unstarted: true, + + Access: svces.Access, + AccessLists: svces.AccessLists, + AccessMonitoringRules: svces.AccessMonitoringRules, + AppSession: svces.Identity, + Apps: svces.Apps, + ClusterConfig: svces.ClusterConfiguration, + CrownJewels: svces.CrownJewels, + DatabaseObjects: svces.DatabaseObjects, + DatabaseServices: svces.DatabaseServices, + Databases: svces.Databases, + DiscoveryConfigs: svces.DiscoveryConfigs, + DynamicAccess: svces.DynamicAccessExt, + Events: svces.Events, + Integrations: svces.Integrations, + KubeWaitingContainers: svces.KubeWaitingContainer, + Kubernetes: svces.Kubernetes, + Notifications: svces.Notifications, + Okta: svces.Okta, + Presence: svces.PresenceInternal, + Provisioner: svces.Provisioner, + Restrictions: svces.Restrictions, + SAMLIdPServiceProviders: svces.SAMLIdPServiceProviders, + SAMLIdPSession: svces.Identity, + SecReports: svces.SecReports, + SnowflakeSession: svces.Identity, + Trust: svces.TrustInternal, + UserGroups: svces.UserGroups, + UserLoginStates: svces.UserLoginStates, + Users: svces.Identity, + WebSession: svces.Identity.WebSessions(), + WebToken: svces.WebTokens(), + WindowsDesktops: svces.WindowsDesktops, }) if err != nil { return nil, trace.Wrap(err) @@ -938,8 +971,9 @@ func TestBuiltin(role types.SystemRole) TestIdentity { func TestServerID(role types.SystemRole, serverID string) TestIdentity { return TestIdentity{ I: authz.BuiltinRole{ - Role: role, - Username: serverID, + Role: types.RoleInstance, + Username: serverID, + AdditionalSystemRoles: types.SystemRoles{role}, Identity: tlsca.Identity{ Username: serverID, }, diff --git a/lib/auth/kube_test.go b/lib/auth/kube_test.go index ddd18064ca4a9..9b8222deda8b7 100644 --- a/lib/auth/kube_test.go +++ b/lib/auth/kube_test.go @@ -31,6 +31,7 @@ import ( "github.com/stretchr/testify/require" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/tlsca" @@ -39,7 +40,9 @@ import ( func TestProcessKubeCSR(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Kubernetes: true, // test requires kube feature is enabled + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, // test requires kube feature is enabled + }, }, }) diff --git a/lib/auth/kubewaitingcontainer/service.go b/lib/auth/kubewaitingcontainer/service.go index a40229b9b5dcb..579ccccd00dde 100644 --- a/lib/auth/kubewaitingcontainer/service.go +++ b/lib/auth/kubewaitingcontainer/service.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package kubewaitingcontainer diff --git a/lib/auth/kubewaitingcontainer/service_test.go b/lib/auth/kubewaitingcontainer/service_test.go index 1477afb5dfa9f..958ea577c0cb2 100644 --- a/lib/auth/kubewaitingcontainer/service_test.go +++ b/lib/auth/kubewaitingcontainer/service_test.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package kubewaitingcontainer diff --git a/lib/auth/machineid/machineidv1/bot_service.go b/lib/auth/machineid/machineidv1/bot_service.go index ee898d6614cf0..e9d24cb74b716 100644 --- a/lib/auth/machineid/machineidv1/bot_service.go +++ b/lib/auth/machineid/machineidv1/bot_service.go @@ -29,6 +29,7 @@ import ( "github.com/jonboulle/clockwork" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/gravitational/teleport" headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" @@ -619,11 +620,14 @@ func botFromUserAndRole(user types.User, role types.Role) (*pb.Bot, error) { return nil, trace.BadParameter("user missing bot label") } + expiry := botExpiryFromUser(user) + b := &pb.Bot{ Kind: types.KindBot, Version: types.V1, Metadata: &headerv1.Metadata{ - Name: botName, + Name: botName, + Expires: expiry, }, Status: &pb.BotStatus{ UserName: user.GetName(), @@ -686,6 +690,7 @@ func botToUserAndRole(bot *pb.Bot, now time.Time, createdBy string) (types.User, roleMeta.Labels = map[string]string{ types.BotLabel: bot.Metadata.Name, } + roleMeta.Expires = userAndRoleExpiryFromBot(bot) role.SetMetadata(roleMeta) // Setup user @@ -707,7 +712,7 @@ func botToUserAndRole(bot *pb.Bot, now time.Time, createdBy string) (types.User, // We always set this to zero here - but in Upsert, we copy from the // previous user before writing if necessary userMeta.Labels[types.BotGenerationLabel] = "0" - + userMeta.Expires = userAndRoleExpiryFromBot(bot) user.SetMetadata(userMeta) traits := map[string][]string{} @@ -728,3 +733,24 @@ func botToUserAndRole(bot *pb.Bot, now time.Time, createdBy string) (types.User, return user, role, nil } + +func userAndRoleExpiryFromBot(bot *pb.Bot) *time.Time { + if bot.Metadata.GetExpires() == nil { + return nil + } + + expiry := bot.Metadata.GetExpires().AsTime() + if expiry.IsZero() || expiry.Unix() == 0 { + return nil + } + return &expiry +} + +func botExpiryFromUser(user types.User) *timestamppb.Timestamp { + userMeta := user.GetMetadata() + userExpiry := userMeta.Expiry() + if userExpiry.IsZero() || userExpiry.Unix() == 0 { + return nil + } + return timestamppb.New(userExpiry) +} diff --git a/lib/auth/machineid/machineidv1/machineidv1_test.go b/lib/auth/machineid/machineidv1/machineidv1_test.go index b95624faaf96b..6e66704c674ee 100644 --- a/lib/auth/machineid/machineidv1/machineidv1_test.go +++ b/lib/auth/machineid/machineidv1/machineidv1_test.go @@ -33,6 +33,7 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/fieldmaskpb" + "google.golang.org/protobuf/types/known/timestamppb" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/defaults" @@ -104,6 +105,7 @@ func TestCreateBot(t *testing.T) { }, ) require.NoError(t, err) + expiry := time.Now().Add(time.Hour) tests := []struct { name string @@ -223,6 +225,118 @@ func TestCreateBot(t *testing.T) { }, }, }, + { + name: "success with expiry", + user: botCreator.GetName(), + req: &machineidv1pb.CreateBotRequest{ + Bot: &machineidv1pb.Bot{ + Metadata: &headerv1.Metadata{ + Name: "success-with-expiry", + Labels: map[string]string{ + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: timestamppb.New(expiry), + }, + Spec: &machineidv1pb.BotSpec{ + Roles: []string{testRole.GetName()}, + Traits: []*machineidv1pb.Trait{ + { + Name: constants.TraitLogins, + Values: []string{"root"}, + }, + { + Name: constants.TraitKubeUsers, + Values: []string{}, + }, + }, + }, + }, + }, + + assertError: require.NoError, + want: &machineidv1pb.Bot{ + Kind: types.KindBot, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: "success-with-expiry", + Labels: map[string]string{ + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: timestamppb.New(expiry), + }, + Spec: &machineidv1pb.BotSpec{ + Roles: []string{testRole.GetName()}, + Traits: []*machineidv1pb.Trait{ + { + Name: constants.TraitLogins, + Values: []string{"root"}, + }, + }, + }, + Status: &machineidv1pb.BotStatus{ + UserName: "bot-success-with-expiry", + RoleName: "bot-success-with-expiry", + }, + }, + wantUser: &types.UserV2{ + Kind: types.KindUser, + Version: types.V2, + Metadata: types.Metadata{ + Name: "bot-success-with-expiry", + Namespace: defaults.Namespace, + Labels: map[string]string{ + types.BotLabel: "success-with-expiry", + types.BotGenerationLabel: "0", + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: &expiry, + }, + Spec: types.UserSpecV2{ + CreatedBy: types.CreatedBy{ + User: types.UserRef{Name: botCreator.GetName()}, + }, + Roles: []string{"bot-success-with-expiry"}, + Traits: map[string][]string{ + constants.TraitLogins: {"root"}, + }, + }, + Status: types.UserStatusV2{ + PasswordState: types.PasswordState_PASSWORD_STATE_UNSET, + }, + }, + wantRole: &types.RoleV6{ + Kind: types.KindRole, + Version: types.V7, + Metadata: types.Metadata{ + Name: "bot-success-with-expiry", + Namespace: defaults.Namespace, + Labels: map[string]string{ + types.BotLabel: "success-with-expiry", + }, + Description: "Automatically generated role for bot success-with-expiry", + Expires: &expiry, + }, + Spec: types.RoleSpecV6{ + Options: types.RoleOptions{ + MaxSessionTTL: types.Duration(12 * time.Hour), + }, + Allow: types.RoleConditions{ + Impersonate: &types.ImpersonateConditions{ + Roles: []string{testRole.GetName()}, + }, + Rules: []types.Rule{ + types.NewRule( + types.KindCertAuthority, + []string{types.VerbReadNoSecrets}, + ), + }, + }, + }, + }, + }, { name: "bot already exists", user: botCreator.GetName(), @@ -759,6 +873,7 @@ func TestUpsertBot(t *testing.T) { }, }) require.NoError(t, err) + expiry := time.Now().Add(time.Hour) // We find the user associated with the Bot and set the generation label. This allows us to ensure that the // generation label is preserved when UpsertBot is called. @@ -880,6 +995,108 @@ func TestUpsertBot(t *testing.T) { }, }, }, + { + name: "new with expiry", + user: botCreator.GetName(), + req: &machineidv1pb.UpsertBotRequest{ + Bot: &machineidv1pb.Bot{ + Metadata: &headerv1.Metadata{ + Name: "new-with-expiry", + Labels: map[string]string{ + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: timestamppb.New(expiry), + }, + Spec: &machineidv1pb.BotSpec{ + Roles: []string{testRole.GetName()}, + Traits: []*machineidv1pb.Trait{ + { + Name: constants.TraitLogins, + Values: []string{"root"}, + }, + }, + }, + }, + }, + + assertError: require.NoError, + want: &machineidv1pb.Bot{ + Kind: types.KindBot, + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: "new-with-expiry", + Labels: map[string]string{ + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: timestamppb.New(expiry), + }, + Spec: &machineidv1pb.BotSpec{ + Roles: []string{testRole.GetName()}, + Traits: []*machineidv1pb.Trait{ + { + Name: constants.TraitLogins, + Values: []string{"root"}, + }, + }, + }, + Status: &machineidv1pb.BotStatus{ + UserName: "bot-new-with-expiry", + RoleName: "bot-new-with-expiry", + }, + }, + wantUser: &types.UserV2{ + Kind: types.KindUser, + Version: types.V2, + Metadata: types.Metadata{ + Name: "bot-new-with-expiry", + Namespace: defaults.Namespace, + Labels: map[string]string{ + types.BotLabel: "new-with-expiry", + types.BotGenerationLabel: "0", + "my-label": "my-value", + "my-other-label": "my-other-value", + }, + Expires: &expiry, + }, + Spec: types.UserSpecV2{ + Roles: []string{"bot-new-with-expiry"}, + Traits: map[string][]string{ + constants.TraitLogins: {"root"}, + }, + CreatedBy: types.CreatedBy{ + User: types.UserRef{Name: botCreator.GetName()}, + }, + }, + }, + wantRole: &types.RoleV6{ + Kind: types.KindRole, + Version: types.V7, + Metadata: types.Metadata{ + Name: "bot-new-with-expiry", + Namespace: defaults.Namespace, + Labels: map[string]string{ + types.BotLabel: "new-with-expiry", + }, + Description: "Automatically generated role for bot new-with-expiry", + Expires: &expiry, + }, + Spec: types.RoleSpecV6{ + Options: types.RoleOptions{ + MaxSessionTTL: types.Duration(12 * time.Hour), + }, + Allow: types.RoleConditions{ + Impersonate: &types.ImpersonateConditions{ + Roles: []string{testRole.GetName()}, + }, + Rules: []types.Rule{ + types.NewRule(types.KindCertAuthority, []string{types.VerbReadNoSecrets}), + }, + }, + }, + }, + }, { name: "already exists", user: botCreator.GetName(), diff --git a/lib/auth/methods.go b/lib/auth/methods.go index 7dffef7b890d5..e42cf1ae5b398 100644 --- a/lib/auth/methods.go +++ b/lib/auth/methods.go @@ -30,7 +30,6 @@ import ( "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/constants" - devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1" mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" @@ -38,9 +37,7 @@ import ( wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" "github.com/gravitational/teleport/lib/authz" "github.com/gravitational/teleport/lib/defaults" - dtconfig "github.com/gravitational/teleport/lib/devicetrust/config" "github.com/gravitational/teleport/lib/events" - "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" ) @@ -630,89 +627,22 @@ func (a *Server) AuthenticateWebUser(ctx context.Context, req authclient.Authent } sess, err := a.CreateWebSessionFromReq(ctx, NewWebSessionRequest{ - User: user.GetName(), - LoginIP: loginIP, - Roles: user.GetRoles(), - Traits: user.GetTraits(), - LoginTime: a.clock.Now().UTC(), - AttestWebSession: true, + User: user.GetName(), + LoginIP: loginIP, + LoginUserAgent: userAgent, + Roles: user.GetRoles(), + Traits: user.GetTraits(), + LoginTime: a.clock.Now().UTC(), + AttestWebSession: true, + CreateDeviceWebToken: true, }) if err != nil { return nil, trace.Wrap(err) } - // Create the device trust DeviceWebToken. - // We only get a token if the server is enabled for Device Trust and the user - // has a suitable trusted device. - if loginIP != "" && userAgent != "" { - webToken, err := a.createDeviceWebToken(ctx, &devicepb.DeviceWebToken{ - WebSessionId: sess.GetName(), - BrowserUserAgent: userAgent, - BrowserIp: loginIP, - User: sess.GetUser(), - }) - switch { - case err != nil: - log.WithError(err).Warn("Failed to create DeviceWebToken for user") - case webToken != nil: // May be nil even if err==nil. - sess.SetDeviceWebToken(&types.DeviceWebToken{ - Id: webToken.Id, - Token: webToken.Token, - }) - } - } - - // Calculate the trusted device requirement for the session. Helps inform the - // frontend if the user might run into access problems without a trusted - // device. - trustedDeviceRequirement, err := a.calculateTrustedDeviceMode(ctx, func() ([]types.Role, error) { - // TODO(codingllama): Levegare the checker inside CreateWebSessionFromReq to - // avoid duplicate work here. - roles, err := services.FetchRoles(user.GetRoles(), a, user.GetTraits()) - if err != nil { - return nil, trace.Wrap(err) - } - return roles, nil - }) - if err != nil { - return nil, trace.Wrap(err) - } - sess.SetTrustedDeviceRequirement(trustedDeviceRequirement) - return sess, nil } -func (a *Server) calculateTrustedDeviceMode(ctx context.Context, getRoles func() ([]types.Role, error)) (types.TrustedDeviceRequirement, error) { - const unspecified = types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_UNSPECIFIED - - // Don't evaluate for OSS. - if !modules.GetModules().IsEnterpriseBuild() { - return unspecified, nil - } - - // Required by cluster mode? - ap, err := a.GetAuthPreference(ctx) - if err != nil { - return unspecified, trace.Wrap(err) - } - if dtconfig.GetEffectiveMode(ap.GetDeviceTrust()) == constants.DeviceTrustModeRequired { - return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_REQUIRED, nil - } - - // Required by roles? - roles, err := getRoles() - if err != nil { - return unspecified, trace.Wrap(err) - } - for _, role := range roles { - if role.GetOptions().DeviceTrustMode == constants.DeviceTrustModeRequired { - return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_REQUIRED, nil - } - } - - return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_NOT_REQUIRED, nil -} - // AuthenticateSSHUser authenticates an SSH user and returns SSH and TLS // certificates for the public key in req. func (a *Server) AuthenticateSSHUser(ctx context.Context, req authclient.AuthenticateSSHRequest) (*authclient.SSHLoginResponse, error) { diff --git a/lib/auth/middleware.go b/lib/auth/middleware.go index 0e53634a75a18..dad4a8a15f2a0 100644 --- a/lib/auth/middleware.go +++ b/lib/auth/middleware.go @@ -409,11 +409,12 @@ func (a *Middleware) ValidateClientVersion(ctx context.Context, info IdentityInf } ua := metadata.UserAgentFromContext(ctx) - logger := log.WithFields(logrus.Fields{"user_agent": ua, "identity": info.IdentityGetter.GetIdentity().Username, "version": clientVersionString}) + + logger := log.WithFields(logrus.Fields{"user_agent": ua, "identity": info.IdentityGetter.GetIdentity().Username, "version": clientVersionString, "addr": info.Conn.RemoteAddr().String()}) clientVersion, err := semver.NewVersion(clientVersionString) if err != nil { logger.WithError(err).Warn("Failed to determine client version") - a.displayRejectedClientAlert(ctx, ua) + a.displayRejectedClientAlert(ctx, clientVersionString, info.Conn.RemoteAddr(), ua, info.IdentityGetter) if err := info.Conn.Close(); err != nil { logger.WithError(err).Warn("Failed to close client connection") } @@ -423,7 +424,7 @@ func (a *Middleware) ValidateClientVersion(ctx context.Context, info IdentityInf if clientVersion.LessThan(*a.OldestSupportedVersion) { logger.Info("Terminating connection of client using unsupported version") - a.displayRejectedClientAlert(ctx, ua) + a.displayRejectedClientAlert(ctx, clientVersionString, info.Conn.RemoteAddr(), ua, info.IdentityGetter) if err := info.Conn.Close(); err != nil { logger.WithError(err).Warn("Failed to close client connection") @@ -442,17 +443,11 @@ var clientUARegex = regexp.MustCompile(`(tsh|tbot|tctl)\/\d+`) // being denied to prevent causing issues. Alerts are limited to being // created once per day to reduce backend writes if there are a large // number of unsupported clients constantly being rejected. -func (a *Middleware) displayRejectedClientAlert(ctx context.Context, userAgent string) { +func (a *Middleware) displayRejectedClientAlert(ctx context.Context, clientVersion string, addr net.Addr, userAgent string, ident authz.IdentityGetter) { if a.AlertCreator == nil { return } - connectionType := "agents" - match := clientUARegex.FindStringSubmatch(userAgent) - if len(match) > 1 { - connectionType = match[1] - } - now := time.Now() lastAlert := a.lastRejectedAlertTime.Load() then := time.Unix(0, lastAlert) @@ -464,9 +459,32 @@ func (a *Middleware) displayRejectedClientAlert(ctx context.Context, userAgent s return } + alertVersion := semver.Version{ + Major: a.OldestSupportedVersion.Major, + Minor: a.OldestSupportedVersion.Minor, + Patch: a.OldestSupportedVersion.Patch, + } + + match := clientUARegex.FindStringSubmatch(userAgent) + i := ident.GetIdentity() + br, builtin := ident.(authz.BuiltinRole) + rbr, remoteBuiltin := ident.(authz.RemoteBuiltinRole) + + var message string + switch { + case len(match) > 1: // A match indicates the connection was from a client tool + message = fmt.Sprintf("Connection from %s v%s by %s was rejected. Connections will be allowed after upgrading %s to v%s or newer", match[1], clientVersion, i.Username, match[1], alertVersion.String()) + case builtin: // If the identity is a builtin then this connection is from an agent + message = fmt.Sprintf("Connection from %s %s at %s, running an unsupported version of v%s was rejected. Connections will be allowed after upgrading the agent to v%s or newer", br.AdditionalSystemRoles, i.Username, addr.String(), clientVersion, alertVersion.String()) + case remoteBuiltin: // If the identity is a remote builtin then this connection is from an agent, or leaf cluster + message = fmt.Sprintf("Connection from %s %s at %s in cluster %s, running an unsupported version of v%s was rejected. Connections will be allowed after upgrading the agent to v%s or newer", rbr.Username, i.Username, addr.String(), rbr.ClusterName, clientVersion, alertVersion.String()) + default: // The connection is from an old client tool that does not provide a user agent. + message = fmt.Sprintf("Connection from tsh, tctl, tbot, or a plugin running v%s by %s was rejected. Connections will be allowed after upgrading to v%s or newer", clientVersion, i.Username, alertVersion.String()) + } + alert, err := types.NewClusterAlert( "rejected-unsupported-connection", - fmt.Sprintf("Connections were rejected from %s running unsupported Teleport versions(<%s), they will be inaccessible until upgraded.", connectionType, a.OldestSupportedVersion), + message, types.WithAlertSeverity(types.AlertSeverity_MEDIUM), types.WithAlertLabel(types.AlertOnLogin, "yes"), types.WithAlertLabel(types.AlertVerbPermit, fmt.Sprintf("%s:%s", types.KindToken, types.VerbCreate)), diff --git a/lib/auth/middleware_test.go b/lib/auth/middleware_test.go index dc56ecfb2635f..c245ae24ca8d9 100644 --- a/lib/auth/middleware_test.go +++ b/lib/auth/middleware_test.go @@ -25,6 +25,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/json" + "fmt" "net" "net/http" "net/http/httptest" @@ -674,7 +675,10 @@ func (f *fakeConn) Close() error { } func (f *fakeConn) RemoteAddr() net.Addr { - return &utils.NetAddr{} + return &utils.NetAddr{ + Addr: "127.0.0.1:6514", + AddrNetwork: "tcp", + } } func TestValidateClientVersion(t *testing.T) { @@ -760,6 +764,88 @@ func TestValidateClientVersion(t *testing.T) { } } +func TestRejectedClientClusterAlertContents(t *testing.T) { + var alerts []types.ClusterAlert + mw := Middleware{ + OldestSupportedVersion: &teleport.MinClientSemVersion, + AlertCreator: func(ctx context.Context, a types.ClusterAlert) error { + alerts = append(alerts, a) + return nil + }, + } + + alertVersion := semver.Version{ + Major: mw.OldestSupportedVersion.Major, + Minor: mw.OldestSupportedVersion.Minor, + Patch: mw.OldestSupportedVersion.Patch, + }.String() + + version := semver.Version{Major: teleport.SemVersion.Major - 5}.String() + + tests := []struct { + name string + userAgent string + identity authz.IdentityGetter + expected string + }{ + { + name: "invalid node", + identity: TestServerID(types.RoleNode, "1-2-3-4").I, + expected: fmt.Sprintf("Connection from Node 1-2-3-4 at 127.0.0.1:6514, running an unsupported version of v%s was rejected. Connections will be allowed after upgrading the agent to v%s or newer", version, alertVersion), + }, + { + name: "invalid tsh", + userAgent: "tsh/" + teleport.Version, + identity: TestUser("llama").I, + expected: fmt.Sprintf("Connection from tsh v%s by llama was rejected. Connections will be allowed after upgrading tsh to v%s or newer", version, alertVersion), + }, + { + name: "invalid remote node", + identity: authz.RemoteBuiltinRole{ + Role: types.RoleNode, + Username: string(types.RoleNode), + ClusterName: "leaf", + Identity: tlsca.Identity{ + Username: "1-2-3-4", + }, + }, + expected: fmt.Sprintf("Connection from Node 1-2-3-4 at 127.0.0.1:6514 in cluster leaf, running an unsupported version of v%s was rejected. Connections will be allowed after upgrading the agent to v%s or newer", version, alertVersion), + }, + + { + name: "invalid tool", + identity: TestUser("llama").I, + expected: fmt.Sprintf("Connection from tsh, tctl, tbot, or a plugin running v%s by llama was rejected. Connections will be allowed after upgrading to v%s or newer", version, alertVersion), + }, + } + + // Trigger alerts from a variety of identities and validate the content of emitted alerts. + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + ctx := metadata.NewIncomingContext(context.Background(), metadata.New(map[string]string{ + "version": version, + "user-agent": test.userAgent, + })) + + err := mw.ValidateClientVersion(ctx, IdentityInfo{Conn: &fakeConn{}, IdentityGetter: test.identity}) + assert.Error(t, err) + + // Assert that only an alert was created and the content matches expectations. + require.Len(t, alerts, 1) + require.Equal(t, "rejected-unsupported-connection", alerts[0].GetName()) + require.Equal(t, test.expected, alerts[0].Spec.Message) + + // Reset the test alerts. + alerts = nil + + // Reset the last alert time to a time beyond the rate limit, allowing the next + // rejection to trigger another alert. + mw.lastRejectedAlertTime.Store(time.Now().Add(-25 * time.Hour).UnixNano()) + }) + } +} + func TestRejectedClientClusterAlert(t *testing.T) { var alerts []types.ClusterAlert mw := Middleware{ @@ -788,7 +874,8 @@ func TestRejectedClientClusterAlert(t *testing.T) { // Assert that only a single alert was created based on the above rejections. require.Len(t, alerts, 1) require.Equal(t, "rejected-unsupported-connection", alerts[0].GetName()) - require.Contains(t, alerts[0].Spec.Message, "agents") + // Assert that the version in the message does not contain any prereleases + require.NotContains(t, alerts[0].Spec.Message, "-aa") for _, tool := range []string{"tsh", "tctl", "tbot"} { t.Run(tool, func(t *testing.T) { @@ -825,6 +912,8 @@ func TestRejectedClientClusterAlert(t *testing.T) { require.Len(t, alerts, 1) assert.Equal(t, "rejected-unsupported-connection", alerts[0].GetName()) require.Contains(t, alerts[0].Spec.Message, tool) + // Assert that the version in the message does not contain any prereleases + require.NotContains(t, alerts[0].Spec.Message, "-aa") }) } diff --git a/lib/auth/notifications/notificationsv1/service.go b/lib/auth/notifications/notificationsv1/service.go index b6b16b39be896..d62976f59d145 100644 --- a/lib/auth/notifications/notificationsv1/service.go +++ b/lib/auth/notifications/notificationsv1/service.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package notifications diff --git a/lib/auth/sessions.go b/lib/auth/sessions.go index c81a861b791be..bb37d71e9f22d 100644 --- a/lib/auth/sessions.go +++ b/lib/auth/sessions.go @@ -26,12 +26,18 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" + "github.com/gravitational/teleport/api/constants" apidefaults "github.com/gravitational/teleport/api/defaults" + devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1" mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" "github.com/gravitational/teleport/api/types" + apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/native" "github.com/gravitational/teleport/lib/defaults" + dtconfig "github.com/gravitational/teleport/lib/devicetrust/config" + "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/jwt" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" @@ -46,6 +52,9 @@ type NewWebSessionRequest struct { User string // LoginIP is an observed IP of the client, it will be embedded into certificates. LoginIP string + // LoginUserAgent is the user agent of the client's browser, as captured by + // the Proxy. + LoginUserAgent string // Roles optionally lists additional user roles Roles []string // Traits optionally lists role traits @@ -67,6 +76,13 @@ type NewWebSessionRequest struct { // This should be provided when extending an attested web session in order to maintain the // session attested status. PrivateKey *keys.PrivateKey + // CreateDeviceWebToken informs Auth to issue a DeviceWebToken when creating + // this session. + // A DeviceWebToken must only be issued for users that have been authenticated + // in the same RPC. + // May only be set internally by Auth (and Auth-related logic), not allowed + // for external requests. + CreateDeviceWebToken bool } // CheckAndSetDefaults validates the request and sets defaults. @@ -87,7 +103,7 @@ func (r *NewWebSessionRequest) CheckAndSetDefaults() error { } func (a *Server) CreateWebSessionFromReq(ctx context.Context, req NewWebSessionRequest) (types.WebSession, error) { - session, err := a.newWebSession(ctx, req, nil /* opts */) + session, _, err := a.newWebSession(ctx, req, nil /* opts */) if err != nil { return nil, trace.Wrap(err) } @@ -97,9 +113,83 @@ func (a *Server) CreateWebSessionFromReq(ctx context.Context, req NewWebSessionR return nil, trace.Wrap(err) } + // Issue and assign the DeviceWebToken, but never persist it with the + // session. + if req.CreateDeviceWebToken { + if err := a.augmentSessionForDeviceTrust(ctx, session, req.LoginIP, req.LoginUserAgent); err != nil { + return nil, trace.Wrap(err) + } + } + return session, nil } +func (a *Server) augmentSessionForDeviceTrust( + ctx context.Context, + session types.WebSession, + loginIP, userAgent string, +) error { + // IP and user agent are mandatory for device web authentication. + if loginIP == "" || userAgent == "" { + return nil + } + + // Create the device trust DeviceWebToken. + // We only get a token if the server is enabled for Device Trust and the user + // has a suitable trusted device. + webToken, err := a.createDeviceWebToken(ctx, &devicepb.DeviceWebToken{ + WebSessionId: session.GetName(), + BrowserUserAgent: userAgent, + BrowserIp: loginIP, + User: session.GetUser(), + }) + switch { + case err != nil: + log.WithError(err).Warn("Failed to create DeviceWebToken for user") + case webToken != nil: // May be nil even if err==nil. + session.SetDeviceWebToken(&types.DeviceWebToken{ + Id: webToken.Id, + Token: webToken.Token, + }) + } + + return nil +} + +func (a *Server) calculateTrustedDeviceMode( + ctx context.Context, + getRoles func() ([]types.Role, error), +) (types.TrustedDeviceRequirement, error) { + const unspecified = types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_UNSPECIFIED + + // Don't evaluate for OSS. + if !modules.GetModules().IsEnterpriseBuild() { + return unspecified, nil + } + + // Required by cluster mode? + ap, err := a.GetAuthPreference(ctx) + if err != nil { + return unspecified, trace.Wrap(err) + } + if dtconfig.GetEffectiveMode(ap.GetDeviceTrust()) == constants.DeviceTrustModeRequired { + return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_REQUIRED, nil + } + + // Required by roles? + roles, err := getRoles() + if err != nil { + return unspecified, trace.Wrap(err) + } + for _, role := range roles { + if role.GetOptions().DeviceTrustMode == constants.DeviceTrustModeRequired { + return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_REQUIRED, nil + } + } + + return types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_NOT_REQUIRED, nil +} + // newWebSessionOpts are WebSession creation options exclusive to Auth. // These options complement [types.NewWebSessionRequest]. // See [Server.newWebSession]. @@ -115,10 +205,10 @@ func (a *Server) newWebSession( ctx context.Context, req NewWebSessionRequest, opts *newWebSessionOpts, -) (types.WebSession, error) { +) (types.WebSession, services.AccessChecker, error) { userState, err := a.GetUserOrLoginState(ctx, req.User) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } if req.LoginIP == "" { // TODO(antonam): consider turning this into error after all use cases are covered (before v14.0 testplan) @@ -127,7 +217,7 @@ func (a *Server) newWebSession( clusterName, err := a.GetClusterName() if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } checker, err := services.NewAccessChecker(&services.AccessInfo{ @@ -136,18 +226,18 @@ func (a *Server) newWebSession( AllowedResourceIDs: req.RequestedResourceIDs, }, clusterName.GetClusterName(), a) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } idleTimeout, err := a.getWebIdleTimeout(ctx) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } if req.PrivateKey == nil { req.PrivateKey, err = native.GeneratePrivateKey() if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } } @@ -161,10 +251,10 @@ func (a *Server) newWebSession( // will be marked with the web session private key policy. webAttData, err := services.NewWebSessionAttestationData(req.PrivateKey.Public()) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } if err = a.UpsertKeyAttestationData(ctx, webAttData, sessionTTL); err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } } @@ -186,15 +276,15 @@ func (a *Server) newWebSession( certs, err := a.generateUserCert(ctx, certReq) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } token, err := utils.CryptoRandomHex(defaults.SessionTokenBytes) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } bearerToken, err := utils.CryptoRandomHex(defaults.SessionTokenBytes) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } bearerTokenTTL := min(sessionTTL, defaults.BearerTokenTTL) @@ -219,9 +309,20 @@ func (a *Server) newWebSession( sess, err := types.NewWebSession(token, types.KindWebSession, sessionSpec) if err != nil { - return nil, trace.Wrap(err) + return nil, nil, trace.Wrap(err) } - return sess, nil + + if tdr, err := a.calculateTrustedDeviceMode(ctx, func() ([]types.Role, error) { + return checker.Roles(), nil + }); err != nil { + log. + WithError(err). + Warn("Failed to calculate trusted device mode for session") + } else { + sess.SetTrustedDeviceRequirement(tdr) + } + + return sess, checker, nil } func (a *Server) getWebIdleTimeout(ctx context.Context) (time.Duration, error) { @@ -267,6 +368,14 @@ type NewAppSessionRequest struct { MFAVerified string // DeviceExtensions holds device-aware user certificate extensions. DeviceExtensions DeviceExtensions + // AppName is the name of the app. + AppName string + // AppURI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + AppURI string + // Identity is the identity of the user. + Identity tlsca.Identity + // ClientAddr is a client (user's) address. + ClientAddr string } // CreateAppSession creates and inserts a services.WebSession into the @@ -274,7 +383,7 @@ type NewAppSessionRequest struct { // The certificate is used for all access requests, which is where access // control is enforced. func (a *Server) CreateAppSession(ctx context.Context, req *proto.CreateAppSessionRequest, identity tlsca.Identity, checker services.AccessChecker) (types.WebSession, error) { - if !modules.GetModules().Features().App { + if !modules.GetModules().Features().GetEntitlement(entitlements.App).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for application access, please contact the cluster administrator") } @@ -325,6 +434,8 @@ func (a *Server) CreateAppSession(ctx context.Context, req *proto.CreateAppSessi AzureIdentity: req.AzureIdentity, GCPServiceAccount: req.GCPServiceAccount, MFAVerified: verifiedMFADeviceID, + AppName: req.AppName, + AppURI: req.URI, DeviceExtensions: DeviceExtensions(identity.DeviceExtensions), }) if err != nil { @@ -335,11 +446,15 @@ func (a *Server) CreateAppSession(ctx context.Context, req *proto.CreateAppSessi } func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionRequest) (types.WebSession, error) { - if !modules.GetModules().Features().App { + if !modules.GetModules().Features().GetEntitlement(entitlements.App).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for application access, please contact the cluster administrator") } + if req.CreateDeviceWebToken { + return nil, trace.BadParameter("parameter CreateDeviceWebToken disallowed for App Sessions") + } + user, err := a.GetUserOrLoginState(ctx, req.User) if err != nil { return nil, trace.Wrap(err) @@ -430,6 +545,42 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR } log.Debugf("Generated application web session for %v with TTL %v.", req.User, req.SessionTTL) UserLoginCount.Inc() + + userMetadata := req.Identity.GetUserMetadata() + userMetadata.User = session.GetUser() + userMetadata.AWSRoleARN = req.AWSRoleARN + + err = a.emitter.EmitAuditEvent(a.closeCtx, &apievents.AppSessionStart{ + Metadata: apievents.Metadata{ + Type: events.AppSessionStartEvent, + Code: events.AppSessionStartCode, + ClusterName: req.ClusterName, + }, + ServerMetadata: apievents.ServerMetadata{ + ServerVersion: teleport.Version, + ServerID: a.ServerID, + ServerNamespace: apidefaults.Namespace, + }, + SessionMetadata: apievents.SessionMetadata{ + SessionID: session.GetName(), + WithMFA: req.MFAVerified, + PrivateKeyPolicy: string(req.Identity.PrivateKeyPolicy), + }, + UserMetadata: userMetadata, + ConnectionMetadata: apievents.ConnectionMetadata{ + RemoteAddr: req.ClientAddr, + }, + PublicAddr: req.PublicAddr, + AppMetadata: apievents.AppMetadata{ + AppURI: req.AppURI, + AppPublicAddr: req.PublicAddr, + AppName: req.AppName, + }, + }) + if err != nil { + log.WithError(err).Warn("Failed to emit app session start event") + } + return session, nil } @@ -520,7 +671,7 @@ func (a *Server) CreateSessionCert(userState services.UserState, sessionTTL time func (a *Server) CreateSnowflakeSession(ctx context.Context, req types.CreateSnowflakeSessionRequest, identity tlsca.Identity, checker services.AccessChecker, ) (types.WebSession, error) { - if !modules.GetModules().Features().DB { + if !modules.GetModules().Features().GetEntitlement(entitlements.DB).Enabled { return nil, trace.AccessDenied( "this Teleport cluster is not licensed for database access, please contact the cluster administrator") } diff --git a/lib/auth/sessions_test.go b/lib/auth/sessions_test.go new file mode 100644 index 0000000000000..4af78758d24f9 --- /dev/null +++ b/lib/auth/sessions_test.go @@ -0,0 +1,85 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package auth + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1" + "github.com/gravitational/teleport/api/types" +) + +func TestServer_CreateWebSessionFromReq_deviceWebToken(t *testing.T) { + t.Parallel() + + testAuthServer, err := NewTestAuthServer(TestAuthServerConfig{ + Dir: t.TempDir(), + }) + require.NoError(t, err, "NewTestAuthServer failed") + t.Cleanup(func() { + assert.NoError(t, testAuthServer.Close(), "testAuthServer.Close() errored") + }) + + authServer := testAuthServer.AuthServer + ctx := context.Background() + + // Wire a fake CreateDeviceWebTokenFunc to authServer. + fakeWebToken := &devicepb.DeviceWebToken{ + Id: "423f10ed-c3c1-4de7-99dc-3bc5b9ab7fd5", + Token: "409d21e4-9563-497f-9393-1209f9e4289c", + } + wantToken := &types.DeviceWebToken{ + Id: fakeWebToken.Id, + Token: fakeWebToken.Token, + } + authServer.SetCreateDeviceWebTokenFunc(func(ctx context.Context, dwt *devicepb.DeviceWebToken) (*devicepb.DeviceWebToken, error) { + return fakeWebToken, nil + }) + + const userLlama = "llama" + user, _, err := CreateUserAndRole(authServer, userLlama, []string{userLlama} /* logins */, nil /* allowRules */) + require.NoError(t, err, "CreateUserAndRole failed") + + // Arbitrary, real-looking values. + const loginIP = "40.89.244.232" + const loginUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" + + t.Run("ok", func(t *testing.T) { + session, err := authServer.CreateWebSessionFromReq(ctx, NewWebSessionRequest{ + User: userLlama, + LoginIP: loginIP, + LoginUserAgent: loginUserAgent, + Roles: user.GetRoles(), + Traits: user.GetTraits(), + SessionTTL: 1 * time.Minute, + LoginTime: time.Now(), + CreateDeviceWebToken: true, + }) + require.NoError(t, err, "CreateWebSessionFromReq failed") + + gotToken := session.GetDeviceWebToken() + if diff := cmp.Diff(wantToken, gotToken); diff != "" { + t.Errorf("CreateWebSessionFromReq DeviceWebToken mismatch (-want +got)\n%s", diff) + } + }) +} diff --git a/lib/auth/usage_test.go b/lib/auth/usage_test.go index c394d2c860f28..4cc3e36ac9e8c 100644 --- a/lib/auth/usage_test.go +++ b/lib/auth/usage_test.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/events" eventstest "github.com/gravitational/teleport/lib/events/test" "github.com/gravitational/teleport/lib/modules" @@ -72,8 +73,8 @@ func TestAccessRequest_WithAndWithoutLimit(t *testing.T) { _, err = s.testpack.a.CreateAccessRequestV2(ctx, req, tlsca.Identity{}) require.Error(t, err, "expected access request creation to fail due to the monthly limit") - // Lift limit with IGS, expect no limit error. - s.features.IdentityGovernanceSecurity = true + // Lift limit, expect no limit error. + s.features.Entitlements[entitlements.AccessRequests] = modules.EntitlementInfo{Enabled: true, Limit: 0} modules.SetTestModules(t, &modules.TestModules{ TestFeatures: s.features, }) @@ -81,20 +82,12 @@ func TestAccessRequest_WithAndWithoutLimit(t *testing.T) { require.NoError(t, err) // Put back limit, expect limit error. - s.features.IdentityGovernanceSecurity = false + s.features.Entitlements[entitlements.AccessRequests] = modules.EntitlementInfo{Enabled: true, Limit: 1} modules.SetTestModules(t, &modules.TestModules{ TestFeatures: s.features, }) _, err = s.testpack.a.CreateAccessRequestV2(ctx, req, tlsca.Identity{}) require.Error(t, err, "expected access request creation to fail due to the monthly limit") - - // Lift limit with legacy non-usage based, expect no limit error. - s.features.IsUsageBasedBilling = false - modules.SetTestModules(t, &modules.TestModules{ - TestFeatures: s.features, - }) - _, err = s.testpack.a.CreateAccessRequestV2(ctx, req, tlsca.Identity{}) - require.NoError(t, err) } type setupAccessRequestLimist struct { @@ -105,7 +98,7 @@ type setupAccessRequestLimist struct { } func setUpAccessRequestLimitForJulyAndAugust(t *testing.T, username string, rolename string) setupAccessRequestLimist { - monthlyLimit := 3 + monthlyLimit := int32(3) makeEvent := func(eventType string, id string, timestamp time.Time) apievents.AuditEvent { return &apievents.AccessRequestCreate{ @@ -119,7 +112,7 @@ func setUpAccessRequestLimitForJulyAndAugust(t *testing.T, username string, role features := modules.GetModules().Features() features.IsUsageBasedBilling = true - features.AccessRequests.MonthlyRequestLimit = monthlyLimit + features.Entitlements[entitlements.AccessRequests] = modules.EntitlementInfo{Limit: monthlyLimit, Enabled: true} modules.SetTestModules(t, &modules.TestModules{ TestFeatures: features, }) @@ -182,7 +175,7 @@ func setUpAccessRequestLimitForJulyAndAugust(t *testing.T, username string, role return setupAccessRequestLimist{ testpack: p, - monthlyLimit: monthlyLimit, + monthlyLimit: int(monthlyLimit), features: features, clock: clock, } diff --git a/lib/auth/userloginstate/generator_test.go b/lib/auth/userloginstate/generator_test.go index c7a9f591d1a6d..caf433dd2bf80 100644 --- a/lib/auth/userloginstate/generator_test.go +++ b/lib/auth/userloginstate/generator_test.go @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport/api/types/header" "github.com/gravitational/teleport/api/types/trait" "github.com/gravitational/teleport/api/types/userloginstate" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/backend/memory" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" @@ -398,8 +399,10 @@ func TestAccessLists(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - Cloud: test.cloud, - IdentityGovernanceSecurity: true, + Cloud: test.cloud, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Identity: {Enabled: true}, + }, }, }) diff --git a/lib/auth/webauthn/login.go b/lib/auth/webauthn/login.go index 8af8cab5cce80..575e80f1368c3 100644 --- a/lib/auth/webauthn/login.go +++ b/lib/auth/webauthn/login.go @@ -357,7 +357,7 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred } // Update last used timestamp and device counter. - if err := setCounterAndTimestamps(dev, credential); err != nil { + if err := updateCredentialAndTimestamps(dev, credential, discoverableLogin); err != nil { return nil, trace.Wrap(err) } // Retroactively write the credential RPID, now that it cleared authn. @@ -420,15 +420,26 @@ func findDeviceByID(devices []*types.MFADevice, id []byte) (*types.MFADevice, bo return nil, false } -func setCounterAndTimestamps(dev *types.MFADevice, credential *wan.Credential) error { - switch d := dev.Device.(type) { +func updateCredentialAndTimestamps( + dest *types.MFADevice, + credential *wan.Credential, + discoverableLogin bool, +) error { + switch d := dest.Device.(type) { case *types.MFADevice_U2F: d.U2F.Counter = credential.Authenticator.SignCount case *types.MFADevice_Webauthn: d.Webauthn.SignatureCounter = credential.Authenticator.SignCount + + // Backfill ResidentKey field. + // This may happen if an authenticator created for "MFA" was actually + // resident all along (eg, Safari/Touch ID registrations). + if discoverableLogin && !d.Webauthn.ResidentKey { + d.Webauthn.ResidentKey = true + } default: return trace.BadParameter("unexpected device type for webauthn: %T", d) } - dev.LastUsed = time.Now() + dest.LastUsed = time.Now() return nil } diff --git a/lib/auth/webauthn/login_test.go b/lib/auth/webauthn/login_test.go index 3ce55ea748c6d..acc60765f7242 100644 --- a/lib/auth/webauthn/login_test.go +++ b/lib/auth/webauthn/login_test.go @@ -1018,6 +1018,68 @@ func TestLoginFlow_userVerification(t *testing.T) { } } +func TestPasswordlessFlow_backfillResidentKey(t *testing.T) { + t.Parallel() + + key, err := mocku2f.Create() + require.NoError(t, err, "Create failed") + key.SetPasswordless() + + const user = "llama" + const origin = "https://example.com" + webIdentity := newFakeIdentity(user) + webConfig := &types.Webauthn{RPID: "example.com"} + ctx := context.Background() + + // Register passwordless device as MFA. + // (Providers might make it passwordless regardless.) + rf := &wanlib.RegistrationFlow{ + Webauthn: webConfig, + Identity: webIdentity, + } + cc, err := rf.Begin(ctx, user, false /* passwordless */) + require.NoError(t, err, "Begin failed") + ccr, err := key.SignCredentialCreation(origin, cc) + require.NoError(t, err, "SignCredentialCreation failed") + mfaDev, err := rf.Finish(ctx, wanlib.RegisterResponse{ + User: user, + DeviceName: "mydevice", + CreationResponse: ccr, + }) + require.NoError(t, err, "Finish failed") + // Sanity check. + require.False(t, + mfaDev.GetWebauthn().ResidentKey, + "MFA device unexpectedly marked as resident key", + ) + + // Set the UserHandle in our fake key. A "regular" authenticator would save + // the handle during registration, but our fake only does that for + // "passwordless" registrations. + wla, err := webIdentity.GetWebauthnLocalAuth(ctx, user) + require.NoError(t, err, "GetWebauthnLocalAuth failed") + key.UserHandle = wla.UserID + + t.Run("ok", func(t *testing.T) { + lf := &wanlib.PasswordlessFlow{ + Webauthn: webConfig, + Identity: webIdentity, + } + + // Login. + assertion, err := lf.Begin(ctx) + require.NoError(t, err, "Begin failed") + assertionResp, err := key.SignAssertion(origin, assertion) + require.NoError(t, err, "SignAssertion failed") + loginData, err := lf.Finish(ctx, assertionResp) + require.NoError(t, err, "Finish failed") + + // Verify that we corrected the ResidentKey field. + mfaDev := loginData.Device + assert.True(t, mfaDev.GetWebauthn().ResidentKey, "ResidentKey field not corrected") + }) +} + type fakeIdentity struct { User *types.UserV2 // MappedUser is used as the reply to GetTeleportUserByWebauthnID. diff --git a/lib/auth/windows/configure-ad.ps1 b/lib/auth/windows/configure-ad.ps1 index aceac25d6b43c..e33127976ecb2 100644 --- a/lib/auth/windows/configure-ad.ps1 +++ b/lib/auth/windows/configure-ad.ps1 @@ -18,7 +18,7 @@ This script will configure your Active Directory system to integrate with Telepo - Enabling RemoteFX for improved remote desktop performance. Ensure you've reviewed this script itself and/or the equivalent manual documentation before proceeding. -For the manual documentation, see: https://goteleport.com/docs/desktop-access/active-directory +For the manual documentation, see: https://goteleport.com/docs/enroll-resources/desktop-access/active-directory Press 'Y' to acknowledge and continue, or any other key to exit. "@ @@ -223,9 +223,9 @@ connections. The next step is to connect a Windows Desktop Service to your Teleport cluster and configure it to connect to the LDAP server of this domain. Instructions for this can be found starting at -https://goteleport.com/docs/desktop-access/active-directory/#step-67-configure-teleport. You may -use the `ldap` section printed above as the basis for your Windows Desktop Service configuration, -which contains values derived from the configuration of this domain.`n +https://goteleport.com/docs/enroll-resources/desktop-access/active-directory/#step-67-configure-teleport. +You may use the `ldap` section printed above as the basis for your Windows Desktop Service +configuration, which contains values derived from the configuration of this domain.`n "@ -f $LDAP_CONFIG_YAML Write-Output $OUTPUT @@ -234,7 +234,7 @@ if ($host.name -match 'ISE') { $WHITESPACE_WARNING=@' # WARNING: -# If you'r copying and pasting the ldap config from above, PowerShell ISE will add whitespace to the start - delete this before you save the config. +# If you're copying and pasting the ldap config from above, PowerShell ISE will add whitespace to the start - delete this before you save the config. '@ Write-Output $WHITESPACE_WARNING diff --git a/lib/backend/dynamo/shards.go b/lib/backend/dynamo/shards.go index 1d912deec02d0..52641b6208dde 100644 --- a/lib/backend/dynamo/shards.go +++ b/lib/backend/dynamo/shards.go @@ -165,7 +165,7 @@ func (b *Backend) pollStreams(externalCtx context.Context) error { } delete(set, event.shardID) if !errors.Is(event.err, io.EOF) { - b.Debugf("Shard ID %v closed with error: %v, reseting buffers.", event.shardID, event.err) + b.Debugf("Shard ID %v closed with error: %v, resetting buffers.", event.shardID, event.err) return trace.Wrap(event.err) } b.Tracef("Shard ID %v exited gracefully.", event.shardID) diff --git a/lib/client/api.go b/lib/client/api.go index 5886995e24f38..4f1086827dd9c 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -600,6 +600,14 @@ func RetryWithRelogin(ctx context.Context, tc *TeleportClient, fn func() error, case tc.NonInteractive: return trace.Wrap(fnErr, "cannot relogin in non-interactive session") case !IsErrorResolvableWithRelogin(fnErr): + // If the connection to Auth was unexpectedly cut, see if the client is too + // old to interact with the cluster. + if errors.Is(fnErr, io.EOF) || (trace.IsConnectionProblem(fnErr) && strings.Contains(fnErr.Error(), "error reading from server: EOF")) { + // The results are intentionally ignored - Ping prints warnings + // related to versions, and that's all that is needed here. + _, _ = tc.Ping(ctx) + } + return trace.Wrap(fnErr) } opt := defaultRetryWithReloginOptions() diff --git a/lib/client/redirect.go b/lib/client/redirect.go index 04d1ce6b1b94f..1e88f4b1cde6e 100644 --- a/lib/client/redirect.go +++ b/lib/client/redirect.go @@ -135,7 +135,12 @@ func NewRedirector(ctx context.Context, login SSHLoginSSO, config *RedirectorCon if err != nil { return nil, trace.Wrap(err) } - callbackURL.Scheme = "https" + // Default to HTTPS if no scheme is specified. + // This will allow users to specify an insecure HTTP URL but + // the backend will verify if the callback URL is allowed. + if callbackURL.Scheme == "" { + callbackURL.Scheme = "https" + } callbackAddr = callbackURL.String() } diff --git a/lib/cloud/aws/policy_statements.go b/lib/cloud/aws/policy_statements.go index ead15df770078..07b890ea99aa0 100644 --- a/lib/cloud/aws/policy_statements.go +++ b/lib/cloud/aws/policy_statements.go @@ -219,6 +219,8 @@ func StatementForListRDSDatabases() *Statement { "rds:DescribeDBInstances", "rds:DescribeDBClusters", "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs", }, Resources: allResources, } diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 220d3fe019722..0052fbfcbf475 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -327,6 +327,12 @@ type IntegrationConfEC2SSMIAM struct { // No trailing / is expected. // Eg https://tenant.teleport.sh ProxyPublicURL string + // ClusterName is the Teleport cluster name. + // Used for resource tagging. + ClusterName string + // IntegrationName is the Teleport AWS OIDC Integration name. + // Used for resource tagging. + IntegrationName string } // IntegrationConfEKSIAM contains the arguments of diff --git a/lib/events/api.go b/lib/events/api.go index 8ac05d415ddde..93d2cfc9d04fc 100644 --- a/lib/events/api.go +++ b/lib/events/api.go @@ -757,6 +757,10 @@ const ( // SPIFFESVIDIssuedEvent is emitted when a SPIFFE SVID is issued. SPIFFESVIDIssuedEvent = "spiffe.svid.issued" + // SPIFFEFederationCreateEvent is emitted when a SPIFFE federation is created. + SPIFFEFederationCreateEvent = "spiffe.federation.create" + // SPIFFEFederationDeleteEvent is emitted when a SPIFFE federation is deleted. + SPIFFEFederationDeleteEvent = "spiffe.federation.delete" // AuthPreferenceUpdateEvent is emitted when a user updates the cluster authentication preferences. AuthPreferenceUpdateEvent = "auth_preference.update" @@ -790,6 +794,9 @@ const ( IntegrationDeleteEvent = "integration.delete" ) +// Add an entry to eventsMap in lib/events/events_test.go when you add +// a new event name here. + const ( // MaxChunkBytes defines the maximum size of a session stream chunk that // can be requested via AuditLog.GetSessionChunk(). Set to 5MB @@ -877,6 +884,9 @@ type StreamPart struct { Number int64 // ETag is a part e-tag ETag string + // LastModified is the time of last modification of this part (if + // available). + LastModified time.Time } // StreamUpload represents stream multipart upload diff --git a/lib/events/auditlog.go b/lib/events/auditlog.go index 709e2c7a23d95..5cb3ab744c31d 100644 --- a/lib/events/auditlog.go +++ b/lib/events/auditlog.go @@ -111,6 +111,10 @@ const ( // AbandonedUploadPollingRate defines how often to check for // abandoned uploads which need to be completed. AbandonedUploadPollingRate = apidefaults.SessionTrackerTTL / 6 + + // UploadCompleterGracePeriod is the default period after which an upload's + // session tracker will be checked to see if it's an abandoned upload. + UploadCompleterGracePeriod = 24 * time.Hour ) var ( diff --git a/lib/events/azsessions/azsessions.go b/lib/events/azsessions/azsessions.go index 85aa13d39084d..527f024670825 100644 --- a/lib/events/azsessions/azsessions.go +++ b/lib/events/azsessions/azsessions.go @@ -28,6 +28,7 @@ import ( "slices" "strconv" "strings" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" @@ -450,7 +451,8 @@ func (h *Handler) UploadPart(ctx context.Context, upload events.StreamUpload, pa // our parts are just over 5 MiB (events.MinUploadPartSizeBytes) so we can // upload them in one shot - if _, err := cErr(partBlob.Upload(ctx, streaming.NopCloser(partBody), nil)); err != nil { + response, err := cErr(partBlob.Upload(ctx, streaming.NopCloser(partBody), nil)) + if err != nil { return nil, trace.Wrap(err) } h.log.WithFields(logrus.Fields{ @@ -459,7 +461,11 @@ func (h *Handler) UploadPart(ctx context.Context, upload events.StreamUpload, pa fieldPartNumber: partNumber, }).Debug("Uploaded part.") - return &events.StreamPart{Number: partNumber}, nil + var lastModified time.Time + if response.LastModified != nil { + lastModified = *response.LastModified + } + return &events.StreamPart{Number: partNumber, LastModified: lastModified}, nil } // ListParts implements [events.MultipartUploader]. @@ -492,8 +498,15 @@ func (h *Handler) ListParts(ctx context.Context, upload events.StreamUpload) ([] if err != nil { continue } - - parts = append(parts, events.StreamPart{Number: partNumber}) + var lastModified time.Time + if b.Properties != nil && + b.Properties.LastModified != nil { + lastModified = *b.Properties.LastModified + } + parts = append(parts, events.StreamPart{ + Number: partNumber, + LastModified: lastModified, + }) } } diff --git a/lib/events/codes.go b/lib/events/codes.go index 50f0d56147a93..e800eb5f41551 100644 --- a/lib/events/codes.go +++ b/lib/events/codes.go @@ -39,7 +39,8 @@ type Event struct { // - Suffix code with one of these letters: I (info), W (warn), E (error). // // After defining an event code, make sure to keep -// `web/packages/teleport/src/services/audit/types.ts` in sync. +// `web/packages/teleport/src/services/audit/types.ts` in sync and add an +// entry in the `eventsMap` in `lib/events/events_test.go`. const ( // UserLocalLoginCode is the successful local user login event code. UserLocalLoginCode = "T1000I" @@ -609,6 +610,10 @@ const ( SPIFFESVIDIssuedSuccessCode = "TSPIFFE000I" // SPIFFESVIDIssuedFailureCode is the SPIFFE SVID issued failure code. SPIFFESVIDIssuedFailureCode = "TSPIFFE000E" + // SPIFFEFederationCreateCode is the SPIFFE Federation created code. + SPIFFEFederationCreateCode = "TSPIFFE001I" + // SPIFFEFederationDeleteCode is the SPIFFE Federation deleted code. + SPIFFEFederationDeleteCode = "TSPIFFE002I" // AuthPreferenceUpdateCode is the auth preference updated event code. AuthPreferenceUpdateCode = "TCAUTH001I" diff --git a/lib/events/complete.go b/lib/events/complete.go index b335363e667c2..62e610df1d7ce 100644 --- a/lib/events/complete.go +++ b/lib/events/complete.go @@ -19,6 +19,7 @@ package events import ( + "cmp" "context" "fmt" "os" @@ -59,6 +60,11 @@ type UploadCompleterConfig struct { Component string // CheckPeriod is a period for checking the upload CheckPeriod time.Duration + // GracePeriod is the period after which an upload's session tracker will be + // checked to see if it's an abandoned upload. A duration of zero will + // result in a sensible default, any negative value will result in no grace + // period. + GracePeriod time.Duration // Clock is used to override clock in tests Clock clockwork.Clock // ClusterName identifies the originating teleport cluster @@ -221,11 +227,21 @@ func (u *UploadCompleter) CheckUploads(ctx context.Context) error { } }() + gracePeriod := cmp.Or(u.cfg.GracePeriod, UploadCompleterGracePeriod) incompleteSessionUploads.Set(float64(len(uploads))) // Complete upload for any uploads without an active session tracker for _, upload := range uploads { log := u.log.WithField("upload", upload.ID).WithField("session", upload.SessionID) + if gracePeriod > 0 && u.cfg.Clock.Since(upload.Initiated) <= gracePeriod { + log.Debug("Found incomplete upload within grace period, terminating check early.") + // not only we can skip this upload, but since uploads are sorted by + // Initiated oldest-to-newest, we can actually just stop checking as + // all further uploads will be closer in time to now and thus they + // will all be within the grace period + break + } + switch _, err := u.cfg.SessionTracker.GetSessionTracker(ctx, upload.SessionID.String()); { case err == nil: // session is still in progress, continue to other uploads log.Debug("session has active tracker and is not ready to be uploaded") @@ -247,6 +263,16 @@ func (u *UploadCompleter) CheckUploads(ctx context.Context) error { } return trace.Wrap(err, "listing parts") } + var lastModified time.Time + for _, part := range parts { + if part.LastModified.After(lastModified) { + lastModified = part.LastModified + } + } + if u.cfg.Clock.Since(lastModified) <= gracePeriod { + log.Debug("Found incomplete upload with recently uploaded part, skipping.") + continue + } log.Debugf("upload has %d parts", len(parts)) diff --git a/lib/events/complete_test.go b/lib/events/complete_test.go index e21b20e1e2058..a810f690682f2 100644 --- a/lib/events/complete_test.go +++ b/lib/events/complete_test.go @@ -71,6 +71,7 @@ func TestUploadCompleterCompletesAbandonedUploads(t *testing.T) { SessionTracker: sessionTrackerService, Clock: clock, ClusterName: "teleport-cluster", + GracePeriod: 24 * time.Hour, }) require.NoError(t, err) @@ -81,7 +82,18 @@ func TestUploadCompleterCompletesAbandonedUploads(t *testing.T) { require.NoError(t, err) require.False(t, mu.IsCompleted(upload.ID)) - clock.Advance(1 * time.Hour) + // enough to expire the session tracker, not enough to pass the grace period + clock.Advance(2 * time.Hour) + + err = uc.CheckUploads(context.Background()) + require.NoError(t, err) + require.False(t, mu.IsCompleted(upload.ID)) + + trackers, err := sessionTrackerService.GetActiveSessionTrackers(context.Background()) + require.NoError(t, err) + require.Empty(t, trackers) + + clock.Advance(22*time.Hour + time.Nanosecond) err = uc.CheckUploads(context.Background()) require.NoError(t, err) @@ -147,6 +159,7 @@ func TestUploadCompleterAcquiresSemaphore(t *testing.T) { }, acquireErr: nil, }, + GracePeriod: -1, }) require.NoError(t, err) @@ -193,6 +206,7 @@ func TestUploadCompleterEmitsSessionEnd(t *testing.T) { Clock: clock, SessionTracker: &mockSessionTrackerService{}, ClusterName: "teleport-cluster", + GracePeriod: -1, }) require.NoError(t, err) @@ -224,6 +238,63 @@ func TestUploadCompleterEmitsSessionEnd(t *testing.T) { } } +func TestCheckUploadsSkipsUploadsInProgress(t *testing.T) { + clock := clockwork.NewFakeClock() + sessionTrackers := []types.SessionTracker{} + + sessionTrackerService := &mockSessionTrackerService{ + clock: clock, + trackers: sessionTrackers, + } + + // simulate an upload that started well before the grace period, + // but the most recently uploaded part is still within the grace period + gracePeriod := 10 * time.Minute + uploadInitiated := clock.Now().Add(-3 * gracePeriod) + lastPartUploaded := clock.Now().Add(-2 * gracePeriod / 3) + + var completedUploads []events.StreamUpload + + uploader := &eventstest.MockUploader{ + MockListUploads: func(ctx context.Context) ([]events.StreamUpload, error) { + return []events.StreamUpload{ + { + ID: "upload-1234", + SessionID: session.NewID(), + Initiated: uploadInitiated, + }, + }, nil + }, + MockListParts: func(ctx context.Context, upload events.StreamUpload) ([]events.StreamPart, error) { + return []events.StreamPart{ + { + Number: int64(1), + ETag: "foo", + LastModified: lastPartUploaded, + }, + }, nil + }, + MockCompleteUpload: func(ctx context.Context, upload events.StreamUpload, parts []events.StreamPart) error { + completedUploads = append(completedUploads, upload) + return nil + }, + } + + uc, err := events.NewUploadCompleter(events.UploadCompleterConfig{ + Uploader: uploader, + AuditLog: &eventstest.MockAuditLog{}, + SessionTracker: sessionTrackerService, + Clock: clock, + ClusterName: "teleport-cluster", + GracePeriod: gracePeriod, + }) + require.NoError(t, err) + + uc.CheckUploads(context.Background()) + require.Empty(t, completedUploads) + +} + func TestCheckUploadsContinuesOnError(t *testing.T) { clock := clockwork.NewFakeClock() expires := clock.Now().Add(time.Hour * 1) @@ -286,6 +357,7 @@ func TestCheckUploadsContinuesOnError(t *testing.T) { SessionTracker: sessionTrackerService, Clock: clock, ClusterName: "teleport-cluster", + GracePeriod: -1, }) require.NoError(t, err) diff --git a/lib/events/dynamic.go b/lib/events/dynamic.go index bac9b583b46fc..a081860c656c0 100644 --- a/lib/events/dynamic.go +++ b/lib/events/dynamic.go @@ -385,24 +385,35 @@ func FromEventFields(fields EventFields) (events.AuditEvent, error) { case UnknownEvent: e = &events.Unknown{} - case CassandraBatchEventCode: + case DatabaseSessionCassandraBatchEvent: e = &events.CassandraBatch{} - case CassandraRegisterEventCode: + case DatabaseSessionCassandraRegisterEvent: e = &events.CassandraRegister{} - case CassandraPrepareEventCode: + case DatabaseSessionCassandraPrepareEvent: e = &events.CassandraPrepare{} - case CassandraExecuteEventCode: + case DatabaseSessionCassandraExecuteEvent: e = &events.CassandraExecute{} - case DiscoveryConfigCreateCode: + case DiscoveryConfigCreateEvent: e = &events.DiscoveryConfigCreate{} - case DiscoveryConfigUpdateCode: + case DiscoveryConfigUpdateEvent: e = &events.DiscoveryConfigUpdate{} - case DiscoveryConfigDeleteCode: + case DiscoveryConfigDeleteEvent: e = &events.DiscoveryConfigDelete{} - case DiscoveryConfigDeleteAllCode: + case DiscoveryConfigDeleteAllEvent: e = &events.DiscoveryConfigDeleteAll{} + case SPIFFEFederationCreateEvent: + e = &events.SPIFFEFederationCreate{} + case SPIFFEFederationDeleteEvent: + e = &events.SPIFFEFederationDelete{} + case IntegrationCreateEvent: + e = &events.IntegrationCreate{} + case IntegrationUpdateEvent: + e = &events.IntegrationUpdate{} + case IntegrationDeleteEvent: + e = &events.IntegrationDelete{} + default: log.Errorf("Attempted to convert dynamic event of unknown type %q into protobuf event.", eventType) unknown := &events.Unknown{} diff --git a/lib/events/events_test.go b/lib/events/events_test.go index 4f8a9817a1dbd..f7e90d38e2d64 100644 --- a/lib/events/events_test.go +++ b/lib/events/events_test.go @@ -20,6 +20,7 @@ package events import ( "encoding/json" + "fmt" "reflect" "testing" "time" @@ -30,6 +31,191 @@ import ( "github.com/gravitational/teleport/lib/utils" ) +// eventsMap maps event names to event types for testing. Be sure to update +// this map if you add a new event type. +var eventsMap = map[string]apievents.AuditEvent{ + SessionPrintEvent: &apievents.SessionPrint{}, + SessionStartEvent: &apievents.SessionStart{}, + SessionEndEvent: &apievents.SessionEnd{}, + SessionUploadEvent: &apievents.SessionUpload{}, + SessionJoinEvent: &apievents.SessionJoin{}, + SessionLeaveEvent: &apievents.SessionLeave{}, + SessionDataEvent: &apievents.SessionData{}, + ClientDisconnectEvent: &apievents.ClientDisconnect{}, + UserLoginEvent: &apievents.UserLogin{}, + UserDeleteEvent: &apievents.UserDelete{}, + UserCreateEvent: &apievents.UserCreate{}, + UserUpdatedEvent: &apievents.UserUpdate{}, + UserPasswordChangeEvent: &apievents.UserPasswordChange{}, + AccessRequestCreateEvent: &apievents.AccessRequestCreate{}, + AccessRequestReviewEvent: &apievents.AccessRequestCreate{}, + AccessRequestUpdateEvent: &apievents.AccessRequestCreate{}, + AccessRequestResourceSearch: &apievents.AccessRequestResourceSearch{}, + BillingCardCreateEvent: &apievents.BillingCardCreate{}, + BillingCardUpdateEvent: &apievents.BillingCardCreate{}, + BillingCardDeleteEvent: &apievents.BillingCardDelete{}, + BillingInformationUpdateEvent: &apievents.BillingInformationUpdate{}, + ResetPasswordTokenCreateEvent: &apievents.UserTokenCreate{}, + ExecEvent: &apievents.Exec{}, + SubsystemEvent: &apievents.Subsystem{}, + X11ForwardEvent: &apievents.X11Forward{}, + PortForwardEvent: &apievents.PortForward{}, + AuthAttemptEvent: &apievents.AuthAttempt{}, + SCPEvent: &apievents.SCP{}, + ResizeEvent: &apievents.Resize{}, + SessionCommandEvent: &apievents.SessionCommand{}, + SessionDiskEvent: &apievents.SessionDisk{}, + SessionNetworkEvent: &apievents.SessionNetwork{}, + RoleCreatedEvent: &apievents.RoleCreate{}, + RoleUpdatedEvent: &apievents.RoleUpdate{}, + RoleDeletedEvent: &apievents.RoleDelete{}, + TrustedClusterCreateEvent: &apievents.TrustedClusterCreate{}, + TrustedClusterDeleteEvent: &apievents.TrustedClusterDelete{}, + TrustedClusterTokenCreateEvent: &apievents.TrustedClusterTokenCreate{}, //nolint:staticcheck // SA1019. We want to test every event type, even if they're deprecated. + ProvisionTokenCreateEvent: &apievents.ProvisionTokenCreate{}, + GithubConnectorCreatedEvent: &apievents.GithubConnectorCreate{}, + GithubConnectorUpdatedEvent: &apievents.GithubConnectorUpdate{}, + GithubConnectorDeletedEvent: &apievents.GithubConnectorDelete{}, + OIDCConnectorCreatedEvent: &apievents.OIDCConnectorCreate{}, + OIDCConnectorUpdatedEvent: &apievents.OIDCConnectorUpdate{}, + OIDCConnectorDeletedEvent: &apievents.OIDCConnectorDelete{}, + SAMLConnectorCreatedEvent: &apievents.SAMLConnectorCreate{}, + SAMLConnectorUpdatedEvent: &apievents.SAMLConnectorUpdate{}, + SAMLConnectorDeletedEvent: &apievents.SAMLConnectorDelete{}, + SessionRejectedEvent: &apievents.SessionReject{}, + AppSessionStartEvent: &apievents.AppSessionStart{}, + AppSessionEndEvent: &apievents.AppSessionEnd{}, + AppSessionChunkEvent: &apievents.AppSessionChunk{}, + AppSessionRequestEvent: &apievents.AppSessionRequest{}, + AppSessionDynamoDBRequestEvent: &apievents.AppSessionDynamoDBRequest{}, + AppCreateEvent: &apievents.AppCreate{}, + AppUpdateEvent: &apievents.AppUpdate{}, + AppDeleteEvent: &apievents.AppDelete{}, + DatabaseCreateEvent: &apievents.DatabaseCreate{}, + DatabaseUpdateEvent: &apievents.DatabaseUpdate{}, + DatabaseDeleteEvent: &apievents.DatabaseDelete{}, + DatabaseSessionStartEvent: &apievents.DatabaseSessionStart{}, + DatabaseSessionEndEvent: &apievents.DatabaseSessionEnd{}, + DatabaseSessionQueryEvent: &apievents.DatabaseSessionQuery{}, + DatabaseSessionQueryFailedEvent: &apievents.DatabaseSessionQuery{}, + DatabaseSessionMalformedPacketEvent: &apievents.DatabaseSessionMalformedPacket{}, + DatabaseSessionPermissionsUpdateEvent: &apievents.DatabasePermissionUpdate{}, + DatabaseSessionUserCreateEvent: &apievents.DatabaseUserCreate{}, + DatabaseSessionUserDeactivateEvent: &apievents.DatabaseUserDeactivate{}, + DatabaseSessionPostgresParseEvent: &apievents.PostgresParse{}, + DatabaseSessionPostgresBindEvent: &apievents.PostgresBind{}, + DatabaseSessionPostgresExecuteEvent: &apievents.PostgresExecute{}, + DatabaseSessionPostgresCloseEvent: &apievents.PostgresClose{}, + DatabaseSessionPostgresFunctionEvent: &apievents.PostgresFunctionCall{}, + DatabaseSessionMySQLStatementPrepareEvent: &apievents.MySQLStatementPrepare{}, + DatabaseSessionMySQLStatementExecuteEvent: &apievents.MySQLStatementExecute{}, + DatabaseSessionMySQLStatementSendLongDataEvent: &apievents.MySQLStatementSendLongData{}, + DatabaseSessionMySQLStatementCloseEvent: &apievents.MySQLStatementClose{}, + DatabaseSessionMySQLStatementResetEvent: &apievents.MySQLStatementReset{}, + DatabaseSessionMySQLStatementFetchEvent: &apievents.MySQLStatementFetch{}, + DatabaseSessionMySQLStatementBulkExecuteEvent: &apievents.MySQLStatementBulkExecute{}, + DatabaseSessionMySQLInitDBEvent: &apievents.MySQLInitDB{}, + DatabaseSessionMySQLCreateDBEvent: &apievents.MySQLCreateDB{}, + DatabaseSessionMySQLDropDBEvent: &apievents.MySQLDropDB{}, + DatabaseSessionMySQLShutDownEvent: &apievents.MySQLShutDown{}, + DatabaseSessionMySQLProcessKillEvent: &apievents.MySQLProcessKill{}, + DatabaseSessionMySQLDebugEvent: &apievents.MySQLDebug{}, + DatabaseSessionMySQLRefreshEvent: &apievents.MySQLRefresh{}, + DatabaseSessionSQLServerRPCRequestEvent: &apievents.SQLServerRPCRequest{}, + DatabaseSessionElasticsearchRequestEvent: &apievents.ElasticsearchRequest{}, + DatabaseSessionOpenSearchRequestEvent: &apievents.OpenSearchRequest{}, + DatabaseSessionDynamoDBRequestEvent: &apievents.DynamoDBRequest{}, + KubeRequestEvent: &apievents.KubeRequest{}, + MFADeviceAddEvent: &apievents.MFADeviceAdd{}, + MFADeviceDeleteEvent: &apievents.MFADeviceDelete{}, + DeviceEvent: &apievents.DeviceEvent{}, + DeviceCreateEvent: &apievents.DeviceEvent2{}, + DeviceDeleteEvent: &apievents.DeviceEvent2{}, + DeviceUpdateEvent: &apievents.DeviceEvent2{}, + DeviceEnrollEvent: &apievents.DeviceEvent2{}, + DeviceAuthenticateEvent: &apievents.DeviceEvent2{}, + DeviceEnrollTokenCreateEvent: &apievents.DeviceEvent2{}, + DeviceWebTokenCreateEvent: &apievents.DeviceEvent2{}, + DeviceAuthenticateConfirmEvent: &apievents.DeviceEvent2{}, + LockCreatedEvent: &apievents.LockCreate{}, + LockDeletedEvent: &apievents.LockDelete{}, + RecoveryCodeGeneratedEvent: &apievents.RecoveryCodeGenerate{}, + RecoveryCodeUsedEvent: &apievents.RecoveryCodeUsed{}, + RecoveryTokenCreateEvent: &apievents.UserTokenCreate{}, + PrivilegeTokenCreateEvent: &apievents.UserTokenCreate{}, + WindowsDesktopSessionStartEvent: &apievents.WindowsDesktopSessionStart{}, + WindowsDesktopSessionEndEvent: &apievents.WindowsDesktopSessionEnd{}, + DesktopClipboardSendEvent: &apievents.DesktopClipboardSend{}, + DesktopClipboardReceiveEvent: &apievents.DesktopClipboardReceive{}, + SessionConnectEvent: &apievents.SessionConnect{}, + AccessRequestDeleteEvent: &apievents.AccessRequestDelete{}, + CertificateCreateEvent: &apievents.CertificateCreate{}, + RenewableCertificateGenerationMismatchEvent: &apievents.RenewableCertificateGenerationMismatch{}, + SFTPEvent: &apievents.SFTP{}, + UpgradeWindowStartUpdateEvent: &apievents.UpgradeWindowStartUpdate{}, + SessionRecordingAccessEvent: &apievents.SessionRecordingAccess{}, + SSMRunEvent: &apievents.SSMRun{}, + KubernetesClusterCreateEvent: &apievents.KubernetesClusterCreate{}, + KubernetesClusterUpdateEvent: &apievents.KubernetesClusterUpdate{}, + KubernetesClusterDeleteEvent: &apievents.KubernetesClusterDelete{}, + DesktopSharedDirectoryStartEvent: &apievents.DesktopSharedDirectoryStart{}, + DesktopSharedDirectoryReadEvent: &apievents.DesktopSharedDirectoryRead{}, + DesktopSharedDirectoryWriteEvent: &apievents.DesktopSharedDirectoryWrite{}, + BotJoinEvent: &apievents.BotJoin{}, + InstanceJoinEvent: &apievents.InstanceJoin{}, + BotCreateEvent: &apievents.BotCreate{}, + BotUpdateEvent: &apievents.BotUpdate{}, + BotDeleteEvent: &apievents.BotDelete{}, + LoginRuleCreateEvent: &apievents.LoginRuleCreate{}, + LoginRuleDeleteEvent: &apievents.LoginRuleDelete{}, + SAMLIdPAuthAttemptEvent: &apievents.SAMLIdPAuthAttempt{}, + SAMLIdPServiceProviderCreateEvent: &apievents.SAMLIdPServiceProviderCreate{}, + SAMLIdPServiceProviderUpdateEvent: &apievents.SAMLIdPServiceProviderUpdate{}, + SAMLIdPServiceProviderDeleteEvent: &apievents.SAMLIdPServiceProviderDelete{}, + SAMLIdPServiceProviderDeleteAllEvent: &apievents.SAMLIdPServiceProviderDeleteAll{}, + OktaGroupsUpdateEvent: &apievents.OktaResourcesUpdate{}, + OktaApplicationsUpdateEvent: &apievents.OktaResourcesUpdate{}, + OktaSyncFailureEvent: &apievents.OktaSyncFailure{}, + OktaAssignmentProcessEvent: &apievents.OktaAssignmentResult{}, + OktaAssignmentCleanupEvent: &apievents.OktaAssignmentResult{}, + OktaUserSyncEvent: &apievents.OktaUserSync{}, + OktaAccessListSyncEvent: &apievents.OktaAccessListSync{}, + AccessGraphAccessPathChangedEvent: &apievents.AccessPathChanged{}, + AccessListCreateEvent: &apievents.AccessListCreate{}, + AccessListUpdateEvent: &apievents.AccessListUpdate{}, + AccessListDeleteEvent: &apievents.AccessListDelete{}, + AccessListReviewEvent: &apievents.AccessListReview{}, + AccessListMemberCreateEvent: &apievents.AccessListMemberCreate{}, + AccessListMemberUpdateEvent: &apievents.AccessListMemberUpdate{}, + AccessListMemberDeleteEvent: &apievents.AccessListMemberDelete{}, + AccessListMemberDeleteAllForAccessListEvent: &apievents.AccessListMemberDeleteAllForAccessList{}, + SecReportsAuditQueryRunEvent: &apievents.AuditQueryRun{}, + SecReportsReportRunEvent: &apievents.SecurityReportRun{}, + ExternalAuditStorageEnableEvent: &apievents.ExternalAuditStorageEnable{}, + ExternalAuditStorageDisableEvent: &apievents.ExternalAuditStorageDisable{}, + CreateMFAAuthChallengeEvent: &apievents.CreateMFAAuthChallenge{}, + ValidateMFAAuthResponseEvent: &apievents.ValidateMFAAuthResponse{}, + SPIFFESVIDIssuedEvent: &apievents.SPIFFESVIDIssued{}, + AuthPreferenceUpdateEvent: &apievents.AuthPreferenceUpdate{}, + ClusterNetworkingConfigUpdateEvent: &apievents.ClusterNetworkingConfigUpdate{}, + SessionRecordingConfigUpdateEvent: &apievents.SessionRecordingConfigUpdate{}, + DatabaseSessionSpannerRPCEvent: &apievents.SpannerRPC{}, + UnknownEvent: &apievents.Unknown{}, + DatabaseSessionCassandraBatchEvent: &apievents.CassandraBatch{}, + DatabaseSessionCassandraRegisterEvent: &apievents.CassandraRegister{}, + DatabaseSessionCassandraPrepareEvent: &apievents.CassandraPrepare{}, + DatabaseSessionCassandraExecuteEvent: &apievents.CassandraExecute{}, + DiscoveryConfigCreateEvent: &apievents.DiscoveryConfigCreate{}, + DiscoveryConfigUpdateEvent: &apievents.DiscoveryConfigUpdate{}, + DiscoveryConfigDeleteEvent: &apievents.DiscoveryConfigDelete{}, + DiscoveryConfigDeleteAllEvent: &apievents.DiscoveryConfigDeleteAll{}, + IntegrationCreateEvent: &apievents.IntegrationCreate{}, + IntegrationUpdateEvent: &apievents.IntegrationUpdate{}, + IntegrationDeleteEvent: &apievents.IntegrationDelete{}, + SPIFFEFederationCreateEvent: &apievents.SPIFFEFederationCreate{}, + SPIFFEFederationDeleteEvent: &apievents.SPIFFEFederationDelete{}, +} + // TestJSON tests JSON marshal events func TestJSON(t *testing.T) { type testCase struct { @@ -776,3 +962,24 @@ func TestJSON(t *testing.T) { }) } } + +// TestEvents tests that all events can be converted and processed correctly. +func TestEvents(t *testing.T) { + t.Parallel() + + for eventName, eventType := range eventsMap { + t.Run(fmt.Sprintf("%s OneOf", eventName), func(t *testing.T) { + converted, err := apievents.ToOneOf(eventType) + require.NoError(t, err, "failed to convert event type to OneOf, is the event type added to api/types/events/oneof.go?") + auditEvent, err := apievents.FromOneOf(*converted) + require.NoError(t, err, "failed to convert OneOf back to an Audit event") + require.IsType(t, eventType, auditEvent, "FromOneOf did not convert the event type correctly") + }) + + t.Run(fmt.Sprintf("%s EventFields", eventName), func(t *testing.T) { + auditEvent, err := FromEventFields(EventFields{EventType: eventName}) + require.NoError(t, err, "failed to convert EventFields to an Audit event, is the event type added to lib/events/dynamic.go?") + require.IsType(t, eventType, auditEvent, "FromEventFields did not convert the event type correctly") + }) + } +} diff --git a/lib/events/eventstest/uploader.go b/lib/events/eventstest/uploader.go index 63a30cd242684..99cee3b1e3f94 100644 --- a/lib/events/eventstest/uploader.go +++ b/lib/events/eventstest/uploader.go @@ -55,6 +55,8 @@ type MemoryUploader struct { objects map[session.ID][]byte eventsC chan events.UploadEvent + // Clock is an optional [clockwork.Clock] to determine the time to associate + // with uploads and parts. Clock clockwork.Clock } @@ -63,7 +65,7 @@ type MemoryUpload struct { // id is the upload ID id string // parts is the upload parts - parts map[int64][]byte + parts map[int64]part // sessionID is the session ID associated with the upload sessionID session.ID //completed specifies upload as completed @@ -73,6 +75,11 @@ type MemoryUpload struct { Initiated time.Time } +type part struct { + data []byte + lastModified time.Time +} + func (m *MemoryUploader) trySendEvent(event events.UploadEvent) { if m.eventsC == nil { return @@ -98,6 +105,7 @@ func (m *MemoryUploader) CreateUpload(ctx context.Context, sessionID session.ID) upload := &events.StreamUpload{ ID: uuid.New().String(), SessionID: sessionID, + Initiated: time.Now(), } if m.Clock != nil { upload.Initiated = m.Clock.Now() @@ -105,7 +113,7 @@ func (m *MemoryUploader) CreateUpload(ctx context.Context, sessionID session.ID) m.uploads[upload.ID] = &MemoryUpload{ id: upload.ID, sessionID: sessionID, - parts: make(map[int64][]byte), + parts: make(map[int64]part), Initiated: upload.Initiated, } return upload, nil @@ -127,11 +135,11 @@ func (m *MemoryUploader) CompleteUpload(ctx context.Context, upload events.Strea partsSet := make(map[int64]bool, len(parts)) for _, part := range parts { partsSet[part.Number] = true - data, ok := up.parts[part.Number] + upPart, ok := up.parts[part.Number] if !ok { return trace.NotFound("part %v has not been uploaded", part.Number) } - result = append(result, data...) + result = append(result, upPart.data...) } // exclude parts that are not requested to be completed for number := range up.parts { @@ -157,8 +165,15 @@ func (m *MemoryUploader) UploadPart(ctx context.Context, upload events.StreamUpl if !ok { return nil, trace.NotFound("upload %q is not found", upload.ID) } - up.parts[partNumber] = data - return &events.StreamPart{Number: partNumber}, nil + lastModified := time.Now() + if m.Clock != nil { + lastModified = m.Clock.Now() + } + up.parts[partNumber] = part{ + data: data, + lastModified: lastModified, + } + return &events.StreamPart{Number: partNumber, LastModified: lastModified}, nil } // ListUploads lists uploads that have been initiated but not completed with @@ -199,7 +214,7 @@ func (m *MemoryUploader) GetParts(uploadID string) ([][]byte, error) { return partNumbers[i] < partNumbers[j] }) for _, partNumber := range partNumbers { - sortedParts = append(sortedParts, up.parts[partNumber]) + sortedParts = append(sortedParts, up.parts[partNumber].data) } return sortedParts, nil } @@ -290,8 +305,8 @@ type MockUploader struct { CreateUploadError error ReserveUploadPartError error - ListPartsError error + MockListParts func(ctx context.Context, upload events.StreamUpload) ([]events.StreamPart, error) MockListUploads func(ctx context.Context) ([]events.StreamUpload, error) MockCompleteUpload func(ctx context.Context, upload events.StreamUpload, parts []events.StreamPart) error } @@ -311,9 +326,9 @@ func (m *MockUploader) ReserveUploadPart(_ context.Context, _ events.StreamUploa return m.ReserveUploadPartError } -func (m *MockUploader) ListParts(_ context.Context, _ events.StreamUpload) ([]events.StreamPart, error) { - if m.ListPartsError != nil { - return nil, m.ListPartsError +func (m *MockUploader) ListParts(ctx context.Context, upload events.StreamUpload) ([]events.StreamPart, error) { + if m.MockListParts != nil { + return m.MockListParts(ctx, upload) } return []events.StreamPart{}, nil diff --git a/lib/events/filesessions/filestream.go b/lib/events/filesessions/filestream.go index c9c5ff5ccd855..0e0399ce89835 100644 --- a/lib/events/filesessions/filestream.go +++ b/lib/events/filesessions/filestream.go @@ -124,12 +124,19 @@ func (h *Handler) UploadPart(ctx context.Context, upload events.StreamUpload, pa } // Rename reservation to part file. - err = os.Rename(reservationPath, h.partPath(upload, partNumber)) + partPath := h.partPath(upload, partNumber) + err = os.Rename(reservationPath, partPath) if err != nil { return nil, trace.ConvertSystemError(err) } - return &events.StreamPart{Number: partNumber}, nil + var lastModified time.Time + fi, err := os.Stat(partPath) + if err == nil { + lastModified = fi.ModTime() + } + + return &events.StreamPart{Number: partNumber, LastModified: lastModified}, nil } // CompleteUpload completes the upload @@ -254,7 +261,8 @@ func (h *Handler) ListParts(ctx context.Context, upload events.StreamUpload) ([] return nil } parts = append(parts, events.StreamPart{ - Number: part, + Number: part, + LastModified: info.ModTime(), }) return nil }) diff --git a/lib/events/gcssessions/gcsstream.go b/lib/events/gcssessions/gcsstream.go index f18487fed85e9..f51a5df111b22 100644 --- a/lib/events/gcssessions/gcsstream.go +++ b/lib/events/gcssessions/gcsstream.go @@ -99,7 +99,7 @@ func (h *Handler) UploadPart(ctx context.Context, upload events.StreamUpload, pa if err != nil { return nil, convertGCSError(err) } - return &events.StreamPart{Number: partNumber}, nil + return &events.StreamPart{Number: partNumber, LastModified: writer.Attrs().Created}, nil } // CompleteUpload completes the upload @@ -249,6 +249,7 @@ func (h *Handler) ListParts(ctx context.Context, upload events.StreamUpload) ([] if err != nil { return nil, trace.Wrap(err) } + part.LastModified = attrs.Updated parts = append(parts, *part) } return parts, nil diff --git a/lib/events/s3sessions/s3stream.go b/lib/events/s3sessions/s3stream.go index c855ca564180f..ec04d7ae9d761 100644 --- a/lib/events/s3sessions/s3stream.go +++ b/lib/events/s3sessions/s3stream.go @@ -103,9 +103,18 @@ func (h *Handler) UploadPart(ctx context.Context, upload events.StreamUpload, pa return nil, trace.Wrap(awsutils.ConvertS3Error(err), "UploadPart(upload %v) part(%v) session(%v)", upload.ID, partNumber, upload.SessionID) } - + // TODO(espadolini): the AWS SDK v1 doesn't expose the Date of the response + // in [s3.UploadPartOutput] so we use the current time instead; AWS SDK v2 + // might expose the returned Date as part of the metadata, so we should + // check if that matches the actual LastModified of the part. It doesn't + // make much sense to do an additional request to check the LastModified of + // the part we just uploaded, however. log.Infof("Uploaded part %v in %v", partNumber, time.Since(start)) - return &events.StreamPart{ETag: aws.StringValue(resp.ETag), Number: partNumber}, nil + return &events.StreamPart{ + ETag: aws.StringValue(resp.ETag), + Number: partNumber, + LastModified: time.Now(), + }, nil } func (h *Handler) abortUpload(ctx context.Context, upload events.StreamUpload) error { @@ -205,10 +214,10 @@ func (h *Handler) ListParts(ctx context.Context, upload events.StreamUpload) ([] return nil, awsutils.ConvertS3Error(err) } for _, part := range re.Parts { - parts = append(parts, events.StreamPart{ - Number: aws.Int64Value(part.PartNumber), - ETag: aws.StringValue(part.ETag), + Number: aws.Int64Value(part.PartNumber), + ETag: aws.StringValue(part.ETag), + LastModified: aws.TimeValue(part.LastModified), }) } if !aws.BoolValue(re.IsTruncated) { diff --git a/lib/events/stream_test.go b/lib/events/stream_test.go index 3371b5c56ca19..6b1dab52e6575 100644 --- a/lib/events/stream_test.go +++ b/lib/events/stream_test.go @@ -134,8 +134,12 @@ func TestNewStreamErrors(t *testing.T) { expectedErr error }{ { - desc: "ListPartsError", - uploader: &eventstest.MockUploader{ListPartsError: expectedErr}, + desc: "ListPartsError", + uploader: &eventstest.MockUploader{ + MockListParts: func(ctx context.Context, upload events.StreamUpload) ([]events.StreamPart, error) { + return nil, expectedErr + }, + }, }, { desc: "ReserveUploadPartError", diff --git a/lib/httplib/httpheaders.go b/lib/httplib/httpheaders.go index b5f6ff9cae464..2c1d500980c3c 100644 --- a/lib/httplib/httpheaders.go +++ b/lib/httplib/httpheaders.go @@ -62,9 +62,10 @@ func newCSPCache() *cspCache { } } -type cspMap map[string][]string +// CSPMap holds a map of Content Security Policy. +type CSPMap map[string][]string -var defaultContentSecurityPolicy = cspMap{ +var defaultContentSecurityPolicy = CSPMap{ "default-src": {"'self'"}, "script-src": {"'self'"}, // specify CSP directives not covered by `default-src` @@ -77,24 +78,24 @@ var defaultContentSecurityPolicy = cspMap{ "style-src": {"'self'", "'unsafe-inline'"}, } -var defaultFontSrc = cspMap{"font-src": {"'self'", "data:"}} -var defaultConnectSrc = cspMap{"connect-src": {"'self'", "wss:"}} +var defaultFontSrc = CSPMap{"font-src": {"'self'", "data:"}} +var defaultConnectSrc = CSPMap{"connect-src": {"'self'", "wss:"}} -var stripeSecurityPolicy = cspMap{ +var stripeSecurityPolicy = CSPMap{ // auto-pay plans in Cloud use stripe.com to manage billing information "script-src": {"https://js.stripe.com"}, "frame-src": {"https://js.stripe.com"}, } -var wasmSecurityPolicy = cspMap{ +var wasmSecurityPolicy = CSPMap{ "script-src": {"'self'", "'wasm-unsafe-eval'"}, } // combineCSPMaps combines multiple CSP maps into a single map. -// When multiple of the input cspMaps have the same key, their +// When multiple of the input CSPMap have the same key, their // respective lists are concatenated. -func combineCSPMaps(cspMaps ...cspMap) cspMap { - combinedMap := make(cspMap) +func combineCSPMaps(cspMaps ...CSPMap) CSPMap { + combinedMap := make(CSPMap) for _, cspMap := range cspMaps { for key, value := range cspMap { @@ -106,11 +107,11 @@ func combineCSPMaps(cspMaps ...cspMap) cspMap { return combinedMap } -// getContentSecurityPolicyString combines multiple CSP maps into a single +// GetContentSecurityPolicyString combines multiple CSP maps into a single // CSP string, alphabetically sorted by the directive key. // When multiple of the input cspMaps have the same key, their // respective lists are concatenated. -func getContentSecurityPolicyString(cspMaps ...cspMap) string { +func GetContentSecurityPolicyString(cspMaps ...CSPMap) string { combined := combineCSPMaps(cspMaps...) keys := make([]string, 0, len(combined)) @@ -175,8 +176,8 @@ func SetDefaultSecurityHeaders(h http.Header) { h.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") } -func getIndexContentSecurityPolicy(withStripe, withWasm bool) cspMap { - cspMaps := []cspMap{defaultContentSecurityPolicy, defaultFontSrc, defaultConnectSrc} +func getIndexContentSecurityPolicy(withStripe, withWasm bool) CSPMap { + cspMaps := []CSPMap{defaultContentSecurityPolicy, defaultFontSrc, defaultConnectSrc} if withStripe { cspMaps = append(cspMaps, stripeSecurityPolicy) @@ -209,7 +210,7 @@ func getIndexContentSecurityPolicyString(cfg proto.Features, urlPath string) str // Nothing found in cache, calculate regex and result withWasm := desktopSessionRe.MatchString(urlPath) || recordingRe.MatchString(urlPath) - cspString := getContentSecurityPolicyString( + cspString := GetContentSecurityPolicyString( getIndexContentSecurityPolicy(withStripe, withWasm), ) // Add result to cache @@ -231,9 +232,9 @@ func getRedirectPageContentSecurityPolicyString(scriptSrc string) string { return cspString } - cspString := getContentSecurityPolicyString( + cspString := GetContentSecurityPolicyString( defaultContentSecurityPolicy, - cspMap{ + CSPMap{ "script-src": {"'" + scriptSrc + "'"}, }, ) diff --git a/lib/integrations/awsoidc/deploydatabaseservice.go b/lib/integrations/awsoidc/deploydatabaseservice.go index d6d35ef91585c..457e224882091 100644 --- a/lib/integrations/awsoidc/deploydatabaseservice.go +++ b/lib/integrations/awsoidc/deploydatabaseservice.go @@ -147,7 +147,8 @@ type DeployDatabaseServiceResponse struct { // ClusterARN is the Amazon ECS Cluster ARN where the task was started. ClusterARN string - // ClusterDashboardURL is a link to the Cluster's Dashboard URL in Amazon Console. + // ClusterDashboardURL is a link to the Amazon ECS cluster dashboard or + // a specific cluster service if a single deployment was requested. ClusterDashboardURL string } @@ -214,7 +215,7 @@ func DeployDatabaseService(ctx context.Context, clt DeployServiceClient, req Dep ) log.DebugContext(ctx, "Upsert ECS Cluster") - cluster, err := upsertCluster(ctx, clt, req.ecsClusterName, req.ResourceCreationTags) + ecsCluster, err := upsertCluster(ctx, clt, req.ecsClusterName, req.ResourceCreationTags) if err != nil { return nil, trace.Wrap(err) } @@ -260,11 +261,22 @@ func DeployDatabaseService(ctx context.Context, clt DeployServiceClient, req Dep } return &DeployDatabaseServiceResponse{ - ClusterARN: aws.ToString(cluster.ClusterArn), - ClusterDashboardURL: ecsClusterDashboardURL(req.Region, aws.ToString(cluster.ClusterName)), + ClusterARN: aws.ToString(ecsCluster.ClusterArn), + ClusterDashboardURL: deploymentURL(req.Region, aws.ToString(ecsCluster.ClusterName), req.Deployments), }, nil } +// deploymentURL returns a link to the service in the ECS cluster for a single +// deployment, which is the nominal case since we updated the enrollment flow +// to deploy a single VPC at a time, or a link to the ECS cluster overview +// if multiple deployments are requested. +func deploymentURL(region, ecsClusterName string, deps []DeployDatabaseServiceRequestDeployment) string { + if len(deps) == 1 { + return ecsServiceDashboardURL(region, ecsClusterName, deps[0].VPCID) + } + return ecsClusterDashboardURL(region, ecsClusterName) +} + // ecsTaskName returns the normalized ECS TaskDefinition Family func ecsTaskName(teleportClusterName, deploymentMode, vpcid string) string { return normalizeECSResourceName(fmt.Sprintf("%s-teleport-%s-%s", teleportClusterName, deploymentMode, vpcid)) @@ -294,7 +306,11 @@ func ECSDatabaseServiceDashboardURL(region, teleportClusterName, vpcID string) ( return "", trace.BadParameter("empty VPC ID") } ecsClusterName := normalizeECSClusterName(teleportClusterName) + return ecsServiceDashboardURL(region, ecsClusterName, vpcID), nil +} + +func ecsServiceDashboardURL(region, ecsClusterName, vpcID string) string { ecsClusterDashboard := ecsClusterDashboardURL(region, ecsClusterName) serviceName := ecsServiceName(DatabaseServiceDeploymentMode, vpcID) - return fmt.Sprintf("%s/%s", ecsClusterDashboard, serviceName), nil + return fmt.Sprintf("%s/%s", ecsClusterDashboard, serviceName) } diff --git a/lib/integrations/awsoidc/deploydatabaseservice_test.go b/lib/integrations/awsoidc/deploydatabaseservice_test.go index ec871eaf092ac..96026dcfbbd40 100644 --- a/lib/integrations/awsoidc/deploydatabaseservice_test.go +++ b/lib/integrations/awsoidc/deploydatabaseservice_test.go @@ -439,7 +439,7 @@ func TestDeployDatabaseService(t *testing.T) { }, ) require.NoError(t, err) - require.Equal(t, "https://us-east-1.console.aws.amazon.com/ecs/v2/clusters/cluster-name-teleport/services", resp.ClusterDashboardURL) + require.Equal(t, "https://us-east-1.console.aws.amazon.com/ecs/v2/clusters/cluster-name-teleport/services/database-service-vpc-123", resp.ClusterDashboardURL) require.Equal(t, "ARNcluster-name-teleport", resp.ClusterARN) require.Contains(t, mockClient.clusters, "cluster-name-teleport") require.Contains(t, mockClient.services, "database-service-vpc-123") @@ -550,7 +550,7 @@ func TestDeployDatabaseService(t *testing.T) { }, ) require.NoError(t, err) - require.Equal(t, "https://us-east-1.console.aws.amazon.com/ecs/v2/clusters/cluster-name-teleport/services", resp.ClusterDashboardURL) + require.Equal(t, "https://us-east-1.console.aws.amazon.com/ecs/v2/clusters/cluster-name-teleport/services/database-service-vpc-123", resp.ClusterDashboardURL) require.Equal(t, "ARNcluster-name-teleport", resp.ClusterARN) }) } diff --git a/lib/integrations/awsoidc/ec2_ssm_iam_config.go b/lib/integrations/awsoidc/ec2_ssm_iam_config.go index 8f1903bd19b47..55ebcccaa0a03 100644 --- a/lib/integrations/awsoidc/ec2_ssm_iam_config.go +++ b/lib/integrations/awsoidc/ec2_ssm_iam_config.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/trace" awslib "github.com/gravitational/teleport/lib/cloud/aws" + "github.com/gravitational/teleport/lib/integrations/awsoidc/tags" ) const ( @@ -60,6 +61,13 @@ type EC2SSMIAMConfigureRequest struct { // No trailing / is expected. // Eg https://tenant.teleport.sh ProxyPublicURL string + + // ClusterName is the Teleport cluster name. + // Used for resource tagging. + ClusterName string + // IntegrationName is the Teleport AWS OIDC Integration name. + // Used for resource tagging. + IntegrationName string } // CheckAndSetDefaults ensures the required fields are present. @@ -84,6 +92,14 @@ func (r *EC2SSMIAMConfigureRequest) CheckAndSetDefaults() error { return trace.BadParameter("proxy public url is required") } + if r.ClusterName == "" { + return trace.BadParameter("cluster name is required") + } + + if r.IntegrationName == "" { + return trace.BadParameter("integration name is required") + } + return nil } @@ -165,11 +181,14 @@ func ConfigureEC2SSM(ctx context.Context, clt EC2SSMConfigureClient, req EC2SSMI slog.InfoContext(ctx, "IntegrationRole: IAM Policy added to Role", "policy", req.IntegrationRoleEC2SSMPolicy, "role", req.IntegrationRole) + ownershipTags := tags.DefaultResourceCreationTags(req.ClusterName, req.IntegrationName) + _, err = clt.CreateDocument(ctx, &ssm.CreateDocumentInput{ Name: aws.String(req.SSMDocumentName), DocumentType: ssmtypes.DocumentTypeCommand, DocumentFormat: ssmtypes.DocumentFormatYaml, Content: aws.String(awslib.EC2DiscoverySSMDocument(req.ProxyPublicURL)), + Tags: ownershipTags.ToSSMTags(), }) if err != nil { var docAlreadyExistsError *ssmtypes.DocumentAlreadyExists diff --git a/lib/integrations/awsoidc/ec2_ssm_iam_config_test.go b/lib/integrations/awsoidc/ec2_ssm_iam_config_test.go index 1e2828be03785..298a464a10492 100644 --- a/lib/integrations/awsoidc/ec2_ssm_iam_config_test.go +++ b/lib/integrations/awsoidc/ec2_ssm_iam_config_test.go @@ -39,6 +39,8 @@ func TestEC2SSMIAMConfigReqDefaults(t *testing.T) { IntegrationRole: "integrationrole", SSMDocumentName: "MyDoc", ProxyPublicURL: "https://proxy.example.com", + ClusterName: "my-cluster", + IntegrationName: "my-integration", } } @@ -58,6 +60,8 @@ func TestEC2SSMIAMConfigReqDefaults(t *testing.T) { IntegrationRoleEC2SSMPolicy: "EC2DiscoverWithSSM", SSMDocumentName: "MyDoc", ProxyPublicURL: "https://proxy.example.com", + ClusterName: "my-cluster", + IntegrationName: "my-integration", }, }, { @@ -78,6 +82,24 @@ func TestEC2SSMIAMConfigReqDefaults(t *testing.T) { }, errCheck: badParameterCheck, }, + { + name: "missing integration name", + req: func() EC2SSMIAMConfigureRequest { + req := baseReq() + req.IntegrationName = "" + return req + }, + errCheck: badParameterCheck, + }, + { + name: "missing cluster name", + req: func() EC2SSMIAMConfigureRequest { + req := baseReq() + req.ClusterName = "" + return req + }, + errCheck: badParameterCheck, + }, { name: "missing ssm document", req: func() EC2SSMIAMConfigureRequest { @@ -118,6 +140,8 @@ func TestEC2SSMIAMConfig(t *testing.T) { IntegrationRole: "integrationrole", SSMDocumentName: "MyDoc", ProxyPublicURL: "https://proxy.example.com", + ClusterName: "my-cluster", + IntegrationName: "my-integration", } } @@ -157,13 +181,21 @@ func TestEC2SSMIAMConfig(t *testing.T) { err := ConfigureEC2SSM(ctx, &clt, tt.req()) tt.errCheck(t, err) + if err == nil { + require.Contains(t, clt.existingDocs, tt.req().SSMDocumentName) + require.ElementsMatch(t, []ssmtypes.Tag{ + {Key: aws.String("teleport.dev/cluster"), Value: aws.String("my-cluster")}, + {Key: aws.String("teleport.dev/integration"), Value: aws.String("my-integration")}, + {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, + }, clt.existingDocs[tt.req().SSMDocumentName]) + } }) } } type mockEC2SSMIAMConfigClient struct { existingRoles []string - existingDocs []string + existingDocs map[string][]ssmtypes.Tag } // PutRolePolicy creates or replaces a Policy by its name in a IAM Role. @@ -179,8 +211,12 @@ func (m *mockEC2SSMIAMConfigClient) PutRolePolicy(ctx context.Context, params *i // CreateDocument creates an SSM document. func (m *mockEC2SSMIAMConfigClient) CreateDocument(ctx context.Context, params *ssm.CreateDocumentInput, optFns ...func(*ssm.Options)) (*ssm.CreateDocumentOutput, error) { - if slices.Contains(m.existingDocs, aws.ToString(params.Name)) { + if m.existingDocs == nil { + m.existingDocs = make(map[string][]ssmtypes.Tag) + } + if _, ok := m.existingDocs[aws.ToString(params.Name)]; ok { return nil, &ssmtypes.DocumentAlreadyExists{} } + m.existingDocs[aws.ToString(params.Name)] = params.Tags return nil, nil } diff --git a/lib/integrations/awsoidc/tags/tags.go b/lib/integrations/awsoidc/tags/tags.go index 0ed290105a19b..f8b39c04a8a2b 100644 --- a/lib/integrations/awsoidc/tags/tags.go +++ b/lib/integrations/awsoidc/tags/tags.go @@ -28,6 +28,7 @@ import ( ecsTypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" iamTypes "github.com/aws/aws-sdk-go-v2/service/iam/types" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + ssmtypes "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/gravitational/teleport/api/types" ) @@ -151,6 +152,18 @@ func (d AWSTags) ToAthenaTags() []athenatypes.Tag { return athenaTags } +// ToSSMTags returns the default tags using the expected type for SSM resources: [ssmtypes.Tag] +func (d AWSTags) ToSSMTags() []ssmtypes.Tag { + ssmTags := make([]ssmtypes.Tag, 0, len(d)) + for k, v := range d { + ssmTags = append(ssmTags, ssmtypes.Tag{ + Key: &k, + Value: &v, + }) + } + return ssmTags +} + // ToMap returns the default tags using the expected type for other aws resources. // Eg Glue resources func (d AWSTags) ToMap() map[string]string { diff --git a/lib/integrations/awsoidc/tags/tags_test.go b/lib/integrations/awsoidc/tags/tags_test.go index 7b07e86f9340e..287c4caebe3a6 100644 --- a/lib/integrations/awsoidc/tags/tags_test.go +++ b/lib/integrations/awsoidc/tags/tags_test.go @@ -25,6 +25,7 @@ import ( ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types" ecstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" iamtypes "github.com/aws/aws-sdk-go-v2/service/iam/types" + ssmtypes "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/stretchr/testify/require" ) @@ -67,6 +68,15 @@ func TestDefaultTags(t *testing.T) { require.ElementsMatch(t, expectedEC2Tags, d.ToEC2Tags()) }) + t.Run("ssm tags", func(t *testing.T) { + expectedTags := []ssmtypes.Tag{ + {Key: aws.String("teleport.dev/cluster"), Value: aws.String("mycluster")}, + {Key: aws.String("teleport.dev/integration"), Value: aws.String("myawsaccount")}, + {Key: aws.String("teleport.dev/origin"), Value: aws.String("integration_awsoidc")}, + } + require.ElementsMatch(t, expectedTags, d.ToSSMTags()) + }) + t.Run("resource is teleport managed", func(t *testing.T) { t.Run("ECS Tags", func(t *testing.T) { t.Run("all tags match", func(t *testing.T) { diff --git a/lib/integrations/diagnostics/profile.go b/lib/integrations/diagnostics/profile.go index dc18ba8c028b5..5d185a271c8bd 100644 --- a/lib/integrations/diagnostics/profile.go +++ b/lib/integrations/diagnostics/profile.go @@ -41,31 +41,31 @@ func Profile(dir string) error { timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10) traceFile, err := os.Create(filepath.Join(dir, timestamp+"-trace.profile")) if err != nil { - return trace.Wrap(err, "creating trace proile file") + return trace.Wrap(err, "creating trace profile file") } defer traceFile.Close() cpuFile, err := os.Create(filepath.Join(dir, timestamp+"-cpu.profile")) if err != nil { - return trace.Wrap(err, "creating cpu proile file") + return trace.Wrap(err, "creating cpu profile file") } defer cpuFile.Close() heapFile, err := os.Create(filepath.Join(dir, timestamp+"-heap.profile")) if err != nil { - return trace.Wrap(err, "creating heap proile file") + return trace.Wrap(err, "creating heap profile file") } defer heapFile.Close() goroutineFile, err := os.Create(filepath.Join(dir, timestamp+"-goroutine.profile")) if err != nil { - return trace.Wrap(err, "creating goroutine proile file") + return trace.Wrap(err, "creating goroutine profile file") } defer goroutineFile.Close() blockFile, err := os.Create(filepath.Join(dir, timestamp+"-block.profile")) if err != nil { - return trace.Wrap(err, "creating block proile file") + return trace.Wrap(err, "creating block profile file") } defer blockFile.Close() diff --git a/lib/integrations/externalauditstorage/configurator.go b/lib/integrations/externalauditstorage/configurator.go index 15b388a8659c4..dd63222b5bc20 100644 --- a/lib/integrations/externalauditstorage/configurator.go +++ b/lib/integrations/externalauditstorage/configurator.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/externalauditstorage" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" ) @@ -182,7 +183,7 @@ func NewDraftConfigurator(ctx context.Context, ecaSvc ExternalAuditStorageGetter func newConfigurator(ctx context.Context, spec *externalauditstorage.ExternalAuditStorageSpec, integrationSvc services.IntegrationsGetter, alertService ClusterAlertService, optFns ...func(*Options)) (*Configurator, error) { // ExternalAuditStorage is only available in Cloud Enterprise - if !modules.GetModules().Features().Cloud || !modules.GetModules().Features().ExternalAuditStorage { + if !modules.GetModules().Features().Cloud || !modules.GetModules().Features().GetEntitlement(entitlements.ExternalAuditStorage).Enabled { return &Configurator{isUsed: false}, nil } diff --git a/lib/integrations/externalauditstorage/configurator_test.go b/lib/integrations/externalauditstorage/configurator_test.go index 08824475b453b..abb1ce1425b9e 100644 --- a/lib/integrations/externalauditstorage/configurator_test.go +++ b/lib/integrations/externalauditstorage/configurator_test.go @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/externalauditstorage" "github.com/gravitational/teleport/api/types/header" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/backend/memory" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services/local" @@ -102,8 +103,10 @@ func TestConfiguratorIsUsed(t *testing.T) { name: "cloud enterprise without config", modules: &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }, wantIsUsed: false, @@ -112,8 +115,10 @@ func TestConfiguratorIsUsed(t *testing.T) { name: "cloud enterprise with only draft", modules: &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }, // Just create draft, External Audit Storage should be disabled, it's @@ -129,8 +134,10 @@ func TestConfiguratorIsUsed(t *testing.T) { name: "cloud enterprise with cluster config", modules: &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }, // Create draft and promote it to cluster. @@ -178,8 +185,10 @@ func TestCredentialsCache(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }) @@ -338,8 +347,10 @@ func TestDraftConfigurator(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }) diff --git a/lib/kube/proxy/forwarder.go b/lib/kube/proxy/forwarder.go index 51f9299c91f8a..5f7ac1736ae7c 100644 --- a/lib/kube/proxy/forwarder.go +++ b/lib/kube/proxy/forwarder.go @@ -67,6 +67,7 @@ import ( "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" apiutils "github.com/gravitational/teleport/api/utils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/authz" @@ -76,6 +77,7 @@ import ( "github.com/gravitational/teleport/lib/httplib/reverseproxy" "github.com/gravitational/teleport/lib/kube/proxy/responsewriters" "github.com/gravitational/teleport/lib/kube/proxy/streamproto" + "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" @@ -172,6 +174,18 @@ type ForwarderConfig struct { // ClusterFeaturesGetter is a function that returns the Teleport cluster licensed features. type ClusterFeaturesGetter func() proto.Features +func (f ClusterFeaturesGetter) GetEntitlement(e entitlements.EntitlementKind) modules.EntitlementInfo { + al, ok := f().Entitlements[string(e)] + if !ok { + return modules.EntitlementInfo{} + } + + return modules.EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, + } +} + // CheckAndSetDefaults checks and sets default values func (f *ForwarderConfig) CheckAndSetDefaults() error { if f.AuthClient == nil { @@ -491,7 +505,7 @@ const accessDeniedMsg = "[00] access denied" // authenticate function authenticates request func (f *Forwarder) authenticate(req *http.Request) (*authContext, error) { // If the cluster is not licensed for Kubernetes, return an error to the client. - if !f.cfg.ClusterFeatures().Kubernetes { + if !f.cfg.ClusterFeatures.GetEntitlement(entitlements.K8s).Enabled { // If the cluster is not licensed for Kubernetes, return an error to the client. return nil, trace.AccessDenied("Teleport cluster is not licensed for Kubernetes") } @@ -1112,14 +1126,14 @@ func matchKubernetesResource(resource types.KubernetesResource, allowed, denied // utils.KubeResourceMatchesRegex checks if the resource.Kind is strictly equal // to each entry and validates if the Name and Namespace fields matches the // regex allowed by each entry. - result, err := utils.KubeResourceMatchesRegex(resource, denied) + result, err := utils.KubeResourceMatchesRegex(resource, denied, types.Deny) if err != nil { return false, trace.Wrap(err) } else if result { return false, nil } - result, err = utils.KubeResourceMatchesRegex(resource, allowed) + result, err = utils.KubeResourceMatchesRegex(resource, allowed, types.Allow) if err != nil { return false, trace.Wrap(err) } diff --git a/lib/kube/proxy/forwarder_test.go b/lib/kube/proxy/forwarder_test.go index 397a174566890..982fd6bb8bcfa 100644 --- a/lib/kube/proxy/forwarder_test.go +++ b/lib/kube/proxy/forwarder_test.go @@ -52,6 +52,7 @@ import ( "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/authz" @@ -88,7 +89,9 @@ var ( func fakeClusterFeatures() proto.Features { return proto.Features{ - Kubernetes: true, + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.K8s): {Enabled: true}, + }, } } @@ -1487,14 +1490,18 @@ func TestKubernetesLicenseEnforcement(t *testing.T) { { name: "kubernetes agent is licensed", features: proto.Features{ - Kubernetes: true, + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.K8s): {Enabled: true}, + }, }, assertErrFunc: require.NoError, }, { name: "kubernetes isn't licensed", features: proto.Features{ - Kubernetes: false, + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.K8s): {Enabled: false}, + }, }, assertErrFunc: func(tt require.TestingT, err error, i ...interface{}) { require.Error(tt, err) diff --git a/lib/kube/proxy/moderated_sessions_test.go b/lib/kube/proxy/moderated_sessions_test.go index d16f37291a74c..1b2abc5704ea2 100644 --- a/lib/kube/proxy/moderated_sessions_test.go +++ b/lib/kube/proxy/moderated_sessions_test.go @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/events" testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" "github.com/gravitational/teleport/lib/modules" @@ -49,7 +50,11 @@ import ( func TestModeratedSessions(t *testing.T) { // enable enterprise features to have access to ModeratedSessions. - modules.SetTestModules(t, &modules.TestModules{TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{Kubernetes: true}}) + modules.SetTestModules(t, &modules.TestModules{TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + }, + }}) const ( moderatorUsername = "moderator_user" moderatorRoleName = "mod_role" @@ -496,7 +501,11 @@ func validateSessionTracker(testCtx *TestContext, sessionID string, reason strin // Lock watcher connection to be stale and it takes ~5 minutes to happen. func TestInteractiveSessionsNoAuth(t *testing.T) { // enable enterprise features to have access to ModeratedSessions. - modules.SetTestModules(t, &modules.TestModules{TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{Kubernetes: true}}) + modules.SetTestModules(t, &modules.TestModules{TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + }, + }}) const ( moderatorUsername = "moderator_user" moderatorRoleName = "mod_role" diff --git a/lib/kube/proxy/sess.go b/lib/kube/proxy/sess.go index ccd1ee620b119..b05352096f92b 100644 --- a/lib/kube/proxy/sess.go +++ b/lib/kube/proxy/sess.go @@ -23,6 +23,7 @@ import ( "fmt" "io" "net/http" + "path" "reflect" "slices" "strings" @@ -1325,7 +1326,7 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy SessionID: s.id.String(), Kind: string(types.KubernetesSessionKind), State: types.SessionState_SessionStatePending, - Hostname: s.podName, + Hostname: path.Join(s.podNamespace, s.podName), ClusterName: s.ctx.teleportCluster.name, KubernetesCluster: s.ctx.kubeClusterName, HostUser: p.Ctx.User.GetName(), @@ -1362,7 +1363,7 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy case err != nil: return trace.Wrap(err) // the tracker was created successfully - case err == nil: + default: s.tracker = tracker } diff --git a/lib/kube/proxy/sess_test.go b/lib/kube/proxy/sess_test.go index a25848766666b..469fe2c4df27a 100644 --- a/lib/kube/proxy/sess_test.go +++ b/lib/kube/proxy/sess_test.go @@ -281,16 +281,18 @@ func Test_session_trackSession(t *testing.T) { assertErr: require.NoError, }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sess := &session{ log: logrus.New().WithField(teleport.ComponentKey, "test"), id: uuid.New(), req: &http.Request{ - URL: &url.URL{}, + URL: &url.URL{ + RawQuery: "command=command&command=arg1&command=arg2", + }, }, podName: "podName", + podNamespace: "podNamespace", accessEvaluator: auth.NewSessionAccessEvaluator(tt.args.policies, types.KubernetesSessionKind, "username"), ctx: authContext{ Context: authz.Context{ @@ -319,6 +321,18 @@ func Test_session_trackSession(t *testing.T) { } err := sess.trackSession(p, tt.args.policies) tt.assertErr(t, err) + if err != nil { + return + } + tracker := tt.args.authClient.(*mockSessionTrackerService).tracker + require.Equal(t, "username", tracker.GetHostUser()) + require.Equal(t, "name", tracker.GetClusterName()) + require.Equal(t, "kubeClusterName", tracker.GetKubeCluster()) + require.Equal(t, sess.id.String(), tracker.GetSessionID()) + require.Equal(t, []string{"command", "arg1", "arg2"}, tracker.GetCommand()) + require.Equal(t, "podNamespace/podName", tracker.GetHostname()) + require.Equal(t, types.KubernetesSessionKind, tracker.GetSessionKind()) + }) } } @@ -326,9 +340,11 @@ func Test_session_trackSession(t *testing.T) { type mockSessionTrackerService struct { authclient.ClientI returnErr bool + tracker types.SessionTracker } -func (m *mockSessionTrackerService) CreateSessionTracker(ctx context.Context, tracker types.SessionTracker) (types.SessionTracker, error) { +func (m *mockSessionTrackerService) CreateSessionTracker(_ context.Context, tracker types.SessionTracker) (types.SessionTracker, error) { + m.tracker = tracker if m.returnErr { return nil, trace.ConnectionProblem(nil, "mock error") } diff --git a/lib/kube/proxy/utils_testing.go b/lib/kube/proxy/utils_testing.go index 626fd4889adeb..95997812c6c81 100644 --- a/lib/kube/proxy/utils_testing.go +++ b/lib/kube/proxy/utils_testing.go @@ -47,6 +47,7 @@ import ( "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/keygen" @@ -209,7 +210,13 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo heartbeatsWaitChannel := make(chan struct{}, len(cfg.Clusters)+1) client := newAuthClientWithStreamer(testCtx, cfg.CreateAuditStreamErr) - features := func() proto.Features { return proto.Features{Kubernetes: true} } + features := func() proto.Features { + return proto.Features{ + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.K8s): {Enabled: true}, + }, + } + } if cfg.ClusterFeatures != nil { features = cfg.ClusterFeatures } diff --git a/lib/modules/modules.go b/lib/modules/modules.go index affaa6a4f5f56..6265e999e90cb 100644 --- a/lib/modules/modules.go +++ b/lib/modules/modules.go @@ -38,6 +38,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/native" "github.com/gravitational/teleport/lib/automaticupgrades" "github.com/gravitational/teleport/lib/tlsca" @@ -45,177 +46,174 @@ import ( // Features provides supported and unsupported features type Features struct { - // Kubernetes enables Kubernetes Access product - Kubernetes bool - // App enables Application Access product - App bool - // DB enables database access product - DB bool - // OIDC enables OIDC connectors - OIDC bool - // SAML enables SAML connectors - SAML bool - // AccessControls enables FIPS access controls - AccessControls bool - // Currently this flag is to gate actions from OSS clusters. - // - // Determining support for access request is currently determined by: - // 1) Enterprise + [Features.IdentityGovernanceSecurity] == true, new flag - // introduced with Enterprise Usage Based (EUB) product. - // 2) Enterprise + [Features.IsUsageBasedBilling] == false, legacy support - // where before EUB, it was unlimited. - // - // AdvancedAccessWorkflows is currently set to true for all - // enterprise editions (team, cloud, on-prem). Historically, access request - // was only available for enterprise cloud and enterprise on-prem. - AdvancedAccessWorkflows bool + // --------------- Cloud Settings // Cloud enables some cloud-related features Cloud bool - // HSM enables PKCS#11 HSM support - HSM bool - // Desktop enables desktop access product - Desktop bool + // CustomTheme holds the name of WebUI custom theme. + CustomTheme string + // IsStripeManaged indicates if the cluster billing is managed via Stripe + IsStripeManaged bool + // IsUsageBasedBilling enables some usage-based billing features + IsUsageBasedBilling bool + // Questionnaire indicates whether cluster users should get an onboarding questionnaire + Questionnaire bool + // SupportType indicates the type of customer's support + SupportType proto.SupportType + // Entitlements reflect Cloud Entitlements including access and limits + Entitlements map[entitlements.EntitlementKind]EntitlementInfo + + // todo (michellescripts) have the following fields evaluated for deprecation, consolidation, or fetch from Cloud + // AdvancedAccessWorkflows is currently set to the value of the Cloud Access Requests entitlement + AdvancedAccessWorkflows bool // RecoveryCodes enables account recovery codes RecoveryCodes bool // Plugins enables hosted plugins Plugins bool // AutomaticUpgrades enables automatic upgrades of agents/services. AutomaticUpgrades bool - // IsUsageBasedBilling enables some usage-based billing features - IsUsageBasedBilling bool - // DeviceTrust holds its namesake feature settings. - DeviceTrust DeviceTrustFeature - // FeatureHiding enables hiding features from being discoverable for users who don't have the necessary permissions. - FeatureHiding bool - // AccessRequests holds its namesake feature settings. - AccessRequests AccessRequestsFeature - // CustomTheme holds the name of WebUI custom theme. - CustomTheme string - // AccessGraph enables the usage of access graph. // NOTE: this is a legacy flag that is currently used to signal // that Access Graph integration is *enabled* on a cluster. // *Access* to the feature is gated on the `Policy` flag. // TODO(justinas): remove this field once "TAG enabled" status is moved to a resource in the backend. AccessGraph bool - // IdentityGovernanceSecurity indicates whether IGS related features are enabled: - // access list, access request, access monitoring, device trust. - IdentityGovernanceSecurity bool - // AccessList holds its namesake feature settings. - AccessList AccessListFeature - // AccessMonitoring holds its namesake feature settings. - AccessMonitoring AccessMonitoringFeature + // AccessMonitoringConfigured contributes to the enablement of access monitoring. + // NOTE: this flag is used to signal that Access Monitoring is *enabled* on a cluster. + // *Access* to the feature is gated on the `AccessMonitoring` entitlement. + AccessMonitoringConfigured bool + // --------------- Deprecated Fields + // AccessControls enables FIPS access controls + // Deprecated + AccessControls bool + // Assist enables Assistant feature + // Deprecated + Assist bool // ProductType describes the product being used. + // Deprecated ProductType ProductType - // Policy holds settings for the Teleport Policy feature set. - // At the time of writing, this includes Teleport Access Graph (TAG). - Policy PolicyFeature - // Questionnaire indicates whether cluster users should get an onboarding questionnaire - Questionnaire bool - // IsStripeManaged indicates if the cluster billing is managed via Stripe - IsStripeManaged bool - // ExternalAuditStorage indicates whether the EAS feature is enabled in the cluster. - ExternalAuditStorage bool - // SupportType indicates the type of customer's support - SupportType proto.SupportType - // JoinActiveSessions indicates whether joining active sessions via web UI is enabled - JoinActiveSessions bool - // MobileDeviceManagement indicates whether endpoints management (like Jamf Plugin) can be used in the cluster - MobileDeviceManagement bool } -// DeviceTrustFeature holds the Device Trust feature general and usage-based -// settings. -// Limits have no affect if [Feature.IdentityGovernanceSecurity] is enabled. -type DeviceTrustFeature struct { - // Currently this flag is to gate actions from OSS clusters. - // - // Determining support for device trust is currently determined by: - // 1) Enterprise + [Features.IdentityGovernanceSecurity] == true, new flag - // introduced with Enterprise Usage Based (EUB) product. - // 2) Enterprise + [Features.IsUsageBasedBilling] == false, legacy support - // where before EUB, it was unlimited. +// EntitlementInfo is the state and limits of a particular entitlement +type EntitlementInfo struct { + // Enabled indicates the feature is 'on' if true; feature is disabled if false Enabled bool - // DevicesUsageLimit is the usage-based limit for the number of - // registered/enrolled devices, at the implementation's discretion. - DevicesUsageLimit int + // Limit indicates the allotted amount of use when limited; if 0 use is unlimited + Limit int32 } -// AccessRequestsFeature holds the Access Requests feature general and usage-based settings. -// Limits have no affect if [Feature.IdentityGovernanceSecurity] is enabled. -type AccessRequestsFeature struct { - // MonthlyRequestLimit is the usage-based limit for the number of - // access requests created in a calendar month. - MonthlyRequestLimit int +// UnderLimit tests that a given entitlement is under its prescribed limit +// based on the supplied use count. A return value of `true` indicates that +// there is still at least *some* capacity left in the entitlement. The actual +// definition of a "use" depends on the entitlement in question. +// A disabled entitlement is always out of its limit. +func (e EntitlementInfo) UnderLimit(count int) bool { + return e.Enabled && (e.Limit == 0 || count < int(e.Limit)) } -// AccessListFeature holds the Access List feature settings. -// Limits have no affect if feature is enabled. -type AccessListFeature struct { - // Limit for the number of access list creatable when feature is - // not enabled. - CreateLimit int +// ToProto converts Features into proto.Features +func (f Features) ToProto() *proto.Features { + protoF := &proto.Features{ + Cloud: f.Cloud, + CustomTheme: f.CustomTheme, + IsStripeManaged: f.IsStripeManaged, + IsUsageBased: f.IsUsageBasedBilling, + Questionnaire: f.Questionnaire, + SupportType: f.SupportType, + AccessControls: f.AccessControls, + AccessGraph: f.AccessGraph, + AdvancedAccessWorkflows: f.AdvancedAccessWorkflows, + AutomaticUpgrades: f.AutomaticUpgrades, + Plugins: f.Plugins, + ProductType: proto.ProductType(f.ProductType), + RecoveryCodes: f.RecoveryCodes, + AccessMonitoringConfigured: f.AccessMonitoringConfigured, + Entitlements: f.EntitlementsToProto(), + } + + // remove setLegacyLogic in v18 + setLegacyLogic(protoF, f) + return protoF +} + +// setLegacyLogic sets the deprecated fields; to be removed in v18 - use entitlements +func setLegacyLogic(protoF *proto.Features, f Features) { + protoF.Kubernetes = f.GetEntitlement(entitlements.K8s).Enabled + protoF.App = f.GetEntitlement(entitlements.App).Enabled + protoF.DB = f.GetEntitlement(entitlements.DB).Enabled + protoF.OIDC = f.GetEntitlement(entitlements.OIDC).Enabled + protoF.SAML = f.GetEntitlement(entitlements.SAML).Enabled + protoF.HSM = f.GetEntitlement(entitlements.HSM).Enabled + protoF.Desktop = f.GetEntitlement(entitlements.Desktop).Enabled + protoF.FeatureHiding = f.GetEntitlement(entitlements.FeatureHiding).Enabled + protoF.IdentityGovernance = f.GetEntitlement(entitlements.Identity).Enabled + protoF.ExternalAuditStorage = f.GetEntitlement(entitlements.ExternalAuditStorage).Enabled + protoF.JoinActiveSessions = f.GetEntitlement(entitlements.JoinActiveSessions).Enabled + protoF.MobileDeviceManagement = f.GetEntitlement(entitlements.MobileDeviceManagement).Enabled + + protoF.DeviceTrust = &proto.DeviceTrustFeature{ + Enabled: f.GetEntitlement(entitlements.DeviceTrust).Enabled, DevicesUsageLimit: f.GetEntitlement(entitlements.DeviceTrust).Limit, + } + protoF.AccessRequests = &proto.AccessRequestsFeature{ + MonthlyRequestLimit: f.GetEntitlement(entitlements.AccessRequests).Limit, + } + protoF.AccessMonitoring = &proto.AccessMonitoringFeature{ + Enabled: f.AccessMonitoringConfigured, MaxReportRangeLimit: f.GetEntitlement(entitlements.AccessMonitoring).Limit, + } + protoF.AccessList = &proto.AccessListFeature{ + CreateLimit: f.GetEntitlement(entitlements.AccessLists).Limit, + } + protoF.Policy = &proto.PolicyFeature{ + Enabled: f.GetEntitlement(entitlements.Policy).Enabled, + } } -// AccessMonitoring holds the Access Monitoring feature settings. -// Limits have no affect if [Feature.IdentityGovernanceSecurity] is enabled. -type AccessMonitoringFeature struct { - // True if enabled in the auth service config: [auth_service.access_monitoring.enabled]. - Enabled bool - // Defines the max number of days to include in an access report. - MaxReportRangeLimit int +// EntitlementsToProto takes the features.Entitlements object and returns a proto version. If not present on Features, the +// proto entitlement will default to false +func (f Features) EntitlementsToProto() map[string]*proto.EntitlementInfo { + all := entitlements.AllEntitlements + result := make(map[string]*proto.EntitlementInfo, len(all)) + + for _, e := range all { + al, ok := f.Entitlements[e] + if !ok { + result[string(e)] = &proto.EntitlementInfo{} + continue + } + + result[string(e)] = &proto.EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, + } + } + + return result } -type PolicyFeature struct { - // Enabled is set to `true` if Teleport Policy is enabled in the license. - Enabled bool +// GetEntitlement takes an entitlement and returns either the Features entitlement, or if not present, a false entitlement +func (f Features) GetEntitlement(e entitlements.EntitlementKind) EntitlementInfo { + al, ok := f.Entitlements[e] + if !ok { + return EntitlementInfo{} + } + + return EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, + } } -// ToProto converts Features into proto.Features -func (f Features) ToProto() *proto.Features { - return &proto.Features{ - ProductType: proto.ProductType(f.ProductType), - Kubernetes: f.Kubernetes, - App: f.App, - DB: f.DB, - OIDC: f.OIDC, - SAML: f.SAML, - AccessControls: f.AccessControls, - AdvancedAccessWorkflows: f.AdvancedAccessWorkflows, - Cloud: f.Cloud, - HSM: f.HSM, - Desktop: f.Desktop, - RecoveryCodes: f.RecoveryCodes, - Plugins: f.Plugins, - AutomaticUpgrades: f.AutomaticUpgrades, - IsUsageBased: f.IsUsageBasedBilling, - FeatureHiding: f.FeatureHiding, - CustomTheme: f.CustomTheme, - AccessGraph: f.AccessGraph, - DeviceTrust: &proto.DeviceTrustFeature{ - Enabled: f.DeviceTrust.Enabled, - DevicesUsageLimit: int32(f.DeviceTrust.DevicesUsageLimit), - }, - AccessRequests: &proto.AccessRequestsFeature{ - MonthlyRequestLimit: int32(f.AccessRequests.MonthlyRequestLimit), - }, - IdentityGovernance: f.IdentityGovernanceSecurity, - AccessMonitoring: &proto.AccessMonitoringFeature{ - Enabled: f.AccessMonitoring.Enabled, - MaxReportRangeLimit: int32(f.AccessMonitoring.MaxReportRangeLimit), - }, - AccessList: &proto.AccessListFeature{ - CreateLimit: int32(f.AccessList.CreateLimit), - }, - Policy: &proto.PolicyFeature{ - Enabled: f.Policy.Enabled, - }, - Questionnaire: f.Questionnaire, - IsStripeManaged: f.IsStripeManaged, - ExternalAuditStorage: f.ExternalAuditStorage, - SupportType: f.SupportType, - JoinActiveSessions: f.JoinActiveSessions, - MobileDeviceManagement: f.MobileDeviceManagement, +// GetProtoEntitlement takes a proto features set and an entitlement and returns either the proto features entitlement, +// or if not present, a false entitlement +func GetProtoEntitlement(f *proto.Features, e entitlements.EntitlementKind) *proto.EntitlementInfo { + fE := f.GetEntitlements() + al, ok := fE[string(e)] + if !ok { + return &proto.EntitlementInfo{} + } + + return &proto.EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, } } @@ -230,23 +228,6 @@ const ( ProductTypeEUB ProductType = 2 ) -// IsLegacy describes the legacy enterprise product that existed before the -// usage-based product was introduced. Some features (Device Trust, for example) -// require the IGS add-on in usage-based products but are included for legacy -// licenses. -func (f Features) IsLegacy() bool { - return !f.IsUsageBasedBilling -} - -func (f Features) IGSEnabled() bool { - return f.IdentityGovernanceSecurity -} - -// TODO(mcbattirola): remove isTeam when it is no longer used -func (f Features) IsTeam() bool { - return f.ProductType == ProductTypeTeam -} - // AccessResourcesGetter is a minimal interface that is used to get access lists // and related resources from the backend. type AccessResourcesGetter interface { @@ -398,20 +379,23 @@ func (p *defaultModules) PrintVersion() { fmt.Printf("Teleport v%s git:%s %s\n", teleport.Version, teleport.Gitref, runtime.Version()) } -// Features returns supported features +// Features returns supported features for default modules which is applied for OSS users +// todo (michellescripts) remove deprecated features func (p *defaultModules) Features() Features { p.loadDynamicValues.Do(func() { p.automaticUpgrades = automaticupgrades.IsEnabled() }) return Features{ - Kubernetes: true, - DB: true, - App: true, - Desktop: true, - AutomaticUpgrades: p.automaticUpgrades, - JoinActiveSessions: true, - SupportType: proto.SupportType_SUPPORT_TYPE_FREE, + AutomaticUpgrades: p.automaticUpgrades, + SupportType: proto.SupportType_SUPPORT_TYPE_FREE, + Entitlements: map[entitlements.EntitlementKind]EntitlementInfo{ + entitlements.App: {Enabled: true, Limit: 0}, + entitlements.DB: {Enabled: true, Limit: 0}, + entitlements.Desktop: {Enabled: true, Limit: 0}, + entitlements.JoinActiveSessions: {Enabled: true, Limit: 0}, + entitlements.K8s: {Enabled: true, Limit: 0}, + }, } } diff --git a/lib/modules/modules_test.go b/lib/modules/modules_test.go index 4b00efd2d79f2..4d0946adf6011 100644 --- a/lib/modules/modules_test.go +++ b/lib/modules/modules_test.go @@ -20,13 +20,16 @@ package modules_test import ( "context" + "math" "os" "testing" "github.com/stretchr/testify/require" + "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/modules" ) @@ -86,3 +89,197 @@ func TestValidateSessionRecordingConfigOnCloud(t *testing.T) { _, err = testServer.AuthServer.UpsertSessionRecordingConfig(ctx, recConfig) require.EqualError(t, err, "cannot set proxy recording mode on Cloud") } + +func TestFeatures_ToProto(t *testing.T) { + expected := &proto.Features{ + CustomTheme: "dark", + ProductType: 1, + SupportType: 1, + AccessControls: true, + AccessGraph: true, + AdvancedAccessWorkflows: true, + AutomaticUpgrades: true, + Cloud: true, + IsStripeManaged: true, + IsUsageBased: true, + Plugins: true, + Questionnaire: true, + RecoveryCodes: true, + AccessMonitoringConfigured: false, + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 111}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 2113}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 39}, + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: true}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 103}, + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.HSM): {Enabled: true}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.OktaSCIM): {Enabled: true}, + string(entitlements.OktaUserSync): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + string(entitlements.SessionLocks): {Enabled: true}, + string(entitlements.UpsellAlert): {Enabled: true}, + string(entitlements.UsageReporting): {Enabled: true}, + }, + // Legacy Fields; remove in v18 + Kubernetes: true, + App: false, + DB: true, + OIDC: true, + SAML: true, + HSM: true, + Desktop: true, + FeatureHiding: true, + IdentityGovernance: true, + ExternalAuditStorage: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + DeviceTrust: &proto.DeviceTrustFeature{ + Enabled: true, + DevicesUsageLimit: 103, + }, + AccessRequests: &proto.AccessRequestsFeature{ + MonthlyRequestLimit: 39, + }, + AccessMonitoring: &proto.AccessMonitoringFeature{ + Enabled: false, // set to value of AccessMonitoringConfigured + MaxReportRangeLimit: 2113, + }, + AccessList: &proto.AccessListFeature{ + CreateLimit: 111, + }, + Policy: &proto.PolicyFeature{ + Enabled: true, + }, + } + + f := modules.Features{ + CustomTheme: "dark", + ProductType: 1, + SupportType: 1, + AccessControls: true, + AccessGraph: true, + AdvancedAccessWorkflows: true, + Assist: true, + AutomaticUpgrades: true, + Cloud: true, + IsStripeManaged: true, + IsUsageBasedBilling: true, + Plugins: true, + Questionnaire: true, + RecoveryCodes: true, + AccessMonitoringConfigured: false, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.AccessLists: {Enabled: true, Limit: 111}, + entitlements.AccessMonitoring: {Enabled: true, Limit: 2113}, + entitlements.AccessRequests: {Enabled: true, Limit: 39}, + entitlements.App: {Enabled: false, Limit: 0}, + entitlements.CloudAuditLogRetention: {Enabled: true, Limit: 0}, + entitlements.DB: {Enabled: true, Limit: 0}, + entitlements.Desktop: {Enabled: true, Limit: 0}, + entitlements.DeviceTrust: {Enabled: true, Limit: 103}, + entitlements.ExternalAuditStorage: {Enabled: true, Limit: 0}, + entitlements.FeatureHiding: {Enabled: true, Limit: 0}, + entitlements.HSM: {Enabled: true, Limit: 0}, + entitlements.Identity: {Enabled: true, Limit: 0}, + entitlements.JoinActiveSessions: {Enabled: true, Limit: 0}, + entitlements.K8s: {Enabled: true, Limit: 0}, + entitlements.MobileDeviceManagement: {Enabled: true, Limit: 0}, + entitlements.OIDC: {Enabled: true, Limit: 0}, + entitlements.OktaSCIM: {Enabled: true, Limit: 0}, + entitlements.OktaUserSync: {Enabled: true, Limit: 0}, + entitlements.Policy: {Enabled: true, Limit: 0}, + entitlements.SAML: {Enabled: true, Limit: 0}, + entitlements.SessionLocks: {Enabled: true, Limit: 0}, + entitlements.UpsellAlert: {Enabled: true, Limit: 0}, + entitlements.UsageReporting: {Enabled: true, Limit: 0}, + }, + } + + actual := f.ToProto() + require.Equal(t, expected, actual) +} + +func TestFeatures_GetEntitlement(t *testing.T) { + f := modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.AccessLists: {Enabled: true, Limit: 111}, + entitlements.K8s: {Enabled: false}, + entitlements.SAML: {}, + }, + } + + actual := f.GetEntitlement(entitlements.AccessLists) + require.Equal(t, modules.EntitlementInfo{Enabled: true, Limit: 111}, actual) + + actual = f.GetEntitlement(entitlements.K8s) + require.Equal(t, modules.EntitlementInfo{Enabled: false}, actual) + + actual = f.GetEntitlement(entitlements.SAML) + require.Equal(t, modules.EntitlementInfo{}, actual) + + actual = f.GetEntitlement(entitlements.UsageReporting) + require.Equal(t, modules.EntitlementInfo{}, actual) +} + +func TestEntitlementInfo_UnderLimit(t *testing.T) { + testCases := []struct { + name string + count int + uut modules.EntitlementInfo + assert require.BoolAssertionFunc + }{ + { + name: "disabled is always out of limit", + count: 10, + uut: modules.EntitlementInfo{Enabled: false, Limit: 10000}, + assert: require.False, + }, + { + name: "within limits returns true", + count: 10, + uut: modules.EntitlementInfo{Enabled: true, Limit: 10000}, + assert: require.True, + }, + { + name: "at limits returns false", + count: 10000, + uut: modules.EntitlementInfo{Enabled: true, Limit: 10000}, + assert: require.False, + }, + { + name: "above limits returns false", + count: 10001, + uut: modules.EntitlementInfo{Enabled: true, Limit: 10000}, + assert: require.False, + }, + { + name: "zero limit implies max", + count: math.MaxInt64, + uut: modules.EntitlementInfo{Enabled: true, Limit: 0}, + assert: require.True, + }, + { + name: "handles above MaxInt32", + count: math.MaxInt32 + 1, + uut: modules.EntitlementInfo{Enabled: true, Limit: math.MaxInt32}, + assert: require.False, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.assert(t, tc.uut.UnderLimit(tc.count)) + }) + } +} diff --git a/lib/resumption/client.go b/lib/resumption/client.go index f12f51a35805f..3325a3b74e7f4 100644 --- a/lib/resumption/client.go +++ b/lib/resumption/client.go @@ -219,6 +219,12 @@ func runClientResumableUnlocking(ctx context.Context, resumableConn *Conn, first case <-detached: } + reconnectTicker.Stop() + select { + case <-reconnectTicker.Chan(): + default: + } + slog.DebugContext(ctx, "connection lost, starting reconnection loop", "host_id", hostID) reconnectDeadline := time.Now().Add(reconnectTimeout) backoff := minBackoff @@ -262,10 +268,6 @@ func runClientResumableUnlocking(ctx context.Context, resumableConn *Conn, first } reconnectTicker.Reset(replacementInterval) - select { - case <-reconnectTicker.Chan(): - default: - } } } diff --git a/lib/resumption/resumption_test.go b/lib/resumption/resumption_test.go index de6f74a89f58c..db915fcb062f3 100644 --- a/lib/resumption/resumption_test.go +++ b/lib/resumption/resumption_test.go @@ -212,6 +212,9 @@ func testResumption(t *testing.T, network, address string, expectedHostID string default: } + // wait until the reconnection loop has passed the reconnection phase + // and is waiting on the reconnection timer again + clock.BlockUntil(1) clock.Advance(replacementInterval) redialingSyncPoint <- struct{}{} diff --git a/lib/service/connect.go b/lib/service/connect.go index 8d1edfde555ae..ce377b68c78e7 100644 --- a/lib/service/connect.go +++ b/lib/service/connect.go @@ -43,7 +43,9 @@ import ( "github.com/gravitational/teleport/api/client/proto" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" + apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/retryutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" @@ -1135,7 +1137,10 @@ func (process *TeleportProcess) getConnector(clientIdentity, serverIdentity *sta } // Set cluster features and return successfully with a working connector. - process.setClusterFeatures(pingResponse.GetServerFeatures()) + // TODO(michellescripts) remove clone & compatibility check in v18 + cloned := apiutils.CloneProtoMsg(pingResponse.GetServerFeatures()) + supportEntitlementsCompatibility(cloned) + process.setClusterFeatures(cloned) process.setAuthSubjectiveAddr(pingResponse.RemoteAddr) process.logger.InfoContext(process.ExitContext(), "features loaded from auth server", "identity", clientIdentity.ID.Role, "features", pingResponse.GetServerFeatures()) @@ -1146,6 +1151,70 @@ func (process *TeleportProcess) getConnector(clientIdentity, serverIdentity *sta }, nil } +// supportEntitlementsCompatibility ensures entitlements are backwards compatible +// If Entitlements are present, there are no changes +// If Entitlements are not present, sets the entitlements fields to legacy field values +// TODO(michellescripts) remove in v18 +func supportEntitlementsCompatibility(features *proto.Features) { + if len(features.Entitlements) > 0 { + return + } + + features.Entitlements = getBaseEntitlements(features.GetEntitlements()) + + // Entitlements: All records are {enabled: false}; update to equal legacy feature value + features.Entitlements[string(entitlements.ExternalAuditStorage)] = &proto.EntitlementInfo{Enabled: features.GetExternalAuditStorage()} + features.Entitlements[string(entitlements.FeatureHiding)] = &proto.EntitlementInfo{Enabled: features.GetFeatureHiding()} + features.Entitlements[string(entitlements.Identity)] = &proto.EntitlementInfo{Enabled: features.GetIdentityGovernance()} + features.Entitlements[string(entitlements.JoinActiveSessions)] = &proto.EntitlementInfo{Enabled: features.GetJoinActiveSessions()} + features.Entitlements[string(entitlements.MobileDeviceManagement)] = &proto.EntitlementInfo{Enabled: features.GetMobileDeviceManagement()} + features.Entitlements[string(entitlements.OIDC)] = &proto.EntitlementInfo{Enabled: features.GetOIDC()} + features.Entitlements[string(entitlements.Policy)] = &proto.EntitlementInfo{Enabled: features.GetPolicy().GetEnabled()} + features.Entitlements[string(entitlements.SAML)] = &proto.EntitlementInfo{Enabled: features.GetSAML()} + features.Entitlements[string(entitlements.K8s)] = &proto.EntitlementInfo{Enabled: features.GetKubernetes()} + features.Entitlements[string(entitlements.App)] = &proto.EntitlementInfo{Enabled: features.GetApp()} + features.Entitlements[string(entitlements.DB)] = &proto.EntitlementInfo{Enabled: features.GetDB()} + features.Entitlements[string(entitlements.Desktop)] = &proto.EntitlementInfo{Enabled: features.GetDesktop()} + features.Entitlements[string(entitlements.HSM)] = &proto.EntitlementInfo{Enabled: features.GetHSM()} + + // set default Identity fields to legacy feature value + features.Entitlements[string(entitlements.AccessLists)] = &proto.EntitlementInfo{Enabled: true, Limit: features.GetAccessList().GetCreateLimit()} + features.Entitlements[string(entitlements.AccessMonitoring)] = &proto.EntitlementInfo{Enabled: features.GetAccessMonitoring().GetEnabled(), Limit: features.GetAccessMonitoring().GetMaxReportRangeLimit()} + features.Entitlements[string(entitlements.AccessRequests)] = &proto.EntitlementInfo{Enabled: features.GetAccessRequests().MonthlyRequestLimit > 0, Limit: features.GetAccessRequests().GetMonthlyRequestLimit()} + features.Entitlements[string(entitlements.DeviceTrust)] = &proto.EntitlementInfo{Enabled: features.GetDeviceTrust().GetEnabled(), Limit: features.GetDeviceTrust().GetDevicesUsageLimit()} + // override Identity Package features if Identity is enabled: set true and clear limit + if features.GetIdentityGovernance() { + features.Entitlements[string(entitlements.AccessLists)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.AccessMonitoring)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.AccessRequests)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.DeviceTrust)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.OktaSCIM)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.OktaUserSync)] = &proto.EntitlementInfo{Enabled: true} + features.Entitlements[string(entitlements.SessionLocks)] = &proto.EntitlementInfo{Enabled: true} + } +} + +// getBaseEntitlements takes a cloud entitlement set and returns a modules Entitlement set +func getBaseEntitlements(protoEntitlements map[string]*proto.EntitlementInfo) map[string]*proto.EntitlementInfo { + all := entitlements.AllEntitlements + result := make(map[string]*proto.EntitlementInfo, len(all)) + + for _, e := range all { + al, ok := protoEntitlements[string(e)] + if !ok { + result[string(e)] = &proto.EntitlementInfo{} + continue + } + + result[string(e)] = &proto.EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, + } + } + + return result +} + // newClient attempts to connect to either the proxy server or auth server // For config v3 and onwards, it will only connect to either the proxy (via tunnel) or the auth server (direct), // depending on what was specified in the config. diff --git a/lib/service/connect_test.go b/lib/service/connect_test.go new file mode 100644 index 0000000000000..5a2df2e136ef5 --- /dev/null +++ b/lib/service/connect_test.go @@ -0,0 +1,283 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package service + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/api/client/proto" + apiutils "github.com/gravitational/teleport/api/utils" + "github.com/gravitational/teleport/entitlements" +) + +func Test_supportEntitlementsCompatibility(t *testing.T) { + tests := []struct { + name string + features *proto.Features + expected map[string]*proto.EntitlementInfo + }{ + { + name: "entitlements present; keeps entitlement values", + features: &proto.Features{ + DeviceTrust: nil, + AccessRequests: nil, + AccessList: nil, + AccessMonitoring: nil, + Policy: nil, + CustomTheme: "", + ProductType: 0, + SupportType: 0, + Kubernetes: false, + App: false, + DB: false, + OIDC: false, + SAML: false, + AccessControls: false, + AdvancedAccessWorkflows: false, + Cloud: false, + HSM: false, + Desktop: false, + RecoveryCodes: false, + Plugins: false, + AutomaticUpgrades: false, + IsUsageBased: false, + Assist: false, + FeatureHiding: false, + IdentityGovernance: false, + AccessGraph: false, + Questionnaire: false, + IsStripeManaged: false, + ExternalAuditStorage: false, + JoinActiveSessions: false, + MobileDeviceManagement: false, + AccessMonitoringConfigured: false, + Entitlements: map[string]*proto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 111}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 2113}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 39}, + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: true}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 103}, + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.HSM): {Enabled: true}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.OktaSCIM): {Enabled: true}, + string(entitlements.OktaUserSync): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + string(entitlements.SessionLocks): {Enabled: true}, + string(entitlements.UpsellAlert): {Enabled: true}, + string(entitlements.UsageReporting): {Enabled: true}, + }, + }, + expected: map[string]*proto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 111}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 2113}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 39}, + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: true}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 103}, + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.HSM): {Enabled: true}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.OktaSCIM): {Enabled: true}, + string(entitlements.OktaUserSync): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + string(entitlements.SessionLocks): {Enabled: true}, + string(entitlements.UpsellAlert): {Enabled: true}, + string(entitlements.UsageReporting): {Enabled: true}, + }, + }, + { + name: "entitlements not present; identity on - sets legacy fields & drops limits", + features: &proto.Features{ + DeviceTrust: &proto.DeviceTrustFeature{ + Enabled: true, + DevicesUsageLimit: 33, + }, + AccessRequests: &proto.AccessRequestsFeature{ + MonthlyRequestLimit: 22, + }, + AccessList: &proto.AccessListFeature{ + CreateLimit: 44, + }, + AccessMonitoring: &proto.AccessMonitoringFeature{ + Enabled: true, + MaxReportRangeLimit: 55, + }, + Policy: &proto.PolicyFeature{ + Enabled: true, + }, + CustomTheme: "", + ProductType: 0, + SupportType: 0, + Kubernetes: true, + App: true, + DB: true, + OIDC: true, + SAML: true, + AccessControls: true, + AdvancedAccessWorkflows: true, + Cloud: true, + HSM: true, + Desktop: true, + RecoveryCodes: true, + Plugins: true, + AutomaticUpgrades: true, + IsUsageBased: true, + Assist: true, + FeatureHiding: true, + IdentityGovernance: true, + AccessGraph: true, + Questionnaire: true, + IsStripeManaged: true, + ExternalAuditStorage: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + AccessMonitoringConfigured: true, + }, + expected: map[string]*proto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true}, + string(entitlements.AccessMonitoring): {Enabled: true}, + string(entitlements.AccessRequests): {Enabled: true}, + string(entitlements.App): {Enabled: true}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: true}, + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.HSM): {Enabled: true}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.OktaSCIM): {Enabled: true}, + string(entitlements.OktaUserSync): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + string(entitlements.SessionLocks): {Enabled: true}, + // defaults, no legacy equivalent + string(entitlements.UsageReporting): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + }, + }, + { + name: "entitlements not present; identity off - sets legacy fields", + features: &proto.Features{ + DeviceTrust: &proto.DeviceTrustFeature{ + Enabled: true, + DevicesUsageLimit: 33, + }, + AccessRequests: &proto.AccessRequestsFeature{ + MonthlyRequestLimit: 22, + }, + AccessList: &proto.AccessListFeature{ + CreateLimit: 44, + }, + AccessMonitoring: &proto.AccessMonitoringFeature{ + Enabled: true, + MaxReportRangeLimit: 55, + }, + Policy: &proto.PolicyFeature{ + Enabled: true, + }, + CustomTheme: "", + ProductType: 0, + SupportType: 0, + Kubernetes: true, + App: true, + DB: true, + OIDC: true, + SAML: true, + AccessControls: true, + AdvancedAccessWorkflows: true, + Cloud: true, + HSM: true, + Desktop: true, + RecoveryCodes: true, + Plugins: true, + AutomaticUpgrades: true, + IsUsageBased: true, + Assist: true, + FeatureHiding: true, + IdentityGovernance: false, + AccessGraph: true, + Questionnaire: true, + IsStripeManaged: true, + ExternalAuditStorage: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + AccessMonitoringConfigured: true, + }, + expected: map[string]*proto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 44}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 55}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 22}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 33}, + string(entitlements.App): {Enabled: true}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.HSM): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + + // defaults, no legacy equivalent + string(entitlements.UsageReporting): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + // Identity off, fields false + string(entitlements.Identity): {Enabled: false}, + string(entitlements.SessionLocks): {Enabled: false}, + string(entitlements.OktaSCIM): {Enabled: false}, + string(entitlements.OktaUserSync): {Enabled: false}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cloned := apiutils.CloneProtoMsg(tt.features) + + supportEntitlementsCompatibility(cloned) + require.Equal(t, tt.expected, cloned.Entitlements) + }) + } +} diff --git a/lib/service/kubernetes.go b/lib/service/kubernetes.go index 2681f7a404043..432ff238bcc0e 100644 --- a/lib/service/kubernetes.go +++ b/lib/service/kubernetes.go @@ -29,9 +29,11 @@ import ( "github.com/gravitational/teleport" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/authz" kubeproxy "github.com/gravitational/teleport/lib/kube/proxy" "github.com/gravitational/teleport/lib/labels" + "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/reversetunnelclient" @@ -47,7 +49,9 @@ func (process *TeleportProcess) initKubernetes() { if conn == nil { return trace.Wrap(err) } - if !process.GetClusterFeatures().Kubernetes { + features := process.GetClusterFeatures() + k8s := modules.GetProtoEntitlement(&features, entitlements.K8s) + if !k8s.Enabled { logger.WarnContext(process.ExitContext(), "Warning: Kubernetes service not initialized because Teleport Auth Server is not licensed for Kubernetes Access. Please contact the cluster administrator to enable it.") return nil } diff --git a/lib/service/service.go b/lib/service/service.go index b61155dd001ac..73d0bfe8a45f6 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -1989,13 +1989,12 @@ func (process *TeleportProcess) initAuthService() error { return nil } - cache, err := process.newAccessCache(accesspoint.AccessCacheConfig{ - Services: as.Services, - Setup: cache.ForAuth, - CacheName: []string{teleport.ComponentAuth}, - Events: true, - Unstarted: true, - }) + cache, err := process.newAccessCacheForServices(accesspoint.Config{ + Setup: cache.ForAuth, + CacheName: []string{teleport.ComponentAuth}, + EventsSystem: true, + Unstarted: true, + }, as.Services) if err != nil { return trace.Wrap(err) } @@ -2375,13 +2374,88 @@ func (process *TeleportProcess) OnExit(serviceName string, callback func(interfa } // newAccessCache returns new local cache access point -func (process *TeleportProcess) newAccessCache(cfg accesspoint.AccessCacheConfig) (*cache.Cache, error) { +func (process *TeleportProcess) newAccessCacheForServices(cfg accesspoint.Config, services *auth.Services) (*cache.Cache, error) { + cfg.Context = process.ExitContext() + cfg.ProcessID = process.id + cfg.TracingProvider = process.TracingProvider + cfg.MaxRetryPeriod = process.Config.CachePolicy.MaxRetryPeriod + + cfg.Access = services.Access + cfg.AccessLists = services.AccessLists + cfg.AccessMonitoringRules = services.AccessMonitoringRules + cfg.AppSession = services.Identity + cfg.Apps = services.Apps + cfg.ClusterConfig = services.ClusterConfiguration + cfg.CrownJewels = services.CrownJewels + cfg.DatabaseObjects = services.DatabaseObjects + cfg.DatabaseServices = services.DatabaseServices + cfg.Databases = services.Databases + cfg.DiscoveryConfigs = services.DiscoveryConfigs + cfg.DynamicAccess = services.DynamicAccessExt + cfg.Events = services.Events + cfg.Integrations = services.Integrations + cfg.KubeWaitingContainers = services.KubeWaitingContainer + cfg.Kubernetes = services.Kubernetes + cfg.Notifications = services.Notifications + cfg.Okta = services.Okta + cfg.Presence = services.PresenceInternal + cfg.Provisioner = services.Provisioner + cfg.Restrictions = services.Restrictions + cfg.SAMLIdPServiceProviders = services.SAMLIdPServiceProviders + cfg.SAMLIdPSession = services.Identity + cfg.SecReports = services.SecReports + cfg.SnowflakeSession = services.Identity + cfg.Trust = services.TrustInternal + cfg.UserGroups = services.UserGroups + cfg.UserLoginStates = services.UserLoginStates + cfg.Users = services.Identity + cfg.WebSession = services.Identity.WebSessions() + cfg.WebToken = services.Identity.WebTokens() + cfg.WindowsDesktops = services.WindowsDesktops + + return accesspoint.NewCache(cfg) +} + +func (process *TeleportProcess) newAccessCacheForClient(cfg accesspoint.Config, client authclient.ClientI) (*cache.Cache, error) { cfg.Context = process.ExitContext() cfg.ProcessID = process.id cfg.TracingProvider = process.TracingProvider cfg.MaxRetryPeriod = process.Config.CachePolicy.MaxRetryPeriod - return accesspoint.NewAccessCache(cfg) + cfg.Access = client + cfg.AccessLists = client.AccessListClient() + cfg.AccessMonitoringRules = client.AccessMonitoringRuleClient() + cfg.AppSession = client + cfg.Apps = client + cfg.ClusterConfig = client + cfg.CrownJewels = client.CrownJewelServiceClient() + cfg.DatabaseObjects = client.DatabaseObjectsClient() + cfg.DatabaseServices = client + cfg.Databases = client + cfg.DiscoveryConfigs = client.DiscoveryConfigClient() + cfg.DynamicAccess = client + cfg.Events = client + cfg.Integrations = client + cfg.KubeWaitingContainers = client + cfg.Kubernetes = client + cfg.Notifications = client + cfg.Okta = client.OktaClient() + cfg.Presence = client + cfg.Provisioner = client + cfg.Restrictions = client + cfg.SAMLIdPServiceProviders = client + cfg.SAMLIdPSession = client + cfg.SecReports = client.SecReportsClient() + cfg.SnowflakeSession = client + cfg.Trust = client + cfg.UserGroups = client + cfg.UserLoginStates = client.UserLoginStateClient() + cfg.Users = client + cfg.WebSession = client.WebSessions() + cfg.WebToken = client.WebTokens() + cfg.WindowsDesktops = client + + return accesspoint.NewCache(cfg) } // newLocalCacheForNode returns new instance of access point configured for a local proxy. @@ -2524,33 +2598,12 @@ func (process *TeleportProcess) newLocalCacheForWindowsDesktop(clt authclient.Cl return authclient.NewWindowsDesktopWrapper(clt, cache), nil } -// accessPointWrapper is a wrapper around [authclient.ClientI] that reduces the surface area of the -// auth.ClientI.DiscoveryConfigClient interface to services.DiscoveryConfigs. -// Cache doesn't implement the full [authclient.ClientI] interface, so we need to wrap [authclient.ClientI] -// to make it compatible with the services.DiscoveryConfigs interface. -type accessPointWrapper struct { - authclient.ClientI -} - -func (a accessPointWrapper) CrownJewelClient() services.CrownJewels { - return a.ClientI.CrownJewelServiceClient() -} - -func (a accessPointWrapper) DatabaseObjectsClient() services.DatabaseObjects { - return a.ClientI.DatabaseObjectsClient() -} - -func (a accessPointWrapper) DiscoveryConfigClient() services.DiscoveryConfigs { - return a.ClientI.DiscoveryConfigClient() -} - // NewLocalCache returns new instance of access point func (process *TeleportProcess) NewLocalCache(clt authclient.ClientI, setupConfig cache.SetupConfigFn, cacheName []string) (*cache.Cache, error) { - return process.newAccessCache(accesspoint.AccessCacheConfig{ - Services: &accessPointWrapper{ClientI: clt}, + return process.newAccessCacheForClient(accesspoint.Config{ Setup: setupConfig, CacheName: cacheName, - }) + }, clt) } // GetRotation returns the process rotation. diff --git a/lib/service/service_test.go b/lib/service/service_test.go index 325a4d148fc6f..2a32913450cf2 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -49,6 +49,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/breaker" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" @@ -477,8 +478,10 @@ func TestAthenaAuditLogSetup(t *testing.T) { ctx := context.Background() modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - Cloud: true, - ExternalAuditStorage: true, + Cloud: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.ExternalAuditStorage: {Enabled: true}, + }, }, }) diff --git a/lib/services/access_request_cache.go b/lib/services/access_request_cache.go index 277358414f415..d58ba38aacca3 100644 --- a/lib/services/access_request_cache.go +++ b/lib/services/access_request_cache.go @@ -56,6 +56,8 @@ type AccessRequestCacheConfig struct { Events types.Events // Getter is an access request getter client. Getter AccessRequestGetter + // MaxRetryPeriod is the maximum retry period on failed watches. + MaxRetryPeriod time.Duration } // CheckAndSetDefaults valides the config and provides reasonable defaults for optional fields. @@ -87,8 +89,12 @@ type AccessRequestCache struct { primaryCache *sortcache.SortCache[*types.AccessRequestV3] ttlCache *utils.FnCache initC chan struct{} + initOnce sync.Once closeContext context.Context cancel context.CancelFunc + // onInit is a callback used in tests to detect + // individual initializations. + onInit func() } // NewAccessRequestCache sets up a new [AccessRequestCache] instance based on the supplied @@ -120,8 +126,9 @@ func NewAccessRequestCache(cfg AccessRequestCacheConfig) (*AccessRequestCache, e } if _, err := newResourceWatcher(ctx, c, ResourceWatcherConfig{ - Component: "access-request-cache", - Client: cfg.Events, + Component: "access-request-cache", + Client: cfg.Events, + MaxRetryPeriod: cfg.MaxRetryPeriod, }); err != nil { cancel() return nil, trace.Wrap(err) @@ -352,10 +359,22 @@ func (c *AccessRequestCache) getResourcesAndUpdateCurrent(ctx context.Context) e c.rw.Lock() defer c.rw.Unlock() c.primaryCache = cache - close(c.initC) + c.initOnce.Do(func() { + close(c.initC) + }) + if c.onInit != nil { + c.onInit() + } return nil } +// SetInitCallback is used in tests that care about cache inits. +func (c *AccessRequestCache) SetInitCallback(cb func()) { + c.rw.Lock() + defer c.rw.Unlock() + c.onInit = cb +} + // processEventsAndUpdateCurrent is part of the resourceCollector interface and is used to update the // primary cache state when modification events occur. func (c *AccessRequestCache) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { @@ -395,6 +414,7 @@ func (c *AccessRequestCache) notifyStale() { } c.primaryCache = nil c.initC = make(chan struct{}) + c.initOnce = sync.Once{} } // initializationChan is part of the resourceCollector interface and gets the channel diff --git a/lib/services/access_request_cache_test.go b/lib/services/access_request_cache_test.go index 905e2882f97e5..1be5d24044529 100644 --- a/lib/services/access_request_cache_test.go +++ b/lib/services/access_request_cache_test.go @@ -22,7 +22,10 @@ import ( "testing" "time" + "github.com/google/uuid" + "github.com/gravitational/trace" "github.com/stretchr/testify/require" + "golang.org/x/sync/errgroup" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" @@ -34,6 +37,8 @@ import ( type accessRequestServices struct { types.Events services.DynamicAccessExt + + bk *memory.Memory } func newAccessRequestPack(t *testing.T) (accessRequestServices, *services.AccessRequestCache) { @@ -43,11 +48,13 @@ func newAccessRequestPack(t *testing.T) (accessRequestServices, *services.Access svcs := accessRequestServices{ Events: local.NewEventsService(bk), DynamicAccessExt: local.NewDynamicAccessService(bk), + bk: bk, } cache, err := services.NewAccessRequestCache(services.AccessRequestCacheConfig{ - Events: svcs, - Getter: svcs, + Events: svcs, + Getter: svcs, + MaxRetryPeriod: time.Millisecond * 100, }) require.NoError(t, err) @@ -60,6 +67,108 @@ func newAccessRequestPack(t *testing.T) (accessRequestServices, *services.Access return svcs, cache } +func TestAccessRequestCacheResets(t *testing.T) { + const ( + requestCount = 100 + workers = 20 + resets = 3 + ) + + t.Parallel() + + svcs, cache := newAccessRequestPack(t) + defer cache.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + for i := 0; i < requestCount; i++ { + r, err := types.NewAccessRequest(uuid.New().String(), "alice@example.com", "some-role") + require.NoError(t, err) + + _, err = svcs.CreateAccessRequestV2(ctx, r) + require.NoError(t, err) + } + + timeout := time.After(time.Second * 30) + + for { + rsp, err := cache.ListAccessRequests(ctx, &proto.ListAccessRequestsRequest{ + Limit: requestCount, + }) + require.NoError(t, err) + if len(rsp.AccessRequests) == requestCount { + break + } + + select { + case <-timeout: + require.FailNow(t, "timeout waiting for access request cache to populate") + case <-time.After(time.Millisecond * 200): + } + } + + doneC := make(chan struct{}) + reads := make(chan struct{}, workers) + var eg errgroup.Group + + for i := 0; i < workers; i++ { + eg.Go(func() error { + for { + select { + case <-doneC: + return nil + case <-time.After(time.Millisecond * 20): + } + + rsp, err := cache.ListAccessRequests(ctx, &proto.ListAccessRequestsRequest{ + Limit: int32(requestCount), + }) + if err != nil { + return trace.Errorf("unexpected read failure: %v", err) + } + + select { + case reads <- struct{}{}: + default: + } + + if len(rsp.AccessRequests) != requestCount { + return trace.Errorf("unexpected number of access requests: %d (expected %d)", len(rsp.AccessRequests), requestCount) + } + } + }) + } + + inits := make(chan struct{}, resets+1) + cache.SetInitCallback(func() { + inits <- struct{}{} + }) + + timeout = time.After(time.Second * 30) + for i := 0; i < resets; i++ { + svcs.bk.CloseWatchers() + select { + case <-inits: + case <-timeout: + require.FailNowf(t, "timeout waiting for access request cache to reset", "reset=%d", i) + } + + for j := 0; j < workers; j++ { + // ensure that we're not racing ahead of worker reads too + // much if inits are happening quickly. + select { + case <-reads: + case <-timeout: + require.FailNowf(t, "timeout waiting for worker reads to catch up", "reset=%d", i) + } + } + } + + close(doneC) + require.NoError(t, eg.Wait()) +} + // TestAccessRequestCacheBasics verifies the basic expected behaviors of the access request cache, // including correct sorting and handling of put/delete events. func TestAccessRequestCacheBasics(t *testing.T) { diff --git a/lib/services/crown_jewels_test.go b/lib/services/crown_jewels_test.go index 62f579ea11f47..4b9347ea61d01 100644 --- a/lib/services/crown_jewels_test.go +++ b/lib/services/crown_jewels_test.go @@ -65,6 +65,7 @@ func TestUnmarshalCrownJewel(t *testing.T) { }, }, Spec: &crownjewelv1.CrownJewelSpec{ + Query: "SELECT * FROM nodes", TeleportMatchers: []*crownjewelv1.TeleportMatcher{ { Kinds: []string{"node"}, @@ -106,6 +107,7 @@ metadata: env: example name: example-crown-jewel spec: + query: "SELECT * FROM nodes" aws_matchers: - regions: - us-west-1 diff --git a/lib/services/local/access_list.go b/lib/services/local/access_list.go index 49c075448e246..97317a4648999 100644 --- a/lib/services/local/access_list.go +++ b/lib/services/local/access_list.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" @@ -195,7 +196,7 @@ func (a *AccessListService) runOpWithLock(ctx context.Context, accessList *acces // the AccessList feature action := updateAccessList - if !modules.GetModules().Features().IGSEnabled() { + if !modules.GetModules().Features().GetEntitlement(entitlements.Identity).Enabled { action = func() error { err := a.service.RunWhileLocked(ctx, createAccessListLimitLockName, accessListLockTTL, func(ctx context.Context, _ backend.Backend) error { @@ -463,7 +464,7 @@ func (a *AccessListService) UpsertAccessListWithMembers(ctx context.Context, acc // AccessList feature action := reconcileMembers - if !modules.GetModules().Features().IGSEnabled() { + if !modules.GetModules().Features().GetEntitlement(entitlements.Identity).Enabled { action = func() error { return a.service.RunWhileLocked(ctx, createAccessListLimitLockName, 2*accessListLockTTL, func(ctx context.Context, _ backend.Backend) error { @@ -659,8 +660,8 @@ func lockName(accessListName string) string { // access list name matches the ones we retrieved. // Returns error if limit has been reached. func (a *AccessListService) VerifyAccessListCreateLimit(ctx context.Context, targetAccessListName string) error { - feature := modules.GetModules().Features() - if feature.IGSEnabled() { + f := modules.GetModules().Features() + if f.GetEntitlement(entitlements.Identity).Enabled { return nil // unlimited } @@ -669,6 +670,9 @@ func (a *AccessListService) VerifyAccessListCreateLimit(ctx context.Context, tar return trace.Wrap(err) } + // We are *always* allowed to create at least one AccessLists in order to + // demonstrate the functionality. + // TODO(tcsc): replace with a default OSS entitlement of 1 if len(lists) == 0 { return nil } @@ -681,7 +685,8 @@ func (a *AccessListService) VerifyAccessListCreateLimit(ctx context.Context, tar } } - if len(lists) < feature.AccessList.CreateLimit { + accessListEntitlement := f.GetEntitlement(entitlements.AccessLists) + if accessListEntitlement.UnderLimit(len(lists)) { return nil } diff --git a/lib/services/local/access_list_test.go b/lib/services/local/access_list_test.go index 4d572b091989c..c0a41478fbb61 100644 --- a/lib/services/local/access_list_test.go +++ b/lib/services/local/access_list_test.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/types/header" "github.com/gravitational/teleport/api/types/trait" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/backend/memory" "github.com/gravitational/teleport/lib/modules" @@ -140,36 +141,218 @@ func TestAccessListCRUD(t *testing.T) { require.ElementsMatch(t, expectedAccessList, created.Spec.Owners) } -// TestAccessListCreate_UpsertAccessList_WithoutLimit tests creating access list -// is unlimited if IGS feature is enabled. -func TestAccessListCreate_UpsertAccessList_WithoutLimit(t *testing.T) { +func requireAccessDenied(t require.TestingT, err error, i ...any) { + require.True( + t, + trace.IsAccessDenied(err), + "err should be access denied, was: %s", err, + ) +} + +// TestAccessList_EntitlementLimits asserts that any limits on creating +// AccessLists are correctly enforced at Upsert time. +func TestAccessList_EntitlementLimits(t *testing.T) { + type aclSelector func([]*accesslist.AccessList) *accesslist.AccessList + ctx := context.Background() clock := clockwork.NewFakeClock() - mem, err := memory.New(memory.Config{ - Context: ctx, - Clock: clock, - }) - require.NoError(t, err) + // an ACL selection function that creates a new AccessList to insert + createNew := func([]*accesslist.AccessList) *accesslist.AccessList { + return newAccessList(t, "test-target", clock) + } - service := newAccessListService(t, mem, clock, true /* igsEnabled */) + // an ACL selection function that selects the nth access list from the list + // of pre-created ACLs. Used to simulate an update. + update := func(n int) aclSelector { + return func(acls []*accesslist.AccessList) *accesslist.AccessList { + return acls[n] + } + } - accessList1 := newAccessList(t, "accessList1", clock) - accessList2 := newAccessList(t, "accessList2", clock) - accessList3 := newAccessList(t, "accessList3", clock) + testCases := []struct { + name string + igsEnabled bool + aclName string + entitlement modules.EntitlementInfo + existingACLCount int + aclSelector aclSelector + expectErrorFn require.ErrorAssertionFunc + expectedACLCount int + }{ + { + name: "igs-enabled-no-limit-on-create", + igsEnabled: true, + entitlement: modules.EntitlementInfo{Enabled: false}, + existingACLCount: 3, + aclSelector: createNew, + expectErrorFn: require.NoError, + expectedACLCount: 4, + }, + { + name: "can-create-one-access-list-when-disabled", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: false}, + existingACLCount: 0, + aclSelector: createNew, + expectErrorFn: require.NoError, + expectedACLCount: 1, + }, + { + name: "cant-create-a-second-access-list-when-disabled", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: false}, + existingACLCount: 1, + aclSelector: createNew, + expectErrorFn: requireAccessDenied, + expectedACLCount: 1, + }, + { + name: "disabled-allows-update", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: false}, + existingACLCount: 3, + aclSelector: update(1), + expectErrorFn: require.NoError, + expectedACLCount: 3, + }, + { + name: "under-default-limit-succeeds", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 1}, + existingACLCount: 0, + aclSelector: createNew, + expectErrorFn: require.NoError, + expectedACLCount: 1, + }, + { + name: "at-default-limit-fails", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 1}, + existingACLCount: 1, + aclSelector: createNew, + expectErrorFn: requireAccessDenied, + expectedACLCount: 1, + }, + { + name: "at-default-limit-allows-update", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 1}, + existingACLCount: 1, + aclSelector: update(0), + expectErrorFn: require.NoError, + expectedACLCount: 1, + }, + { + name: "infinite-limit-succeeds", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 0}, + existingACLCount: 5, + aclSelector: createNew, + expectErrorFn: require.NoError, + expectedACLCount: 6, + }, + { + name: "above-limit-fails", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 10}, + existingACLCount: 20, + aclSelector: createNew, + expectErrorFn: requireAccessDenied, + expectedACLCount: 20, + }, + { + name: "above-limit-allows-update", + igsEnabled: false, + entitlement: modules.EntitlementInfo{Enabled: true, Limit: 10}, + existingACLCount: 20, + aclSelector: update(15), + expectErrorFn: require.NoError, + expectedACLCount: 20, + }, + } - // No limit to creating access list. - _, err = service.UpsertAccessList(ctx, accessList1) - require.NoError(t, err) - _, err = service.UpsertAccessList(ctx, accessList2) - require.NoError(t, err) - _, err = service.UpsertAccessList(ctx, accessList3) - require.NoError(t, err) + // aclOperation abstracts over Upsert and UpsertWithMembers so we can use + // the same test code and cases for both operations. + type aclOperation func(context.Context, *AccessListService, *accesslist.AccessList) (*accesslist.AccessList, error) - // Fetch all access lists. - out, err := service.GetAccessLists(ctx) - require.NoError(t, err) - require.Len(t, out, 3) + operations := []struct { + name string + invoke aclOperation + }{ + { + name: "Upsert", + invoke: func(ctx context.Context, uut *AccessListService, acl *accesslist.AccessList) (*accesslist.AccessList, error) { + return uut.UpsertAccessList(ctx, acl) + }, + }, + { + name: "UpsertWithMembers", + invoke: func(ctx context.Context, uut *AccessListService, acl *accesslist.AccessList) (*accesslist.AccessList, error) { + updatedACL, _, err := uut.UpsertAccessListWithMembers(ctx, acl, []*accesslist.AccessListMember{}) + return updatedACL, err + }, + }, + } + + for _, op := range operations { + t.Run(op.name, func(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // GIVEN an AccessList service specifically configured with/without + // IGS and a specific AccessList entitlement... + mem, err := memory.New(memory.Config{ + Context: ctx, + Clock: clock, + }) + require.NoError(t, err, "failed creating in-memory backend") + uut := newAccessListService(t, mem, clock, tc.igsEnabled) + + // note - we do this _after_ creating the AccessList Service test + // target because the `newAccessListService()` fixture also sets the + // test modules, and that would clobber our test setup if we went + // first + modules.SetTestModules(t, &modules.TestModules{ + TestBuildType: modules.BuildEnterprise, + TestFeatures: modules.Features{ + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Identity: {Enabled: tc.igsEnabled}, + entitlements.AccessLists: tc.entitlement, + }, + }, + }) + + // ALSO GIVEN a number of pre-created AccessLists... + var preCreatedACLs []*accesslist.AccessList + for i := 0; i < tc.existingACLCount; i++ { + // note that we write these setup resources directly to the back-end + // service in order to bypass any limit enforcement. This lets us + // set up a wider range of interesting test cases + acl, err := uut.service.UpsertResource(ctx, + newAccessList(t, fmt.Sprintf("accessList-%02d", i), clock)) + require.NoError(t, err, "Creating existing AccessLists for test") + preCreatedACLs = append(preCreatedACLs, acl) + } + + // WHEN I attempt to create a new AccessList or update an existing + // one... + testACL := tc.aclSelector(preCreatedACLs) + _, err = op.invoke(ctx, uut, testACL) + + // EXPECT that the error state will match the expectation in the + // test case + + tc.expectErrorFn(t, err) + + // ALSO EXPECT that the number of AccessLists stored by the service + // matches the expectation in the test case + out, err := uut.GetAccessLists(ctx) + require.NoError(t, err) + require.Len(t, out, tc.expectedACLCount) + }) + } + }) + } } // TestAccessListCreate_UpdateAccessList tests creating access list @@ -206,148 +389,6 @@ func TestAccessListCreate_UpdateAccessList(t *testing.T) { require.True(t, trace.IsCompareFailed(err), "expected precondition failed error, got %v", err) } -// TestAccessListCreate_UpsertAccessList_WithLimit tests creating access list -// is limited to the limit defined in feature if IGS is NOT enabled. -// Also tests "upserting" and deleting is allowed despite "create" limit reached. -func TestAccessListCreate_UpsertAccessList_WithLimit(t *testing.T) { - ctx := context.Background() - clock := clockwork.NewFakeClock() - - mem, err := memory.New(memory.Config{ - Context: ctx, - Clock: clock, - }) - require.NoError(t, err) - - service := newAccessListService(t, mem, clock, false /* igsEnabled */) - - accessList1 := newAccessList(t, "accessList1", clock) - accessList2 := newAccessList(t, "accessList2", clock) - - // First create is free. - _, err = service.UpsertAccessList(ctx, accessList1) - require.NoError(t, err) - - // Second create should return an error. - _, err = service.UpsertAccessList(ctx, accessList2) - require.True(t, trace.IsAccessDenied(err), "expected access denied / license limit error, got %v", err) - require.ErrorContains(t, err, "reached its limit") - - // Double check only be one access list exists. - out, err := service.GetAccessLists(ctx) - require.NoError(t, err) - require.Len(t, out, 1) - - // Updating existing access list should be allowed. - accessList1.Spec.Description = "changing description" - _, err = service.UpsertAccessList(ctx, accessList1) - require.NoError(t, err) - - // Delete the one access list. - err = service.DeleteAccessList(ctx, "accessList1") - require.NoError(t, err) - - // Create the same list again. - _, err = service.UpsertAccessList(ctx, accessList1) - require.NoError(t, err) -} - -// TestAccessListCreate_UpsertAccessListWithMembers_WithLimit tests creating access list -// with members, is limited to the limit defined in feature if IGS is NOT enabled. -// Also tests "upserting" and deleting is allowed despite "create" limit reached. -func TestAccessListCreate_UpsertAccessListWithMembers_WithLimit(t *testing.T) { - ctx := context.Background() - clock := clockwork.NewFakeClock() - - mem, err := memory.New(memory.Config{ - Context: ctx, - Clock: clock, - }) - require.NoError(t, err) - - service := newAccessListService(t, mem, clock, false /* igsEnabled */) - - accessList1 := newAccessList(t, "accessList1", clock) - accessList2 := newAccessList(t, "accessList2", clock) - - accessListMember1 := newAccessListMember(t, accessList1.GetName(), "alice") - accessListMember2 := newAccessListMember(t, accessList1.GetName(), "bob") - - // First create is free. - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList1, []*accesslist.AccessListMember{accessListMember1}) - require.NoError(t, err) - - // Check the count - count, err := service.CountAccessListMembers(ctx, accessList1.GetName()) - require.NoError(t, err) - require.Equal(t, uint32(1), count) - - // Second create should return an error. - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList2, []*accesslist.AccessListMember{accessListMember2}) - require.True(t, trace.IsAccessDenied(err), "expected access denied / license limit error, got %v", err) - require.ErrorContains(t, err, "reached its limit") - - // Double check only be one access list exists. - out, err := service.GetAccessLists(ctx) - require.NoError(t, err) - require.Len(t, out, 1) - require.Equal(t, "accessList1", out[0].Metadata.Name) - - // Double check only one member exists. - members, _, err := service.ListAccessListMembers(ctx, accessList1.GetName(), 0 /* default size*/, "") - require.NoError(t, err) - require.Len(t, members, 1) - require.Equal(t, "alice", members[0].Metadata.Name) - - // Updating existing access list should be allowed. - accessList1.Spec.Description = "changing description" - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList1, []*accesslist.AccessListMember{accessListMember1}) - require.NoError(t, err) - - // Delete the one access list. - err = service.DeleteAccessList(ctx, "accessList1") - require.NoError(t, err) - - // Create the same list again. - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList1, []*accesslist.AccessListMember{accessListMember1}) - require.NoError(t, err) -} - -// TestAccessListCreate_UpsertAccessListWithMembers_WithoutLimit tests creating access list -// with members is unlimited if IGS feature is enabled. -func TestAccessListCreate_UpsertAccessListWithMembers_WithoutLimit(t *testing.T) { - ctx := context.Background() - clock := clockwork.NewFakeClock() - - mem, err := memory.New(memory.Config{ - Context: ctx, - Clock: clock, - }) - require.NoError(t, err) - - service := newAccessListService(t, mem, clock, true /* igsEnabled */) - - accessList1 := newAccessList(t, "accessList1", clock) - accessList2 := newAccessList(t, "accessList2", clock) - accessList3 := newAccessList(t, "accessList3", clock) - - accessListMember1 := newAccessListMember(t, accessList1.GetName(), "alice") - accessListMember2 := newAccessListMember(t, accessList1.GetName(), "bob") - - // No limit to creating access list. - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList1, []*accesslist.AccessListMember{accessListMember1}) - require.NoError(t, err) - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList2, []*accesslist.AccessListMember{accessListMember2}) - require.NoError(t, err) - _, _, err = service.UpsertAccessListWithMembers(ctx, accessList3, []*accesslist.AccessListMember{}) - require.NoError(t, err) - - // Fetch all access lists. - out, err := service.GetAccessLists(ctx) - require.NoError(t, err) - require.Len(t, out, 3) -} - func TestAccessListDedupeOwnersBackwardsCompat(t *testing.T) { ctx := context.Background() clock := clockwork.NewFakeClock() @@ -1167,9 +1208,9 @@ func newAccessListService(t *testing.T, mem *memory.Memory, clock clockwork.Cloc modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - IdentityGovernanceSecurity: igsEnabled, - AccessList: modules.AccessListFeature{ - CreateLimit: 1, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Identity: {Enabled: igsEnabled}, + entitlements.AccessLists: {Enabled: true, Limit: 1}, }, }, }) diff --git a/lib/services/local/notifications.go b/lib/services/local/notifications.go index 3fe337ac53241..c1fec623b9844 100644 --- a/lib/services/local/notifications.go +++ b/lib/services/local/notifications.go @@ -229,15 +229,20 @@ func (s *NotificationsService) CreateGlobalNotification(ctx context.Context, glo if err != nil { return nil, trace.Wrap(err) } - globalNotification.Metadata = &headerv1.Metadata{Name: uuid.String()} - globalNotification.Spec.Notification.Metadata.Name = uuid.String() if err := CheckAndSetExpiry(globalNotification.Spec.Notification, s.clock); err != nil { return nil, trace.Wrap(err) } - globalNotification.Spec.Notification.Spec.Created = timestamppb.New(s.clock.Now()) + globalNotification.Metadata = &headerv1.Metadata{ + Name: uuid.String(), + // Set the same expiry on the outer GlobalNotification wrapper's metadata. This is necessary for the sqlite cleanup routine + // to be able to delete this notification when it expires. + Expires: globalNotification.GetSpec().GetNotification().GetMetadata().Expires, + } + globalNotification.Spec.Notification.Spec.Created = timestamppb.New(s.clock.Now()) + globalNotification.Spec.Notification.Metadata.Name = uuid.String() globalNotification.Spec.Notification.Metadata.Labels[types.NotificationScope] = "global" created, err := s.globalNotificationService.CreateResource(ctx, globalNotification) diff --git a/lib/services/local/notifications_test.go b/lib/services/local/notifications_test.go index 2755540f8fe36..c5934b772b324 100644 --- a/lib/services/local/notifications_test.go +++ b/lib/services/local/notifications_test.go @@ -160,6 +160,9 @@ func TestGlobalNotificationCRUD(t *testing.T) { _, err = service.CreateGlobalNotification(ctx, globalNotificationLateExpiry) require.True(t, trace.IsBadParameter(err), "got error %T, expected a bad parameter error due to notification-late-expiry having an expiry date more than 90 days later", err) + // Verify that the Metada.Expires on the global notification wrapper is the same as in the inner notification. + require.Equal(t, notification.Metadata.Expires, notification.Spec.Notification.Metadata.Expires) + // Test deleting a notification. err = service.DeleteGlobalNotification(ctx, globalNotification1Id) require.NoError(t, err) diff --git a/lib/services/local/users.go b/lib/services/local/users.go index 8bf7a74b62b68..505e1abdb2034 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -1246,6 +1246,9 @@ func (s *IdentityService) GetMFADevices(ctx context.Context, user string, withSe // UpsertOIDCConnector upserts OIDC Connector func (s *IdentityService) UpsertOIDCConnector(ctx context.Context, connector types.OIDCConnector) (types.OIDCConnector, error) { + if err := connector.Validate(); err != nil { + return nil, trace.Wrap(err) + } rev := connector.GetRevision() value, err := services.MarshalOIDCConnector(connector) if err != nil { @@ -1267,6 +1270,9 @@ func (s *IdentityService) UpsertOIDCConnector(ctx context.Context, connector typ // CreateOIDCConnector creates a new OIDC connector. func (s *IdentityService) CreateOIDCConnector(ctx context.Context, connector types.OIDCConnector) (types.OIDCConnector, error) { + if err := connector.Validate(); err != nil { + return nil, trace.Wrap(err) + } value, err := services.MarshalOIDCConnector(connector) if err != nil { return nil, trace.Wrap(err) @@ -1286,6 +1292,9 @@ func (s *IdentityService) CreateOIDCConnector(ctx context.Context, connector typ // UpdateOIDCConnector updates an existing OIDC connector. func (s *IdentityService) UpdateOIDCConnector(ctx context.Context, connector types.OIDCConnector) (types.OIDCConnector, error) { + if err := connector.Validate(); err != nil { + return nil, trace.Wrap(err) + } value, err := services.MarshalOIDCConnector(connector) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/presence.go b/lib/services/presence.go index e9b9f8c3d06c3..1b7528ebdf425 100644 --- a/lib/services/presence.go +++ b/lib/services/presence.go @@ -20,6 +20,7 @@ package services import ( "context" + "time" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/internalutils/stream" @@ -203,4 +204,7 @@ type Presence interface { type PresenceInternal interface { Presence InventoryInternal + + UpsertHostUserInteractionTime(ctx context.Context, name string, loginTime time.Time) error + GetHostUserInteractionTime(ctx context.Context, name string) (time.Time, error) } diff --git a/lib/services/resource.go b/lib/services/resource.go index ba02befb56c85..f48b7023d1a57 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -560,6 +560,44 @@ func init() { return githubConnector, nil }) + RegisterResourceMarshaler(types.KindSAMLConnector, func(resource types.Resource, opts ...MarshalOption) ([]byte, error) { + samlConnector, ok := resource.(types.SAMLConnector) + if !ok { + return nil, trace.BadParameter("expected SAMLConnector, got %T", resource) + } + bytes, err := MarshalSAMLConnector(samlConnector, opts...) + if err != nil { + return nil, trace.Wrap(err) + } + return bytes, nil + }) + RegisterResourceUnmarshaler(types.KindSAMLConnector, func(bytes []byte, opts ...MarshalOption) (types.Resource, error) { + samlConnector, err := UnmarshalSAMLConnector(bytes, opts...) + if err != nil { + return nil, trace.Wrap(err) + } + return samlConnector, nil + }) + + RegisterResourceMarshaler(types.KindOIDCConnector, func(resource types.Resource, opts ...MarshalOption) ([]byte, error) { + oidConnector, ok := resource.(types.OIDCConnector) + if !ok { + return nil, trace.BadParameter("expected OIDCConnector, got %T", resource) + } + bytes, err := MarshalOIDCConnector(oidConnector, opts...) + if err != nil { + return nil, trace.Wrap(err) + } + return bytes, nil + }) + RegisterResourceUnmarshaler(types.KindOIDCConnector, func(bytes []byte, opts ...MarshalOption) (types.Resource, error) { + oidcConnector, err := UnmarshalOIDCConnector(bytes, opts...) + if err != nil { + return nil, trace.Wrap(err) + } + return oidcConnector, nil + }) + RegisterResourceMarshaler(types.KindRole, func(resource types.Resource, opts ...MarshalOption) ([]byte, error) { role, ok := resource.(types.Role) if !ok { diff --git a/lib/services/role.go b/lib/services/role.go index 8c760d56e98e6..21589e2b41cc3 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -2421,7 +2421,7 @@ func NewKubernetesResourceMatcher(resource types.KubernetesResource) *Kubernetes // Match matches a Kubernetes Resource against provided role and condition. func (m *KubernetesResourceMatcher) Match(role types.Role, condition types.RoleConditionType) (bool, error) { - result, err := utils.KubeResourceMatchesRegex(m.resource, role.GetKubeResources(condition)) + result, err := utils.KubeResourceMatchesRegex(m.resource, role.GetKubeResources(condition), condition) return result, trace.Wrap(err) } diff --git a/lib/services/services.go b/lib/services/services.go index c3719e5eecc4d..9a566fc8f9450 100644 --- a/lib/services/services.go +++ b/lib/services/services.go @@ -19,46 +19,8 @@ package services import ( - "github.com/gravitational/teleport/api/client/secreport" "github.com/gravitational/teleport/api/types" ) -// Services collects all services -type Services interface { - UsersService - Provisioner - Trust - types.Events - ClusterConfiguration - Access - DynamicAccessCore - Presence - Restrictions - Apps - Databases - DatabaseServices - Kubernetes - AppSession - SnowflakeSession - SAMLIdPSession - types.WebSessionsGetter - types.WebTokensGetter - WindowsDesktops - SAMLIdPServiceProviders - UserGroups - Integrations - KubeWaitingContainer - Notifications - - OktaClient() Okta - AccessListClient() AccessLists - AccessMonitoringRuleClient() AccessMonitoringRules - UserLoginStateClient() UserLoginStates - DiscoveryConfigClient() DiscoveryConfigs - SecReportsClient() *secreport.Client - CrownJewelClient() CrownJewels - DatabaseObjectsClient() DatabaseObjects -} - // RotationGetter returns the rotation state. type RotationGetter func(role types.SystemRole) (*types.Rotation, error) diff --git a/lib/srv/alpnproxy/local_proxy_test.go b/lib/srv/alpnproxy/local_proxy_test.go index 1a7321457d112..f7940ef22c069 100644 --- a/lib/srv/alpnproxy/local_proxy_test.go +++ b/lib/srv/alpnproxy/local_proxy_test.go @@ -533,12 +533,18 @@ func TestKubeMiddleware(t *testing.T) { err := km.CheckAndSetDefaults() require.NoError(t, err) - rw := responsewriters.NewMemoryResponseWriter() - // HandleRequest will reissue certificate if needed. - km.HandleRequest(rw, req) - - // request timed out. - require.Equal(t, http.StatusInternalServerError, rw.Status()) + var rw *responsewriters.MemoryResponseWriter + // We use `require.Eventually` to avoid a very rare test flakiness case when reissue goroutine manages to + // successfully finish before the parent goroutine has a chance to check the context (and see that it's expired). + require.Eventually(t, func() bool { + rw = responsewriters.NewMemoryResponseWriter() + // HandleRequest will reissue certificate if needed. + km.HandleRequest(rw, req) + + // request timed out. + return rw.Status() == http.StatusInternalServerError + + }, 5*time.Second, 100*time.Millisecond) require.Contains(t, rw.Buffer().String(), "context canceled") // just let the reissuing goroutine some time to replace certs. diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index 4a2ba8a53dca0..c3a62d899cd6f 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -54,6 +54,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/native" @@ -1076,7 +1077,9 @@ func TestMongoDBMaxMessageSize(t *testing.T) { func TestAccessDisabled(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - DB: false, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.DB: {Enabled: false}, + }, }, }) diff --git a/lib/srv/db/common/databaseobject/databaseobject_test.go b/lib/srv/db/common/databaseobject/databaseobject_test.go index 60c250f630461..a622de56b991e 100644 --- a/lib/srv/db/common/databaseobject/databaseobject_test.go +++ b/lib/srv/db/common/databaseobject/databaseobject_test.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package databaseobject diff --git a/lib/srv/db/common/databaseobjectimportrule/create.go b/lib/srv/db/common/databaseobjectimportrule/create.go index 5dfb56595c671..5f2bff26fe545 100644 --- a/lib/srv/db/common/databaseobjectimportrule/create.go +++ b/lib/srv/db/common/databaseobjectimportrule/create.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package databaseobjectimportrule diff --git a/lib/srv/db/common/databaseobjectimportrule/create_test.go b/lib/srv/db/common/databaseobjectimportrule/create_test.go index 8253fbb7a0c4c..e3bb591eb011d 100644 --- a/lib/srv/db/common/databaseobjectimportrule/create_test.go +++ b/lib/srv/db/common/databaseobjectimportrule/create_test.go @@ -1,16 +1,18 @@ -// Copyright 2024 Gravitational, Inc. +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package databaseobjectimportrule diff --git a/lib/srv/db/postgres/schema.go b/lib/srv/db/postgres/schema.go index 4712d764f923a..00ba7fd23292e 100644 --- a/lib/srv/db/postgres/schema.go +++ b/lib/srv/db/postgres/schema.go @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package postgres diff --git a/lib/srv/desktop/rdp/rdpclient/src/client.rs b/lib/srv/desktop/rdp/rdpclient/src/client.rs index d2b62a3978bb3..70dce95aa1e88 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/client.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/client.rs @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . pub mod global; diff --git a/lib/srv/desktop/rdp/rdpclient/src/client/global.rs b/lib/srv/desktop/rdp/rdpclient/src/client/global.rs index 380e53e5c1767..65051237d7670 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/client/global.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/client/global.rs @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . //! This module contains static structures which are used in common by all //! desktop sessions on a given windows_desktop_service. @@ -27,8 +29,8 @@ //! managed by Go). //! //! In practice this primarily means ensuring that any such global, static -//! structures that might be accessed directly by a call from go are [`Send`] -//! + [`Sync`] and thus are only mutated when locked. See [`assert_send_sync`] +//! structures that might be accessed directly by a call from go are `Send + Sync` +//! and thus are only mutated when locked. See `assert_send_sync` //! below for an example of how this is enforced. use super::ClientHandle; diff --git a/lib/srv/desktop/rdp/rdpclient/src/lib.rs b/lib/srv/desktop/rdp/rdpclient/src/lib.rs index 845e3355813e4..08f79ee9f13ad 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/lib.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/lib.rs @@ -486,19 +486,6 @@ pub enum CGODisconnectCode { DisconnectCodeServer = 2, } -#[repr(C)] -pub struct CGOReadRdpOutputReturns { - user_message: *const c_char, - disconnect_code: CGODisconnectCode, - err_code: CGOErrCode, -} - -#[repr(C)] -pub struct CGOClientOrError { - client: u64, - err: CGOErrCode, -} - /// CGOMousePointerEvent is a CGO-compatible version of PointerEvent that we pass back to Go. /// PointerEvent is a mouse move or click update from the user. #[repr(C)] diff --git a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/filesystem.rs b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/filesystem.rs index 5a1bc3e09b393..5210a704252e3 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/filesystem.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/filesystem.rs @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . use super::{ path::UnixPath, diff --git a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs index e146dbe2fcb0e..4cc1f32dec8f3 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/rdpdr/tdp.rs @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . use super::{filesystem::FileCacheObject, path::UnixPath}; use crate::{ diff --git a/lib/srv/desktop/rdp/rdpclient/src/ssl.rs b/lib/srv/desktop/rdp/rdpclient/src/ssl.rs index 55fd39c6fabe8..76db641a525f5 100644 --- a/lib/srv/desktop/rdp/rdpclient/src/ssl.rs +++ b/lib/srv/desktop/rdp/rdpclient/src/ssl.rs @@ -1,20 +1,18 @@ -/* - * - * Copyright 2021 Gravitational, Inc. - * - * 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. - * / - */ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . use crate::client::{ClientError, ClientResult}; #[cfg(feature = "fips")] diff --git a/lib/srv/discovery/access_graph.go b/lib/srv/discovery/access_graph.go index c92468a4e616c..3eec9262a16d1 100644 --- a/lib/srv/discovery/access_graph.go +++ b/lib/srv/discovery/access_graph.go @@ -34,7 +34,9 @@ import ( "github.com/gravitational/teleport/api/metadata" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/retryutils" + "github.com/gravitational/teleport/entitlements" accessgraphv1alpha "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha" + "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" aws_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/aws-sync" ) @@ -249,7 +251,8 @@ func (s *Server) initializeAndWatchAccessGraph(ctx context.Context, reloadCh <-c ) clusterFeatures := s.Config.ClusterFeatures() - if !clusterFeatures.AccessGraph && (clusterFeatures.Policy == nil || !clusterFeatures.Policy.Enabled) { + policy := modules.GetProtoEntitlement(&clusterFeatures, entitlements.Policy) + if !clusterFeatures.AccessGraph && !policy.Enabled { return trace.Wrap(errTAGFeatureNotEnabled) } diff --git a/lib/srv/discovery/config_test.go b/lib/srv/discovery/config_test.go index 2801e8c1f1736..9e96d5f087c4f 100644 --- a/lib/srv/discovery/config_test.go +++ b/lib/srv/discovery/config_test.go @@ -1,18 +1,18 @@ -/* -Copyright 2024 Gravitational, Inc. - -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. -*/ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package discovery diff --git a/lib/srv/discovery/database_watcher.go b/lib/srv/discovery/database_watcher.go index c49b32f4eaeb5..c3ab1abb437bf 100644 --- a/lib/srv/discovery/database_watcher.go +++ b/lib/srv/discovery/database_watcher.go @@ -138,16 +138,17 @@ func (s *Server) getCurrentDatabases() map[string]types.Database { func (s *Server) onDatabaseCreate(ctx context.Context, database types.Database) error { s.Log.Debugf("Creating database %s.", database.GetName()) err := s.AccessPoint.CreateDatabase(ctx, database) - // If the database already exists but has an empty discovery group, update it. - if trace.IsAlreadyExists(err) && s.updatesEmptyDiscoveryGroup( - func() (types.ResourceWithLabels, error) { + // If the database already exists but has cloud origin and an empty + // discovery group, then update it. + if err != nil { + err := s.resolveCreateErr(err, types.OriginCloud, func() (types.ResourceWithLabels, error) { return s.AccessPoint.GetDatabase(ctx, database.GetName()) - }) { + }) + if err != nil { + return trace.Wrap(err) + } return trace.Wrap(s.onDatabaseUpdate(ctx, database, nil)) } - if err != nil { - return trace.Wrap(err) - } err = s.emitUsageEvents(map[string]*usageeventsv1.ResourceCreateEvent{ databaseEventPrefix + database.GetName(): { ResourceType: types.DiscoveredResourceDatabase, diff --git a/lib/srv/discovery/discovery.go b/lib/srv/discovery/discovery.go index dcf4da61cee47..9f9d4c0d33481 100644 --- a/lib/srv/discovery/discovery.go +++ b/lib/srv/discovery/discovery.go @@ -1686,14 +1686,42 @@ func splitMatchers[T types.Matcher](matchers []T, matcherTypeCheck func(string) return } -func (s *Server) updatesEmptyDiscoveryGroup(getter func() (types.ResourceWithLabels, error)) bool { - if s.DiscoveryGroup == "" { - return false +func (s *Server) resolveCreateErr(createErr error, discoveryOrigin string, getter func() (types.ResourceWithLabels, error)) error { + // We can only resolve the error if we have a discovery group configured + // and the error is that the resource already exists. + if s.DiscoveryGroup == "" || !trace.IsAlreadyExists(createErr) { + return trace.Wrap(createErr) } + old, err := getter() if err != nil { - return false + return trace.NewAggregate(createErr, err) + } + + // Check that the registered resource origin matches the origin we want. + oldOrigin, err := types.GetOrigin(old) + if err != nil { + return trace.NewAggregate(createErr, err) + } + if oldOrigin != discoveryOrigin { + return trace.Wrap(createErr, + "not updating because the resource origin indicates that it is not managed by auto-discovery", + ) } + + // Check that the registered resource's discovery group is blank or matches + // this server's discovery group. + // We check if the old group is empty because that's a special case where + // the old/new groups don't match but we still want to update the resource. + // In this way, discovery agents with a discovery_group essentially claim + // the resources they discover that used to be (or currently are) discovered + // by an agent that did not have a discovery_group configured. oldDiscoveryGroup, _ := old.GetLabel(types.TeleportInternalDiscoveryGroupName) - return oldDiscoveryGroup == "" + if oldDiscoveryGroup != "" && oldDiscoveryGroup != s.DiscoveryGroup { + return trace.Wrap(createErr, + "not updating because the resource is in a different discovery group", + ) + } + + return nil } diff --git a/lib/srv/discovery/discovery_test.go b/lib/srv/discovery/discovery_test.go index 18c02109becf9..893afc43ae479 100644 --- a/lib/srv/discovery/discovery_test.go +++ b/lib/srv/discovery/discovery_test.go @@ -585,7 +585,7 @@ func TestDiscoveryServer(t *testing.T) { tc.emitter.t = t if tc.discoveryConfig != nil { - _, err := tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, tc.discoveryConfig) + _, err := tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, tc.discoveryConfig) require.NoError(t, err) } @@ -1963,7 +1963,7 @@ func TestDiscoveryDatabase(t *testing.T) { // Add Dynamic Matchers and wait for reconcile again if tc.discoveryConfigs != nil { for _, dc := range tc.discoveryConfigs(t) { - _, err := tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, dc) + _, err := tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, dc) require.NoError(t, err) } @@ -2088,7 +2088,7 @@ func TestDiscoveryDatabaseRemovingDiscoveryConfigs(t *testing.T) { ) require.NoError(t, err) - _, err = tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, dc1) + _, err = tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, dc1) require.NoError(t, err) actualDatabases, err := tlsServer.Auth().GetDatabases(ctx) @@ -2114,7 +2114,7 @@ func TestDiscoveryDatabaseRemovingDiscoveryConfigs(t *testing.T) { require.NoError(t, err) require.Zero(t, reporter.DiscoveryFetchEventCount()) - _, err = tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, dc1) + _, err = tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, dc1) require.NoError(t, err) // Check for new resource in reconciler @@ -2144,7 +2144,7 @@ func TestDiscoveryDatabaseRemovingDiscoveryConfigs(t *testing.T) { t.Run("removing the DiscoveryConfig: fetcher is removed and database is removed", func(t *testing.T) { // Remove DiscoveryConfig - err = tlsServer.Auth().DiscoveryConfigClient().DeleteDiscoveryConfig(ctx, dc1.GetName()) + err = tlsServer.Auth().DiscoveryConfigs.DeleteDiscoveryConfig(ctx, dc1.GetName()) require.NoError(t, err) currentEmittedEvents := reporter.DiscoveryFetchEventCount() @@ -2496,7 +2496,7 @@ func TestAzureVMDiscovery(t *testing.T) { emitter.t = t if tc.discoveryConfig != nil { - _, err := tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, tc.discoveryConfig) + _, err := tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, tc.discoveryConfig) require.NoError(t, err) // Wait for the DiscoveryConfig to be added to the dynamic matchers @@ -2761,7 +2761,7 @@ func TestGCPVMDiscovery(t *testing.T) { emitter.t = t if tc.discoveryConfig != nil { - _, err := tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, tc.discoveryConfig) + _, err := tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, tc.discoveryConfig) require.NoError(t, err) // Wait for the DiscoveryConfig to be added to the dynamic matchers @@ -2793,12 +2793,7 @@ func TestGCPVMDiscovery(t *testing.T) { // TestServer_onCreate tests the update of the discovery_group of a resource // when a resource already exists with the same name but an empty discovery_group. func TestServer_onCreate(t *testing.T) { - _, awsRedshiftDB := makeRedshiftCluster(t, "aws-redshift", "us-east-1", "test") - _, awsRedshiftDBEmptyDiscoveryGroup := makeRedshiftCluster(t, "aws-redshift", "us-east-1", "" /* empty discovery group */) - accessPoint := &fakeAccessPoint{ - kube: mustConvertEKSToKubeCluster(t, eksMockClusters[0], "" /* empty discovery group */), - database: awsRedshiftDBEmptyDiscoveryGroup, - } + accessPoint := &fakeAccessPoint{} s := &Server{ Config: &Config{ DiscoveryGroup: "test-cluster", @@ -2808,31 +2803,106 @@ func TestServer_onCreate(t *testing.T) { } t.Run("onCreate update kube", func(t *testing.T) { + // With cloud origin and an empty discovery group, it should update. + accessPoint.kube = mustConvertEKSToKubeCluster(t, eksMockClusters[0], "" /* empty discovery group */) err := s.onKubeCreate(context.Background(), mustConvertEKSToKubeCluster(t, eksMockClusters[0], "test-cluster")) require.NoError(t, err) - require.True(t, accessPoint.updateKube) + require.True(t, accessPoint.updatedKube) + + // Reset the updated flag and set the registered kube cluster to have + // non-cloud origin. It should not update. + accessPoint.updatedKube = false + accessPoint.kube.SetOrigin(types.OriginDynamic) + err = s.onKubeCreate(context.Background(), mustConvertEKSToKubeCluster(t, eksMockClusters[0], "test-cluster")) + require.Error(t, err) + require.False(t, accessPoint.updatedKube) - // Reset the update flag. - accessPoint.updateKube = false + // Reset the updated flag and set the registered kube cluster to have + // an empty origin. It should not update. + accessPoint.updatedKube = false + accessPoint.kube.SetOrigin("") + err = s.onKubeCreate(context.Background(), mustConvertEKSToKubeCluster(t, eksMockClusters[0], "test-cluster")) + require.Error(t, err) + require.False(t, accessPoint.updatedKube) + + // Reset the update flag and set the registered kube cluster to have + // a non-empty discovery group. It should not update. + accessPoint.updatedKube = false accessPoint.kube = mustConvertEKSToKubeCluster(t, eksMockClusters[0], "nonEmpty") - // Update the kube cluster with non-empty discovery group. err = s.onKubeCreate(context.Background(), mustConvertEKSToKubeCluster(t, eksMockClusters[0], "test-cluster")) require.Error(t, err) - require.False(t, accessPoint.updateKube) + require.False(t, accessPoint.updatedKube) }) t.Run("onCreate update database", func(t *testing.T) { + _, awsRedshiftDB := makeRedshiftCluster(t, "aws-redshift", "us-east-1", "test") + _, awsRedshiftDBEmptyDiscoveryGroup := makeRedshiftCluster(t, "aws-redshift", "us-east-1", "" /* empty discovery group */) + + // With cloud origin and an empty discovery group, it should update. + accessPoint.database = awsRedshiftDBEmptyDiscoveryGroup err := s.onDatabaseCreate(context.Background(), awsRedshiftDB) require.NoError(t, err) - require.True(t, accessPoint.updateDatabase) + require.True(t, accessPoint.updatedDatabase) - // Reset the update flag. - accessPoint.updateDatabase = false + // Reset the updated flag and set the db to empty discovery group + // but non-cloud origin. It should not update. + accessPoint.updatedDatabase = false + accessPoint.database.SetOrigin(types.OriginDynamic) + err = s.onDatabaseCreate(context.Background(), awsRedshiftDB) + require.Error(t, err) + require.False(t, accessPoint.updatedDatabase) + + // Reset the updated flag and set the db to empty discovery group + // but empty origin. It should not update. + accessPoint.updatedDatabase = false + accessPoint.database.SetOrigin("") + err = s.onDatabaseCreate(context.Background(), awsRedshiftDB) + require.Error(t, err) + require.False(t, accessPoint.updatedDatabase) + + // Reset the updated flag and set the registered db to have a non-empty + // discovery group. It should not update. + accessPoint.updatedDatabase = false accessPoint.database = awsRedshiftDB - // Update the db with non-empty discovery group. err = s.onDatabaseCreate(context.Background(), awsRedshiftDB) require.Error(t, err) - require.False(t, accessPoint.updateDatabase) + require.False(t, accessPoint.updatedDatabase) + }) + + t.Run("onCreate update app", func(t *testing.T) { + kubeSvc := newMockKubeService("service1", "ns1", "", + map[string]string{"test-label": "testval"}, nil, + []corev1.ServicePort{{Port: 42, Name: "http", Protocol: corev1.ProtocolTCP}}) + + // With kube origin and empty discovery group, it should update. + accessPoint.app = mustConvertKubeServiceToApp(t, "" /*empty discovery group*/, "http", kubeSvc, kubeSvc.Spec.Ports[0]) + err := s.onAppCreate(context.Background(), mustConvertKubeServiceToApp(t, "notEmpty", "http", kubeSvc, kubeSvc.Spec.Ports[0])) + require.NoError(t, err) + require.True(t, accessPoint.updatedApp) + + // Reset the updated flag and set the app to empty discovery group + // but non-cloud origin. It should not update. + accessPoint.updatedApp = false + accessPoint.app.SetOrigin(types.OriginDynamic) + err = s.onAppCreate(context.Background(), mustConvertKubeServiceToApp(t, "notEmpty", "http", kubeSvc, kubeSvc.Spec.Ports[0])) + require.Error(t, err) + require.False(t, accessPoint.updatedApp) + + // Reset the updated flag and set the app to empty discovery group + // but non-cloud origin. It should not update. + accessPoint.updatedApp = false + accessPoint.app.SetOrigin("") + err = s.onAppCreate(context.Background(), mustConvertKubeServiceToApp(t, "notEmpty", "http", kubeSvc, kubeSvc.Spec.Ports[0])) + require.Error(t, err) + require.False(t, accessPoint.updatedApp) + + // Reset the updated flag and set the app to non-empty discovery group. + // It should not update. + accessPoint.updatedApp = false + accessPoint.app = mustConvertKubeServiceToApp(t, "nonEmpty", "http", kubeSvc, kubeSvc.Spec.Ports[0]) + err = s.onAppCreate(context.Background(), mustConvertKubeServiceToApp(t, "notEmpty", "http", kubeSvc, kubeSvc.Spec.Ports[0])) + require.Error(t, err) + require.False(t, accessPoint.updatedApp) }) } @@ -2931,10 +3001,12 @@ type fakeAccessPoint struct { ping func(context.Context) (proto.PingResponse, error) enrollEKSClusters func(context.Context, *integrationpb.EnrollEKSClustersRequest, ...grpc.CallOption) (*integrationpb.EnrollEKSClustersResponse, error) - updateKube bool - updateDatabase bool + updatedKube bool + updatedDatabase bool + updatedApp bool kube types.KubeCluster database types.Database + app types.Application upsertedServerInfos chan types.ServerInfo reports map[string][]discoveryconfig.Status } @@ -2981,7 +3053,7 @@ func (f *fakeAccessPoint) CreateDatabase(ctx context.Context, database types.Dat } func (f *fakeAccessPoint) UpdateDatabase(ctx context.Context, database types.Database) error { - f.updateDatabase = true + f.updatedDatabase = true return nil } @@ -2991,7 +3063,20 @@ func (f *fakeAccessPoint) CreateKubernetesCluster(ctx context.Context, cluster t // UpdateKubernetesCluster updates existing kubernetes cluster resource. func (f *fakeAccessPoint) UpdateKubernetesCluster(ctx context.Context, cluster types.KubeCluster) error { - f.updateKube = true + f.updatedKube = true + return nil +} + +func (f *fakeAccessPoint) GetApp(ctx context.Context, name string) (types.Application, error) { + return f.app, nil +} + +func (f *fakeAccessPoint) CreateApp(ctx context.Context, _ types.Application) error { + return trace.AlreadyExists("already exists") +} + +func (f *fakeAccessPoint) UpdateApp(ctx context.Context, _ types.Application) error { + f.updatedApp = true return nil } diff --git a/lib/srv/discovery/fetchers/eks.go b/lib/srv/discovery/fetchers/eks.go index 01e6812988693..1dc89d2baeb34 100644 --- a/lib/srv/discovery/fetchers/eks.go +++ b/lib/srv/discovery/fetchers/eks.go @@ -563,6 +563,9 @@ func (a *eksFetcher) upsertRoleAndBinding(ctx context.Context, cluster *eks.Clus } func (a *eksFetcher) createKubeClient(cluster *eks.Cluster) (*kubernetes.Clientset, error) { + if a.stsClient == nil { + return nil, trace.BadParameter("STS client is not set") + } token, _, err := kubeutils.GenAWSEKSToken(a.stsClient, aws.StringValue(cluster.Name), a.Clock) if err != nil { return nil, trace.Wrap(err, "unable to generate EKS token for cluster %q", aws.StringValue(cluster.Name)) @@ -666,10 +669,6 @@ func (a *eksFetcher) upsertAccessEntry(ctx context.Context, client eksiface.EKSA } func (a *eksFetcher) setCallerIdentity(ctx context.Context) error { - if a.AssumeRole.RoleARN != "" { - a.callerIdentity = a.AssumeRole.RoleARN - return nil - } var err error a.stsClient, err = a.ClientGetter.GetAWSSTSClient( ctx, @@ -679,6 +678,11 @@ func (a *eksFetcher) setCallerIdentity(ctx context.Context) error { if err != nil { return trace.Wrap(err) } + + if a.AssumeRole.RoleARN != "" { + a.callerIdentity = a.AssumeRole.RoleARN + return nil + } identity, err := a.stsClient.GetCallerIdentityWithContext(ctx, &sts.GetCallerIdentityInput{}) if err != nil { return trace.Wrap(err) diff --git a/lib/srv/discovery/kube_integration_watcher_test.go b/lib/srv/discovery/kube_integration_watcher_test.go index 738ad09c067a4..5075da163d392 100644 --- a/lib/srv/discovery/kube_integration_watcher_test.go +++ b/lib/srv/discovery/kube_integration_watcher_test.go @@ -458,7 +458,7 @@ func TestDiscoveryKubeIntegrationEKS(t *testing.T) { if tc.discoveryConfig != nil { dc := tc.discoveryConfig(t) - _, err := tlsServer.Auth().DiscoveryConfigClient().CreateDiscoveryConfig(ctx, dc) + _, err := tlsServer.Auth().DiscoveryConfigs.CreateDiscoveryConfig(ctx, dc) require.NoError(t, err) // Wait for the DiscoveryConfig to be added to the dynamic fetchers diff --git a/lib/srv/discovery/kube_services_watcher.go b/lib/srv/discovery/kube_services_watcher.go index 88b978f283cff..eb6d68cc964f7 100644 --- a/lib/srv/discovery/kube_services_watcher.go +++ b/lib/srv/discovery/kube_services_watcher.go @@ -122,11 +122,14 @@ func (s *Server) onAppCreate(ctx context.Context, app types.Application) error { // In this case, we need to update the resource with the // discovery group label to ensure the user doesn't have to manually delete // the resource. - if trace.IsAlreadyExists(err) { - return trace.Wrap(s.onAppUpdate(ctx, app, nil)) - } if err != nil { - return trace.Wrap(err) + err := s.resolveCreateErr(err, types.OriginDiscoveryKubernetes, func() (types.ResourceWithLabels, error) { + return s.AccessPoint.GetApp(ctx, app.GetName()) + }) + if err != nil { + return trace.Wrap(err) + } + return trace.Wrap(s.onAppUpdate(ctx, app, nil)) } err = s.emitUsageEvents(map[string]*usageeventsv1.ResourceCreateEvent{ appEventPrefix + app.GetName(): { diff --git a/lib/srv/discovery/kube_watcher.go b/lib/srv/discovery/kube_watcher.go index 58c61475c8f32..e18cc23e68c99 100644 --- a/lib/srv/discovery/kube_watcher.go +++ b/lib/srv/discovery/kube_watcher.go @@ -121,15 +121,15 @@ func (s *Server) onKubeCreate(ctx context.Context, kubeCluster types.KubeCluster s.Log.Debugf("Creating kube_cluster %s.", kubeCluster.GetName()) err := s.AccessPoint.CreateKubernetesCluster(ctx, kubeCluster) // If the kube already exists but has an empty discovery group, update it. - if trace.IsAlreadyExists(err) && s.updatesEmptyDiscoveryGroup( - func() (types.ResourceWithLabels, error) { + if err != nil { + err := s.resolveCreateErr(err, types.OriginCloud, func() (types.ResourceWithLabels, error) { return s.AccessPoint.GetKubernetesCluster(ctx, kubeCluster.GetName()) - }) { + }) + if err != nil { + return trace.Wrap(err) + } return trace.Wrap(s.onKubeUpdate(ctx, kubeCluster, nil)) } - if err != nil { - return trace.Wrap(err) - } err = s.emitUsageEvents(map[string]*usageeventsv1.ResourceCreateEvent{ kubeEventPrefix + kubeCluster.GetName(): { ResourceType: types.DiscoveredResourceKubernetes, diff --git a/lib/srv/heartbeatv2.go b/lib/srv/heartbeatv2.go index b5b59ae516bed..d59b573a612d9 100644 --- a/lib/srv/heartbeatv2.go +++ b/lib/srv/heartbeatv2.go @@ -60,6 +60,9 @@ type HeartbeatV2Config[T any] struct { OnHeartbeat func(error) // AnnounceInterval is the interval at which heartbeats are attempted (optional). AnnounceInterval time.Duration + // DisruptionAnnounceInterval is the interval at which heartbeats are attempted when + // if there was a disuption in the control stream since the last heartbeat (optional). + DisruptionAnnounceInterval time.Duration // PollInterval is the interval at which checks for change are performed (optional). PollInterval time.Duration } @@ -100,9 +103,10 @@ func NewSSHServerHeartbeat(cfg HeartbeatV2Config[*types.ServerV2]) (*HeartbeatV2 } return newHeartbeatV2(cfg.InventoryHandle, inner, heartbeatV2Config{ - onHeartbeatInner: cfg.OnHeartbeat, - announceInterval: cfg.AnnounceInterval, - pollInterval: cfg.PollInterval, + onHeartbeatInner: cfg.OnHeartbeat, + announceInterval: cfg.AnnounceInterval, + disruptionAnnounceInterval: cfg.DisruptionAnnounceInterval, + pollInterval: cfg.PollInterval, }), nil } @@ -119,9 +123,10 @@ func NewAppServerHeartbeat(cfg HeartbeatV2Config[*types.AppServerV3]) (*Heartbea } return newHeartbeatV2(cfg.InventoryHandle, inner, heartbeatV2Config{ - onHeartbeatInner: cfg.OnHeartbeat, - announceInterval: cfg.AnnounceInterval, - pollInterval: cfg.PollInterval, + onHeartbeatInner: cfg.OnHeartbeat, + announceInterval: cfg.AnnounceInterval, + disruptionAnnounceInterval: cfg.DisruptionAnnounceInterval, + pollInterval: cfg.PollInterval, }), nil } @@ -209,9 +214,10 @@ type HeartbeatV2 struct { } type heartbeatV2Config struct { - announceInterval time.Duration - pollInterval time.Duration - onHeartbeatInner func(error) + announceInterval time.Duration + disruptionAnnounceInterval time.Duration + pollInterval time.Duration + onHeartbeatInner func(error) // -- below values only used in tests @@ -227,6 +233,11 @@ func (c *heartbeatV2Config) SetDefaults() { // from the average of ~5m30s that was used for V1 ssh server heartbeats. c.announceInterval = 2 * (apidefaults.ServerAnnounceTTL / 3) } + if c.disruptionAnnounceInterval == 0 { + // if there was a disruption in the control stream, we want to heartbeat a bit + // sooner in case the disruption affected the most recent announce's success. + c.disruptionAnnounceInterval = 2 * (c.announceInterval / 3) + } if c.pollInterval == 0 { c.pollInterval = defaults.HeartbeatCheckPeriod } @@ -357,6 +368,21 @@ func (h *HeartbeatV2) runWithSender(sender inventory.DownstreamSender) { h.shouldAnnounce = true } + // in the event of disruption, we want to heartbeat a bit sooner than the normal. + // this helps prevent node heartbeats from getting too stale when auth servers fail + // in a manner that isn't immediately detected by the agent (e.g. deadlock, + // i/o timeout, etc). Since we're heartbeating over a channel, such failure modes + // can sometimes mean that the last announce failed "silently" from our perspective. + if t, ok := h.announce.LastTick(); ok { + elapsed := time.Since(t) + dai := utils.SeventhJitter(h.disruptionAnnounceInterval) + if elapsed >= dai { + h.shouldAnnounce = true + } else { + h.announce.ResetTo(dai - elapsed) + } + } + for { if h.shouldAnnounce { if ok := h.inner.Announce(h.closeContext, sender); ok { diff --git a/lib/srv/regular/sshserver.go b/lib/srv/regular/sshserver.go index 9975612c12c3d..aa7c3c3745c5e 100644 --- a/lib/srv/regular/sshserver.go +++ b/lib/srv/regular/sshserver.go @@ -66,7 +66,6 @@ import ( authorizedkeysreporter "github.com/gravitational/teleport/lib/secretsscanner/authorizedkeys" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/srv/ingress" "github.com/gravitational/teleport/lib/sshutils" @@ -211,7 +210,7 @@ type Server struct { // creation createHostUser bool - storage *local.PresenceService + storage services.PresenceInternal // users is used to start the automatic user deletion loop users srv.HostUsers @@ -616,7 +615,7 @@ func SetCreateHostUser(createUser bool) ServerOption { } // SetStoragePresenceService configures host user creation on a server -func SetStoragePresenceService(service *local.PresenceService) ServerOption { +func SetStoragePresenceService(service services.PresenceInternal) ServerOption { return func(s *Server) error { s.storage = service return nil diff --git a/lib/srv/regular/sshserver_test.go b/lib/srv/regular/sshserver_test.go index 9a402fc9af256..624b1eac89fe9 100644 --- a/lib/srv/regular/sshserver_test.go +++ b/lib/srv/regular/sshserver_test.go @@ -126,7 +126,7 @@ func newFixture(t *testing.T) *sshTestFixture { return newCustomFixture(t, func(*auth.TestServerConfig) {}) } -func newFixtureWithoutDiskBasedLogging(t *testing.T, sshOpts ...ServerOption) *sshTestFixture { +func newFixtureWithoutDiskBasedLogging(t testing.TB, sshOpts ...ServerOption) *sshTestFixture { t.Helper() f := newCustomFixture(t, func(cfg *auth.TestServerConfig) { @@ -143,7 +143,7 @@ func newFixtureWithoutDiskBasedLogging(t *testing.T, sshOpts ...ServerOption) *s return f } -func (f *sshTestFixture) newSSHClient(ctx context.Context, t *testing.T, user *user.User) *tracessh.Client { +func (f *sshTestFixture) newSSHClient(ctx context.Context, t testing.TB, user *user.User) *tracessh.Client { // set up SSH client using the user private key for signing up, err := newUpack(f.testSrv, user.Username, []string{user.Username}, wildcardAllow) require.NoError(t, err) @@ -172,7 +172,7 @@ func (f *sshTestFixture) newSSHClient(ctx context.Context, t *testing.T, user *u return client } -func newCustomFixture(t *testing.T, mutateCfg func(*auth.TestServerConfig), sshOpts ...ServerOption) *sshTestFixture { +func newCustomFixture(t testing.TB, mutateCfg func(*auth.TestServerConfig), sshOpts ...ServerOption) *sshTestFixture { ctx := context.Background() u, err := user.Current() @@ -236,6 +236,7 @@ func newCustomFixture(t *testing.T, mutateCfg func(*auth.TestServerConfig), sshO SetLockWatcher(lockWatcher), SetX11ForwardingConfig(&x11.ServerConfig{}), SetSessionController(sessionController), + SetStoragePresenceService(testServer.AuthServer.AuthServer.PresenceInternal), } serverOptions = append(serverOptions, sshOpts...) @@ -2878,6 +2879,7 @@ func newUpack(testSvr *auth.TestServer, username string, allowedLogins []string, role.SetRules(types.Allow, rules) opts := role.GetOptions() opts.PermitX11Forwarding = types.NewBool(true) + opts.CreateHostUser = types.NewBoolOption(true) role.SetOptions(opts) role.SetLogins(types.Allow, allowedLogins) role.SetNodeLabels(types.Allow, allowedLabels) @@ -2926,7 +2928,7 @@ func newUpack(testSvr *auth.TestServer, username string, allowedLogins []string, }, nil } -func newLockWatcher(ctx context.Context, t *testing.T, client types.Events) *services.LockWatcher { +func newLockWatcher(ctx context.Context, t testing.TB, client types.Events) *services.LockWatcher { lockWatcher, err := services.NewLockWatcher(ctx, services.LockWatcherConfig{ ResourceWatcherConfig: services.ResourceWatcherConfig{ Component: "test", @@ -2964,7 +2966,7 @@ func newCertAuthorityWatcher(ctx context.Context, t *testing.T, client types.Eve } // newSigner creates a new SSH signer that can be used by the Server. -func newSigner(t *testing.T, ctx context.Context, testServer *auth.TestServer) ssh.Signer { +func newSigner(t testing.TB, ctx context.Context, testServer *auth.TestServer) ssh.Signer { t.Helper() priv, pub, err := testauthority.New().GenerateKeyPair() diff --git a/lib/srv/regular/sshserver_unix_test.go b/lib/srv/regular/sshserver_unix_test.go index 9a1a7dae48009..7b01dc4b4aa5f 100644 --- a/lib/srv/regular/sshserver_unix_test.go +++ b/lib/srv/regular/sshserver_unix_test.go @@ -21,15 +21,22 @@ package regular import ( + "context" "net" "os" + "os/user" + "sync" "syscall" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sys/unix" + tracessh "github.com/gravitational/teleport/api/observability/tracing/ssh" "github.com/gravitational/teleport/lib/srv" + "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/teleport/lib/utils/host" "github.com/gravitational/teleport/lib/utils/uds" ) @@ -128,3 +135,74 @@ func TestValidateListenerSocket(t *testing.T) { }) } } + +// BenchmarkRootExecCommand measures performance of running multiple exec requests +// over a single ssh connection. The same test is run with and without host user +// creation support to catch any performance degradation caused by user provisioning. +func BenchmarkRootExecCommand(b *testing.B) { + utils.RequireRoot(b) + + b.ReportAllocs() + + cases := []struct { + name string + createUser bool + }{ + { + name: "no user creation", + }, + { + name: "with user creation", + createUser: true, + }, + } + + for _, test := range cases { + b.Run(test.name, func(b *testing.B) { + var opts []ServerOption + if test.createUser { + opts = []ServerOption{SetCreateHostUser(true)} + } + + f := newFixtureWithoutDiskBasedLogging(b, opts...) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + username := f.user + if test.createUser { + username = utils.GenerateLocalUsername(b) + b.Cleanup(func() { _, _ = host.UserDel(username) }) + } + + _, err := newUpack(f.testSrv, username, []string{username, f.user}, wildcardAllow) + require.NoError(b, err) + + clt := f.newSSHClient(context.Background(), b, &user.User{Username: username}) + + executeCommand(b, clt, "uptime", 10) + } + }) + } +} + +func executeCommand(tb testing.TB, clt *tracessh.Client, command string, executions int) { + tb.Helper() + + var wg sync.WaitGroup + for i := 0; i < executions; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + ctx := context.Background() + + se, err := clt.NewSession(ctx) + assert.NoError(tb, err) + defer se.Close() + + assert.NoError(tb, se.Run(ctx, command)) + }() + } + + wg.Wait() +} diff --git a/lib/srv/server/installer/autodiscover.go b/lib/srv/server/installer/autodiscover.go index 287677b3aa68b..a9b8901127972 100644 --- a/lib/srv/server/installer/autodiscover.go +++ b/lib/srv/server/installer/autodiscover.go @@ -52,6 +52,13 @@ import ( "github.com/gravitational/teleport/lib/utils/packagemanager" ) +const ( + discoverNotice = "" + + "Teleport Discover has successfully configured /etc/teleport.yaml for this server to join the cluster.\n" + + "Discover might replace the configuration if the server fails to join the cluster.\n" + + "Please remove this file if you are managing this instance using another tool or doing so manually.\n" +) + // AutoDiscoverNodeInstallerConfig installs and configures a Teleport Server into the current system. type AutoDiscoverNodeInstallerConfig struct { Logger *slog.Logger @@ -312,6 +319,7 @@ func (ani *AutoDiscoverNodeInstaller) configureTeleportNode(ctx context.Context, _ = os.Remove(teleportYamlConfigurationPathNew) }() + discoverNoticeFile := teleportYamlConfigurationPath + ".discover" // Check if file already exists and has the same content that we are about to write if _, err := os.Stat(teleportYamlConfigurationPath); err == nil { hashExistingFile, err := checksum(teleportYamlConfigurationPath) @@ -325,14 +333,38 @@ func (ani *AutoDiscoverNodeInstaller) configureTeleportNode(ctx context.Context, } if hashExistingFile == hashNewFile { + if err := os.WriteFile(discoverNoticeFile, []byte(discoverNotice), 0o644); err != nil { + return trace.Wrap(err) + } + return trace.AlreadyExists("teleport.yaml is up to date") } + + // If a previous /etc/teleport.yaml configuration file exists and is different from the target one, it might be because one of the following reasons: + // - discover installation params (eg token name) were changed + // - `$ teleport node configure` command produces a different output + // - teleport was manually installed / configured + // + // For the first two scenarios, it's fine, and even desired in most cases, to restart teleport with the new configuration. + // + // However, for the last scenario (teleport was manually installed), this flow must not replace the currently running teleport service configuration. + // To prevent this, this flow checks for the existence of the discover notice file, and only allows replacement if it does exist. + if _, err := os.Stat(discoverNoticeFile); err != nil { + ani.Logger.InfoContext(ctx, "Refusing to replace the existing teleport configuration. For the script to replace the existing configuration remove the Teleport configuration.", + "teleport_configuration", teleportYamlConfigurationPath, + "discover_notice_file", discoverNoticeFile) + return trace.BadParameter("missing discover notice file") + } } if err := os.Rename(teleportYamlConfigurationPathNew, teleportYamlConfigurationPath); err != nil { return trace.Wrap(err) } + if err := os.WriteFile(discoverNoticeFile, []byte(discoverNotice), 0o644); err != nil { + return trace.Wrap(err) + } + return nil } diff --git a/lib/srv/server/installer/autodiscover_test.go b/lib/srv/server/installer/autodiscover_test.go index 5d36a036e1db6..0d02cb918f2cf 100644 --- a/lib/srv/server/installer/autodiscover_test.go +++ b/lib/srv/server/installer/autodiscover_test.go @@ -201,6 +201,8 @@ func TestAutoDiscoverNode(t *testing.T) { for binName, mockBin := range mockBins { require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) } + require.FileExists(t, testTempDir+"/etc/teleport.yaml") + require.FileExists(t, testTempDir+"/etc/teleport.yaml.discover") }) } } @@ -277,6 +279,8 @@ func TestAutoDiscoverNode(t *testing.T) { for binName, mockBin := range mockBins { require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) } + require.FileExists(t, testTempDir+"/etc/teleport.yaml") + require.FileExists(t, testTempDir+"/etc/teleport.yaml.discover") }) t.Run("fails when imds server is not available", func(t *testing.T) { @@ -314,9 +318,11 @@ func TestAutoDiscoverNode(t *testing.T) { for binName, mockBin := range mockBins { require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) } + require.NoFileExists(t, testTempDir+"/etc/teleport.yaml") + require.NoFileExists(t, testTempDir+"/etc/teleport.yaml.discover") }) - t.Run("reconfigures and restarts if target teleport.yaml is different", func(t *testing.T) { + t.Run("reconfigures and restarts if target teleport.yaml is different and discover file exists", func(t *testing.T) { distroConfig := wellKnownOS["ubuntu"]["24.04"] testTempDir := t.TempDir() @@ -345,6 +351,8 @@ func TestAutoDiscoverNode(t *testing.T) { // create an existing teleport.yaml configuration file require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml", []byte("has wrong config"), 0o644)) + // create a teleport.yaml.discover to indicate that this host is controlled by the discover flow + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml.discover", []byte(""), 0o644)) // package manager is not called in this scenario because teleport binary already exists in the system require.FileExists(t, mockBins["teleport"].Path) @@ -374,11 +382,72 @@ func TestAutoDiscoverNode(t *testing.T) { require.NoFileExists(t, testTempDir+"/etc/teleport.yaml.new") require.FileExists(t, testTempDir+"/etc/teleport.yaml") + require.FileExists(t, testTempDir+"/etc/teleport.yaml.discover") bs, err := os.ReadFile(testTempDir + "/etc/teleport.yaml") require.NoError(t, err) require.Equal(t, "teleport.yaml configuration bytes", string(bs)) }) + t.Run("does not reconfigure if teleport.yaml exists but discover file does not exists", func(t *testing.T) { + distroConfig := wellKnownOS["ubuntu"]["24.04"] + + testTempDir := t.TempDir() + + setupDirsForTest(t, testTempDir, distroConfig) + + installerConfig := &AutoDiscoverNodeInstallerConfig{ + RepositoryChannel: "stable/rolling", + AutoUpgrades: false, + ProxyPublicAddr: "proxy.example.com", + TeleportPackage: "teleport", + TokenName: "my-token", + AzureClientID: "azure-client-id", + + fsRootPrefix: testTempDir, + imdsProviders: mockIMDSProviders, + binariesLocation: binariesLocation, + aptPublicKeyEndpoint: mockRepoKeys.URL, + } + + teleportInstaller, err := NewAutoDiscoverNodeInstaller(installerConfig) + require.NoError(t, err) + + // package manager is not called in this scenario because teleport binary already exists in the system + require.FileExists(t, mockBins["teleport"].Path) + + // create an existing teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml", []byte("has wrong config"), 0o644)) + + // package manager is not called in this scenario because teleport binary already exists in the system + require.FileExists(t, mockBins["teleport"].Path) + + mockBins["teleport"].Expect("node", + "configure", + "--output=file://"+testTempDir+"/etc/teleport.yaml.new", + "--proxy=proxy.example.com", + "--join-method=azure", + "--token=my-token", + "--labels=teleport.internal/region=eastus,teleport.internal/resource-group=TestGroup,teleport.internal/subscription-id=5187AF11-3581-4AB6-A654-59405CD40C44,teleport.internal/vm-id=ED7DAC09-6E73-447F-BD18-AF4D1196C1E4", + "--azure-client-id=azure-client-id", + ).AndCallFunc(func(c *bintest.Call) { + // create a teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml.new", []byte("teleport.yaml configuration bytes"), 0o644)) + c.Exit(0) + }) + + require.ErrorContains(t, teleportInstaller.Install(ctx), "missing discover notice file") + + for binName, mockBin := range mockBins { + require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) + } + + require.NoFileExists(t, testTempDir+"/etc/teleport.yaml.new") + require.FileExists(t, testTempDir+"/etc/teleport.yaml") + bs, err := os.ReadFile(testTempDir + "/etc/teleport.yaml") + require.NoError(t, err) + require.Equal(t, "has wrong config", string(bs)) + }) + t.Run("does nothing if teleport is already installed and target teleport.yaml configuration already exists", func(t *testing.T) { distroName := "ubuntu" distroVersion := "24.04" @@ -440,6 +509,91 @@ func TestAutoDiscoverNode(t *testing.T) { require.NoError(t, err) require.Equal(t, "teleport.yaml configuration bytes", string(bs)) }) + + t.Run("does nothing if target teleport.yaml configuration exists but was manually created/edited", func(t *testing.T) { + distroName := "ubuntu" + distroVersion := "24.04" + distroConfig := wellKnownOS[distroName][distroVersion] + + testTempDir := t.TempDir() + + setupDirsForTest(t, testTempDir, distroConfig) + + installerConfig := &AutoDiscoverNodeInstallerConfig{ + RepositoryChannel: "stable/rolling", + AutoUpgrades: false, + ProxyPublicAddr: "proxy.example.com", + TeleportPackage: "teleport", + TokenName: "my-token", + AzureClientID: "azure-client-id", + + fsRootPrefix: testTempDir, + imdsProviders: mockIMDSProviders, + binariesLocation: binariesLocation, + aptPublicKeyEndpoint: mockRepoKeys.URL, + } + + teleportInstaller, err := NewAutoDiscoverNodeInstaller(installerConfig) + require.NoError(t, err) + + // package manager is not called in this scenario because teleport binary already exists in the system + require.FileExists(t, mockBins["teleport"].Path) + + // create an existing teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml", []byte("teleport.yaml bytes"), 0o644)) + + // package manager is not called in this scenario because teleport binary already exists in the system + require.FileExists(t, mockBins["teleport"].Path) + + mockBins["teleport"].Expect("node", + "configure", + "--output=file://"+testTempDir+"/etc/teleport.yaml.new", + "--proxy=proxy.example.com", + "--join-method=azure", + "--token=my-token", + "--labels=teleport.internal/region=eastus,teleport.internal/resource-group=TestGroup,teleport.internal/subscription-id=5187AF11-3581-4AB6-A654-59405CD40C44,teleport.internal/vm-id=ED7DAC09-6E73-447F-BD18-AF4D1196C1E4", + "--azure-client-id=azure-client-id", + ).AndCallFunc(func(c *bintest.Call) { + // create a teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml.new", []byte("teleport.yaml configuration bytes"), 0o644)) + c.Exit(0) + }) + + require.ErrorContains(t, teleportInstaller.Install(ctx), "missing discover notice file") + + for binName, mockBin := range mockBins { + require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) + } + + t.Run("even if it runs multiple times", func(t *testing.T) { + + // create an existing teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml", []byte("manual configuration already exists"), 0o644)) + + // package manager is not called in this scenario because teleport binary already exists in the system + require.FileExists(t, mockBins["teleport"].Path) + + mockBins["teleport"].Expect("node", + "configure", + "--output=file://"+testTempDir+"/etc/teleport.yaml.new", + "--proxy=proxy.example.com", + "--join-method=azure", + "--token=my-token", + "--labels=teleport.internal/region=eastus,teleport.internal/resource-group=TestGroup,teleport.internal/subscription-id=5187AF11-3581-4AB6-A654-59405CD40C44,teleport.internal/vm-id=ED7DAC09-6E73-447F-BD18-AF4D1196C1E4", + "--azure-client-id=azure-client-id", + ).AndCallFunc(func(c *bintest.Call) { + // create a teleport.yaml configuration file + require.NoError(t, os.WriteFile(testTempDir+"/etc/teleport.yaml.new", []byte("teleport.yaml configuration bytes"), 0o644)) + c.Exit(0) + }) + + require.ErrorContains(t, teleportInstaller.Install(ctx), "missing discover notice file") + + for binName, mockBin := range mockBins { + require.True(t, mockBin.Check(t), "mismatch between expected invocations and actual calls for %q", binName) + } + }) + }) } // wellKnownOS lists the officially supported repositories for Linux Distros diff --git a/lib/srv/sess.go b/lib/srv/sess.go index 1ffbc249db7e3..e5172a5248f4e 100644 --- a/lib/srv/sess.go +++ b/lib/srv/sess.go @@ -271,6 +271,7 @@ func (s *SessionRegistry) TryCreateHostUser(ctx *ServerContext) error { ui, err := ctx.Identity.AccessChecker.HostUsers(ctx.srv.GetInfo()) if err != nil { if trace.IsAccessDenied(err) { + log.Warnf("Unable to create host users: %v", err) return nil } log.Debug("Error while checking host users creation permission: ", err) @@ -1333,21 +1334,21 @@ func (s *session) startInteractive(ctx context.Context, scx *ServerContext, p *p s.log.WithError(err).Error("Received error waiting for the interactive session to finish") } - if result != nil { - if err := s.registry.broadcastResult(s.id, *result); err != nil { - s.log.Warningf("Failed to broadcast session result: %v", err) - } - } - // wait for copying from the pty to be complete or a timeout before // broadcasting the result (which will close the pty) if it has not been // closed already. select { case <-time.After(defaults.WaitCopyTimeout): - s.log.Error("Timed out waiting for PTY copy to finish, session data may be missing.") + s.log.Debug("Timed out waiting for PTY copy to finish, session data may be missing.") case <-s.doneCh: } + if result != nil { + if err := s.registry.broadcastResult(s.id, *result); err != nil { + s.log.Warningf("Failed to broadcast session result: %v", err) + } + } + if execRequest, err := scx.GetExecRequest(); err == nil && execRequest.GetCommand() != "" { emitExecAuditEvent(scx, execRequest.GetCommand(), err) } @@ -1514,8 +1515,11 @@ func (s *session) broadcastResult(r ExecResult) { s.mu.Lock() defer s.mu.Unlock() + payload := ssh.Marshal(struct{ C uint32 }{C: uint32(r.Code)}) for _, p := range s.parties { - p.ctx.SendExecResult(r) + if _, err := p.ch.SendRequest("exit-status", false, payload); err != nil { + s.log.Infof("Failed to send exit status for %v: %v", r.Command, err) + } } } diff --git a/lib/srv/usermgmt.go b/lib/srv/usermgmt.go index 8a1a7bc697f9d..aaa93de0ffcd7 100644 --- a/lib/srv/usermgmt.go +++ b/lib/srv/usermgmt.go @@ -23,6 +23,7 @@ import ( "errors" "fmt" "io" + "maps" "os/user" "regexp" "strings" @@ -35,11 +36,10 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/teleport/lib/services/local" ) // NewHostUsers initialize a new HostUsers object -func NewHostUsers(ctx context.Context, storage *local.PresenceService, uuid string) HostUsers { +func NewHostUsers(ctx context.Context, storage services.PresenceInternal, uuid string) HostUsers { //nolint:staticcheck // SA4023. False positive on macOS. backend, err := newHostUsersBackend() switch { @@ -176,7 +176,7 @@ type HostUserManagement struct { backend HostUsersBackend ctx context.Context cancel context.CancelFunc - storage *local.PresenceService + storage services.PresenceInternal userGrace time.Duration } @@ -229,20 +229,20 @@ func (u *HostUserManagement) UpsertUser(name string, ui *services.HostUsersInfo) return nil, trace.BadParameter("Mode is a required argument to CreateUser") } - groups := make([]string, 0, len(ui.Groups)) + groupsToAdd := make([]string, 0, len(ui.Groups)) for _, group := range ui.Groups { if group == name { // this causes an error as useradd expects the group with the same name as the user to be available log.Debugf("Skipping group creation with name the same as login user (%q, %q).", name, group) continue } - groups = append(groups, group) + groupsToAdd = append(groupsToAdd, group) } if ui.Mode == types.CreateHostUserMode_HOST_USER_MODE_INSECURE_DROP { - groups = append(groups, types.TeleportServiceGroup) + groupsToAdd = append(groupsToAdd, types.TeleportServiceGroup) } var errs []error - for _, group := range groups { + for _, group := range groupsToAdd { if err := u.createGroupIfNotExist(group); err != nil { errs = append(errs, err) continue @@ -259,13 +259,12 @@ func (u *HostUserManagement) UpsertUser(name string, ui *services.HostUsersInfo) if tempUser != nil { // Collect actions that need to be done together under a lock on the user. - actionsUnderLock := []func() error{ - func() error { - // If the user exists, set user groups again as they might have changed. - return trace.Wrap(u.backend.SetUserGroups(name, groups)) - }, - } + actionsUnderLock := make([]func() error, 0, 2) doWithUserLock := func() error { + if len(actionsUnderLock) == 0 { + return nil + } + return trace.Wrap(u.doWithUserLock(func(_ types.SemaphoreLease) error { for _, action := range actionsUnderLock { if err := action(); err != nil { @@ -276,6 +275,38 @@ func (u *HostUserManagement) UpsertUser(name string, ui *services.HostUsersInfo) })) } + // Get the user's current groups. + currentGroups := make(map[string]struct{}, len(groupsToAdd)) + groupIds, err := u.backend.UserGIDs(tempUser) + if err != nil { + return nil, trace.Wrap(err) + } + for _, groupId := range groupIds { + group, err := u.backend.LookupGroupByID(groupId) + if err != nil { + return nil, trace.Wrap(err) + } + currentGroups[group.Name] = struct{}{} + } + + // Get the groups that the user should end up with, including the primary group. + finalGroups := make(map[string]struct{}, len(groupsToAdd)+1) + for _, group := range groupsToAdd { + finalGroups[group] = struct{}{} + } + primaryGroup, err := u.backend.LookupGroupByID(tempUser.Gid) + if err != nil { + return nil, trace.Wrap(err) + } + finalGroups[primaryGroup.Name] = struct{}{} + + // Check if the user's groups need to be updated. + if !maps.Equal(currentGroups, finalGroups) { + actionsUnderLock = append(actionsUnderLock, func() error { + return trace.Wrap(u.backend.SetUserGroups(name, groupsToAdd)) + }) + } + systemGroup, err := u.backend.LookupGroup(types.TeleportServiceGroup) if err != nil { if isUnknownGroupError(err, types.TeleportServiceGroup) { @@ -339,7 +370,7 @@ func (u *HostUserManagement) UpsertUser(name string, ui *services.HostUsersInfo) } } - err = u.backend.CreateUser(name, groups, home, ui.UID, ui.GID) + err = u.backend.CreateUser(name, groupsToAdd, home, ui.UID, ui.GID) if err != nil && !trace.IsAlreadyExists(err) { return trace.WrapWithMessage(err, "error while creating user") } diff --git a/lib/srv/usermgmt_test.go b/lib/srv/usermgmt_test.go index 7003237105e2a..4725a9acc9070 100644 --- a/lib/srv/usermgmt_test.go +++ b/lib/srv/usermgmt_test.go @@ -27,6 +27,7 @@ import ( "testing" "github.com/gravitational/trace" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/types" @@ -46,6 +47,8 @@ type testHostUserBackend struct { userUID map[string]string // userGID: user -> gid userGID map[string]string + + setUserGroupsCalls int } func newTestUserMgmt() *testHostUserBackend { @@ -68,28 +71,40 @@ func (tm *testHostUserBackend) GetAllUsers() ([]string, error) { func (tm *testHostUserBackend) Lookup(username string) (*user.User, error) { if _, ok := tm.users[username]; !ok { - return nil, nil + return nil, user.UnknownUserError(username) } return &user.User{ Username: username, + Uid: tm.userUID[username], + Gid: tm.userGID[username], }, nil } func (tm *testHostUserBackend) LookupGroup(groupname string) (*user.Group, error) { + gid, ok := tm.groups[groupname] + if !ok { + return nil, user.UnknownGroupError(groupname) + } return &user.Group{ - Gid: tm.groups[groupname], + Gid: gid, Name: groupname, }, nil } func (tm *testHostUserBackend) LookupGroupByID(gid string) (*user.Group, error) { - return &user.Group{ - Gid: tm.groups[gid], - Name: gid, - }, nil + for groupName, groupGid := range tm.groups { + if groupGid == gid { + return &user.Group{ + Gid: gid, + Name: groupName, + }, nil + } + } + return nil, user.UnknownGroupIdError(gid) } func (tm *testHostUserBackend) SetUserGroups(name string, groups []string) error { + tm.setUserGroupsCalls++ if _, ok := tm.users[name]; !ok { return trace.NotFound("User %q doesn't exist", name) } @@ -98,10 +113,12 @@ func (tm *testHostUserBackend) SetUserGroups(name string, groups []string) error } func (tm *testHostUserBackend) UserGIDs(u *user.User) ([]string, error) { - ids := make([]string, 0, len(tm.users[u.Username])) + ids := make([]string, 0, len(tm.users[u.Username])+1) for _, id := range tm.users[u.Username] { ids = append(ids, tm.groups[id]) } + // Include primary group. + ids = append(ids, u.Gid) return ids, nil } @@ -110,7 +127,10 @@ func (tm *testHostUserBackend) CreateGroup(group, gid string) error { if ok { return trace.AlreadyExists("Group %q, already exists", group) } - tm.groups[group] = fmt.Sprint(len(tm.groups) + 1) + if gid == "" { + gid = fmt.Sprint(len(tm.groups) + 1) + } + tm.groups[group] = gid return nil } @@ -119,6 +139,14 @@ func (tm *testHostUserBackend) CreateUser(user string, groups []string, home, ui if ok { return trace.AlreadyExists("Group %q, already exists", user) } + if uid == "" { + uid = fmt.Sprint(len(tm.users) + 1) + } + if gid == "" { + gid = fmt.Sprint(len(tm.groups) + 1) + } + // Ensure that the user has a primary group. It's OK if it already exists. + _ = tm.CreateGroup(user, gid) tm.users[user] = groups tm.userUID[user] = uid tm.userGID[user] = gid @@ -358,3 +386,47 @@ func TestIsUnknownGroupError(t *testing.T) { require.Equal(t, tc.isUnknownGroupError, isUnknownGroupError(tc.err, unknownGroupName)) } } + +func TestUpdateUserGroups(t *testing.T) { + t.Parallel() + + backend := newTestUserMgmt() + bk, err := memory.New(memory.Config{}) + require.NoError(t, err) + pres := local.NewPresenceService(bk) + users := HostUserManagement{ + backend: backend, + storage: pres, + } + + allGroups := []string{"foo", "bar", "baz", "quux"} + for _, group := range allGroups { + require.NoError(t, backend.CreateGroup(group, "")) + } + + userinfo := &services.HostUsersInfo{ + Groups: allGroups[:2], + Mode: types.CreateHostUserMode_HOST_USER_MODE_KEEP, + } + // Create a user with some groups. + closer, err := users.UpsertUser("alice", userinfo) + assert.NoError(t, err) + assert.Nil(t, closer) + assert.Zero(t, backend.setUserGroupsCalls) + assert.ElementsMatch(t, userinfo.Groups, backend.users["alice"]) + + // Update user with new groups. + userinfo.Groups = allGroups[2:] + closer, err = users.UpsertUser("alice", userinfo) + assert.NoError(t, err) + assert.Nil(t, closer) + assert.Equal(t, 1, backend.setUserGroupsCalls) + assert.ElementsMatch(t, userinfo.Groups, backend.users["alice"]) + + // Upsert again with same groups should not call SetUserGroups. + closer, err = users.UpsertUser("alice", userinfo) + assert.NoError(t, err) + assert.Nil(t, closer) + assert.Equal(t, 1, backend.setUserGroupsCalls) + assert.ElementsMatch(t, userinfo.Groups, backend.users["alice"]) +} diff --git a/lib/tbot/config/config.go b/lib/tbot/config/config.go index 6ffae7a328c08..bb4ca66d35449 100644 --- a/lib/tbot/config/config.go +++ b/lib/tbot/config/config.go @@ -445,6 +445,15 @@ func (conf *BotConfig) CheckAndSetDefaults() error { ) } + if conf.CertificateTTL > defaults.MaxRenewableCertTTL { + log.WarnContext( + context.TODO(), + "Requested certificate TTL exceeds the maximum TTL allowed and will likely be reduced by the Teleport server", + "requested_ttl", conf.CertificateTTL, + "maximum_ttl", defaults.MaxRenewableCertTTL, + ) + } + return nil } @@ -631,6 +640,27 @@ func destinationFromURI(uriString string) (bot.Destination, error) { ) } return &DestinationMemory{}, nil + case "kubernetes-secret": + if uri.Host != "" { + return nil, trace.BadParameter( + "kubernetes-secret scheme should not be specified with host", + ) + } + if uri.Path == "" { + return nil, trace.BadParameter( + "kubernetes-secret scheme should have a path specified", + ) + } + // kubernetes-secret:///my-secret + // TODO(noah): Eventually we'll support namespace in the host part of + // the URI. For now, we'll default to the namespace tbot is running in. + + // Path will be prefixed with '/' so we'll strip it off. + secretName := strings.TrimPrefix(uri.Path, "/") + + return &DestinationKubernetesSecret{ + Name: secretName, + }, nil default: return nil, trace.BadParameter( "unrecognized data storage scheme", diff --git a/lib/tbot/config/config_test.go b/lib/tbot/config/config_test.go index c98e4a0cee227..123e1b6b6c8e3 100644 --- a/lib/tbot/config/config_test.go +++ b/lib/tbot/config/config_test.go @@ -198,6 +198,19 @@ func TestDestinationFromURI(t *testing.T) { in: "foobar://", wantErr: true, }, + { + in: "kubernetes-secret:///my-secret", + want: &DestinationKubernetesSecret{ + Name: "my-secret", + }, + }, + { + in: "kubernetes-secret://my-secret", + want: &DestinationKubernetesSecret{ + Name: "my-secret", + }, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.in, func(t *testing.T) { diff --git a/lib/tbot/config/service_spiffe_workload_api.go b/lib/tbot/config/service_spiffe_workload_api.go index 59c2db2cbb315..5c034653b740b 100644 --- a/lib/tbot/config/service_spiffe_workload_api.go +++ b/lib/tbot/config/service_spiffe_workload_api.go @@ -23,6 +23,8 @@ import ( "github.com/gravitational/trace" "gopkg.in/yaml.v3" + + "github.com/gravitational/teleport/lib/tbot/spiffe/workloadattest" ) const SPIFFEWorkloadAPIServiceType = "spiffe-workload-api" @@ -58,6 +60,27 @@ type SVIDRequestRuleUnix struct { GID *int `yaml:"gid,omitempty"` } +// SVIDRequestRuleKubernetes is a workload attestation ruleset for workloads +// that connect via Unix domain sockets and are running in a Kubernetes pod. +// +// Requires the "kubernetes" attestor to be enabled. +// +// Fields should be a subset of workloadattest.KubernetesAttestation. +type SVIDRequestRuleKubernetes struct { + // Namespace is the Kubernetes namespace that a workload must be running in + // to be issued this SVID. + // If unspecified, the namespace is not checked. + Namespace string `yaml:"namespace,omitempty"` + // ServiceAccount is the Kubernetes service account that a workload must be + // running as to be issued this SVID. + // If unspecified, the service account is not checked. + ServiceAccount string `yaml:"service_account,omitempty"` + // PodName is the Kubernetes pod name that a workload must be running in to + // be issued this SVID. + // If unspecified, the pod name is not checked. + PodName string `yaml:"pod_name,omitempty"` +} + // SVIDRequestRule is an individual workload attestation rule. All values // specified within the rule must be satisfied for the rule itself to pass. type SVIDRequestRule struct { @@ -65,6 +88,10 @@ type SVIDRequestRule struct { // Unix domain sockets. If any value here is set, the rule will not pass // unless the workload is connecting via a Unix domain socket. Unix SVIDRequestRuleUnix `yaml:"unix"` + // Kubernetes is the workload attestation ruleset for workloads that connect + // via the Unix domain socket and are running in a Kubernetes pod. + // The "kubernetes" attestor must be enabled or these rules will fail. + Kubernetes SVIDRequestRuleKubernetes `yaml:"kubernetes"` } func (o SVIDRequestRule) LogValue() slog.Value { @@ -92,6 +119,8 @@ type SPIFFEWorkloadAPIService struct { // SVIDs is the list of SVIDs that the SPIFFE Workload API server should // provide. SVIDs []SVIDRequestWithRules `yaml:"svids"` + // Attestors is the configuration for the workload attestation process. + Attestors workloadattest.Config `yaml:"attestors"` } func (s *SPIFFEWorkloadAPIService) Type() string { @@ -121,8 +150,11 @@ func (s *SPIFFEWorkloadAPIService) CheckAndSetDefaults() error { } for i, svid := range s.SVIDs { if err := svid.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err, "validiting svid[%d]", i) + return trace.Wrap(err, "validating svid[%d]", i) } } + if err := s.Attestors.CheckAndSetDefaults(); err != nil { + return trace.Wrap(err, "validating attestor") + } return nil } diff --git a/lib/tbot/config/service_spiffe_workload_api_test.go b/lib/tbot/config/service_spiffe_workload_api_test.go index 1e4334730490c..795cf38b00896 100644 --- a/lib/tbot/config/service_spiffe_workload_api_test.go +++ b/lib/tbot/config/service_spiffe_workload_api_test.go @@ -20,6 +20,8 @@ package config import ( "testing" + + "github.com/gravitational/teleport/lib/tbot/spiffe/workloadattest" ) func ptr[T any](v T) *T { @@ -34,6 +36,18 @@ func TestSPIFFEWorkloadAPIService_YAML(t *testing.T) { name: "full", in: SPIFFEWorkloadAPIService{ Listen: "unix:///var/run/spiffe.sock", + Attestors: workloadattest.Config{ + Kubernetes: workloadattest.KubernetesAttestorConfig{ + Enabled: true, + Kubelet: workloadattest.KubeletClientConfig{ + SecurePort: 12345, + TokenPath: "/path/to/token", + CAPath: "/path/to/ca.pem", + SkipVerify: true, + Anonymous: true, + }, + }, + }, SVIDs: []SVIDRequestWithRules{ { SVIDRequest: SVIDRequest{ @@ -56,6 +70,11 @@ func TestSPIFFEWorkloadAPIService_YAML(t *testing.T) { Unix: SVIDRequestRuleUnix{ PID: ptr(100), }, + Kubernetes: SVIDRequestRuleKubernetes{ + Namespace: "my-namespace", + PodName: "my-pod", + ServiceAccount: "service-account", + }, }, }, }, diff --git a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden index 31eacda54d8c0..53a59aceacc8e 100644 --- a/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden +++ b/lib/tbot/config/testdata/TestBotConfig_YAML/standard_config.golden @@ -35,8 +35,13 @@ services: pid: 100 uid: 1000 gid: 1234 + kubernetes: {} - unix: pid: 100 + kubernetes: {} + attestors: + kubernetes: + enabled: false - type: example message: llama - type: ssh-multiplexer diff --git a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden index 53fc172b4dc4b..4a7c696e887bf 100644 --- a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden +++ b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/full.golden @@ -14,5 +14,19 @@ svids: pid: 100 uid: 1000 gid: 1234 + kubernetes: {} - unix: pid: 100 + kubernetes: + namespace: my-namespace + service_account: service-account + pod_name: my-pod +attestors: + kubernetes: + enabled: true + kubelet: + secure_port: 12345 + token_path: /path/to/token + ca_path: /path/to/ca.pem + skip_verify: true + anonymous: true diff --git a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/minimal.golden b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/minimal.golden index 1cef5bf13e1e0..326b4dfab8a67 100644 --- a/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/minimal.golden +++ b/lib/tbot/config/testdata/TestSPIFFEWorkloadAPIService_YAML/minimal.golden @@ -2,3 +2,6 @@ type: spiffe-workload-api listen: unix:///var/run/spiffe.sock svids: - path: /foo +attestors: + kubernetes: + enabled: false diff --git a/lib/tbot/service_spiffe_workload_api.go b/lib/tbot/service_spiffe_workload_api.go index 680c9fa56f5ec..b04fac4d3f9e5 100644 --- a/lib/tbot/service_spiffe_workload_api.go +++ b/lib/tbot/service_spiffe_workload_api.go @@ -54,6 +54,7 @@ import ( "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/tbot/config" + "github.com/gravitational/teleport/lib/tbot/spiffe/workloadattest" "github.com/gravitational/teleport/lib/uds" ) @@ -87,6 +88,8 @@ type SPIFFEWorkloadAPIService struct { trustDomain string + attestor *workloadattest.Attestor + // trustBundle is protected by trustBundleMu. Use setTrustBundle and // getTrustBundle to access it. trustBundle []byte @@ -170,6 +173,11 @@ func (s *SPIFFEWorkloadAPIService) setup(ctx context.Context) (err error) { } s.trustDomain = authPing.ClusterName + s.attestor, err = workloadattest.NewAttestor(s.log, s.cfg.Attestors) + if err != nil { + return trace.Wrap(err, "setting up workload attestation") + } + return nil } @@ -419,11 +427,16 @@ func (s *SPIFFEWorkloadAPIService) fetchX509SVIDs( // filterSVIDRequests filters the SVID requests based on the workload // attestation. +// +// TODO(noah): In a future PR, we need to totally refactor this to a more +// flexible rules engine otherwise this is going to get absurdly large as +// we add more types. Ideally, something that would be compatible with a +// predicate language would be great. func filterSVIDRequests( ctx context.Context, log *slog.Logger, svidRequests []config.SVIDRequestWithRules, - udsCreds *uds.Creds, + att workloadattest.Attestation, ) []config.SVIDRequest { var filtered []config.SVIDRequest for _, req := range svidRequests { @@ -442,33 +455,91 @@ func filterSVIDRequests( match := false for _, rule := range req.Rules { log := log.With("rule", rule) - log.DebugContext( - ctx, - "Evaluating rule against workload attestation", - ) - if rule.Unix.UID != nil && (udsCreds == nil || *rule.Unix.UID != udsCreds.UID) { + logMismatch := func(field string, want any, got any) { log.DebugContext( ctx, "Rule did not match workload attestation", - "field", "unix.uid", + "field", field, + "want", want, + "got", got, ) - continue } - if rule.Unix.PID != nil && (udsCreds == nil || *rule.Unix.PID != udsCreds.PID) { + logNotAttested := func(requiredAttestor string) { log.DebugContext( ctx, - "Rule did not match workload attestation", - "field", "unix.pid", + "Workload did not complete attestation required for this rule", + "required_attestor", requiredAttestor, ) - continue } - if rule.Unix.GID != nil && (udsCreds == nil || *rule.Unix.GID != udsCreds.GID) { - log.DebugContext( - ctx, - "Rule did not match workload attestation", - "field", "unix.gid", - ) - continue + log.DebugContext( + ctx, + "Evaluating rule against workload attestation", + ) + if rule.Unix.UID != nil { + if !att.Unix.Attested { + logNotAttested("unix") + continue + } + if *rule.Unix.UID != att.Unix.UID { + logMismatch("unix.uid", *rule.Unix.UID, att.Unix.UID) + continue + } + // Rule field matched! + } + if rule.Unix.PID != nil { + if !att.Unix.Attested { + logNotAttested("unix") + continue + } + if *rule.Unix.PID != att.Unix.PID { + logMismatch("unix.pid", *rule.Unix.PID, att.Unix.PID) + continue + } + // Rule field matched! + } + if rule.Unix.GID != nil { + if !att.Unix.Attested { + logNotAttested("unix") + continue + } + if *rule.Unix.GID != att.Unix.GID { + logMismatch("unix.gid", *rule.Unix.GID, att.Unix.GID) + continue + } + // Rule field matched! + } + if rule.Kubernetes.Namespace != "" { + if !att.Kubernetes.Attested { + logNotAttested("kubernetes") + continue + } + if rule.Kubernetes.Namespace != att.Kubernetes.Namespace { + logMismatch("kubernetes.namespace", rule.Kubernetes.Namespace, att.Kubernetes.Namespace) + continue + } + // Rule field matched! + } + if rule.Kubernetes.PodName != "" { + if !att.Kubernetes.Attested { + logNotAttested("kubernetes") + continue + } + if rule.Kubernetes.PodName != att.Kubernetes.PodName { + logMismatch("kubernetes.pod_name", rule.Kubernetes.PodName, att.Kubernetes.PodName) + continue + } + // Rule field matched! + } + if rule.Kubernetes.ServiceAccount != "" { + if !att.Kubernetes.Attested { + logNotAttested("kubernetes") + continue + } + if rule.Kubernetes.ServiceAccount != att.Kubernetes.ServiceAccount { + logMismatch("kubernetes.service_account", rule.Kubernetes.ServiceAccount, att.Kubernetes.ServiceAccount) + continue + } + // Rule field matched! } log.DebugContext( @@ -489,49 +560,59 @@ func filterSVIDRequests( return filtered } -// FetchX509SVID generates and returns the X.509 SVIDs available to a workload. -// It is a streaming RPC, and sends renewed SVIDs to the client before they -// expire. -// Implements the SPIFFE Workload API FetchX509SVID method. -func (s *SPIFFEWorkloadAPIService) FetchX509SVID( - _ *workloadpb.X509SVIDRequest, - srv workloadpb.SpiffeWorkloadAPI_FetchX509SVIDServer, -) error { - renewCh, unsubscribe := s.trustBundleBroadcast.subscribe() - defer unsubscribe() - ctx := srv.Context() +func (s *SPIFFEWorkloadAPIService) authenticateClient(ctx context.Context) (*slog.Logger, workloadattest.Attestation, error) { + // The zero value of the attestation is equivalent to no attestation. + var att workloadattest.Attestation p, ok := peer.FromContext(ctx) if !ok { - return trace.BadParameter("peer not found in context") + return nil, att, trace.BadParameter("peer not found in context") } log := s.log authInfo, ok := p.AuthInfo.(uds.AuthInfo) + if ok && authInfo.Creds != nil { + var err error + att, err = s.attestor.Attest(ctx, authInfo.Creds.PID) + if err != nil { + return nil, att, trace.Wrap(err, "performing workload attestation") + } log = log.With( - slog.Group("workload", - slog.Group("unix", - "pid", authInfo.Creds.PID, - "uid", authInfo.Creds.UID, - "gid", authInfo.Creds.GID, - ), - ), + "workload", slog.LogValuer(att), ) } if p.Addr.String() != "" { log = log.With( - slog.Group("workload", - slog.String("addr", p.Addr.String()), - ), + slog.String("remote_addr", p.Addr.String()), ) } + return log, att, nil +} + +// FetchX509SVID generates and returns the X.509 SVIDs available to a workload. +// It is a streaming RPC, and sends renewed SVIDs to the client before they +// expire. +// Implements the SPIFFE Workload API FetchX509SVID method. +func (s *SPIFFEWorkloadAPIService) FetchX509SVID( + _ *workloadpb.X509SVIDRequest, + srv workloadpb.SpiffeWorkloadAPI_FetchX509SVIDServer, +) error { + renewCh, unsubscribe := s.trustBundleBroadcast.subscribe() + defer unsubscribe() + ctx := srv.Context() + + log, creds, err := s.authenticateClient(ctx) + if err != nil { + return trace.Wrap(err) + } + log.InfoContext(ctx, "FetchX509SVID stream opened by workload") defer log.InfoContext(ctx, "FetchX509SVID stream has closed") // Before we issue the SVIDs to the workload, we need to complete workload // attestation and determine which SVIDs to issue. - svidReqs := filterSVIDRequests(ctx, log, s.cfg.SVIDs, authInfo.Creds) + svidReqs := filterSVIDRequests(ctx, log, s.cfg.SVIDs, creds) // The SPIFFE Workload API (5.2.1): // diff --git a/lib/tbot/service_spiffe_workload_api_test.go b/lib/tbot/service_spiffe_workload_api_test.go index 1638a836f6e41..3a331a1a1f06d 100644 --- a/lib/tbot/service_spiffe_workload_api_test.go +++ b/lib/tbot/service_spiffe_workload_api_test.go @@ -26,7 +26,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/gravitational/teleport/lib/tbot/config" - "github.com/gravitational/teleport/lib/uds" + "github.com/gravitational/teleport/lib/tbot/spiffe/workloadattest" "github.com/gravitational/teleport/lib/utils" ) @@ -35,17 +35,18 @@ func ptr[T any](v T) *T { } func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { + // This test is more for overall behavior. Use the _field test for + // each individual field. ctx := context.Background() log := utils.NewSlogLoggerForTests() tests := []struct { name string - uds *uds.Creds + att workloadattest.Attestation in []config.SVIDRequestWithRules want []config.SVIDRequest }{ { name: "no rules", - uds: nil, in: []config.SVIDRequestWithRules{ { SVIDRequest: config.SVIDRequest{ @@ -68,11 +69,14 @@ func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { }, }, { - name: "no rules with uds", - uds: &uds.Creds{ - UID: 1000, - GID: 1001, - PID: 1002, + name: "no rules with attestation", + att: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + UID: 1000, + GID: 1001, + PID: 1002, + }, }, in: []config.SVIDRequestWithRules{ { @@ -96,11 +100,43 @@ func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { }, }, { - name: "no matching rules with uds", - uds: &uds.Creds{ - UID: 1000, - GID: 1001, - PID: 1002, + name: "no rules with attestation", + att: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + // We don't expect that workloadattest will ever return + // Attested: false and include UID/PID/GID but we want to + // ensure we handle this by failing regardless. + Attested: false, + UID: 1000, + GID: 1001, + PID: 1002, + }, + }, + in: []config.SVIDRequestWithRules{ + { + SVIDRequest: config.SVIDRequest{ + Path: "/foo", + }, + Rules: []config.SVIDRequestRule{ + { + Unix: config.SVIDRequestRuleUnix{ + UID: ptr(1000), + }, + }, + }, + }, + }, + want: nil, + }, + { + name: "no matching rules with attestation", + att: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + UID: 1000, + GID: 1001, + PID: 1002, + }, }, in: []config.SVIDRequestWithRules{ { @@ -137,8 +173,7 @@ func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { want: nil, }, { - name: "no matching rules without uds", - uds: nil, + name: "no matching rules without attestation", in: []config.SVIDRequestWithRules{ { SVIDRequest: config.SVIDRequest{ @@ -174,10 +209,13 @@ func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { }, { name: "some matching rules with uds", - uds: &uds.Creds{ - UID: 1000, - GID: 1001, - PID: 1002, + att: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + UID: 1000, + GID: 1001, + PID: 1002, + }, }, in: []config.SVIDRequestWithRules{ { @@ -230,8 +268,158 @@ func TestSPIFFEWorkloadAPIService_filterSVIDRequests(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := filterSVIDRequests(ctx, log, tt.in, tt.uds) + got := filterSVIDRequests(ctx, log, tt.in, tt.att) assert.Empty(t, gocmp.Diff(tt.want, got)) }) } } + +func TestSPIFFEWorkloadAPIService_filterSVIDRequests_field(t *testing.T) { + ctx := context.Background() + log := utils.NewSlogLoggerForTests() + tests := []struct { + field string + matching workloadattest.Attestation + nonMatching workloadattest.Attestation + rule config.SVIDRequestRule + }{ + { + field: "unix.pid", + rule: config.SVIDRequestRule{ + Unix: config.SVIDRequestRuleUnix{ + PID: ptr(1000), + }, + }, + matching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + PID: 1000, + }, + }, + nonMatching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + PID: 200, + }, + }, + }, + { + field: "unix.uid", + rule: config.SVIDRequestRule{ + Unix: config.SVIDRequestRuleUnix{ + UID: ptr(1000), + }, + }, + matching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + UID: 1000, + }, + }, + nonMatching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + UID: 200, + }, + }, + }, + { + field: "unix.gid", + rule: config.SVIDRequestRule{ + Unix: config.SVIDRequestRuleUnix{ + GID: ptr(1000), + }, + }, + matching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + GID: 1000, + }, + }, + nonMatching: workloadattest.Attestation{ + Unix: workloadattest.UnixAttestation{ + Attested: true, + GID: 200, + }, + }, + }, + { + field: "unix.namespace", + rule: config.SVIDRequestRule{ + Kubernetes: config.SVIDRequestRuleKubernetes{ + Namespace: "foo", + }, + }, + matching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + Namespace: "foo", + }, + }, + nonMatching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + Namespace: "bar", + }, + }, + }, + { + field: "kubernetes.service_account", + rule: config.SVIDRequestRule{ + Kubernetes: config.SVIDRequestRuleKubernetes{ + ServiceAccount: "foo", + }, + }, + matching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + ServiceAccount: "foo", + }, + }, + nonMatching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + ServiceAccount: "bar", + }, + }, + }, + { + field: "kubernetes.pod_name", + rule: config.SVIDRequestRule{ + Kubernetes: config.SVIDRequestRuleKubernetes{ + PodName: "foo", + }, + }, + matching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + PodName: "foo", + }, + }, + nonMatching: workloadattest.Attestation{ + Kubernetes: workloadattest.KubernetesAttestation{ + Attested: true, + PodName: "bar", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.field, func(t *testing.T) { + rules := []config.SVIDRequestWithRules{ + { + SVIDRequest: config.SVIDRequest{ + Path: "/foo", + }, + Rules: []config.SVIDRequestRule{tt.rule}, + }, + } + t.Run("matching", func(t *testing.T) { + assert.Len(t, filterSVIDRequests(ctx, log, rules, tt.matching), 1) + }) + t.Run("non-matching", func(t *testing.T) { + assert.Empty(t, filterSVIDRequests(ctx, log, rules, tt.nonMatching)) + }) + }) + } +} diff --git a/lib/tbot/spiffe/workloadattest/attest.go b/lib/tbot/spiffe/workloadattest/attest.go new file mode 100644 index 0000000000000..cd3d87cf65dc1 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/attest.go @@ -0,0 +1,107 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "context" + "log/slog" + + "github.com/gravitational/trace" +) + +// Attestation holds the results of the attestation process carried out on a +// PID by the attestor. +type Attestation struct { + Unix UnixAttestation + Kubernetes KubernetesAttestation +} + +// LogValue implements slog.LogValue to provide a nicely formatted set of +// log keys for a given attestation. +func (a Attestation) LogValue() slog.Value { + return slog.GroupValue( + slog.Attr{ + Key: "unix", + Value: a.Unix.LogValue(), + }, + slog.Attr{ + Key: "kubernetes", + Value: a.Kubernetes.LogValue(), + }, + ) +} + +type attestor[T any] interface { + Attest(ctx context.Context, pid int) (T, error) +} + +// Attestor runs the workload attestation process on a given PID to determine +// key information about the process. +type Attestor struct { + log *slog.Logger + kubernetes attestor[KubernetesAttestation] + unix attestor[UnixAttestation] +} + +// Config is the configuration for Attestor +type Config struct { + Kubernetes KubernetesAttestorConfig `yaml:"kubernetes"` +} + +func (c *Config) CheckAndSetDefaults() error { + return trace.Wrap(c.Kubernetes.CheckAndSetDefaults(), "validating kubernetes") +} + +// NewAttestor returns an Attestor from the given config. +func NewAttestor(log *slog.Logger, cfg Config) (*Attestor, error) { + att := &Attestor{ + log: log, + unix: NewUnixAttestor(), + } + if cfg.Kubernetes.Enabled { + att.kubernetes = NewKubernetesAttestor(cfg.Kubernetes, log) + } + return att, nil +} + +func (a *Attestor) Attest(ctx context.Context, pid int) (Attestation, error) { + a.log.DebugContext(ctx, "Starting workload attestation", "pid", pid) + defer a.log.DebugContext(ctx, "Finished workload attestation complete", "pid", pid) + + att := Attestation{} + var err error + + // We always perform the unix attestation first + att.Unix, err = a.unix.Attest(ctx, pid) + if err != nil { + return att, err + } + + // Then we can perform the optionally configured attestations + // For these, failure is soft. If it fails, we log, but still return the + // successfully attested data. + if a.kubernetes != nil { + att.Kubernetes, err = a.kubernetes.Attest(ctx, pid) + if err != nil { + a.log.WarnContext(ctx, "Failed to perform Kubernetes workload attestation", "error", err) + } + } + + return att, nil +} diff --git a/lib/tbot/spiffe/workloadattest/kubernetes.go b/lib/tbot/spiffe/workloadattest/kubernetes.go new file mode 100644 index 0000000000000..afadbab5c45e4 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/kubernetes.go @@ -0,0 +1,135 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "log/slog" + + "github.com/gravitational/trace" +) + +// KubernetesAttestation holds the Kubernetes pod information retrieved from +// the workload attestation process. +type KubernetesAttestation struct { + // Attested is true if the PID was successfully attested to a Kubernetes + // pod. This indicates the validity of the rest of the fields. + Attested bool + // Namespace is the namespace of the pod. + Namespace string + // ServiceAccount is the service account of the pod. + ServiceAccount string + // PodName is the name of the pod. + PodName string + // PodUID is the UID of the pod. + PodUID string + // Labels is a map of labels on the pod. + Labels map[string]string +} + +// LogValue implements slog.LogValue to provide a nicely formatted set of +// log keys for a given attestation. +func (a KubernetesAttestation) LogValue() slog.Value { + values := []slog.Attr{ + slog.Bool("attested", a.Attested), + } + if a.Attested { + labels := []slog.Attr{} + for k, v := range a.Labels { + labels = append(labels, slog.String(k, v)) + } + values = append(values, + slog.String("namespace", a.Namespace), + slog.String("service_account", a.ServiceAccount), + slog.String("pod_name", a.PodName), + slog.String("pod_uid", a.PodUID), + slog.Attr{ + Key: "labels", + Value: slog.GroupValue(labels...), + }, + ) + } + return slog.GroupValue(values...) +} + +// KubernetesAttestorConfig holds the configuration for the KubernetesAttestor. +type KubernetesAttestorConfig struct { + // Enabled is true if the KubernetesAttestor is enabled. If false, + // Kubernetes attestation will not be attempted. + Enabled bool `yaml:"enabled"` + Kubelet KubeletClientConfig `yaml:"kubelet,omitempty"` +} + +func (c *KubernetesAttestorConfig) CheckAndSetDefaults() error { + if !c.Enabled { + return nil + } + return trace.Wrap(c.Kubelet.CheckAndSetDefaults(), "validating kubelet") +} + +const ( + // nodeNameEnv is used to inject the current nodes name via the downward API. + // This provides a hostname for the kubelet client to use. + nodeNameEnv = "TELEPORT_NODE_NAME" + defaultServiceAccountTokenPath = "/var/run/secrets/kubernetes.io/serviceaccount/token" + defaultCAPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + defaultSecurePort = 10250 +) + +// KubeletClientConfig holds the configuration for the Kubelet client +// used to query the Kubelet API for workload attestation. +type KubeletClientConfig struct { + // ReadOnlyPort is the port on which the Kubelet API is exposed for + // read-only operations. This is mutually exclusive with SecurePort. + // This is primarily left for legacy support - since Kubernetes 1.16, the + // read-only port is disabled by default. + ReadOnlyPort int `yaml:"read_only_port,omitempty"` + // SecurePort specifies the secure port on which the Kubelet API is exposed. + // If unspecified, this defaults to `10250`. This is mutually exclusive + // with ReadOnlyPort. + SecurePort int `yaml:"secure_port,omitempty"` + + // TokenPath is the path to the token file used to authenticate with the + // Kubelet API when using the secure port. + // Defaults to `/var/run/secrets/kubernetes.io/serviceaccount/token`. + TokenPath string `yaml:"token_path,omitempty"` + // CAPath is the path to the CA file used to verify the certificate + // presented by Kubelet when using the secure port. + // Defaults to `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`. + CAPath string `yaml:"ca_path,omitempty"` + // SkipVerify is used to skip verification of the Kubelet's certificate when + // using the secure port. If set, CAPath will be ignored. + // + // This is useful in scenarios where Kubelet has not been configured with a + // valid certificate signed by the cluster CA. This is more common than + // you'd think. + SkipVerify bool `yaml:"skip_verify,omitempty"` + // Anonymous is used to indicate that no authentication should be used + // when connecting to the secure Kubelet API. If set, TokenPath will be + // ignored. + Anonymous bool `yaml:"anonymous,omitempty"` +} + +// CheckAndSetDefaults checks the KubeletClientConfig for any invalid values +// and sets defaults where necessary. +func (c KubeletClientConfig) CheckAndSetDefaults() error { + if c.ReadOnlyPort != 0 && c.SecurePort != 0 { + return trace.BadParameter("readOnlyPort and securePort are mutually exclusive") + } + return nil +} diff --git a/lib/tbot/spiffe/workloadattest/kubernetes_unix.go b/lib/tbot/spiffe/workloadattest/kubernetes_unix.go new file mode 100644 index 0000000000000..567b33d337d00 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/kubernetes_unix.go @@ -0,0 +1,316 @@ +//go:build unix + +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "cmp" + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "log/slog" + "net" + "net/http" + "net/url" + "os" + "path" + "regexp" + "strconv" + "strings" + "time" + + "github.com/gravitational/trace" + v1 "k8s.io/api/core/v1" + "k8s.io/utils/mount" +) + +// KubernetesAttestor attests a workload to a Kubernetes pod. +// +// It requires: +// +// - `hostPID: true` so we can view the /proc of other pods. +// - `TELEPORT_MY_NODE_NAME` to be set to the node name of the current node. +// - A service account that allows it to query the Kubelet API. +// +// It roughly takes the following steps: +// 1. From the PID, determine the container ID and pod ID from the +// /proc//mountinfo file. +// 2. Makes a request to the Kubelet API to list all pods on the node. +// 3. Find the pod and container with the matching ID. +// 4. Convert the pod information to a KubernetesAttestation. +type KubernetesAttestor struct { + kubeletClient *kubeletClient + log *slog.Logger + // rootPath specifies the location of `/`. This allows overriding for tests. + rootPath string +} + +// NewKubernetesAttestor creates a new KubernetesAttestor. +func NewKubernetesAttestor(cfg KubernetesAttestorConfig, log *slog.Logger) *KubernetesAttestor { + kubeletClient := newKubeletClient(cfg.Kubelet) + return &KubernetesAttestor{ + kubeletClient: kubeletClient, + log: log, + } +} + +// Attest resolves the Kubernetes pod information from the +// PID of the workload. +func (a *KubernetesAttestor) Attest(ctx context.Context, pid int) (KubernetesAttestation, error) { + a.log.DebugContext(ctx, "Starting Kubernetes workload attestation", "pid", pid) + + podID, containerID, err := a.getContainerAndPodID(pid) + if err != nil { + return KubernetesAttestation{}, trace.Wrap(err, "determining pod and container ID") + } + a.log.DebugContext(ctx, "Found pod and container ID", "pod_id", podID, "container_id", containerID) + + pod, err := a.getPodForID(ctx, podID) + if err != nil { + return KubernetesAttestation{}, trace.Wrap(err, "finding pod by ID") + } + a.log.DebugContext(ctx, "Found pod", "pod_name", pod.Name) + + att := KubernetesAttestation{ + Attested: true, + Namespace: pod.Namespace, + ServiceAccount: pod.Spec.ServiceAccountName, + PodName: pod.Name, + PodUID: string(pod.UID), + Labels: pod.Labels, + } + a.log.DebugContext(ctx, "Finished Kubernetes workload attestation", "attestation", att) + return att, nil +} + +// getContainerAndPodID retrieves the container ID and pod ID for the provided +// PID. +func (a *KubernetesAttestor) getContainerAndPodID(pid int) (podID string, containerID string, err error) { + info, err := mount.ParseMountInfo( + path.Join(a.rootPath, "/proc", strconv.Itoa(pid), "mountinfo"), + ) + if err != nil { + return "", "", trace.Wrap( + err, "parsing mountinfo", + ) + } + + // Find the cgroup or cgroupv2 mount + // For cgroup v2, we expect a single mount. But for cgroup v1, there will + // be one mount per subsystem, but regardless, they will all contain the + // same container ID/pod ID. + var cgroupMount mount.MountInfo + for _, m := range info { + if m.FsType == "cgroup" || m.FsType == "cgroup2" { + cgroupMount = m + break + } + } + + podID, containerID, err = mountpointSourceToContainerAndPodID( + cgroupMount.Root, + ) + if err != nil { + return "", "", trace.Wrap( + err, "parsing cgroup mount (root: %q)", cgroupMount.Root, + ) + } + return podID, containerID, nil +} + +var ( + // A container ID is usually a 64 character hex string, so this regex just + // selects for that. + containerIDRegex = regexp.MustCompile(`(?P[[:xdigit:]]{64})`) + // A pod ID is usually a UUID prefaced with "pod". + // There are two main cgroup drivers: + // - systemd , the dashes are replaced with underscores + // - cgroupfs, the dashes are kept. + podIDRegex = regexp.MustCompile(`pod(?P[[:xdigit:]]{8}[_-][[:xdigit:]]{4}[_-][[:xdigit:]]{4}[_-][[:xdigit:]]{4}[_-][[:xdigit:]]{12})`) +) + +// mountpointSourceToContainerAndPodID takes the source of the cgroup mountpoint +// and extracts the container ID and pod ID from it. +// +// Note: this is a fairly naive implementation, we may need to make further +// improvements to account for other distributions of Kubernetes. +func mountpointSourceToContainerAndPodID(source string) (podID string, containerID string, err error) { + // From the mount, we need to extract the container ID and pod ID. + // Unfortunately this process can be a little fragile, as the format of + // the mountpoint varies across Kubernetes implementations. + // There's a collection of real world mountfiles in testdata/mountfile. + + matches := containerIDRegex.FindStringSubmatch(source) + if len(matches) != 2 { + return "", "", trace.BadParameter( + "expected 2 matches searching for container ID but found %d", + len(matches), + ) + } + containerID = matches[1] + if containerID == "" { + return "", "", trace.BadParameter( + "source does not contain container ID", + ) + } + + matches = podIDRegex.FindStringSubmatch(source) + if len(matches) != 2 { + return "", "", trace.BadParameter( + "expected 2 matches searching for pod ID but found %d", + len(matches), + ) + } + podID = matches[1] + if podID == "" { + return "", "", trace.BadParameter( + "source does not contain pod ID", + ) + } + + // When using the `systemd` cgroup driver, the dashes are replaced with + // underscores. So let's correct that. + podID = strings.ReplaceAll(podID, "_", "-") + + return podID, containerID, nil +} + +// getPodForID retrieves the pod information for the provided pod ID. +// https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/server.go#L371 +func (a *KubernetesAttestor) getPodForID(ctx context.Context, podID string) (*v1.Pod, error) { + pods, err := a.kubeletClient.ListAllPods(ctx) + if err != nil { + return nil, trace.Wrap(err, "listing all pods") + } + for _, pod := range pods.Items { + if string(pod.UID) == podID { + return &pod, nil + } + } + return nil, trace.NotFound("pod %q not found", podID) +} + +// kubeletClient is a HTTP client for the Kubelet API +type kubeletClient struct { + cfg KubeletClientConfig + getEnv func(string) string +} + +func newKubeletClient(cfg KubeletClientConfig) *kubeletClient { + return &kubeletClient{ + cfg: cfg, + getEnv: os.Getenv, + } +} + +type roundTripperFn func(req *http.Request) (*http.Response, error) + +func (f roundTripperFn) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func (c *kubeletClient) httpClient() (url.URL, *http.Client, error) { + host := c.getEnv(nodeNameEnv) + + if c.cfg.ReadOnlyPort != 0 { + return url.URL{ + Scheme: "http", + Host: net.JoinHostPort(host, strconv.Itoa(c.cfg.ReadOnlyPort)), + }, &http.Client{}, nil + } + + port := cmp.Or(c.cfg.SecurePort, defaultSecurePort) + + transport := &http.Transport{ + TLSClientConfig: &tls.Config{}, + } + + switch { + case c.cfg.SkipVerify: + transport.TLSClientConfig.InsecureSkipVerify = true + default: + caPath := cmp.Or(c.cfg.CAPath, defaultCAPath) + certPool := x509.NewCertPool() + caPEM, err := os.ReadFile(caPath) + if err != nil { + return url.URL{}, nil, trace.Wrap(err, "reading CA file %q", caPath) + } + if !certPool.AppendCertsFromPEM(caPEM) { + return url.URL{}, nil, trace.BadParameter("failed to append CA cert from %q", caPath) + } + transport.TLSClientConfig.RootCAs = certPool + } + + client := &http.Client{ + Transport: transport, + // 10 seconds is fairly generous given that we're expecting to talk to + // kubelet on the same physical machine. + Timeout: 10 * time.Second, + } + + switch { + case c.cfg.Anonymous: + // Nothing to do + case c.cfg.TokenPath != "": + fallthrough + default: + tokenPath := cmp.Or(c.cfg.TokenPath, defaultServiceAccountTokenPath) + token, err := os.ReadFile(tokenPath) + if err != nil { + return url.URL{}, nil, trace.Wrap(err, "reading token file %q", tokenPath) + } + client.Transport = roundTripperFn(func(req *http.Request) (*http.Response, error) { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + return transport.RoundTrip(req) + }) + } + + return url.URL{ + Scheme: "https", + Host: net.JoinHostPort(host, strconv.Itoa(port)), + }, client, nil +} + +func (c *kubeletClient) ListAllPods(ctx context.Context) (*v1.PodList, error) { + reqUrl, client, err := c.httpClient() + if err != nil { + return nil, trace.Wrap(err, "creating HTTP client") + } + reqUrl.Path = "/pods" + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl.String(), nil) + if err != nil { + return nil, trace.Wrap(err, "creating request") + } + + res, err := client.Do(req) + if err != nil { + return nil, trace.Wrap(err, "performing request") + } + defer res.Body.Close() + + out := &v1.PodList{} + if err := json.NewDecoder(res.Body).Decode(out); err != nil { + return nil, trace.Wrap(err, "decoding response") + } + return out, nil +} diff --git a/lib/tbot/spiffe/workloadattest/kubernetes_unix_test.go b/lib/tbot/spiffe/workloadattest/kubernetes_unix_test.go new file mode 100644 index 0000000000000..79704cb775cf8 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/kubernetes_unix_test.go @@ -0,0 +1,178 @@ +//go:build unix + +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "context" + "encoding/json" + "net" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + "github.com/gravitational/teleport/lib/utils" +) + +func TestKubernetesAttestor_getContainerAndPodID(t *testing.T) { + log := utils.NewSlogLoggerForTests() + tests := []struct { + name string + wantPodID string + wantContainerID string + }{ + { + name: "k8s-real-docker-desktop", + wantPodID: "941f292f-a62d-48ab-b9a8-eec84d87b928", + wantContainerID: "3f79e718744418736d0f6b9958e08d44e969c6577068c33de1cc400d35aacec8", + }, + { + name: "k8s-real-orbstack", + wantPodID: "36827f77-691f-45aa-a470-0989cf3749c4", + wantContainerID: "64dd9bf5199ff782835247cb072e4842dc3d0135ef02f6498cb6bb6f37a320d2", + }, + { + name: "k8s-real-k3s-ubuntu-v1.28.6+k3s2", + wantPodID: "fecd2321-17b5-49b9-9f75-8c5be777fbfb", + wantContainerID: "397529d07efebd566f15dbc7e8af9f3ef586033f5e753adfa96b2bf730102c64", + }, + { + name: "k8s-real-gcp-v1.29.5-gke.1091002", + wantPodID: "61c266b0-6f75-4490-8d92-3c9ae4d02787", + wantContainerID: "9da25af0b548c8c60aa60f77f299ba727bf72d58248bd7528eb5390ffcce555a", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + require.NoError(t, os.MkdirAll(filepath.Join(tempDir, "proc", "1234"), 0755)) + require.NoError(t, utils.CopyFile( + filepath.Join("testdata", "mountfile", tt.name), + filepath.Join(tempDir, "proc", "1234", "mountinfo"), + 0755), + ) + attestor := &KubernetesAttestor{ + rootPath: tempDir, + log: log, + } + gotPodID, gotContainerID, err := attestor.getContainerAndPodID(1234) + assert.NoError(t, err) + assert.Equal(t, tt.wantPodID, gotPodID) + assert.Equal(t, tt.wantContainerID, gotContainerID) + }) + } +} + +func TestKubernetesAttestor_Attest(t *testing.T) { + t.Parallel() + log := utils.NewSlogLoggerForTests() + ctx := context.Background() + + mockToken := "FOOBARBUZZ" + mockPID := 1234 + // Value from k8s-real-gcp-v1.29.5-gke.1091002 + mockPodID := "61c266b0-6f75-4490-8d92-3c9ae4d02787" + + // Setup mock Kubelet Secure API + mockKubeletAPI := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if req.URL.Path != "/pods" { + http.NotFound(w, req) + return + } + out := v1.PodList{ + Items: []v1.Pod{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod", + Namespace: "default", + UID: types.UID(mockPodID), + Labels: map[string]string{ + "my-label": "my-label-value", + }, + }, + Spec: v1.PodSpec{ + ServiceAccountName: "my-service-account", + }, + }, + }, + } + w.WriteHeader(200) + assert.NoError(t, json.NewEncoder(w).Encode(out)) + })) + t.Cleanup(mockKubeletAPI.Close) + kubeletAddr := mockKubeletAPI.Listener.Addr().String() + host, port, err := net.SplitHostPort(kubeletAddr) + require.NoError(t, err) + portInt, err := strconv.Atoi(port) + require.NoError(t, err) + + // Setup mock filesystem + tmpDir := t.TempDir() + tokenPath := filepath.Join(tmpDir, "token") + require.NoError(t, os.WriteFile(tokenPath, []byte(mockToken), 0644)) + procPath := filepath.Join(tmpDir, "proc") + procPIDPath := filepath.Join(procPath, strconv.Itoa(mockPID)) + pidMountInfoPath := filepath.Join(procPIDPath, "mountinfo") + require.NoError(t, os.MkdirAll(procPIDPath, 0755)) + require.NoError(t, utils.CopyFile( + filepath.Join("testdata", "mountfile", "k8s-real-gcp-v1.29.5-gke.1091002"), + pidMountInfoPath, + 0755), + ) + + // Setup Attestor for mocks + attestor := NewKubernetesAttestor(KubernetesAttestorConfig{ + Enabled: true, + Kubelet: KubeletClientConfig{ + TokenPath: tokenPath, + SkipVerify: true, + SecurePort: portInt, + }, + }, log) + attestor.rootPath = tmpDir + attestor.kubeletClient.getEnv = func(s string) string { + env := map[string]string{ + "TELEPORT_NODE_NAME": host, + } + return env[s] + } + + att, err := attestor.Attest(ctx, mockPID) + assert.NoError(t, err) + assert.Equal(t, KubernetesAttestation{ + Attested: true, + ServiceAccount: "my-service-account", + Namespace: "default", + PodName: "my-pod", + PodUID: mockPodID, + Labels: map[string]string{ + "my-label": "my-label-value", + }, + }, att) +} diff --git a/lib/tbot/spiffe/workloadattest/kubernetes_windows.go b/lib/tbot/spiffe/workloadattest/kubernetes_windows.go new file mode 100644 index 0000000000000..27b11b13227ca --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/kubernetes_windows.go @@ -0,0 +1,41 @@ +//go:build windows + +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "context" + "log/slog" + + "github.com/gravitational/trace" +) + +// WindowsKubernetesAttestor is the windows stub for KubernetesAttestor. +type WindowsKubernetesAttestor struct { +} + +func (a WindowsKubernetesAttestor) Attest(_ context.Context, _ int) (KubernetesAttestation, error) { + return KubernetesAttestation{}, trace.NotImplemented("kubernetes attestation is not supported on windows") +} + +// NewKubernetesAttestor creates a new KubernetesAttestor. +func NewKubernetesAttestor(_ KubernetesAttestorConfig, _ *slog.Logger) *WindowsKubernetesAttestor { + return &WindowsKubernetesAttestor{} +} diff --git a/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-docker-desktop b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-docker-desktop new file mode 100644 index 0000000000000..4b18eb32c96ef --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-docker-desktop @@ -0,0 +1,22 @@ +752 518 0:203 / / rw,relatime master:65 - overlay overlay rw,lowerdir=/var/lib/desktop-containerd/daemon/io.containerd.snapshotter.v1.overlayfs/snapshots/140/fs:/var/lib/desktop-containerd/daemon/io.containerd.snapshotter.v1.overlayfs/snapshots/134/fs,upperdir=/var/lib/desktop-containerd/daemon/io.containerd.snapshotter.v1.overlayfs/snapshots/141/fs,workdir=/var/lib/desktop-containerd/daemon/io.containerd.snapshotter.v1.overlayfs/snapshots/141/work +753 752 0:205 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +754 752 0:206 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +755 754 0:207 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +756 752 0:201 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +757 756 0:31 /../../pod941f292f-a62d-48ab-b9a8-eec84d87b928/3f79e718744418736d0f6b9958e08d44e969c6577068c33de1cc400d35aacec8 /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +758 754 0:197 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +759 754 0:196 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +760 754 254:1 /kubelet/pods/941f292f-a62d-48ab-b9a8-eec84d87b928/containers/ubuntu/0a0e971b /dev/termination-log rw,relatime - ext4 /dev/vda1 rw,discard +761 752 254:1 /docker/containers/4bdc92c994044b7998d9288ce0dfd191bff269fe24040c7966381a32ee2566c6/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw,discard +762 752 254:1 /docker/containers/4bdc92c994044b7998d9288ce0dfd191bff269fe24040c7966381a32ee2566c6/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw,discard +763 752 254:1 /kubelet/pods/941f292f-a62d-48ab-b9a8-eec84d87b928/etc-hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw,discard +764 752 0:193 / /run/secrets/kubernetes.io/serviceaccount ro,relatime - tmpfs tmpfs rw,size=7926524k +519 753 0:205 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +536 753 0:205 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +537 753 0:205 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +538 753 0:205 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +539 753 0:205 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +540 753 0:206 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +541 753 0:206 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +567 753 0:206 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +582 756 0:208 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-gcp-v1.29.5-gke.1091002 b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-gcp-v1.29.5-gke.1091002 new file mode 100644 index 0000000000000..308bb7dce070d --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-gcp-v1.29.5-gke.1091002 @@ -0,0 +1,24 @@ +2649 2422 0:419 / / rw,relatime master:943 - overlay overlay rw,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/434/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/448/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/448/work +2650 2649 0:421 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +2651 2649 0:422 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +2652 2651 0:423 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +2653 2651 0:411 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +2654 2649 0:415 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +2655 2654 0:25 /../../kubepods-besteffort-pod61c266b0_6f75_4490_8d92_3c9ae4d02787.slice/cri-containerd-9da25af0b548c8c60aa60f77f299ba727bf72d58248bd7528eb5390ffcce555a.scope /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +2656 2649 8:1 /var/lib/kubelet/pods/61c266b0-6f75-4490-8d92-3c9ae4d02787/etc-hosts /etc/hosts rw,relatime - ext4 /dev/sda1 rw,commit=30 +2657 2651 8:1 /var/lib/kubelet/pods/61c266b0-6f75-4490-8d92-3c9ae4d02787/containers/ubuntu/32ca55fa /dev/termination-log rw,relatime - ext4 /dev/sda1 rw,commit=30 +2658 2649 8:1 /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/569976599cee4242e02a57be87909f6f08bc6615e346d57a1f07dfab7239c4ff/hostname /etc/hostname rw,nosuid,nodev,relatime - ext4 /dev/sda1 rw,commit=30 +2659 2649 8:1 /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/569976599cee4242e02a57be87909f6f08bc6615e346d57a1f07dfab7239c4ff/resolv.conf /etc/resolv.conf rw,nosuid,nodev,relatime - ext4 /dev/sda1 rw,commit=30 +2660 2651 0:408 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +2661 2649 0:407 / /run/secrets/kubernetes.io/serviceaccount ro,relatime - tmpfs tmpfs rw,size=2873312k +2423 2650 0:421 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +2424 2650 0:421 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +2425 2650 0:421 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +2426 2650 0:421 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +2427 2650 0:421 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +2428 2650 0:424 / /proc/acpi ro,relatime - tmpfs tmpfs ro +2429 2650 0:422 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +2430 2650 0:422 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +2431 2650 0:422 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +2432 2650 0:425 / /proc/scsi ro,relatime - tmpfs tmpfs ro +2433 2654 0:426 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-k3s-ubuntu-v1.28.6+k3s2 b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-k3s-ubuntu-v1.28.6+k3s2 new file mode 100644 index 0000000000000..b7987523080fc --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-k3s-ubuntu-v1.28.6+k3s2 @@ -0,0 +1,27 @@ +3029 2813 0:398 / / rw,relatime master:1634 - overlay overlay rw,lowerdir=/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/668/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/667/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/666/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/665/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/664/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/663/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/662/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/661/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/660/fs:/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/659/fs,upperdir=/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/1104/fs,workdir=/ssd/k3s/agent/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/1104/work,nouserxattr +2709 3029 0:418 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +3030 3029 0:419 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +2697 3030 0:420 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +3031 3030 0:264 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +3032 3029 0:272 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +3033 3032 0:29 /../../kubepods-besteffort-podfecd2321_17b5_49b9_9f75_8c5be777fbfb.slice/cri-containerd-397529d07efebd566f15dbc7e8af9f3ef586033f5e753adfa96b2bf730102c64.scope /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw +3034 3029 0:39 /kubelet/pods/fecd2321-17b5-49b9-9f75-8c5be777fbfb/etc-hosts /etc/hosts rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3035 3030 0:39 /kubelet/pods/fecd2321-17b5-49b9-9f75-8c5be777fbfb/containers/influxdb2/0b3cd38e /dev/termination-log rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3036 3029 0:39 /k3s/agent/containerd/io.containerd.grpc.v1.cri/sandboxes/dfb5782367e348095bcac6bc52e3f2428dbfdc4704c1f94897b7095831de0f29/hostname /etc/hostname rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3041 3029 0:39 /k3s/agent/containerd/io.containerd.grpc.v1.cri/sandboxes/dfb5782367e348095bcac6bc52e3f2428dbfdc4704c1f94897b7095831de0f29/resolv.conf /etc/resolv.conf rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3056 3030 0:172 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64 +3057 3029 0:39 /k3s/agent/containerd/io.containerd.grpc.v1.cri/containers/397529d07efebd566f15dbc7e8af9f3ef586033f5e753adfa96b2bf730102c64/volumes/e8d71e077278681842902223965b71754c3cead29651ea453b1022a0715a64ae /etc/influxdb2 rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3067 3029 0:39 /k3s/storage/pvc-fe4e77b2-8676-40b8-acca-bf0a7208ee37_influxdb_influxdb-influxdb2 /var/lib/influxdb2 rw,noatime - zfs ssd rw,xattr,posixacl,casesensitive +3068 3029 0:124 / /run/secrets/kubernetes.io/serviceaccount ro,relatime - tmpfs tmpfs rw,size=49238972k,inode64 +3362 2709 0:418 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +3364 2709 0:418 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +3365 2709 0:418 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +3381 2709 0:418 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +3382 2709 0:418 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +3383 2709 0:431 / /proc/asound ro,relatime - tmpfs tmpfs ro,inode64 +3384 2709 0:432 / /proc/acpi ro,relatime - tmpfs tmpfs ro,inode64 +3385 2709 0:419 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +3386 2709 0:419 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +3387 2709 0:419 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755,inode64 +3388 2709 0:433 / /proc/scsi ro,relatime - tmpfs tmpfs ro,inode64 +3389 3032 0:434 / /sys/firmware ro,relatime - tmpfs tmpfs ro,inode64 \ No newline at end of file diff --git a/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-orbstack b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-orbstack new file mode 100644 index 0000000000000..7aff934e8cde8 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/testdata/mountfile/k8s-real-orbstack @@ -0,0 +1,24 @@ +705 559 0:163 / / ro,relatime master:126 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/Z45N3JIQYJQ54CBI7H3XMKVR5I:/var/lib/docker/overlay2/l/7KUPS4PU3O5IJL4EIRN7FMAOYD:/var/lib/docker/overlay2/l/ETEFQDOQ5PLMGLRYOA5RFON3OS:/var/lib/docker/overlay2/l/2B54A5B3XLE76YZCPIVK6UA7RI:/var/lib/docker/overlay2/l/KJGEGGJV7KZFUYQL46H7NCKSGR:/var/lib/docker/overlay2/l/UTJK53EUHIMBZO4NRBU7FR4KZ7:/var/lib/docker/overlay2/l/KHWFISJTIZFY3EZO27BU32LI6L:/var/lib/docker/overlay2/l/CD7NUI35TQGZLK6OY625DPG75E:/var/lib/docker/overlay2/l/MTGDF36JSTP6LT4N5SJM7JQVZF:/var/lib/docker/overlay2/l/56576N3DLXLKEFS4BVEDLETXGY:/var/lib/docker/overlay2/l/TEJQCUGT2ZHWVW65FILDOZNO3Y:/var/lib/docker/overlay2/l/ESKTCIGN4JBSHMNLLDE5UWBKGR:/var/lib/docker/overlay2/l/K4SEMZCPJSC5OOK4HNSTJ5EADF:/var/lib/docker/overlay2/l/OFXCSYIR4UIHYMYJQYQNAP2IVZ:/var/lib/docker/overlay2/l/HHM5GPXHH5O7FGYKI3DAF2TIE3:/var/lib/docker/overlay2/l/6EQX2D3HPZETMHLYONEJBT57GT:/var/lib/docker/overlay2/l/IB4VF3AIY6HVGYQ4CLLZD2HEMO:/var/lib/docker/overlay2/l/4SXNG5ILJTM4EGDS2DH2YODOHB:/var/lib/docker/overlay2/l/DA2FKFC5NFV4LTLQ7KXZJ7QH5N:/var/lib/docker/overlay2/l/W54AWW6M7O6OLVIFMHMPXIDZG5,upperdir=/var/lib/docker/overlay2/a5af8a9c1badd3ba20f186c2da75c1bd0a6a832227388d4936ce9e7729fbeec4/diff,workdir=/var/lib/docker/overlay2/a5af8a9c1badd3ba20f186c2da75c1bd0a6a832227388d4936ce9e7729fbeec4/work +706 705 0:169 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +707 705 0:170 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +708 707 0:171 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +709 705 0:138 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +710 709 0:31 /../../pod36827f77-691f-45aa-a470-0989cf3749c4/64dd9bf5199ff782835247cb072e4842dc3d0135ef02f6498cb6bb6f37a320d2 /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw,nsdelegate +711 707 0:134 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +712 707 0:132 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +713 707 0:36 /k8s/default/kubelet/pods/36827f77-691f-45aa-a470-0989cf3749c4/containers/teleport/d1a0d450 /dev/termination-log rw,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +714 705 0:36 /k8s/default/kubelet/pods/36827f77-691f-45aa-a470-0989cf3749c4/volumes/kubernetes.io~configmap/config /etc/teleport ro,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +715 705 0:119 / /etc/teleport-secrets ro,relatime - tmpfs tmpfs rw,size=8121144k +716 705 0:36 /docker/containers/1927b688b6cc740a4d73f211b67b7573503ff3dd401d3e8d43dd449d032ce8d2/resolv.conf /etc/resolv.conf ro,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +717 705 0:36 /docker/containers/1927b688b6cc740a4d73f211b67b7573503ff3dd401d3e8d43dd449d032ce8d2/hostname /etc/hostname ro,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +718 705 0:36 /k8s/default/kubelet/pods/36827f77-691f-45aa-a470-0989cf3749c4/etc-hosts /etc/hosts rw,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +719 705 0:36 /k8s/default/kubelet/pods/36827f77-691f-45aa-a470-0989cf3749c4/volumes/kubernetes.io~empty-dir/data /var/lib/teleport rw,noatime - btrfs /dev/vdb1 rw,nodatasum,nodatacow,ssd,discard,space_cache=v2,subvolid=5,subvol=/ +720 705 0:114 / /var/run/secrets/kubernetes.io/serviceaccount ro,relatime - tmpfs tmpfs rw,size=8121144k +535 706 0:169 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +541 706 0:169 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +553 706 0:169 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +554 706 0:169 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +556 706 0:169 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +562 706 0:170 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +566 706 0:170 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +567 709 0:167 / /sys/firmware ro,relatime - tmpfs tmpfs ro \ No newline at end of file diff --git a/lib/tbot/spiffe/workloadattest/unix.go b/lib/tbot/spiffe/workloadattest/unix.go new file mode 100644 index 0000000000000..2f67fd7f6bad2 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/unix.go @@ -0,0 +1,122 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "context" + "log/slog" + + "github.com/gravitational/trace" + "github.com/shirou/gopsutil/v4/process" +) + +// UnixAttestation holds the Unix process information retrieved from the +// workload attestation process. +type UnixAttestation struct { + // Attested is true if the PID was successfully attested to a Unix + // process. This indicates the validity of the rest of the fields. + Attested bool + // PID is the process ID of the attested process. + PID int + // UID is the primary user ID of the attested process. + UID int + // GID is the primary group ID of the attested process. + GID int +} + +// LogValue implements slog.LogValue to provide a nicely formatted set of +// log keys for a given attestation. +func (a UnixAttestation) LogValue() slog.Value { + values := []slog.Attr{ + slog.Bool("attested", a.Attested), + } + if a.Attested { + values = append(values, + slog.Int("uid", a.UID), + slog.Int("pid", a.PID), + slog.Int("gid", a.GID), + ) + } + return slog.GroupValue(values...) +} + +// UnixAttestor attests a process id to a Unix process. +type UnixAttestor struct { +} + +// NewUnixAttestor returns a new UnixAttestor. +func NewUnixAttestor() *UnixAttestor { + return &UnixAttestor{} +} + +// Attest attests a process id to a Unix process. +func (a *UnixAttestor) Attest(ctx context.Context, pid int) (UnixAttestation, error) { + p, err := process.NewProcessWithContext(ctx, int32(pid)) + if err != nil { + return UnixAttestation{}, trace.Wrap(err, "getting process") + } + + att := UnixAttestation{ + Attested: true, + PID: pid, + } + // On Linux: + // Real, effective, saved, and file system GIDs + // On Darwin: + // Effective, effective, saved GIDs + gids, err := p.Gids() + if err != nil { + return UnixAttestation{}, trace.Wrap(err, "getting gids") + } + // We generally want to select the effective GID. + switch len(gids) { + case 0: + // error as none returned + return UnixAttestation{}, trace.BadParameter("no gids returned") + case 1: + // Only one GID - this is unusual but let's take it. + att.GID = int(gids[0]) + default: + // Take the index 1 entry as this is effective + att.GID = int(gids[1]) + } + + // On Linux: + // Real, effective, saved set, and file system UIDs + // On Darwin: + // Effective + uids, err := p.Uids() + if err != nil { + return UnixAttestation{}, trace.Wrap(err, "getting uids") + } + // We generally want to select the effective GID. + switch len(uids) { + case 0: + // error as none returned + return UnixAttestation{}, trace.BadParameter("no uids returned") + case 1: + // Only one UID, we expect this on Darwin to be the Effective UID + att.UID = int(uids[0]) + default: + // Take the index 1 entry as this is Effective UID on Linux + att.UID = int(uids[1]) + } + + return att, nil +} diff --git a/lib/tbot/spiffe/workloadattest/unix_test.go b/lib/tbot/spiffe/workloadattest/unix_test.go new file mode 100644 index 0000000000000..667fdcffb2634 --- /dev/null +++ b/lib/tbot/spiffe/workloadattest/unix_test.go @@ -0,0 +1,46 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package workloadattest + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestUnixAttestor_Attest(t *testing.T) { + t.Parallel() + ctx := context.Background() + + pid := os.Getpid() + uid := os.Getuid() + gid := os.Getgid() + + attestor := NewUnixAttestor() + att, err := attestor.Attest(ctx, pid) + require.NoError(t, err) + require.Equal(t, UnixAttestation{ + Attested: true, + PID: pid, + UID: uid, + GID: gid, + }, att) +} diff --git a/lib/teleterm/apiserver/apiserver.go b/lib/teleterm/apiserver/apiserver.go index d54531afca218..f622fe5614437 100644 --- a/lib/teleterm/apiserver/apiserver.go +++ b/lib/teleterm/apiserver/apiserver.go @@ -92,10 +92,14 @@ func (s *APIServer) Serve() error { // Stop stops the server and closes all listeners func (s *APIServer) Stop() { - s.grpcServer.GracefulStop() + // Gracefully stopping the gRPC server takes a second or two. Closing the VNet service is almost + // immediate. Closing the VNet service before the gRPC server gives some time for the VNet admin + // process to notice that the client is gone and shut down as well. if err := s.vnetService.Close(); err != nil { log.WithError(err).Error("Error while closing VNet service") } + + s.grpcServer.GracefulStop() } func newListener(hostAddr string, listeningC chan<- utils.NetAddr) (net.Listener, error) { diff --git a/lib/teleterm/apiserver/handler/time_converter.go b/lib/teleterm/apiserver/handler/time_converter.go index 550c0ebf037e1..6bf0cd60ed16f 100644 --- a/lib/teleterm/apiserver/handler/time_converter.go +++ b/lib/teleterm/apiserver/handler/time_converter.go @@ -1,18 +1,18 @@ -/** - * Copyright 2024 Gravitational, Inc. - * - * 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. - */ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package handler diff --git a/lib/teleterm/apiserver/handler/time_converter_test.go b/lib/teleterm/apiserver/handler/time_converter_test.go index 1e6215b7f8beb..f0eee31041d42 100644 --- a/lib/teleterm/apiserver/handler/time_converter_test.go +++ b/lib/teleterm/apiserver/handler/time_converter_test.go @@ -1,18 +1,18 @@ -/** - * Copyright 2024 Gravitational, Inc. - * - * 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. - */ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package handler diff --git a/lib/teleterm/clusters/cluster_apps.go b/lib/teleterm/clusters/cluster_apps.go index 65f49e2ad377d..035b27a165862 100644 --- a/lib/teleterm/clusters/cluster_apps.go +++ b/lib/teleterm/clusters/cluster_apps.go @@ -169,6 +169,7 @@ func (c *Cluster) ReissueAppCert(ctx context.Context, clusterClient *client.Clus AWSRoleARN: "", AzureIdentity: "", GCPServiceAccount: "", + URI: app.GetURI(), } // TODO (Joerger): DELETE IN v17.0.0 diff --git a/lib/teleterm/daemon/mfaprompt.go b/lib/teleterm/daemon/mfaprompt.go index 5a797c21f39e1..82404ea5d5010 100644 --- a/lib/teleterm/daemon/mfaprompt.go +++ b/lib/teleterm/daemon/mfaprompt.go @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package daemon diff --git a/lib/teleterm/vnet/service_daemon_darwin.go b/lib/teleterm/vnet/service_daemon_darwin.go index 67b55d15b8b40..bbcb01c80bad0 100644 --- a/lib/teleterm/vnet/service_daemon_darwin.go +++ b/lib/teleterm/vnet/service_daemon_darwin.go @@ -21,20 +21,14 @@ package vnet import ( "context" - "os" "github.com/gravitational/trace" api "github.com/gravitational/teleport/gen/proto/go/teleport/lib/teleterm/vnet/v1" - "github.com/gravitational/teleport/lib/vnet" vnetdaemon "github.com/gravitational/teleport/lib/vnet/daemon" ) func (s *Service) GetBackgroundItemStatus(ctx context.Context, req *api.GetBackgroundItemStatusRequest) (*api.GetBackgroundItemStatusResponse, error) { - if os.Getenv(vnet.EnvFeatureFlag) != "yes" { - return nil, trace.NotImplemented("tsh was built with VNet daemon support, but the feature flag is not enabled") - } - status, err := vnetdaemon.DaemonStatus() if err != nil { return nil, trace.Wrap(err) @@ -55,6 +49,8 @@ func backgroundItemStatusFromServiceStatus(status vnetdaemon.ServiceStatus) api. return api.BackgroundItemStatus_BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL case vnetdaemon.ServiceStatusNotFound: return api.BackgroundItemStatus_BACKGROUND_ITEM_STATUS_NOT_FOUND + case vnetdaemon.ServiceStatusNotSupported: + return api.BackgroundItemStatus_BACKGROUND_ITEM_STATUS_NOT_SUPPORTED default: return api.BackgroundItemStatus_BACKGROUND_ITEM_STATUS_UNSPECIFIED } diff --git a/lib/tlsca/ca.go b/lib/tlsca/ca.go index ff67923ae8ae6..b7dc63b39b843 100644 --- a/lib/tlsca/ca.go +++ b/lib/tlsca/ca.go @@ -228,6 +228,9 @@ type RouteToApp struct { // GCPServiceAccount is the GCP service account to assume when accessing GCP API. GCPServiceAccount string + + // URI is the URI of the app. This is the internal endpoint where the application is running and isn't user-facing. + URI string } // RouteToDatabase contains routing information for databases. @@ -304,6 +307,7 @@ func (id *Identity) GetEventIdentity() events.Identity { AWSRoleARN: id.RouteToApp.AWSRoleARN, AzureIdentity: id.RouteToApp.AzureIdentity, GCPServiceAccount: id.RouteToApp.GCPServiceAccount, + URI: id.RouteToApp.URI, } } var routeToDatabase *events.RouteToDatabase diff --git a/lib/utils/diagnostics/latency/monitor.go b/lib/utils/diagnostics/latency/monitor.go index f5a5fa8ca01d4..392607e3dfbfd 100644 --- a/lib/utils/diagnostics/latency/monitor.go +++ b/lib/utils/diagnostics/latency/monitor.go @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package latency diff --git a/lib/utils/diagnostics/latency/monitor_test.go b/lib/utils/diagnostics/latency/monitor_test.go index a14c29998d2dd..85089d4e21313 100644 --- a/lib/utils/diagnostics/latency/monitor_test.go +++ b/lib/utils/diagnostics/latency/monitor_test.go @@ -1,16 +1,18 @@ -// Copyright 2023 Gravitational, Inc +// Teleport +// Copyright (C) 2024 Gravitational, Inc. // -// 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 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. // -// 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. +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package latency diff --git a/lib/utils/interval/interval.go b/lib/utils/interval/interval.go index 67003c98c4416..2bde9f81f66b5 100644 --- a/lib/utils/interval/interval.go +++ b/lib/utils/interval/interval.go @@ -21,6 +21,7 @@ package interval import ( "errors" "sync" + "sync/atomic" "time" "github.com/jonboulle/clockwork" @@ -38,8 +39,9 @@ import ( type Interval struct { cfg Config ch chan time.Time - reset chan struct{} + reset chan time.Duration fire chan struct{} + lastTick atomic.Pointer[time.Time] closeOnce sync.Once done chan struct{} } @@ -88,7 +90,7 @@ func New(cfg Config) *Interval { interval := &Interval{ ch: make(chan time.Time, 1), cfg: cfg, - reset: make(chan struct{}), + reset: make(chan time.Duration), fire: make(chan struct{}), done: make(chan struct{}), } @@ -121,7 +123,15 @@ func (i *Interval) Stop() { // jitter(duration) regardless of current timer progress). func (i *Interval) Reset() { select { - case i.reset <- struct{}{}: + case i.reset <- time.Duration(0): + case <-i.done: + } +} + +// ResetTo resets the interval to the target duration for the next tick. +func (i *Interval) ResetTo(d time.Duration) { + select { + case i.reset <- d: case <-i.done: } } @@ -140,6 +150,20 @@ func (i *Interval) Next() <-chan time.Time { return i.ch } +// LastTick gets the most recent tick if the interval has fired at least once. Note that the +// tick returned by this method is the last *generated* tick, not necessarily the last tick +// that was *observed* by the consumer of the interval. +func (i *Interval) LastTick() (tick time.Time, ok bool) { + if t := i.lastTick.Load(); t != nil { + return *t, true + } + return time.Time{}, false +} + +func (i *Interval) setLastTick(tick time.Time) { + i.lastTick.Store(&tick) +} + // duration gets the duration of the interval. Each call applies the jitter // if one was supplied. func (i *Interval) duration() time.Duration { @@ -163,13 +187,17 @@ func (i *Interval) run(timer clockwork.Timer) { // output channel is set. timer.Reset(i.duration()) ch = i.ch - case <-i.reset: + i.setLastTick(tick) + case d := <-i.reset: // stop and drain timer if !timer.Stop() { <-timer.Chan() } + if d == 0 { + d = i.duration() + } // re-set the timer - timer.Reset(i.duration()) + timer.Reset(d) // ensure we don't send any pending ticks ch = nil case <-i.fire: @@ -182,6 +210,7 @@ func (i *Interval) run(timer clockwork.Timer) { // simulate firing of the timer tick = time.Now() ch = i.ch + i.setLastTick(tick) case ch <- tick: // tick has been sent, set ch back to nil to prevent // double-send and wait for next timer firing diff --git a/lib/utils/interval/interval_test.go b/lib/utils/interval/interval_test.go index 281df018f9919..52a0692f91b87 100644 --- a/lib/utils/interval/interval_test.go +++ b/lib/utils/interval/interval_test.go @@ -24,9 +24,39 @@ import ( "testing" "time" + "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" ) +// TestLastTick verifies that the LastTick method returns the last tick time as expected. +func TestLastTick(t *testing.T) { + clock := clockwork.NewFakeClock() + interval := New(Config{ + Duration: time.Minute, + Clock: clock, + }) + + _, ok := interval.LastTick() + require.False(t, ok) + + timeout := time.After(time.Second * 30) + for i := 0; i < 3; i++ { + clock.Advance(time.Minute) + + var tick time.Time + select { + case tick = <-interval.Next(): + case <-timeout: + t.Fatal("timeout waiting for tick") + } + require.Equal(t, clock.Now(), tick) + + tick, ok = interval.LastTick() + require.True(t, ok) + require.Equal(t, clock.Now(), tick) + } +} + // TestIntervalReset verifies the basic behavior of the interval reset functionality. // Since time based tests tend to be flaky, this test passes if it has a >50% success // rate (i.e. >50% of resets seemed to have actually extended the timer successfully). @@ -83,6 +113,53 @@ func TestIntervalReset(t *testing.T) { require.Greater(t, success.Load(), failure.Load()) } +// TestIntervalResetTo verifies the basic behavior of the interval ResetTo method. +// Since time based tests tend to be flaky, this test passes if it has a >50% success +// rate (i.e. >50% of ResetTo calls seemed to have changed the timer's behavior as expected). +func TestIntervalResetTo(t *testing.T) { + const workers = 1_000 + const ticks = 12 + const longDuration = time.Millisecond * 800 + const shortDuration = time.Millisecond * 200 + t.Parallel() + + var success, failure atomic.Uint64 + var wg sync.WaitGroup + + for i := 0; i < workers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + + interval := New(Config{ + Duration: longDuration, + }) + defer interval.Stop() + + start := time.Now() + + for i := 0; i < ticks; i++ { + interval.ResetTo(shortDuration) + <-interval.Next() + } + + elapsed := time.Since(start) + // if the above works completed before the expected minimum time + // to complete all ticks as long ticks, we assume that ResetTo has + // successfully shortened the interval. + if elapsed < longDuration*time.Duration(ticks) { + success.Add(1) + } else { + failure.Add(1) + } + }() + } + + wg.Wait() + + require.Greater(t, success.Load(), failure.Load()) +} + func TestNewNoop(t *testing.T) { t.Parallel() i := NewNoop() diff --git a/lib/utils/replace.go b/lib/utils/replace.go index cf3448247e6f0..686c39127d532 100644 --- a/lib/utils/replace.go +++ b/lib/utils/replace.go @@ -149,14 +149,14 @@ const ( // input is the resource we are checking for access. // resources is a list of resources that the user has access to - collected from // their roles that match the Kubernetes cluster where the resource is defined. -func KubeResourceMatchesRegex(input types.KubernetesResource, resources []types.KubernetesResource) (bool, error) { +// cond is the deny or allow condition of the role that we are evaluating. +func KubeResourceMatchesRegex(input types.KubernetesResource, resources []types.KubernetesResource, cond types.RoleConditionType) (bool, error) { if len(input.Verbs) != 1 { return false, trace.BadParameter("only one verb is supported, input: %v", input.Verbs) } // isClusterWideResource is true if the resource is cluster-wide, e.g. a // namespace resource or a clusterrole. isClusterWideResource := slices.Contains(types.KubernetesClusterWideResourceKinds, input.Kind) - verb := input.Verbs[0] // If the user is list/read/watch a namespace, they should be able to see the // namespace they have resources defined for. @@ -191,7 +191,7 @@ func KubeResourceMatchesRegex(input types.KubernetesResource, resources []types. if ok, err := MatchString(input.Namespace, resource.Name); err != nil || ok { return ok, trace.Wrap(err) } - case targetsReadOnlyNamespace && resource.Kind != types.KindKubeNamespace && resource.Namespace != "": + case targetsReadOnlyNamespace && cond == types.Allow && resource.Kind != types.KindKubeNamespace && resource.Namespace != "": // If the user requests a read-only namespace get/list/watch, they should // be able to see the list of namespaces they have resources defined in. // This means that if the user has access to pods in the "foo" namespace, @@ -250,7 +250,6 @@ func KubeResourceCouldMatchRules(input types.KubernetesResource, resources []typ // permissions for. targetsReadOnlyNamespace := input.Kind == types.KindKubeNamespace && slices.Contains([]string{types.KubeVerbGet, types.KubeVerbList, types.KubeVerbWatch}, verb) - for _, resource := range resources { // If the resource has a wildcard verb, it matches all verbs. // Otherwise, the resource must have the verb we're looking for otherwise @@ -278,19 +277,13 @@ func KubeResourceCouldMatchRules(input types.KubernetesResource, resources []typ if ok, err := MatchString(input.Namespace, resource.Name); err != nil || ok && isAllowOrFullDeny { return isAllowOrFullDeny || isDeny, trace.Wrap(err) } - case targetsReadOnlyNamespace && resource.Kind != types.KindKubeNamespace && resource.Namespace != "": + case targetsReadOnlyNamespace && !isDeny && resource.Kind != types.KindKubeNamespace && resource.Namespace != "": // If the user requests a read-only namespace get/list/watch, they should // be able to see the list of namespaces they have resources defined in. // This means that if the user has access to pods in the "foo" namespace, // they should be able to see the "foo" namespace in the list of namespaces // but only if the request is read-only. - isAllowOrFullDeny := !isDeny || resource.Name == types.Wildcard && resource.Namespace == types.Wildcard - if isAllowOrFullDeny { - return isAllowOrFullDeny, nil - } - if ok, err := MatchString(input.Name, resource.Namespace); err != nil || ok && isAllowOrFullDeny { - return ok && isAllowOrFullDeny, trace.Wrap(err) - } + return true, nil default: if input.Kind != resource.Kind && resource.Kind != types.Wildcard { continue diff --git a/lib/utils/replace_test.go b/lib/utils/replace_test.go index 1c424ec2f30a7..e2583d4606500 100644 --- a/lib/utils/replace_test.go +++ b/lib/utils/replace_test.go @@ -162,6 +162,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { name string input types.KubernetesResource resources []types.KubernetesResource + action types.RoleConditionType matches bool assert require.ErrorAssertionFunc }{ @@ -180,8 +181,102 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.Error, + action: types.Allow, + matches: false, + }, + { + name: "list namespace matches resource", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Verbs: []string{types.KubeVerbList}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + assert: require.NoError, + action: types.Allow, + matches: true, + }, + { + name: "list namespace doesn't match denying secrets", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Verbs: []string{types.KubeVerbList}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + assert: require.NoError, + action: types.Deny, matches: false, }, + { + name: "get namespace match denying everything", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Name: "default", + Verbs: []string{types.KubeVerbGet}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.Wildcard, + Namespace: types.Wildcard, + Name: types.Wildcard, + Verbs: []string{types.Wildcard}, + }, + }, + assert: require.NoError, + action: types.Deny, + matches: true, + }, + { + name: "get namespace doesn't match denying secrets", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Name: "default", + Verbs: []string{types.KubeVerbGet}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + assert: require.NoError, + action: types.Deny, + matches: false, + }, + { + name: "get secret matches denying secrets", + input: types.KubernetesResource{ + Kind: types.KindKubeSecret, + Name: "default", + Verbs: []string{types.KubeVerbGet}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + assert: require.NoError, + action: types.Deny, + matches: true, + }, { name: "input matches single resource with wildcard verb", input: types.KubernetesResource{ @@ -199,6 +294,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -218,6 +314,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -237,6 +334,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, { @@ -255,6 +353,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, { @@ -286,6 +385,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -305,6 +405,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -324,6 +425,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, { @@ -342,6 +444,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { Verbs: []string{types.Wildcard}, }, }, + action: types.Allow, assert: require.Error, }, { @@ -359,6 +462,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { Name: "podname", }, }, + action: types.Allow, assert: require.NoError, }, { @@ -376,6 +480,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -394,6 +499,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -412,6 +518,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, { @@ -430,6 +537,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, @@ -449,6 +557,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, @@ -468,6 +577,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -486,6 +596,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, @@ -505,6 +616,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: true, }, { @@ -523,6 +635,7 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, { @@ -547,12 +660,13 @@ func TestKubeResourceMatchesRegex(t *testing.T) { }, }, assert: require.NoError, + action: types.Allow, matches: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := KubeResourceMatchesRegex(tt.input, tt.resources) + got, err := KubeResourceMatchesRegex(tt.input, tt.resources, tt.action) tt.assert(t, err) require.Equal(t, tt.matches, got) }) @@ -619,6 +733,42 @@ func TestKubeResourceCouldMatchRules(t *testing.T) { assert: require.NoError, matches: true, }, + { + name: "input doesn't match kind deny", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Verbs: []string{types.KubeVerbList}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + action: types.Deny, + assert: require.NoError, + matches: false, + }, + { + name: "input doesn't match kind allow", + input: types.KubernetesResource{ + Kind: types.KindNamespace, + Verbs: []string{types.KubeVerbList}, + }, + resources: []types.KubernetesResource{ + { + Kind: types.KindKubeSecret, + Namespace: "*", + Name: "*", + Verbs: []string{types.Wildcard}, + }, + }, + action: types.Allow, + assert: require.NoError, + matches: true, + }, { name: "input matches single resource with wildcard verb", input: types.KubernetesResource{ @@ -1030,9 +1180,10 @@ func TestKubeResourceCouldMatchRules(t *testing.T) { }, }, assert: require.NoError, - matches: true, + matches: false, action: types.Deny, }, + { name: "list namespace with resource denying update access to namespace", input: types.KubernetesResource{ diff --git a/lib/utils/testhelpers.go b/lib/utils/testhelpers.go index 82c72147278ce..446624717cf11 100644 --- a/lib/utils/testhelpers.go +++ b/lib/utils/testhelpers.go @@ -94,32 +94,32 @@ func RunTestBackgroundTask(ctx context.Context, t *testing.T, task *TestBackgrou } // RequireRoot skips the current test if it is not running as root. -func RequireRoot(t *testing.T) { - t.Helper() +func RequireRoot(tb testing.TB) { + tb.Helper() if os.Geteuid() != 0 { - t.Skip("This test will be skipped because tests are not being run as root.") + tb.Skip("This test will be skipped because tests are not being run as root.") } } -func generateUsername(t *testing.T) string { +func generateUsername(tb testing.TB) string { suffix := make([]byte, 8) _, err := rand.Read(suffix) - require.NoError(t, err) + require.NoError(tb, err) return fmt.Sprintf("teleport-%x", suffix) } // GenerateLocalUsername generates the username for a local user that does not // already exists (but it does not create the user). -func GenerateLocalUsername(t *testing.T) string { +func GenerateLocalUsername(tb testing.TB) string { const maxAttempts = 10 for i := 0; i < maxAttempts; i++ { - login := generateUsername(t) + login := generateUsername(tb) _, err := user.Lookup(login) if errors.Is(err, user.UnknownUserError(login)) { return login } - require.NoError(t, err) + require.NoError(tb, err) } - t.Fatalf("Unable to generate unused username after %v attempts", maxAttempts) + tb.Fatalf("Unable to generate unused username after %v attempts", maxAttempts) return "" } diff --git a/lib/vnet/customdnszonevalidator.go b/lib/vnet/customdnszonevalidator.go index a328df5bea1a6..752606581eaa4 100644 --- a/lib/vnet/customdnszonevalidator.go +++ b/lib/vnet/customdnszonevalidator.go @@ -19,7 +19,6 @@ package vnet import ( "context" "errors" - "log/slog" "net" "slices" "sync" @@ -67,7 +66,7 @@ func (c *customDNSZoneValidator) validate(ctx context.Context, clusterName, cust } requiredTXTRecord := clusterTXTRecordPrefix + clusterName - slog.InfoContext(ctx, "Checking validity of custom DNS zone by querying for required TXT record.", "zone", customDNSZone, "record", requiredTXTRecord) + log.InfoContext(ctx, "Checking validity of custom DNS zone by querying for required TXT record.", "zone", customDNSZone, "record", requiredTXTRecord) records, err := c.lookupTXT(ctx, customDNSZone) if err != nil { @@ -83,7 +82,7 @@ func (c *customDNSZoneValidator) validate(ctx context.Context, clusterName, cust return trace.Wrap(errNoTXTRecord(customDNSZone, requiredTXTRecord)) } - slog.InfoContext(ctx, "Custom DNS zone has valid TXT record.", "zone", customDNSZone, "cluster", clusterName) + log.InfoContext(ctx, "Custom DNS zone has valid TXT record.", "zone", customDNSZone, "cluster", clusterName) c.mu.Lock() defer c.mu.Unlock() diff --git a/lib/vnet/daemon/client_darwin.go b/lib/vnet/daemon/client_darwin.go index 9c53d8a7ee580..cdaddab625603 100644 --- a/lib/vnet/daemon/client_darwin.go +++ b/lib/vnet/daemon/client_darwin.go @@ -30,7 +30,6 @@ import ( "fmt" "os" "path/filepath" - "runtime" "strconv" "strings" "time" @@ -201,6 +200,8 @@ const ( ServiceStatusEnabled ServiceStatus = 1 ServiceStatusRequiresApproval ServiceStatus = 2 ServiceStatusNotFound ServiceStatus = 3 + // ServiceStatusNotSupported is returned by us when macOS version is < 13.0. + ServiceStatusNotSupported ServiceStatus = -1 ) func (s ServiceStatus) String() string { @@ -213,6 +214,8 @@ func (s ServiceStatus) String() string { return "requires approval" case ServiceStatusNotFound: return "not found" + case ServiceStatusNotSupported: + return "not supported" default: return strconv.Itoa(int(s)) } @@ -261,28 +264,20 @@ func startByCalling(ctx context.Context, bundlePath string, config Config) error errC := make(chan error, 1) go func() { - var pinner runtime.Pinner - defer pinner.Unpin() - req := C.StartVnetRequest{ bundle_path: C.CString(bundlePath), - vnet_config: &C.VnetConfig{ - socket_path: C.CString(config.SocketPath), - ipv6_prefix: C.CString(config.IPv6Prefix), - dns_addr: C.CString(config.DNSAddr), - home_path: C.CString(config.HomePath), - }, + socket_path: C.CString(config.SocketPath), + ipv6_prefix: C.CString(config.IPv6Prefix), + dns_addr: C.CString(config.DNSAddr), + home_path: C.CString(config.HomePath), } defer func() { C.free(unsafe.Pointer(req.bundle_path)) - C.free(unsafe.Pointer(req.vnet_config.socket_path)) - C.free(unsafe.Pointer(req.vnet_config.ipv6_prefix)) - C.free(unsafe.Pointer(req.vnet_config.dns_addr)) - C.free(unsafe.Pointer(req.vnet_config.home_path)) + C.free(unsafe.Pointer(req.socket_path)) + C.free(unsafe.Pointer(req.ipv6_prefix)) + C.free(unsafe.Pointer(req.dns_addr)) + C.free(unsafe.Pointer(req.home_path)) }() - // Structs passed directly as arguments to cgo functions are automatically pinned. - // However, structs within structs have to be pinned by hand. - pinner.Pin(req.vnet_config) var res C.StartVnetResult defer func() { @@ -320,7 +315,15 @@ func startByCalling(ctx context.Context, bundlePath string, config Config) error } if errorDomain == nsCocoaErrorDomain && errorCode == errorCodeNSXPCConnectionCodeSigningRequirementFailure { - errC <- trace.Wrap(errXPCConnectionCodeSigningRequirementFailure, "the daemon does not appear to be code signed correctly") + // If the client submits TELEPORT_HOME to which the user doesn't have access, the daemon is + // going to shut down with an error soon after starting. Because of that, macOS won't have + // enough time to perform the verification of the code signing requirement of the daemon, as + // requested by the client. + // + // In that scenario, macOS is going to simply error that connection with + // NSXPCConnectionCodeSigningRequirementFailure. Without looking at logs, it's not possible + // to differentiate that from a "legitimate" failure caused by an incorrect requirement. + errC <- trace.Wrap(errXPCConnectionCodeSigningRequirementFailure, "either daemon is not signed correctly or it shut down before signature could be verified") return } diff --git a/lib/vnet/daemon/client_darwin.h b/lib/vnet/daemon/client_darwin.h index e362c4add527b..5afa0dffe7db5 100644 --- a/lib/vnet/daemon/client_darwin.h +++ b/lib/vnet/daemon/client_darwin.h @@ -38,7 +38,11 @@ void OpenSystemSettingsLoginItems(void); typedef struct StartVnetRequest { const char *bundle_path; - VnetConfig *vnet_config; + + const char *socket_path; + const char *ipv6_prefix; + const char *dns_addr; + const char *home_path; } StartVnetRequest; typedef struct StartVnetResult { @@ -73,7 +77,7 @@ void StartVnet(StartVnetRequest *request, StartVnetResult *outResult); void InvalidateDaemonClient(void); @interface VNEDaemonClient : NSObject -- (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *error))completion; +- (void)startVnet:(VNEConfig *)config completion:(void (^)(NSError *error))completion; // invalidate executes all outstanding reply blocks, error handling blocks, // and invalidation blocks and forbids from sending or receiving new messages. - (void)invalidate; diff --git a/lib/vnet/daemon/client_darwin.m b/lib/vnet/daemon/client_darwin.m index b131926d04038..3d5d50226570f 100644 --- a/lib/vnet/daemon/client_darwin.m +++ b/lib/vnet/daemon/client_darwin.m @@ -73,15 +73,11 @@ void OpenSystemSettingsLoginItems(void) { } } -@interface VNEDaemonClient () - -@property(nonatomic, strong, readwrite) NSXPCConnection *connection; -@property(nonatomic, strong, readonly) NSString *bundlePath; -@property(nonatomic, strong, readonly) NSString *codeSigningRequirement; - -@end - -@implementation VNEDaemonClient +@implementation VNEDaemonClient { + NSXPCConnection *_connection; + NSString *_bundlePath; + NSString *_codeSigningRequirement; +} - (id)initWithBundlePath:(NSString *)bundlePath codeSigningRequirement:(NSString *)codeSigningRequirement { self = [super init]; @@ -115,7 +111,7 @@ - (NSXPCConnection *)connection { return _connection; } -- (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *))completion { +- (void)startVnet:(VNEConfig *)config completion:(void (^)(NSError *))completion { // This way of calling the XPC proxy ensures either the error handler or // the reply block gets called. // https://forums.developer.apple.com/forums/thread/713429 @@ -123,10 +119,9 @@ - (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *))compl completion(error); }]; - [(id)proxy startVnet:vnetConfig - completion:^(NSError *error) { - completion(error); - }]; + [(id)proxy startVnet:config completion:^(NSError *error) { + completion(error); + }]; } - (void)invalidate { @@ -155,9 +150,15 @@ void StartVnet(StartVnetRequest *request, StartVnetResult *outResult) { daemonClient = [[VNEDaemonClient alloc] initWithBundlePath:@(request->bundle_path) codeSigningRequirement:requirement]; } + VNEConfig *config = [[VNEConfig alloc] init]; + [config setSocketPath:@(request->socket_path)]; + [config setIpv6Prefix:@(request->ipv6_prefix)]; + [config setDnsAddr:@(request->dns_addr)]; + [config setHomePath:@(request->home_path)]; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); - [daemonClient startVnet:request->vnet_config + [daemonClient startVnet:config completion:^(NSError *error) { if (error) { outResult->ok = false; diff --git a/lib/vnet/daemon/common.go b/lib/vnet/daemon/common.go index 896e6b2ab5814..fbcd3969d5926 100644 --- a/lib/vnet/daemon/common.go +++ b/lib/vnet/daemon/common.go @@ -17,6 +17,7 @@ package daemon import ( + "log/slog" "time" "github.com/gravitational/trace" @@ -34,6 +35,26 @@ type Config struct { DNSAddr string // HomePath points to TELEPORT_HOME that will be used by the admin process. HomePath string + // ClientCred are the credentials of the unprivileged process that wants to start VNet. + ClientCred ClientCred +} + +// ClientCred are the credentials of the unprivileged process that wants to start VNet. +type ClientCred struct { + // Valid is set if the Euid and Egid fields have been set. + Valid bool + // Egid is the effective group ID of the unprivileged process. + Egid int + // Euid is the effective user ID of the unprivileged process. + Euid int +} + +func (c ClientCred) LogValue() slog.Value { + return slog.GroupValue( + slog.Bool("creds_valid", c.Valid), + slog.Int("egid", c.Egid), + slog.Int("euid", c.Euid), + ) } func (c *Config) CheckAndSetDefaults() error { @@ -46,6 +67,8 @@ func (c *Config) CheckAndSetDefaults() error { return trace.BadParameter("missing DNS address") case c.HomePath == "": return trace.BadParameter("missing home path") + case c.ClientCred.Valid == false: + return trace.BadParameter("missing client credentials") } return nil } diff --git a/lib/vnet/daemon/common_darwin.h b/lib/vnet/daemon/common_darwin.h index 92c73b310f4b3..b8491fc5a81d2 100644 --- a/lib/vnet/daemon/common_darwin.h +++ b/lib/vnet/daemon/common_darwin.h @@ -15,12 +15,28 @@ extern const int VNEAlreadyRunningError; // https://developer.apple.com/documentation/security/1395809-seccodecopysigninginformation?language=objc extern const int VNEMissingCodeSigningIdentifiersError; -typedef struct VnetConfig { - const char *socket_path; - const char *ipv6_prefix; - const char *dns_addr; - const char *home_path; -} VnetConfig; +// VNEConfig is used to send a config necessary to start VNet between the client and the daemon +// service. When adding or removing properties, remember to adjust the implementation of VNEConfig +// as well. +// +// Although it's not the primary use case, it's possible for the client to connect to a service +// of a different version of tsh where VNEConfig does not have the same properties. +// Thanks to the conformance to NSSecureCoding, adding and removing properties does not cause either +// end of the connection to blow up: +// +// * If the client sends a property that the daemon doesn't know about, the property will be ignored +// on the daemon side. +// * If the client does not send a property that the daemon expects, the property will not be set on +// the daemon side. +// +// In either case, the expectation is that the Obj-C side pushes the config to the Go side which +// actually validates the config. +@interface VNEConfig : NSObject +@property(copy) NSString *socketPath; +@property(copy) NSString *ipv6Prefix; +@property(copy) NSString *dnsAddr; +@property(copy) NSString *homePath; +@end @protocol VNEDaemonProtocol // startVnet passes the config back to Go code (which then starts VNet in a separate thread) @@ -29,7 +45,7 @@ typedef struct VnetConfig { // Only the first call to this method starts VNet. Subsequent calls return VNEAlreadyRunningError. // The daemon process exits after VNet is stopped, after which it can be spawned again by calling // this method. -- (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *error))completion; +- (void)startVnet:(VNEConfig *)vnetConfig completion:(void (^)(NSError *error))completion; @end // Returns the label for the daemon by getting the identifier of the bundle diff --git a/lib/vnet/daemon/common_darwin.m b/lib/vnet/daemon/common_darwin.m index 3a405209893f8..ca9eb1d96b048 100644 --- a/lib/vnet/daemon/common_darwin.m +++ b/lib/vnet/daemon/common_darwin.m @@ -16,6 +16,7 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +#include "common_darwin.h" #import #import @@ -118,3 +119,27 @@ bool getCodeSigningRequirement(NSString **outRequirement, NSError **outError) { return true; } + +@implementation VNEConfig ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.socketPath forKey:@"socketPath"]; + [coder encodeObject:self.ipv6Prefix forKey:@"ipv6Prefix"]; + [coder encodeObject:self.dnsAddr forKey:@"dnsAddr"]; + [coder encodeObject:self.homePath forKey:@"homePath"]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + if (self = [super init]) { + [self setSocketPath:[coder decodeObjectOfClass:[NSString class] forKey:@"socketPath"]]; + [self setIpv6Prefix:[coder decodeObjectOfClass:[NSString class] forKey:@"ipv6Prefix"]]; + [self setDnsAddr:[coder decodeObjectOfClass:[NSString class] forKey:@"dnsAddr"]]; + [self setHomePath:[coder decodeObjectOfClass:[NSString class] forKey:@"homePath"]]; + } + return self; +} + +@end diff --git a/lib/vnet/daemon/service_darwin.go b/lib/vnet/daemon/service_darwin.go index bd7db4096da06..b4e940c77bb63 100644 --- a/lib/vnet/daemon/service_darwin.go +++ b/lib/vnet/daemon/service_darwin.go @@ -77,6 +77,7 @@ func Start(ctx context.Context, workFn func(context.Context, Config) error) erro "ipv6_prefix", config.IPv6Prefix, "dns_addr", config.DNSAddr, "home_path", config.HomePath, + "client_cred", config.ClientCred, ) return trace.Wrap(workFn(ctx, config)) @@ -101,8 +102,10 @@ func waitForVnetConfig(ctx context.Context) (Config, error) { C.free(unsafe.Pointer(result.home_path)) }() + var clientCred C.ClientCred + // This call gets unblocked when the daemon gets stopped through C.DaemonStop. - C.WaitForVnetConfig(&result) + C.WaitForVnetConfig(&result, &clientCred) if !result.ok { errC <- trace.Wrap(errors.New(C.GoString(result.error_description))) return @@ -113,6 +116,11 @@ func waitForVnetConfig(ctx context.Context) (Config, error) { IPv6Prefix: C.GoString(result.ipv6_prefix), DNSAddr: C.GoString(result.dns_addr), HomePath: C.GoString(result.home_path), + ClientCred: ClientCred{ + Valid: bool(clientCred.valid), + Egid: int(clientCred.egid), + Euid: int(clientCred.euid), + }, } errC <- nil }() diff --git a/lib/vnet/daemon/service_darwin.h b/lib/vnet/daemon/service_darwin.h index fd39979eed25f..9d14d06780b4f 100644 --- a/lib/vnet/daemon/service_darwin.h +++ b/lib/vnet/daemon/service_darwin.h @@ -48,11 +48,20 @@ typedef struct VnetConfigResult { const char *home_path; } VnetConfigResult; +typedef struct ClientCred { + // valid is set if the euid and egid fields have been set. + bool valid; + // egid is the effective group ID of the process on the other side of the XPC connection. + gid_t egid; + // euid is the effective user ID of the process on the other side of the XPC connection. + uid_t euid; +} ClientCred; + // WaitForVnetConfig blocks until a client calls the daemon with a config necessary to start VNet. // It can be interrupted by calling DaemonStop. // // The caller is expected to check outResult.ok to see if the call succeeded and to free strings // in VnetConfigResult. -void WaitForVnetConfig(VnetConfigResult *outResult); +void WaitForVnetConfig(VnetConfigResult *outResult, ClientCred *outClientCred); #endif /* TELEPORT_LIB_VNET_DAEMON_SERVICE_DARWIN_H_ */ diff --git a/lib/vnet/daemon/service_darwin.m b/lib/vnet/daemon/service_darwin.m index 01b636f72fe6a..10d586535adf7 100644 --- a/lib/vnet/daemon/service_darwin.m +++ b/lib/vnet/daemon/service_darwin.m @@ -25,23 +25,28 @@ #include +@interface VNEClientCred : NSObject +@property BOOL valid; +@property gid_t egid; +@property uid_t euid; +@end + +@implementation VNEClientCred +@end + @interface VNEDaemonService () -@property(nonatomic, strong, readwrite) NSXPCListener *listener; // started describes whether the XPC listener is listening for new connections. -@property(nonatomic, readwrite) BOOL started; -// gotConfig describes if the daemon received a VNet config from a client. -@property(nonatomic, readwrite) BOOL gotConfig; - -@property(nonatomic, readwrite) NSString *socketPath; -@property(nonatomic, readwrite) NSString *ipv6Prefix; -@property(nonatomic, readwrite) NSString *dnsAddr; -@property(nonatomic, readwrite) NSString *homePath; -@property(nonatomic, readwrite) dispatch_semaphore_t gotVnetConfigSema; +@property(readonly) BOOL started; +@property(readonly) VNEConfig *config; +@property(readonly) VNEClientCred *clientCred; @end -@implementation VNEDaemonService +@implementation VNEDaemonService { + NSXPCListener *_listener; + dispatch_semaphore_t _gotVnetConfigSema; +} - (id)initWithBundlePath:(NSString *)bundlePath codeSigningRequirement:(NSString *)codeSigningRequirement { self = [super init]; @@ -83,7 +88,7 @@ - (void)waitForVnetConfig { #pragma mark - VNEDaemonProtocol -- (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *error))completion { +- (void)startVnet:(VNEConfig *)config completion:(void (^)(NSError *error))completion { @synchronized(self) { // startVnet is expected to be called only once per daemon's lifetime. // Between the process with the daemon client exiting and the admin process (which runs the @@ -92,7 +97,7 @@ - (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *error)) // // In such scenarios, we want to return an error so that the client can wait for the daemon // to exit and retry the call. - if (_gotConfig) { + if (_config != nil) { NSError *error = [[NSError alloc] initWithDomain:@(VNEErrorDomain) code:VNEAlreadyRunningError userInfo:nil]; @@ -100,11 +105,13 @@ - (void)startVnet:(VnetConfig *)vnetConfig completion:(void (^)(NSError *error)) return; } - _gotConfig = YES; - _socketPath = @(vnetConfig->socket_path); - _ipv6Prefix = @(vnetConfig->ipv6_prefix); - _dnsAddr = @(vnetConfig->dns_addr); - _homePath = @(vnetConfig->home_path); + _config = config; + + NSXPCConnection *currentConn = [NSXPCConnection currentConnection]; + _clientCred = [[VNEClientCred alloc] init]; + [_clientCred setEgid:[currentConn effectiveGroupIdentifier]]; + [_clientCred setEuid:[currentConn effectiveUserIdentifier]]; + [_clientCred setValid:YES]; dispatch_semaphore_signal(_gotVnetConfigSema); completion(nil); @@ -153,33 +160,40 @@ void DaemonStart(const char *bundle_path, DaemonStartResult *outResult) { } void DaemonStop(void) { - if (daemonService && [daemonService started]) { + if (daemonService && daemonService.started) { [daemonService stop]; } } -void WaitForVnetConfig(VnetConfigResult *outResult) { +void WaitForVnetConfig(VnetConfigResult *outResult, ClientCred *outClientCred) { if (!daemonService) { outResult->error_description = strdup("daemon was not initialized yet"); return; } - if (![daemonService started]) { + if (!daemonService.started) { outResult->error_description = strdup("daemon was not started yet"); } [daemonService waitForVnetConfig]; - if (![daemonService started]) { + if (!daemonService.started) { outResult->error_description = strdup("daemon was stopped while waiting for VNet config"); return; } @synchronized(daemonService) { - outResult->socket_path = VNECopyNSString([daemonService socketPath]); - outResult->ipv6_prefix = VNECopyNSString([daemonService ipv6Prefix]); - outResult->dns_addr = VNECopyNSString([daemonService dnsAddr]); - outResult->home_path = VNECopyNSString([daemonService homePath]); + outResult->socket_path = VNECopyNSString(daemonService.config.socketPath); + outResult->ipv6_prefix = VNECopyNSString(daemonService.config.ipv6Prefix); + outResult->dns_addr = VNECopyNSString(daemonService.config.dnsAddr); + outResult->home_path = VNECopyNSString(daemonService.config.homePath); + + if (daemonService.clientCred && [daemonService.clientCred valid]) { + outClientCred->egid = daemonService.clientCred.egid; + outClientCred->euid = daemonService.clientCred.euid; + outClientCred->valid = true; + } + outResult->ok = true; } } diff --git a/lib/vnet/osconfig.go b/lib/vnet/osconfig.go index b47aec5415b12..0642ebd0980dd 100644 --- a/lib/vnet/osconfig.go +++ b/lib/vnet/osconfig.go @@ -18,7 +18,6 @@ package vnet import ( "context" - "log/slog" "net" "github.com/gravitational/trace" @@ -28,6 +27,7 @@ import ( "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/client/clientcache" + "github.com/gravitational/teleport/lib/vnet/daemon" ) type osConfig struct { @@ -43,14 +43,16 @@ type osConfigurator struct { clientStore *client.Store clientCache *clientcache.Cache clusterConfigCache *ClusterConfigCache - tunName string - tunIPv6 string - dnsAddr string - homePath string - tunIPv4 string + // daemonClientCred are the credentials of the process that contacted the daemon. + daemonClientCred daemon.ClientCred + tunName string + tunIPv6 string + dnsAddr string + homePath string + tunIPv4 string } -func newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath string) (*osConfigurator, error) { +func newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath string, daemonClientCred daemon.ClientCred) (*osConfigurator, error) { if homePath == "" { // This runs as root so we need to be configured with the user's home path. return nil, trace.BadParameter("homePath must be passed from unprivileged process") @@ -61,11 +63,12 @@ func newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath string) (*osConfig tunIPv6 := ipv6Prefix + "1" configurator := &osConfigurator{ - tunName: tunName, - tunIPv6: tunIPv6, - dnsAddr: dnsAddr, - homePath: homePath, - clientStore: client.NewFSClientStore(homePath), + tunName: tunName, + tunIPv6: tunIPv6, + dnsAddr: dnsAddr, + homePath: homePath, + clientStore: client.NewFSClientStore(homePath), + daemonClientCred: daemonClientCred, } configurator.clusterConfigCache = NewClusterConfigCache(clockwork.NewRealClock()) @@ -89,18 +92,32 @@ func (c *osConfigurator) close() error { return trace.Wrap(c.clientCache.Clear()) } +// updateOSConfiguration reads tsh profiles out of [c.homePath]. For each profile, it reads the VNet +// config of the root cluster and of each leaf cluster. Then it proceeds to update the OS based on +// information from that config. +// +// For the duration of reading data from clusters, it drops the root privileges, only to regain them +// before configuring the OS. func (c *osConfigurator) updateOSConfiguration(ctx context.Context) error { var dnsZones []string var cidrRanges []string - profileNames, err := profile.ListProfileNames(c.homePath) - if err != nil { - return trace.Wrap(err, "listing user profiles") - } - for _, profileName := range profileNames { - profileDNSZones, profileCIDRRanges := c.getDNSZonesAndCIDRRangesForProfile(ctx, profileName) - dnsZones = append(dnsZones, profileDNSZones...) - cidrRanges = append(cidrRanges, profileCIDRRanges...) + // Drop privileges to ensure that the user who spawned the daemon client has privileges necessary + // to access c.homePath that it sent when starting the daemon. + // Otherwise a client could make the daemon read a profile out of any directory. + if err := c.doWithDroppedRootPrivileges(ctx, func() error { + profileNames, err := profile.ListProfileNames(c.homePath) + if err != nil { + return trace.Wrap(err, "listing user profiles") + } + for _, profileName := range profileNames { + profileDNSZones, profileCIDRRanges := c.getDNSZonesAndCIDRRangesForProfile(ctx, profileName) + dnsZones = append(dnsZones, profileDNSZones...) + cidrRanges = append(cidrRanges, profileCIDRRanges...) + } + return nil + }); err != nil { + return trace.Wrap(err) } dnsZones = utils.Deduplicate(dnsZones) @@ -114,7 +131,7 @@ func (c *osConfigurator) updateOSConfiguration(ctx context.Context) error { } } - err = configureOS(ctx, &osConfig{ + err := configureOS(ctx, &osConfig{ tunName: c.tunName, tunIPv6: c.tunIPv6, tunIPv4: c.tunIPv4, @@ -137,14 +154,14 @@ func (c *osConfigurator) getDNSZonesAndCIDRRangesForProfile(ctx context.Context, defer func() { if shouldClearCacheForRoot { if err := c.clientCache.ClearForRoot(profileName); err != nil { - slog.ErrorContext(ctx, "Error while clearing client cache", "profile", profileName, "error", err) + log.ErrorContext(ctx, "Error while clearing client cache", "profile", profileName, "error", err) } } }() rootClient, err := c.clientCache.Get(ctx, profileName, "" /*leafClusterName*/) if err != nil { - slog.WarnContext(ctx, + log.WarnContext(ctx, "Failed to get root cluster client from cache, profile may be expired, not configuring VNet for this cluster", "profile", profileName, "error", err) @@ -152,7 +169,7 @@ func (c *osConfigurator) getDNSZonesAndCIDRRangesForProfile(ctx context.Context, } clusterConfig, err := c.clusterConfigCache.GetClusterConfig(ctx, rootClient) if err != nil { - slog.WarnContext(ctx, + log.WarnContext(ctx, "Failed to load VNet configuration, profile may be expired, not configuring VNet for this cluster", "profile", profileName, "error", err) @@ -164,7 +181,7 @@ func (c *osConfigurator) getDNSZonesAndCIDRRangesForProfile(ctx context.Context, leafClusters, err := getLeafClusters(ctx, rootClient) if err != nil { - slog.WarnContext(ctx, + log.WarnContext(ctx, "Failed to list leaf clusters, profile may be expired, not configuring VNet for leaf clusters of this cluster", "profile", profileName, "error", err) @@ -179,7 +196,7 @@ func (c *osConfigurator) getDNSZonesAndCIDRRangesForProfile(ctx context.Context, for _, leafClusterName := range leafClusters { clusterClient, err := c.clientCache.Get(ctx, profileName, leafClusterName) if err != nil { - slog.WarnContext(ctx, + log.WarnContext(ctx, "Failed to create leaf cluster client, not configuring VNet for this cluster", "profile", profileName, "leaf_cluster", leafClusterName, "error", err) continue @@ -187,7 +204,7 @@ func (c *osConfigurator) getDNSZonesAndCIDRRangesForProfile(ctx context.Context, clusterConfig, err := c.clusterConfigCache.GetClusterConfig(ctx, clusterClient) if err != nil { - slog.WarnContext(ctx, + log.WarnContext(ctx, "Failed to load VNet configuration, not configuring VNet for this cluster", "profile", profileName, "leaf_cluster", leafClusterName, "error", err) continue diff --git a/lib/vnet/osconfig_darwin.go b/lib/vnet/osconfig_darwin.go index e2428bf46b773..27864c80bb400 100644 --- a/lib/vnet/osconfig_darwin.go +++ b/lib/vnet/osconfig_darwin.go @@ -19,10 +19,11 @@ package vnet import ( "bufio" "context" - "log/slog" "os" "os/exec" "path/filepath" + "sync/atomic" + "syscall" "github.com/gravitational/trace" ) @@ -34,14 +35,14 @@ func configureOS(ctx context.Context, cfg *osConfig) error { // process exits and the TUN is deleted. if cfg.tunIPv4 != "" { - slog.InfoContext(ctx, "Setting IPv4 address for the TUN device.", "device", cfg.tunName, "address", cfg.tunIPv4) + log.InfoContext(ctx, "Setting IPv4 address for the TUN device.", "device", cfg.tunName, "address", cfg.tunIPv4) cmd := exec.CommandContext(ctx, "ifconfig", cfg.tunName, cfg.tunIPv4, cfg.tunIPv4, "up") if err := cmd.Run(); err != nil { return trace.Wrap(err, "running %v", cmd.Args) } } for _, cidrRange := range cfg.cidrRanges { - slog.InfoContext(ctx, "Setting an IP route for the VNet.", "netmask", cidrRange) + log.InfoContext(ctx, "Setting an IP route for the VNet.", "netmask", cidrRange) cmd := exec.CommandContext(ctx, "route", "add", "-net", cidrRange, "-interface", cfg.tunName) if err := cmd.Run(); err != nil { return trace.Wrap(err, "running %v", cmd.Args) @@ -49,13 +50,13 @@ func configureOS(ctx context.Context, cfg *osConfig) error { } if cfg.tunIPv6 != "" { - slog.InfoContext(ctx, "Setting IPv6 address for the TUN device.", "device", cfg.tunName, "address", cfg.tunIPv6) + log.InfoContext(ctx, "Setting IPv6 address for the TUN device.", "device", cfg.tunName, "address", cfg.tunIPv6) cmd := exec.CommandContext(ctx, "ifconfig", cfg.tunName, "inet6", cfg.tunIPv6, "prefixlen", "64") if err := cmd.Run(); err != nil { return trace.Wrap(err, "running %v", cmd.Args) } - slog.InfoContext(ctx, "Setting an IPv6 route for the VNet.") + log.InfoContext(ctx, "Setting an IPv6 route for the VNet.") cmd = exec.CommandContext(ctx, "route", "add", "-inet6", cfg.tunIPv6, "-prefixlen", "64", "-interface", cfg.tunName) if err := cmd.Run(); err != nil { return trace.Wrap(err, "running %v", cmd.Args) @@ -78,7 +79,7 @@ func configureDNS(ctx context.Context, nameserver string, zones []string) error return trace.BadParameter("empty nameserver with non-empty zones") } - slog.DebugContext(ctx, "Configuring DNS.", "nameserver", nameserver, "zones", zones) + log.DebugContext(ctx, "Configuring DNS.", "nameserver", nameserver, "zones", zones) if err := os.MkdirAll(resolverPath, os.FileMode(0755)); err != nil { return trace.Wrap(err, "creating %s", resolverPath) } @@ -140,3 +141,42 @@ func vnetManagedResolverFiles() (map[string]struct{}, error) { } return matchingFiles, nil } + +var hasDroppedPrivileges atomic.Bool + +// doWithDroppedRootPrivileges drops the privileges of the current process to those of the client +// process that called the VNet daemon. +func (c *osConfigurator) doWithDroppedRootPrivileges(ctx context.Context, fn func() error) (err error) { + if !hasDroppedPrivileges.CompareAndSwap(false, true) { + // At the moment of writing, the VNet daemon wasn't expected to do multiple things in parallel + // with dropped privileges. If you run into this error, consider if employing a mutex is going + // to be enough or if a more elaborate refactoring is required. + return trace.CompareFailed("privileges are being temporarily dropped already") + } + defer hasDroppedPrivileges.Store(false) + + rootEgid := os.Getegid() + rootEuid := os.Geteuid() + + log.InfoContext(ctx, "Temporarily dropping root privileges.", "egid", c.daemonClientCred.Egid, "euid", c.daemonClientCred.Euid) + + if err := syscall.Setegid(c.daemonClientCred.Egid); err != nil { + panic(trace.Wrap(err, "setting egid")) + } + if err := syscall.Seteuid(c.daemonClientCred.Euid); err != nil { + panic(trace.Wrap(err, "setting euid")) + } + + defer func() { + if err := syscall.Seteuid(rootEuid); err != nil { + panic(trace.Wrap(err, "reverting euid")) + } + if err := syscall.Setegid(rootEgid); err != nil { + panic(trace.Wrap(err, "reverting egid")) + } + + log.InfoContext(ctx, "Restored root privileges.", "egid", rootEgid, "euid", rootEuid) + }() + + return trace.Wrap(fn()) +} diff --git a/lib/vnet/osconfig_other.go b/lib/vnet/osconfig_other.go new file mode 100644 index 0000000000000..22780f8bc5f11 --- /dev/null +++ b/lib/vnet/osconfig_other.go @@ -0,0 +1,34 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +//go:build !darwin +// +build !darwin + +package vnet + +import ( + "context" + + "github.com/gravitational/trace" +) + +func configureOS(ctx context.Context, cfg *osConfig) error { + return trace.Wrap(ErrVnetNotImplemented) +} + +func (c *osConfigurator) doWithDroppedRootPrivileges(ctx context.Context, fn func() error) (err error) { + return trace.Wrap(ErrVnetNotImplemented) +} diff --git a/lib/vnet/setup.go b/lib/vnet/setup.go index cf0e360a8b5f1..446fa5d1022c6 100644 --- a/lib/vnet/setup.go +++ b/lib/vnet/setup.go @@ -20,7 +20,6 @@ import ( "context" "errors" "fmt" - "log/slog" "os" "time" @@ -28,11 +27,15 @@ import ( "golang.org/x/sync/errgroup" "golang.zx2c4.com/wireguard/tun" + "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/profile" "github.com/gravitational/teleport/api/types" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/vnet/daemon" ) +var log = logutils.NewPackageLogger(teleport.ComponentKey, "vnet") + // SetupAndRun creates a network stack for VNet and runs it in the background. To do this, it also // needs to launch an admin process in the background. It returns [ProcessManager] which controls // the lifecycle of both background tasks. @@ -68,7 +71,7 @@ func SetupAndRun(ctx context.Context, config *SetupAndRunConfig) (*ProcessManage if err != nil { return nil, trace.Wrap(err) } - slog.DebugContext(ctx, "Created unix socket for admin process", "socket", socketPath) + log.DebugContext(ctx, "Created unix socket for admin process", "socket", socketPath) pm.AddCriticalBackgroundTask("socket closer", func() error { // Keep the socket open until the process context is canceled. // Closing the socket signals the admin process to terminate. @@ -115,7 +118,7 @@ func SetupAndRun(ctx context.Context, config *SetupAndRunConfig) (*ProcessManage // problem with the admin process. // Returning error from processCtx will be more informative to the user, e.g., the error // will say "password prompt closed by user" instead of "read from closed socket". - slog.DebugContext(ctx, "Error from recvTUNErr ignored in favor of processCtx.Err", "error", err) + log.DebugContext(ctx, "Error from recvTUNErr ignored in favor of processCtx.Err", "error", err) return nil, trace.Wrap(context.Cause(processCtx)) } return nil, trace.Wrap(err, "receiving TUN device from admin process") @@ -219,6 +222,9 @@ func (pm *ProcessManager) Close() { // It also handles host OS configuration that must run as root, and stays alive to keep the host configuration // up to date. It will stay running until the socket at config.socketPath is deleted or until encountering an // unrecoverable error. +// +// OS configuration is updated every [osConfigurationInterval]. During the update, it temporarily +// changes egid and euid of the process to that of the client connecting to the daemon. func AdminSetup(ctx context.Context, config daemon.Config) error { if err := config.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) @@ -234,7 +240,7 @@ func AdminSetup(ctx context.Context, config daemon.Config) error { errCh := make(chan error) go func() { - errCh <- trace.Wrap(osConfigurationLoop(ctx, tunName, config.IPv6Prefix, config.DNSAddr, config.HomePath)) + errCh <- trace.Wrap(osConfigurationLoop(ctx, tunName, config.IPv6Prefix, config.DNSAddr, config.HomePath, config.ClientCred)) }() // Stay alive until we get an error on errCh, indicating that the osConfig loop exited. @@ -246,7 +252,7 @@ func AdminSetup(ctx context.Context, config daemon.Config) error { select { case <-ticker.C: if _, err := os.Stat(config.SocketPath); err != nil { - slog.DebugContext(ctx, "failed to stat socket path, assuming parent exited") + log.DebugContext(ctx, "failed to stat socket path, assuming parent exited") cancel() return trace.Wrap(<-errCh) } @@ -267,7 +273,7 @@ func createAndSendTUNDevice(ctx context.Context, socketPath string) (string, err defer func() { // We can safely close the TUN device in the admin process after it has been sent on the socket. if err := tun.Close(); err != nil { - slog.WarnContext(ctx, "Failed to close TUN device.", "error", trace.Wrap(err)) + log.WarnContext(ctx, "Failed to close TUN device.", "error", trace.Wrap(err)) } }() @@ -279,14 +285,14 @@ func createAndSendTUNDevice(ctx context.Context, socketPath string) (string, err // osConfigurationLoop will keep running until [ctx] is canceled or an unrecoverable error is encountered, in // order to keep the host OS configuration up to date. -func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, homePath string) error { - osConfigurator, err := newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath) +func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, homePath string, clientCred daemon.ClientCred) error { + osConfigurator, err := newOSConfigurator(tunName, ipv6Prefix, dnsAddr, homePath, clientCred) if err != nil { return trace.Wrap(err, "creating OS configurator") } defer func() { if err := osConfigurator.close(); err != nil { - slog.ErrorContext(ctx, "Error while closing OS configurator", "error", err) + log.ErrorContext(ctx, "Error while closing OS configurator", "error", err) } }() @@ -301,7 +307,7 @@ func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, home // Shutting down, deconfigure OS. Pass context.Background because [ctx] has likely been canceled // already but we still need to clean up. if err := osConfigurator.deconfigureOS(context.Background()); err != nil { - slog.ErrorContext(ctx, "Error deconfiguring host OS before shutting down.", "error", err) + log.ErrorContext(ctx, "Error deconfiguring host OS before shutting down.", "error", err) } }() @@ -311,7 +317,8 @@ func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, home // Re-configure the host OS every 10 seconds. This will pick up any newly logged-in clusters by // reading profiles from TELEPORT_HOME. - ticker := time.NewTicker(10 * time.Second) + const osConfigurationInterval = 10 * time.Second + ticker := time.NewTicker(osConfigurationInterval) defer ticker.Stop() for { select { @@ -326,7 +333,7 @@ func osConfigurationLoop(ctx context.Context, tunName, ipv6Prefix, dnsAddr, home } func createTUNDevice(ctx context.Context) (tun.Device, string, error) { - slog.DebugContext(ctx, "Creating TUN device.") + log.DebugContext(ctx, "Creating TUN device.") dev, err := tun.CreateTUN("utun", mtu) if err != nil { return nil, "", trace.Wrap(err, "creating TUN device") diff --git a/lib/vnet/setup_daemon_darwin.go b/lib/vnet/setup_daemon_darwin.go index b777dfbd674f5..dd6676b02b850 100644 --- a/lib/vnet/setup_daemon_darwin.go +++ b/lib/vnet/setup_daemon_darwin.go @@ -21,22 +21,14 @@ package vnet import ( "context" - "os" "github.com/gravitational/trace" "github.com/gravitational/teleport/lib/vnet/daemon" ) -const EnvFeatureFlag = "VNETDAEMON" - func execAdminProcess(ctx context.Context, config daemon.Config) error { - // TODO(ravicious): Remove the feature env var after the daemon gets implemented. - if os.Getenv(EnvFeatureFlag) == "yes" { - return trace.Wrap(daemon.RegisterAndCall(ctx, config)) - } - - return trace.Wrap(execAdminSubcommand(ctx, config)) + return trace.Wrap(daemon.RegisterAndCall(ctx, config)) } func DaemonSubcommand(ctx context.Context) error { diff --git a/lib/vnet/setup_darwin.go b/lib/vnet/setup_darwin.go index 688a39ff55c04..e967eb8f11b73 100644 --- a/lib/vnet/setup_darwin.go +++ b/lib/vnet/setup_darwin.go @@ -72,9 +72,11 @@ do shell script quoted form of executableName & `+ `" %s -d --socket " & quoted form of socketPath & `+ `" --ipv6-prefix " & quoted form of ipv6Prefix & `+ `" --dns-addr " & quoted form of dnsAddr & `+ + `" --egid %d --euid %d" & `+ `" >/var/log/vnet.log 2>&1" `+ `with prompt "Teleport VNet wants to set up a virtual network device." with administrator privileges`, - executableName, config.SocketPath, config.IPv6Prefix, config.DNSAddr, teleport.VnetAdminSetupSubCommand) + executableName, config.SocketPath, config.IPv6Prefix, config.DNSAddr, teleport.VnetAdminSetupSubCommand, + os.Getegid(), os.Geteuid()) // The context we pass here has effect only on the password prompt being shown. Once osascript spawns the // privileged process, canceling the context (and thus killing osascript) has no effect on the privileged diff --git a/lib/vnet/setup_other.go b/lib/vnet/setup_other.go index e7f723138b187..11916d1bd94a7 100644 --- a/lib/vnet/setup_other.go +++ b/lib/vnet/setup_other.go @@ -48,10 +48,6 @@ func receiveTUNDevice(socket *net.UnixListener) (tun.Device, error) { return nil, trace.Wrap(ErrVnetNotImplemented) } -func configureOS(ctx context.Context, cfg *osConfig) error { - return trace.Wrap(ErrVnetNotImplemented) -} - func execAdminProcess(ctx context.Context, config daemon.Config) error { return trace.Wrap(ErrVnetNotImplemented) } diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index e209675939a65..c36e256e9ab0f 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -72,6 +72,7 @@ import ( "github.com/gravitational/teleport/api/types/installers" "github.com/gravitational/teleport/api/utils/keys" apisshutils "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/state" @@ -917,6 +918,9 @@ func (h *Handler) bindDefaultEndpoints() { h.GET(OIDCJWKWURI, h.WithLimiter(h.jwksOIDC)) h.GET("/webapi/thumbprint", h.WithLimiter(h.thumbprint)) + // SPIFFE Federation Trust Bundle + h.GET("/webapi/spiffe/bundle.json", h.WithLimiter(h.getSPIFFEBundle)) + // DiscoveryConfig CRUD h.GET("/webapi/sites/:site/discoveryconfig", h.WithClusterAuth(h.discoveryconfigList)) h.POST("/webapi/sites/:site/discoveryconfig", h.WithClusterAuth(h.discoveryconfigCreate)) @@ -1003,12 +1007,14 @@ func (h *Handler) Close() error { } type userStatusResponse struct { - HasDeviceExtensions bool `json:"hasDeviceExtensions,omitempty"` - Message string `json:"message"` // Always set to "ok" + RequiresDeviceTrust types.TrustedDeviceRequirement `json:"requiresDeviceTrust,omitempty"` + HasDeviceExtensions bool `json:"hasDeviceExtensions,omitempty"` + Message string `json:"message"` // Always set to "ok" } func (h *Handler) getUserStatus(w http.ResponseWriter, r *http.Request, _ httprouter.Params, c *SessionContext) (interface{}, error) { return userStatusResponse{ + RequiresDeviceTrust: c.cfg.Session.GetTrustedDeviceRequirement(), HasDeviceExtensions: c.cfg.Session.GetHasDeviceExtensions(), Message: "ok", }, nil @@ -1095,14 +1101,11 @@ func (h *Handler) getUserContext(w http.ResponseWriter, r *http.Request, p httpr if err != nil { return nil, trace.Wrap(err) } - accessMonitoringEnabled := pingResp.GetServerFeatures().GetAccessMonitoring().GetEnabled() - // DELETE IN 16.0 - // If ServerFeatures.AccessMonitoring is nil, then that means the response came from a older auth - // where ServerFeatures.AccessMonitoring field does not exist. - if pingResp.GetServerFeatures().GetAccessMonitoring() == nil { - accessMonitoringEnabled = pingResp.ServerFeatures != nil && pingResp.ServerFeatures.GetIdentityGovernance() - } + features := pingResp.GetServerFeatures() + entitlement := modules.GetProtoEntitlement(features, entitlements.AccessMonitoring) + // ensure entitlement is set & feature is configured + accessMonitoringEnabled := entitlement.Enabled && features.GetAccessMonitoringConfigured() userContext, err := ui.NewUserContext(user, accessChecker.Roles(), *pingResp.ServerFeatures, desktopRecordingEnabled, accessMonitoringEnabled) if err != nil { @@ -1460,9 +1463,10 @@ func (h *Handler) pingWithConnector(w http.ResponseWriter, r *http.Request, p ht return nil, trace.Wrap(err) } response := &webclient.PingResponse{ - Proxy: *proxyConfig, - ServerVersion: teleport.Version, - ClusterName: h.auth.clusterName, + Proxy: *proxyConfig, + ServerVersion: teleport.Version, + MinClientVersion: teleport.MinClientVersion, + ClusterName: h.auth.clusterName, } hasMessageOfTheDay := cap.GetMessageOfTheDay() != "" @@ -1646,11 +1650,6 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou } } - // TODO(mcbattirola): remove isTeam when it is no longer used - isTeam := clusterFeatures.GetProductType() == proto.ProductType_PRODUCT_TYPE_TEAM - - policy := clusterFeatures.GetPolicy() - webCfg := webclient.WebConfig{ Edition: modules.GetModules().BuildType(), Auth: authSettings, @@ -1660,33 +1659,22 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou RecoveryCodesEnabled: clusterFeatures.GetRecoveryCodes(), UI: h.getUIConfig(r.Context()), IsDashboard: services.IsDashboard(clusterFeatures), + IsTeam: false, IsUsageBasedBilling: clusterFeatures.GetIsUsageBased(), AutomaticUpgrades: automaticUpgradesEnabled, AutomaticUpgradesTargetVersion: automaticUpgradesTargetVersion, - HideInaccessibleFeatures: clusterFeatures.GetFeatureHiding(), CustomTheme: clusterFeatures.GetCustomTheme(), - IsIGSEnabled: clusterFeatures.GetIdentityGovernance(), - IsPolicyEnabled: policy != nil && policy.Enabled, + Questionnaire: clusterFeatures.GetQuestionnaire(), + IsStripeManaged: clusterFeatures.GetIsStripeManaged(), + PremiumSupport: clusterFeatures.GetSupportType() == proto.SupportType_SUPPORT_TYPE_PREMIUM, PlayableDatabaseProtocols: player.SupportedDatabaseProtocols, - FeatureLimits: webclient.FeatureLimits{ - AccessListCreateLimit: int(clusterFeatures.GetAccessList().GetCreateLimit()), - AccessMonitoringMaxReportRangeLimit: int(clusterFeatures.GetAccessMonitoring().GetMaxReportRangeLimit()), - AccessRequestMonthlyRequestLimit: int(clusterFeatures.GetAccessRequests().GetMonthlyRequestLimit()), - }, - Questionnaire: clusterFeatures.GetQuestionnaire(), - IsStripeManaged: clusterFeatures.GetIsStripeManaged(), - ExternalAuditStorage: clusterFeatures.GetExternalAuditStorage(), - PremiumSupport: clusterFeatures.GetSupportType() == proto.SupportType_SUPPORT_TYPE_PREMIUM, - AccessRequests: clusterFeatures.GetAccessRequests().MonthlyRequestLimit > 0, - TrustedDevices: clusterFeatures.GetDeviceTrust().GetEnabled(), - OIDC: clusterFeatures.GetOIDC(), - SAML: clusterFeatures.GetSAML(), - MobileDeviceManagement: clusterFeatures.GetMobileDeviceManagement(), - JoinActiveSessions: clusterFeatures.GetJoinActiveSessions(), - // TODO(mcbattirola): remove isTeam when it is no longer used - IsTeam: isTeam, + // Entitlements are reset/overridden in setEntitlementsWithLegacyLogic until setEntitlementsWithLegacyLogic is removed in v18 + Entitlements: GetWebCfgEntitlements(clusterFeatures.GetEntitlements()), } + // Set entitlements with backwards field compatibility + setEntitlementsWithLegacyLogic(&webCfg, clusterFeatures) + resource, err := h.cfg.ProxyClient.GetClusterName() if err != nil { h.log.WithError(err).Warn("Failed to query cluster name.") @@ -1703,6 +1691,105 @@ func (h *Handler) getWebConfig(w http.ResponseWriter, r *http.Request, p httprou return nil, nil } +// setEntitlementsWithLegacyLogic ensures entitlements on webCfg are backwards compatible +// If Entitlements are present, will set the legacy fields equal to the equivalent entitlement value +// i.e. webCfg.IsIGSEnabled = clusterFeatures.Entitlements[entitlements.Identity].Enabled +// && webCfg.Entitlements[entitlements.Identity] = clusterFeatures.Entitlements[entitlements.Identity].Enabled +// If Entitlements are not present, will set the legacy fields AND the entitlement equal to the legacy feature +// i.e. webCfg.IsIGSEnabled = clusterFeatures.GetIdentityGovernance() +// && webCfg.Entitlements[entitlements.Identity] = clusterFeatures.GetIdentityGovernance() +// todo (michellescripts) remove in v18; & inline entitlement logic above +func setEntitlementsWithLegacyLogic(webCfg *webclient.WebConfig, clusterFeatures proto.Features) { + // if Entitlements are not present, GetWebCfgEntitlements will return a map of entitlement to {enabled:false} + // if Entitlements are present, GetWebCfgEntitlements will populate the fields appropriately + webCfg.Entitlements = GetWebCfgEntitlements(clusterFeatures.GetEntitlements()) + + if ent := clusterFeatures.GetEntitlements(); len(ent) > 0 { + // webCfg.Entitlements: No update as they are set above + // webCfg.: set equal to entitlement value + webCfg.AccessRequests = modules.GetProtoEntitlement(&clusterFeatures, entitlements.AccessRequests).Enabled + webCfg.ExternalAuditStorage = modules.GetProtoEntitlement(&clusterFeatures, entitlements.ExternalAuditStorage).Enabled + webCfg.HideInaccessibleFeatures = modules.GetProtoEntitlement(&clusterFeatures, entitlements.FeatureHiding).Enabled + webCfg.IsIGSEnabled = modules.GetProtoEntitlement(&clusterFeatures, entitlements.Identity).Enabled + webCfg.IsPolicyEnabled = modules.GetProtoEntitlement(&clusterFeatures, entitlements.Policy).Enabled + webCfg.JoinActiveSessions = modules.GetProtoEntitlement(&clusterFeatures, entitlements.JoinActiveSessions).Enabled + webCfg.MobileDeviceManagement = modules.GetProtoEntitlement(&clusterFeatures, entitlements.MobileDeviceManagement).Enabled + webCfg.OIDC = modules.GetProtoEntitlement(&clusterFeatures, entitlements.OIDC).Enabled + webCfg.SAML = modules.GetProtoEntitlement(&clusterFeatures, entitlements.SAML).Enabled + webCfg.TrustedDevices = modules.GetProtoEntitlement(&clusterFeatures, entitlements.DeviceTrust).Enabled + webCfg.FeatureLimits = webclient.FeatureLimits{ + AccessListCreateLimit: int(modules.GetProtoEntitlement(&clusterFeatures, entitlements.AccessLists).Limit), + AccessMonitoringMaxReportRangeLimit: int(modules.GetProtoEntitlement(&clusterFeatures, entitlements.AccessMonitoring).Limit), + AccessRequestMonthlyRequestLimit: int(modules.GetProtoEntitlement(&clusterFeatures, entitlements.AccessRequests).Limit), + } + + } else { + // webCfg.Entitlements: All records are {enabled: false}; update to equal legacy feature value + webCfg.Entitlements[string(entitlements.ExternalAuditStorage)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetExternalAuditStorage()} + webCfg.Entitlements[string(entitlements.FeatureHiding)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetFeatureHiding()} + webCfg.Entitlements[string(entitlements.Identity)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetIdentityGovernance()} + webCfg.Entitlements[string(entitlements.JoinActiveSessions)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetJoinActiveSessions()} + webCfg.Entitlements[string(entitlements.MobileDeviceManagement)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetMobileDeviceManagement()} + webCfg.Entitlements[string(entitlements.OIDC)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetOIDC()} + webCfg.Entitlements[string(entitlements.Policy)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetPolicy() != nil && clusterFeatures.GetPolicy().Enabled} + webCfg.Entitlements[string(entitlements.SAML)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetSAML()} + + // set default Identity fields to legacy feature value + webCfg.Entitlements[string(entitlements.AccessLists)] = webclient.EntitlementInfo{Enabled: true, Limit: clusterFeatures.GetAccessList().GetCreateLimit()} + webCfg.Entitlements[string(entitlements.AccessMonitoring)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetAccessMonitoring().GetEnabled(), Limit: clusterFeatures.GetAccessMonitoring().GetMaxReportRangeLimit()} + webCfg.Entitlements[string(entitlements.AccessRequests)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetAccessRequests().MonthlyRequestLimit > 0, Limit: clusterFeatures.GetAccessRequests().GetMonthlyRequestLimit()} + webCfg.Entitlements[string(entitlements.DeviceTrust)] = webclient.EntitlementInfo{Enabled: clusterFeatures.GetDeviceTrust().GetEnabled(), Limit: clusterFeatures.GetDeviceTrust().GetDevicesUsageLimit()} + // override Identity Package features if Identity is enabled: set true and clear limit + if clusterFeatures.GetIdentityGovernance() { + webCfg.Entitlements[string(entitlements.AccessLists)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.AccessMonitoring)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.AccessRequests)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.DeviceTrust)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.OktaSCIM)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.OktaUserSync)] = webclient.EntitlementInfo{Enabled: true} + webCfg.Entitlements[string(entitlements.SessionLocks)] = webclient.EntitlementInfo{Enabled: true} + } + + // webCfg.: set equal to legacy feature value + webCfg.AccessRequests = clusterFeatures.GetAccessRequests().MonthlyRequestLimit > 0 + webCfg.ExternalAuditStorage = clusterFeatures.GetExternalAuditStorage() + webCfg.HideInaccessibleFeatures = clusterFeatures.GetFeatureHiding() + webCfg.IsIGSEnabled = clusterFeatures.GetIdentityGovernance() + webCfg.IsPolicyEnabled = clusterFeatures.GetPolicy() != nil && clusterFeatures.GetPolicy().Enabled + webCfg.JoinActiveSessions = clusterFeatures.GetJoinActiveSessions() + webCfg.MobileDeviceManagement = clusterFeatures.GetMobileDeviceManagement() + webCfg.OIDC = clusterFeatures.GetOIDC() + webCfg.SAML = clusterFeatures.GetSAML() + webCfg.TrustedDevices = clusterFeatures.GetDeviceTrust().GetEnabled() + webCfg.FeatureLimits = webclient.FeatureLimits{ + AccessListCreateLimit: int(clusterFeatures.GetAccessList().GetCreateLimit()), + AccessMonitoringMaxReportRangeLimit: int(clusterFeatures.GetAccessMonitoring().GetMaxReportRangeLimit()), + AccessRequestMonthlyRequestLimit: int(clusterFeatures.GetAccessRequests().GetMonthlyRequestLimit()), + } + } +} + +// GetWebCfgEntitlements takes a cloud entitlement set and returns a modules Entitlement set +func GetWebCfgEntitlements(protoEntitlements map[string]*proto.EntitlementInfo) map[string]webclient.EntitlementInfo { + all := entitlements.AllEntitlements + result := make(map[string]webclient.EntitlementInfo, len(all)) + + for _, e := range all { + al, ok := protoEntitlements[string(e)] + if !ok { + result[string(e)] = webclient.EntitlementInfo{} + continue + } + + result[string(e)] = webclient.EntitlementInfo{ + Enabled: al.Enabled, + Limit: al.Limit, + } + } + + return result +} + type JWKSResponse struct { // Keys is a list of public keys in JWK format. Keys []jwt.JWK `json:"keys"` @@ -1757,6 +1844,7 @@ func (h *Handler) githubLoginWeb(w http.ResponseWriter, r *http.Request, p httpr CreateWebSession: true, ClientRedirectURL: req.ClientRedirectURL, ClientLoginIP: remoteAddr, + ClientUserAgent: r.UserAgent(), }) if err != nil { logger.WithError(err).Error("Error creating auth request.") @@ -1854,6 +1942,14 @@ func (h *Handler) githubCallback(w http.ResponseWriter, r *http.Request, p httpr return client.LoginFailedRedirectURL } + if dwt := response.Session.GetDeviceWebToken(); dwt != nil { + logger.Debug("GitHub WebSession created with device web token") + // if a device web token is present, we must send the user to the device authorize page + // to upgrade the session. + // TODO (avatus) the web client currently doesn't handle any redirects after authorizing a web + // session with device trust. Once it does, append a redirect_url here as a query parameter + return fmt.Sprintf("/web/device/authorize/%s/%s", dwt.Id, dwt.Token) + } return res.ClientRedirectURL } @@ -2050,7 +2146,7 @@ type CreateSessionResponse struct { DeviceWebToken *types.DeviceWebToken `json:"deviceWebToken,omitempty"` // TrustedDeviceRequirement calculated for the web session. // Follows [types.TrustedDeviceRequirement]. - TrustedDeviceRequirement int32 `json:"trusted_device_requirement,omitempty"` + TrustedDeviceRequirement int32 `json:"trustedDeviceRequirement,omitempty"` } func newSessionResponse(sctx *SessionContext) (*CreateSessionResponse, error) { diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 65b0bb108c8cd..ba567a46c6b6a 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -81,6 +81,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/breaker" authproto "github.com/gravitational/teleport/api/client/proto" + clientproto "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/client/webclient" "github.com/gravitational/teleport/api/constants" apidefaults "github.com/gravitational/teleport/api/defaults" @@ -94,6 +95,7 @@ import ( apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/grpc/interceptors" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/agentless" "github.com/gravitational/teleport/lib/auth" @@ -4399,7 +4401,9 @@ func TestClusterAppsGet(t *testing.T) { func TestApplicationAccessDisabled(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - App: false, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.App: {Enabled: false}, + }, }, }) @@ -4508,7 +4512,7 @@ func TestApplicationWebSessionsDeletedAfterLogout(t *testing.T) { require.Empty(t, collectAppSessions(context.Background())) } -func TestGetWebConfig(t *testing.T) { +func TestGetWebConfig_WithEntitlements(t *testing.T) { ctx := context.Background() env := newWebPack(t, 1) @@ -4564,6 +4568,41 @@ func TestGetWebConfig(t *testing.T) { JoinActiveSessions: true, Edition: modules.BuildOSS, // testBuildType is empty PlayableDatabaseProtocols: player.SupportedDatabaseProtocols, + Entitlements: map[string]webclient.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: false}, + string(entitlements.AccessMonitoring): {Enabled: false}, + string(entitlements.AccessRequests): {Enabled: false}, + string(entitlements.App): {Enabled: true}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + string(entitlements.DB): {Enabled: true}, + string(entitlements.Desktop): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: false}, + string(entitlements.ExternalAuditStorage): {Enabled: false}, + string(entitlements.FeatureHiding): {Enabled: false}, + string(entitlements.HSM): {Enabled: false}, + string(entitlements.Identity): {Enabled: false}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.K8s): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: false}, + string(entitlements.OIDC): {Enabled: false}, + string(entitlements.OktaSCIM): {Enabled: false}, + string(entitlements.OktaUserSync): {Enabled: false}, + string(entitlements.Policy): {Enabled: false}, + string(entitlements.SAML): {Enabled: false}, + string(entitlements.SessionLocks): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.UsageReporting): {Enabled: false}, + }, + TunnelPublicAddress: "", + RecoveryCodesEnabled: false, + UI: webclient.UIConfig{}, + IsDashboard: false, + IsUsageBasedBilling: false, + AutomaticUpgradesTargetVersion: "", + CustomTheme: "", + Questionnaire: false, + IsStripeManaged: false, + PremiumSupport: false, } // Make a request. @@ -4587,6 +4626,11 @@ func TestGetWebConfig(t *testing.T) { Cloud: true, IsUsageBasedBilling: true, AutomaticUpgrades: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.DB: {Enabled: true, Limit: 22}, + entitlements.DeviceTrust: {Enabled: true, Limit: 33}, + entitlements.Desktop: {Enabled: true, Limit: 44}, + }, }, }) @@ -4607,6 +4651,13 @@ func TestGetWebConfig(t *testing.T) { expectedCfg.AutomaticUpgradesTargetVersion = "v" + teleport.Version expectedCfg.JoinActiveSessions = false expectedCfg.Edition = "" // testBuildType is empty + expectedCfg.TrustedDevices = true + expectedCfg.Entitlements[string(entitlements.App)] = webclient.EntitlementInfo{Enabled: false} + expectedCfg.Entitlements[string(entitlements.DB)] = webclient.EntitlementInfo{Enabled: true, Limit: 22} + expectedCfg.Entitlements[string(entitlements.DeviceTrust)] = webclient.EntitlementInfo{Enabled: true, Limit: 33} + expectedCfg.Entitlements[string(entitlements.Desktop)] = webclient.EntitlementInfo{Enabled: true, Limit: 44} + expectedCfg.Entitlements[string(entitlements.JoinActiveSessions)] = webclient.EntitlementInfo{Enabled: false} + expectedCfg.Entitlements[string(entitlements.K8s)] = webclient.EntitlementInfo{Enabled: false} // request and verify enabled features are enabled. re, err = clt.Get(ctx, endpoint, nil) @@ -4626,6 +4677,10 @@ func TestGetWebConfig(t *testing.T) { } env.proxies[0].client = mockClient expectedCfg.AutomaticUpgrades = false + expectedCfg.TrustedDevices = false + expectedCfg.Entitlements[string(entitlements.DB)] = webclient.EntitlementInfo{Enabled: false} + expectedCfg.Entitlements[string(entitlements.Desktop)] = webclient.EntitlementInfo{Enabled: false} + expectedCfg.Entitlements[string(entitlements.DeviceTrust)] = webclient.EntitlementInfo{Enabled: false} // update modules but NOT the expected config modules.SetTestModules(t, &modules.TestModules{ @@ -4645,23 +4700,21 @@ func TestGetWebConfig(t *testing.T) { require.Equal(t, expectedCfg, cfg) } -func TestGetWebConfig_IGSFeatureLimits(t *testing.T) { +func TestGetWebConfig_LegacyFeatureLimits(t *testing.T) { ctx := context.Background() env := newWebPack(t, 1) modules.SetTestModules(t, &modules.TestModules{ TestFeatures: modules.Features{ - ProductType: modules.ProductTypeTeam, - IdentityGovernanceSecurity: true, - AccessList: modules.AccessListFeature{ - CreateLimit: 5, - }, - AccessMonitoring: modules.AccessMonitoringFeature{ - MaxReportRangeLimit: 10, - }, + ProductType: modules.ProductTypeTeam, IsUsageBasedBilling: true, IsStripeManaged: true, Questionnaire: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.Identity: {Enabled: true}, + entitlements.AccessLists: {Enabled: true, Limit: 5}, + entitlements.AccessMonitoring: {Enabled: true, Limit: 10}, + }, }, }) @@ -4678,12 +4731,37 @@ func TestGetWebConfig_IGSFeatureLimits(t *testing.T) { AccessListCreateLimit: 5, AccessMonitoringMaxReportRangeLimit: 10, }, - IsTeam: true, + IsTeam: false, IsIGSEnabled: true, IsStripeManaged: true, Questionnaire: true, IsUsageBasedBilling: true, PlayableDatabaseProtocols: player.SupportedDatabaseProtocols, + Entitlements: map[string]webclient.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 5}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 10}, + string(entitlements.AccessRequests): {Enabled: false}, + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + string(entitlements.DB): {Enabled: false}, + string(entitlements.Desktop): {Enabled: false}, + string(entitlements.DeviceTrust): {Enabled: false}, + string(entitlements.ExternalAuditStorage): {Enabled: false}, + string(entitlements.FeatureHiding): {Enabled: false}, + string(entitlements.HSM): {Enabled: false}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: false}, + string(entitlements.K8s): {Enabled: false}, + string(entitlements.MobileDeviceManagement): {Enabled: false}, + string(entitlements.OIDC): {Enabled: false}, + string(entitlements.OktaSCIM): {Enabled: false}, + string(entitlements.OktaUserSync): {Enabled: false}, + string(entitlements.Policy): {Enabled: false}, + string(entitlements.SAML): {Enabled: false}, + string(entitlements.SessionLocks): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.UsageReporting): {Enabled: false}, + }, } // Make a request. @@ -8844,7 +8922,9 @@ func startKubeWithoutCleanup(ctx context.Context, t *testing.T, cfg startKubeOpt Clock: clockwork.NewRealClock(), ClusterFeatures: func() authproto.Features { return authproto.Features{ - Kubernetes: true, + Entitlements: map[string]*authproto.EntitlementInfo{ + string(entitlements.K8s): {Enabled: true}, + }, } }, }, @@ -10379,3 +10459,490 @@ func TestUnstartedServerShutdown(t *testing.T) { // Shutdown the server before starting it shouldn't panic. require.NoError(t, srv.Shutdown(context.Background())) } + +func Test_setEntitlementsWithLegacyLogic(t *testing.T) { + tests := []struct { + name string + config *webclient.WebConfig + clusterFeatures authproto.Features + expected *webclient.WebConfig + }{ + { + name: "sets entitlements", + config: &webclient.WebConfig{}, + clusterFeatures: authproto.Features{ + AccessControls: false, + AccessGraph: false, + AccessList: &clientproto.AccessListFeature{ + CreateLimit: 10, + }, + AccessMonitoring: &clientproto.AccessMonitoringFeature{ + Enabled: false, + MaxReportRangeLimit: 20, + }, + AccessMonitoringConfigured: false, + AccessRequests: &clientproto.AccessRequestsFeature{ + MonthlyRequestLimit: 30, + }, + AdvancedAccessWorkflows: false, + App: false, + Assist: false, + AutomaticUpgrades: false, + Cloud: false, + CustomTheme: "theme", + DB: false, + Desktop: false, + DeviceTrust: &clientproto.DeviceTrustFeature{ + Enabled: false, + DevicesUsageLimit: 40, + }, + ExternalAuditStorage: false, + FeatureHiding: false, + HSM: false, + IdentityGovernance: false, + IsStripeManaged: false, + IsUsageBased: false, + JoinActiveSessions: false, + Kubernetes: false, + MobileDeviceManagement: false, + OIDC: false, + Plugins: false, + Policy: nil, + ProductType: 0, + Questionnaire: false, + RecoveryCodes: false, + SAML: false, + SupportType: 0, + // since present, becomes source of truth for feature enablement + Entitlements: map[string]*authproto.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 99}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 99}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 99}, + string(entitlements.App): {Enabled: true, Limit: 99}, + string(entitlements.CloudAuditLogRetention): {Enabled: true, Limit: 99}, + string(entitlements.DB): {Enabled: true, Limit: 99}, + string(entitlements.Desktop): {Enabled: true, Limit: 99}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 99}, + string(entitlements.ExternalAuditStorage): {Enabled: true, Limit: 99}, + string(entitlements.FeatureHiding): {Enabled: true, Limit: 99}, + string(entitlements.HSM): {Enabled: true, Limit: 99}, + string(entitlements.Identity): {Enabled: true, Limit: 99}, + string(entitlements.JoinActiveSessions): {Enabled: true, Limit: 99}, + string(entitlements.K8s): {Enabled: true, Limit: 99}, + string(entitlements.MobileDeviceManagement): {Enabled: true, Limit: 99}, + string(entitlements.OIDC): {Enabled: true, Limit: 99}, + string(entitlements.OktaSCIM): {Enabled: true, Limit: 99}, + string(entitlements.OktaUserSync): {Enabled: true, Limit: 99}, + string(entitlements.Policy): {Enabled: true, Limit: 99}, + string(entitlements.SAML): {Enabled: true, Limit: 99}, + string(entitlements.SessionLocks): {Enabled: true, Limit: 99}, + string(entitlements.UpsellAlert): {Enabled: true, Limit: 99}, + string(entitlements.UsageReporting): {Enabled: true, Limit: 99}, + }, + }, + expected: &webclient.WebConfig{ + Auth: webclient.WebConfigAuthSettings{}, + AutomaticUpgrades: false, + AutomaticUpgradesTargetVersion: "", + CanJoinSessions: false, + CustomTheme: "", + Edition: "", + IsCloud: false, + IsDashboard: false, + IsStripeManaged: false, + IsTeam: false, + IsUsageBasedBilling: false, + PlayableDatabaseProtocols: nil, + PremiumSupport: false, + ProxyClusterName: "", + Questionnaire: false, + RecoveryCodesEnabled: false, + TunnelPublicAddress: "", + UI: webclient.UIConfig{}, + // set by the equivalent entitlement value + AccessRequests: true, + ExternalAuditStorage: true, + HideInaccessibleFeatures: true, + IsIGSEnabled: true, + IsPolicyEnabled: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + OIDC: true, + SAML: true, + TrustedDevices: true, + FeatureLimits: webclient.FeatureLimits{ + AccessListCreateLimit: 99, + AccessMonitoringMaxReportRangeLimit: 99, + AccessRequestMonthlyRequestLimit: 99, + }, + Entitlements: map[string]webclient.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true, Limit: 99}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 99}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 99}, + string(entitlements.App): {Enabled: true, Limit: 99}, + string(entitlements.CloudAuditLogRetention): {Enabled: true, Limit: 99}, + string(entitlements.DB): {Enabled: true, Limit: 99}, + string(entitlements.Desktop): {Enabled: true, Limit: 99}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 99}, + string(entitlements.ExternalAuditStorage): {Enabled: true, Limit: 99}, + string(entitlements.FeatureHiding): {Enabled: true, Limit: 99}, + string(entitlements.HSM): {Enabled: true, Limit: 99}, + string(entitlements.Identity): {Enabled: true, Limit: 99}, + string(entitlements.JoinActiveSessions): {Enabled: true, Limit: 99}, + string(entitlements.K8s): {Enabled: true, Limit: 99}, + string(entitlements.MobileDeviceManagement): {Enabled: true, Limit: 99}, + string(entitlements.OIDC): {Enabled: true, Limit: 99}, + string(entitlements.OktaSCIM): {Enabled: true, Limit: 99}, + string(entitlements.OktaUserSync): {Enabled: true, Limit: 99}, + string(entitlements.Policy): {Enabled: true, Limit: 99}, + string(entitlements.SAML): {Enabled: true, Limit: 99}, + string(entitlements.SessionLocks): {Enabled: true, Limit: 99}, + string(entitlements.UpsellAlert): {Enabled: true, Limit: 99}, + string(entitlements.UsageReporting): {Enabled: true, Limit: 99}, + }, + }, + }, + { + name: "sets legacy features when no entitlements are present (Identity true)", + config: &webclient.WebConfig{}, + clusterFeatures: authproto.Features{ + AccessControls: false, + AccessGraph: false, + AccessMonitoringConfigured: false, + AdvancedAccessWorkflows: false, + App: false, + Assist: false, + AutomaticUpgrades: false, + Cloud: false, + CustomTheme: "", + DB: false, + Desktop: false, + HSM: false, + IsStripeManaged: false, + IsUsageBased: false, + Kubernetes: false, + Plugins: false, + ProductType: 0, + Questionnaire: false, + RecoveryCodes: false, + SupportType: 0, + // not present + Entitlements: nil, + // will set equivalent entitlement values + ExternalAuditStorage: true, + FeatureHiding: true, + IdentityGovernance: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + OIDC: true, + SAML: true, + AccessRequests: &clientproto.AccessRequestsFeature{ + MonthlyRequestLimit: 88, + }, + AccessList: &clientproto.AccessListFeature{ + CreateLimit: 88, + }, + AccessMonitoring: &clientproto.AccessMonitoringFeature{ + Enabled: true, + MaxReportRangeLimit: 88, + }, + DeviceTrust: &clientproto.DeviceTrustFeature{ + Enabled: true, + DevicesUsageLimit: 88, + }, + Policy: &clientproto.PolicyFeature{ + Enabled: true, + }, + }, + expected: &webclient.WebConfig{ + Auth: webclient.WebConfigAuthSettings{}, + AutomaticUpgrades: false, + AutomaticUpgradesTargetVersion: "", + CanJoinSessions: false, + CustomTheme: "", + Edition: "", + IsCloud: false, + IsDashboard: false, + IsStripeManaged: false, + IsTeam: false, + IsUsageBasedBilling: false, + PlayableDatabaseProtocols: nil, + PremiumSupport: false, + ProxyClusterName: "", + Questionnaire: false, + RecoveryCodesEnabled: false, + TunnelPublicAddress: "", + UI: webclient.UIConfig{}, + // set to legacy feature + AccessRequests: true, + ExternalAuditStorage: true, + HideInaccessibleFeatures: true, + IsIGSEnabled: true, + IsPolicyEnabled: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + OIDC: true, + SAML: true, + TrustedDevices: true, + FeatureLimits: webclient.FeatureLimits{ + AccessListCreateLimit: 88, + AccessMonitoringMaxReportRangeLimit: 88, + AccessRequestMonthlyRequestLimit: 88, + }, + Entitlements: map[string]webclient.EntitlementInfo{ + // no equivalent legacy feature; defaults to false + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + string(entitlements.DB): {Enabled: false}, + string(entitlements.Desktop): {Enabled: false}, + string(entitlements.HSM): {Enabled: false}, + string(entitlements.K8s): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.UsageReporting): {Enabled: false}, + + // set to equivalent legacy feature + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.Identity): {Enabled: true}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + // set to legacy feature "IsIGSEnabled"; true so set true and clear limits + string(entitlements.AccessLists): {Enabled: true}, + string(entitlements.AccessMonitoring): {Enabled: true}, + string(entitlements.AccessRequests): {Enabled: true}, + string(entitlements.DeviceTrust): {Enabled: true}, + string(entitlements.OktaSCIM): {Enabled: true}, + string(entitlements.OktaUserSync): {Enabled: true}, + string(entitlements.SessionLocks): {Enabled: true}, + }, + }, + }, + { + name: "sets legacy features when no entitlements are present (Identity false)", + config: &webclient.WebConfig{}, + clusterFeatures: authproto.Features{ + AccessControls: false, + AccessGraph: false, + AccessMonitoringConfigured: false, + AdvancedAccessWorkflows: false, + App: false, + Assist: false, + AutomaticUpgrades: false, + Cloud: false, + CustomTheme: "", + DB: false, + Desktop: false, + HSM: false, + IsStripeManaged: false, + IsUsageBased: false, + Kubernetes: false, + Plugins: false, + ProductType: 0, + Questionnaire: false, + RecoveryCodes: false, + SupportType: 0, + // not present + Entitlements: nil, + // will set equivalent entitlement values + ExternalAuditStorage: true, + FeatureHiding: true, + IdentityGovernance: false, + JoinActiveSessions: true, + MobileDeviceManagement: true, + OIDC: true, + SAML: true, + AccessRequests: &clientproto.AccessRequestsFeature{ + MonthlyRequestLimit: 88, + }, + AccessList: &clientproto.AccessListFeature{ + CreateLimit: 88, + }, + AccessMonitoring: &clientproto.AccessMonitoringFeature{ + Enabled: true, + MaxReportRangeLimit: 88, + }, + DeviceTrust: &clientproto.DeviceTrustFeature{ + Enabled: true, + DevicesUsageLimit: 88, + }, + Policy: &clientproto.PolicyFeature{ + Enabled: true, + }, + }, + expected: &webclient.WebConfig{ + Auth: webclient.WebConfigAuthSettings{}, + AutomaticUpgrades: false, + AutomaticUpgradesTargetVersion: "", + CanJoinSessions: false, + CustomTheme: "", + Edition: "", + IsCloud: false, + IsDashboard: false, + IsStripeManaged: false, + IsTeam: false, + IsUsageBasedBilling: false, + PlayableDatabaseProtocols: nil, + PremiumSupport: false, + ProxyClusterName: "", + Questionnaire: false, + RecoveryCodesEnabled: false, + TunnelPublicAddress: "", + UI: webclient.UIConfig{}, + // set to legacy feature + AccessRequests: true, + ExternalAuditStorage: true, + HideInaccessibleFeatures: true, + IsIGSEnabled: false, + IsPolicyEnabled: true, + JoinActiveSessions: true, + MobileDeviceManagement: true, + OIDC: true, + SAML: true, + TrustedDevices: true, + FeatureLimits: webclient.FeatureLimits{ + AccessListCreateLimit: 88, + AccessMonitoringMaxReportRangeLimit: 88, + AccessRequestMonthlyRequestLimit: 88, + }, + Entitlements: map[string]webclient.EntitlementInfo{ + // no equivalent legacy feature; defaults to false + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + string(entitlements.DB): {Enabled: false}, + string(entitlements.Desktop): {Enabled: false}, + string(entitlements.HSM): {Enabled: false}, + string(entitlements.K8s): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.UsageReporting): {Enabled: false}, + + // set to equivalent legacy feature + string(entitlements.ExternalAuditStorage): {Enabled: true}, + string(entitlements.FeatureHiding): {Enabled: true}, + string(entitlements.Identity): {Enabled: false}, + string(entitlements.JoinActiveSessions): {Enabled: true}, + string(entitlements.MobileDeviceManagement): {Enabled: true}, + string(entitlements.OIDC): {Enabled: true}, + string(entitlements.Policy): {Enabled: true}, + string(entitlements.SAML): {Enabled: true}, + // set to legacy feature "IsIGSEnabled"; false so set value and keep limits + string(entitlements.AccessLists): {Enabled: true, Limit: 88}, + string(entitlements.AccessMonitoring): {Enabled: true, Limit: 88}, + string(entitlements.AccessRequests): {Enabled: true, Limit: 88}, + string(entitlements.DeviceTrust): {Enabled: true, Limit: 88}, + string(entitlements.OktaSCIM): {Enabled: false}, + string(entitlements.OktaUserSync): {Enabled: false}, + string(entitlements.SessionLocks): {Enabled: false}, + }, + }, + }, + { + name: "retains non-feature field values", + config: &webclient.WebConfig{ + Auth: webclient.WebConfigAuthSettings{ + LocalAuthEnabled: true, + AllowPasswordless: true, + MOTD: "some-message", + }, + PlayableDatabaseProtocols: []string{"play-able"}, + UI: webclient.UIConfig{ + ScrollbackLines: 10, + ShowResources: "foo", + }, + Edition: "edition", + TunnelPublicAddress: "0000", + AutomaticUpgradesTargetVersion: "99", + CustomTheme: "theme", + CanJoinSessions: true, + IsCloud: true, + RecoveryCodesEnabled: true, + IsDashboard: true, + IsUsageBasedBilling: true, + AutomaticUpgrades: true, + Questionnaire: true, + IsStripeManaged: true, + PremiumSupport: true, + }, + clusterFeatures: authproto.Features{ + DeviceTrust: &clientproto.DeviceTrustFeature{}, + AccessRequests: &clientproto.AccessRequestsFeature{}, + AccessList: &clientproto.AccessListFeature{}, + AccessMonitoring: &clientproto.AccessMonitoringFeature{}, + Policy: &clientproto.PolicyFeature{}, + }, + expected: &webclient.WebConfig{ + Auth: webclient.WebConfigAuthSettings{ + LocalAuthEnabled: true, + AllowPasswordless: true, + MOTD: "some-message", + }, + PlayableDatabaseProtocols: []string{"play-able"}, + UI: webclient.UIConfig{ + ScrollbackLines: 10, + ShowResources: "foo", + }, + Edition: "edition", + TunnelPublicAddress: "0000", + AutomaticUpgradesTargetVersion: "99", + CustomTheme: "theme", + CanJoinSessions: true, + IsCloud: true, + RecoveryCodesEnabled: true, + IsDashboard: true, + IsUsageBasedBilling: true, + AutomaticUpgrades: true, + Questionnaire: true, + IsStripeManaged: true, + PremiumSupport: true, + // Default; not under test + ProxyClusterName: "", + FeatureLimits: webclient.FeatureLimits{}, + IsTeam: false, + HideInaccessibleFeatures: false, + IsIGSEnabled: false, + IsPolicyEnabled: false, + ExternalAuditStorage: false, + JoinActiveSessions: false, + AccessRequests: false, + TrustedDevices: false, + OIDC: false, + SAML: false, + MobileDeviceManagement: false, + Entitlements: map[string]webclient.EntitlementInfo{ + string(entitlements.AccessLists): {Enabled: true}, // AccessLists had no previous behavior from an enablement perspective; so we default to true + string(entitlements.AccessMonitoring): {Enabled: false}, + string(entitlements.AccessRequests): {Enabled: false}, + string(entitlements.App): {Enabled: false}, + string(entitlements.CloudAuditLogRetention): {Enabled: false}, + string(entitlements.DB): {Enabled: false}, + string(entitlements.Desktop): {Enabled: false}, + string(entitlements.DeviceTrust): {Enabled: false}, + string(entitlements.ExternalAuditStorage): {Enabled: false}, + string(entitlements.FeatureHiding): {Enabled: false}, + string(entitlements.HSM): {Enabled: false}, + string(entitlements.Identity): {Enabled: false}, + string(entitlements.JoinActiveSessions): {Enabled: false}, + string(entitlements.K8s): {Enabled: false}, + string(entitlements.MobileDeviceManagement): {Enabled: false}, + string(entitlements.OIDC): {Enabled: false}, + string(entitlements.OktaSCIM): {Enabled: false}, + string(entitlements.OktaUserSync): {Enabled: false}, + string(entitlements.Policy): {Enabled: false}, + string(entitlements.SAML): {Enabled: false}, + string(entitlements.SessionLocks): {Enabled: false}, + string(entitlements.UpsellAlert): {Enabled: false}, + string(entitlements.UsageReporting): {Enabled: false}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + setEntitlementsWithLegacyLogic(tt.config, tt.clusterFeatures) + + assert.Equal(t, tt.expected, tt.config) + }) + } +} diff --git a/lib/web/apps.go b/lib/web/apps.go index c2678c6e7821b..7366cdbed5135 100644 --- a/lib/web/apps.go +++ b/lib/web/apps.go @@ -29,17 +29,13 @@ import ( "github.com/gravitational/trace" "github.com/julienschmidt/httprouter" - "github.com/gravitational/teleport" apiclient "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/proto" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - apievents "github.com/gravitational/teleport/api/types/events" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" - "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/reversetunnelclient" - "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/web/app" "github.com/gravitational/teleport/lib/web/ui" @@ -260,58 +256,14 @@ func (h *Handler) createAppSession(w http.ResponseWriter, r *http.Request, p htt ClusterName: result.ClusterName, AWSRoleARN: req.AWSRole, MFAResponse: mfaProtoResponse, + AppName: result.App.GetName(), + URI: result.App.GetURI(), + ClientAddr: r.RemoteAddr, }) if err != nil { return nil, trace.Wrap(err) } - // Extract the identity of the user. - certificate, err := tlsca.ParseCertificatePEM(ws.GetTLSCert()) - if err != nil { - return nil, trace.Wrap(err) - } - identity, err := tlsca.FromSubject(certificate.Subject, certificate.NotAfter) - if err != nil { - return nil, trace.Wrap(err) - } - - userMetadata := identity.GetUserMetadata() - userMetadata.User = ws.GetUser() - userMetadata.AWSRoleARN = req.AWSRole - - // Now that the certificate has been issued, emit a "new session created" - // for all events associated with this certificate. - appSessionStartEvent := &apievents.AppSessionStart{ - Metadata: apievents.Metadata{ - Type: events.AppSessionStartEvent, - Code: events.AppSessionStartCode, - ClusterName: identity.RouteToApp.ClusterName, - }, - ServerMetadata: apievents.ServerMetadata{ - ServerVersion: teleport.Version, - ServerID: h.cfg.HostUUID, - ServerNamespace: apidefaults.Namespace, - }, - SessionMetadata: apievents.SessionMetadata{ - SessionID: identity.RouteToApp.SessionID, - WithMFA: identity.MFAVerified, - PrivateKeyPolicy: string(identity.PrivateKeyPolicy), - }, - UserMetadata: userMetadata, - ConnectionMetadata: apievents.ConnectionMetadata{ - RemoteAddr: r.RemoteAddr, - }, - PublicAddr: identity.RouteToApp.PublicAddr, - AppMetadata: apievents.AppMetadata{ - AppURI: result.App.GetURI(), - AppPublicAddr: result.App.GetPublicAddr(), - AppName: result.App.GetName(), - }, - } - if err := h.cfg.Emitter.EmitAuditEvent(h.cfg.Context, appSessionStartEvent); err != nil { - return nil, trace.Wrap(err) - } - return &CreateAppSessionResponse{ CookieValue: ws.GetName(), SubjectCookieValue: ws.GetBearerToken(), diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index cd70b482fa7ad..9c0ca267130d1 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -195,8 +195,9 @@ func (h *Handler) awsOIDCDeployDatabaseServices(w http.ResponseWriter, r *http.R h.PublicProxyAddr(), iamTokenName, types.Labels{ - types.DiscoveryLabelVPCID: []string{d.VPCID}, - types.DiscoveryLabelRegion: []string{req.Region}, + types.DiscoveryLabelVPCID: []string{d.VPCID}, + types.DiscoveryLabelRegion: []string{req.Region}, + types.DiscoveryLabelAccountID: []string{req.AccountID}, }, ) if err != nil { @@ -369,6 +370,11 @@ func (h *Handler) awsOIDCConfigureAWSAppAccessIAM(w http.ResponseWriter, r *http func (h *Handler) awsOIDCConfigureEC2SSMIAM(w http.ResponseWriter, r *http.Request, p httprouter.Params) (any, error) { queryParams := r.URL.Query() + integrationName := queryParams.Get("integrationName") + if len(integrationName) == 0 { + return nil, trace.BadParameter("missing integrationName param") + } + role := queryParams.Get("role") if err := aws.IsValidIAMRoleName(role); err != nil { return nil, trace.BadParameter("invalid role %q", role) @@ -390,6 +396,11 @@ func (h *Handler) awsOIDCConfigureEC2SSMIAM(w http.ResponseWriter, r *http.Reque proxyPublicURL = "https://" + proxyPublicURL } + clusterName, err := h.GetProxyClient().GetDomainName(r.Context()) + if err != nil { + return nil, trace.Wrap(err) + } + // The script must execute the following command: // teleport integration configure ec2-ssm-iam argsList := []string{ @@ -398,6 +409,8 @@ func (h *Handler) awsOIDCConfigureEC2SSMIAM(w http.ResponseWriter, r *http.Reque fmt.Sprintf("--aws-region=%s", shsprintf.EscapeDefaultContext(region)), fmt.Sprintf("--ssm-document-name=%s", shsprintf.EscapeDefaultContext(ssmDocumentName)), fmt.Sprintf("--proxy-public-url=%s", shsprintf.EscapeDefaultContext(proxyPublicURL)), + fmt.Sprintf("--cluster=%s", shsprintf.EscapeDefaultContext(clusterName)), + fmt.Sprintf("--name=%s", shsprintf.EscapeDefaultContext(integrationName)), } script, err := oneoff.BuildScript(oneoff.OneOffScriptParams{ TeleportArgs: strings.Join(argsList, " "), diff --git a/lib/web/integrations_awsoidc_test.go b/lib/web/integrations_awsoidc_test.go index 41d01db465c7c..ec0b091f80438 100644 --- a/lib/web/integrations_awsoidc_test.go +++ b/lib/web/integrations_awsoidc_test.go @@ -284,30 +284,36 @@ func TestBuildEC2SSMIAMScript(t *testing.T) { { name: "valid", reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "role": []string{"myRole"}, - "ssmDocument": []string{"TeleportDiscoveryInstallerTest"}, + "awsRegion": []string{"us-east-1"}, + "role": []string{"myRole"}, + "ssmDocument": []string{"TeleportDiscoveryInstallerTest"}, + "integrationName": []string{"my-integration"}, }, errCheck: require.NoError, expectedTeleportArgs: "integration configure ec2-ssm-iam " + "--role=myRole " + "--aws-region=us-east-1 " + "--ssm-document-name=TeleportDiscoveryInstallerTest " + - "--proxy-public-url=" + proxyPublicURL, + "--proxy-public-url=" + proxyPublicURL + " " + + "--cluster=localhost " + + "--name=my-integration", }, { name: "valid with symbols in role", reqQuery: url.Values{ - "awsRegion": []string{"us-east-1"}, - "role": []string{"Test+1=2,3.4@5-6_7"}, - "ssmDocument": []string{"TeleportDiscoveryInstallerTest"}, + "awsRegion": []string{"us-east-1"}, + "role": []string{"Test+1=2,3.4@5-6_7"}, + "ssmDocument": []string{"TeleportDiscoveryInstallerTest"}, + "integrationName": []string{"my-integration"}, }, errCheck: require.NoError, expectedTeleportArgs: "integration configure ec2-ssm-iam " + "--role=Test\\+1=2,3.4\\@5-6_7 " + "--aws-region=us-east-1 " + "--ssm-document-name=TeleportDiscoveryInstallerTest " + - "--proxy-public-url=" + proxyPublicURL, + "--proxy-public-url=" + proxyPublicURL + " " + + "--cluster=localhost " + + "--name=my-integration", }, { name: "missing aws-region", diff --git a/lib/web/spiffe.go b/lib/web/spiffe.go new file mode 100644 index 0000000000000..a47e938c51387 --- /dev/null +++ b/lib/web/spiffe.go @@ -0,0 +1,93 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package web + +import ( + "net/http" + "time" + + "github.com/gravitational/trace" + "github.com/julienschmidt/httprouter" + "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" + "github.com/spiffe/go-spiffe/v2/spiffeid" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/tlsca" +) + +// getSPIFFEBundle returns the SPIFFE-compatible trust bundle which allows other +// trust domains to federate with this Teleport cluster. +// +// Mounted at /webapi/spiffe/bundle.json +// +// Must abide by the standard for a "https_web" profile as described in +// https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Federation.md#5-serving-and-consuming-a-spiffe-bundle-endpoint +func (h *Handler) getSPIFFEBundle(w http.ResponseWriter, r *http.Request, _ httprouter.Params) (any, error) { + cn, err := h.GetAccessPoint().GetClusterName() + if err != nil { + return nil, trace.Wrap(err, "fetching cluster name") + } + + td, err := spiffeid.TrustDomainFromString(cn.GetClusterName()) + if err != nil { + return nil, trace.Wrap(err, "creating trust domain") + } + + bundle := spiffebundle.New(td) + // The refresh hint indicates how often a federated trust domain should + // check for updates to the bundle. This should be a low value to ensure + // that CA rotations are picked up quickly. Since we're leveraging + // https_web, it's not critical for a federated trust domain to catch + // all phases of the rotation - however, if we support https_spiffe in + // future, we may need to consider a lower value or enforcing a wait + // period during rotations equivalent to the refresh hint. + bundle.SetRefreshHint(5 * time.Minute) + // TODO(noah): + // For now, we omit the SequenceNumber field. This is only a SHOULD not a + // MUST per the spec. To add this, we will add a sequence number to the + // cert authority and increment it on every update. + + const loadKeysFalse = false + spiffeCA, err := h.GetAccessPoint().GetCertAuthority(r.Context(), types.CertAuthID{ + Type: types.SPIFFECA, + DomainName: cn.GetClusterName(), + }, loadKeysFalse) + if err != nil { + return nil, trace.Wrap(err, "fetching SPIFFE CA") + } + + for _, certPEM := range services.GetTLSCerts(spiffeCA) { + cert, err := tlsca.ParseCertificatePEM(certPEM) + if err != nil { + return nil, trace.Wrap(err, "parsing certificate") + } + bundle.AddX509Authority(cert) + } + + bundleBytes, err := bundle.Marshal() + if err != nil { + return nil, trace.Wrap(err, "marshaling bundle") + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + if _, err = w.Write(bundleBytes); err != nil { + h.logger.DebugContext(h.cfg.Context, "Failed to write SPIFFE bundle response", "error", err) + } + return nil, nil +} diff --git a/lib/web/spiffe_test.go b/lib/web/spiffe_test.go new file mode 100644 index 0000000000000..7d04c80ad7465 --- /dev/null +++ b/lib/web/spiffe_test.go @@ -0,0 +1,71 @@ +/* + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package web + +import ( + "context" + "crypto/x509" + "testing" + + "github.com/gravitational/roundtrip" + "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" + "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/client" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/tlsca" +) + +func TestGetSPIFFEBundle(t *testing.T) { + ctx := context.Background() + env := newWebPack(t, 1) + authServer := env.server.Auth() + cn, err := authServer.GetClusterName() + require.NoError(t, err) + ca, err := authServer.GetCertAuthority(ctx, types.CertAuthID{ + Type: types.SPIFFECA, + DomainName: cn.GetClusterName(), + }, false) + require.NoError(t, err) + + var wantCACerts []*x509.Certificate + for _, certPem := range services.GetTLSCerts(ca) { + cert, err := tlsca.ParseCertificatePEM(certPem) + require.NoError(t, err) + wantCACerts = append(wantCACerts, cert) + } + + clt, err := client.NewWebClient(env.proxies[0].webURL.String(), roundtrip.HTTPClient(client.NewInsecureWebClient())) + require.NoError(t, err) + + res, err := clt.Get(ctx, clt.Endpoint("webapi", "spiffe", "bundle.json"), nil) + require.NoError(t, err) + + td, err := spiffeid.TrustDomainFromString(cn.GetClusterName()) + require.NoError(t, err) + gotBundle, err := spiffebundle.Read(td, res.Reader()) + require.NoError(t, err) + + require.Len(t, gotBundle.X509Authorities(), len(wantCACerts)) + for _, caCert := range wantCACerts { + require.True(t, gotBundle.HasX509Authority(caCert), "certificate not found in bundle") + } +} diff --git a/lib/web/ui/integration.go b/lib/web/ui/integration.go index 3de8c7bbce860..fe0a3c305f21c 100644 --- a/lib/web/ui/integration.go +++ b/lib/web/ui/integration.go @@ -237,6 +237,9 @@ type AWSOIDCDeployDatabaseServiceRequest struct { // Region is the AWS Region for the Service. Region string `json:"region"` + // AccountID is the AWS account to deploy service to. + AccountID string `json:"accountId"` + // TaskRoleARN is the AWS Role's ARN used within the Task execution. // Ensure the AWS Client's Role has `iam:PassRole` for this Role's ARN. // This can be either the ARN or the short name of the AWS Role. diff --git a/package.json b/package.json index 522042577e05a..e2d9408139981 100644 --- a/package.json +++ b/package.json @@ -87,5 +87,5 @@ "tslib": "^2.6.3", "whatwg-fetch": "^3.6.20" }, - "packageManager": "pnpm@9.5.0" + "packageManager": "pnpm@9.7.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fd95be8a0c03e..e4f2e4c8f2b35 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -348,27 +348,27 @@ importers: '@opentelemetry/semantic-conventions': specifier: 1.25.1 version: 1.25.1 + '@xterm/addon-canvas': + specifier: ^0.7.0 + version: 0.7.0(@xterm/xterm@5.5.0) + '@xterm/addon-fit': + specifier: ^0.10.0 + version: 0.10.0(@xterm/xterm@5.5.0) + '@xterm/addon-web-links': + specifier: ^0.11.0 + version: 0.11.0(@xterm/xterm@5.5.0) + '@xterm/addon-webgl': + specifier: ^0.18.0 + version: 0.18.0(@xterm/xterm@5.5.0) + '@xterm/xterm': + specifier: ^5.5.0 + version: 5.5.0 create-react-class: specifier: ^15.6.3 version: 15.7.0 events: specifier: 3.3.0 version: 3.3.0 - xterm: - specifier: ^5.3.0 - version: 5.3.0 - xterm-addon-canvas: - specifier: ^0.5.0 - version: 0.5.0(xterm@5.3.0) - xterm-addon-fit: - specifier: ^0.8.0 - version: 0.8.0(xterm@5.3.0) - xterm-addon-web-links: - specifier: ^0.9.0 - version: 0.9.0(xterm@5.3.0) - xterm-addon-webgl: - specifier: ^0.16.0 - version: 0.16.0(xterm@5.3.0) devDependencies: '@gravitational/build': specifier: workspace:* @@ -446,12 +446,18 @@ importers: '@types/whatwg-url': specifier: ^11.0.5 version: 11.0.5 + '@xterm/addon-fit': + specifier: ^0.10.0 + version: 0.10.0(@xterm/xterm@5.5.0) + '@xterm/xterm': + specifier: ^5.5.0 + version: 5.5.0 electron: - specifier: 31.1.0 - version: 31.1.0 + specifier: 31.3.1 + version: 31.3.1 electron-builder: - specifier: ^25.0.1 - version: 25.0.1(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)) + specifier: ^25.0.3 + version: 25.0.3(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)) electron-notarize: specifier: ^1.2.2 version: 1.2.2 @@ -476,12 +482,6 @@ importers: whatwg-url: specifier: ^13.0.0 version: 13.0.0 - xterm: - specifier: ^5.3.0 - version: 5.3.0 - xterm-addon-fit: - specifier: ^0.8.0 - version: 0.8.0(xterm@5.3.0) zod: specifier: ^3.23.8 version: 3.23.8 @@ -2899,6 +2899,29 @@ packages: resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} engines: {node: '>=10.0.0'} + '@xterm/addon-canvas@0.7.0': + resolution: {integrity: sha512-LF5LYcfvefJuJ7QotNRdRSPc9YASAVDeoT5uyXS/nZshZXjYplGXRECBGiznwvhNL2I8bq1Lf5MzRwstsYQ2Iw==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/addon-fit@0.10.0': + resolution: {integrity: sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/addon-web-links@0.11.0': + resolution: {integrity: sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/addon-webgl@0.18.0': + resolution: {integrity: sha512-xCnfMBTI+/HKPdRnSOHaJDRqEpq2Ugy8LEj9GiY4J3zJObo3joylIFaMvzBwbYRg8zLtkO0KQaStCeSfoaI2/w==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/xterm@5.5.0': + resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} @@ -3063,15 +3086,15 @@ packages: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} - app-builder-bin@5.0.0-alpha.6: - resolution: {integrity: sha512-KVrQQpaYHTlzuj1TE8k+qwwu/o/R8bsFyglUl/3guc2MUbSYvVqeAlxucotAxfp4SnNNBdNE6GGMbhqAKagakQ==} + app-builder-bin@5.0.0-alpha.7: + resolution: {integrity: sha512-ww2mK4ITUvqisnqOuUWAeHzokpPidyZ7a0ZkwW+V7sF5/Pdi2OldkRjAWqEzn6Xtmj3SLVT84as4wB59A6jJ4g==} - app-builder-lib@25.0.1: - resolution: {integrity: sha512-zpSaCgGnv1D+dv9IC/ry/x4JAuqHsW/VFDp7lg+IzvTOIgLJkfqyavyP5gEOtUFI5rOO3bwB2TENV5i6lLIpIQ==} + app-builder-lib@25.0.3: + resolution: {integrity: sha512-c0LJCJMGgDDGmZUSKeyDYKI5rYc6sQ4PS0Ak62HWArotHDwgAk9qIIewNnvIn/9KskEGwHQr8Y/TumWRqUKRwQ==} engines: {node: '>=14.0.0'} peerDependencies: - dmg-builder: 25.0.1 - electron-builder-squirrel-windows: 25.0.1 + dmg-builder: 25.0.3 + electron-builder-squirrel-windows: 25.0.3 app-root-dir@1.0.2: resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} @@ -3435,8 +3458,8 @@ packages: resolution: {integrity: sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg==} engines: {node: '>=12.0.0'} - builder-util@25.0.1: - resolution: {integrity: sha512-bxT7+1rnxEGIZGrzBdMAL0brasBmQV4bon3sZC0XC4V2Za4FZ7CXAO9tuetuVpFXYFau+6BL63UbN9HFGMmV5g==} + builder-util@25.0.3: + resolution: {integrity: sha512-eH5c1ukdY2xjtFQWQ6jlzEuXuqcuAVc3UQ6V6fdYu9Kg3CkDbCR82Mox42uaJDmee9WXSbP/88cOworFdOHPhw==} bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} @@ -4100,8 +4123,8 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dmg-builder@25.0.1: - resolution: {integrity: sha512-9mGcvQeQBsXOAuqJf5Z0xTsa0LQZmqaLbc5n6TucviN16OjyRsieNv2ogvEvJPScL8jyPSM062FHAhxsVys0Hg==} + dmg-builder@25.0.3: + resolution: {integrity: sha512-RAzB1NSOkzDA19Kl+R/rndYFfMCZDN4pmg5TNwQPeV+ICig12xQDqlPoql1Eay79pXM45CG74aTuBOcK/thGJg==} dmg-license@1.0.11: resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} @@ -4182,11 +4205,11 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-builder-squirrel-windows@25.0.1: - resolution: {integrity: sha512-MsfO7wHky5aYf72i9wFd1hZINyQHvnB4o2CHcXnEzsM21WHZJpXol62NBJhp+1pk6fuARA0jF1DtAcBco+y9YA==} + electron-builder-squirrel-windows@25.0.3: + resolution: {integrity: sha512-VeKeCKn8VgMG3loPnCtxPcximwpyb9a1YVubsyYMN/0CDGlsjfwdQEjrU5FD2/DkbZT7ghjei4QGjCQkRlZ1Cg==} - electron-builder@25.0.1: - resolution: {integrity: sha512-1ft2JHDQeXRicAC8Icqf0ErzeY5cDXesmkKZsI9EWzOlvm+Dm6z8oRpPt39IFl7LbPlJ2yRrLE7DahktiRTFrg==} + electron-builder@25.0.3: + resolution: {integrity: sha512-CToK0oEH/vxTbnEhXgInQWAuPEgkj11nQ3Jlse/Pc/aPNULxRSimH2UodZHrVlmVLozI4XVJqqh+pTVFXXZBaw==} engines: {node: '>=14.0.0'} hasBin: true @@ -4195,8 +4218,8 @@ packages: engines: {node: '>= 10.0.0'} deprecated: Please use @electron/notarize moving forward. There is no API change, just a package name change - electron-publish@25.0.1: - resolution: {integrity: sha512-9ADYaKARy9rfCgiaFt/q2YJxZdx26WAZbnq06LBaZEg48YnlyPBo2ZwcIVbt6+RszTOgKvaZY/KqT6GkDRiikw==} + electron-publish@25.0.3: + resolution: {integrity: sha512-wSGm+TFK2lArswIFBPLuIRHbo945s3MCvG5y1xVC57zL/PsrElUkaGH2ERtRrcKNpaDNq77rDA9JnMJhAFJjUg==} electron-to-chromium@1.4.805: resolution: {integrity: sha512-8W4UJwX/w9T0QSzINJckTKG6CYpAUTqsaWcWIsdud3I1FYJcMgW9QqT1/4CBff/pP/TihWh13OmiyY8neto6vw==} @@ -4212,8 +4235,8 @@ packages: '@swc/core': optional: true - electron@31.1.0: - resolution: {integrity: sha512-TBOwqLxSxnx6+pH6GMri7R3JPH2AkuGJHfWZS0p1HsmN+Qr1T9b0IRJnnehSd/3NZAmAre4ft9Ljec7zjyKFJA==} + electron@31.3.1: + resolution: {integrity: sha512-9fiuWlRhBfygtcT+auRd/WdBK/f8LZZcrpx0RjpXhH2DPTP/PfnkC4JB1PW55qCbGbh4wAgkYbf4ExIag8oGCA==} engines: {node: '>= 12.20.55'} hasBin: true @@ -8264,34 +8287,6 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - xterm-addon-canvas@0.5.0: - resolution: {integrity: sha512-QOo/eZCMrCleAgMimfdbaZCgmQRWOml63Ued6RwQ+UTPvQj3Av9QKx3xksmyYrDGRO/AVRXa9oNuzlYvLdmoLQ==} - deprecated: This package is now deprecated. Move to @xterm/addon-canvas instead. - peerDependencies: - xterm: ^5.0.0 - - xterm-addon-fit@0.8.0: - resolution: {integrity: sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==} - deprecated: This package is now deprecated. Move to @xterm/addon-fit instead. - peerDependencies: - xterm: ^5.0.0 - - xterm-addon-web-links@0.9.0: - resolution: {integrity: sha512-LIzi4jBbPlrKMZF3ihoyqayWyTXAwGfu4yprz1aK2p71e9UKXN6RRzVONR0L+Zd+Ik5tPVI9bwp9e8fDTQh49Q==} - deprecated: This package is now deprecated. Move to @xterm/addon-web-links instead. - peerDependencies: - xterm: ^5.0.0 - - xterm-addon-webgl@0.16.0: - resolution: {integrity: sha512-E8cq1AiqNOv0M/FghPT+zPAEnvIQRDbAbkb04rRYSxUym69elPWVJ4sv22FCLBqM/3LcrmBLl/pELnBebVFKgA==} - deprecated: This package is now deprecated. Move to @xterm/addon-webgl instead. - peerDependencies: - xterm: ^5.0.0 - - xterm@5.3.0: - resolution: {integrity: sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==} - deprecated: This package is now deprecated. Move to @xterm/xterm instead. - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -11846,6 +11841,24 @@ snapshots: '@xmldom/xmldom@0.8.10': {} + '@xterm/addon-canvas@0.7.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/addon-fit@0.10.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/addon-web-links@0.11.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/addon-webgl@0.18.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/xterm@5.5.0': {} + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} @@ -12000,9 +12013,9 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - app-builder-bin@5.0.0-alpha.6: {} + app-builder-bin@5.0.0-alpha.7: {} - app-builder-lib@25.0.1(dmg-builder@25.0.1(electron-builder-squirrel-windows@25.0.1))(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)): + app-builder-lib@25.0.3(dmg-builder@25.0.3(electron-builder-squirrel-windows@25.0.3))(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)): dependencies: '@develar/schema-utils': 2.6.5 '@electron/notarize': 2.3.2 @@ -12013,14 +12026,14 @@ snapshots: '@types/fs-extra': 9.0.13 async-exit-hook: 2.0.1 bluebird-lst: 1.0.9 - builder-util: 25.0.1 + builder-util: 25.0.3 builder-util-runtime: 9.2.5 chromium-pickle-js: 0.2.0 debug: 4.3.4(supports-color@5.5.0) - dmg-builder: 25.0.1(electron-builder-squirrel-windows@25.0.1) + dmg-builder: 25.0.3(electron-builder-squirrel-windows@25.0.3) ejs: 3.1.10 - electron-builder-squirrel-windows: 25.0.1(dmg-builder@25.0.1) - electron-publish: 25.0.1 + electron-builder-squirrel-windows: 25.0.3(dmg-builder@25.0.3) + electron-publish: 25.0.3 form-data: 4.0.0 fs-extra: 10.1.0 hosted-git-info: 4.1.0 @@ -12563,11 +12576,11 @@ snapshots: transitivePeerDependencies: - supports-color - builder-util@25.0.1: + builder-util@25.0.3: dependencies: 7zip-bin: 5.2.0 '@types/debug': 4.1.8 - app-builder-bin: 5.0.0-alpha.6 + app-builder-bin: 5.0.0-alpha.7 bluebird-lst: 1.0.9 builder-util-runtime: 9.2.5 chalk: 4.1.2 @@ -13320,10 +13333,10 @@ snapshots: dependencies: path-type: 4.0.0 - dmg-builder@25.0.1(electron-builder-squirrel-windows@25.0.1): + dmg-builder@25.0.3(electron-builder-squirrel-windows@25.0.3): dependencies: - app-builder-lib: 25.0.1(dmg-builder@25.0.1(electron-builder-squirrel-windows@25.0.1))(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)) - builder-util: 25.0.1 + app-builder-lib: 25.0.3(dmg-builder@25.0.3(electron-builder-squirrel-windows@25.0.3))(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)) + builder-util: 25.0.3 builder-util-runtime: 9.2.5 fs-extra: 10.1.0 iconv-lite: 0.6.3 @@ -13421,24 +13434,24 @@ snapshots: dependencies: jake: 10.8.5 - electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1): + electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3): dependencies: - app-builder-lib: 25.0.1(dmg-builder@25.0.1(electron-builder-squirrel-windows@25.0.1))(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)) + app-builder-lib: 25.0.3(dmg-builder@25.0.3(electron-builder-squirrel-windows@25.0.3))(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)) archiver: 5.3.2 - builder-util: 25.0.1 + builder-util: 25.0.3 fs-extra: 10.1.0 transitivePeerDependencies: - bluebird - dmg-builder - supports-color - electron-builder@25.0.1(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)): + electron-builder@25.0.3(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)): dependencies: - app-builder-lib: 25.0.1(dmg-builder@25.0.1(electron-builder-squirrel-windows@25.0.1))(electron-builder-squirrel-windows@25.0.1(dmg-builder@25.0.1)) - builder-util: 25.0.1 + app-builder-lib: 25.0.3(dmg-builder@25.0.3(electron-builder-squirrel-windows@25.0.3))(electron-builder-squirrel-windows@25.0.3(dmg-builder@25.0.3)) + builder-util: 25.0.3 builder-util-runtime: 9.2.5 chalk: 4.1.2 - dmg-builder: 25.0.1(electron-builder-squirrel-windows@25.0.1) + dmg-builder: 25.0.3(electron-builder-squirrel-windows@25.0.3) fs-extra: 10.1.0 is-ci: 3.0.1 lazy-val: 1.0.5 @@ -13457,10 +13470,10 @@ snapshots: transitivePeerDependencies: - supports-color - electron-publish@25.0.1: + electron-publish@25.0.3: dependencies: '@types/fs-extra': 9.0.13 - builder-util: 25.0.1 + builder-util: 25.0.3 builder-util-runtime: 9.2.5 chalk: 4.1.2 fs-extra: 10.1.0 @@ -13485,7 +13498,7 @@ snapshots: transitivePeerDependencies: - supports-color - electron@31.1.0: + electron@31.3.1: dependencies: '@electron/get': 2.0.2 '@types/node': 20.14.9 @@ -18379,24 +18392,6 @@ snapshots: xtend@4.0.2: {} - xterm-addon-canvas@0.5.0(xterm@5.3.0): - dependencies: - xterm: 5.3.0 - - xterm-addon-fit@0.8.0(xterm@5.3.0): - dependencies: - xterm: 5.3.0 - - xterm-addon-web-links@0.9.0(xterm@5.3.0): - dependencies: - xterm: 5.3.0 - - xterm-addon-webgl@0.16.0(xterm@5.3.0): - dependencies: - xterm: 5.3.0 - - xterm@5.3.0: {} - y18n@5.0.8: {} yallist@2.1.2: {} diff --git a/proto/teleport/lib/teleterm/vnet/v1/vnet_service.proto b/proto/teleport/lib/teleterm/vnet/v1/vnet_service.proto index c9d7e5d90f606..895985b043cb1 100644 --- a/proto/teleport/lib/teleterm/vnet/v1/vnet_service.proto +++ b/proto/teleport/lib/teleterm/vnet/v1/vnet_service.proto @@ -80,4 +80,5 @@ enum BackgroundItemStatus { BACKGROUND_ITEM_STATUS_ENABLED = 2; BACKGROUND_ITEM_STATUS_REQUIRES_APPROVAL = 3; BACKGROUND_ITEM_STATUS_NOT_FOUND = 4; + BACKGROUND_ITEM_STATUS_NOT_SUPPORTED = 5; } diff --git a/tool/tctl/common/admin_action_test.go b/tool/tctl/common/admin_action_test.go index 48d9bec14bdcc..51ffb7cb893f1 100644 --- a/tool/tctl/common/admin_action_test.go +++ b/tool/tctl/common/admin_action_test.go @@ -40,6 +40,7 @@ import ( "github.com/gravitational/teleport/api/mfa" "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/mocku2f" @@ -954,8 +955,10 @@ func newAdminActionTestSuite(t *testing.T) *adminActionTestSuite { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - OIDC: true, - SAML: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.OIDC: {Enabled: true}, + entitlements.SAML: {Enabled: true}, + }, }, }) diff --git a/tool/tctl/common/auth_command.go b/tool/tctl/common/auth_command.go index 255c6922c68ee..bfe6edc3c9f2c 100644 --- a/tool/tctl/common/auth_command.go +++ b/tool/tctl/common/auth_command.go @@ -895,6 +895,7 @@ func (a *AuthCommand) generateUserKeys(ctx context.Context, clusterAPI certifica Name: a.appName, PublicAddr: server.GetApp().GetPublicAddr(), ClusterName: a.leafCluster, + URI: server.GetApp().GetURI(), } // TODO (Joerger): DELETE IN v17.0.0 diff --git a/tool/tctl/common/edit_command_test.go b/tool/tctl/common/edit_command_test.go index a84b34b15bd03..b42517ac70382 100644 --- a/tool/tctl/common/edit_command_test.go +++ b/tool/tctl/common/edit_command_test.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/modules" @@ -333,8 +334,10 @@ func TestEditEnterpriseResources(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - OIDC: true, - SAML: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.OIDC: {Enabled: true}, + entitlements.SAML: {Enabled: true}, + }, }, }) log := utils.NewSlogLoggerForTests() diff --git a/tool/tctl/common/plugin/okta.go b/tool/tctl/common/plugin/okta.go index 75c5bcb2e7c7c..e63ee8a512610 100644 --- a/tool/tctl/common/plugin/okta.go +++ b/tool/tctl/common/plugin/okta.go @@ -34,7 +34,7 @@ import ( ) func (p *PluginsCommand) initInstallOkta(parent *kingpin.CmdClause) { - p.install.okta.cmd = parent.Command("okta", "Install an okta integration") + p.install.okta.cmd = parent.Command("okta", "Install an Okta integration.") p.install.okta.cmd. Flag("name", "Name of the plugin resource to create"). Default("okta"). diff --git a/tool/tctl/common/plugin/plugins_command.go b/tool/tctl/common/plugin/plugins_command.go index 56bebe1a655f9..ba6c92f7ae5a9 100644 --- a/tool/tctl/common/plugin/plugins_command.go +++ b/tool/tctl/common/plugin/plugins_command.go @@ -86,7 +86,7 @@ func (p *PluginsCommand) Initialize(app *kingpin.Application, config *servicecfg pluginsCommand := app.Command("plugins", "Manage Teleport plugins.").Hidden() p.cleanupCmd = pluginsCommand.Command("cleanup", "Cleans up the given plugin type.") - p.cleanupCmd.Arg("type", "The type of plugin to cleanup. Only supports okta at present.").Required().EnumVar(&p.pluginType, string(types.PluginTypeOkta)) + p.cleanupCmd.Arg("type", "The type of plugin to clean up. Only supports Okta at present.").Required().EnumVar(&p.pluginType, string(types.PluginTypeOkta)) p.cleanupCmd.Flag("dry-run", "Dry run the cleanup command. Dry run defaults to on.").Default("true").BoolVar(&p.dryRun) p.initInstall(pluginsCommand, config) @@ -101,7 +101,7 @@ func (p *PluginsCommand) initInstall(parent *kingpin.CmdClause, config *servicec } func (p *PluginsCommand) initInstallSCIM(parent *kingpin.CmdClause) { - p.install.scim.cmd = p.install.cmd.Command("scim", "Install a new SCIM integration") + p.install.scim.cmd = p.install.cmd.Command("scim", "Install a new SCIM integration.") p.install.scim.cmd. Flag("name", "The name of the SCIM plugin resource to create"). Default("scim"). @@ -130,7 +130,7 @@ func (p *PluginsCommand) initInstallSCIM(parent *kingpin.CmdClause) { } func (p *PluginsCommand) initDelete(parent *kingpin.CmdClause) { - p.delete.cmd = parent.Command("delete", "Remove a plugin instance") + p.delete.cmd = parent.Command("delete", "Remove a plugin instance.") p.delete.cmd. Arg("name", "The name of the SCIM plugin resource to delete"). StringVar(&p.delete.name) diff --git a/tool/tctl/common/resource_command.go b/tool/tctl/common/resource_command.go index 4cc2e32a90a38..524d9db10472c 100644 --- a/tool/tctl/common/resource_command.go +++ b/tool/tctl/common/resource_command.go @@ -294,7 +294,7 @@ func (rc *ResourceCommand) GetMany(ctx context.Context, client *authclient.Clien } resources = append(resources, collection.resources()...) } - if err := utils.WriteYAML(os.Stdout, resources); err != nil { + if err := utils.WriteYAML(rc.stdout, resources); err != nil { return trace.Wrap(err) } return nil diff --git a/tool/tctl/common/resource_command_test.go b/tool/tctl/common/resource_command_test.go index 5fdaf282691ff..4b4e2f5cccf56 100644 --- a/tool/tctl/common/resource_command_test.go +++ b/tool/tctl/common/resource_command_test.go @@ -34,6 +34,7 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/testing/protocmp" "k8s.io/apimachinery/pkg/util/yaml" @@ -44,6 +45,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/discoveryconfig" "github.com/gravitational/teleport/api/types/header" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/config" @@ -1410,6 +1412,17 @@ func TestCreateResources(t *testing.T) { test.create(t, rootClient) }) } + + // Verify that the created resources appear in tctl get all + out, err := runResourceCommand(t, rootClient, []string{"get", "all"}) + require.NoError(t, err) + s := out.String() + require.NotEmpty(t, s) + assert.Contains(t, s, "kind: github") + assert.Contains(t, s, "kind: cluster_auth_preference") + assert.Contains(t, s, "kind: cluster_networking_config") + assert.Contains(t, s, "kind: user") + assert.Contains(t, s, "kind: role") } func testCreateGithubConnector(t *testing.T, clt *authclient.Client) { @@ -2020,8 +2033,10 @@ func TestCreateEnterpriseResources(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - OIDC: true, - SAML: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.OIDC: {Enabled: true}, + entitlements.SAML: {Enabled: true}, + }, }, }) @@ -2048,6 +2063,13 @@ func TestCreateEnterpriseResources(t *testing.T) { }) } + // Verify that the created resources appear in tctl get all + out, err := runResourceCommand(t, clt, []string{"get", "all"}) + require.NoError(t, err) + s := out.String() + require.NotEmpty(t, s) + assert.Contains(t, s, "kind: saml") + assert.Contains(t, s, "kind: oidc") } func testCreateOIDCConnector(t *testing.T, clt *authclient.Client) { diff --git a/tool/teleport/common/debug.go b/tool/teleport/common/debug.go index b8fe5fda49f31..fda61c91e43b8 100644 --- a/tool/teleport/common/debug.go +++ b/tool/teleport/common/debug.go @@ -176,9 +176,10 @@ func newDebugClient(configPath string) (DebugClient, string, string, error) { } // ReadConfigFile returns nil configuration if the file doesn't exists. - // In that case, fallback to default data dir path. + // In that case, fallback to default data dir path. The data directory + // is not required so should use the default if not specified. dataDir := defaults.DataDir - if cfg != nil { + if cfg != nil && cfg.DataDir != "" { dataDir = cfg.DataDir } diff --git a/tool/teleport/common/integration_configure.go b/tool/teleport/common/integration_configure.go index dab36f0a5f8b3..ca2296555e3cf 100644 --- a/tool/teleport/common/integration_configure.go +++ b/tool/teleport/common/integration_configure.go @@ -92,6 +92,8 @@ func onIntegrationConfEC2SSMIAM(ctx context.Context, params config.IntegrationCo IntegrationRole: params.RoleName, SSMDocumentName: params.SSMDocumentName, ProxyPublicURL: params.ProxyPublicURL, + ClusterName: params.ClusterName, + IntegrationName: params.IntegrationName, } return trace.Wrap(awsoidc.ConfigureEC2SSM(ctx, awsClt, confReq)) } diff --git a/tool/teleport/common/teleport.go b/tool/teleport/common/teleport.go index 02f846853e697..b139f8cff3080 100644 --- a/tool/teleport/common/teleport.go +++ b/tool/teleport/common/teleport.go @@ -484,6 +484,8 @@ func Run(options Options) (app *kingpin.Application, executedCommand string, con integrationConfEC2SSMCmd.Flag("ssm-document-name", "The AWS SSM Document name to create that will be used to install teleport.").Required().StringVar(&ccf.IntegrationConfEC2SSMIAMArguments.SSMDocumentName) integrationConfEC2SSMCmd.Flag("proxy-public-url", "Proxy Public URL (eg https://mytenant.teleport.sh).").StringVar(&ccf. IntegrationConfEC2SSMIAMArguments.ProxyPublicURL) + integrationConfEC2SSMCmd.Flag("cluster", "Teleport Cluster's name.").Required().StringVar(&ccf.IntegrationConfEC2SSMIAMArguments.ClusterName) + integrationConfEC2SSMCmd.Flag("name", "Integration name.").Required().StringVar(&ccf.IntegrationConfEC2SSMIAMArguments.IntegrationName) integrationConfAWSAppAccessCmd := integrationConfigureCmd.Command("aws-app-access-iam", "Adds required IAM permissions to connect to AWS using App Access.") integrationConfAWSAppAccessCmd.Flag("role", "The AWS Role name used by the AWS OIDC Integration.").Required().StringVar(&ccf.IntegrationConfAWSAppAccessIAMArguments.RoleName) diff --git a/tool/teleport/testenv/test_server.go b/tool/teleport/testenv/test_server.go index aa479fa51dd41..bdb1dcf9bc01f 100644 --- a/tool/teleport/testenv/test_server.go +++ b/tool/teleport/testenv/test_server.go @@ -44,6 +44,7 @@ import ( "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/api/utils/keys" apisshutils "github.com/gravitational/teleport/api/utils/sshutils" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/authclient" @@ -435,9 +436,11 @@ func (p *cliModules) PrintVersion() { // Features returns supported features func (p *cliModules) Features() modules.Features { return modules.Features{ - Kubernetes: true, - DB: true, - App: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + entitlements.DB: {Enabled: true}, + entitlements.App: {Enabled: true}, + }, AdvancedAccessWorkflows: true, AccessControls: true, } diff --git a/tool/tsh/common/access_request_test.go b/tool/tsh/common/access_request_test.go index f0673bfe7ad85..7f25c5157149b 100644 --- a/tool/tsh/common/access_request_test.go +++ b/tool/tsh/common/access_request_test.go @@ -29,6 +29,7 @@ import ( "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/asciitable" "github.com/gravitational/teleport/lib/modules" @@ -40,7 +41,9 @@ func TestAccessRequestSearch(t *testing.T) { modules.SetTestModules(t, &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - Kubernetes: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + }, }, }, ) diff --git a/tool/tsh/common/app.go b/tool/tsh/common/app.go index d55dd89f1bc62..eb7964e43a33f 100644 --- a/tool/tsh/common/app.go +++ b/tool/tsh/common/app.go @@ -345,6 +345,7 @@ func onAppConfig(cf *CLIConf) error { AWSRoleARN: app.AWSRoleARN, AzureIdentity: app.AzureIdentity, GCPServiceAccount: app.GCPServiceAccount, + URI: app.GetURI(), } conf, err := formatAppConfig(tc, profile, routeToApp, cf.Format) if err != nil { @@ -528,6 +529,7 @@ func getAppInfo(cf *CLIConf, tc *client.TeleportClient, matchRouteToApp func(tls Name: app.GetName(), PublicAddr: app.GetPublicAddr(), ClusterName: tc.SiteName, + URI: app.GetURI(), }, app: app, } @@ -655,5 +657,6 @@ func tlscaRouteToAppToProto(route tlsca.RouteToApp) proto.RouteToApp { AWSRoleARN: route.AWSRoleARN, AzureIdentity: route.AzureIdentity, GCPServiceAccount: route.GCPServiceAccount, + URI: route.URI, } } diff --git a/tool/tsh/common/app_local_proxy.go b/tool/tsh/common/app_local_proxy.go index ab7fba8de5a86..619a39859e608 100644 --- a/tool/tsh/common/app_local_proxy.go +++ b/tool/tsh/common/app_local_proxy.go @@ -60,10 +60,6 @@ func (a *localProxyApp) StartLocalProxy(ctx context.Context, opts ...alpnproxy.L if err := a.startLocalALPNProxy(ctx, a.port, false /*withTLS*/, opts...); err != nil { return trace.Wrap(err) } - - if a.port == "" { - fmt.Println("To avoid port randomization, you can choose the listening port using the --port flag.") - } return nil } @@ -72,10 +68,6 @@ func (a *localProxyApp) StartLocalProxyWithTLS(ctx context.Context, opts ...alpn if err := a.startLocalALPNProxy(ctx, a.port, true /*withTLS*/, opts...); err != nil { return trace.Wrap(err) } - - if a.port == "" { - fmt.Println("To avoid port randomization, you can choose the listening port using the --port flag.") - } return nil } @@ -88,10 +80,6 @@ func (a *localProxyApp) StartLocalProxyWithForwarder(ctx context.Context, forwar if err := a.startLocalForwardProxy(ctx, a.port, forwardMatcher); err != nil { return trace.Wrap(err) } - - if a.port == "" { - fmt.Println("To avoid port randomization, you can choose the listening port using the --port flag.") - } return nil } @@ -154,8 +142,6 @@ func (a *localProxyApp) startLocalALPNProxy(ctx context.Context, port string, wi return trace.Wrap(err) } - fmt.Printf("Proxying connections to %s on %v\n", a.appInfo.RouteToApp.Name, a.localALPNProxy.GetAddr()) - go func() { if err = a.localALPNProxy.Start(ctx); err != nil { log.WithError(err).Errorf("Failed to start local ALPN proxy.") @@ -206,3 +192,7 @@ func (a *localProxyApp) startLocalForwardProxy(ctx context.Context, port string, }() return nil } + +func (a *localProxyApp) GetAddr() string { + return a.localALPNProxy.GetAddr() +} diff --git a/tool/tsh/common/app_test.go b/tool/tsh/common/app_test.go index 72b13180c59f9..7ffe458a7ba87 100644 --- a/tool/tsh/common/app_test.go +++ b/tool/tsh/common/app_test.go @@ -37,10 +37,12 @@ import ( "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" + apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/asciitable" "github.com/gravitational/teleport/lib/auth/mocku2f" "github.com/gravitational/teleport/lib/client" + "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/service/servicecfg" testserver "github.com/gravitational/teleport/tool/teleport/testenv" ) @@ -261,6 +263,26 @@ func TestAppCommands(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, app.name, resp.Header.Get("Server")) + // Verify that the app.session.start event was emitted. + if app.cluster == "root" { + require.EventuallyWithT(t, func(t *assert.CollectT) { + now := time.Now() + ctx := context.Background() + es, _, err := rootAuthServer.SearchEvents(ctx, events.SearchEventsRequest{ + From: now.Add(-time.Hour), + To: now.Add(time.Hour), + Order: types.EventOrderDescending, + EventTypes: []string{events.AppSessionStartEvent}, + }) + assert.NoError(t, err) + + for _, e := range es { + assert.Equal(t, e.(*apievents.AppSessionStart).AppName, app.name) + return + } + t.Errorf("failed to find AppSessionStartCode event (0/%d events matched)", len(es)) + }, 5*time.Second, 500*time.Millisecond) + } // app logout. err = Run(ctx, []string{ "app", diff --git a/tool/tsh/common/db_test.go b/tool/tsh/common/db_test.go index 3cca05d12162e..ccb239057cf3d 100644 --- a/tool/tsh/common/db_test.go +++ b/tool/tsh/common/db_test.go @@ -40,6 +40,7 @@ import ( apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/fixtures" @@ -76,7 +77,9 @@ func TestTshDB(t *testing.T) { &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - DB: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.DB: {Enabled: true}, + }, }, }, ) diff --git a/tool/tsh/common/hardware_key_test.go b/tool/tsh/common/hardware_key_test.go index 7e4bcd4cbc233..4c37d45a92960 100644 --- a/tool/tsh/common/hardware_key_test.go +++ b/tool/tsh/common/hardware_key_test.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/auth/mocku2f" @@ -292,7 +293,9 @@ func TestHardwareKeyApp(t *testing.T) { testModules := &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - App: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.App: {Enabled: true}, + }, }, } modules.SetTestModules(t, testModules) diff --git a/tool/tsh/common/kube_test.go b/tool/tsh/common/kube_test.go index c8f6226b47090..5cd3aefd1ffbd 100644 --- a/tool/tsh/common/kube_test.go +++ b/tool/tsh/common/kube_test.go @@ -47,6 +47,7 @@ import ( "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/keypaths" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/asciitable" "github.com/gravitational/teleport/lib/defaults" @@ -320,7 +321,9 @@ func TestKubeSelection(t *testing.T) { &modules.TestModules{ TestBuildType: modules.BuildEnterprise, TestFeatures: modules.Features{ - Kubernetes: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + }, }, }, ) diff --git a/tool/tsh/common/play.go b/tool/tsh/common/play.go index 0c78b17fd412f..67614b161bb07 100644 --- a/tool/tsh/common/play.go +++ b/tool/tsh/common/play.go @@ -1,18 +1,18 @@ -/* -Copyright 2016-2023 Gravitational, Inc. - -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. -*/ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package common diff --git a/tool/tsh/common/proxy.go b/tool/tsh/common/proxy.go index 53866dede32ec..fca65feafb46d 100644 --- a/tool/tsh/common/proxy.go +++ b/tool/tsh/common/proxy.go @@ -396,6 +396,11 @@ func onProxyCommandApp(cf *CLIConf) error { return trace.Wrap(err) } + fmt.Printf("Proxying connections to %s on %v\n", cf.AppName, proxyApp.GetAddr()) + if cf.LocalProxyPort == "" { + fmt.Println("To avoid port randomization, you can choose the listening port using the --port flag.") + } + defer func() { if err := proxyApp.Close(); err != nil { log.WithError(err).Error("Failed to close app proxy.") diff --git a/tool/tsh/common/tsh.go b/tool/tsh/common/tsh.go index a7fc58543c477..aa5afe53ac819 100644 --- a/tool/tsh/common/tsh.go +++ b/tool/tsh/common/tsh.go @@ -31,7 +31,7 @@ import ( "os" "os/exec" "os/signal" - "path" + "path/filepath" "regexp" "runtime" "runtime/pprof" @@ -596,7 +596,7 @@ func Main() { // lets see: if the executable name is 'ssh' or 'scp' we convert // that to "tsh ssh" or "tsh scp" - switch path.Base(os.Args[0]) { + switch filepath.Base(os.Args[0]) { case "ssh": cmdLine = append([]string{"ssh"}, cmdLineOrig...) case "scp": @@ -5172,10 +5172,10 @@ func serializeEnvironment(profile *client.ProfileStatus, format string) (string, func setEnvFlags(cf *CLIConf) { // these can only be set with env vars. if homeDir := os.Getenv(types.HomeEnvVar); homeDir != "" { - cf.HomePath = path.Clean(homeDir) + cf.HomePath = filepath.Clean(homeDir) } if configPath := os.Getenv(globalTshConfigEnvVar); configPath != "" { - cf.GlobalTshConfigPath = path.Clean(configPath) + cf.GlobalTshConfigPath = filepath.Clean(configPath) } // prioritize CLI input for the rest. diff --git a/tool/tsh/common/tsh_test.go b/tool/tsh/common/tsh_test.go index 80c7197c6bdde..2907fb1e32a77 100644 --- a/tool/tsh/common/tsh_test.go +++ b/tool/tsh/common/tsh_test.go @@ -70,6 +70,7 @@ import ( "github.com/gravitational/teleport/api/utils/keypaths" "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/api/utils/prompt" + "github.com/gravitational/teleport/entitlements" "github.com/gravitational/teleport/integration/kube" "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/auth" @@ -227,9 +228,11 @@ func (p *cliModules) PrintVersion() { // Features returns supported features func (p *cliModules) Features() modules.Features { return modules.Features{ - Kubernetes: true, - DB: true, - App: true, + Entitlements: map[entitlements.EntitlementKind]modules.EntitlementInfo{ + entitlements.K8s: {Enabled: true}, + entitlements.DB: {Enabled: true}, + entitlements.App: {Enabled: true}, + }, AdvancedAccessWorkflows: true, AccessControls: true, } diff --git a/tool/tsh/common/vnet_common.go b/tool/tsh/common/vnet_common.go index 6dae51fc692d1..80f03eaa3c536 100644 --- a/tool/tsh/common/vnet_common.go +++ b/tool/tsh/common/vnet_common.go @@ -177,6 +177,7 @@ func (p *vnetAppProvider) reissueAppCert(ctx context.Context, tc *client.Telepor Name: app.GetName(), PublicAddr: app.GetPublicAddr(), ClusterName: tc.SiteName, + URI: app.GetURI(), } profile, err := tc.ProfileStatus() diff --git a/tool/tsh/common/vnet_daemon_darwin.go b/tool/tsh/common/vnet_daemon_darwin.go new file mode 100644 index 0000000000000..771ee9a22834c --- /dev/null +++ b/tool/tsh/common/vnet_daemon_darwin.go @@ -0,0 +1,43 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +//go:build vnetdaemon +// +build vnetdaemon + +package common + +import ( + "log/slog" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/lib/utils" + "github.com/gravitational/teleport/lib/vnet" +) + +func (c *vnetDaemonCommand) run(cf *CLIConf) error { + if cf.Debug { + utils.InitLogger(utils.LoggingForDaemon, slog.LevelDebug) + } else { + utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) + } + + return trace.Wrap(vnet.DaemonSubcommand(cf.Context)) +} + +func (c *vnetAdminSetupCommand) run(cf *CLIConf) error { + return trace.NotImplemented("tsh was built with support for VNet daemon, use %s instead", vnetDaemonSubCommand) +} diff --git a/tool/tsh/common/vnet_darwin.go b/tool/tsh/common/vnet_darwin.go index 05e849a973287..a5fcbc9cb2438 100644 --- a/tool/tsh/common/vnet_darwin.go +++ b/tool/tsh/common/vnet_darwin.go @@ -21,17 +21,12 @@ package common import ( "fmt" - "log/slog" - "os" "github.com/alecthomas/kingpin/v2" "github.com/gravitational/trace" "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/vnet" - "github.com/gravitational/teleport/lib/vnet/daemon" ) type vnetCommand struct { @@ -80,6 +75,12 @@ type vnetAdminSetupCommand struct { ipv6Prefix string // dnsAddr is the IP address for the VNet DNS server. dnsAddr string + // egid of the user starting VNet. Unsafe for production use, as the egid comes from an unstrusted + // source. + egid int + // euid of the user starting VNet. Unsafe for production use, as the euid comes from an unstrusted + // source. + euid int } func newVnetAdminSetupCommand(app *kingpin.Application) *vnetAdminSetupCommand { @@ -89,26 +90,11 @@ func newVnetAdminSetupCommand(app *kingpin.Application) *vnetAdminSetupCommand { cmd.Flag("socket", "unix socket path").StringVar(&cmd.socketPath) cmd.Flag("ipv6-prefix", "IPv6 prefix for the VNet").StringVar(&cmd.ipv6Prefix) cmd.Flag("dns-addr", "VNet DNS address").StringVar(&cmd.dnsAddr) + cmd.Flag("egid", "effective group ID of the user starting VNet").IntVar(&cmd.egid) + cmd.Flag("euid", "effective user ID of the user starting VNet").IntVar(&cmd.euid) return cmd } -func (c *vnetAdminSetupCommand) run(cf *CLIConf) error { - homePath := os.Getenv(types.HomeEnvVar) - if homePath == "" { - // This runs as root so we need to be configured with the user's home path. - return trace.BadParameter("%s must be set", types.HomeEnvVar) - } - - config := daemon.Config{ - SocketPath: c.socketPath, - IPv6Prefix: c.ipv6Prefix, - DNSAddr: c.dnsAddr, - HomePath: homePath, - } - - return trace.Wrap(vnet.AdminSetup(cf.Context, config)) -} - type vnetDaemonCommand struct { *kingpin.CmdClause // Launch daemons added through SMAppService are launched from a static .plist file, hence @@ -118,17 +104,9 @@ type vnetDaemonCommand struct { func newVnetDaemonCommand(app *kingpin.Application) *vnetDaemonCommand { return &vnetDaemonCommand{ - // The command must match the command provided in the .plist file. - CmdClause: app.Command("vnet-daemon", "Start the VNet daemon").Hidden(), + CmdClause: app.Command(vnetDaemonSubCommand, "Start the VNet daemon").Hidden(), } } -func (c *vnetDaemonCommand) run(cf *CLIConf) error { - if cf.Debug { - utils.InitLogger(utils.LoggingForDaemon, slog.LevelDebug) - } else { - utils.InitLogger(utils.LoggingForDaemon, slog.LevelInfo) - } - - return trace.Wrap(vnet.DaemonSubcommand(cf.Context)) -} +// The command must match the command provided in the .plist file. +const vnetDaemonSubCommand = "vnet-daemon" diff --git a/tool/tsh/common/vnet_nodaemon_darwin.go b/tool/tsh/common/vnet_nodaemon_darwin.go new file mode 100644 index 0000000000000..b383c03197a4b --- /dev/null +++ b/tool/tsh/common/vnet_nodaemon_darwin.go @@ -0,0 +1,56 @@ +// Teleport +// Copyright (C) 2024 Gravitational, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +//go:build !vnetdaemon +// +build !vnetdaemon + +package common + +import ( + "os" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/vnet" + "github.com/gravitational/teleport/lib/vnet/daemon" +) + +func (c *vnetDaemonCommand) run(cf *CLIConf) error { + return trace.NotImplemented("tsh was built without support for VNet daemon") +} + +func (c *vnetAdminSetupCommand) run(cf *CLIConf) error { + homePath := os.Getenv(types.HomeEnvVar) + if homePath == "" { + // This runs as root so we need to be configured with the user's home path. + return trace.BadParameter("%s must be set", types.HomeEnvVar) + } + + config := daemon.Config{ + SocketPath: c.socketPath, + IPv6Prefix: c.ipv6Prefix, + DNSAddr: c.dnsAddr, + HomePath: homePath, + ClientCred: daemon.ClientCred{ + Valid: true, + Egid: c.egid, + Euid: c.euid, + }, + } + + return trace.Wrap(vnet.AdminSetup(cf.Context, config)) +} diff --git a/web/packages/build/jest/jest-environment-patched-jsdom.js b/web/packages/build/jest/jest-environment-patched-jsdom.js index 01de01f0fd9d3..642a360b9e395 100644 --- a/web/packages/build/jest/jest-environment-patched-jsdom.js +++ b/web/packages/build/jest/jest-environment-patched-jsdom.js @@ -33,6 +33,21 @@ export default class PatchedJSDOMEnvironment extends JSDOMEnvironment { if (!global.Element.prototype.scrollIntoView) { global.Element.prototype.scrollIntoView = () => {}; } + + // TODO(gzdunek): Remove this once JSDOM provides matchMedia. + // https://github.com/jsdom/jsdom/issues/3522 + if (!global.matchMedia) { + global.matchMedia = query => ({ + matches: false, + media: query, + onchange: null, + addListener: () => {}, + removeListener: () => {}, + addEventListener: () => {}, + removeEventListener: () => {}, + dispatchEvent: () => {}, + }); + } } } export const TestEnvironment = PatchedJSDOMEnvironment; diff --git a/web/packages/design/src/Icon/Icons.story.tsx b/web/packages/design/src/Icon/Icons.story.tsx index c4672580afa47..42002a906c9ba 100644 --- a/web/packages/design/src/Icon/Icons.story.tsx +++ b/web/packages/design/src/Icon/Icons.story.tsx @@ -182,6 +182,7 @@ export const Icons = () => ( + diff --git a/web/packages/design/src/Icon/Icons/ShieldWarning.tsx b/web/packages/design/src/Icon/Icons/ShieldWarning.tsx new file mode 100644 index 0000000000000..0d3274d654d30 --- /dev/null +++ b/web/packages/design/src/Icon/Icons/ShieldWarning.tsx @@ -0,0 +1,70 @@ +/** + * Teleport + * Copyright (C) 2023 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/* MIT License + +Copyright (c) 2020 Phosphor Icons + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +import React from 'react'; + +import { Icon, IconProps } from '../Icon'; + +/* + +THIS FILE IS GENERATED. DO NOT EDIT. + +*/ + +export function ShieldWarning({ size = 24, color, ...otherProps }: IconProps) { + return ( + + + + + + ); +} diff --git a/web/packages/design/src/Icon/assets/ShieldWarning.svg b/web/packages/design/src/Icon/assets/ShieldWarning.svg new file mode 100644 index 0000000000000..b1ec93b336b18 --- /dev/null +++ b/web/packages/design/src/Icon/assets/ShieldWarning.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/web/packages/design/src/Icon/index.ts b/web/packages/design/src/Icon/index.ts index 24769fbac3aec..73318bc91288f 100644 --- a/web/packages/design/src/Icon/index.ts +++ b/web/packages/design/src/Icon/index.ts @@ -170,6 +170,7 @@ export { Scan } from './Icons/Scan'; export { Server } from './Icons/Server'; export { Share } from './Icons/Share'; export { ShieldCheck } from './Icons/ShieldCheck'; +export { ShieldWarning } from './Icons/ShieldWarning'; export { Sliders } from './Icons/Sliders'; export { SlidersVertical } from './Icons/SlidersVertical'; export { Speed } from './Icons/Speed'; diff --git a/web/packages/design/src/SVGIcon/TeleportGearIcon.tsx b/web/packages/design/src/SVGIcon/TeleportGearIcon.tsx index 66fc90d5b237b..2c58ed8e54a66 100644 --- a/web/packages/design/src/SVGIcon/TeleportGearIcon.tsx +++ b/web/packages/design/src/SVGIcon/TeleportGearIcon.tsx @@ -33,9 +33,18 @@ export function TeleportGearIcon({ size = 16 }: Omit) { } return ( - - - + + + + ); diff --git a/web/packages/design/src/Text/Text.jsx b/web/packages/design/src/Text/Text.jsx index 40983bc206ac7..d08de66e486c6 100644 --- a/web/packages/design/src/Text/Text.jsx +++ b/web/packages/design/src/Text/Text.jsx @@ -52,3 +52,83 @@ Text.defaultProps = { }; export default Text; + +/** + * H1 heading. Example usage: page titles and empty result set notifications. + * + * Do not use where `h1` typography is used only to make the text bigger (i.e. + * there's no following content that is logically tied to the heading). + */ +export const H1 = props => ; + +/** Subtitle for heading level 1. Renders as a paragraph. */ +export const Subtitle1 = props => ( + +); + +/** + * H2 heading. Example usage: dialog titles, dialog-like side panel titles. + * + * Do not use where `h2` typography is used only to make the text bigger (i.e. + * there's no following content that is logically tied to the heading). + */ +export const H2 = props => ; + +/** Subtitle for heading level 2. Renders as a paragraph. */ +export const Subtitle2 = props => ( + +); + +/** + * H3 heading. Example usage: explanatory side panel titles, resource enrollment + * step boxes. + * + * Do not use where `h3` typography is used only to make the text stand out more + * (i.e. there's no following content that is logically tied to the heading). + */ +export const H3 = props => ; + +/** Subtitle for heading level 3. Renders as a paragraph. */ +export const Subtitle3 = props => ( + +); + +/** + * H4 heading. + * + * Do not use where `h4` typography is used only to make the text stand out more + * (i.e. there's no following content that is logically tied to the heading). + */ +export const H4 = props => ; + +/** + * A paragraph. Use for text consisting of actual sentences. Applies + * inter-paragraph spacing if grouped with other paragraphs, but doesn't apply + * typography. Use directly when typography is expected to be set by the parent + * component; prefer {@link P1}, {@link P2}, {@link P3} otherwise. + */ +export const P = styled(Text).attrs({ as: 'p' })` + p + & { + margin-top: ${props => props.theme.space[3]}px; + // Allow overriding. + ${space} + } +`; + +/** + * A {@link P} that uses `body1` typography. Applies inter-paragraph spacing if + * grouped with other paragraphs. + */ +export const P1 = props => ; + +/** + * A {@link P} that uses `body2` typography. Applies inter-paragraph spacing if + * grouped with other paragraphs. + */ +export const P2 = props => ; + +/** + * A {@link P} that uses `body3` typography. Applies inter-paragraph spacing if + * grouped with other paragraphs. + */ +export const P3 = props => ; diff --git a/web/packages/design/src/Text/index.js b/web/packages/design/src/Text/index.js index 6b30a4e21e4bb..d4c1d1a1bbaf6 100644 --- a/web/packages/design/src/Text/index.js +++ b/web/packages/design/src/Text/index.js @@ -17,4 +17,16 @@ */ import Text from './Text'; +export { + H1, + H2, + H3, + H4, + P1, + P2, + P3, + Subtitle1, + Subtitle2, + Subtitle3, +} from './Text'; export default Text; diff --git a/web/packages/design/src/index.ts b/web/packages/design/src/index.ts index 1fde350b6e23f..c9cd66f1222ad 100644 --- a/web/packages/design/src/index.ts +++ b/web/packages/design/src/index.ts @@ -39,7 +39,18 @@ import LabelState from './LabelState'; import Link from './Link'; import { Mark } from './Mark'; import Image from './Image'; -import Text from './Text'; +import Text, { + H1, + H2, + H3, + H4, + P1, + P2, + P3, + Subtitle1, + Subtitle2, + Subtitle3, +} from './Text'; import SideNav, { SideNavItem } from './SideNav'; import { StepSlider } from './StepSlider'; import TopNav from './TopNav'; @@ -69,6 +80,10 @@ export { CardSuccessLogin, DocumentTitle, Flex, + H1, + H2, + H3, + H4, Indicator, Input, Label, @@ -88,8 +103,14 @@ export { Menu, MenuItem, MenuItemIcon, + P1, + P2, + P3, TextArea, Toggle, + Subtitle1, + Subtitle2, + Subtitle3, }; export type { TextAreaProps } from './TextArea'; export * from './keyframes'; diff --git a/web/packages/design/src/theme/typography.js b/web/packages/design/src/theme/typography.js index 30b5a3f79946e..bb2fe53c706a0 100644 --- a/web/packages/design/src/theme/typography.js +++ b/web/packages/design/src/theme/typography.js @@ -18,6 +18,7 @@ const light = 300; const regular = 400; +const medium = 500; const bold = 600; export const fontSizes = [10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 34]; @@ -101,6 +102,84 @@ const typography = { fontSize: '14px', lineHeight: '20px', }, + + newBody1: { + fontSize: '16px', + fontWeight: light, + lineHeight: '24px', + letterSpacing: '0.08px', + }, + newBody2: { + fontSize: '14px', + fontWeight: light, + lineHeight: '24px', + letterSpacing: '0.035px', + }, + newBody3: { + fontSize: '12px', + fontWeight: regular, + lineHeight: '20px', + letterSpacing: '0.015px', + }, + newBody4: { + fontSize: '10px', + fontWeight: regular, + lineHeight: '16px', + letterSpacing: '0.013px', + }, + + /** + * Don't use directly, prefer the `H1` component except for text that doesn't + * introduce document structure. + */ + newH1: { + fontWeight: medium, + fontSize: '24px', + lineHeight: '32px', + }, + /** + * Don't use directly, prefer the `H2` component except for text that doesn't + * introduce document structure. + */ + newH2: { + fontWeight: medium, + fontSize: '18px', + lineHeight: '24px', + }, + /** + * Don't use directly, prefer the `H3` component except for text that doesn't + * introduce document structure. + */ + newH3: { + fontWeight: bold, + fontSize: '14px', + lineHeight: '20px', + }, + newH4: { + fontWeight: medium, + fontSize: '12px', + lineHeight: '20px', + letterSpacing: '0.03px', + textTransform: 'uppercase', + }, + newSubtitle1: { + fontSize: '16px', + fontWeight: regular, + lineHeight: '24px', + letterSpacing: '0.024px', + }, + newSubtitle2: { + fontSize: '14px', + fontWeight: regular, + lineHeight: '20px', + letterSpacing: '0.014px', + }, + newSubtitle3: { + fontSize: '12px', + fontWeight: bold, + lineHeight: '20px', + letterSpacing: '0.012px', + }, }; export default typography; diff --git a/web/packages/shared/components/AccessRequests/AssumeStartTime/AssumeStartTime.story.tsx b/web/packages/shared/components/AccessRequests/AssumeStartTime/AssumeStartTime.story.tsx index 5c217cc9cb7f8..473e297cbae70 100644 --- a/web/packages/shared/components/AccessRequests/AssumeStartTime/AssumeStartTime.story.tsx +++ b/web/packages/shared/components/AccessRequests/AssumeStartTime/AssumeStartTime.story.tsx @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import React, { useState } from 'react'; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/AdditionalOptions.tsx b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/AdditionalOptions.tsx index de9cde3487d6a..7d97bc9084136 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/AdditionalOptions.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/AdditionalOptions.tsx @@ -1,17 +1,19 @@ /** - * Copyright 2024 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import React, { useState } from 'react'; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/utils.ts b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/utils.ts index 6fda2a2aee9b0..9fe62cdcabd70 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/utils.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/utils.ts @@ -1,17 +1,19 @@ /** - * Copyright 2024 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import { addHours, addDays, isAfter } from 'date-fns'; diff --git a/web/packages/shared/components/AccessRequests/Shared/utils.ts b/web/packages/shared/components/AccessRequests/Shared/utils.ts index 8fe3dd818d6be..99536746726b3 100644 --- a/web/packages/shared/components/AccessRequests/Shared/utils.ts +++ b/web/packages/shared/components/AccessRequests/Shared/utils.ts @@ -1,17 +1,19 @@ /** - * Copyright 2024 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import { formatDuration, intervalToDuration } from 'date-fns'; diff --git a/web/packages/shared/components/AuthorizeDeviceWeb/AuthorizeDeviceWeb.tsx b/web/packages/shared/components/AuthorizeDeviceWeb/AuthorizeDeviceWeb.tsx index 9a46336ea0efb..0bf8023beacd9 100644 --- a/web/packages/shared/components/AuthorizeDeviceWeb/AuthorizeDeviceWeb.tsx +++ b/web/packages/shared/components/AuthorizeDeviceWeb/AuthorizeDeviceWeb.tsx @@ -139,8 +139,10 @@ export const DeviceTrustConnectPassthrough = ({ const SkipAuthNotice = styled(Box)` text-align: center; width: 100%; - position: absolute; - bottom: 24px; + @media (min-height: 500px) { + position: absolute; + bottom: 24px; + } `; const DownloadButton = styled(ButtonLink)` @@ -156,5 +158,5 @@ const BoldText = styled.span` const Wrapper = styled(Box)` text-align: center; line-height: 32px; - padding-top: 200px; + padding-top: 5vh; `; diff --git a/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.test.tsx b/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.test.tsx index 0029c15af8314..426e45c61650d 100644 --- a/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.test.tsx +++ b/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.test.tsx @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import { diff --git a/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.tsx b/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.tsx index 6b76c9236d2dc..cd30ba6d90f75 100644 --- a/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.tsx +++ b/web/packages/shared/components/LatencyDiagnostic/LatencyDiagnostic.tsx @@ -1,17 +1,19 @@ /** - Copyright 2023 Gravitational, Inc. - - 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. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import styled from 'styled-components'; diff --git a/web/packages/shared/components/LatencyDiagnostic/index.ts b/web/packages/shared/components/LatencyDiagnostic/index.ts index 36b33f959b217..518ca5ac530f6 100644 --- a/web/packages/shared/components/LatencyDiagnostic/index.ts +++ b/web/packages/shared/components/LatencyDiagnostic/index.ts @@ -1,17 +1,19 @@ /** - Copyright 2023 Gravitational, Inc. - - 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. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ export * from './LatencyDiagnostic'; diff --git a/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx b/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx index ea05565de2150..a8b95d64ba316 100644 --- a/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx +++ b/web/packages/shared/components/UnifiedResources/CardsView/ResourceCard.story.tsx @@ -33,6 +33,7 @@ import { nodes } from 'teleport/Nodes/fixtures'; import makeApp from 'teleport/services/apps/makeApps'; import { ResourceActionButton } from 'teleport/UnifiedResources/ResourceActionButton'; +import { SamlAppActionProvider } from 'teleport/SamlApplications/useSamlAppActions'; import { makeUnifiedResourceViewItemApp, @@ -102,56 +103,51 @@ const ActionButton = Action; export const Cards: Story = { render() { return ( - - {[ - ...apps.map(resource => - makeUnifiedResourceViewItemApp(resource, { - ActionButton: ( - - alert('Sets resource spec and opens update dialog') - } - /> - ), - }) - ), - ...databases.map(resource => - makeUnifiedResourceViewItemDatabase(resource, { - ActionButton, - }) - ), - ...kubes.map(resource => - makeUnifiedResourceViewItemKube(resource, { ActionButton }) - ), - ...nodes.map(resource => - makeUnifiedResourceViewItemNode(resource, { - ActionButton, - }) - ), - ...additionalResources.map(resource => - makeUnifiedResourceViewItemApp(resource, { ActionButton }) - ), - ...desktops.map(resource => - makeUnifiedResourceViewItemDesktop(resource, { ActionButton }) - ), - ].map((res, i) => ( - {}} - selectResource={() => {}} - selected={false} - pinningSupport={PinningSupport.Supported} - name={res.name} - primaryIconName={res.primaryIconName} - SecondaryIcon={res.SecondaryIcon} - cardViewProps={res.cardViewProps} - labels={res.labels} - ActionButton={res.ActionButton} - /> - ))} - + + + {[ + ...apps.map(resource => + makeUnifiedResourceViewItemApp(resource, { + ActionButton: , + }) + ), + ...databases.map(resource => + makeUnifiedResourceViewItemDatabase(resource, { + ActionButton, + }) + ), + ...kubes.map(resource => + makeUnifiedResourceViewItemKube(resource, { ActionButton }) + ), + ...nodes.map(resource => + makeUnifiedResourceViewItemNode(resource, { + ActionButton, + }) + ), + ...additionalResources.map(resource => + makeUnifiedResourceViewItemApp(resource, { ActionButton }) + ), + ...desktops.map(resource => + makeUnifiedResourceViewItemDesktop(resource, { ActionButton }) + ), + ].map((res, i) => ( + {}} + selectResource={() => {}} + selected={false} + pinningSupport={PinningSupport.Supported} + name={res.name} + primaryIconName={res.primaryIconName} + SecondaryIcon={res.SecondaryIcon} + cardViewProps={res.cardViewProps} + labels={res.labels} + ActionButton={res.ActionButton} + /> + ))} + + ); }, }; diff --git a/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.test.ts b/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.test.ts index cbfbde3cf3bb4..8af64c7237581 100644 --- a/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.test.ts +++ b/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.test.ts @@ -65,6 +65,14 @@ const testCases: { name: string; app: App; expectedIcon: string }[] = [ }), expectedIcon: 'outreach.io', }, + { + name: 'match by label - default value', + app: makeApp({ + name: 'no-match', + labels: [{ name: 'teleport.icon', value: 'default' }], + }), + expectedIcon: 'application', + }, { name: 'no matches', app: makeApp({ @@ -79,6 +87,27 @@ const testCases: { name: string; app: App; expectedIcon: string }[] = [ }), expectedIcon: 'microsoft', }, + { + name: 'match by name with paranthesis and brackets', + app: makeApp({ + name: 'Clearfeed (adobe) [adobe]', + }), + expectedIcon: 'clearfeed', + }, + { + name: 'match by name if whole text starts and ends with paranthesis', + app: makeApp({ + name: '(clearfeed)', + }), + expectedIcon: 'clearfeed', + }, + { + name: 'match by name if whole text starts and ends with bracket', + app: makeApp({ + name: '[clearfeed]', + }), + expectedIcon: 'clearfeed', + }, ]; test.each(testCases)('guessAppIcon: $name', ({ app, expectedIcon }) => { diff --git a/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.ts b/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.ts index c3bfe54b3007f..fa93ffd5e3670 100644 --- a/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.ts +++ b/web/packages/shared/components/UnifiedResources/shared/guessAppIcon.ts @@ -27,17 +27,21 @@ import { UnifiedResourceApp } from '../types'; export function guessAppIcon(resource: UnifiedResourceApp): ResourceIconName { const { awsConsole = false, name, friendlyName, labels } = resource; - if (awsConsole) { - return 'aws'; - } - // Label matching takes precedence and we can assume it can be a direct lookup // since we expect a certain format. const labelIconValue = labels?.find(l => l.name === 'teleport.icon')?.value; + if (labelIconValue === 'default') { + // Allow opting out of a specific icon. + return 'application'; + } if (labelIconValue && resourceIconSpecs[labelIconValue]) { return labelIconValue as ResourceIconName; } + if (awsConsole) { + return 'aws'; + } + const app = { name: withoutWhiteSpaces(name)?.toLocaleLowerCase(), friendlyName: withoutWhiteSpaces(friendlyName)?.toLocaleLowerCase(), @@ -104,9 +108,26 @@ function match( } /** - * Dashes may be a common separator for the app `name` field. - * White spaces may be a common separator for `friendlyName` field. + * Strips characters like dashes and white space and strips + * paranthesis and brackets and whatever words were inside of them. + * + * - Dashes may be a common separator for the app `name` field. + * - White spaces may be a common separator for `friendlyName` field. + * - Words inside paranthesis/brackets may contain other unrelated + * keywords eg: "Clearfeed (Google Auth)" */ function withoutWhiteSpaces(text?: string) { - return text?.replace(/-|\s/g, ''); + if (!text) { + return ''; + } + + // Remove paranthesis and brackets and words inside them. + let modifiedText = text.replace(/\[[^\]]*\]|\([^)]*\)/g, ''); + // If for whatever reason the whole text begain + // with a paranthesis or bracket. + if (!modifiedText) { + modifiedText = text; + } + // Remove rest of characters. + return modifiedText.replace(/-|\s/g, ''); } diff --git a/web/packages/shared/utils/advancedSearchLabelQuery.ts b/web/packages/shared/utils/advancedSearchLabelQuery.ts index 94bba698183da..12e7ef643c82b 100644 --- a/web/packages/shared/utils/advancedSearchLabelQuery.ts +++ b/web/packages/shared/utils/advancedSearchLabelQuery.ts @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ export function makeAdvancedSearchQueryForLabel( diff --git a/web/packages/shared/utils/text.test.ts b/web/packages/shared/utils/text.test.ts index af62870c5dfcd..f9dc2729ff7db 100644 --- a/web/packages/shared/utils/text.test.ts +++ b/web/packages/shared/utils/text.test.ts @@ -18,8 +18,9 @@ import { pluralize, capitalizeFirstLetter } from './text'; -test('pluralize: sending in zero number', () => { - expect(pluralize(0, 'apple')).toBe('apple'); +test('pluralize', () => { + expect(pluralize(0, 'apple')).toBe('apples'); + expect(pluralize(1, 'apple')).toBe('apple'); expect(pluralize(2, 'apple')).toBe('apples'); }); diff --git a/web/packages/shared/utils/text.ts b/web/packages/shared/utils/text.ts index b2bd37544f299..a424ea5bd9b14 100644 --- a/web/packages/shared/utils/text.ts +++ b/web/packages/shared/utils/text.ts @@ -17,17 +17,17 @@ */ /** - * pluralize adds an 's' to the given word if num is bigger than 1. + * pluralize adds an 's' to the given word if num is other than 1. */ // If you ever need to pluralize a word which cannot be pluralized by appending 's', just add a // third optional argument which is the pluralized noun. // https://api.rubyonrails.org/v7.0.4.2/classes/ActionView/Helpers/TextHelper.html#method-i-pluralize export function pluralize(num: number, word: string) { - if (num > 1) { - return `${word}s`; + if (num === 1) { + return word; } - return word; + return `${word}s`; } /** diff --git a/web/packages/teleport/package.json b/web/packages/teleport/package.json index 3f4aa00aee9a1..cf7bbcafc55d9 100644 --- a/web/packages/teleport/package.json +++ b/web/packages/teleport/package.json @@ -32,13 +32,13 @@ "@opentelemetry/sdk-trace-base": "1.25.1", "@opentelemetry/sdk-trace-web": "1.25.1", "@opentelemetry/semantic-conventions": "1.25.1", + "@xterm/xterm": "^5.5.0", + "@xterm/addon-canvas": "^0.7.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.18.0", "create-react-class": "^15.6.3", - "events": "3.3.0", - "xterm": "^5.3.0", - "xterm-addon-canvas": "^0.5.0", - "xterm-addon-fit": "^0.8.0", - "xterm-addon-web-links": "^0.9.0", - "xterm-addon-webgl": "^0.16.0" + "events": "3.3.0" }, "devDependencies": { "@gravitational/build": "workspace:*", diff --git a/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx b/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx index c0c5199047779..273fa2238bebd 100644 --- a/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx +++ b/web/packages/teleport/src/AppLauncher/AppLauncher.test.tsx @@ -17,7 +17,7 @@ */ import React from 'react'; -import { render, waitFor } from 'design/utils/testing'; +import { render, waitFor, screen } from 'design/utils/testing'; import { createMemoryHistory } from 'history'; import { Router } from 'react-router'; @@ -28,7 +28,11 @@ import service from 'teleport/services/apps'; import { AppLauncher } from './AppLauncher'; -const testCases: { name: string; path: string; expectedPath: string }[] = [ +const launcherPathTestCases: { + name: string; + path: string; + expectedPath: string; +}[] = [ { name: 'no state and no path', path: '?path=', @@ -97,54 +101,263 @@ describe('app launcher path is properly formed', () => { assignMock.mockClear(); }); - test.each(testCases)('$name', async ({ path: query, expectedPath }) => { - const launcherPath = `/web/launch/grafana.localhost${query}`; - const mockHistory = createMemoryHistory({ - initialEntries: [launcherPath], + test.each(launcherPathTestCases)( + '$name', + async ({ path: query, expectedPath }) => { + render( + + + + + + ); + + await waitFor(() => + expect(window.location.replace).toHaveBeenCalledWith( + `https://grafana.localhost/${expectedPath}` + ) + ); + expect(screen.queryByText(/access denied/i)).not.toBeInTheDocument(); + } + ); +}); + +const appSessionTestCases: { + name: string; + path: string; + returnedFqdn: string; + expectedFqdn: string; + expectedPublicAddr: string; + expectedArn: string; +}[] = [ + { + name: 'ARN URL', + path: 'test-app.test.teleport/test.teleport/test-app.test.teleport/arn:aws:iam::joe123:role%2FEC2FullAccess?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: 'arn:aws:iam::joe123:role/EC2FullAccess', + }, + { + name: 'uppercase resolved FQDN', + path: 'test-app.test.teleport/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'TEST-APP.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase public addr', + path: 'test-app.test.teleport/test.teleport/TEST-APP.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'TEST-APP.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase FQDN', + path: 'TEST-APP.test.teleport/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase resolved FQDN, public addr', + path: 'test-app.test.teleport/test.teleport/TEST-APP.test.teleport?state=ABC', + returnedFqdn: 'TEST-APP.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'TEST-APP.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase resolved FQDN,FQDN', + path: 'TEST-APP.test.teleport/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'TEST-APP.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase public addr, FQDN', + path: 'TEST-APP.test.teleport/test.teleport/TEST-APP.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'TEST-APP.test.teleport', + expectedArn: undefined, + }, + { + name: 'uppercase FQDN, resolved FQDN, public addr', + path: 'TEST-APP.test.teleport/test.teleport/TEST-APP.test.teleport?state=ABC', + returnedFqdn: 'TEST-APP.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'TEST-APP.test.teleport', + expectedArn: undefined, + }, + { + name: 'public addr with port', + path: 'test-app.test.teleport/test.teleport/test-app.test.teleport:443?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'FQDN with port', + path: 'test-app.test.teleport:443/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport:443', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'resolved FQDN with port', + path: 'test-app.test.teleport/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport:443', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'FQDN, public addr with port', + path: 'test-app.test.teleport:443/test.teleport/test-app.test.teleport:443?state=ABC', + returnedFqdn: 'test-app.test.teleport', + expectedFqdn: 'test-app.test.teleport:443', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'FQDN, resolved FQDN with port', + path: 'test-app.test.teleport:443/test.teleport/test-app.test.teleport?state=ABC', + returnedFqdn: 'test-app.test.teleport:443', + expectedFqdn: 'test-app.test.teleport:443', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'public addr, resolved FQDN with port', + path: 'test-app.test.teleport/test.teleport/test-app.test.teleport:443?state=ABC', + returnedFqdn: 'test-app.test.teleport:443', + expectedFqdn: 'test-app.test.teleport', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, + { + name: 'FQDN, public addr, resolved FQDN with port', + path: 'test-app.test.teleport:443/test.teleport/test-app.test.teleport:443?state=ABC', + returnedFqdn: 'test-app.test.teleport:443', + expectedFqdn: 'test-app.test.teleport:443', + expectedPublicAddr: 'test-app.test.teleport', + expectedArn: undefined, + }, +]; + +describe('fqdn is matched', () => { + const realLocation = window.location; + const assignMock = jest.fn(); + + beforeEach(() => { + global.fetch = jest.fn(() => Promise.resolve({})) as jest.Mock; + jest.spyOn(api, 'get').mockResolvedValue({}); + jest.spyOn(api, 'post').mockResolvedValue({}); + + delete window.location; + window.location = { ...realLocation, replace: assignMock }; + }); + + afterEach(() => { + window.location = realLocation; + assignMock.mockClear(); + }); + + test.each(appSessionTestCases)( + '$name', + async ({ + path, + returnedFqdn, + expectedFqdn, + expectedPublicAddr, + expectedArn, + }) => { + jest.spyOn(service, 'getAppFqdn').mockResolvedValue({ + fqdn: returnedFqdn, + }); + jest.spyOn(service, 'createAppSession'); + + render( + + + + + + ); + + await waitFor(() => { + expect(service.createAppSession).toHaveBeenCalledWith({ + fqdn: expectedFqdn, + clusterId: 'test.teleport', + publicAddr: expectedPublicAddr, + arn: expectedArn, + }); + }); + + await waitFor(() => expect(window.location.replace).toHaveBeenCalled()); + expect(screen.queryByText(/access denied/i)).not.toBeInTheDocument(); + } + ); + + test('not matching FQDN throws error', async () => { + jest.spyOn(service, 'getAppFqdn').mockResolvedValue({ + fqdn: 'different.fqdn', }); render( - + ); - await waitFor(() => - expect(window.location.replace).toHaveBeenCalledWith( - `https://grafana.localhost/${expectedPath}` + await screen.findByText(/access denied/i); + expect( + screen.getByText( + /failed to match applications with FQDN "test-app.test.teleport:443"/i ) - ); + ).toBeInTheDocument(); + expect(window.location.replace).not.toHaveBeenCalled(); }); - test('arn is url decoded', async () => { + test('invalid URL when constructing a new URL with a malformed FQDN', async () => { jest.spyOn(service, 'getAppFqdn').mockResolvedValue({ - fqdn: 'test-app.test.teleport', - }); - jest.spyOn(service, 'createAppSession'); - - const launcherPath = - '/web/launch/test-app.test.teleport/test.teleport/test-app.test.teleport/arn:aws:iam::joe123:role%2FEC2FullAccess?state=ABC'; - const mockHistory = createMemoryHistory({ - initialEntries: [launcherPath], + fqdn: 'invalid.fqdn:3080:3090', }); render( - + ); - await waitFor(() => { - expect(service.createAppSession).toHaveBeenCalledWith({ - fqdn: 'test-app.test.teleport', - clusterId: 'test.teleport', - publicAddr: 'test-app.test.teleport', - arn: 'arn:aws:iam::joe123:role/EC2FullAccess', - }); - }); + await screen.findByText(/access denied/i); + expect(screen.getByText(/Failed to parse URL:/i)).toBeInTheDocument(); + expect(window.location.replace).not.toHaveBeenCalled(); }); }); + +function createMockHistory(path: string) { + const launcherPath = `/web/launch/${path}`; + return createMemoryHistory({ + initialEntries: [launcherPath], + }); +} diff --git a/web/packages/teleport/src/AppLauncher/AppLauncher.tsx b/web/packages/teleport/src/AppLauncher/AppLauncher.tsx index f1740376b19fb..0008a04ca9c53 100644 --- a/web/packages/teleport/src/AppLauncher/AppLauncher.tsx +++ b/web/packages/teleport/src/AppLauncher/AppLauncher.tsx @@ -52,8 +52,14 @@ export function AppLauncher() { publicAddr: params.publicAddr, arn: params.arn, }); - if (resolvedApp.fqdn !== params.fqdn) { - throw Error(`Failed to match applications with FQDN ${params.fqdn}`); + // Because the ports are stripped from the FQDNs before they are + // compared, an attacker can pass a FQDN with a different port than + // what the app's public address is configured with and have Teleport + // redirect to the public address with an arbitrary port. But because + // the attacker can't control what domain is redirected to this has + // a low risk factor. + if (prepareFqdn(resolvedApp.fqdn) !== prepareFqdn(params.fqdn)) { + throw Error(`Failed to match applications with FQDN "${params.fqdn}"`); } let path = ''; @@ -140,8 +146,30 @@ export function AppLauncherAccessDenied(props: AppLauncherAccessDeniedProps) { return ; } +// prepareFqdn removes the port from the FQDN if it has one and ensures +// the FQDN is lowercase. This is to prevent issues matching the +// resolved fqdn with the one that was passed. Apps generally aren't +// supposed to have a port in the public address but some integrations +// create apps that do. The FQDN is also lowercased to prevent +// issues with case sensitivity. +function prepareFqdn(fqdn: string) { + try { + const fqdnUrl = new URL('https://' + fqdn); + fqdnUrl.port = ''; + // The returned FQDN will have a scheme added to it, but that's + // fine because we're just using it to compare the FQDNs. + return fqdnUrl.toString().toLowerCase(); + } catch (err) { + throwFailedToParseUrlError(err); + } +} + function getXTeleportAuthUrl({ fqdn, port }: { fqdn: string; port: string }) { - return new URL(`https://${fqdn}${port}/x-teleport-auth`); + try { + return new URL(`https://${fqdn}${port}/x-teleport-auth`); + } catch (err) { + throwFailedToParseUrlError(err); + } } // initiateNewAuthExchange is the first step to gaining access to an @@ -197,3 +225,7 @@ function initiateNewAuthExchange({ window.location.replace(url.toString()); } + +function throwFailedToParseUrlError(err: TypeError) { + throw Error(`Failed to parse URL: ${err.message}`); +} diff --git a/web/packages/teleport/src/Console/DocumentSsh/Terminal/Terminal.tsx b/web/packages/teleport/src/Console/DocumentSsh/Terminal/Terminal.tsx index c832e7c625460..027a756aaae5c 100644 --- a/web/packages/teleport/src/Console/DocumentSsh/Terminal/Terminal.tsx +++ b/web/packages/teleport/src/Console/DocumentSsh/Terminal/Terminal.tsx @@ -23,7 +23,7 @@ import React, { useRef, } from 'react'; import { Flex } from 'design'; -import { ITheme } from 'xterm'; +import { ITheme } from '@xterm/xterm'; import { getPlatformType } from 'design/platform'; diff --git a/web/packages/teleport/src/Console/StyledXterm/StyledXterm.tsx b/web/packages/teleport/src/Console/StyledXterm/StyledXterm.tsx index 7c20e10b45356..07f0aba027f99 100644 --- a/web/packages/teleport/src/Console/StyledXterm/StyledXterm.tsx +++ b/web/packages/teleport/src/Console/StyledXterm/StyledXterm.tsx @@ -19,7 +19,7 @@ import styled from 'styled-components'; import { Box } from 'design'; -import 'xterm/css/xterm.css'; +import '@xterm/xterm/css/xterm.css'; const StyledXterm = styled(Box)( () => ` diff --git a/web/packages/teleport/src/DeviceTrust/types.ts b/web/packages/teleport/src/DeviceTrust/types.ts index 7341003ff18b0..1c4463fc39a67 100644 --- a/web/packages/teleport/src/DeviceTrust/types.ts +++ b/web/packages/teleport/src/DeviceTrust/types.ts @@ -36,3 +36,9 @@ export type DeviceListProps = { fetchStatus?: 'loading' | 'disabled' | ''; fetchData?: () => void; }; + +export enum TrustedDeviceRequirement { + UNSPECIFIED, + NOT_REQUIRED, + REQUIRED, +} diff --git a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx index 86fdac8008ebe..e60eadf209d91 100644 --- a/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx +++ b/web/packages/teleport/src/Discover/Database/DeployService/AutoDeploy/AutoDeploy.tsx @@ -40,6 +40,7 @@ import { DiscoverServiceDeployType, } from 'teleport/services/userEvent'; import cfg from 'teleport/config'; +import { splitAwsIamArn } from 'teleport/services/integrations/aws'; import { ActionButtons, @@ -100,9 +101,13 @@ export function AutoDeploy({ toggleDeployMethod }: DeployServiceProp) { dbMeta.autoDiscovery.requiredVpcsAndSubnets; const vpcIds = Object.keys(requiredVpcsAndSubnets); + const { awsAccountId } = splitAwsIamArn( + agentMeta.awsIntegration.spec.roleArn + ); integrationService .deployDatabaseServices(integrationName, { region: dbMeta.awsRegion, + accountId: awsAccountId, taskRoleArn, deployments: vpcIds.map(vpcId => ({ vpcId, @@ -373,24 +378,21 @@ const CreateAccessRole = ({ Step 1 - Name a Task Role ARN for this Database Service and generate a configure - command. This command will configure the required permissions in your - AWS account. + Name an IAM role for the Teleport Database Service and generate a + configuration command. The generated command will create the role and + configure permissions for it in your AWS account. setTaskRoleArn(e.target.value)} - toolTipContent={`Amazon Resource Names (ARNs) uniquely identify AWS \ - resources. In this case you will naming an IAM role that this \ - deployed service will be using`} /> {scriptUrl ? 'Regenerate Command' : 'Generate Command'} diff --git a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx index f7a6aed57f582..ac0a80847f580 100644 --- a/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx +++ b/web/packages/teleport/src/Discover/Kubernetes/EnrollEKSCluster/EnrollEksCluster.tsx @@ -286,7 +286,7 @@ export function EnrollEksCluster(props: AgentStepProps) { ); } else if ( result.error && - !result.error.message.includes( + !result.error.includes( 'teleport-kube-agent is already installed on the cluster' ) ) { diff --git a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx index 83f83ba16a904..cd0e53ac3814f 100644 --- a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx +++ b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx @@ -132,6 +132,7 @@ export function DiscoveryConfigSsm() { iamRoleName: arnResourceName, region: selectedRegion, ssmDocument: ssmDocumentName, + integrationName: agentMeta.awsIntegration.name, }); setScriptUrl(scriptUrl); } diff --git a/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx b/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx index 71d1f57364af6..26201a6ea5b69 100644 --- a/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx +++ b/web/packages/teleport/src/Discover/Shared/Aws/ConfigureIamPerms.tsx @@ -142,7 +142,9 @@ export function ConfigureIamPerms({ "Action": [ "rds:DescribeDBInstances", "rds:DescribeDBClusters", - "ec2:DescribeSecurityGroups" + "ec2:DescribeSecurityGroups", + "ec2:DescribeSubnets", + "ec2:DescribeVpcs" ], "Resource": "*" } diff --git a/web/packages/teleport/src/Login/useLogin.ts b/web/packages/teleport/src/Login/useLogin.ts index 2ef46613d5919..8c5a1da3d574c 100644 --- a/web/packages/teleport/src/Login/useLogin.ts +++ b/web/packages/teleport/src/Login/useLogin.ts @@ -25,6 +25,7 @@ import history from 'teleport/services/history'; import cfg from 'teleport/config'; import auth, { UserCredentials } from 'teleport/services/auth'; import { storageService } from 'teleport/services/storageService'; +import { TrustedDeviceRequirement } from 'teleport/DeviceTrust/types'; export default function useLogin() { const [attempt, attemptActions] = useAttempt({ isProcessing: false }); @@ -50,10 +51,16 @@ export default function useLogin() { // onSuccess can receive a device webtoken. If so, it will // enable a prompt to allow users to authorize the current - function onSuccess({ deviceWebToken }: LoginResponse) { + function onSuccess({ + deviceWebToken, + trustedDeviceRequirement, + }: LoginResponse) { // deviceWebToken will only exist on a login response // from enterprise but just in case there is a version mismatch // between the webclient and proxy + if (trustedDeviceRequirement === TrustedDeviceRequirement.REQUIRED) { + session.setDeviceTrustRequired(); + } if (deviceWebToken && cfg.isEnterprise) { return authorizeWithDeviceTrust(deviceWebToken); } @@ -123,6 +130,7 @@ type DeviceWebToken = { type LoginResponse = { deviceWebToken?: DeviceWebToken; + trustedDeviceRequirement?: TrustedDeviceRequirement; }; function authorizeWithDeviceTrust(token: DeviceWebToken) { diff --git a/web/packages/teleport/src/Main/Main.tsx b/web/packages/teleport/src/Main/Main.tsx index a0105ea9cfe7c..bfaec119415b1 100644 --- a/web/packages/teleport/src/Main/Main.tsx +++ b/web/packages/teleport/src/Main/Main.tsx @@ -327,7 +327,7 @@ export const useNoMinWidth = () => { }, []); }; -const ContentMinWidth = ({ children }: { children: ReactNode }) => { +export const ContentMinWidth = ({ children }: { children: ReactNode }) => { const [enforceMinWidth, setEnforceMinWidth] = useState(true); return ( diff --git a/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx b/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx new file mode 100644 index 0000000000000..929f4ff149e78 --- /dev/null +++ b/web/packages/teleport/src/SamlApplications/useSamlAppActions.tsx @@ -0,0 +1,118 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import React, { createContext, useContext } from 'react'; +import { Attempt } from 'shared/hooks/useAsync'; + +import { SamlMeta } from 'teleport/Discover/useDiscover'; + +import type { SamlAppToDelete } from 'teleport/services/samlidp/types'; +import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; +import type { Access } from 'teleport/services/user'; + +/** + * SamlAppAction defines Saml application edit and delete actions. + */ +export interface SamlAppAction { + /** + * actions controls Saml menu button view and edit and delete onClick behaviour. + */ + actions: { + /** + * showActions dictates whether to show or hide the Saml menu button. + */ + showActions: boolean; + /** + * startEdit triggers Saml app edit flow. + */ + startEdit: (resourceSpec: ResourceSpec) => void; + /** + * startDelete triggers Saml app delete flow. + */ + startDelete: (resourceSpec: ResourceSpec) => void; + }; + /** + * currentAction specifies edit or delete mode. + */ + currentAction?: SamlAppActionMode; + /** + * deleteSamlAppAttempt is an attempt to delete Saml + * app in the backend. + */ + deleteSamlAppAttempt?: Attempt; + /** + * samlAppToDelete defines Saml app item that is to be + * deleted from the unified view. + */ + samlAppToDelete?: SamlAppToDelete; + /** + * fetchSamlResourceAttempt is an attempt to fetch + * Saml resource spec from the backend. It is used to + * pre-populate input fields in the Saml Discover flow. + */ + fetchSamlResourceAttempt?: Attempt; + /** + * resourceSpec holds current Saml app resource spec. + */ + resourceSpec?: ResourceSpec; + /** + * userSamlIdPPerm holds user's RBAC permissions to + * saml_idp_service_provider resource. + */ + userSamlIdPPerm?: Access; + /** + * clearAction clears edit or delete flow. + */ + clearAction?: () => void; + /** + * onDelete handles Saml app delete in the backend. + */ + onDelete?: () => void; +} + +export const SamlAppActionContext = createContext(null); + +export function useSamlAppAction() { + return useContext(SamlAppActionContext); +} + +/** + * SamlAppActionProvider is a dummy provider to satisfy + * SamlAppActionContext in Teleport community edition. + */ +export function SamlAppActionProvider({ + children, +}: { + children: React.ReactNode; +}) { + const value: SamlAppAction = { + actions: { + showActions: false, + startEdit: null, + startDelete: null, + }, + }; + + return ( + + {children} + + ); +} + +export type SamlAppActionMode = 'edit' | 'delete'; diff --git a/web/packages/teleport/src/Sessions/Sessions.story.test.tsx b/web/packages/teleport/src/Sessions/Sessions.story.test.tsx index 6ded560b167cf..0487ef2abb799 100644 --- a/web/packages/teleport/src/Sessions/Sessions.story.test.tsx +++ b/web/packages/teleport/src/Sessions/Sessions.story.test.tsx @@ -33,8 +33,7 @@ test('loaded', () => { expect(container.firstChild).toMatchSnapshot(); }); -test('active sessions CTA', () => { - cfg.isTeam = true; +test('active sessions CTA', async () => { cfg.isEnterprise = true; const { container } = render(); expect(container.firstChild).toMatchSnapshot(); diff --git a/web/packages/teleport/src/Sessions/__snapshots__/Sessions.story.test.tsx.snap b/web/packages/teleport/src/Sessions/__snapshots__/Sessions.story.test.tsx.snap index 772095ec8d4ae..273b15338eaa3 100644 --- a/web/packages/teleport/src/Sessions/__snapshots__/Sessions.story.test.tsx.snap +++ b/web/packages/teleport/src/Sessions/__snapshots__/Sessions.story.test.tsx.snap @@ -484,7 +484,7 @@ exports[`active sessions CTA 1`] = ` { test('support Enterprise with CTA', () => { cfg.isEnterprise = true; - cfg.isTeam = true; const { container } = render( diff --git a/web/packages/teleport/src/Support/Support.tsx b/web/packages/teleport/src/Support/Support.tsx index fe40920857a96..ad1ec0360d030 100644 --- a/web/packages/teleport/src/Support/Support.tsx +++ b/web/packages/teleport/src/Support/Support.tsx @@ -174,9 +174,9 @@ const getDocUrls = (version = '', isEnterprise: boolean) => { } return { - getStarted: withUTM(`https://goteleport.com/docs${docVer}/getting-started`), + getStarted: withUTM(`https://goteleport.com/docs${docVer}`), tshGuide: withUTM( - `https://goteleport.com/docs${docVer}/server-access/guides/tsh` + `https://goteleport.com/docs${docVer}/connect-your-client/tsh/` ), adminGuide: withUTM( `https://goteleport.com/docs${docVer}/management/admin/` diff --git a/web/packages/teleport/src/Support/__snapshots__/Support.story.test.tsx.snap b/web/packages/teleport/src/Support/__snapshots__/Support.story.test.tsx.snap index 98f6f53ff89c4..2ee5a24fbd5dd 100644 --- a/web/packages/teleport/src/Support/__snapshots__/Support.story.test.tsx.snap +++ b/web/packages/teleport/src/Support/__snapshots__/Support.story.test.tsx.snap @@ -245,7 +245,7 @@ exports[`support Cloud 1`] = ` @@ -253,7 +253,7 @@ exports[`support Cloud 1`] = ` @@ -687,7 +687,7 @@ exports[`support Enterprise 1`] = ` @@ -695,7 +695,7 @@ exports[`support Enterprise 1`] = ` @@ -1134,7 +1134,7 @@ exports[`support Enterprise with CTA 1`] = ` @@ -1213,7 +1213,7 @@ exports[`support Enterprise with CTA 1`] = ` @@ -1640,7 +1640,7 @@ exports[`support OSS 1`] = ` @@ -1648,7 +1648,7 @@ exports[`support OSS 1`] = ` @@ -2158,7 +2158,7 @@ exports[`support OSSWithCTA 1`] = ` @@ -2166,7 +2166,7 @@ exports[`support OSSWithCTA 1`] = ` diff --git a/web/packages/teleport/src/TopBar/DeviceTrustIcon.tsx b/web/packages/teleport/src/TopBar/DeviceTrustIcon.tsx index 5030690c56351..c888896d5fb5c 100644 --- a/web/packages/teleport/src/TopBar/DeviceTrustIcon.tsx +++ b/web/packages/teleport/src/TopBar/DeviceTrustIcon.tsx @@ -18,35 +18,52 @@ import styled from 'styled-components'; import { Flex } from 'design'; -import { ShieldCheck } from 'design/Icon'; -import { HoverTooltip } from 'shared/components/ToolTip'; +import { ShieldCheck, ShieldWarning } from 'design/Icon'; +import { IconProps } from 'design/Icon/Icon'; -import session from 'teleport/services/websession'; +import { DeviceTrustStatusKind } from './DeviceTrustStatus'; -export const DeviceTrustIcon = ({ iconSize = 24 }: { iconSize?: number }) => { - const deviceTrusted = session.getIsDeviceTrusted(); +export const DeviceTrustIcon = ({ kind }: { kind: DeviceTrustStatusKind }) => { + const iconSize = 18; - if (!deviceTrusted) { - return null; + if (kind === 'authorized') { + return ( + + ); } return ( - - - - + + ); +}; + +const ShieldIcon = ({ + Icon, + iconSize, + color, + ...props +}: { + Icon: (props: IconProps) => JSX.Element; + iconSize: number; + color: string; +}) => { + return ( + + ); }; const Wrapper = styled(Flex)` height: 100%; - padding-left: 8px; `; diff --git a/web/packages/teleport/src/TopBar/DeviceTrustStatus.tsx b/web/packages/teleport/src/TopBar/DeviceTrustStatus.tsx new file mode 100644 index 0000000000000..ca5e054373020 --- /dev/null +++ b/web/packages/teleport/src/TopBar/DeviceTrustStatus.tsx @@ -0,0 +1,89 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import styled from 'styled-components'; +import { Flex, Text } from 'design'; + +import session from 'teleport/services/websession'; + +import { DeviceTrustIcon } from './DeviceTrustIcon'; + +export type DeviceTrustStatusKind = 'authorized' | 'warning' | 'none'; + +const DeviceTrustText = ({ kind }: { kind: DeviceTrustStatusKind }) => { + if (kind === 'authorized') { + return ( + + Session authorized with device trust. + + ); + } + if (kind === 'warning') { + return ( + + Session is not authorized with Device Trust. Access is restricted. + + ); + } + return null; +}; + +function getDeviceTrustStatusKind( + deviceTrusted: boolean, + deviceTrustRequired: boolean +): DeviceTrustStatusKind { + if (deviceTrustRequired && deviceTrusted) { + return 'authorized'; + } + if (deviceTrustRequired) { + return 'warning'; + } + + return 'none'; +} + +export const DeviceTrustStatus = ({ + iconOnly = false, +}: { + iconOnly?: boolean; +}) => { + const deviceTrustRequired = session.getDeviceTrustRequired(); + const deviceTrusted = session.getIsDeviceTrusted(); + const kind = getDeviceTrustStatusKind(deviceTrusted, deviceTrustRequired); + if (kind === 'none') { + return null; + } + + return ( + + + {!iconOnly && } + + ); +}; + +const Wrapper = styled(Flex)<{ $iconOnly?: boolean }>` + ${p => (p.$iconOnly ? 'padding-left: 16px' : 'padding: 12px;')} + align-items: center; +`; + +const StatusText = styled(Text)` + font-size: ${p => p.theme.fontSizes[1]}px; + margin-left: 16px; + font-style: italic; +`; diff --git a/web/packages/teleport/src/TopBar/TopBar.test.tsx b/web/packages/teleport/src/TopBar/TopBar.test.tsx index ecd134c2324b5..da5d193a5d338 100644 --- a/web/packages/teleport/src/TopBar/TopBar.test.tsx +++ b/web/packages/teleport/src/TopBar/TopBar.test.tsx @@ -24,6 +24,7 @@ import { Router } from 'react-router'; import { createMemoryHistory } from 'history'; import { mockIntersectionObserver } from 'jsdom-testing-mocks'; +import session from 'teleport/services/websession'; import { LayoutContextProvider } from 'teleport/Main/LayoutContext'; import TeleportContextProvider from 'teleport/TeleportContextProvider'; import { FeaturesContextProvider } from 'teleport/FeaturesContext'; @@ -137,6 +138,37 @@ test('notification bell with notification', async () => { expect(screen.getByTestId('tb-notifications-dropdown')).toBeVisible(); }); +test('warning icon will show if session requires device trust and is not authorized', async () => { + setup(); + jest.spyOn(session, 'getDeviceTrustRequired').mockImplementation(() => true); + + render(getTopBar()); + + // the icon will show in the topbar and the usermenunav dropdown + expect(screen.getAllByTestId('device-trust-required-icon')).toHaveLength(2); +}); + +test('authorized icon will show if session is authorized', async () => { + setup(); + jest.spyOn(session, 'getDeviceTrustRequired').mockImplementation(() => true); + jest.spyOn(session, 'getIsDeviceTrusted').mockImplementation(() => true); + + render(getTopBar()); + + // the icon will show in the topbar and the usermenunav dropdown + expect(screen.getAllByTestId('device-trusted-icon')).toHaveLength(2); +}); + +test('icon will not show if device trust is not required', async () => { + setup(); + jest.spyOn(session, 'getDeviceTrustRequired').mockImplementation(() => false); + + render(getTopBar()); + + // no icons will be present + expect(screen.queryByTestId('device-trust-icon')).not.toBeInTheDocument(); +}); + const getTopBar = () => { return ( diff --git a/web/packages/teleport/src/TopBar/TopBar.tsx b/web/packages/teleport/src/TopBar/TopBar.tsx index 07c27722c8527..363b814879df5 100644 --- a/web/packages/teleport/src/TopBar/TopBar.tsx +++ b/web/packages/teleport/src/TopBar/TopBar.tsx @@ -203,10 +203,7 @@ export function TopBar({ CustomLogo }: TopBarProps) { {!feature?.logoOnlyTopbar && ( - + )} diff --git a/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx b/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx index ce9e23e6e0008..05fcfe3de05ce 100644 --- a/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx +++ b/web/packages/teleport/src/UnifiedResources/ResourceActionButton.tsx @@ -16,14 +16,13 @@ * along with this program. If not, see . */ -import React, { useState, Dispatch, SetStateAction } from 'react'; +import React, { useState } from 'react'; import { ButtonBorder, ButtonWithMenu, MenuItem } from 'design'; import { LoginItem, MenuLogin } from 'shared/components/MenuLogin'; import { AwsLaunchButton } from 'shared/components/AwsLaunchButton'; import { UnifiedResource } from 'teleport/services/agents'; import cfg from 'teleport/config'; - import useTeleport from 'teleport/useTeleport'; import { Database } from 'teleport/services/databases'; import { openNewTab } from 'teleport/lib/util'; @@ -34,23 +33,22 @@ import KubeConnectDialog from 'teleport/Kubes/ConnectDialog'; import useStickyClusterId from 'teleport/useStickyClusterId'; import { Node, sortNodeLogins } from 'teleport/services/nodes'; import { App } from 'teleport/services/apps'; - import { ResourceKind } from 'teleport/Discover/Shared'; import { DiscoverEventResource } from 'teleport/services/userEvent'; +import { useSamlAppAction } from 'teleport/SamlApplications/useSamlAppActions'; import type { ResourceSpec } from 'teleport/Discover/SelectResource/types'; type Props = { resource: UnifiedResource; - setResourceSpec?: Dispatch>; }; -export const ResourceActionButton = ({ resource, setResourceSpec }: Props) => { +export const ResourceActionButton = ({ resource }: Props) => { switch (resource.kind) { case 'node': return ; case 'app': - return ; + return ; case 'db': return ; case 'kube_cluster': @@ -144,9 +142,8 @@ const DesktopConnect = ({ desktop }: { desktop: Desktop }) => { type AppLaunchProps = { app: App; - setResourceSpec?: Dispatch>; }; -const AppLaunch = ({ app, setResourceSpec }: AppLaunchProps) => { +const AppLaunch = ({ app }: AppLaunchProps) => { const { name, launchUrl, @@ -160,6 +157,7 @@ const AppLaunch = ({ app, setResourceSpec }: AppLaunchProps) => { samlAppSsoUrl, samlAppPreset, } = app; + const { actions, userSamlIdPPerm } = useSamlAppAction(); if (awsConsole) { return ( { ); } - function handleSamlAppEditButtonClick() { - setResourceSpec({ - name: name, - event: DiscoverEventResource.SamlApplication, - kind: ResourceKind.SamlApplication, - samlMeta: { preset: samlAppPreset }, - icon: 'application', - keywords: 'saml', - }); - } if (samlApp) { - if (setResourceSpec) { + if (actions.showActions) { + const currentSamlAppSpec: ResourceSpec = { + name: name, + event: DiscoverEventResource.SamlApplication, + kind: ResourceKind.SamlApplication, + samlMeta: { preset: samlAppPreset }, + icon: 'application', + keywords: 'saml', + }; return ( { forwardedAs="a" title="Log in to SAML application" > - Edit + actions.startEdit(currentSamlAppSpec)} + disabled={!userSamlIdPPerm.edit} // disable props does not disable onClick + > + Edit + + actions.startDelete(currentSamlAppSpec)} + disabled={!userSamlIdPPerm.remove} // disable props does not disable onClick + > + Delete + ); } else { diff --git a/web/packages/teleport/src/UnifiedResources/UnifiedResources.tsx b/web/packages/teleport/src/UnifiedResources/UnifiedResources.tsx index c7fff86888bb3..df2215f13a40d 100644 --- a/web/packages/teleport/src/UnifiedResources/UnifiedResources.tsx +++ b/web/packages/teleport/src/UnifiedResources/UnifiedResources.tsx @@ -16,8 +16,7 @@ * along with this program. If not, see . */ -import React, { useCallback, useState } from 'react'; - +import React, { useCallback, useState, useMemo } from 'react'; import { Flex } from 'design'; import { Danger } from 'design/Alert'; @@ -50,6 +49,10 @@ import { encodeUrlQueryParams } from 'teleport/components/hooks/useUrlFiltering' import Empty, { EmptyStateInfo } from 'teleport/components/Empty'; import { FeatureFlags } from 'teleport/types'; import { UnifiedResource } from 'teleport/services/agents'; +import { + useSamlAppAction, + SamlAppActionProvider, +} from 'teleport/SamlApplications/useSamlAppActions'; import { ResourceActionButton } from './ResourceActionButton'; import SearchPanel from './SearchPanel'; @@ -59,11 +62,13 @@ export function UnifiedResources() { return ( - + + + ); } @@ -149,7 +154,12 @@ export function ClusterResources({ getClusterPinnedResources: getCurrentClusterPinnedResources, }; - const { fetch, resources, attempt, clear } = useUnifiedResourcesFetch({ + const { + fetch, + resources: unfilteredResources, + attempt, + clear, + } = useUnifiedResourcesFetch({ fetchFunc: useCallback( async (paginationParams, signal) => { const response = await teleCtx.resourceService.fetchUnifiedResources( @@ -187,6 +197,22 @@ export function ClusterResources({ ), }); + const { samlAppToDelete } = useSamlAppAction(); + const resources = useMemo( + () => + samlAppToDelete?.backendDeleted + ? unfilteredResources.filter( + res => + !( + res.kind === 'app' && + res.samlApp && + res.name === samlAppToDelete.name + ) + ) + : unfilteredResources, + [samlAppToDelete, unfilteredResources] + ); + // This state is used to recognize when the `params` value has changed, // and reset the overall state of `useUnifiedResourcesFetch` hook. It's tempting to use a // `useEffect` here, but doing so can cause unwanted behavior where the previous, diff --git a/web/packages/teleport/src/Welcome/NewCredentials/NewPasswordlessDevice.tsx b/web/packages/teleport/src/Welcome/NewCredentials/NewPasswordlessDevice.tsx index 530789ba55cf5..3b6b30db51248 100644 --- a/web/packages/teleport/src/Welcome/NewCredentials/NewPasswordlessDevice.tsx +++ b/web/packages/teleport/src/Welcome/NewCredentials/NewPasswordlessDevice.tsx @@ -18,7 +18,7 @@ import React, { useState } from 'react'; import { Text, Box, ButtonPrimary, ButtonText } from 'design'; -import { Danger, Info } from 'design/Alert'; +import { Danger } from 'design/Alert'; import FieldInput from 'shared/components/FieldInput'; import Validation, { Validator } from 'shared/components/Validation'; import { requiredField } from 'shared/components/Validation/rules'; @@ -73,15 +73,6 @@ export function NewPasswordlessDevice(props: UseTokenState & SliderProps) { changeFlow({ flow: 'local', applyNextAnimation }); } - // Firefox currently does not support passwordless and when - // registering, users will 'soft lock' where firefox prompts - // but when touching the device, it does not do anything. - // We display a soft warning because firefox may provide - // support in the near future: https://github.com/gravitational/webapps/pull/876 - const isFirefox = window.navigator?.userAgent - ?.toLowerCase() - .includes('firefox'); - return ( {({ validator }) => ( @@ -92,12 +83,6 @@ export function NewPasswordlessDevice(props: UseTokenState & SliderProps) { {submitAttempt.status === 'failed' && ( )} - {isFirefox && ( - - Firefox may not support passwordless register. Please try Chrome - or Safari. - - )} Setting up account for: {resetToken.user} diff --git a/web/packages/teleport/src/components/Authenticated/Authenticated.tsx b/web/packages/teleport/src/components/Authenticated/Authenticated.tsx index e294af5d979f6..b0bd82f257424 100644 --- a/web/packages/teleport/src/components/Authenticated/Authenticated.tsx +++ b/web/packages/teleport/src/components/Authenticated/Authenticated.tsx @@ -27,6 +27,7 @@ import session from 'teleport/services/websession'; import { storageService } from 'teleport/services/storageService'; import { ApiError } from 'teleport/services/api/parseError'; import { StyledIndicator } from 'teleport/Main'; +import { TrustedDeviceRequirement } from 'teleport/DeviceTrust/types'; import { ErrorDialog } from './ErrorDialogue'; @@ -62,6 +63,9 @@ const Authenticated: React.FC = ({ children }) => { if (result.hasDeviceExtensions) { session.setIsDeviceTrusted(); } + if (result.requiresDeviceTrust === TrustedDeviceRequirement.REQUIRED) { + session.setDeviceTrustRequired(); + } setAttempt({ status: 'success' }); } catch (e) { if (e instanceof ApiError && e.response?.status == 403) { diff --git a/web/packages/teleport/src/components/FormLogin/FormLogin.tsx b/web/packages/teleport/src/components/FormLogin/FormLogin.tsx index e7bb637d6c317..45400996944ac 100644 --- a/web/packages/teleport/src/components/FormLogin/FormLogin.tsx +++ b/web/packages/teleport/src/components/FormLogin/FormLogin.tsx @@ -141,21 +141,8 @@ const Passwordless = ({ const ref = useRefAutoFocus({ shouldFocus: hasTransitionEnded && autoFocus, }); - // Firefox currently does not support passwordless and when - // logging in, it will return an ambiguous error. - // We display a soft warning because firefox may provide - // support in the near future: https://github.com/gravitational/webapps/pull/876 - const isFirefox = window.navigator?.userAgent - ?.toLowerCase() - .includes('firefox'); return ( - {isFirefox && ( - - Firefox may not support passwordless login. Please try Chrome or - Safari. - - )} . */ import React, { useState } from 'react'; diff --git a/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.test.tsx b/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.test.tsx index 9bde1e72fa7a2..601f651a24bb6 100644 --- a/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.test.tsx +++ b/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.test.tsx @@ -99,7 +99,7 @@ function render(path: string) { - + diff --git a/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.tsx b/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.tsx index f59075f25f294..80f06c38029e7 100644 --- a/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.tsx +++ b/web/packages/teleport/src/components/UserMenuNav/UserMenuNav.tsx @@ -20,7 +20,7 @@ import React, { useState } from 'react'; import styled, { useTheme } from 'styled-components'; import { Moon, Sun, ChevronDown, Logout as LogoutIcon } from 'design/Icon'; -import { Text } from 'design'; +import { Text, Box } from 'design'; import { useRefClickOutside } from 'shared/hooks/useRefClickOutside'; import { getCurrentTheme, getNextTheme } from 'design/ThemeProvider'; @@ -40,11 +40,10 @@ import { STARTING_TRANSITION_DELAY, INCREMENT_TRANSITION_DELAY, } from 'teleport/components/Dropdown'; -import { DeviceTrustIcon } from 'teleport/TopBar/DeviceTrustIcon'; +import { DeviceTrustStatus } from 'teleport/TopBar/DeviceTrustStatus'; interface UserMenuNavProps { username: string; - iconSize: number; } const Container = styled.div` @@ -101,7 +100,7 @@ const StyledAvatar = styled.div` const Arrow = styled.div` line-height: 0; - padding-left: 32px; + padding-left: ${p => p.theme.space[3]}px; svg { transform: ${p => (p.open ? 'rotate(-180deg)' : 'none')}; @@ -114,7 +113,7 @@ const Arrow = styled.div` } `; -export function UserMenuNav({ username, iconSize }: UserMenuNavProps) { +export function UserMenuNav({ username }: UserMenuNavProps) { const [open, setOpen] = useState(false); const theme = useTheme(); @@ -165,7 +164,9 @@ export function UserMenuNav({ username, iconSize }: UserMenuNavProps) { {initial} {username} - + + + @@ -173,6 +174,7 @@ export function UserMenuNav({ username, iconSize }: UserMenuNavProps) { + {items} diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index 4a958135553e1..2849e35ac12c0 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -22,6 +22,8 @@ import { IncludedResourceMode } from 'shared/components/UnifiedResources'; import generateResourcePath from './generateResourcePath'; +import { defaultEntitlements } from './entitlement'; + import type { Auth2faType, AuthProvider, @@ -38,9 +40,7 @@ import type { ParticipantMode } from 'teleport/services/session'; import type { YamlSupportedResourceKind } from './services/yaml/types'; const cfg = { - /** - * @deprecated use cfg.edition instead - */ + /** @deprecated Use cfg.edition instead. */ isEnterprise: false, edition: 'oss', isCloud: false, @@ -60,26 +60,22 @@ const cfg = { isUsageBasedBilling: false, hideInaccessibleFeatures: false, customTheme: '', - /** - * isTeam is true if [Features.ProductType] == Team - * @deprecated use other flags do determine cluster features istead of relying on isTeam - * TODO(mcbattirola): remove isTeam when it is no longer used - */ + /** @deprecated */ isTeam: false, isStripeManaged: false, hasQuestionnaire: false, externalAuditStorage: false, premiumSupport: false, accessRequests: false, + /** @deprecated Use entitlements instead. */ trustedDevices: false, oidc: false, saml: false, + /** @deprecated Use entitlements instead. */ joinActiveSessions: false, + /** @deprecated Use entitlements instead. */ mobileDeviceManagement: false, - - // isIgsEnabled refers to Identity Governance & Security product. - // It refers to a group of features: access request, device trust, - // access list, and access monitoring. + /** @deprecated Use entitlements instead. */ isIgsEnabled: false, // isPolicyEnabled refers to the Teleport Policy product @@ -90,14 +86,19 @@ const cfg = { baseUrl: window.location.origin, // featureLimits define limits for features. - // Typically used with feature teasers if feature is not enabled for the - // product type eg: Team product contains teasers to upgrade to Enterprise. + /** @deprecated Use entitlements instead. */ featureLimits: { + /** @deprecated Use entitlements instead. */ accessListCreateLimit: 0, + /** @deprecated Use entitlements instead. */ accessMonitoringMaxReportRangeLimit: 0, + /** @deprecated Use entitlements instead. */ AccessRequestMonthlyRequestLimit: 0, }, + // default entitlements to false + entitlements: defaultEntitlements, + ui: { scrollbackLines: 1000, showResources: 'requestable', @@ -325,7 +326,7 @@ const cfg = { '/v1/webapi/scripts/integrations/configure/aws-app-access-iam.sh?role=:iamRoleName', awsConfigureIamEc2AutoDiscoverWithSsmPath: - '/v1/webapi/scripts/integrations/configure/ec2-ssm-iam.sh?role=:iamRoleName&awsRegion=:region&ssmDocument=:ssmDocument', + '/v1/webapi/scripts/integrations/configure/ec2-ssm-iam.sh?role=:iamRoleName&awsRegion=:region&ssmDocument=:ssmDocument&integrationName=:integrationName', eksClustersListPath: '/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/eksclusters', @@ -450,18 +451,6 @@ const cfg = { return 'sso'; }, - // isLegacyEnterprise describes product that should have legacy support - // where certain features access remain unlimited. This was before - // product EUB (enterprise usage based) was introduced. - // eg: access request and device trust. - isLegacyEnterprise() { - return cfg.isEnterprise && !cfg.isUsageBasedBilling; - }, - - getAuthType() { - return cfg.auth.authType; - }, - getDeviceTrustAuthorizeRoute(id: string, token: string) { return generatePath(cfg.routes.deviceTrustAuthorize, { id, token }); }, @@ -1220,6 +1209,7 @@ export interface UrlAwsConfigureIamEc2AutoDiscoverWithSsmScriptParams { region: Regions; iamRoleName: string; ssmDocument: string; + integrationName: string; } export interface UrlGcpWorkforceConfigParam { diff --git a/web/packages/teleport/src/entitlement.ts b/web/packages/teleport/src/entitlement.ts new file mode 100644 index 0000000000000..c50bac886afd6 --- /dev/null +++ b/web/packages/teleport/src/entitlement.ts @@ -0,0 +1,72 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// entitlement list should be 1:1 with EntitlementKinds in entitlements/entitlements.go +type entitlement = + | 'AccessLists' + | 'AccessMonitoring' + | 'AccessRequests' + | 'App' + | 'CloudAuditLogRetention' + | 'DB' + | 'Desktop' + | 'DeviceTrust' + | 'ExternalAuditStorage' + | 'FeatureHiding' + | 'HSM' + | 'Identity' + | 'JoinActiveSessions' + | 'K8s' + | 'MobileDeviceManagement' + | 'OIDC' + | 'OktaSCIM' + | 'OktaUserSync' + | 'Policy' + | 'SAML' + | 'SessionLocks' + | 'UpsellAlert' + | 'UsageReporting'; + +export const defaultEntitlements: Record< + entitlement, + { enabled: boolean; limit: number } +> = { + AccessLists: { enabled: false, limit: 0 }, + AccessMonitoring: { enabled: false, limit: 0 }, + AccessRequests: { enabled: false, limit: 0 }, + App: { enabled: false, limit: 0 }, + CloudAuditLogRetention: { enabled: false, limit: 0 }, + DB: { enabled: false, limit: 0 }, + Desktop: { enabled: false, limit: 0 }, + DeviceTrust: { enabled: false, limit: 0 }, + ExternalAuditStorage: { enabled: false, limit: 0 }, + FeatureHiding: { enabled: false, limit: 0 }, + HSM: { enabled: false, limit: 0 }, + Identity: { enabled: false, limit: 0 }, + JoinActiveSessions: { enabled: false, limit: 0 }, + K8s: { enabled: false, limit: 0 }, + MobileDeviceManagement: { enabled: false, limit: 0 }, + OIDC: { enabled: false, limit: 0 }, + OktaSCIM: { enabled: false, limit: 0 }, + OktaUserSync: { enabled: false, limit: 0 }, + Policy: { enabled: false, limit: 0 }, + SAML: { enabled: false, limit: 0 }, + SessionLocks: { enabled: false, limit: 0 }, + UpsellAlert: { enabled: false, limit: 0 }, + UsageReporting: { enabled: false, limit: 0 }, +}; diff --git a/web/packages/teleport/src/generateResourcePath.test.ts b/web/packages/teleport/src/generateResourcePath.test.ts new file mode 100644 index 0000000000000..f224dc024662c --- /dev/null +++ b/web/packages/teleport/src/generateResourcePath.test.ts @@ -0,0 +1,68 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import cfg, { UrlResourcesParams } from './config'; +import generateResourcePath from './generateResourcePath'; + +test('undefined params are set to empty string', () => { + expect( + generateResourcePath(cfg.api.unifiedResourcesPath, { clusterId: 'cluster' }) + ).toStrictEqual( + '/v1/webapi/sites/cluster/resources?searchAsRoles=&limit=&startKey=&kinds=&query=&search=&sort=&pinnedOnly=&includedResourceMode=' + ); +}); + +test('defined params are set', () => { + const unifiedParams: UrlResourcesParams = { + query: 'query', + search: 'search', + sort: { fieldName: 'field', dir: 'DESC' }, + limit: 100, + startKey: 'startkey', + searchAsRoles: 'yes', + pinnedOnly: true, + includedResourceMode: 'all', + kinds: ['app'], + }; + expect( + generateResourcePath(cfg.api.unifiedResourcesPath, { + clusterId: 'cluster', + ...unifiedParams, + }) + ).toStrictEqual( + '/v1/webapi/sites/cluster/resources?searchAsRoles=yes&limit=100&startKey=startkey&kinds=app&query=query&search=search&sort=field:desc&pinnedOnly=true&includedResourceMode=all' + ); +}); + +test('defined params but set to empty values are set to empty string', () => { + const unifiedParams: UrlResourcesParams = { + query: '', + search: null, + limit: 0, + pinnedOnly: false, + kinds: [], + }; + expect( + generateResourcePath(cfg.api.unifiedResourcesPath, { + clusterId: 'cluster', + ...unifiedParams, + }) + ).toStrictEqual( + '/v1/webapi/sites/cluster/resources?searchAsRoles=&limit=&startKey=&kinds=&query=&search=&sort=&pinnedOnly=&includedResourceMode=' + ); +}); diff --git a/web/packages/teleport/src/generateResourcePath.ts b/web/packages/teleport/src/generateResourcePath.ts index 3c0abd1747a13..a3a034af33d92 100644 --- a/web/packages/teleport/src/generateResourcePath.ts +++ b/web/packages/teleport/src/generateResourcePath.ts @@ -50,7 +50,7 @@ export default function generateResourcePath( const output = path .replace(':clusterId', params.clusterId) - .replace(':limit?', params.limit) + .replace(':limit?', params.limit || '') .replace(':startKey?', params.startKey || '') .replace(':query?', processedParams.query || '') .replace(':search?', processedParams.search || '') diff --git a/web/packages/teleport/src/lib/term/terminal.ts b/web/packages/teleport/src/lib/term/terminal.ts index 7816a78f92f2c..cc8f68a2ff12b 100644 --- a/web/packages/teleport/src/lib/term/terminal.ts +++ b/web/packages/teleport/src/lib/term/terminal.ts @@ -16,13 +16,13 @@ * along with this program. If not, see . */ -import 'xterm/css/xterm.css'; -import { ITheme, Terminal } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; -import { WebglAddon } from 'xterm-addon-webgl'; +import '@xterm/xterm/css/xterm.css'; +import { ITheme, Terminal } from '@xterm/xterm'; +import { FitAddon } from '@xterm/addon-fit'; +import { WebglAddon } from '@xterm/addon-webgl'; +import { WebLinksAddon } from '@xterm/addon-web-links'; +import { CanvasAddon } from '@xterm/addon-canvas'; import { debounce, isInteger } from 'shared/utils/highbar'; -import { WebLinksAddon } from 'xterm-addon-web-links'; -import { CanvasAddon } from 'xterm-addon-canvas'; import Logger from 'shared/libs/logger'; import cfg from 'teleport/config'; diff --git a/web/packages/teleport/src/services/discovery/discovery.ts b/web/packages/teleport/src/services/discovery/discovery.ts index 38a497080dde6..bef90e31971c3 100644 --- a/web/packages/teleport/src/services/discovery/discovery.ts +++ b/web/packages/teleport/src/services/discovery/discovery.ts @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import api from 'teleport/services/api'; diff --git a/web/packages/teleport/src/services/discovery/index.ts b/web/packages/teleport/src/services/discovery/index.ts index 948b825b4d062..67db3acf751bb 100644 --- a/web/packages/teleport/src/services/discovery/index.ts +++ b/web/packages/teleport/src/services/discovery/index.ts @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ export * from './discovery'; diff --git a/web/packages/teleport/src/services/discovery/types.ts b/web/packages/teleport/src/services/discovery/types.ts index 70a82daf03a7e..de90d04c2cd39 100644 --- a/web/packages/teleport/src/services/discovery/types.ts +++ b/web/packages/teleport/src/services/discovery/types.ts @@ -1,17 +1,19 @@ /** - * Copyright 2023 Gravitational, Inc. + * Teleport + * Copyright (C) 2024 Gravitational, Inc. * - * 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 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * http://www.apache.org/licenses/LICENSE-2.0 + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. * - * 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. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ import { Regions } from '../integrations'; diff --git a/web/packages/teleport/src/services/integrations/types.ts b/web/packages/teleport/src/services/integrations/types.ts index 025472b22bc90..0c25eada27039 100644 --- a/web/packages/teleport/src/services/integrations/types.ts +++ b/web/packages/teleport/src/services/integrations/types.ts @@ -324,6 +324,8 @@ type DeployDatabaseServiceDeployment = { // -account-id: s // -vpc-id: export type AwsOidcDeployDatabaseServicesRequest = { + // The AWS account to deploy the db service to. + accountId: string; // Region is the AWS Region for the Service. region: string; // TaskRoleARN is the AWS Role's ARN used within the Task execution. @@ -366,7 +368,7 @@ export type EnrollEksClustersResponse = { results: { clusterName: string; resourceId: string; - error: { message: string }; + error: string; }[]; }; diff --git a/web/packages/teleport/src/services/sales/index.ts b/web/packages/teleport/src/services/sales/index.ts index e4750fa1b0e22..de5c8c27f923b 100644 --- a/web/packages/teleport/src/services/sales/index.ts +++ b/web/packages/teleport/src/services/sales/index.ts @@ -17,12 +17,10 @@ */ import { CtaEvent } from 'teleport/services/userEvent'; -import cfg from 'teleport/config'; // These URLs are the shorten URL version. These marketing URL's // are defined in the "next" repo. // eg: https://github.com/gravitational/next/pull/2298 -const UPGRADE_TEAM_URL = 'https://goteleport.com/r/upgrade-team'; const UPGRADE_COMMUNITY_URL = 'https://goteleport.com/r/upgrade-community'; // UPGRADE_IGS_URL is enterprise upgrading to enterprise with Identity Governance & Security const UPGRADE_IGS_URL = 'https://goteleport.com/r/upgrade-igs'; @@ -46,11 +44,7 @@ export function getSalesURL( url?: string ) { if (!url) { - url = UPGRADE_COMMUNITY_URL; - if (isEnterprise) { - // TODO(mcbattirola): remove isTeam when it is no longer used - url = cfg.isTeam ? UPGRADE_TEAM_URL : UPGRADE_IGS_URL; - } + url = isEnterprise ? UPGRADE_IGS_URL : UPGRADE_COMMUNITY_URL; } const params = getParams(version, isEnterprise, event); return `${url}?${params}`; diff --git a/web/packages/teleport/src/services/samlidp/types.ts b/web/packages/teleport/src/services/samlidp/types.ts index 12add6ec1ed78..2270fed85ed43 100644 --- a/web/packages/teleport/src/services/samlidp/types.ts +++ b/web/packages/teleport/src/services/samlidp/types.ts @@ -75,3 +75,21 @@ export type SamlGcpWorkforce = { poolName: string; poolProviderName: string; }; + +/** + * SamlAppToDelete is used to define the name of an + * SAML app item to be deleted and its deletion state in the + * backend. Intended to be used in the unified resource view. + */ +export type SamlAppToDelete = { + /** + * name is the name of Saml app item to delete. + */ + name: string; + // kind: string; + /** + * backendDeleted specifies if the item is deleted + * in the backend. + */ + backendDeleted: boolean; +}; diff --git a/web/packages/teleport/src/services/storageService/types.ts b/web/packages/teleport/src/services/storageService/types.ts index c4aad5d9b4e1c..d604d289bfa7e 100644 --- a/web/packages/teleport/src/services/storageService/types.ts +++ b/web/packages/teleport/src/services/storageService/types.ts @@ -41,7 +41,7 @@ export const KeysEnum = { export type SurveyRequest = { companyName: string; employeeCount: string; - resourcesList: Array; + resources: Array; role: string; team: string; }; diff --git a/web/packages/teleport/src/services/websession/websession.ts b/web/packages/teleport/src/services/websession/websession.ts index 8bff075d128a2..2d271fb25d9b4 100644 --- a/web/packages/teleport/src/services/websession/websession.ts +++ b/web/packages/teleport/src/services/websession/websession.ts @@ -176,6 +176,14 @@ const session = { return !!this._isRenewing; }, + setDeviceTrustRequired() { + this._isDeviceTrustRequired = true; + }, + + getDeviceTrustRequired() { + return !!this._isDeviceTrustRequired; + }, + getIsDeviceTrusted() { return !!this._isDeviceTrusted; }, diff --git a/web/packages/teleport/src/teleportContext.tsx b/web/packages/teleport/src/teleportContext.tsx index 6405a9a5e1305..1f40c5ceee3c6 100644 --- a/web/packages/teleport/src/teleportContext.tsx +++ b/web/packages/teleport/src/teleportContext.tsx @@ -77,15 +77,14 @@ class TeleportContext implements types.Context { // lockedFeatures are the features disabled in the user's cluster. // Mainly used to hide features and/or show CTAs when the user cluster doesn't support it. lockedFeatures: types.LockedFeatures = { - authConnectors: !(cfg.oidc && cfg.saml), - // Below should be locked for the following cases: - // 1) feature disabled in the cluster features - // 2) is not a legacy and igs is not enabled. legacies should have unlimited access. - accessRequests: - !cfg.accessRequests || (!cfg.isLegacyEnterprise() && !cfg.isIgsEnabled), - trustedDevices: - !cfg.trustedDevices || (!cfg.isLegacyEnterprise() && !cfg.isIgsEnabled), + authConnectors: !( + cfg.entitlements.OIDC.enabled && cfg.entitlements.SAML.enabled + ), + accessRequests: !cfg.entitlements.AccessRequests.enabled, + trustedDevices: !cfg.entitlements.DeviceTrust.enabled, }; + // entitlements define a customer’s access to a specific features + entitlements = cfg.entitlements; // hasExternalAuditStorage indicates if an account has set up external audit storage. It is used to show or hide the External Audit Storage CTAs. hasExternalAuditStorage = false; diff --git a/web/packages/teleterm/build_resources/linux/after-install.tpl b/web/packages/teleterm/build_resources/linux/after-install.tpl index 74e29dd5bf724..98ee9fec46b1c 100644 --- a/web/packages/teleterm/build_resources/linux/after-install.tpl +++ b/web/packages/teleterm/build_resources/linux/after-install.tpl @@ -6,8 +6,13 @@ set -eu # https://github.com/electron-userland/electron-builder/blob/v24.4.0/packages/app-builder-lib/templates/linux/after-install.tpl ### -# SUID chrome-sandbox for Electron 5+ -chmod 4755 "/opt/${sanitizedProductName}/chrome-sandbox" || true +# Check if user namespaces are supported by the kernel and working with a quick test: +if ! { [[ -L /proc/self/ns/user ]] && unshare --user true; }; then + # Use SUID chrome-sandbox only on systems without user namespaces: + chmod 4755 '/opt/${sanitizedProductName}/chrome-sandbox' || true +else + chmod 0755 '/opt/${sanitizedProductName}/chrome-sandbox' || true +fi # update-mime-database and update-desktop-database might be missing from minimal variants of some # Linux distributions. diff --git a/web/packages/teleterm/package.json b/web/packages/teleterm/package.json index 8a81331e986d1..4f301f3e4c3d1 100644 --- a/web/packages/teleterm/package.json +++ b/web/packages/teleterm/package.json @@ -42,8 +42,10 @@ "@types/node-forge": "^1.3.11", "@types/tar-fs": "^2.0.4", "@types/whatwg-url": "^11.0.5", - "electron": "31.1.0", - "electron-builder": "^25.0.1", + "@xterm/xterm": "^5.5.0", + "@xterm/addon-fit": "^0.10.0", + "electron": "31.3.1", + "electron-builder": "^25.0.3", "electron-notarize": "^1.2.2", "electron-vite": "^2.3.0", "events": "3.3.0", @@ -52,8 +54,6 @@ "react-dnd": "^14.0.4", "react-dnd-html5-backend": "^14.0.2", "whatwg-url": "^13.0.0", - "xterm": "^5.3.0", - "xterm-addon-fit": "^0.8.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.23.1" }, diff --git a/web/packages/teleterm/src/mainProcess/contextMenus/terminalContextMenu.ts b/web/packages/teleterm/src/mainProcess/contextMenus/terminalContextMenu.ts index 3ba18f08355c2..b4aa181677f3a 100644 --- a/web/packages/teleterm/src/mainProcess/contextMenus/terminalContextMenu.ts +++ b/web/packages/teleterm/src/mainProcess/contextMenus/terminalContextMenu.ts @@ -18,18 +18,24 @@ import { ipcMain, ipcRenderer, Menu } from 'electron'; +import { ConfigService } from 'teleterm/services/config'; + import { TerminalContextMenuEventChannel } from '../types'; -export function subscribeToTerminalContextMenuEvent(): void { +export function subscribeToTerminalContextMenuEvent( + configService: ConfigService +): void { ipcMain.on(TerminalContextMenuEventChannel, () => { Menu.buildFromTemplate([ { label: 'Copy', role: 'copy', + accelerator: configService.get('keymap.terminalCopy').value, }, { label: 'Paste', role: 'paste', + accelerator: configService.get('keymap.terminalPaste').value, }, ]).popup(); }); diff --git a/web/packages/teleterm/src/mainProcess/mainProcess.ts b/web/packages/teleterm/src/mainProcess/mainProcess.ts index 4430dc7c6ba8e..1e2c8d35b410f 100644 --- a/web/packages/teleterm/src/mainProcess/mainProcess.ts +++ b/web/packages/teleterm/src/mainProcess/mainProcess.ts @@ -44,6 +44,7 @@ import { ChildProcessAddresses, MainProcessIpc, RendererIpc, + TERMINATE_MESSAGE, } from 'teleterm/mainProcess/types'; import { getAssetPath } from 'teleterm/mainProcess/runtimeSettings'; import { RootClusterUri } from 'teleterm/ui/uri'; @@ -143,7 +144,11 @@ export default class MainProcess { terminateWithTimeout(this.tshdProcess, 10_000, () => { this.gracefullyKillTshdProcess(); }), - terminateWithTimeout(this.sharedProcess), + terminateWithTimeout(this.sharedProcess, 5_000, process => + // process.kill doesn't allow running a cleanup code in the child process + // on Windows + process.send(TERMINATE_MESSAGE) + ), this.agentRunner.killAll(), ]); } @@ -183,9 +188,6 @@ export default class MainProcess { env: { ...process.env, TELEPORT_HOME: homeDir, - VNETDAEMON: this.configService.get('feature.vnetDaemon').value - ? 'yes' - : undefined, }, } ); @@ -499,7 +501,7 @@ export default class MainProcess { } ); - subscribeToTerminalContextMenuEvent(); + subscribeToTerminalContextMenuEvent(this.configService); subscribeToTabContextMenuEvent(); subscribeToConfigServiceEvents(this.configService); subscribeToFileStorageEvents(this.appStateFileStorage); diff --git a/web/packages/teleterm/src/mainProcess/types.ts b/web/packages/teleterm/src/mainProcess/types.ts index 78e73e9fe1e90..78683cd1067d6 100644 --- a/web/packages/teleterm/src/mainProcess/types.ts +++ b/web/packages/teleterm/src/mainProcess/types.ts @@ -243,6 +243,7 @@ export enum FileStorageEventType { Write = 'Write', Replace = 'Replace', GetFilePath = 'GetFilePath', + GetFileName = 'GetFileName', GetFileLoadingError = 'GetFileLoadingError', } @@ -276,3 +277,12 @@ export enum MainProcessIpc { export enum WindowsManagerIpc { SignalUserInterfaceReadiness = 'windows-manager-signal-user-interface-readiness', } + +/** + * A custom message to gracefully quit a process. + * It is sent to the child process with `process.send`. + * + * We need this because `process.kill('SIGTERM')` doesn't work on Windows, + * so we couldn't run any cleanup logic. + */ +export const TERMINATE_MESSAGE = 'TERMINATE_MESSAGE'; diff --git a/web/packages/teleterm/src/mainProcess/windowsManager.ts b/web/packages/teleterm/src/mainProcess/windowsManager.ts index 01281ba77397f..daa0935122c4c 100644 --- a/web/packages/teleterm/src/mainProcess/windowsManager.ts +++ b/web/packages/teleterm/src/mainProcess/windowsManager.ts @@ -154,7 +154,10 @@ export class WindowsManager { return callback(false); } - if (permission === 'clipboard-sanitized-write') { + if ( + permission === 'clipboard-sanitized-write' || + permission === 'clipboard-read' + ) { return callback(true); } return callback(false); diff --git a/web/packages/teleterm/src/preload.ts b/web/packages/teleterm/src/preload.ts index c5b72720ca7a1..9a691d4ebf085 100644 --- a/web/packages/teleterm/src/preload.ts +++ b/web/packages/teleterm/src/preload.ts @@ -74,7 +74,14 @@ async function getElectronGlobals(): Promise { credentials.shared, runtimeSettings, { - noResume: mainProcessClient.configService.get('ssh.noResume').value, + ssh: { + noResume: mainProcessClient.configService.get('ssh.noResume').value, + }, + terminal: { + windowsBackend: mainProcessClient.configService.get( + 'terminal.windowsBackend' + ).value, + }, } ); const { diff --git a/web/packages/teleterm/src/services/config/appConfigSchema.ts b/web/packages/teleterm/src/services/config/appConfigSchema.ts index 91950eed522b1..34a85cda610b5 100644 --- a/web/packages/teleterm/src/services/config/appConfigSchema.ts +++ b/web/packages/teleterm/src/services/config/appConfigSchema.ts @@ -22,6 +22,9 @@ import { Platform } from 'teleterm/mainProcess/types'; import { createKeyboardShortcutSchema } from './keyboardShortcutSchema'; +// When adding a new config property, add it to the docs too +// (teleport-connect.mdx#configuration). + export type AppConfigSchema = ReturnType; export type AppConfig = z.infer; @@ -54,6 +57,22 @@ export const createAppConfigSchema = (platform: Platform) => { .max(256) .default(15) .describe('Font size for the terminal.'), + 'terminal.windowsBackend': z + .enum(['auto', 'winpty']) + .default('auto') + .describe( + '`auto` uses modern ConPTY system if available, which requires Windows 10 (19H1) or above. Set to `winpty` to use winpty even if ConPTY is available.' + ), + 'terminal.rightClick': z + .enum(['paste', 'copyPaste', 'menu']) + .default(platform === 'win32' ? 'copyPaste' : 'menu') + .describe( + '`paste` pastes clipboard content, `copyPaste` copies if text is selected, otherwise pastes, `menu` shows context menu.' + ), + 'terminal.copyOnSelect': z + .boolean() + .default(false) + .describe('Automatically copies selected text to the clipboard.'), 'usageReporting.enabled': z .boolean() .default(false) @@ -94,6 +113,16 @@ export const createAppConfigSchema = (platform: Platform) => { 'keymap.newTerminalTab': shortcutSchema .default(defaultKeymap['newTerminalTab']) .describe(getShortcutDesc('open a new terminal tab')), + // Even if this is set to a non-default copy shortcut for a given platform, + // the default shortcut will still work (for example, Command+C on Macs). + 'keymap.terminalCopy': shortcutSchema + .default(defaultKeymap['terminalCopy']) + .describe(getShortcutDesc('copy text in the terminal')), + // Even if this is set to a non-default paste shortcut for a given platform, + // the default shortcut will still work (for example, Command+V on Macs). + 'keymap.terminalPaste': shortcutSchema + .default(defaultKeymap['terminalPaste']) + .describe(getShortcutDesc('paste text in the terminal')), 'keymap.previousTab': shortcutSchema .default(defaultKeymap['previousTab']) .describe(getShortcutDesc('go to the previous tab')), @@ -122,10 +151,6 @@ export const createAppConfigSchema = (platform: Platform) => { .boolean() .default(false) .describe('Disables SSH connection resumption.'), - 'feature.vnetDaemon': z - .boolean() - .default(false) - .describe('Use daemon instead of osascript for VNet'), }); }; @@ -147,7 +172,9 @@ export type KeyboardShortcutAction = | 'openSearchBar' | 'openConnections' | 'openClusters' - | 'openProfiles'; + | 'openProfiles' + | 'terminalCopy' + | 'terminalPaste'; const getDefaultKeymap = ( platform: Platform @@ -173,6 +200,8 @@ const getDefaultKeymap = ( openConnections: 'Ctrl+Shift+P', openClusters: 'Ctrl+Shift+E', openProfiles: 'Ctrl+Shift+I', + terminalCopy: 'Ctrl+Shift+C', + terminalPaste: 'Ctrl+Shift+V', }; case 'linux': return { @@ -194,6 +223,8 @@ const getDefaultKeymap = ( openConnections: 'Ctrl+Shift+P', openClusters: 'Ctrl+Shift+E', openProfiles: 'Ctrl+Shift+I', + terminalCopy: 'Ctrl+Shift+C', + terminalPaste: 'Ctrl+Shift+V', }; case 'darwin': return { @@ -215,6 +246,8 @@ const getDefaultKeymap = ( openConnections: 'Command+P', openClusters: 'Command+E', openProfiles: 'Command+I', + terminalCopy: 'Command+C', + terminalPaste: 'Command+V', }; } }; diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 986f75747fac0..56310749bd237 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -import path from 'path'; - import { z, ZodIssue } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; @@ -64,6 +62,9 @@ export interface ConfigService { getConfigError(): ConfigError | undefined; } +// createConfigService must return a client that works both in the browser and in Node.js, as the +// returned service is used both in the main process and in Storybook to provide a fake +// implementation of config service. export function createConfigService({ configFile, jsonSchemaFile, @@ -124,7 +125,7 @@ function updateJsonSchema({ schema.extend({ $schema: z.string() }), { $refStrategy: 'none' } ); - const jsonSchemaFileName = path.basename(jsonSchemaFile.getFilePath()); + const jsonSchemaFileName = jsonSchemaFile.getFileName(); const jsonSchemaFileNameInConfig = configFile.get('$schema'); jsonSchemaFile.replace(jsonSchema); diff --git a/web/packages/teleterm/src/services/fileStorage/fileStorage.ts b/web/packages/teleterm/src/services/fileStorage/fileStorage.ts index 350de5edbd973..994db45a0e610 100644 --- a/web/packages/teleterm/src/services/fileStorage/fileStorage.ts +++ b/web/packages/teleterm/src/services/fileStorage/fileStorage.ts @@ -19,6 +19,7 @@ // Both versions are imported because some operations need to be sync. import fsAsync from 'node:fs/promises'; import fs from 'node:fs'; +import path from 'node:path'; import { debounce } from 'shared/utils/highbar'; @@ -44,6 +45,12 @@ export interface FileStorage { /** Returns the file path used to create the storage. */ getFilePath(): string; + /** Returns the file name used to create the storage. + * + * Added so that ConfigService itself doesn't need to import node:path and can remain universal. + */ + getFileName(): string; + /** Returns the error that could occur while reading and parsing the file. */ getFileLoadingError(): Error | undefined; } @@ -116,6 +123,10 @@ export function createFileStorage(opts: { return opts.filePath; } + function getFileName(): string { + return path.basename(opts.filePath); + } + function getFileLoadingError(): Error | undefined { return error; } @@ -134,6 +145,7 @@ export function createFileStorage(opts: { get, replace, getFilePath, + getFileName, getFileLoadingError, }; } diff --git a/web/packages/teleterm/src/services/fileStorage/fileStorageClient.ts b/web/packages/teleterm/src/services/fileStorage/fileStorageClient.ts index 2f38e5d0cfc92..a639dcd949443 100644 --- a/web/packages/teleterm/src/services/fileStorage/fileStorageClient.ts +++ b/web/packages/teleterm/src/services/fileStorage/fileStorageClient.ts @@ -25,6 +25,10 @@ import { import { FileStorage } from './fileStorage'; +// TODO(ravicious): The main process should not expose the whole interface of FileStorage to the +// renderer, only what's absolutely needed by the renderer. FileStorage at the moment includes a +// bunch of functions that are used only in the main process (and should be used only there). +// https://github.com/gravitational/teleport/issues/24380 export function subscribeToFileStorageEvents(configService: FileStorage): void { ipcMain.on( FileStorageEventChannel, @@ -40,8 +44,12 @@ export function subscribeToFileStorageEvents(configService: FileStorage): void { return configService.replace(item.json); case FileStorageEventType.GetFilePath: return configService.getFilePath(); + case FileStorageEventType.GetFileName: + return configService.getFileName(); case FileStorageEventType.GetFileLoadingError: return configService.getFileLoadingError(); + default: + eventType satisfies never; } } ); @@ -74,6 +82,12 @@ export function createFileStorageClient(): FileStorage { FileStorageEventType.GetFilePath, {} ), + getFileName: () => + ipcRenderer.sendSync( + FileStorageEventChannel, + FileStorageEventType.GetFileName, + {} + ), getFileLoadingError: () => ipcRenderer.sendSync( FileStorageEventChannel, diff --git a/web/packages/teleterm/src/services/fileStorage/fixtures/mocks.ts b/web/packages/teleterm/src/services/fileStorage/fixtures/mocks.ts index 06260d28d14d9..af2e850b5cbb2 100644 --- a/web/packages/teleterm/src/services/fileStorage/fixtures/mocks.ts +++ b/web/packages/teleterm/src/services/fileStorage/fixtures/mocks.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { FileStorage } from 'teleterm/services/fileStorage'; +import type { FileStorage } from 'teleterm/services/fileStorage'; export function createMockFileStorage(opts?: { filePath: string; @@ -41,6 +41,10 @@ export function createMockFileStorage(opts?: { return opts?.filePath || ''; }, + getFileName() { + return opts?.filePath.split('/').at(-1) || ''; + }, + getFileLoadingError() { return undefined; }, diff --git a/web/packages/teleterm/src/services/pty/fixtures/mocks.ts b/web/packages/teleterm/src/services/pty/fixtures/mocks.ts index c9e2c62e392c7..9cefda658c666 100644 --- a/web/packages/teleterm/src/services/pty/fixtures/mocks.ts +++ b/web/packages/teleterm/src/services/pty/fixtures/mocks.ts @@ -20,6 +20,7 @@ import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost'; import { PtyProcessCreationStatus, PtyServiceClient, + WindowsPty, } from 'teleterm/services/pty'; export class MockPtyProcess implements IPtyProcess { @@ -29,7 +30,7 @@ export class MockPtyProcess implements IPtyProcess { resize() {} - dispose() {} + async dispose() {} onData() { return () => {}; @@ -64,10 +65,12 @@ export class MockPtyServiceClient implements PtyServiceClient { createPtyProcess(): Promise<{ process: IPtyProcess; creationStatus: PtyProcessCreationStatus; + windowsPty: WindowsPty; }> { return Promise.resolve({ process: new MockPtyProcess(), creationStatus: PtyProcessCreationStatus.Ok, + windowsPty: undefined, }); } } diff --git a/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.test.ts b/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.test.ts index b37187ed4f5cd..4f8720d3d2482 100644 --- a/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.test.ts +++ b/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.test.ts @@ -47,7 +47,7 @@ describe('getPtyProcessOptions', () => { const { env } = getPtyProcessOptions( makeRuntimeSettings(), - { noResume: false }, + { ssh: { noResume: false }, windowsPty: { useConpty: true } }, cmd, processEnv ); @@ -76,7 +76,7 @@ describe('getPtyProcessOptions', () => { const { env } = getPtyProcessOptions( makeRuntimeSettings(), - { noResume: false }, + { ssh: { noResume: false }, windowsPty: { useConpty: true } }, cmd, processEnv ); @@ -103,7 +103,7 @@ describe('getPtyProcessOptions', () => { const { args } = getPtyProcessOptions( makeRuntimeSettings(), - { noResume: true }, + { ssh: { noResume: true }, windowsPty: { useConpty: true } }, cmd, processEnv ); diff --git a/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.ts b/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.ts index 4857d3a498694..1e122404e3f09 100644 --- a/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.ts +++ b/web/packages/teleterm/src/services/pty/ptyHost/buildPtyOptions.ts @@ -25,8 +25,9 @@ import { assertUnreachable } from 'teleterm/ui/utils'; import { PtyCommand, PtyProcessCreationStatus, - SshOptions, TshKubeLoginCommand, + SshOptions, + WindowsPty, } from '../types'; import { @@ -34,9 +35,14 @@ import { ResolveShellEnvTimeoutError, } from './resolveShellEnv'; +type PtyOptions = { + ssh: SshOptions; + windowsPty: Pick; +}; + export async function buildPtyOptions( settings: RuntimeSettings, - sshOptions: SshOptions, + options: PtyOptions, cmd: PtyCommand ): Promise<{ processOptions: PtyProcessOptions; @@ -60,6 +66,8 @@ export async function buildPtyOptions( const combinedEnv = { ...process.env, ...shellEnv, + TERM_PROGRAM: 'Teleport_Connect', + TERM_PROGRAM_VERSION: settings.appVersion, TELEPORT_HOME: settings.tshd.homeDir, TELEPORT_CLUSTER: cmd.clusterName, TELEPORT_PROXY: cmd.proxyHost, @@ -68,7 +76,7 @@ export async function buildPtyOptions( return { processOptions: getPtyProcessOptions( settings, - sshOptions, + options, cmd, combinedEnv ), @@ -79,10 +87,12 @@ export async function buildPtyOptions( export function getPtyProcessOptions( settings: RuntimeSettings, - sshOptions: SshOptions, + options: PtyOptions, cmd: PtyCommand, env: typeof process.env ): PtyProcessOptions { + const useConpty = options.windowsPty?.useConpty; + switch (cmd.kind) { case 'pty.shell': { // Teleport Connect bundles a tsh binary, but the user might have one already on their system. @@ -104,6 +114,7 @@ export function getPtyProcessOptions( cwd: cmd.cwd, env: { ...env, ...cmd.env }, initMessage: cmd.initMessage, + useConpty, }; } @@ -129,6 +140,7 @@ export function getPtyProcessOptions( path: settings.defaultShell, args: isWindows ? powershellCommandArgs : bashCommandArgs, env: { ...env, KUBECONFIG: getKubeConfigFilePath(cmd, settings) }, + useConpty, }; } @@ -140,7 +152,7 @@ export function getPtyProcessOptions( const args = [ `--proxy=${cmd.rootClusterId}`, 'ssh', - ...(sshOptions.noResume ? ['--no-resume'] : []), + ...(options.ssh.noResume ? ['--no-resume'] : []), '--forward-agent', loginHost, ]; @@ -149,6 +161,7 @@ export function getPtyProcessOptions( path: settings.tshd.binaryPath, args, env, + useConpty, }; } @@ -159,6 +172,7 @@ export function getPtyProcessOptions( path: cmd.path, args: cmd.args, env: { ...env, ...cmd.env }, + useConpty, }; } diff --git a/web/packages/teleterm/src/services/pty/ptyHost/ptyHostClient.ts b/web/packages/teleterm/src/services/pty/ptyHost/ptyHostClient.ts index 74c9dfd90fa29..8990bfb0a1f64 100644 --- a/web/packages/teleterm/src/services/pty/ptyHost/ptyHostClient.ts +++ b/web/packages/teleterm/src/services/pty/ptyHost/ptyHostClient.ts @@ -41,6 +41,7 @@ export function createPtyHostClient( args: ptyOptions.args, path: ptyOptions.path, env: Struct.fromJson(ptyOptions.env), + useConpty: ptyOptions.useConpty, }); if (ptyOptions.cwd) { diff --git a/web/packages/teleterm/src/services/pty/ptyHost/ptyProcess.ts b/web/packages/teleterm/src/services/pty/ptyHost/ptyProcess.ts index 8b97c017f7a93..cec0ba3d246f3 100644 --- a/web/packages/teleterm/src/services/pty/ptyHost/ptyProcess.ts +++ b/web/packages/teleterm/src/services/pty/ptyHost/ptyProcess.ts @@ -47,7 +47,7 @@ export function createPtyProcess( exchangeEventsStream.resize(columns, rows); }, - dispose(): void { + async dispose(): Promise { exchangeEventsStream.dispose(); }, diff --git a/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.test.ts b/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.test.ts new file mode 100644 index 0000000000000..28e89c7e26ccc --- /dev/null +++ b/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.test.ts @@ -0,0 +1,61 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { makeRuntimeSettings } from 'teleterm/mainProcess/fixtures/mocks'; + +import { getWindowsPty } from './windowsPty'; + +test.each([ + { + name: 'uses conpty on supported Windows version', + platform: 'win32' as const, + osVersion: '10.0.22621', + terminalOptions: { windowsBackend: 'auto' as const }, + expected: { useConpty: true, buildNumber: 22621 }, + }, + { + name: 'uses winpty on unsupported Windows version', + platform: 'win32' as const, + osVersion: '10.0.18308', + terminalOptions: { windowsBackend: 'auto' as const }, + expected: { useConpty: false, buildNumber: 18308 }, + }, + { + name: 'uses winpty when Windows version is supported, but conpty is disabled in options', + platform: 'win32' as const, + osVersion: '10.0.22621', + terminalOptions: { windowsBackend: 'winpty' as const }, + expected: { useConpty: false, buildNumber: 22621 }, + }, + { + name: 'undefined on non-Windows OS', + platform: 'darwin' as const, + osVersion: '23.5.0', + terminalOptions: { windowsBackend: 'auto' as const }, + expected: undefined, + }, +])('$name', ({ platform, osVersion, terminalOptions, expected }) => { + const pty = getWindowsPty( + makeRuntimeSettings({ + platform, + osVersion, + }), + terminalOptions + ); + expect(pty).toEqual(expected); +}); diff --git a/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.ts b/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.ts new file mode 100644 index 0000000000000..8bd69d0d9de32 --- /dev/null +++ b/web/packages/teleterm/src/services/pty/ptyHost/windowsPty.ts @@ -0,0 +1,49 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import { RuntimeSettings } from 'teleterm/mainProcess/types'; + +import { TerminalOptions, WindowsPty } from '../types'; + +export const WIN_BUILD_STABLE_CONPTY = 18309; + +export function getWindowsPty( + runtimeSettings: RuntimeSettings, + terminalOptions: TerminalOptions +): WindowsPty { + if (runtimeSettings.platform !== 'win32') { + return undefined; + } + + const buildNumber = getWindowsBuildNumber(runtimeSettings.osVersion); + const useConpty = + terminalOptions.windowsBackend === 'auto' && + buildNumber >= WIN_BUILD_STABLE_CONPTY; + return { + useConpty, + buildNumber, + }; +} + +function getWindowsBuildNumber(osVersion: string): number { + const parsedOsVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(osVersion); + if (parsedOsVersion?.length === 4) { + return parseInt(parsedOsVersion[3]); + } + return 0; +} diff --git a/web/packages/teleterm/src/services/pty/ptyService.ts b/web/packages/teleterm/src/services/pty/ptyService.ts index b13c11325179f..3b82021e8868d 100644 --- a/web/packages/teleterm/src/services/pty/ptyService.ts +++ b/web/packages/teleterm/src/services/pty/ptyService.ts @@ -23,21 +23,26 @@ import { RuntimeSettings } from 'teleterm/mainProcess/types'; import { buildPtyOptions } from './ptyHost/buildPtyOptions'; import { createPtyHostClient } from './ptyHost/ptyHostClient'; import { createPtyProcess } from './ptyHost/ptyProcess'; -import { PtyServiceClient, SshOptions } from './types'; +import { PtyServiceClient, PtyOptions } from './types'; +import { getWindowsPty } from './ptyHost/windowsPty'; export function createPtyService( address: string, credentials: ChannelCredentials, runtimeSettings: RuntimeSettings, - sshOptions: SshOptions + options: PtyOptions ): PtyServiceClient { const ptyHostClient = createPtyHostClient(address, credentials); return { createPtyProcess: async command => { + const windowsPty = getWindowsPty(runtimeSettings, options.terminal); const { processOptions, creationStatus } = await buildPtyOptions( runtimeSettings, - sshOptions, + { + ssh: options.ssh, + windowsPty, + }, command ); const ptyId = await ptyHostClient.createPtyProcess(processOptions); @@ -46,6 +51,7 @@ export function createPtyService( return { process: createPtyProcess(ptyHostClient, ptyId), creationStatus, + windowsPty, }; }, }; diff --git a/web/packages/teleterm/src/services/pty/types.ts b/web/packages/teleterm/src/services/pty/types.ts index 7119a89ea993c..aaac99a224ede 100644 --- a/web/packages/teleterm/src/services/pty/types.ts +++ b/web/packages/teleterm/src/services/pty/types.ts @@ -37,9 +37,21 @@ export type PtyServiceClient = { createPtyProcess: (cmd: PtyCommand) => Promise<{ process: IPtyProcess; creationStatus: PtyProcessCreationStatus; + windowsPty: WindowsPty; }>; }; +/** + * Pty information for Windows. + * undefined for non-Windows OS. + */ +export type WindowsPty = + | { + useConpty: boolean; + buildNumber: number; + } + | undefined; + export type ShellCommand = PtyCommandBase & { kind: 'pty.shell'; cwd?: string; @@ -107,3 +119,12 @@ export type SshOptions = { */ noResume: boolean; }; + +export type TerminalOptions = { + windowsBackend: 'auto' | 'winpty'; +}; + +export type PtyOptions = { + ssh: SshOptions; + terminal: TerminalOptions; +}; diff --git a/web/packages/teleterm/src/sharedProcess/api/proto/ptyHostService.proto b/web/packages/teleterm/src/sharedProcess/api/proto/ptyHostService.proto index f9baea4f2c9fc..98a0519c61a81 100644 --- a/web/packages/teleterm/src/sharedProcess/api/proto/ptyHostService.proto +++ b/web/packages/teleterm/src/sharedProcess/api/proto/ptyHostService.proto @@ -41,6 +41,7 @@ message PtyCreate { reserved "init_command"; google.protobuf.Struct env = 7; string init_message = 8; + bool use_conpty = 9; } message PtyClientEvent { diff --git a/web/packages/teleterm/src/sharedProcess/api/protogen/ptyHostService_pb.ts b/web/packages/teleterm/src/sharedProcess/api/protogen/ptyHostService_pb.ts index cd6cd61badcea..35f043a2d4624 100644 --- a/web/packages/teleterm/src/sharedProcess/api/protogen/ptyHostService_pb.ts +++ b/web/packages/teleterm/src/sharedProcess/api/protogen/ptyHostService_pb.ts @@ -69,6 +69,10 @@ export interface PtyCreate { * @generated from protobuf field: string init_message = 8; */ initMessage: string; + /** + * @generated from protobuf field: bool use_conpty = 9; + */ + useConpty: boolean; } /** * @generated from protobuf message PtyClientEvent @@ -266,7 +270,8 @@ class PtyCreate$Type extends MessageType { { no: 4, name: "args", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, { no: 5, name: "cwd", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, { no: 7, name: "env", kind: "message", T: () => Struct }, - { no: 8, name: "init_message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + { no: 8, name: "init_message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 9, name: "use_conpty", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } ]); } create(value?: PartialMessage): PtyCreate { @@ -275,6 +280,7 @@ class PtyCreate$Type extends MessageType { message.args = []; message.cwd = ""; message.initMessage = ""; + message.useConpty = false; if (value !== undefined) reflectionMergePartial(this, message, value); return message; @@ -299,6 +305,9 @@ class PtyCreate$Type extends MessageType { case /* string init_message */ 8: message.initMessage = reader.string(); break; + case /* bool use_conpty */ 9: + message.useConpty = reader.bool(); + break; default: let u = options.readUnknownField; if (u === "throw") @@ -326,6 +335,9 @@ class PtyCreate$Type extends MessageType { /* string init_message = 8; */ if (message.initMessage !== "") writer.tag(8, WireType.LengthDelimited).string(message.initMessage); + /* bool use_conpty = 9; */ + if (message.useConpty !== false) + writer.tag(9, WireType.Varint).bool(message.useConpty); let u = options.writeUnknownFields; if (u !== false) (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); diff --git a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyEventsStreamHandler.ts b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyEventsStreamHandler.ts index 0417408cc1ba7..a9aa281451131 100644 --- a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyEventsStreamHandler.ts +++ b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyEventsStreamHandler.ts @@ -131,16 +131,16 @@ export class PtyEventsStreamHandler { private handleStreamError(error: Error): void { this.logger.error(`stream has ended with error`, error); - this.cleanResources(); + void this.cleanResources(); } private handleStreamEnd(): void { this.logger.info(`stream has ended`); - this.cleanResources(); + void this.cleanResources(); } - private cleanResources(): void { - this.ptyProcess.dispose(); + private async cleanResources(): Promise { + await this.ptyProcess.dispose(); if (this.ptyId) { this.ptyProcesses.delete(this.ptyId); } diff --git a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyHostService.ts b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyHostService.ts index 651a196e5ad6d..ffb1cb524321b 100644 --- a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyHostService.ts +++ b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyHostService.ts @@ -27,7 +27,9 @@ import { IPtyHost } from './../api/protogen/ptyHostService_pb.grpc-server'; import { PtyCwd, PtyId } from './../api/protogen/ptyHostService_pb'; import { PtyEventsStreamHandler } from './ptyEventsStreamHandler'; -export function createPtyHostService(): IPtyHost { +export function createPtyHostService(): IPtyHost & { + dispose(): Promise; +} { const logger = new Logger('PtyHostService'); const ptyProcesses = new Map(); @@ -43,6 +45,7 @@ export function createPtyHostService(): IPtyHost { ptyId, env: Struct.toJson(call.request.env!) as Record, initMessage: ptyOptions.initMessage, + useConpty: ptyOptions.useConpty, }); ptyProcesses.set(ptyId, ptyProcess); } catch (error) { @@ -73,5 +76,12 @@ export function createPtyHostService(): IPtyHost { }); }, exchangeEvents: stream => new PtyEventsStreamHandler(stream, ptyProcesses), + dispose: async () => { + await Promise.all( + Array.from(ptyProcesses.values()).map(ptyProcess => + ptyProcess.dispose() + ) + ); + }, }; } diff --git a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.test.ts b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.test.ts index 18288c307d981..77d8a7dddad68 100644 --- a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.test.ts +++ b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.test.ts @@ -38,6 +38,7 @@ describe('PtyProcess', () => { args: [], env: { PATH: '/foo/bar' }, ptyId: '1234', + useConpty: true, }); const startErrorCb = jest.fn(); diff --git a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.ts b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.ts index ededa80e5ffc4..1762ca17a1ef2 100644 --- a/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.ts +++ b/web/packages/teleterm/src/sharedProcess/ptyHost/ptyProcess.ts @@ -24,6 +24,8 @@ import { EventEmitter } from 'node:events'; import * as nodePTY from 'node-pty'; import which from 'which'; +import { wait } from 'shared/utils/wait'; + import Logger from 'teleterm/logger'; import { PtyProcessOptions, IPtyProcess } from './types'; @@ -59,6 +61,12 @@ export class PtyProcess extends EventEmitter implements IPtyProcess { * It emits TermEventEnum.StartError on error. start itself always returns a fulfilled promise. */ async start(cols: number, rows: number) { + if (process.platform === 'win32') { + this._logger.info( + this.options.useConpty ? 'ConPTY enabled' : 'ConPTY disabled' + ); + } + try { // which throws an error if the argument is not found in path. // TODO(ravicious): Remove the manual check for the existence of the executable after node-pty @@ -76,8 +84,10 @@ export class PtyProcess extends EventEmitter implements IPtyProcess { // https://unix.stackexchange.com/questions/123858 cwd: this.options.cwd || getDefaultCwd(this.options.env), env: this.options.env, - // Turn off ConPTY due to an uncaught exception being thrown when a PTY is closed. - useConpty: false, + useConpty: this.options.useConpty, + // Do not clear the terminal on launch when using ConPTY. + conptyInheritCursor: + this.options.useConpty && !!this.options.initMessage, }); } catch (error) { this._logger.error(error); @@ -132,10 +142,38 @@ export class PtyProcess extends EventEmitter implements IPtyProcess { } } - dispose() { + async dispose() { + if (this._disposed) { + this._logger.info(`PTY process is not running. Nothing to kill`); + return; + } + const controller = new AbortController(); + const processExit = promisifyProcessExit(this._process); + this.removeAllListeners(); - this._process?.kill(); - this._disposed = true; + this._process.kill(); + + // Wait for the process to exit. + // It's needed for ssh sessions on Windows with ConPTY enabled. + // When we didn't wait, conhost.exe processes started by node-pty + // were left running after closing the app. + // Killing a process doesn't happen immediately, but instead appears to be + // queued, so we need to give it time to execute. + // + // Although this was added specifically for Windows, + // we run the same cleanup code for all platforms. + const hasExited = await Promise.race([ + processExit.then(() => controller.abort()).then(() => true), + // timeout for killing the shared process is 5 seconds + wait(4_000, controller.signal) + .catch(() => {}) // ignore abort errors + .then(() => false), + ]); + if (hasExited) { + this._disposed = true; + } else { + this._logger.error('Failed to dispose PTY process within the timeout'); + } } onData(cb: (data: string) => void) { @@ -254,3 +292,7 @@ function getDefaultCwd(env: Record): string { return userDir || process.cwd(); } + +function promisifyProcessExit(childProcess: nodePTY.IPty): Promise { + return new Promise(resolve => childProcess.onExit(() => resolve())); +} diff --git a/web/packages/teleterm/src/sharedProcess/ptyHost/types.ts b/web/packages/teleterm/src/sharedProcess/ptyHost/types.ts index a43e82c033458..cd0f4b8bce4c6 100644 --- a/web/packages/teleterm/src/sharedProcess/ptyHost/types.ts +++ b/web/packages/teleterm/src/sharedProcess/ptyHost/types.ts @@ -22,13 +22,15 @@ export type PtyProcessOptions = { args: string[]; cwd?: string; initMessage?: string; + /** Whether to use the ConPTY system on Windows. */ + useConpty: boolean; }; export type IPtyProcess = { start(cols: number, rows: number): void; write(data: string): void; resize(cols: number, rows: number): void; - dispose(): void; + dispose(): Promise; getCwd(): Promise; getPtyId(): string; // The listener removal functions are used only on the frontend app side from the renderer process. diff --git a/web/packages/teleterm/src/sharedProcess/sharedProcess.ts b/web/packages/teleterm/src/sharedProcess/sharedProcess.ts index b4f0f5c06c861..1b9be627d8f3e 100644 --- a/web/packages/teleterm/src/sharedProcess/sharedProcess.ts +++ b/web/packages/teleterm/src/sharedProcess/sharedProcess.ts @@ -28,7 +28,7 @@ import { readGrpcCert, shouldEncryptConnection, } from 'teleterm/services/grpcCredentials'; -import { RuntimeSettings } from 'teleterm/mainProcess/types'; +import { RuntimeSettings, TERMINATE_MESSAGE } from 'teleterm/mainProcess/types'; import Logger from 'teleterm/logger'; import { ptyHostDefinition } from 'teleterm/sharedProcess/api/protogen/ptyHostService_pb.grpc-server'; @@ -74,7 +74,8 @@ async function initializeServer( } const server = new Server(); - server.addService(ptyHostDefinition, createPtyHostService()); + const ptyHostService = createPtyHostService(); + server.addService(ptyHostDefinition, ptyHostService); // grpc-js requires us to pass localhost:port for TCP connections, const grpcServerAddress = address.replace('tcp://', ''); @@ -95,8 +96,13 @@ async function initializeServer( logger.error('Could not start shared server', e); } - process.once('exit', () => { - server.forceShutdown(); + process.on('message', async message => { + if (message === TERMINATE_MESSAGE) { + new Logger('Process').info('Received terminate message, exiting'); + server.forceShutdown(); + await ptyHostService.dispose(); + process.exit(0); + } }); } diff --git a/web/packages/teleterm/src/ui/Document/Document.tsx b/web/packages/teleterm/src/ui/Document/Document.tsx index 9a68d5e1b349a..454134fbb2441 100644 --- a/web/packages/teleterm/src/ui/Document/Document.tsx +++ b/web/packages/teleterm/src/ui/Document/Document.tsx @@ -22,33 +22,19 @@ import { useRefAutoFocus } from 'shared/hooks'; const Document: React.FC<{ visible: boolean; - onContextMenu?(): void; autoFocusDisabled?: boolean; [x: string]: any; -}> = ({ visible, children, onContextMenu, autoFocusDisabled, ...styles }) => { +}> = ({ visible, children, autoFocusDisabled, ...styles }) => { const ref = useRefAutoFocus({ shouldFocus: visible && !autoFocusDisabled, }); - function handleContextMenu( - e: React.MouseEvent - ): void { - if (onContextMenu) { - // `preventDefault` prevents opening the universal context menu - // and thus only the document-specific menu gets displayed. - // Opening two menus at the same time on Linux causes flickering. - e.preventDefault(); - onContextMenu(); - } - } - return ( {$fileTransfer} @@ -132,6 +131,10 @@ export function DocumentTerminal(props: { unsanitizedFontFamily={unsanitizedTerminalFontFamily} fontSize={terminalFontSize} onEnterKey={attempt.data.refreshTitle} + windowsPty={attempt.data.windowsPty} + openContextMenu={attempt.data.openContextMenu} + configService={configService} + keyboardShortcutsService={ctx.keyboardShortcutsService} /> )} diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.test.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.test.tsx new file mode 100644 index 0000000000000..a4bf19e149829 --- /dev/null +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.test.tsx @@ -0,0 +1,154 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import 'jest-canvas-mock'; +import { EventEmitter } from 'node:events'; + +import userEvent from '@testing-library/user-event'; +import { screen, waitFor } from '@testing-library/react'; +import { render } from 'design/utils/testing'; + +import { MockAppContext } from 'teleterm/ui/fixtures/mocks'; +import Logger, { NullService } from 'teleterm/logger'; +import { IAppContext } from 'teleterm/ui/types'; + +import { Terminal } from './Terminal'; + +beforeAll(() => { + Logger.init(new NullService()); +}); + +beforeEach(() => { + userEvent.setup(); +}); + +// TODO(gzdunek): Add tests for copying text. +// Unfortunately, simulating text selection with a single right click or +// mouseMove doesn't work. +// Probably because xterm doesn't render properly in JSDOM? +// I can see that the element with `xterm-screen` class has zero width and height. + +test('keyboard shortcut pastes text', async () => { + const appContext = new MockAppContext({ platform: 'win32' }); + + render(); + + await navigator.clipboard.writeText('some-command'); + await userEvent.keyboard('{Control>}{Shift>}V'); // Ctrl+Shift+V + + await waitFor(() => { + expect(screen.getByText('some-command')).toBeInTheDocument(); + }); +}); + +test.each([ + { + name: "mouse right click pastes text when 'terminal.rightClick: paste' is configured", + getAppContext: () => { + const appContext = new MockAppContext(); + appContext.configService.set('terminal.rightClick', 'paste'); + return appContext; + }, + }, + { + name: "mouse right click pastes text when 'terminal.rightClick: copyPaste' is configured", + getAppContext: () => { + const appContext = new MockAppContext(); + appContext.configService.set('terminal.rightClick', 'copyPaste'); + return appContext; + }, + }, +])(`$name`, async testCase => { + const appContext = testCase.getAppContext(); + + render(); + + await userEvent.keyboard('some-command '); + const terminalContent = await screen.findByText('some-command'); + + await navigator.clipboard.writeText('--flag=test'); + await userEvent.pointer({ keys: '[MouseRight>]', target: terminalContent }); + + await waitFor(() => { + expect(screen.getByText('some-command --flag=test')).toBeInTheDocument(); + }); +}); + +test("mouse right click opens context menu when 'terminal.rightClick: menu' is configured", async () => { + const appContext = new MockAppContext(); + jest.spyOn(appContext.mainProcessClient, 'openTerminalContextMenu'); + appContext.configService.set('terminal.rightClick', 'menu'); + const openContextMenu = jest.fn(); + + render( + + ); + + await userEvent.keyboard('some-command '); + const terminalContent = await screen.findByText('some-command'); + + await navigator.clipboard.writeText('--flag=test'); + await userEvent.pointer({ keys: '[MouseRight>]', target: terminalContent }); + + expect(openContextMenu).toHaveBeenCalledTimes(1); + expect(openContextMenu).toHaveBeenCalledWith( + expect.objectContaining({ defaultPrevented: true }) + ); +}); + +function ConfiguredTerminal(props: { + appContext: IAppContext; + onOpenContextMenu?(): void; +}) { + const emitter = new EventEmitter(); + const writeFn = jest.fn().mockImplementation(a => { + emitter.emit('', a); + }); + return ( + '', + write: writeFn, + getPtyId: () => '', + dispose: async () => {}, + getCwd: async () => '', + onData: handler => { + const listener = event => handler(event); + emitter.addListener('', listener); + return () => emitter.removeListener('', listener); + }, + onExit: () => () => {}, + onOpen: () => () => {}, + onStartError: () => () => {}, + resize: () => {}, + }} + reconnect={() => {}} + visible={true} + unsanitizedFontFamily={'monospace'} + fontSize={12} + openContextMenu={props.onOpenContextMenu} + windowsPty={undefined} + configService={props.appContext.configService} + keyboardShortcutsService={props.appContext.keyboardShortcutsService} + /> + ); +} diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx index b51605f63a810..8bc1fb7f0e706 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/Terminal.tsx @@ -27,8 +27,12 @@ import { makeSuccessAttempt, } from 'shared/hooks/useAsync'; +import { WindowsPty } from 'teleterm/services/pty'; import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost'; import { DocumentTerminal } from 'teleterm/ui/services/workspacesService'; +import { KeyboardShortcutsService } from 'teleterm/ui/services/keyboardShortcuts'; + +import { ConfigService } from 'teleterm/services/config'; import { Reconnect } from '../Reconnect'; @@ -48,6 +52,10 @@ type TerminalProps = { unsanitizedFontFamily: string; fontSize: number; onEnterKey?(): void; + windowsPty: WindowsPty; + openContextMenu(): void; + configService: ConfigService; + keyboardShortcutsService: KeyboardShortcutsService; }; export function Terminal(props: TerminalProps) { @@ -68,11 +76,18 @@ export function Terminal(props: TerminalProps) { setStartPtyProcessAttempt(makeSuccessAttempt(undefined)); }); - const ctrl = new XTermCtrl(props.ptyProcess, { - el: refElement.current, - fontSize: props.fontSize, - theme: theme.colors.terminal, - }); + const ctrl = new XTermCtrl( + props.ptyProcess, + { + el: refElement.current, + fontSize: props.fontSize, + theme: theme.colors.terminal, + windowsPty: props.windowsPty, + openContextMenu: props.openContextMenu, + }, + props.configService, + props.keyboardShortcutsService + ); // Start the PTY process. ctrl.open(); diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts index fdae12dcad53e..5e7c5776ca71d 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/Terminal/ctrl.ts @@ -16,13 +16,16 @@ * along with this program. If not, see . */ -import 'xterm/css/xterm.css'; -import { IDisposable, ITheme, Terminal } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; +import '@xterm/xterm/css/xterm.css'; +import { IDisposable, ITheme, Terminal } from '@xterm/xterm'; +import { FitAddon } from '@xterm/addon-fit'; import { debounce } from 'shared/utils/highbar'; +import { WindowsPty } from 'teleterm/services/pty'; import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost'; import Logger from 'teleterm/logger'; +import { ConfigService, AppConfig } from 'teleterm/services/config'; +import { KeyboardShortcutsService } from 'teleterm/ui/services/keyboardShortcuts'; const WINDOW_RESIZE_DEBOUNCE_DELAY = 200; @@ -30,6 +33,8 @@ type Options = { el: HTMLElement; fontSize: number; theme: ITheme; + windowsPty: WindowsPty; + openContextMenu(e: MouseEvent): void; }; export default class TtyTerminal { @@ -40,13 +45,23 @@ export default class TtyTerminal { private debouncedResize: () => void; private logger = new Logger('lib/term/terminal'); private removePtyProcessOnDataListener: () => void; + private config: Pick< + AppConfig, + 'terminal.rightClick' | 'terminal.copyOnSelect' + >; constructor( private ptyProcess: IPtyProcess, - private options: Options + private options: Options, + configService: ConfigService, + private keyboardShortcutsService: KeyboardShortcutsService ) { this.el = options.el; this.term = null; + this.config = { + 'terminal.rightClick': configService.get('terminal.rightClick').value, + 'terminal.copyOnSelect': configService.get('terminal.copyOnSelect').value, + }; this.debouncedResize = debounce( this.requestResize.bind(this), @@ -67,18 +82,91 @@ export default class TtyTerminal { fontSize: this.options.fontSize, scrollback: 5000, minimumContrastRatio: 4.5, // minimum for WCAG AA compliance + rightClickSelectsWord: this.config['terminal.rightClick'] === 'menu', theme: this.options.theme, + windowsPty: this.options.windowsPty && { + backend: this.options.windowsPty.useConpty ? 'conpty' : 'winpty', + buildNumber: this.options.windowsPty.buildNumber, + }, windowOptions: { setWinSizeChars: true, }, }); + this.term.onSelectionChange(() => { + if (this.config['terminal.copyOnSelect'] && this.term.hasSelection()) { + void this.copySelection(); + } + }); + this.term.loadAddon(this.fitAddon); this.registerResizeHandler(); this.term.open(this.el); + this.term.attachCustomKeyEventHandler(e => { + const action = this.keyboardShortcutsService.getShortcutAction(e); + const isKeyDown = e.type === 'keydown'; + if (action === 'terminalCopy' && isKeyDown && this.term.hasSelection()) { + void this.copySelection(); + // Do not invoke a copy action from the menu. + e.preventDefault(); + // Event handled, do not process it in xterm. + return false; + } + if (action === 'terminalPaste' && isKeyDown) { + void this.paste(); + // Do not invoke a copy action from the menu. + e.preventDefault(); + // Event handled, do not process it in xterm. + return false; + } + + return true; + }); + + this.term.element.addEventListener('contextmenu', e => { + // We always call preventDefault because: + // 1. When `terminalRightClick` is not `menu`, we don't want to show it. + // 2. When `terminalRightClick` is `menu`, opening two menus at + // the same time on Linux causes flickering. + e.preventDefault(); + + if (this.config['terminal.rightClick'] === 'menu') { + this.options.openContextMenu(e); + } + }); + + this.term.element.addEventListener('mousedown', e => { + // Secondary button, usually the right button. + if (e.button !== 2) { + return; + } + + e.stopImmediatePropagation(); + e.stopPropagation(); + e.preventDefault(); + + const terminalRightClick = this.config['terminal.rightClick']; + + switch (terminalRightClick) { + case 'paste': { + void this.paste(); + break; + } + case 'copyPaste': { + if (this.term.hasSelection()) { + void this.copySelection(); + this.term.clearSelection(); + } else { + void this.paste(); + } + break; + } + } + }); + this.fitAddon.fit(); this.term.onData(data => { @@ -125,6 +213,16 @@ export default class TtyTerminal { window.removeEventListener('resize', this.debouncedResize); } + private async copySelection(): Promise { + const selection = this.term.getSelection(); + await navigator.clipboard.writeText(selection); + } + + private async paste(): Promise { + const text = await navigator.clipboard.readText(); + this.term.paste(text); + } + private registerResizeHandler(): void { let prevCols: number, prevRows: number; this.resizeHandler = this.term.parser.registerCsiHandler( diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.test.tsx b/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.test.tsx index 6aad2d0c4dceb..3280880988f4a 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.test.tsx +++ b/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.test.tsx @@ -237,6 +237,7 @@ test('useDocumentTerminal shows a warning notification if the call to TerminalsS jest.spyOn(terminalsService, 'createPtyProcess').mockResolvedValue({ process: getPtyProcessMock(), creationStatus: PtyProcessCreationStatus.ResolveShellEnvTimeout, + windowsPty: undefined, }); jest.spyOn(notificationsService, 'notifyWarning'); @@ -574,6 +575,7 @@ const testSetup = ( return { process: getPtyProcessMock(), creationStatus: PtyProcessCreationStatus.Ok, + windowsPty: undefined, }; }); diff --git a/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts b/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts index 029d7df11f38d..155cc3e36c200 100644 --- a/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts +++ b/web/packages/teleterm/src/ui/DocumentTerminal/useDocumentTerminal.ts @@ -29,7 +29,11 @@ import { import { IPtyProcess } from 'teleterm/sharedProcess/ptyHost'; import { useWorkspaceContext } from 'teleterm/ui/Documents'; import { routing } from 'teleterm/ui/uri'; -import { PtyCommand, PtyProcessCreationStatus } from 'teleterm/services/pty'; +import { + PtyCommand, + PtyProcessCreationStatus, + WindowsPty, +} from 'teleterm/services/pty'; import { AmbiguousHostnameError } from 'teleterm/ui/services/resources'; import { retryWithRelogin } from 'teleterm/ui/utils'; import Logger from 'teleterm/logger'; @@ -72,7 +76,7 @@ export function useDocumentTerminal(doc: types.DocumentTerminal) { return () => { if (attempt.status === 'success') { - attempt.data.ptyProcess.dispose(); + void attempt.data.ptyProcess.dispose(); } }; // This cannot be run only mount. If the user has initialized a new PTY process by clicking the @@ -230,7 +234,7 @@ async function setUpPtyProcess( getClusterName() ); - const ptyProcess = await createPtyProcess(ctx, cmd); + const { process: ptyProcess, windowsPty } = await createPtyProcess(ctx, cmd); if (doc.kind === 'doc.terminal_tsh_node') { ctx.usageService.captureProtocolUse({ @@ -317,14 +321,15 @@ async function setUpPtyProcess( ptyProcess, refreshTitle, openContextMenu, + windowsPty, }; } async function createPtyProcess( ctx: IAppContext, cmd: PtyCommand -): Promise { - const { process, creationStatus } = +): Promise<{ process: IPtyProcess; windowsPty: WindowsPty }> { + const { process, creationStatus, windowsPty } = await ctx.terminalsService.createPtyProcess(cmd); if (creationStatus === PtyProcessCreationStatus.ResolveShellEnvTimeout) { @@ -336,7 +341,7 @@ async function createPtyProcess( }); } - return process; + return { process, windowsPty }; } // TODO(ravicious): Instead of creating cmd within useDocumentTerminal, make useDocumentTerminal diff --git a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx index 1df3cc707f2a9..58554c11cbf1c 100644 --- a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx +++ b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx @@ -24,9 +24,13 @@ import styled from 'styled-components'; import Document from 'teleterm/ui/Document'; import { useKeyboardShortcutFormatters } from 'teleterm/ui/services/keyboardShortcuts'; import { KeyboardShortcutAction } from 'teleterm/services/config'; +import { useAppContext } from 'teleterm/ui/appContextProvider'; export function KeyboardShortcutsPanel() { + const { mainProcessClient } = useAppContext(); + const { platform } = mainProcessClient.getRuntimeSettings(); const { getAccelerator } = useKeyboardShortcutFormatters(); + const isNotMac = platform !== 'darwin'; const items: { title: string; shortcutAction: KeyboardShortcutAction }[] = [ { @@ -53,12 +57,22 @@ export function KeyboardShortcutsPanel() { title: 'Open Profiles', shortcutAction: 'openProfiles', }, + // We don't need to show these shortcuts on macOS, + // 99% of the users are not going to change them. + isNotMac && { + title: 'Copy in Terminal', + shortcutAction: 'terminalCopy', + }, + isNotMac && { + title: 'Paste in Terminal', + shortcutAction: 'terminalPaste', + }, ]; return ( - {items.map(item => ( + {items.filter(Boolean).map(item => ( props.theme.space[4]}px; + row-gap: ${props => props.theme.space[3]}px; margin: auto; + padding-block: ${props => props.theme.space[3]}px; `; diff --git a/web/packages/teleterm/src/ui/Vnet/vnetContext.tsx b/web/packages/teleterm/src/ui/Vnet/vnetContext.tsx index f77086d4ccab3..4caf7ece9b3e5 100644 --- a/web/packages/teleterm/src/ui/Vnet/vnetContext.tsx +++ b/web/packages/teleterm/src/ui/Vnet/vnetContext.tsx @@ -207,7 +207,11 @@ const notifyAboutDaemonBackgroundItem = async (ctx: IAppContext) => { throw error; } - if (backgroundItemStatus === BackgroundItemStatus.ENABLED) { + if ( + backgroundItemStatus === BackgroundItemStatus.ENABLED || + backgroundItemStatus === BackgroundItemStatus.NOT_SUPPORTED || + backgroundItemStatus === BackgroundItemStatus.UNSPECIFIED + ) { return; } diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts index 2f8d1700e01ae..8a3374ee6e48f 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts @@ -28,6 +28,15 @@ import { KeyboardShortcutEventSubscriber, } from './types'; +/** + * These actions are handled outside the keyboard event subscribers, + * allow them to pass through (without calling preventDefault and stopPropagation). + */ +const EXTERNALLY_HANDLED_ACTIONS = new Set([ + 'terminalCopy', + 'terminalPaste', +]); + export class KeyboardShortcutsService { private eventsSubscribers = new Set(); private readonly acceleratorsToActions = new Map< @@ -64,6 +73,8 @@ export class KeyboardShortcutsService { openConnections: this.configService.get('keymap.openConnections').value, openClusters: this.configService.get('keymap.openClusters').value, openProfiles: this.configService.get('keymap.openProfiles').value, + terminalCopy: this.configService.get('keymap.terminalCopy').value, + terminalPaste: this.configService.get('keymap.terminalPaste').value, }; this.acceleratorsToActions = mapAcceleratorsToActions(this.shortcutsConfig); this.attachKeydownHandler(); @@ -104,6 +115,10 @@ export class KeyboardShortcutsService { return; } + if (EXTERNALLY_HANDLED_ACTIONS.has(shortcutAction)) { + return; + } + event.preventDefault(); event.stopPropagation(); this.notifyEventsSubscribers({ action: shortcutAction }); @@ -114,7 +129,7 @@ export class KeyboardShortcutsService { }); } - private getShortcutAction( + public getShortcutAction( event: KeyboardEvent ): KeyboardShortcutAction | undefined { // If only a modifier is pressed, `code` is this modifier name