From f3eacb53235c507acc071fe30e59ed5d0160d053 Mon Sep 17 00:00:00 2001 From: Yassine Bounekhla <56373201+rudream@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:48:59 -0400 Subject: [PATCH 01/22] sidenav related fixes and tweaks (#47889) --- web/packages/design/src/Alert/Alert.tsx | 8 +- web/packages/design/src/Icon/Icons.story.tsx | 3 + .../design/src/Icon/Icons/KeyHole.tsx | 73 ++++++ .../design/src/Icon/Icons/LockKey.tsx | 73 ++++++ .../design/src/Icon/Icons/PlugsConnected.tsx | 72 ++++++ .../design/src/Icon/assets/KeyHole.svg | 4 + .../design/src/Icon/assets/LockKey.svg | 4 + .../design/src/Icon/assets/PlugsConnected.svg | 7 + web/packages/design/src/Icon/index.ts | 5 +- .../teleport/src/Main/MainContainer.tsx | 4 +- .../SideNavigation/CategoryIcon.tsx | 2 +- .../Navigation/SideNavigation/Navigation.tsx | 240 +++++++++++++----- .../src/Navigation/SideNavigation/Section.tsx | 30 ++- .../Navigation/SideNavigation/categories.ts | 1 - .../Navigation/SideNavigation/zIndexMap.ts | 8 +- .../src/Notifications/Notification.story.tsx | 2 +- .../teleport/src/TopBar/TopBarSideNav.tsx | 3 - .../src/components/Dropdown/Dropdown.tsx | 3 - web/packages/teleport/src/features.tsx | 52 ++-- web/packages/teleport/src/types.ts | 8 +- 20 files changed, 477 insertions(+), 125 deletions(-) create mode 100644 web/packages/design/src/Icon/Icons/KeyHole.tsx create mode 100644 web/packages/design/src/Icon/Icons/LockKey.tsx create mode 100644 web/packages/design/src/Icon/Icons/PlugsConnected.tsx create mode 100644 web/packages/design/src/Icon/assets/KeyHole.svg create mode 100644 web/packages/design/src/Icon/assets/LockKey.svg create mode 100644 web/packages/design/src/Icon/assets/PlugsConnected.svg diff --git a/web/packages/design/src/Alert/Alert.tsx b/web/packages/design/src/Alert/Alert.tsx index 5e471280ffe24..c674aff2b1b79 100644 --- a/web/packages/design/src/Alert/Alert.tsx +++ b/web/packages/design/src/Alert/Alert.tsx @@ -20,6 +20,8 @@ import React, { useState } from 'react'; import styled, { useTheme } from 'styled-components'; import { style, color, ColorProps } from 'styled-system'; +import { IconProps } from 'design/Icon/Icon'; + import { space, SpaceProps, width, WidthProps } from '../system'; import { Theme } from '../theme'; import * as Icon from '../Icon'; @@ -111,7 +113,7 @@ interface Props { /** Additional description to be displayed below the main content. */ details?: React.ReactNode; /** Overrides the icon specified by {@link AlertProps.kind}. */ - icon?: React.ComponentType; + icon?: React.ComponentType; /** If specified, causes the alert to display a primary action button. */ primaryAction?: Action; /** If specified, causes the alert to display a secondary action button. */ @@ -253,8 +255,8 @@ const AlertIcon = ({ ...otherProps }: { kind: AlertKind | BannerKind; - customIcon?: React.ComponentType; -} & Icon.IconProps) => { + customIcon?: React.ComponentType; +} & IconProps) => { const commonProps = { role: 'graphics-symbol', ...otherProps }; if (CustomIcon) { return ; diff --git a/web/packages/design/src/Icon/Icons.story.tsx b/web/packages/design/src/Icon/Icons.story.tsx index a511f5692b4ca..4a792aeec912c 100644 --- a/web/packages/design/src/Icon/Icons.story.tsx +++ b/web/packages/design/src/Icon/Icons.story.tsx @@ -135,6 +135,7 @@ export const Icons = () => ( + @@ -152,6 +153,7 @@ export const Icons = () => ( + @@ -170,6 +172,7 @@ export const Icons = () => ( + diff --git a/web/packages/design/src/Icon/Icons/KeyHole.tsx b/web/packages/design/src/Icon/Icons/KeyHole.tsx new file mode 100644 index 0000000000000..afc86a7543647 --- /dev/null +++ b/web/packages/design/src/Icon/Icons/KeyHole.tsx @@ -0,0 +1,73 @@ +/** + * 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 KeyHole({ size = 24, color, ...otherProps }: IconProps) { + return ( + + + + + ); +} diff --git a/web/packages/design/src/Icon/Icons/LockKey.tsx b/web/packages/design/src/Icon/Icons/LockKey.tsx new file mode 100644 index 0000000000000..65a953566d71d --- /dev/null +++ b/web/packages/design/src/Icon/Icons/LockKey.tsx @@ -0,0 +1,73 @@ +/** + * 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 LockKey({ size = 24, color, ...otherProps }: IconProps) { + return ( + + + + + ); +} diff --git a/web/packages/design/src/Icon/Icons/PlugsConnected.tsx b/web/packages/design/src/Icon/Icons/PlugsConnected.tsx new file mode 100644 index 0000000000000..ec991cd95b2ee --- /dev/null +++ b/web/packages/design/src/Icon/Icons/PlugsConnected.tsx @@ -0,0 +1,72 @@ +/** + * 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 PlugsConnected({ size = 24, color, ...otherProps }: IconProps) { + return ( + + + + + + + + ); +} diff --git a/web/packages/design/src/Icon/assets/KeyHole.svg b/web/packages/design/src/Icon/assets/KeyHole.svg new file mode 100644 index 0000000000000..c4c69dfaf4c8e --- /dev/null +++ b/web/packages/design/src/Icon/assets/KeyHole.svg @@ -0,0 +1,4 @@ + + + + diff --git a/web/packages/design/src/Icon/assets/LockKey.svg b/web/packages/design/src/Icon/assets/LockKey.svg new file mode 100644 index 0000000000000..554f55b8d71d4 --- /dev/null +++ b/web/packages/design/src/Icon/assets/LockKey.svg @@ -0,0 +1,4 @@ + + + + diff --git a/web/packages/design/src/Icon/assets/PlugsConnected.svg b/web/packages/design/src/Icon/assets/PlugsConnected.svg new file mode 100644 index 0000000000000..2ce54755155bf --- /dev/null +++ b/web/packages/design/src/Icon/assets/PlugsConnected.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/web/packages/design/src/Icon/index.ts b/web/packages/design/src/Icon/index.ts index 57f2fa84d3a11..6e24c134497db 100644 --- a/web/packages/design/src/Icon/index.ts +++ b/web/packages/design/src/Icon/index.ts @@ -22,7 +22,7 @@ THIS FILE IS GENERATED. DO NOT EDIT. */ -export { Icon, type IconProps } from './Icon'; +export { Icon } from './Icon'; export { Add } from './Icons/Add'; export { AddCircle } from './Icons/AddCircle'; @@ -121,6 +121,7 @@ export { Info } from './Icons/Info'; export { Integrations } from './Icons/Integrations'; export { Invoices } from './Icons/Invoices'; export { Key } from './Icons/Key'; +export { KeyHole } from './Icons/KeyHole'; export { Keyboard } from './Icons/Keyboard'; export { Keypair } from './Icons/Keypair'; export { Kubernetes } from './Icons/Kubernetes'; @@ -138,6 +139,7 @@ export { ListMagnifyingGlass } from './Icons/ListMagnifyingGlass'; export { ListThin } from './Icons/ListThin'; export { ListView } from './Icons/ListView'; export { Lock } from './Icons/Lock'; +export { LockKey } from './Icons/LockKey'; export { Logout } from './Icons/Logout'; export { Magnifier } from './Icons/Magnifier'; export { MagnifyingMinus } from './Icons/MagnifyingMinus'; @@ -156,6 +158,7 @@ export { PaperPlane } from './Icons/PaperPlane'; export { Password } from './Icons/Password'; export { Pencil } from './Icons/Pencil'; export { Planet } from './Icons/Planet'; +export { PlugsConnected } from './Icons/PlugsConnected'; export { Plus } from './Icons/Plus'; export { PowerSwitch } from './Icons/PowerSwitch'; export { Printer } from './Icons/Printer'; diff --git a/web/packages/teleport/src/Main/MainContainer.tsx b/web/packages/teleport/src/Main/MainContainer.tsx index 4f7910b80e5dd..75a4109c32d15 100644 --- a/web/packages/teleport/src/Main/MainContainer.tsx +++ b/web/packages/teleport/src/Main/MainContainer.tsx @@ -29,11 +29,9 @@ export const MainContainer = styled.div` --sidebar-width: 256px; --sidenav-width: 76px; --sidenav-panel-width: 224px; + overflow: hidden; margin-top: ${p => p.theme.topBarHeight[0]}px; @media screen and (min-width: ${p => p.theme.breakpoints.small}px) { margin-top: ${p => p.theme.topBarHeight[1]}px; } - @media screen and (min-width: ${p => p.theme.breakpoints.large}px) { - margin-top: ${p => p.theme.topBarHeight[2]}px; - } `; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/CategoryIcon.tsx b/web/packages/teleport/src/Navigation/SideNavigation/CategoryIcon.tsx index feb2135801050..944b53c218b2e 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/CategoryIcon.tsx +++ b/web/packages/teleport/src/Navigation/SideNavigation/CategoryIcon.tsx @@ -41,7 +41,7 @@ export function CategoryIcon({ Icon = Icons.Server; break; case NavigationCategory.Access: - Icon = Icons.Lock; + Icon = Icons.KeyHole; break; case NavigationCategory.Identity: Icon = Icons.FingerprintSimple; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx b/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx index 9d39688b52156..2b532b44e86ac 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx +++ b/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx @@ -16,10 +16,10 @@ * along with this program. If not, see . */ -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useEffect, useRef } from 'react'; import styled, { useTheme } from 'styled-components'; import { matchPath, useHistory } from 'react-router'; -import { Text, Flex, Box } from 'design'; +import { Text, Flex, Box, P2 } from 'design'; import { ToolTipInfo } from 'shared/components/ToolTip'; @@ -123,6 +123,8 @@ function getSubsectionsForCategory( }); } +// getNavSubsectionForRoute returns the sidenav subsection that the user is correctly on (based on route). +// Note that it is possible for this not to return anything, such as in the case where the user is on a page that isn't in the sidenav (eg. Account Settings). function getNavSubsectionForRoute( features: TeleportFeature[], route: history.Location | Location @@ -150,14 +152,64 @@ function getNavSubsectionForRoute( }; } +/** + * useDebounceClose adds a debounce to closing drawers, this is to prevent the drawer closing if the user overshoots it, giving them a slight delay to re-enter the drawer. + */ +function useDebounceClose( + value: T | null, + delay: number, + isClosing: boolean +): T | null { + const [debouncedValue, setDebouncedValue] = useState(value); + const timeoutRef = useRef(); + + useEffect(() => { + // Clear any existing timeout + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + // If we're closing the drarwer as opposed to switching to a different section (value is null and isClosing is true), apply debounce. + if (value === null && isClosing) { + timeoutRef.current = setTimeout(() => { + setDebouncedValue(null); + }, delay); + } else { + // For opening or any other change, update immediately. + setDebouncedValue(value); + } + + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, [value, delay, isClosing]); + + return debouncedValue; +} + export function Navigation() { const features = useFeatures(); const history = useHistory(); - const [expandedSection, setExpandedSection] = - useState(null); - const currentView = getNavSubsectionForRoute(features, history.location); + const [targetSection, setTargetSection] = useState( + null + ); + const [isClosing, setIsClosing] = useState(false); + const debouncedSection = useDebounceClose(targetSection, 200, isClosing); const [previousExpandedSection, setPreviousExpandedSection] = useState(); + const navigationTimeoutRef = useRef(); + + // Clear navigation timeout on unmount. + useEffect(() => { + return () => { + if (navigationTimeoutRef.current) { + clearTimeout(navigationTimeoutRef.current); + } + }; + }, []); + const currentView = getNavSubsectionForRoute(features, history.location); const navSections = getNavigationSections(features).filter( section => section.subsections.length @@ -165,24 +217,59 @@ export function Navigation() { const handleSetExpandedSection = useCallback( (section: NavigationSection) => { + setIsClosing(false); if (!section.standalone) { - setPreviousExpandedSection(expandedSection); - setExpandedSection(section); + setPreviousExpandedSection(debouncedSection); + setTargetSection(section); } else { setPreviousExpandedSection(null); - setExpandedSection(null); + setTargetSection(null); } }, - [expandedSection] + [debouncedSection] ); - const resetExpandedSection = useCallback(() => { + const resetExpandedSection = useCallback((closeAfterDelay = true) => { + setIsClosing(closeAfterDelay); setPreviousExpandedSection(null); - setExpandedSection(null); + setTargetSection(null); }, []); + // Handler for navigation actions + const handleNavigation = useCallback( + (route: string) => { + history.push(route); + + // Clear any existing timeout + if (navigationTimeoutRef.current) { + clearTimeout(navigationTimeoutRef.current); + } + + // Add a small delay to the close to allow the user to see some feedback (see the section they clicked become active). + navigationTimeoutRef.current = setTimeout(() => { + resetExpandedSection(false); + }, 150); + }, + [resetExpandedSection, history] + ); + + // Hide the nav if the current feature has hideNavigation set to true. + const hideNav = features.find( + f => + f.route && + matchPath(history.location.pathname, { + path: f.route.path, + exact: f.route.exact ?? false, + }) + )?.hideNavigation; + + if (hideNav) { + return null; + } + return ( resetExpandedSection()} onKeyUp={e => e.key === 'Escape' && resetExpandedSection()} onBlur={(event: React.FocusEvent) => { @@ -200,73 +287,81 @@ export function Navigation() { {navSections.map(section => ( -
handleSetExpandedSection(section)} - aria-controls={`panel-${expandedSection?.category}`} - onClick={() => { - if (section.standalone) { - history.push(section.subsections[0].route); + + {section.category === 'Add New' && } +
handleSetExpandedSection(section)} + aria-controls={`panel-${debouncedSection?.category}`} + onClick={() => { + if (section.standalone) { + handleNavigation(section.subsections[0].route); + } + }} + isExpanded={ + !!debouncedSection && + !debouncedSection.standalone && + section.category === debouncedSection?.category } - }} - isExpanded={ - !!expandedSection && - !expandedSection.standalone && - section.category === expandedSection?.category - } - > - handleSetExpandedSection(section)} > - handleSetExpandedSection(section)} + onMouseEnter={() => handleSetExpandedSection(section)} > - - - - {section.category} - - - {!section.standalone && - section.subsections.map(section => ( - - - {section.title} - - ))} - - {cfg.edition === 'oss' && } - {cfg.edition === 'community' && } - - -
+ + + + {section.category} + + + {!section.standalone && + section.subsections.map(subsection => ( + { + e.preventDefault(); + handleNavigation(subsection.route); + }} + > + + {subsection.title} + + ))} + + {cfg.edition === 'oss' && } + {cfg.edition === 'community' && } + + +
+ ))}
@@ -356,3 +451,10 @@ const SubText = styled(Text)` color: ${props => props.theme.colors.text.disabled}; font-size: ${props => props.theme.fontSizes[1]}px; `; + +const Divider = styled.div` + z-index: ${zIndexMap.sideNavButtons}; + height: 1px; + background: ${props => props.theme.colors.interactive.tonal.neutral[1]}; + width: 60px; +`; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/Section.tsx b/web/packages/teleport/src/Navigation/SideNavigation/Section.tsx index dab21250a8ae0..ab4bd8efc6cab 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/Section.tsx +++ b/web/packages/teleport/src/Navigation/SideNavigation/Section.tsx @@ -62,16 +62,14 @@ export function Section({ const rightPanelWidth = '236px'; -export const RightPanel = styled(Box).attrs({ pt: 2, px: 2 })<{ +export const RightPanel = styled(Box).attrs({ pt: 2, px: '5px' })<{ isVisible: boolean; skipAnimation: boolean; }>` position: fixed; left: var(--sidenav-width); height: 100%; - scrollbar-gutter: auto; scrollbar-color: ${p => p.theme.colors.spotBackground[2]} transparent; - overflow: visible; width: ${rightPanelWidth}; background: ${p => p.theme.colors.levels.surface}; z-index: ${zIndexMap.sideNavExpandedPanel}; @@ -94,18 +92,14 @@ export const RightPanel = styled(Box).attrs({ pt: 2, px: 2 })<{ top: ${p => p.theme.topBarHeight[1]}px; padding-bottom: ${p => p.theme.topBarHeight[1] + p.theme.space[2]}px; } - @media screen and (min-width: ${p => p.theme.breakpoints.large}px) { - top: ${p => p.theme.topBarHeight[2]}px; - padding-bottom: ${p => p.theme.topBarHeight[3] + p.theme.space[2]}px; - } `; export const CategoryButton = styled.button<{ $active: boolean; isExpanded: boolean; }>` - height: 60px; - width: 60px; + min-height: 60px; + min-width: 60px; cursor: pointer; outline: hidden; border: none; @@ -115,6 +109,11 @@ export const CategoryButton = styled.button<{ justify-content: center; border-radius: ${props => props.theme.radii[2]}px; z-index: ${zIndexMap.sideNavButtons}; + display: flex; + align-items: center; + justify-content: center; + gap: ${props => props.theme.space[1]}px; + font-family: ${props => props.theme.font}; font-size: ${props => props.theme.typography.body4.fontSize}; font-weight: ${props => props.theme.typography.body4.fontWeight}; @@ -177,14 +176,22 @@ export function SubsectionItem({ to, exact, children, + onClick, }: { $active: boolean; to: string; exact: boolean; children: React.ReactNode; + onClick?: (event: React.MouseEvent) => void; }) { return ( - + {children} ); @@ -214,6 +221,9 @@ export function getSubsectionStyles(theme: Theme, active: boolean) { return css` color: ${theme.colors.brand}; background: ${theme.colors.interactive.tonal.primary[0]}; + p { + font-weight: 500; + } &:focus-visible { outline: 2px solid ${theme.colors.interactive.solid.primary.default}; } diff --git a/web/packages/teleport/src/Navigation/SideNavigation/categories.ts b/web/packages/teleport/src/Navigation/SideNavigation/categories.ts index 33d6cf290e40a..f1692be3df123 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/categories.ts +++ b/web/packages/teleport/src/Navigation/SideNavigation/categories.ts @@ -42,7 +42,6 @@ export const NAVIGATION_CATEGORIES = [ ]; export const STANDALONE_CATEGORIES = [ - NavigationCategory.AddNew, // TODO(rudream): Remove this once shortcuts to pinned/nodes/apps/dbs/desktops/kubes are implemented. NavigationCategory.Resources, ]; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/zIndexMap.ts b/web/packages/teleport/src/Navigation/SideNavigation/zIndexMap.ts index a876bddbe8d37..745f119349d4c 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/zIndexMap.ts +++ b/web/packages/teleport/src/Navigation/SideNavigation/zIndexMap.ts @@ -17,8 +17,8 @@ */ export const zIndexMap = { - topBar: 23, - sideNavButtons: 22, - sideNavContainer: 21, - sideNavExpandedPanel: 20, + topBar: 9, + sideNavButtons: 8, + sideNavContainer: 7, + sideNavExpandedPanel: 6, }; diff --git a/web/packages/teleport/src/Notifications/Notification.story.tsx b/web/packages/teleport/src/Notifications/Notification.story.tsx index 05b76bfae920b..d8619f66a8227 100644 --- a/web/packages/teleport/src/Notifications/Notification.story.tsx +++ b/web/packages/teleport/src/Notifications/Notification.story.tsx @@ -220,7 +220,7 @@ const ListComponent = () => { css={` width: 100%; justify-content: center; - height: ${p => p.theme.topBarHeight[2]}px; + height: ${p => p.theme.topBarHeight[1]}px; `} > diff --git a/web/packages/teleport/src/TopBar/TopBarSideNav.tsx b/web/packages/teleport/src/TopBar/TopBarSideNav.tsx index a3a5d966ce2b6..c787f984fa763 100644 --- a/web/packages/teleport/src/TopBar/TopBarSideNav.tsx +++ b/web/packages/teleport/src/TopBar/TopBarSideNav.tsx @@ -85,9 +85,6 @@ export const TopBarContainer = styled(TopNav)` @media screen and (min-width: ${p => p.theme.breakpoints.small}px) { height: ${p => p.theme.topBarHeight[1]}px; } - @media screen and (min-width: ${p => p.theme.breakpoints.large}px) { - height: ${p => p.theme.topBarHeight[2]}px; - } `; const TeleportLogo = ({ CustomLogo }: TopBarProps) => { diff --git a/web/packages/teleport/src/components/Dropdown/Dropdown.tsx b/web/packages/teleport/src/components/Dropdown/Dropdown.tsx index 546dccd7c8dcc..36e47071dcfe7 100644 --- a/web/packages/teleport/src/components/Dropdown/Dropdown.tsx +++ b/web/packages/teleport/src/components/Dropdown/Dropdown.tsx @@ -50,9 +50,6 @@ export const Dropdown = styled.div` @media screen and (min-width: ${p => p.theme.breakpoints.small}px) { top: ${p => p.theme.topBarHeight[1]}px; } - @media screen and (min-width: ${p => p.theme.breakpoints.large}px) { - top: ${p => p.theme.topBarHeight[2]}px; - } `; export const DropdownItem = styled.div<{ diff --git a/web/packages/teleport/src/features.tsx b/web/packages/teleport/src/features.tsx index 0ea8bd7b9d3c1..807b257f11cf8 100644 --- a/web/packages/teleport/src/features.tsx +++ b/web/packages/teleport/src/features.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { - AddCircle, Bots as BotsIcon, CirclePlay, ClipboardUser, @@ -29,14 +28,14 @@ import { Laptop, ListAddCheck, ListThin, - Lock, + LockKey, + PlugsConnected, Question, Server, - ShieldCheck, SlidersVertical, Terminal, UserCircleGear, - Users as UsersIcon, + User as UserIcon, } from 'design/Icon'; import cfg from 'teleport/config'; @@ -221,7 +220,7 @@ export class FeatureUsers implements TeleportFeature { navigationItem = { title: NavTitle.Users, - icon: UsersIcon, + icon: UserIcon, exact: true, getLink() { return cfg.getUsersRoute(); @@ -268,13 +267,12 @@ export class FeatureBots implements TeleportFeature { export class FeatureAddBots implements TeleportFeature { category = NavigationCategory.Management; section = ManagementSection.Access; - sideNavCategory = SideNavigationCategory.Access; - hideFromNavigation = true; + sideNavCategory = SideNavigationCategory.AddNew; route = { - title: 'New Bot', + title: 'Bot', path: cfg.routes.botsNew, - exact: false, + exact: true, component: () => , }; @@ -285,6 +283,16 @@ export class FeatureAddBots implements TeleportFeature { getRoute() { return this.route; } + + navigationItem = { + title: NavTitle.NewBot, + icon: BotsIcon, + exact: true, + getLink() { + return cfg.getBotsNewRoute(); + }, + searchableTags: ['add bot', 'new bot', 'bots'], + }; } export class FeatureRoles implements TeleportFeature { @@ -332,7 +340,7 @@ export class FeatureAuthConnectors implements TeleportFeature { navigationItem = { title: NavTitle.AuthConnectors, - icon: ShieldCheck, + icon: PlugsConnected, exact: false, getLink() { return cfg.routes.sso; @@ -359,7 +367,7 @@ export class FeatureLocks implements TeleportFeature { navigationItem = { title: NavTitle.SessionAndIdentityLocks, - icon: Lock, + icon: LockKey, exact: false, getLink() { return cfg.getLocksRoute(); @@ -394,7 +402,7 @@ export class FeatureDiscover implements TeleportFeature { standalone = true; route = { - title: 'Enroll New Resource', + title: 'Resource', path: cfg.routes.discover, exact: true, component: Discover, @@ -402,7 +410,7 @@ export class FeatureDiscover implements TeleportFeature { navigationItem = { title: NavTitle.EnrollNewResource, - icon: AddCircle, + icon: Server, exact: true, getLink() { return cfg.routes.discover; @@ -453,11 +461,10 @@ export class FeatureIntegrations implements TeleportFeature { export class FeatureIntegrationEnroll implements TeleportFeature { category = NavigationCategory.Management; section = ManagementSection.Access; - sideNavCategory = SideNavigationCategory.Access; - parent = FeatureIntegrations; + sideNavCategory = SideNavigationCategory.AddNew; route = { - title: 'Enroll New Integration', + title: 'Integration', path: cfg.routes.integrationEnroll, exact: false, component: () => , @@ -469,7 +476,7 @@ export class FeatureIntegrationEnroll implements TeleportFeature { navigationItem = { title: NavTitle.EnrollNewIntegration, - icon: AddCircle, + icon: IntegrationsIcon, getLink() { return cfg.getIntegrationEnrollRoute(null); }, @@ -668,17 +675,18 @@ export function getOSSFeatures(): TeleportFeature[] { // TODO(rudream): Implement shortcuts to pinned/nodes/apps/dbs/desktops/kubes. new FeatureUnifiedResources(), - // Management + // AddNew + new FeatureDiscover(), + new FeatureIntegrationEnroll(), + new FeatureAddBots(), // - Access new FeatureUsers(), - new FeatureRoles(), new FeatureBots(), - new FeatureAddBots(), new FeatureJoinTokens(), + new FeatureRoles(), new FeatureAuthConnectors(), new FeatureIntegrations(), - new FeatureIntegrationEnroll(), new FeatureClusters(), new FeatureTrust(), @@ -693,8 +701,6 @@ export function getOSSFeatures(): TeleportFeature[] { new FeatureRecordings(), new FeatureSessions(), - new FeatureDiscover(), - // Other new FeatureAccount(), new FeatureHelpAndSupport(), diff --git a/web/packages/teleport/src/types.ts b/web/packages/teleport/src/types.ts index 2644288375b82..2c3620e6d86b7 100644 --- a/web/packages/teleport/src/types.ts +++ b/web/packages/teleport/src/types.ts @@ -63,12 +63,14 @@ export enum NavTitle { // Access Management Users = 'Users', Bots = 'Bots', - Roles = 'User Roles', + Roles = 'Roles', JoinTokens = 'Join Tokens', AuthConnectors = 'Auth Connectors', Integrations = 'Integrations', - EnrollNewResource = 'Enroll New Resource', - EnrollNewIntegration = 'Enroll New Integration', + EnrollNewResource = 'Resource', + EnrollNewIntegration = 'Integration', + NewAccessList = 'Access List', + NewBot = 'Bot', // Identity Governance & Security AccessLists = 'Access Lists', From dbf356b09f1e36f072af1bc94b59effc1119dfa6 Mon Sep 17 00:00:00 2001 From: Yassine Bounekhla <56373201+rudream@users.noreply.github.com> Date: Mon, 28 Oct 2024 03:44:06 -0400 Subject: [PATCH 02/22] [Web] Add resource kind-specific sidenav sections (#47882) * add resource kind-specific nav sections * update eref --- e | 2 +- .../Navigation/SideNavigation/Navigation.tsx | 24 +- .../SideNavigation/ResourcesSection.tsx | 349 ++++++++++++++++++ .../src/Navigation/SideNavigation/Search.tsx | 33 +- .../src/Navigation/SideNavigation/Section.tsx | 4 +- .../Navigation/SideNavigation/categories.ts | 18 +- .../encodeUrlQueryParams.test.ts | 15 +- .../useUrlFiltering/encodeUrlQueryParams.ts | 2 +- .../hooks/useUrlFiltering/useUrlFiltering.ts | 15 +- web/packages/teleport/src/features.tsx | 5 +- 10 files changed, 439 insertions(+), 28 deletions(-) create mode 100644 web/packages/teleport/src/Navigation/SideNavigation/ResourcesSection.tsx diff --git a/e b/e index fc67d20733894..03e3eb1845e67 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit fc67d20733894f45e37aeebba64494085ef7667c +Subproject commit 03e3eb1845e6780f764c5c8164dd55232714b6d4 diff --git a/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx b/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx index 2b532b44e86ac..2099a09abd61f 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx +++ b/web/packages/teleport/src/Navigation/SideNavigation/Navigation.tsx @@ -36,11 +36,12 @@ import { import { zIndexMap } from './zIndexMap'; import { + CustomNavigationSubcategory, NAVIGATION_CATEGORIES, - STANDALONE_CATEGORIES, SidenavCategory, } from './categories'; import { SearchSection } from './Search'; +import { ResourcesSection } from './ResourcesSection'; import type * as history from 'history'; import type { TeleportFeature } from 'teleport/types'; @@ -86,6 +87,20 @@ export type NavigationSubsection = { icon: (props) => JSX.Element; parent?: TeleportFeature; searchableTags?: string[]; + /** + * customRouteMatchFn is a custom function for determining whether this subsection is currently active, + * this is useful in cases where a simple base route match isn't sufficient. + */ + customRouteMatchFn?: (currentViewRoute: string) => boolean; + /** + * subCategory is the subcategory (ie. subsection grouping) this subsection should be under, if applicable. + * */ + subCategory?: CustomNavigationSubcategory; + /** + * onClick is custom code that can be run when clicking on the subsection. + * Note that this is merely extra logic, and does not replace the default routing behaviour of a subsection which will navigate the user to the route. + */ + onClick?: () => void; }; function getNavigationSections( @@ -94,7 +109,6 @@ function getNavigationSections( const navigationSections = NAVIGATION_CATEGORIES.map(category => ({ category, subsections: getSubsectionsForCategory(category, features), - standalone: STANDALONE_CATEGORIES.indexOf(category) !== -1, })); return navigationSections; @@ -292,6 +306,12 @@ export function Navigation() { handleSetExpandedSection={handleSetExpandedSection} currentView={currentView} /> + {navSections.map(section => ( {section.category === 'Add New' && } diff --git a/web/packages/teleport/src/Navigation/SideNavigation/ResourcesSection.tsx b/web/packages/teleport/src/Navigation/SideNavigation/ResourcesSection.tsx new file mode 100644 index 0000000000000..dbcfbdc903195 --- /dev/null +++ b/web/packages/teleport/src/Navigation/SideNavigation/ResourcesSection.tsx @@ -0,0 +1,349 @@ +/** + * 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 from 'react'; +import styled from 'styled-components'; +import { matchPath } from 'react-router'; + +import { Box, Flex, Text } from 'design'; +import * as Icons from 'design/Icon'; + +import { DefaultTab } from 'gen-proto-ts/teleport/userpreferences/v1/unified_resource_preferences_pb'; +import { UserPreferences } from 'gen-proto-ts/teleport/userpreferences/v1/userpreferences_pb'; + +import cfg from 'teleport/config'; +import useStickyClusterId from 'teleport/useStickyClusterId'; +import { encodeUrlQueryParams } from 'teleport/components/hooks/useUrlFiltering'; +import { EncodeUrlQueryParamsProps } from 'teleport/components/hooks/useUrlFiltering/encodeUrlQueryParams'; +import { ResourceIdKind } from 'teleport/services/agents'; +import { useUser } from 'teleport/User/UserContext'; + +import { NavigationSubsection, NavigationSection } from './Navigation'; +import { + Section, + RightPanel, + verticalPadding, + SubsectionItem, +} from './Section'; +import { CustomNavigationSubcategory, NavigationCategory } from './categories'; + +/** + * getResourcesSectionForSearch returns a NavigationSection for resources, + * this is only used for the sake of indexing these subsections in the sidenav search. + */ +export function getResourcesSectionForSearch( + subsectionProps: GetSubsectionProps +): NavigationSection { + return { + category: NavigationCategory.Resources, + subsections: getResourcesSubsections(subsectionProps), + }; +} + +type GetSubsectionProps = { + clusterId: string; + preferences: UserPreferences; + updatePreferences: (preferences: Partial) => Promise; + searchParams: URLSearchParams; +}; + +function encodeUrlQueryParamsWithTypedKinds( + params: Omit & { + kinds?: ResourceIdKind[]; + } +) { + return encodeUrlQueryParams(params); +} + +function getResourcesSubsections({ + clusterId, + preferences, + updatePreferences, + searchParams, +}: GetSubsectionProps): NavigationSubsection[] { + const baseRoute = cfg.getUnifiedResourcesRoute(clusterId); + + const setPinnedUserPreference = (pinnedOnly: boolean) => { + // Return early if the current user preference already matches the pinnedOnly param provided, since nothing needs to be done. + if ( + (pinnedOnly && + preferences?.unifiedResourcePreferences?.defaultTab === + DefaultTab.PINNED) || + (!pinnedOnly && + (preferences?.unifiedResourcePreferences?.defaultTab === + DefaultTab.ALL || + preferences?.unifiedResourcePreferences?.defaultTab === + DefaultTab.UNSPECIFIED)) + ) { + return; + } + + updatePreferences({ + ...preferences, + unifiedResourcePreferences: { + ...preferences?.unifiedResourcePreferences, + defaultTab: pinnedOnly ? DefaultTab.PINNED : DefaultTab.ALL, + }, + }); + }; + + const currentKinds = searchParams + .getAll('kinds') + .flatMap(k => k.split(',')) + .filter(Boolean); + const isPinnedOnly = + preferences?.unifiedResourcePreferences?.defaultTab === DefaultTab.PINNED; + + // isKindActive returns true if we are currently filtering for only the provided kind of resource. + const isKindActive = (kind: ResourceIdKind) => { + // This subsection for this kind should only be marked active when it is the only kind being filtered for, + // if there are multiple kinds then the "All Resources" button should be active. + return currentKinds.length === 1 && currentKinds[0] === kind; + }; + + const allResourcesRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + pinnedOnly: false, + }); + const pinnedOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + pinnedOnly: true, + }); + const applicationsOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + kinds: ['app'], + pinnedOnly: false, + }); + const databasesOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + kinds: ['db'], + pinnedOnly: false, + }); + const desktopsOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + kinds: ['windows_desktop'], + pinnedOnly: false, + }); + const kubesOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + kinds: ['kube_cluster'], + pinnedOnly: false, + }); + const nodesOnlyRoute = encodeUrlQueryParamsWithTypedKinds({ + pathname: baseRoute, + kinds: ['node'], + pinnedOnly: false, + }); + + return [ + { + title: 'All Resources', + icon: Icons.Server, + route: allResourcesRoute, + searchableTags: ['resources', 'resources', 'all resources'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: currentViewRoute => + !!matchPath(currentViewRoute, { + path: cfg.routes.unifiedResources, + exact: false, + }) && + !isPinnedOnly && + currentKinds.length !== 1, + onClick: () => setPinnedUserPreference(false), + }, + { + title: 'Pinned Resources', + icon: Icons.PushPin, + route: pinnedOnlyRoute, + searchableTags: ['resources', 'resources', 'pinned resources'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isPinnedOnly && currentKinds.length !== 1, + onClick: () => setPinnedUserPreference(true), + }, + { + title: 'Applications', + icon: Icons.Application, + route: applicationsOnlyRoute, + searchableTags: ['resources', 'apps', 'applications'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isKindActive('app'), + onClick: () => setPinnedUserPreference(false), + subCategory: CustomNavigationSubcategory.FilteredViews, + }, + { + title: 'Databases', + icon: Icons.Database, + route: databasesOnlyRoute, + searchableTags: ['resources', 'dbs', 'databases'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isKindActive('db'), + onClick: () => setPinnedUserPreference(false), + subCategory: CustomNavigationSubcategory.FilteredViews, + }, + { + title: 'Desktops', + icon: Icons.Database, + route: desktopsOnlyRoute, + searchableTags: ['resources', 'desktops', 'rdp', 'windows'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isKindActive('windows_desktop'), + onClick: () => setPinnedUserPreference(false), + subCategory: CustomNavigationSubcategory.FilteredViews, + }, + { + title: 'Kubernetes', + icon: Icons.Kubernetes, + route: kubesOnlyRoute, + searchableTags: ['resources', 'k8s', 'kubes', 'kubernetes'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isKindActive('kube_cluster'), + onClick: () => setPinnedUserPreference(false), + subCategory: CustomNavigationSubcategory.FilteredViews, + }, + { + title: 'SSH Resources', + icon: Icons.Server, + route: nodesOnlyRoute, + searchableTags: ['resources', 'servers', 'nodes', 'ssh resources'], + category: NavigationCategory.Resources, + exact: false, + customRouteMatchFn: () => isKindActive('node'), + onClick: () => setPinnedUserPreference(false), + subCategory: CustomNavigationSubcategory.FilteredViews, + }, + ]; +} + +export function ResourcesSection({ + expandedSection, + previousExpandedSection, + handleSetExpandedSection, + currentView, +}: { + expandedSection: NavigationSection; + previousExpandedSection: NavigationSection; + currentView: NavigationSubsection; + handleSetExpandedSection: (section: NavigationSection) => void; +}) { + const { clusterId } = useStickyClusterId(); + const { preferences, updatePreferences } = useUser(); + const section: NavigationSection = { + category: NavigationCategory.Resources, + subsections: [], + }; + const baseRoute = cfg.getUnifiedResourcesRoute(clusterId); + + const searchParams = new URLSearchParams(location.search); + + const isExpanded = expandedSection?.category === NavigationCategory.Resources; + + const subsections = getResourcesSubsections({ + clusterId, + preferences, + updatePreferences, + searchParams, + }); + + const currentViewRoute = currentView?.route; + + return ( +
null} + setExpandedSection={() => handleSetExpandedSection(section)} + aria-controls={`panel-${expandedSection?.category}`} + isExpanded={isExpanded} + > + handleSetExpandedSection(section)} + > + + + + Resources + + + {subsections + .filter(section => !section.subCategory) + .map(section => ( + + + {section.title} + + ))} + + + + + Filtered Views + + + + {subsections + .filter( + section => + section.subCategory === + CustomNavigationSubcategory.FilteredViews + ) + .map(section => ( + + + {section.title} + + ))} + + +
+ ); +} + +export const Divider = styled.div` + height: 1px; + width: 100%; + background: ${props => props.theme.colors.interactive.tonal.neutral[1]}; + margin: ${props => props.theme.space[1]}px 0px + ${props => props.theme.space[1]}px 0px; +`; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/Search.tsx b/web/packages/teleport/src/Navigation/SideNavigation/Search.tsx index 9ca0c39aab873..118fc905f7f79 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/Search.tsx +++ b/web/packages/teleport/src/Navigation/SideNavigation/Search.tsx @@ -23,6 +23,9 @@ import styled from 'styled-components'; import { Box, Flex, Text } from 'design'; import { height, space, color } from 'design/system'; +import useStickyClusterId from 'teleport/useStickyClusterId'; +import { useUser } from 'teleport/User/UserContext'; + import { NavigationSection, NavigationSubsection } from './Navigation'; import { Section, @@ -32,6 +35,7 @@ import { } from './Section'; import { CategoryIcon } from './CategoryIcon'; import { CustomNavigationCategory } from './categories'; +import { getResourcesSectionForSearch } from './ResourcesSection'; export function SearchSection({ navigationSections, @@ -50,6 +54,20 @@ export function SearchSection({ category: CustomNavigationCategory.Search, subsections: [], }; + const { clusterId } = useStickyClusterId(); + const { preferences, updatePreferences } = useUser(); + + const searchParams = new URLSearchParams(location.search); + + const searchableNavSections: NavigationSection[] = [ + getResourcesSectionForSearch({ + clusterId, + preferences, + updatePreferences, + searchParams, + }), + ...navigationSections, + ]; const isExpanded = expandedSection?.category === CustomNavigationCategory.Search; @@ -70,7 +88,7 @@ export function SearchSection({ onFocus={() => handleSetExpandedSection(section)} > @@ -123,7 +141,11 @@ function SearchContent({ ))} @@ -141,7 +163,12 @@ function SearchResult({ $active: boolean; }) { return ( - + ` display: flex; diff --git a/web/packages/teleport/src/Navigation/SideNavigation/categories.ts b/web/packages/teleport/src/Navigation/SideNavigation/categories.ts index f1692be3df123..6bc60bd20f818 100644 --- a/web/packages/teleport/src/Navigation/SideNavigation/categories.ts +++ b/web/packages/teleport/src/Navigation/SideNavigation/categories.ts @@ -25,23 +25,27 @@ export enum NavigationCategory { AddNew = 'Add New', } -/* CustomNavigationCategory are pseudo-categories which exist only in the nav menu, eg. Search. */ +/** + * CustomNavigationCategory are pseudo-categories which exist only in the nav menu, eg. Search. + */ export enum CustomNavigationCategory { Search = 'Search', } +/** + * CustomNavigationSubcategory are subcategories within a navigation category which can be used to + * create groupings of subsections, eg. Filtered Views. + */ +export enum CustomNavigationSubcategory { + FilteredViews = 'Filtered Views', +} + export type SidenavCategory = NavigationCategory | CustomNavigationCategory; export const NAVIGATION_CATEGORIES = [ - NavigationCategory.Resources, NavigationCategory.Access, NavigationCategory.Identity, NavigationCategory.Policy, NavigationCategory.Audit, NavigationCategory.AddNew, ]; - -export const STANDALONE_CATEGORIES = [ - // TODO(rudream): Remove this once shortcuts to pinned/nodes/apps/dbs/desktops/kubes are implemented. - NavigationCategory.Resources, -]; diff --git a/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.test.ts b/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.test.ts index f68e5a0ca5733..56ac3f40c6358 100644 --- a/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.test.ts +++ b/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.test.ts @@ -29,17 +29,17 @@ const testCases: { { title: 'No query params', args: { pathname: '/foo' }, - expected: '/foo', + expected: '/foo?pinnedOnly=false', }, { title: 'Search string', args: { pathname: '/test', searchString: 'something' }, - expected: '/test?search=something', + expected: '/test?search=something&pinnedOnly=false', }, { title: 'Search string, encoded', args: { pathname: '/test', searchString: 'a$b$c' }, - expected: '/test?search=a%24b%24c', + expected: '/test?search=a%24b%24c&pinnedOnly=false', }, { title: 'Advanced search', @@ -48,7 +48,7 @@ const testCases: { searchString: 'foo=="bar"', isAdvancedSearch: true, }, - expected: '/test?query=foo%3D%3D%22bar%22', + expected: '/test?query=foo%3D%3D%22bar%22&pinnedOnly=false', }, { title: 'Search and sort', @@ -57,7 +57,7 @@ const testCases: { searchString: 'foobar', sort: { fieldName: 'name', dir: 'ASC' }, }, - expected: '/test?search=foobar&sort=name%3Aasc', + expected: '/test?search=foobar&sort=name%3Aasc&pinnedOnly=false', }, { title: 'Sort only', @@ -65,7 +65,7 @@ const testCases: { pathname: '/test', sort: { fieldName: 'name', dir: 'ASC' }, }, - expected: '/test?sort=name%3Aasc', + expected: '/test?sort=name%3Aasc&pinnedOnly=false', }, { title: 'Search, sort, and filter by kind', @@ -75,7 +75,8 @@ const testCases: { sort: { fieldName: 'name', dir: 'DESC' }, kinds: ['db', 'node'], }, - expected: '/test?search=foo&sort=name%3Adesc&kinds=db&kinds=node', + expected: + '/test?search=foo&sort=name%3Adesc&pinnedOnly=false&kinds=db&kinds=node', }, ]; diff --git a/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.ts b/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.ts index a00b57dc47695..fbcbf0217f917 100644 --- a/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.ts +++ b/web/packages/teleport/src/components/hooks/useUrlFiltering/encodeUrlQueryParams.ts @@ -45,7 +45,7 @@ export function encodeUrlQueryParams({ urlParams.append('sort', `${sort.fieldName}:${sort.dir.toLowerCase()}`); } - if (pinnedOnly) { + if (pinnedOnly !== undefined) { urlParams.append('pinnedOnly', `${pinnedOnly}`); } diff --git a/web/packages/teleport/src/components/hooks/useUrlFiltering/useUrlFiltering.ts b/web/packages/teleport/src/components/hooks/useUrlFiltering/useUrlFiltering.ts index 37652913fcb21..fa2bc1ce175a1 100644 --- a/web/packages/teleport/src/components/hooks/useUrlFiltering/useUrlFiltering.ts +++ b/web/packages/teleport/src/components/hooks/useUrlFiltering/useUrlFiltering.ts @@ -62,8 +62,16 @@ export function useUrlFiltering( const [initialParamsState] = useState(initialParams); const params = useMemo(() => { - return { ...initialParamsState, ...getResourceUrlQueryParams(search) }; - }, [initialParamsState, search]); + const urlParams = getResourceUrlQueryParams(search); + return { + ...initialParamsState, + ...urlParams, + pinnedOnly: + urlParams.pinnedOnly !== undefined + ? urlParams.pinnedOnly + : initialParamsState.pinnedOnly, + }; + }, [search]); function setParams(newParams: ResourceFilter) { replaceHistory( @@ -134,6 +142,7 @@ export default function getResourceUrlQueryParams( // Conditionally adds the sort field based on whether it exists or not ...(!!processedSortParam && { sort: processedSortParam }), // Conditionally adds the pinnedResources field based on whether its true or not - ...(pinnedOnly === 'true' && { pinnedOnly: true }), + pinnedOnly: + pinnedOnly === 'true' ? true : pinnedOnly === 'false' ? false : undefined, }; } diff --git a/web/packages/teleport/src/features.tsx b/web/packages/teleport/src/features.tsx index 807b257f11cf8..f1aab44471ad5 100644 --- a/web/packages/teleport/src/features.tsx +++ b/web/packages/teleport/src/features.tsx @@ -415,7 +415,7 @@ export class FeatureDiscover implements TeleportFeature { getLink() { return cfg.routes.discover; }, - searchableTags: ['new resource', 'add'], + searchableTags: ['new', 'add', 'enroll', 'resources'], }; hasAccess(flags: FeatureFlags) { @@ -480,6 +480,7 @@ export class FeatureIntegrationEnroll implements TeleportFeature { getLink() { return cfg.getIntegrationEnrollRoute(null); }, + searchableTags: ['new', 'add', 'enroll', 'integration'], }; // getRoute allows child class extending this @@ -593,7 +594,7 @@ export class FeatureTrust implements TeleportFeature { getLink() { return cfg.routes.trustedClusters; }, - searchableTags: ['clusters', 'trusted clusters'], + searchableTags: ['clusters', 'trusted clusters', 'root clusters'], }; } From 54c9060e75c2b3429f213d60e6b84b26807e4d79 Mon Sep 17 00:00:00 2001 From: Trent Clarke Date: Mon, 28 Oct 2024 23:20:14 +1100 Subject: [PATCH 03/22] Adds caching support for Identity Center resources (#47880) * Adds caching support for Identity Center resources Adds support for caching (and watching) some IdentityCenter resource types. Specifically: - identitycenterv1.Account - identitycenterv1.AccountAsssignment - identitycenterv1.PrincipalAssignment Also breaks the cache's `genericcollection` out into its own file as an attempt to reduce clutter in the main collections source file. * Update identitycenter_events.go * Update identitycenter_events.go * Speed up tests --- api/client/events.go | 23 +- api/client/proto/event.pb.go | 761 ++++++++++-------- .../teleport/legacy/client/proto/event.proto | 9 + api/types/plugin.go | 3 +- lib/auth/accesspoint/accesspoint.go | 1 + lib/auth/auth.go | 1 + lib/cache/cache.go | 15 + lib/cache/cache_test.go | 148 ++-- lib/cache/collections.go | 268 +++--- lib/cache/genericcollection.go | 128 +++ lib/cache/identitycenter.go | 196 +++++ lib/cache/identitycenter_test.go | 263 ++++++ lib/service/service.go | 1 + lib/services/identitycenter.go | 4 + lib/services/local/events.go | 6 + lib/services/local/identitycenter.go | 10 + lib/services/local/identitycenter_events.go | 162 ++++ lib/services/local/identitycenter_test.go | 4 + 18 files changed, 1435 insertions(+), 568 deletions(-) create mode 100644 lib/cache/genericcollection.go create mode 100644 lib/cache/identitycenter.go create mode 100644 lib/cache/identitycenter_test.go create mode 100644 lib/services/local/identitycenter_events.go diff --git a/api/client/events.go b/api/client/events.go index 89c7260e38ac6..89e5b5ecc3157 100644 --- a/api/client/events.go +++ b/api/client/events.go @@ -23,6 +23,7 @@ import ( clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1" crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1" dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1" + identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1" machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" @@ -122,7 +123,18 @@ func EventToGRPC(in types.Event) (*proto.Event, error) { out.Resource = &proto.Event_AutoUpdateAgentRollout{ AutoUpdateAgentRollout: r, } - + case *identitycenterv1.Account: + out.Resource = &proto.Event_IdentityCenterAccount{ + IdentityCenterAccount: r, + } + case *identitycenterv1.PrincipalAssignment: + out.Resource = &proto.Event_IdentityCenterPrincipalAssignment{ + IdentityCenterPrincipalAssignment: r, + } + case *identitycenterv1.AccountAssignment: + out.Resource = &proto.Event_IdentityCenterAccountAssignment{ + IdentityCenterAccountAssignment: r, + } default: return nil, trace.BadParameter("resource type %T is not supported", r) } @@ -588,6 +600,15 @@ func EventFromGRPC(in *proto.Event) (*types.Event, error) { } else if r := in.GetProvisioningPrincipalState(); r != nil { out.Resource = types.Resource153ToLegacy(r) return &out, nil + } else if r := in.GetIdentityCenterAccount(); r != nil { + out.Resource = types.Resource153ToLegacy(r) + return &out, nil + } else if r := in.GetIdentityCenterPrincipalAssignment(); r != nil { + out.Resource = types.Resource153ToLegacy(r) + return &out, nil + } else if r := in.GetIdentityCenterAccountAssignment(); r != nil { + out.Resource = types.Resource153ToLegacy(r) + return &out, nil } else { return nil, trace.BadParameter("received unsupported resource %T", in.Resource) } diff --git a/api/client/proto/event.pb.go b/api/client/proto/event.pb.go index f022839dcd0c5..8cb8416436e6f 100644 --- a/api/client/proto/event.pb.go +++ b/api/client/proto/event.pb.go @@ -28,6 +28,7 @@ import ( v17 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1" v18 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1" v12 "github.com/gravitational/teleport/api/gen/proto/go/teleport/discoveryconfig/v1" + v114 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" v15 "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1" v19 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" v16 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" @@ -182,6 +183,9 @@ type Event struct { // *Event_DynamicWindowsDesktop // *Event_ProvisioningPrincipalState // *Event_AutoUpdateAgentRollout + // *Event_IdentityCenterAccount + // *Event_IdentityCenterPrincipalAssignment + // *Event_IdentityCenterAccountAssignment Resource isEvent_Resource `protobuf_oneof:"Resource"` } @@ -691,6 +695,27 @@ func (x *Event) GetAutoUpdateAgentRollout() *v111.AutoUpdateAgentRollout { return nil } +func (x *Event) GetIdentityCenterAccount() *v114.Account { + if x, ok := x.GetResource().(*Event_IdentityCenterAccount); ok { + return x.IdentityCenterAccount + } + return nil +} + +func (x *Event) GetIdentityCenterPrincipalAssignment() *v114.PrincipalAssignment { + if x, ok := x.GetResource().(*Event_IdentityCenterPrincipalAssignment); ok { + return x.IdentityCenterPrincipalAssignment + } + return nil +} + +func (x *Event) GetIdentityCenterAccountAssignment() *v114.AccountAssignment { + if x, ok := x.GetResource().(*Event_IdentityCenterAccountAssignment); ok { + return x.IdentityCenterAccountAssignment + } + return nil +} + type isEvent_Resource interface { isEvent_Resource() } @@ -1029,6 +1054,23 @@ type Event_AutoUpdateAgentRollout struct { AutoUpdateAgentRollout *v111.AutoUpdateAgentRollout `protobuf:"bytes,71,opt,name=AutoUpdateAgentRollout,proto3,oneof"` } +type Event_IdentityCenterAccount struct { + // IdentityCenterAccount is a resource for tracking Identity Center accounts + IdentityCenterAccount *v114.Account `protobuf:"bytes,72,opt,name=IdentityCenterAccount,proto3,oneof"` +} + +type Event_IdentityCenterPrincipalAssignment struct { + // IdentityCenterPrincipalAssignment is a resource for tracking the AWS + // Permission Sets assigned to a Teleport user or AAccess List + IdentityCenterPrincipalAssignment *v114.PrincipalAssignment `protobuf:"bytes,73,opt,name=IdentityCenterPrincipalAssignment,proto3,oneof"` +} + +type Event_IdentityCenterAccountAssignment struct { + // IdentityCenterAccountlAssignment is a resource representing a potential + // Permission Set grant on a specific AWS account. + IdentityCenterAccountAssignment *v114.AccountAssignment `protobuf:"bytes,74,opt,name=IdentityCenterAccountAssignment,proto3,oneof"` +} + func (*Event_ResourceHeader) isEvent_Resource() {} func (*Event_CertAuthority) isEvent_Resource() {} @@ -1161,6 +1203,12 @@ func (*Event_ProvisioningPrincipalState) isEvent_Resource() {} func (*Event_AutoUpdateAgentRollout) isEvent_Resource() {} +func (*Event_IdentityCenterAccount) isEvent_Resource() {} + +func (*Event_IdentityCenterPrincipalAssignment) isEvent_Resource() {} + +func (*Event_IdentityCenterAccountAssignment) isEvent_Resource() {} + var File_teleport_legacy_client_proto_event_proto protoreflect.FileDescriptor var file_teleport_legacy_client_proto_event_proto_rawDesc = []byte{ @@ -1187,346 +1235,370 @@ var file_teleport_legacy_client_proto_event_proto_rawDesc = []byte{ 0x65, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x31, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3b, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, - 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x6b, - 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x74, 0x65, - 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, - 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 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, 0x1a, 0x2d, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2b, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2f, - 0x76, 0x31, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, 0x73, - 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x31, 0x2f, - 0x75, 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x31, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, - 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2f, - 0x76, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x68, 0x6f, 0x73, 0x74, 0x75, 0x73, 0x65, - 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0xf6, 0x25, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, 0x70, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x3f, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, - 0x52, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, - 0x12, 0x3e, 0x0a, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, 0x48, - 0x00, 0x52, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x3b, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x56, 0x32, 0x48, 0x00, 0x52, - 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x41, 0x0a, - 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, 0x32, 0x48, 0x00, - 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x12, 0x38, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0b, 0x43, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x55, 0x73, - 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, - 0x23, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x36, 0x48, 0x00, 0x52, 0x04, - 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, 0x4e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, - 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x56, 0x32, - 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, - 0x6c, 0x12, 0x47, 0x0a, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0a, 0x41, 0x70, - 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, - 0x65, 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x33, - 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, - 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, - 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x08, 0x57, - 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, 0x33, - 0x48, 0x00, 0x52, 0x08, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x5c, 0x0a, 0x17, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, - 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, - 0x00, 0x52, 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x16, 0x53, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2f, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x3b, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, + 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, + 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2f, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, + 0x64, 0x2f, 0x76, 0x31, 0x2f, 0x62, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 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, 0x1a, + 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2b, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x31, + 0x2f, 0x75, 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x31, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, + 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x68, 0x6f, 0x73, 0x74, 0x75, 0x73, + 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2f, 0x76, 0x31, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0xcf, 0x28, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x3f, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, + 0x00, 0x52, 0x0e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, + 0x48, 0x00, 0x52, 0x0d, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x3b, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x56, 0x32, 0x48, 0x00, + 0x52, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x41, + 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, 0x32, 0x48, + 0x00, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0b, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x55, + 0x73, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x55, 0x73, 0x65, 0x72, + 0x12, 0x23, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x36, 0x48, 0x00, 0x52, + 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, 0x4e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x32, 0x48, 0x00, 0x52, 0x06, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, + 0x6e, 0x65, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x56, + 0x32, 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x47, 0x0a, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x10, 0x54, 0x75, 0x6e, 0x6e, 0x65, + 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0d, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0a, 0x41, + 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, + 0x33, 0x48, 0x00, 0x52, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x12, 0x41, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x35, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, + 0x52, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x08, + 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x56, + 0x33, 0x48, 0x00, 0x52, 0x08, 0x57, 0x65, 0x62, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x5c, 0x0a, + 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, + 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, + 0x48, 0x00, 0x52, 0x17, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x77, 0x6f, + 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, - 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, - 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x43, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x17, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, - 0x32, 0x48, 0x00, 0x52, 0x12, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x18, - 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4c, 0x6f, - 0x63, 0x6b, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, 0x13, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x34, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, - 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x56, - 0x0a, 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, - 0x6b, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x33, 0x48, 0x00, 0x52, - 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x32, 0x48, 0x00, 0x52, 0x16, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x41, 0x75, 0x74, 0x68, 0x50, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x12, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x56, 0x32, 0x48, 0x00, 0x52, 0x12, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x41, 0x75, 0x64, + 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x04, 0x4c, 0x6f, 0x63, 0x6b, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4c, + 0x6f, 0x63, 0x6b, 0x56, 0x32, 0x48, 0x00, 0x52, 0x04, 0x4c, 0x6f, 0x63, 0x6b, 0x12, 0x50, 0x0a, + 0x13, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x56, 0x34, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x56, 0x0a, 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, + 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, - 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x57, 0x69, 0x6e, 0x64, 0x6f, - 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x56, 0x33, 0x48, 0x00, - 0x52, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x41, 0x70, - 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, - 0x33, 0x48, 0x00, 0x52, 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x20, - 0x0a, 0x03, 0x41, 0x70, 0x70, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x03, 0x41, 0x70, 0x70, - 0x12, 0x41, 0x0a, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, - 0x00, 0x52, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x10, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, - 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x10, 0x4b, 0x75, 0x62, 0x65, - 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x11, - 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, - 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x56, 0x31, 0x48, - 0x00, 0x52, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0f, - 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, - 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x31, 0x48, - 0x00, 0x52, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x24, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x41, 0x4d, 0x4c, 0x49, - 0x64, 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x56, 0x31, 0x48, 0x00, 0x52, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x3d, 0x0a, - 0x0e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, - 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, - 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x53, 0x41, - 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x09, - 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, - 0x70, 0x56, 0x31, 0x48, 0x00, 0x52, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, - 0x12, 0x2f, 0x0a, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x27, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x49, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x56, 0x31, 0x48, 0x00, 0x52, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, - 0x75, 0x6c, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, 0x65, - 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x75, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, - 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, - 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x56, 0x31, 0x48, 0x00, 0x52, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, - 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0b, - 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x57, 0x0a, 0x16, 0x48, + 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x33, 0x48, 0x00, + 0x52, 0x15, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x57, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, + 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x0e, 0x57, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x56, 0x33, 0x48, + 0x00, 0x52, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x41, + 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x56, 0x33, 0x48, 0x00, 0x52, 0x09, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, + 0x20, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x41, 0x70, 0x70, 0x56, 0x33, 0x48, 0x00, 0x52, 0x03, 0x41, 0x70, + 0x70, 0x12, 0x41, 0x0a, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x57, 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, + 0x48, 0x00, 0x52, 0x10, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x10, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, + 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x10, 0x4b, 0x75, 0x62, + 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4a, 0x0a, + 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x56, 0x33, 0x48, 0x00, 0x52, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x65, 0x73, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x56, 0x31, + 0x48, 0x00, 0x52, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x44, 0x0a, + 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x56, 0x31, + 0x48, 0x00, 0x52, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x59, 0x0a, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x24, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x41, 0x4d, 0x4c, + 0x49, 0x64, 0x50, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x56, 0x31, 0x48, 0x00, 0x52, 0x16, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x3d, + 0x0a, 0x0e, 0x53, 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x57, + 0x65, 0x62, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x32, 0x48, 0x00, 0x52, 0x0e, 0x53, + 0x41, 0x4d, 0x4c, 0x49, 0x64, 0x50, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, + 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x56, 0x31, 0x48, 0x00, 0x52, 0x09, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, + 0x70, 0x12, 0x2f, 0x0a, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x27, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x49, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x56, 0x31, 0x48, 0x00, 0x52, 0x08, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x75, 0x6c, 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x75, 0x6c, + 0x65, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x49, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, + 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x73, + 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x31, 0x48, 0x00, 0x52, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x31, 0x48, 0x00, 0x52, + 0x0b, 0x57, 0x61, 0x74, 0x63, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x57, 0x0a, 0x16, + 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x16, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x16, 0x48, 0x65, - 0x61, 0x64, 0x6c, 0x65, 0x73, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, - 0x73, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x0e, 0x55, 0x73, - 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x2e, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, - 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, - 0x52, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, - 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x58, - 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x18, 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, - 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, - 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x48, 0x00, 0x52, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x38, - 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, - 0x52, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x47, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, + 0x69, 0x73, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, + 0x0a, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x0e, 0x55, + 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x2e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, + 0x73, 0x65, 0x72, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x0e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, - 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x48, 0x00, 0x52, 0x10, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, - 0x6d, 0x0a, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6d, - 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x7e, - 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, - 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x37, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6b, 0x75, - 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, - 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x48, 0x00, 0x52, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, - 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x55, - 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x39, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6c, - 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, - 0x65, 0x77, 0x65, 0x6c, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x0b, 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, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x48, 0x00, - 0x52, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x12, 0x4e, 0x0a, 0x0e, - 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x3b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, - 0x64, 0x62, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x46, 0x0a, 0x0b, - 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, 0x63, - 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x3d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6c, 0x75, - 0x73, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x48, 0x00, 0x52, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x53, 0x50, 0x49, 0x46, - 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x3e, 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, 0x48, 0x00, 0x52, 0x10, 0x53, - 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x56, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x41, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, - 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x53, 0x74, - 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x12, 0x3d, - 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x18, 0x43, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, - 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, - 0x6b, 0x48, 0x00, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x56, 0x0a, + 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, + 0x58, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x18, 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x44, 0x0a, 0x0a, 0x41, 0x75, 0x64, + 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x48, 0x00, 0x52, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x38, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x48, + 0x00, 0x52, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x47, 0x0a, 0x0b, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x73, 0x65, 0x63, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, + 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x48, 0x00, 0x52, 0x10, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x12, 0x6d, 0x0a, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, + 0x7e, 0x0a, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, + 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x37, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x3c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6b, + 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, + 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x48, 0x00, 0x52, 0x1a, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, + 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, + 0x55, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x39, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, + 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x12, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x4e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x44, 0x0a, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, + 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x0b, 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, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x48, + 0x00, 0x52, 0x0a, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x12, 0x4e, 0x0a, + 0x0e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x3b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x64, 0x62, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x46, 0x0a, + 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x3c, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x6d, 0x61, + 0x63, 0x68, 0x69, 0x6e, 0x65, 0x69, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x74, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x42, 0x6f, 0x74, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, + 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x3d, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x48, 0x00, 0x52, 0x13, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, + 0x68, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x53, 0x50, 0x49, + 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x3e, 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, 0x48, 0x00, 0x52, 0x10, + 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x46, 0x65, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x56, 0x0a, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x10, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x59, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x6f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x41, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, + 0x75, 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, + 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x11, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x5a, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x56, 0x32, 0x12, + 0x3d, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x18, 0x43, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x75, 0x73, 0x65, + 0x72, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, + 0x73, 0x6b, 0x48, 0x00, 0x52, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x56, + 0x0a, 0x15, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, + 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x18, 0x45, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x57, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x31, 0x48, 0x00, 0x52, 0x15, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, - 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x18, 0x45, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x57, 0x69, 0x6e, 0x64, - 0x6f, 0x77, 0x73, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x56, 0x31, 0x48, 0x00, 0x52, 0x15, - 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x44, 0x65, - 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x6a, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, - 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x69, 0x6e, 0x67, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x68, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x18, 0x47, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, 0x74, - 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, - 0x74, 0x48, 0x00, 0x52, 0x16, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, - 0x31, 0x10, 0x32, 0x4a, 0x04, 0x08, 0x3f, 0x10, 0x40, 0x4a, 0x04, 0x08, 0x44, 0x10, 0x45, 0x52, - 0x12, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x75, - 0x64, 0x69, 0x74, 0x52, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x13, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, - 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6c, 0x61, 0x6e, 0x2a, 0x2a, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x00, 0x12, - 0x07, 0x0a, 0x03, 0x50, 0x55, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, - 0x54, 0x45, 0x10, 0x02, 0x42, 0x34, 0x5a, 0x32, 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, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x12, 0x6a, 0x0a, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, + 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x1a, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x68, 0x0a, 0x16, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x18, 0x47, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x75, + 0x74, 0x6f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x6f, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, + 0x75, 0x74, 0x48, 0x00, 0x52, 0x16, 0x41, 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x6f, 0x75, 0x74, 0x12, 0x5b, 0x0a, 0x15, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x63, + 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x15, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x65, 0x6e, 0x74, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7f, 0x0a, 0x21, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x50, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x61, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x49, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x41, 0x73, 0x73, 0x69, 0x67, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x21, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, + 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x79, 0x0a, 0x1f, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x4a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x43, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x73, 0x73, 0x69, 0x67, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x31, 0x10, 0x32, 0x4a, 0x04, 0x08, + 0x3f, 0x10, 0x40, 0x4a, 0x04, 0x08, 0x44, 0x10, 0x45, 0x52, 0x12, 0x45, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x75, 0x64, 0x69, 0x74, 0x52, 0x0e, 0x53, + 0x74, 0x61, 0x74, 0x69, 0x63, 0x48, 0x6f, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x13, 0x41, + 0x75, 0x74, 0x6f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x6c, + 0x61, 0x6e, 0x2a, 0x2a, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x50, 0x55, 0x54, + 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x42, 0x34, + 0x5a, 0x32, 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, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1609,6 +1681,9 @@ var file_teleport_legacy_client_proto_event_proto_goTypes = []any{ (*types.DynamicWindowsDesktopV1)(nil), // 62: types.DynamicWindowsDesktopV1 (*v113.PrincipalState)(nil), // 63: teleport.provisioning.v1.PrincipalState (*v111.AutoUpdateAgentRollout)(nil), // 64: teleport.autoupdate.v1.AutoUpdateAgentRollout + (*v114.Account)(nil), // 65: teleport.identitycenter.v1.Account + (*v114.PrincipalAssignment)(nil), // 66: teleport.identitycenter.v1.PrincipalAssignment + (*v114.AccountAssignment)(nil), // 67: teleport.identitycenter.v1.AccountAssignment } var file_teleport_legacy_client_proto_event_proto_depIdxs = []int32{ 0, // 0: proto.Event.Type:type_name -> proto.Operation @@ -1678,11 +1753,14 @@ var file_teleport_legacy_client_proto_event_proto_depIdxs = []int32{ 62, // 64: proto.Event.DynamicWindowsDesktop:type_name -> types.DynamicWindowsDesktopV1 63, // 65: proto.Event.ProvisioningPrincipalState:type_name -> teleport.provisioning.v1.PrincipalState 64, // 66: proto.Event.AutoUpdateAgentRollout:type_name -> teleport.autoupdate.v1.AutoUpdateAgentRollout - 67, // [67:67] is the sub-list for method output_type - 67, // [67:67] is the sub-list for method input_type - 67, // [67:67] is the sub-list for extension type_name - 67, // [67:67] is the sub-list for extension extendee - 0, // [0:67] is the sub-list for field type_name + 65, // 67: proto.Event.IdentityCenterAccount:type_name -> teleport.identitycenter.v1.Account + 66, // 68: proto.Event.IdentityCenterPrincipalAssignment:type_name -> teleport.identitycenter.v1.PrincipalAssignment + 67, // 69: proto.Event.IdentityCenterAccountAssignment:type_name -> teleport.identitycenter.v1.AccountAssignment + 70, // [70:70] is the sub-list for method output_type + 70, // [70:70] is the sub-list for method input_type + 70, // [70:70] is the sub-list for extension type_name + 70, // [70:70] is the sub-list for extension extendee + 0, // [0:70] is the sub-list for field type_name } func init() { file_teleport_legacy_client_proto_event_proto_init() } @@ -1757,6 +1835,9 @@ func file_teleport_legacy_client_proto_event_proto_init() { (*Event_DynamicWindowsDesktop)(nil), (*Event_ProvisioningPrincipalState)(nil), (*Event_AutoUpdateAgentRollout)(nil), + (*Event_IdentityCenterAccount)(nil), + (*Event_IdentityCenterPrincipalAssignment)(nil), + (*Event_IdentityCenterAccountAssignment)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/api/proto/teleport/legacy/client/proto/event.proto b/api/proto/teleport/legacy/client/proto/event.proto index f88d95a926ac5..7c0cd043eb13d 100644 --- a/api/proto/teleport/legacy/client/proto/event.proto +++ b/api/proto/teleport/legacy/client/proto/event.proto @@ -23,6 +23,7 @@ import "teleport/clusterconfig/v1/access_graph_settings.proto"; import "teleport/crownjewel/v1/crownjewel.proto"; import "teleport/dbobject/v1/dbobject.proto"; import "teleport/discoveryconfig/v1/discoveryconfig.proto"; +import "teleport/identitycenter/v1/identitycenter.proto"; import "teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto"; import "teleport/legacy/types/types.proto"; import "teleport/machineid/v1/bot_instance.proto"; @@ -197,5 +198,13 @@ message Event { teleport.provisioning.v1.PrincipalState ProvisioningPrincipalState = 70; // AutoUpdateVersion is a resource for controlling the autoupdate agent rollout. teleport.autoupdate.v1.AutoUpdateAgentRollout AutoUpdateAgentRollout = 71; + // IdentityCenterAccount is a resource for tracking Identity Center accounts + teleport.identitycenter.v1.Account IdentityCenterAccount = 72; + // IdentityCenterPrincipalAssignment is a resource for tracking the AWS + // Permission Sets assigned to a Teleport user or AAccess List + teleport.identitycenter.v1.PrincipalAssignment IdentityCenterPrincipalAssignment = 73; + // IdentityCenterAccountlAssignment is a resource representing a potential + // Permission Set grant on a specific AWS account. + teleport.identitycenter.v1.AccountAssignment IdentityCenterAccountAssignment = 74; } } diff --git a/api/types/plugin.go b/api/types/plugin.go index 001b854c49e0f..535933d3017f2 100644 --- a/api/types/plugin.go +++ b/api/types/plugin.go @@ -520,7 +520,8 @@ func (p *PluginV1) GetType() PluginType { return PluginTypeSCIM case *PluginSpecV1_Datadog: return PluginTypeDatadog - + case *PluginSpecV1_AwsIc: + return PluginTypeAWSIdentityCenter default: return PluginTypeUnknown } diff --git a/lib/auth/accesspoint/accesspoint.go b/lib/auth/accesspoint/accesspoint.go index 3cf7c1d2e86aa..5b0d4b6084f07 100644 --- a/lib/auth/accesspoint/accesspoint.go +++ b/lib/auth/accesspoint/accesspoint.go @@ -202,6 +202,7 @@ func NewCache(cfg Config) (*cache.Cache, error) { WebToken: cfg.WebToken, WindowsDesktops: cfg.WindowsDesktops, ProvisioningStates: cfg.ProvisioningStates, + IdentityCenter: cfg.IdentityCenter, } return cache.New(cfg.Setup(cacheCfg)) diff --git a/lib/auth/auth.go b/lib/auth/auth.go index bea574ef75039..fa7ae3d46cca0 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -482,6 +482,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { SPIFFEFederations: cfg.SPIFFEFederations, StaticHostUser: cfg.StaticHostUsers, ProvisioningStates: cfg.ProvisioningStates, + IdentityCenter: cfg.IdentityCenter, } as := Server{ diff --git a/lib/cache/cache.go b/lib/cache/cache.go index 40c71ca1094e6..e9273cfb0e8a8 100644 --- a/lib/cache/cache.go +++ b/lib/cache/cache.go @@ -193,6 +193,9 @@ func ForAuth(cfg Config) Config { {Kind: types.KindAutoUpdateAgentRollout}, {Kind: types.KindUserTask}, {Kind: types.KindProvisioningPrincipalState}, + {Kind: types.KindIdentityCenterAccount}, + {Kind: types.KindIdentityCenterPrincipalAssignment}, + {Kind: types.KindIdentityCenterAccountAssignment}, } cfg.QueueSize = defaults.AuthQueueSize // We don't want to enable partial health for auth cache because auth uses an event stream @@ -544,6 +547,7 @@ type Cache struct { spiffeFederationCache spiffeFederationCacher staticHostUsersCache *local.StaticHostUserService provisioningStatesCache *local.ProvisioningStateService + identityCenterCache *local.IdentityCenterService // closed indicates that the cache has been closed closed atomic.Bool @@ -775,6 +779,9 @@ type Config struct { // ProvisioningStates is the upstream ProvisioningStates service that we're // caching ProvisioningStates services.ProvisioningStates + + // IdentityCenter is the upstream Identity Center service that we're caching + IdentityCenter services.IdentityCenter } // CheckAndSetDefaults checks parameters and sets default values @@ -1007,6 +1014,13 @@ func New(config Config) (*Cache, error) { return nil, trace.Wrap(err) } + identityCenterCache, err := local.NewIdentityCenterService(local.IdentityCenterServiceConfig{ + Backend: config.Backend}) + if err != nil { + cancel() + return nil, trace.Wrap(err) + } + cs := &Cache{ ctx: ctx, cancel: cancel, @@ -1053,6 +1067,7 @@ func New(config Config) (*Cache, error) { spiffeFederationCache: spiffeFederationCache, staticHostUsersCache: staticHostUserCache, provisioningStatesCache: provisioningStatesCache, + identityCenterCache: identityCenterCache, Logger: log.WithFields(log.Fields{ teleport.ComponentKey: config.Component, }), diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index 1139a68ecaeb4..9c11b4f3a1145 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -139,6 +139,7 @@ type testPack struct { staticHostUsers services.StaticHostUser autoUpdateService services.AutoUpdateService provisioningStates services.ProvisioningStates + identityCenter services.IdentityCenter } // testFuncs are functions to support testing an object in a cache. @@ -387,6 +388,13 @@ func newPackWithoutCache(dir string, opts ...packOption) (*testPack, error) { return nil, trace.Wrap(err) } + p.identityCenter, err = local.NewIdentityCenterService(local.IdentityCenterServiceConfig{ + Backend: p.backend, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return p, nil } @@ -438,6 +446,7 @@ func newPack(dir string, setupConfig func(c Config) Config, opts ...packOption) StaticHostUsers: p.staticHostUsers, AutoUpdateService: p.autoUpdateService, ProvisioningStates: p.provisioningStates, + IdentityCenter: p.identityCenter, MaxRetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, })) @@ -848,6 +857,7 @@ func TestCompletenessInit(t *testing.T) { AutoUpdateService: p.autoUpdateService, ProvisioningStates: p.provisioningStates, MaxRetryPeriod: 200 * time.Millisecond, + IdentityCenter: p.identityCenter, EventsC: p.eventsC, })) require.NoError(t, err) @@ -929,6 +939,7 @@ func TestCompletenessReset(t *testing.T) { StaticHostUsers: p.staticHostUsers, AutoUpdateService: p.autoUpdateService, ProvisioningStates: p.provisioningStates, + IdentityCenter: p.identityCenter, MaxRetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, })) @@ -1137,6 +1148,7 @@ func TestListResources_NodesTTLVariant(t *testing.T) { StaticHostUsers: p.staticHostUsers, AutoUpdateService: p.autoUpdateService, ProvisioningStates: p.provisioningStates, + IdentityCenter: p.identityCenter, MaxRetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, neverOK: true, // ensure reads are never healthy @@ -1230,6 +1242,7 @@ func initStrategy(t *testing.T) { StaticHostUsers: p.staticHostUsers, AutoUpdateService: p.autoUpdateService, ProvisioningStates: p.provisioningStates, + IdentityCenter: p.identityCenter, MaxRetryPeriod: 200 * time.Millisecond, EventsC: p.eventsC, })) @@ -3002,7 +3015,7 @@ func testResources153[T types.Resource153](t *testing.T, p *testPack, funcs test } assert.Empty(collect, cmp.Diff(expected, out, cmpOpts...)) - }, 2*time.Second, 250*time.Millisecond) + }, 2*time.Second, 10*time.Millisecond) } // Check that the resource is now in the backend. @@ -3426,71 +3439,74 @@ func TestCacheWatchKindExistsInEvents(t *testing.T) { } events := map[string]types.Resource{ - types.KindCertAuthority: &types.CertAuthorityV2{}, - types.KindClusterName: &types.ClusterNameV2{}, - types.KindClusterAuditConfig: types.DefaultClusterAuditConfig(), - types.KindClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(), - types.KindClusterAuthPreference: types.DefaultAuthPreference(), - types.KindSessionRecordingConfig: types.DefaultSessionRecordingConfig(), - types.KindUIConfig: &types.UIConfigV1{}, - types.KindStaticTokens: &types.StaticTokensV2{}, - types.KindToken: &types.ProvisionTokenV2{}, - types.KindUser: &types.UserV2{}, - types.KindRole: &types.RoleV6{Version: types.V4}, - types.KindNamespace: &types.Namespace{}, - types.KindNode: &types.ServerV2{}, - types.KindProxy: &types.ServerV2{}, - types.KindAuthServer: &types.ServerV2{}, - types.KindReverseTunnel: &types.ReverseTunnelV2{}, - types.KindTunnelConnection: &types.TunnelConnectionV2{}, - types.KindAccessRequest: &types.AccessRequestV3{}, - types.KindAppServer: &types.AppServerV3{}, - types.KindApp: &types.AppV3{}, - types.KindWebSession: &types.WebSessionV2{SubKind: types.KindWebSession}, - types.KindAppSession: &types.WebSessionV2{SubKind: types.KindAppSession}, - types.KindSnowflakeSession: &types.WebSessionV2{SubKind: types.KindSnowflakeSession}, - types.KindSAMLIdPSession: &types.WebSessionV2{SubKind: types.KindSAMLIdPServiceProvider}, - types.KindWebToken: &types.WebTokenV3{}, - types.KindRemoteCluster: &types.RemoteClusterV3{}, - types.KindKubeServer: &types.KubernetesServerV3{}, - types.KindDatabaseService: &types.DatabaseServiceV1{}, - types.KindDatabaseServer: &types.DatabaseServerV3{}, - types.KindDatabase: &types.DatabaseV3{}, - types.KindNetworkRestrictions: &types.NetworkRestrictionsV4{}, - types.KindLock: &types.LockV2{}, - types.KindWindowsDesktopService: &types.WindowsDesktopServiceV3{}, - types.KindWindowsDesktop: &types.WindowsDesktopV3{}, - types.KindDynamicWindowsDesktop: &types.DynamicWindowsDesktopV1{}, - types.KindInstaller: &types.InstallerV1{}, - types.KindKubernetesCluster: &types.KubernetesClusterV3{}, - types.KindSAMLIdPServiceProvider: &types.SAMLIdPServiceProviderV1{}, - types.KindUserGroup: &types.UserGroupV1{}, - types.KindOktaImportRule: &types.OktaImportRuleV1{}, - types.KindOktaAssignment: &types.OktaAssignmentV1{}, - types.KindIntegration: &types.IntegrationV1{}, - types.KindDiscoveryConfig: newDiscoveryConfig(t, "discovery-config"), - types.KindHeadlessAuthentication: &types.HeadlessAuthentication{}, - types.KindUserLoginState: newUserLoginState(t, "user-login-state"), - types.KindAuditQuery: newAuditQuery(t, "audit-query"), - types.KindSecurityReport: newSecurityReport(t, "security-report"), - types.KindSecurityReportState: newSecurityReport(t, "security-report-state"), - types.KindAccessList: newAccessList(t, "access-list", clock), - types.KindAccessListMember: newAccessListMember(t, "access-list", "member"), - types.KindAccessListReview: newAccessListReview(t, "access-list", "review"), - types.KindKubeWaitingContainer: newKubeWaitingContainer(t), - types.KindNotification: types.Resource153ToLegacy(newUserNotification(t, "test")), - types.KindGlobalNotification: types.Resource153ToLegacy(newGlobalNotification(t, "test")), - types.KindAccessMonitoringRule: types.Resource153ToLegacy(newAccessMonitoringRule(t)), - types.KindCrownJewel: types.Resource153ToLegacy(newCrownJewel(t, "test")), - types.KindDatabaseObject: types.Resource153ToLegacy(newDatabaseObject(t, "test")), - types.KindAccessGraphSettings: types.Resource153ToLegacy(newAccessGraphSettings(t)), - types.KindSPIFFEFederation: types.Resource153ToLegacy(newSPIFFEFederation("test")), - types.KindStaticHostUser: types.Resource153ToLegacy(newStaticHostUser(t, "test")), - types.KindAutoUpdateConfig: types.Resource153ToLegacy(newAutoUpdateConfig(t)), - types.KindAutoUpdateVersion: types.Resource153ToLegacy(newAutoUpdateVersion(t)), - types.KindAutoUpdateAgentRollout: types.Resource153ToLegacy(newAutoUpdateAgentRollout(t)), - types.KindUserTask: types.Resource153ToLegacy(newUserTasks(t)), - types.KindProvisioningPrincipalState: types.Resource153ToLegacy(newProvisioningPrincipalState("u-alice@example.com")), + types.KindCertAuthority: &types.CertAuthorityV2{}, + types.KindClusterName: &types.ClusterNameV2{}, + types.KindClusterAuditConfig: types.DefaultClusterAuditConfig(), + types.KindClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(), + types.KindClusterAuthPreference: types.DefaultAuthPreference(), + types.KindSessionRecordingConfig: types.DefaultSessionRecordingConfig(), + types.KindUIConfig: &types.UIConfigV1{}, + types.KindStaticTokens: &types.StaticTokensV2{}, + types.KindToken: &types.ProvisionTokenV2{}, + types.KindUser: &types.UserV2{}, + types.KindRole: &types.RoleV6{Version: types.V4}, + types.KindNamespace: &types.Namespace{}, + types.KindNode: &types.ServerV2{}, + types.KindProxy: &types.ServerV2{}, + types.KindAuthServer: &types.ServerV2{}, + types.KindReverseTunnel: &types.ReverseTunnelV2{}, + types.KindTunnelConnection: &types.TunnelConnectionV2{}, + types.KindAccessRequest: &types.AccessRequestV3{}, + types.KindAppServer: &types.AppServerV3{}, + types.KindApp: &types.AppV3{}, + types.KindWebSession: &types.WebSessionV2{SubKind: types.KindWebSession}, + types.KindAppSession: &types.WebSessionV2{SubKind: types.KindAppSession}, + types.KindSnowflakeSession: &types.WebSessionV2{SubKind: types.KindSnowflakeSession}, + types.KindSAMLIdPSession: &types.WebSessionV2{SubKind: types.KindSAMLIdPServiceProvider}, + types.KindWebToken: &types.WebTokenV3{}, + types.KindRemoteCluster: &types.RemoteClusterV3{}, + types.KindKubeServer: &types.KubernetesServerV3{}, + types.KindDatabaseService: &types.DatabaseServiceV1{}, + types.KindDatabaseServer: &types.DatabaseServerV3{}, + types.KindDatabase: &types.DatabaseV3{}, + types.KindNetworkRestrictions: &types.NetworkRestrictionsV4{}, + types.KindLock: &types.LockV2{}, + types.KindWindowsDesktopService: &types.WindowsDesktopServiceV3{}, + types.KindWindowsDesktop: &types.WindowsDesktopV3{}, + types.KindDynamicWindowsDesktop: &types.DynamicWindowsDesktopV1{}, + types.KindInstaller: &types.InstallerV1{}, + types.KindKubernetesCluster: &types.KubernetesClusterV3{}, + types.KindSAMLIdPServiceProvider: &types.SAMLIdPServiceProviderV1{}, + types.KindUserGroup: &types.UserGroupV1{}, + types.KindOktaImportRule: &types.OktaImportRuleV1{}, + types.KindOktaAssignment: &types.OktaAssignmentV1{}, + types.KindIntegration: &types.IntegrationV1{}, + types.KindDiscoveryConfig: newDiscoveryConfig(t, "discovery-config"), + types.KindHeadlessAuthentication: &types.HeadlessAuthentication{}, + types.KindUserLoginState: newUserLoginState(t, "user-login-state"), + types.KindAuditQuery: newAuditQuery(t, "audit-query"), + types.KindSecurityReport: newSecurityReport(t, "security-report"), + types.KindSecurityReportState: newSecurityReport(t, "security-report-state"), + types.KindAccessList: newAccessList(t, "access-list", clock), + types.KindAccessListMember: newAccessListMember(t, "access-list", "member"), + types.KindAccessListReview: newAccessListReview(t, "access-list", "review"), + types.KindKubeWaitingContainer: newKubeWaitingContainer(t), + types.KindNotification: types.Resource153ToLegacy(newUserNotification(t, "test")), + types.KindGlobalNotification: types.Resource153ToLegacy(newGlobalNotification(t, "test")), + types.KindAccessMonitoringRule: types.Resource153ToLegacy(newAccessMonitoringRule(t)), + types.KindCrownJewel: types.Resource153ToLegacy(newCrownJewel(t, "test")), + types.KindDatabaseObject: types.Resource153ToLegacy(newDatabaseObject(t, "test")), + types.KindAccessGraphSettings: types.Resource153ToLegacy(newAccessGraphSettings(t)), + types.KindSPIFFEFederation: types.Resource153ToLegacy(newSPIFFEFederation("test")), + types.KindStaticHostUser: types.Resource153ToLegacy(newStaticHostUser(t, "test")), + types.KindAutoUpdateConfig: types.Resource153ToLegacy(newAutoUpdateConfig(t)), + types.KindAutoUpdateVersion: types.Resource153ToLegacy(newAutoUpdateVersion(t)), + types.KindAutoUpdateAgentRollout: types.Resource153ToLegacy(newAutoUpdateAgentRollout(t)), + types.KindUserTask: types.Resource153ToLegacy(newUserTasks(t)), + types.KindProvisioningPrincipalState: types.Resource153ToLegacy(newProvisioningPrincipalState("u-alice@example.com")), + types.KindIdentityCenterAccount: types.Resource153ToLegacy(newIdentityCenterAccount("some_account")), + types.KindIdentityCenterAccountAssignment: types.Resource153ToLegacy(newIdentityCenterAccountAssignment("some_account_assignment")), + types.KindIdentityCenterPrincipalAssignment: types.Resource153ToLegacy(newIdentityCenterPrincipalAssignment("some_principal_assignment")), } for name, cfg := range cases { diff --git a/lib/cache/collections.go b/lib/cache/collections.go index 130cfd303c23f..17c28934a32c3 100644 --- a/lib/cache/collections.go +++ b/lib/cache/collections.go @@ -33,6 +33,7 @@ import ( clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1" crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1" dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1" + identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1" machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1" notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1" @@ -94,104 +95,6 @@ type executor[T any, R any] interface { // noReader is returned by getReader for resources which aren't directly used by the cache, and therefore have no associated reader. type noReader struct{} -// genericCollection is a generic collection implementation for resource type T with collection-specific logic -// encapsulated in executor type E. Type R provides getter methods related to the collection, e.g. GetNodes(), -// GetRoles(). -type genericCollection[T any, R any, E executor[T, R]] struct { - cache *Cache - watch types.WatchKind - exec E -} - -// fetch implements collection -func (g *genericCollection[T, R, _]) fetch(ctx context.Context, cacheOK bool) (apply func(ctx context.Context) error, err error) { - // Singleton objects will only get deleted or updated, not both - deleteSingleton := false - - var resources []T - if cacheOK { - resources, err = g.exec.getAll(ctx, g.cache, g.watch.LoadSecrets) - if err != nil { - if !trace.IsNotFound(err) { - return nil, trace.Wrap(err) - } - deleteSingleton = true - } - } - - return func(ctx context.Context) error { - // Always perform the delete if this is not a singleton, otherwise - // only perform the delete if the singleton wasn't found - // or the resource kind isn't cached in the current generation. - if !g.exec.isSingleton() || deleteSingleton || !cacheOK { - if err := g.exec.deleteAll(ctx, g.cache); err != nil { - if !trace.IsNotFound(err) { - return trace.Wrap(err) - } - } - } - // If this is a singleton and we performed a deletion, return here - // because we only want to update or delete a singleton, not both. - // Also don't continue if the resource kind isn't cached in the current generation. - if g.exec.isSingleton() && deleteSingleton || !cacheOK { - return nil - } - for _, resource := range resources { - if err := g.exec.upsert(ctx, g.cache, resource); err != nil { - return trace.Wrap(err) - } - } - return nil - }, nil -} - -// processEvent implements collection -func (g *genericCollection[T, R, _]) processEvent(ctx context.Context, event types.Event) error { - switch event.Type { - case types.OpDelete: - if err := g.exec.delete(ctx, g.cache, event.Resource); err != nil { - if !trace.IsNotFound(err) { - g.cache.Logger.WithError(err).Warn("Failed to delete resource.") - return trace.Wrap(err) - } - } - case types.OpPut: - var resource T - var ok bool - switch r := event.Resource.(type) { - case types.Resource153Unwrapper: - resource, ok = r.Unwrap().(T) - default: - resource, ok = event.Resource.(T) - } - if !ok { - return trace.BadParameter("unexpected type %T", event.Resource) - } - - if err := g.exec.upsert(ctx, g.cache, resource); err != nil { - return trace.Wrap(err) - } - default: - g.cache.Logger.WithField("event", event.Type).Warn("Skipping unsupported event type.") - } - return nil -} - -// watchKind implements collection -func (g *genericCollection[T, R, _]) watchKind() types.WatchKind { - return g.watch -} - -var _ collection = (*genericCollection[types.Resource, any, executor[types.Resource, any]])(nil) - -// genericCollection obtains the reader object from the executor based on the provided health status of the cache. -// Note that cacheOK set to true means that cache is overall healthy and the collection was confirmed as supported. -func (c *genericCollection[T, R, _]) getReader(cacheOK bool) R { - return c.exec.getReader(c.cache, cacheOK) -} - -var _ collectionReader[any] = (*genericCollection[types.Resource, any, executor[types.Resource, any]])(nil) - type crownjewelsGetter interface { ListCrownJewels(ctx context.Context, pageSize int64, nextToken string) ([]*crownjewelv1.CrownJewel, string, error) GetCrownJewel(ctx context.Context, name string) (*crownjewelv1.CrownJewel, error) @@ -208,68 +111,71 @@ type cacheCollections struct { // byKind is a map of registered collections by resource Kind/SubKind byKind map[resourceKind]collection - auditQueries collectionReader[services.SecurityAuditQueryGetter] - secReports collectionReader[services.SecurityReportGetter] - secReportsStates collectionReader[services.SecurityReportStateGetter] - accessLists collectionReader[accessListsGetter] - accessListMembers collectionReader[accessListMembersGetter] - accessListReviews collectionReader[accessListReviewsGetter] - apps collectionReader[services.AppGetter] - nodes collectionReader[nodeGetter] - tunnelConnections collectionReader[tunnelConnectionGetter] - appSessions collectionReader[appSessionGetter] - appServers collectionReader[appServerGetter] - authPreferences collectionReader[authPreferenceGetter] - authServers collectionReader[authServerGetter] - certAuthorities collectionReader[services.AuthorityGetter] - clusterAuditConfigs collectionReader[clusterAuditConfigGetter] - clusterNames collectionReader[clusterNameGetter] - clusterNetworkingConfigs collectionReader[clusterNetworkingConfigGetter] - databases collectionReader[services.DatabaseGetter] - databaseObjects collectionReader[services.DatabaseObjectsGetter] - databaseServers collectionReader[databaseServerGetter] - discoveryConfigs collectionReader[services.DiscoveryConfigsGetter] - installers collectionReader[installerGetter] - integrations collectionReader[services.IntegrationsGetter] - userTasks collectionReader[userTasksGetter] - crownJewels collectionReader[crownjewelsGetter] - kubeClusters collectionReader[kubernetesClusterGetter] - kubeWaitingContainers collectionReader[kubernetesWaitingContainerGetter] - staticHostUsers collectionReader[staticHostUserGetter] - kubeServers collectionReader[kubeServerGetter] - locks collectionReader[services.LockGetter] - namespaces collectionReader[namespaceGetter] - networkRestrictions collectionReader[networkRestrictionGetter] - oktaAssignments collectionReader[oktaAssignmentGetter] - oktaImportRules collectionReader[oktaImportRuleGetter] - proxies collectionReader[services.ProxyGetter] - remoteClusters collectionReader[remoteClusterGetter] - reverseTunnels collectionReader[reverseTunnelGetter] - roles collectionReader[roleGetter] - samlIdPServiceProviders collectionReader[samlIdPServiceProviderGetter] - samlIdPSessions collectionReader[samlIdPSessionGetter] - sessionRecordingConfigs collectionReader[sessionRecordingConfigGetter] - snowflakeSessions collectionReader[snowflakeSessionGetter] - staticTokens collectionReader[staticTokensGetter] - tokens collectionReader[tokenGetter] - uiConfigs collectionReader[uiConfigGetter] - users collectionReader[userGetter] - userGroups collectionReader[userGroupGetter] - userLoginStates collectionReader[services.UserLoginStatesGetter] - webSessions collectionReader[webSessionGetter] - webTokens collectionReader[webTokenGetter] - windowsDesktops collectionReader[windowsDesktopsGetter] - dynamicWindowsDesktops collectionReader[dynamicWindowsDesktopsGetter] - windowsDesktopServices collectionReader[windowsDesktopServiceGetter] - userNotifications collectionReader[notificationGetter] - accessGraphSettings collectionReader[accessGraphSettingsGetter] - globalNotifications collectionReader[notificationGetter] - accessMonitoringRules collectionReader[accessMonitoringRuleGetter] - spiffeFederations collectionReader[SPIFFEFederationReader] - autoUpdateConfigs collectionReader[autoUpdateConfigGetter] - autoUpdateVersions collectionReader[autoUpdateVersionGetter] - autoUpdateAgentRollouts collectionReader[autoUpdateAgentRolloutGetter] - provisioningStates collectionReader[provisioningStateGetter] + auditQueries collectionReader[services.SecurityAuditQueryGetter] + secReports collectionReader[services.SecurityReportGetter] + secReportsStates collectionReader[services.SecurityReportStateGetter] + accessLists collectionReader[accessListsGetter] + accessListMembers collectionReader[accessListMembersGetter] + accessListReviews collectionReader[accessListReviewsGetter] + apps collectionReader[services.AppGetter] + nodes collectionReader[nodeGetter] + tunnelConnections collectionReader[tunnelConnectionGetter] + appSessions collectionReader[appSessionGetter] + appServers collectionReader[appServerGetter] + authPreferences collectionReader[authPreferenceGetter] + authServers collectionReader[authServerGetter] + certAuthorities collectionReader[services.AuthorityGetter] + clusterAuditConfigs collectionReader[clusterAuditConfigGetter] + clusterNames collectionReader[clusterNameGetter] + clusterNetworkingConfigs collectionReader[clusterNetworkingConfigGetter] + databases collectionReader[services.DatabaseGetter] + databaseObjects collectionReader[services.DatabaseObjectsGetter] + databaseServers collectionReader[databaseServerGetter] + discoveryConfigs collectionReader[services.DiscoveryConfigsGetter] + installers collectionReader[installerGetter] + integrations collectionReader[services.IntegrationsGetter] + userTasks collectionReader[userTasksGetter] + crownJewels collectionReader[crownjewelsGetter] + kubeClusters collectionReader[kubernetesClusterGetter] + kubeWaitingContainers collectionReader[kubernetesWaitingContainerGetter] + staticHostUsers collectionReader[staticHostUserGetter] + kubeServers collectionReader[kubeServerGetter] + locks collectionReader[services.LockGetter] + namespaces collectionReader[namespaceGetter] + networkRestrictions collectionReader[networkRestrictionGetter] + oktaAssignments collectionReader[oktaAssignmentGetter] + oktaImportRules collectionReader[oktaImportRuleGetter] + proxies collectionReader[services.ProxyGetter] + remoteClusters collectionReader[remoteClusterGetter] + reverseTunnels collectionReader[reverseTunnelGetter] + roles collectionReader[roleGetter] + samlIdPServiceProviders collectionReader[samlIdPServiceProviderGetter] + samlIdPSessions collectionReader[samlIdPSessionGetter] + sessionRecordingConfigs collectionReader[sessionRecordingConfigGetter] + snowflakeSessions collectionReader[snowflakeSessionGetter] + staticTokens collectionReader[staticTokensGetter] + tokens collectionReader[tokenGetter] + uiConfigs collectionReader[uiConfigGetter] + users collectionReader[userGetter] + userGroups collectionReader[userGroupGetter] + userLoginStates collectionReader[services.UserLoginStatesGetter] + webSessions collectionReader[webSessionGetter] + webTokens collectionReader[webTokenGetter] + windowsDesktops collectionReader[windowsDesktopsGetter] + dynamicWindowsDesktops collectionReader[dynamicWindowsDesktopsGetter] + windowsDesktopServices collectionReader[windowsDesktopServiceGetter] + userNotifications collectionReader[notificationGetter] + accessGraphSettings collectionReader[accessGraphSettingsGetter] + globalNotifications collectionReader[notificationGetter] + accessMonitoringRules collectionReader[accessMonitoringRuleGetter] + spiffeFederations collectionReader[SPIFFEFederationReader] + autoUpdateConfigs collectionReader[autoUpdateConfigGetter] + autoUpdateVersions collectionReader[autoUpdateVersionGetter] + autoUpdateAgentRollouts collectionReader[autoUpdateAgentRolloutGetter] + provisioningStates collectionReader[provisioningStateGetter] + identityCenterAccounts collectionReader[identityCenterAccountGetter] + identityCenterPrincipalAssignments collectionReader[identityCenterPrincipalAssignmentGetter] + identityCenterAccountAssignments collectionReader[identityCenterAccountAssignmentGetter] } // setupCollections returns a registry of collections. @@ -836,6 +742,48 @@ func setupCollections(c *Cache, watches []types.WatchKind) (*cacheCollections, e } collections.byKind[resourceKind] = collections.provisioningStates + case types.KindIdentityCenterAccount: + if c.IdentityCenter == nil { + return nil, trace.BadParameter("missing upstream IdentityCenter collection") + } + collections.identityCenterAccounts = &genericCollection[ + services.IdentityCenterAccount, + identityCenterAccountGetter, + identityCenterAccountExecutor, + ]{ + cache: c, + watch: watch, + } + collections.byKind[resourceKind] = collections.identityCenterAccounts + + case types.KindIdentityCenterPrincipalAssignment: + if c.IdentityCenter == nil { + return nil, trace.BadParameter("missing parameter IdentityCenter") + } + collections.identityCenterPrincipalAssignments = &genericCollection[ + *identitycenterv1.PrincipalAssignment, + identityCenterPrincipalAssignmentGetter, + identityCenterPrincipalAssignmentExecutor, + ]{ + cache: c, + watch: watch, + } + collections.byKind[resourceKind] = collections.identityCenterPrincipalAssignments + + case types.KindIdentityCenterAccountAssignment: + if c.IdentityCenter == nil { + return nil, trace.BadParameter("missing parameter IdentityCenter") + } + collections.identityCenterAccountAssignments = &genericCollection[ + services.IdentityCenterAccountAssignment, + identityCenterAccountAssignmentGetter, + identityCenterAccountAssignmentExecutor, + ]{ + cache: c, + watch: watch, + } + collections.byKind[resourceKind] = collections.identityCenterAccountAssignments + default: return nil, trace.BadParameter("resource %q is not supported", watch.Kind) } diff --git a/lib/cache/genericcollection.go b/lib/cache/genericcollection.go new file mode 100644 index 0000000000000..ac0260da844d9 --- /dev/null +++ b/lib/cache/genericcollection.go @@ -0,0 +1,128 @@ +// 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 cache + +import ( + "context" + + "github.com/gravitational/trace" + + "github.com/gravitational/teleport/api/types" +) + +// genericCollection is a generic collection implementation for resource type T with collection-specific logic +// encapsulated in executor type E. Type R provides getter methods related to the collection, e.g. GetNodes(), +// GetRoles(). +type genericCollection[T any, R any, E executor[T, R]] struct { + cache *Cache + watch types.WatchKind + exec E +} + +// fetch implements collection +func (g *genericCollection[T, R, _]) fetch(ctx context.Context, cacheOK bool) (apply func(ctx context.Context) error, err error) { + // Singleton objects will only get deleted or updated, not both + deleteSingleton := false + + var resources []T + if cacheOK { + resources, err = g.exec.getAll(ctx, g.cache, g.watch.LoadSecrets) + if err != nil { + if !trace.IsNotFound(err) { + return nil, trace.Wrap(err) + } + deleteSingleton = true + } + } + + return func(ctx context.Context) error { + // Always perform the delete if this is not a singleton, otherwise + // only perform the delete if the singleton wasn't found + // or the resource kind isn't cached in the current generation. + if !g.exec.isSingleton() || deleteSingleton || !cacheOK { + if err := g.exec.deleteAll(ctx, g.cache); err != nil { + if !trace.IsNotFound(err) { + return trace.Wrap(err) + } + } + } + // If this is a singleton and we performed a deletion, return here + // because we only want to update or delete a singleton, not both. + // Also don't continue if the resource kind isn't cached in the current generation. + if g.exec.isSingleton() && deleteSingleton || !cacheOK { + return nil + } + for _, resource := range resources { + if err := g.exec.upsert(ctx, g.cache, resource); err != nil { + return trace.Wrap(err) + } + } + return nil + }, nil +} + +// processEvent implements collection +func (g *genericCollection[T, R, _]) processEvent(ctx context.Context, event types.Event) error { + switch event.Type { + case types.OpDelete: + if err := g.exec.delete(ctx, g.cache, event.Resource); err != nil { + if !trace.IsNotFound(err) { + g.cache.Logger.WithError(err).Warn("Failed to delete resource.") + return trace.Wrap(err) + } + } + case types.OpPut: + var resource T + var ok bool + switch r := event.Resource.(type) { + case types.Resource153Unwrapper: + resource, ok = r.Unwrap().(T) + if !ok { + return trace.BadParameter("unexpected wrapped type %T (expected %T)", r.Unwrap(), resource) + } + + default: + resource, ok = event.Resource.(T) + } + + if !ok { + return trace.BadParameter("unexpected type %T (expected %T)", event.Resource, resource) + } + + if err := g.exec.upsert(ctx, g.cache, resource); err != nil { + return trace.Wrap(err) + } + default: + g.cache.Logger.WithField("event", event.Type).Warn("Skipping unsupported event type.") + } + return nil +} + +// watchKind implements collection +func (g *genericCollection[T, R, _]) watchKind() types.WatchKind { + return g.watch +} + +var _ collection = (*genericCollection[types.Resource, any, executor[types.Resource, any]])(nil) + +// genericCollection obtains the reader object from the executor based on the provided health status of the cache. +// Note that cacheOK set to true means that cache is overall healthy and the collection was confirmed as supported. +func (c *genericCollection[T, R, _]) getReader(cacheOK bool) R { + return c.exec.getReader(c.cache, cacheOK) +} + +var _ collectionReader[any] = (*genericCollection[types.Resource, any, executor[types.Resource, any]])(nil) diff --git a/lib/cache/identitycenter.go b/lib/cache/identitycenter.go new file mode 100644 index 0000000000000..1b431cba57da2 --- /dev/null +++ b/lib/cache/identitycenter.go @@ -0,0 +1,196 @@ +// 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 cache + +import ( + "context" + + "github.com/gravitational/trace" + + identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/utils/pagination" +) + +type identityCenterAccountGetter interface { + GetIdentityCenterAccount(context.Context, services.IdentityCenterAccountID) (services.IdentityCenterAccount, error) + ListIdentityCenterAccounts(context.Context, int, *pagination.PageRequestToken) ([]services.IdentityCenterAccount, pagination.NextPageToken, error) +} + +type identityCenterAccountExecutor struct{} + +func (identityCenterAccountExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]services.IdentityCenterAccount, error) { + var pageToken pagination.PageRequestToken + var resources []services.IdentityCenterAccount + for { + resourcesPage, nextPage, err := cache.IdentityCenter.ListIdentityCenterAccounts(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + + resources = append(resources, resourcesPage...) + + if nextPage == pagination.EndOfList { + break + } + pageToken.Update(nextPage) + } + return resources, nil +} + +func (identityCenterAccountExecutor) upsert(ctx context.Context, cache *Cache, resource services.IdentityCenterAccount) error { + _, err := cache.identityCenterCache.UpsertIdentityCenterAccount(ctx, resource) + return trace.Wrap(err) +} + +func (identityCenterAccountExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { + return trace.Wrap(cache.identityCenterCache.DeleteIdentityCenterAccount(ctx, + services.IdentityCenterAccountID(resource.GetName()))) +} + +func (identityCenterAccountExecutor) deleteAll(ctx context.Context, cache *Cache) error { + return trace.Wrap(cache.identityCenterCache.DeleteAllIdentityCenterAccounts(ctx)) +} + +func (identityCenterAccountExecutor) getReader(cache *Cache, cacheOK bool) identityCenterAccountGetter { + if cacheOK { + return cache.identityCenterCache + } + return cache.Config.IdentityCenter +} + +func (identityCenterAccountExecutor) isSingleton() bool { + return false +} + +var _ executor[ + services.IdentityCenterAccount, + identityCenterAccountGetter, +] = identityCenterAccountExecutor{} + +type identityCenterPrincipalAssignmentGetter interface { + GetPrincipalAssignment(context.Context, services.PrincipalAssignmentID) (*identitycenterv1.PrincipalAssignment, error) + ListPrincipalAssignments(context.Context, int, *pagination.PageRequestToken) ([]*identitycenterv1.PrincipalAssignment, pagination.NextPageToken, error) +} + +type identityCenterPrincipalAssignmentExecutor struct{} + +var _ executor[ + *identitycenterv1.PrincipalAssignment, + identityCenterPrincipalAssignmentGetter, +] = identityCenterPrincipalAssignmentExecutor{} + +func (identityCenterPrincipalAssignmentExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]*identitycenterv1.PrincipalAssignment, error) { + var pageToken pagination.PageRequestToken + var resources []*identitycenterv1.PrincipalAssignment + for { + resourcesPage, nextPage, err := cache.IdentityCenter.ListPrincipalAssignments(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + + resources = append(resources, resourcesPage...) + + if nextPage == pagination.EndOfList { + break + } + pageToken.Update(nextPage) + } + return resources, nil +} + +func (identityCenterPrincipalAssignmentExecutor) upsert(ctx context.Context, cache *Cache, resource *identitycenterv1.PrincipalAssignment) error { + _, err := cache.identityCenterCache.UpsertPrincipalAssignment(ctx, resource) + return trace.Wrap(err) +} + +func (identityCenterPrincipalAssignmentExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { + return trace.Wrap(cache.identityCenterCache.DeletePrincipalAssignment(ctx, + services.PrincipalAssignmentID(resource.GetName()))) +} + +func (identityCenterPrincipalAssignmentExecutor) deleteAll(ctx context.Context, cache *Cache) error { + return trace.Wrap(cache.identityCenterCache.DeleteAllPrincipalAssignments(ctx)) +} + +func (identityCenterPrincipalAssignmentExecutor) getReader(cache *Cache, cacheOK bool) identityCenterPrincipalAssignmentGetter { + if cacheOK { + return cache.identityCenterCache + } + return cache.Config.IdentityCenter +} + +func (identityCenterPrincipalAssignmentExecutor) isSingleton() bool { + return false +} + +type identityCenterAccountAssignmentGetter interface { + GetAccountAssignment(context.Context, services.IdentityCenterAccountAssignmentID) (services.IdentityCenterAccountAssignment, error) + ListAccountAssignments(context.Context, int, *pagination.PageRequestToken) ([]services.IdentityCenterAccountAssignment, pagination.NextPageToken, error) +} + +type identityCenterAccountAssignmentExecutor struct{} + +func (identityCenterAccountAssignmentExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]services.IdentityCenterAccountAssignment, error) { + var pageToken pagination.PageRequestToken + var resources []services.IdentityCenterAccountAssignment + for { + resourcesPage, nextPage, err := cache.IdentityCenter.ListAccountAssignments(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + + resources = append(resources, resourcesPage...) + + if nextPage == pagination.EndOfList { + break + } + pageToken.Update(nextPage) + } + return resources, nil +} + +func (identityCenterAccountAssignmentExecutor) upsert(ctx context.Context, cache *Cache, resource services.IdentityCenterAccountAssignment) error { + _, err := cache.identityCenterCache.UpsertAccountAssignment(ctx, resource) + return trace.Wrap(err) +} + +func (identityCenterAccountAssignmentExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { + return trace.Wrap(cache.identityCenterCache.DeleteAccountAssignment(ctx, + services.IdentityCenterAccountAssignmentID(resource.GetName()))) +} + +func (identityCenterAccountAssignmentExecutor) deleteAll(ctx context.Context, cache *Cache) error { + return trace.Wrap(cache.identityCenterCache.DeleteAllIdentityCenterAccounts(ctx)) +} + +func (identityCenterAccountAssignmentExecutor) getReader(cache *Cache, cacheOK bool) identityCenterAccountAssignmentGetter { + if cacheOK { + return cache.identityCenterCache + } + return cache.Config.IdentityCenter +} + +func (identityCenterAccountAssignmentExecutor) isSingleton() bool { + return false +} + +var _ executor[ + services.IdentityCenterAccountAssignment, + identityCenterAccountAssignmentGetter, +] = identityCenterAccountAssignmentExecutor{} diff --git a/lib/cache/identitycenter_test.go b/lib/cache/identitycenter_test.go new file mode 100644 index 0000000000000..c312d778aeafa --- /dev/null +++ b/lib/cache/identitycenter_test.go @@ -0,0 +1,263 @@ +// 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 cache + +import ( + "context" + "log/slog" + "os" + "testing" + + "github.com/gravitational/trace" + + headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/services" + logutils "github.com/gravitational/teleport/lib/utils/log" + "github.com/gravitational/teleport/lib/utils/pagination" +) + +func newIdentityCenterAccount(id string) *identitycenterv1.Account { + return &identitycenterv1.Account{ + Kind: types.KindIdentityCenterAccount, + SubKind: "", + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: id, + }, + Spec: &identitycenterv1.AccountSpec{ + Id: id, + Arn: "arn:aws:sso:::permissionSet/ssoins-722326ecc902a06a/" + id, + }, + Status: &identitycenterv1.AccountStatus{}, + } +} + +// TestIdentityCenterAccount asserts that an Identoty Ceneter Account can be cached +func TestIdentityCenterAccount(t *testing.T) { + slog.SetDefault( + slog.New(logutils.NewSlogTextHandler( + os.Stderr, logutils.SlogTextHandlerConfig{Level: slog.LevelDebug}))) + + t.Parallel() + + fixturePack := newTestPack(t, ForAuth) + t.Cleanup(fixturePack.Close) + + collect := func(ctx context.Context, src identityCenterAccountGetter) ([]services.IdentityCenterAccount, error) { + var result []services.IdentityCenterAccount + var pageToken pagination.PageRequestToken + for { + page, nextPage, err := src.ListIdentityCenterAccounts(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + result = append(result, page...) + + if nextPage == pagination.EndOfList { + break + } + + pageToken.Update(nextPage) + } + return result, nil + } + + testResources153(t, fixturePack, testFuncs153[services.IdentityCenterAccount]{ + newResource: func(s string) (services.IdentityCenterAccount, error) { + return services.IdentityCenterAccount{Account: newIdentityCenterAccount(s)}, nil + }, + create: func(ctx context.Context, item services.IdentityCenterAccount) error { + _, err := fixturePack.identityCenter.CreateIdentityCenterAccount(ctx, item) + return trace.Wrap(err) + }, + update: func(ctx context.Context, item services.IdentityCenterAccount) error { + _, err := fixturePack.identityCenter.UpdateIdentityCenterAccount(ctx, item) + return trace.Wrap(err) + }, + list: func(ctx context.Context) ([]services.IdentityCenterAccount, error) { + return collect(ctx, fixturePack.identityCenter) + }, + delete: func(ctx context.Context, id string) error { + return trace.Wrap(fixturePack.identityCenter.DeleteIdentityCenterAccount( + ctx, services.IdentityCenterAccountID(id))) + }, + deleteAll: func(ctx context.Context) error { + return trace.Wrap(fixturePack.identityCenter.DeleteAllIdentityCenterAccounts(ctx)) + }, + cacheList: func(ctx context.Context) ([]services.IdentityCenterAccount, error) { + return collect(ctx, fixturePack.cache.identityCenterCache) + }, + cacheGet: func(ctx context.Context, id string) (services.IdentityCenterAccount, error) { + r, err := fixturePack.cache.identityCenterCache.GetIdentityCenterAccount( + ctx, services.IdentityCenterAccountID(id)) + return r, trace.Wrap(err) + }, + }) +} + +func newIdentityCenterPrincipalAssignment(id string) *identitycenterv1.PrincipalAssignment { + return &identitycenterv1.PrincipalAssignment{ + Kind: types.KindIdentityCenterPrincipalAssignment, + SubKind: "", + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: id, + }, + Spec: &identitycenterv1.PrincipalAssignmentSpec{ + PrincipalType: identitycenterv1.PrincipalType_PRINCIPAL_TYPE_USER, + PrincipalId: id, + ExternalId: "ext_" + id, + }, + Status: &identitycenterv1.PrincipalAssignmentStatus{ + ProvisioningState: identitycenterv1.ProvisioningState_PROVISIONING_STATE_PROVISIONED, + }, + } +} + +// TestIdentityCenterPrincpialAssignment asserts that an Identity Center PrincipalAssignment can be cached +func TestIdentityCenterPrincipalAssignment(t *testing.T) { + fixturePack := newTestPack(t, ForAuth) + t.Cleanup(fixturePack.Close) + + collect := func(ctx context.Context, src identityCenterPrincipalAssignmentGetter) ([]*identitycenterv1.PrincipalAssignment, error) { + var result []*identitycenterv1.PrincipalAssignment + var pageToken pagination.PageRequestToken + for { + page, nextPage, err := src.ListPrincipalAssignments(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + result = append(result, page...) + + if nextPage == pagination.EndOfList { + break + } + + pageToken.Update(nextPage) + } + return result, nil + } + + testResources153(t, fixturePack, testFuncs153[*identitycenterv1.PrincipalAssignment]{ + newResource: func(s string) (*identitycenterv1.PrincipalAssignment, error) { + return newIdentityCenterPrincipalAssignment(s), nil + }, + create: func(ctx context.Context, item *identitycenterv1.PrincipalAssignment) error { + _, err := fixturePack.identityCenter.CreatePrincipalAssignment(ctx, item) + return trace.Wrap(err) + }, + update: func(ctx context.Context, item *identitycenterv1.PrincipalAssignment) error { + _, err := fixturePack.identityCenter.UpdatePrincipalAssignment(ctx, item) + return trace.Wrap(err) + }, + list: func(ctx context.Context) ([]*identitycenterv1.PrincipalAssignment, error) { + return collect(ctx, fixturePack.identityCenter) + }, + delete: func(ctx context.Context, id string) error { + return trace.Wrap(fixturePack.identityCenter.DeletePrincipalAssignment(ctx, services.PrincipalAssignmentID(id))) + }, + deleteAll: func(ctx context.Context) error { + return trace.Wrap(fixturePack.identityCenter.DeleteAllPrincipalAssignments(ctx)) + }, + cacheList: func(ctx context.Context) ([]*identitycenterv1.PrincipalAssignment, error) { + return collect(ctx, fixturePack.cache.identityCenterCache) + }, + cacheGet: func(ctx context.Context, id string) (*identitycenterv1.PrincipalAssignment, error) { + r, err := fixturePack.cache.identityCenterCache.GetPrincipalAssignment( + ctx, services.PrincipalAssignmentID(id)) + return r, trace.Wrap(err) + }, + }) +} + +func newIdentityCenterAccountAssignment(id string) *identitycenterv1.AccountAssignment { + return &identitycenterv1.AccountAssignment{ + Kind: types.KindIdentityCenterAccountAssignment, + SubKind: "", + Version: types.V1, + Metadata: &headerv1.Metadata{ + Name: id, + }, + Spec: &identitycenterv1.AccountAssignmentSpec{ + Display: "account " + id, + PermissionSet: &identitycenterv1.PermissionSetInfo{}, + AccountName: id, + AccountId: id, + }, + } +} + +// TestIdentityCenterAccountAssignment asserts that an Identity Center +// AccountAssignment can be cached +func TestIdentityCenterAccountAssignment(t *testing.T) { + fixturePack := newTestPack(t, ForAuth) + t.Cleanup(fixturePack.Close) + + collect := func(ctx context.Context, src identityCenterAccountAssignmentGetter) ([]services.IdentityCenterAccountAssignment, error) { + var result []services.IdentityCenterAccountAssignment + var pageToken pagination.PageRequestToken + for { + page, nextPage, err := src.ListAccountAssignments(ctx, 0, &pageToken) + if err != nil { + return nil, trace.Wrap(err) + } + result = append(result, page...) + + if nextPage == pagination.EndOfList { + break + } + + pageToken.Update(nextPage) + } + return result, nil + } + + testResources153(t, fixturePack, testFuncs153[services.IdentityCenterAccountAssignment]{ + newResource: func(s string) (services.IdentityCenterAccountAssignment, error) { + return services.IdentityCenterAccountAssignment{ + AccountAssignment: newIdentityCenterAccountAssignment(s), + }, nil + }, + create: func(ctx context.Context, item services.IdentityCenterAccountAssignment) error { + _, err := fixturePack.identityCenter.CreateAccountAssignment(ctx, item) + return trace.Wrap(err) + }, + update: func(ctx context.Context, item services.IdentityCenterAccountAssignment) error { + _, err := fixturePack.identityCenter.UpdateAccountAssignment(ctx, item) + return trace.Wrap(err) + }, + list: func(ctx context.Context) ([]services.IdentityCenterAccountAssignment, error) { + return collect(ctx, fixturePack.identityCenter) + }, + delete: func(ctx context.Context, id string) error { + return trace.Wrap(fixturePack.identityCenter.DeleteAccountAssignment(ctx, services.IdentityCenterAccountAssignmentID(id))) + }, + deleteAll: func(ctx context.Context) error { + return trace.Wrap(fixturePack.identityCenter.DeleteAllAccountAssignments(ctx)) + }, + cacheList: func(ctx context.Context) ([]services.IdentityCenterAccountAssignment, error) { + return collect(ctx, fixturePack.cache.identityCenterCache) + }, + cacheGet: func(ctx context.Context, id string) (services.IdentityCenterAccountAssignment, error) { + r, err := fixturePack.cache.identityCenterCache.GetAccountAssignment( + ctx, services.IdentityCenterAccountAssignmentID(id)) + return r, trace.Wrap(err) + }, + }) +} diff --git a/lib/service/service.go b/lib/service/service.go index 01e4fdad21224..c171bb74ca301 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -2531,6 +2531,7 @@ func (process *TeleportProcess) newAccessCacheForServices(cfg accesspoint.Config cfg.WindowsDesktops = services.WindowsDesktops cfg.AutoUpdateService = services.AutoUpdateService cfg.ProvisioningStates = services.ProvisioningStates + cfg.IdentityCenter = services.IdentityCenter return accesspoint.NewCache(cfg) } diff --git a/lib/services/identitycenter.go b/lib/services/identitycenter.go index d3fbf6aca9756..e256ab9941025 100644 --- a/lib/services/identitycenter.go +++ b/lib/services/identitycenter.go @@ -204,6 +204,10 @@ type IdentityCenterAccountAssignments interface { // Account Assignment, returning the updated record on success. UpdateAccountAssignment(context.Context, IdentityCenterAccountAssignment) (IdentityCenterAccountAssignment, error) + // UpsertAccountAssignment performs an unconditional update on the supplied + // Account Assignment, returning the updated record on success. + UpsertAccountAssignment(context.Context, IdentityCenterAccountAssignment) (IdentityCenterAccountAssignment, error) + // DeleteAccountAssignment deletes a specific account assignment DeleteAccountAssignment(context.Context, IdentityCenterAccountAssignmentID) error diff --git a/lib/services/local/events.go b/lib/services/local/events.go index 09084857dbf06..2f1c9854da9cd 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -242,6 +242,12 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type parser = newStaticHostUserParser() case types.KindProvisioningPrincipalState: parser = newProvisioningStateParser() + case types.KindIdentityCenterAccount: + parser = newIdentityCenterAccountParser() + case types.KindIdentityCenterPrincipalAssignment: + parser = newIdentityCenterPrincipalAssignmentParser() + case types.KindIdentityCenterAccountAssignment: + parser = newIdentityCenterAccountAssignmentParser() default: if watch.AllowPartialSuccess { continue diff --git a/lib/services/local/identitycenter.go b/lib/services/local/identitycenter.go index a24e433ef3b84..10cdf7777e33b 100644 --- a/lib/services/local/identitycenter.go +++ b/lib/services/local/identitycenter.go @@ -388,6 +388,16 @@ func (svc *IdentityCenterService) UpdateAccountAssignment(ctx context.Context, a return services.IdentityCenterAccountAssignment{AccountAssignment: updated}, nil } +// UpsertAccountAssignment performs an unconditional upsert on the supplied +// Account Assignment, returning the updated record on success. +func (svc *IdentityCenterService) UpsertAccountAssignment(ctx context.Context, asmt services.IdentityCenterAccountAssignment) (services.IdentityCenterAccountAssignment, error) { + updated, err := svc.accountAssignments.UpsertResource(ctx, asmt.AccountAssignment) + if err != nil { + return services.IdentityCenterAccountAssignment{}, trace.Wrap(err, "upserting principal assignment record") + } + return services.IdentityCenterAccountAssignment{AccountAssignment: updated}, nil +} + // DeleteAccountAssignment deletes a specific account assignment func (svc *IdentityCenterService) DeleteAccountAssignment(ctx context.Context, name services.IdentityCenterAccountAssignmentID) error { return trace.Wrap(svc.accountAssignments.DeleteResource(ctx, string(name))) diff --git a/lib/services/local/identitycenter_events.go b/lib/services/local/identitycenter_events.go new file mode 100644 index 0000000000000..b8cc8933b200b --- /dev/null +++ b/lib/services/local/identitycenter_events.go @@ -0,0 +1,162 @@ +// 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 local + +import ( + "strings" + + "github.com/gravitational/trace" + + apidefaults "github.com/gravitational/teleport/api/defaults" + identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/backend" + "github.com/gravitational/teleport/lib/services" +) + +type identityCenterAccountParser struct { + baseParser + prefix backend.Key +} + +func newIdentityCenterAccountParser() *identityCenterAccountParser { + prefix := backend.NewKey(awsResourcePrefix, awsAccountPrefix) + return &identityCenterAccountParser{ + baseParser: newBaseParser(prefix), + prefix: prefix, + } +} + +func (p *identityCenterAccountParser) parse(event backend.Event) (types.Resource, error) { + switch event.Type { + case types.OpDelete: + name := event.Item.Key.TrimPrefix(p.prefix).String() + if name == "" { + return nil, trace.NotFound("failed parsing %v", event.Item.Key.String()) + } + return &types.ResourceHeader{ + Kind: types.KindIdentityCenterAccount, + Version: types.V1, + Metadata: types.Metadata{ + Name: strings.TrimPrefix(name, backend.SeparatorString), + Namespace: apidefaults.Namespace, + }, + }, nil + case types.OpPut: + r, err := services.UnmarshalProtoResource[*identitycenterv1.Account]( + event.Item.Value, + services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), + ) + if err != nil { + return nil, trace.Wrap(err) + } + return types.Resource153ToLegacy(services.IdentityCenterAccount{Account: r}), nil + default: + return nil, trace.BadParameter("event %v is not supported", event.Type) + } +} + +type identityCenterPrincipalAssignmentParser struct { + baseParser + prefix backend.Key +} + +func newIdentityCenterPrincipalAssignmentParser() *identityCenterPrincipalAssignmentParser { + prefix := backend.NewKey(awsResourcePrefix, awsPrincipalAssignmentPrefix) + return &identityCenterPrincipalAssignmentParser{ + baseParser: newBaseParser(prefix), + prefix: prefix, + } +} + +func (p *identityCenterPrincipalAssignmentParser) parse(event backend.Event) (types.Resource, error) { + switch event.Type { + case types.OpDelete: + name := event.Item.Key.TrimPrefix(p.prefix).String() + if name == "" { + return nil, trace.NotFound("failed parsing %v", event.Item.Key.String()) + } + return &types.ResourceHeader{ + Kind: types.KindIdentityCenterPrincipalAssignment, + Version: types.V1, + Metadata: types.Metadata{ + Name: strings.TrimPrefix(name, backend.SeparatorString), + Namespace: apidefaults.Namespace, + }, + }, nil + + case types.OpPut: + r, err := services.UnmarshalProtoResource[*identitycenterv1.PrincipalAssignment]( + event.Item.Value, + services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), + ) + if err != nil { + return nil, trace.Wrap(err) + } + return types.Resource153ToLegacy(r), nil + + default: + return nil, trace.BadParameter("event %v is not supported", event.Type) + } +} + +type identityCenterAccountAssignmentParser struct { + baseParser + prefix backend.Key +} + +func newIdentityCenterAccountAssignmentParser() *identityCenterAccountAssignmentParser { + prefix := backend.NewKey(awsResourcePrefix, awsAccountAssignmentPrefix) + return &identityCenterAccountAssignmentParser{ + baseParser: newBaseParser(prefix), + prefix: prefix, + } +} + +func (p *identityCenterAccountAssignmentParser) parse(event backend.Event) (types.Resource, error) { + switch event.Type { + case types.OpDelete: + name := event.Item.Key.TrimPrefix(p.prefix).String() + if name == "" { + return nil, trace.NotFound("failed parsing %v", event.Item.Key.String()) + } + return &types.ResourceHeader{ + Kind: types.KindIdentityCenterAccountAssignment, + Version: types.V1, + Metadata: types.Metadata{ + Name: strings.TrimPrefix(name, backend.SeparatorString), + Namespace: apidefaults.Namespace, + }, + }, nil + case types.OpPut: + r, err := services.UnmarshalProtoResource[*identitycenterv1.AccountAssignment]( + event.Item.Value, + services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), + ) + if err != nil { + return nil, trace.Wrap(err) + } + return types.Resource153ToLegacy( + services.IdentityCenterAccountAssignment{AccountAssignment: r}), + nil + default: + return nil, trace.BadParameter("event %v is not supported", event.Type) + } +} diff --git a/lib/services/local/identitycenter_test.go b/lib/services/local/identitycenter_test.go index a15c2a51f323b..b64a98eda5df6 100644 --- a/lib/services/local/identitycenter_test.go +++ b/lib/services/local/identitycenter_test.go @@ -100,6 +100,10 @@ func TestIdentityCenterResourceCRUD(t *testing.T) { asmt := r.(services.IdentityCenterAccountAssignment) return svc.UpdateAccountAssignment(subtestCtx, asmt) }, + upsertResource: func(subtestCtx context.Context, svc services.IdentityCenter, r types.Resource153) (types.Resource153, error) { + asmt := r.(services.IdentityCenterAccountAssignment) + return svc.UpsertAccountAssignment(subtestCtx, asmt) + }, }, { name: "PrincipalAssignment", From 0e3e4fc505116d4d3c6e6580dbaeae3386a6ff32 Mon Sep 17 00:00:00 2001 From: Grzegorz Zdunek Date: Mon, 28 Oct 2024 14:00:23 +0100 Subject: [PATCH 04/22] Fix `DataTable` pagination regression (#47990) * Fix `DataTable` navigation regression * Convert `setState` to a callback form --- .../design/src/DataTable/Table.test.tsx | 34 +++++++++++++++++++ web/packages/design/src/DataTable/useTable.ts | 24 ++++++------- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/web/packages/design/src/DataTable/Table.test.tsx b/web/packages/design/src/DataTable/Table.test.tsx index f53522f924c57..77ee038dbfb9d 100644 --- a/web/packages/design/src/DataTable/Table.test.tsx +++ b/web/packages/design/src/DataTable/Table.test.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import { render, fireEvent, screen } from 'design/utils/testing'; @@ -366,3 +367,36 @@ describe('sorting by iso date string', () => { expect(rows[2]).toHaveTextContent('a3'); }); }); + +test('navigate to next and previous pages', async () => { + render( + + ); + + let { rows } = getTableRows(); + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveTextContent(data[0].hostname); + expect(rows[1]).toHaveTextContent(data[1].hostname); + + await userEvent.click(screen.getByTitle('Next page')); + rows = getTableRows().rows; + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveTextContent(data[2].hostname); + expect(rows[1]).toHaveTextContent(data[3].hostname); + + await userEvent.click(screen.getByTitle('Previous page')); + rows = getTableRows().rows; + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveTextContent(data[0].hostname); + expect(rows[1]).toHaveTextContent(data[1].hostname); +}); diff --git a/web/packages/design/src/DataTable/useTable.ts b/web/packages/design/src/DataTable/useTable.ts index 7b7deda0af0e3..e8c70f3bd2dd0 100644 --- a/web/packages/design/src/DataTable/useTable.ts +++ b/web/packages/design/src/DataTable/useTable.ts @@ -185,30 +185,30 @@ export default function useTable({ if (serversideProps) { fetching?.onFetchNext?.(); } - setState({ - ...state, - pagination: state.pagination + setState(prevState => ({ + ...prevState, + pagination: prevState.pagination ? { - ...state.pagination, - currentPage: state.pagination.currentPage + 1, + ...prevState.pagination, + currentPage: prevState.pagination.currentPage + 1, } : undefined, - }); + })); } function prevPage() { if (serversideProps) { fetching?.onFetchPrev?.(); } - setState({ - ...state, - pagination: state.pagination + setState(prevState => ({ + ...prevState, + pagination: prevState.pagination ? { - ...state.pagination, - currentPage: state.pagination.currentPage + 1, + ...prevState.pagination, + currentPage: prevState.pagination.currentPage - 1, } : undefined, - }); + })); } useEffect(() => { From 6cb3df6866949bb9c8ef0c3038ee49b4acad3568 Mon Sep 17 00:00:00 2001 From: Steven Martin Date: Mon, 28 Oct 2024 09:14:21 -0400 Subject: [PATCH 05/22] docs: include directory sharing option in role specs (#47977) --- docs/pages/enroll-resources/desktop-access/rbac.mdx | 8 +++++++- docs/pages/includes/role-spec.mdx | 5 +++++ docs/pages/reference/access-controls/roles.mdx | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/pages/enroll-resources/desktop-access/rbac.mdx b/docs/pages/enroll-resources/desktop-access/rbac.mdx index f03ff9012b1e9..b6c27aaa34f40 100644 --- a/docs/pages/enroll-resources/desktop-access/rbac.mdx +++ b/docs/pages/enroll-resources/desktop-access/rbac.mdx @@ -11,7 +11,7 @@ desktop access: ```yaml kind: role -version: v4 +version: v5 metadata: name: developer spec: @@ -31,6 +31,12 @@ spec: # the clipboard, then it will be disabled. desktop_clipboard: true + # Specify whether directory sharing should be allowed from the + # local machine to remote desktop (requires a supported browser). Defaults to true + # if unspecified. If one or more of the user's roles has disabled + # directory sharing, then it will be disabled. + desktop_directory_sharing: true + # Specify whether local users should be created automatically at connection # time. By default, this feature is disabled, and the user must already exist. # Note: this is applicable to local users only and is not supported in Active diff --git a/docs/pages/includes/role-spec.mdx b/docs/pages/includes/role-spec.mdx index 77c15fd482c47..3030a255d21f0 100644 --- a/docs/pages/includes/role-spec.mdx +++ b/docs/pages/includes/role-spec.mdx @@ -88,6 +88,11 @@ spec: # if unspecified. If one or more of the user's roles has disabled # the clipboard, then it will be disabled. desktop_clipboard: true + # Specify whether directory sharing should be allowed from the + # local machine to remote desktop (requires a supported browser). Defaults to true + # if unspecified. If one or more of the user's roles has disabled + # directory sharing, then it will be disabled. + desktop_directory_sharing: true # enterprise-only: when enabled, the source IP that was used to log in is embedded in the user # certificates, preventing a compromised certificate from being used on another # network. The default is false. diff --git a/docs/pages/reference/access-controls/roles.mdx b/docs/pages/reference/access-controls/roles.mdx index 8975dc1896abd..2b17fd62d9189 100644 --- a/docs/pages/reference/access-controls/roles.mdx +++ b/docs/pages/reference/access-controls/roles.mdx @@ -68,6 +68,7 @@ user: | `max_kubernetes_connections` | Defines the maximum number of concurrent Kubernetes sessions per user | | | `record_session` |Defines the [Session recording mode](../monitoring/audit.mdx).|The strictest value takes precedence.| | `desktop_clipboard` | Allow clipboard sharing for desktop sessions | Logical "AND" i.e. evaluates to "yes" if all roles enable clipboard sharing | +| `desktop_directory_sharing` | Allows sharing local workstation directory to remote desktop | Logical "AND" i.e. evaluates to "yes" if all roles enable directory sharing | | `pin_source_ip` | Enable source IP pinning for SSH certificates. | Logical "OR" i.e. evaluates to "yes" if at least one role requires session termination | | `cert_extensions` | Specifies extensions to be included in SSH certificates | | | `create_host_user_mode` | Allow users to be automatically created on a host | Logical "AND" i.e. if all roles matching a server specify host user creation (`off`, `keep`, `insecure-drop`), it will evaluate to the option specified by all of the roles. If some roles specify both `insecure-drop` or `keep` it will evaluate to `keep`| From 3fe2c3df43d9ac6b559230badff5772a58d7f50f Mon Sep 17 00:00:00 2001 From: rosstimothy <39066650+rosstimothy@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:14:49 +0000 Subject: [PATCH 06/22] Update e (#47999) Includes https://github.com/gravitational/teleport.e/pull/5257 and updates e_imports.go to reflect that cfssl is no longer a direct dependency. --- e | 2 +- e_imports.go | 4 ++-- go.mod | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/e b/e index 03e3eb1845e67..84f36a00ae432 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 03e3eb1845e6780f764c5c8164dd55232714b6d4 +Subproject commit 84f36a00ae432a6d8b08d6b84dd56a4970402bcf diff --git a/e_imports.go b/e_imports.go index d2edd07def844..0934f476e1e07 100644 --- a/e_imports.go +++ b/e_imports.go @@ -61,7 +61,6 @@ import ( _ "github.com/aws/aws-sdk-go-v2/service/sts" _ "github.com/aws/aws-sdk-go-v2/service/sts/types" _ "github.com/beevik/etree" - _ "github.com/cloudflare/cfssl/csr" _ "github.com/coreos/go-oidc/jose" _ "github.com/coreos/go-oidc/oauth2" _ "github.com/coreos/go-oidc/oidc" @@ -80,7 +79,6 @@ import ( _ "github.com/google/safetext/shsprintf" _ "github.com/google/uuid" _ "github.com/gravitational/license" - _ "github.com/gravitational/license/authority" _ "github.com/gravitational/license/constants" _ "github.com/gravitational/license/generate" _ "github.com/gravitational/roundtrip" @@ -186,6 +184,7 @@ import ( _ "github.com/gravitational/teleport/api/types/accessgraph" _ "github.com/gravitational/teleport/api/types/accesslist" _ "github.com/gravitational/teleport/api/types/accesslist/convert/v1" + _ "github.com/gravitational/teleport/api/types/common" _ "github.com/gravitational/teleport/api/types/discoveryconfig" _ "github.com/gravitational/teleport/api/types/events" _ "github.com/gravitational/teleport/api/types/externalauditstorage" @@ -193,6 +192,7 @@ import ( _ "github.com/gravitational/teleport/api/types/header" _ "github.com/gravitational/teleport/api/types/header/convert/legacy" _ "github.com/gravitational/teleport/api/types/header/convert/v1" + _ "github.com/gravitational/teleport/api/types/samlsp" _ "github.com/gravitational/teleport/api/types/secreports" _ "github.com/gravitational/teleport/api/types/secreports/convert/v1" _ "github.com/gravitational/teleport/api/types/trait" diff --git a/go.mod b/go.mod index e338706f376e5..0775645a53dd4 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,6 @@ require ( github.com/charmbracelet/bubbles v0.20.0 github.com/charmbracelet/bubbletea v1.1.0 github.com/charmbracelet/lipgloss v0.13.0 - github.com/cloudflare/cfssl v1.6.4 github.com/coreos/go-oidc v2.2.1+incompatible // replaced github.com/coreos/go-semver v0.3.1 github.com/creack/pty v1.1.23 @@ -287,6 +286,7 @@ require ( github.com/chai2010/gettext-go v1.0.2 // indirect github.com/charmbracelet/x/ansi v0.2.3 // indirect github.com/charmbracelet/x/term v0.2.0 // indirect + github.com/cloudflare/cfssl v1.6.4 // indirect github.com/cncf/xds/go v0.0.0-20240822171458-6449f94b4d59 // indirect github.com/containerd/containerd v1.7.18 // indirect github.com/containerd/errdefs v0.1.0 // indirect From 6d205ba0c89fe830e5c6cdd212976e34d265a8c0 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Mon, 28 Oct 2024 08:31:57 -0600 Subject: [PATCH 07/22] Remove the original unpaginated GetRoles RPC (#47984) This was replaced with ListRoles, which implements pagination. --- api/client/client.go | 20 - api/client/proto/authservice.pb.go | 1968 ++++++++--------- .../legacy/client/proto/authservice.proto | 8 - 3 files changed, 941 insertions(+), 1055 deletions(-) diff --git a/api/client/client.go b/api/client/client.go index 86cf448bcbe77..ee1ea80087791 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -1782,11 +1782,6 @@ func (c *Client) GetRoles(ctx context.Context) ([]types.Role, error) { for { rsp, err := c.ListRoles(ctx, &req) if err != nil { - if trace.IsNotImplemented(err) { - // fallback to calling the old non-paginated role API. - roles, err = c.getRoles(ctx) - return roles, trace.Wrap(err) - } return nil, trace.Wrap(err) } @@ -1802,21 +1797,6 @@ func (c *Client) GetRoles(ctx context.Context) ([]types.Role, error) { return roles, nil } -// getRoles calls the old non-paginated GetRoles method. -// -// DELETE IN 17.0 -func (c *Client) getRoles(ctx context.Context) ([]types.Role, error) { - resp, err := c.grpc.GetRoles(ctx, &emptypb.Empty{}) - if err != nil { - return nil, trace.Wrap(err) - } - roles := make([]types.Role, 0, len(resp.GetRoles())) - for _, role := range resp.GetRoles() { - roles = append(roles, role) - } - return roles, nil -} - // ListRoles is a paginated role getter. func (c *Client) ListRoles(ctx context.Context, req *proto.ListRolesRequest) (*proto.ListRolesResponse, error) { var header gmetadata.MD diff --git a/api/client/proto/authservice.pb.go b/api/client/proto/authservice.pb.go index 3f66847c54fd5..bfd512d622ed5 100644 --- a/api/client/proto/authservice.pb.go +++ b/api/client/proto/authservice.pb.go @@ -15786,949 +15786,947 @@ func init() { } var fileDescriptor_0ffcffcda38ae159 = []byte{ - // 15058 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x59, 0x6c, 0x5c, 0xcb, - 0x76, 0x18, 0xca, 0xe6, 0xcc, 0xc5, 0x41, 0xad, 0x22, 0x29, 0xb6, 0xa8, 0xa1, 0xa5, 0xad, 0x33, - 0xe8, 0xe8, 0x9e, 0xab, 0x81, 0x67, 0xb8, 0x67, 0xba, 0xe7, 0x9c, 0xe6, 0x20, 0x91, 0x12, 0xa7, - 0xb3, 0x9b, 0xa4, 0xce, 0xe4, 0xdb, 0x77, 0xab, 0xbb, 0x44, 0x6e, 0xab, 0xb9, 0x77, 0xdf, 0xbd, - 0x77, 0x4b, 0x47, 0xd7, 0xcf, 0x7e, 0xb0, 0xfd, 0x06, 0xff, 0xbc, 0xf7, 0x6c, 0xe0, 0x3d, 0xc3, - 0x0f, 0xfe, 0xf0, 0x7b, 0x40, 0x02, 0x04, 0x01, 0x12, 0xe4, 0x27, 0xf0, 0x4f, 0xfc, 0x11, 0xe4, - 0x23, 0x37, 0x06, 0x82, 0x24, 0xb0, 0xfd, 0x13, 0x20, 0x74, 0x72, 0x01, 0xff, 0x10, 0xc9, 0x87, - 0x11, 0x24, 0x40, 0x2e, 0x60, 0x20, 0xa8, 0x55, 0xc3, 0xae, 0xda, 0x53, 0x93, 0x3a, 0x3a, 0xd7, - 0xf9, 0x91, 0xd8, 0xab, 0xd6, 0x5a, 0x55, 0xb5, 0xaa, 0x76, 0xd5, 0xaa, 0x55, 0xab, 0xd6, 0x82, - 0x9b, 0x11, 0x6d, 0xd3, 0x8e, 0x1f, 0x44, 0xb7, 0xda, 0x74, 0xdf, 0x69, 0x3e, 0xbf, 0xd5, 0x6c, - 0xbb, 0xd4, 0x8b, 0x6e, 0x75, 0x02, 0x3f, 0xf2, 0x6f, 0x39, 0xdd, 0xe8, 0x20, 0xa4, 0xc1, 0x53, - 0xb7, 0x49, 0x6f, 0x22, 0x84, 0x0c, 0xe1, 0x7f, 0xf3, 0x33, 0xfb, 0xfe, 0xbe, 0xcf, 0x71, 0xd8, - 0x5f, 0xbc, 0x70, 0xfe, 0xc2, 0xbe, 0xef, 0xef, 0xb7, 0x29, 0x27, 0x7e, 0xd4, 0x7d, 0x7c, 0x8b, - 0x1e, 0x76, 0xa2, 0xe7, 0xa2, 0xb0, 0x9a, 0x2c, 0x8c, 0xdc, 0x43, 0x1a, 0x46, 0xce, 0x61, 0x47, - 0x20, 0xbc, 0xa1, 0x9a, 0xe2, 0x44, 0x11, 0x2b, 0x89, 0x5c, 0xdf, 0xbb, 0xf5, 0xf4, 0x8e, 0xfe, - 0x53, 0xa0, 0x5e, 0x2f, 0x6c, 0x75, 0x93, 0x06, 0x51, 0x78, 0x22, 0x4c, 0xfa, 0x94, 0x7a, 0x51, - 0xaa, 0x7a, 0x81, 0x19, 0x3d, 0xef, 0xd0, 0x90, 0xa3, 0xc8, 0xff, 0x04, 0xea, 0xd5, 0x6c, 0x54, - 0xfc, 0x57, 0xa0, 0x7c, 0x3f, 0x1b, 0xe5, 0x19, 0x7d, 0xc4, 0x64, 0xea, 0xa9, 0x3f, 0x7a, 0xa0, - 0x07, 0x4e, 0xa7, 0x43, 0x83, 0xf8, 0x0f, 0x81, 0x7e, 0x5e, 0xa1, 0x1f, 0x3e, 0x76, 0x98, 0x88, - 0x0e, 0x1f, 0x3b, 0xa9, 0x6e, 0x74, 0x43, 0x67, 0x9f, 0x8a, 0xe6, 0x3f, 0xbd, 0xa3, 0xff, 0xe4, - 0xa8, 0xd6, 0x1f, 0x95, 0x60, 0xe8, 0xa1, 0x13, 0x35, 0x0f, 0xc8, 0x27, 0x30, 0xf4, 0xc0, 0xf5, - 0x5a, 0x61, 0xa5, 0x74, 0x65, 0xe0, 0xfa, 0xf8, 0x42, 0xf9, 0x26, 0xef, 0x0a, 0x16, 0xb2, 0x82, - 0xc5, 0xb9, 0x9f, 0x1d, 0x55, 0xfb, 0x8e, 0x8f, 0xaa, 0x67, 0x9e, 0x30, 0xb4, 0x37, 0xfd, 0x43, - 0x37, 0xc2, 0xb1, 0xb5, 0x39, 0x1d, 0xd9, 0x85, 0xe9, 0x5a, 0xbb, 0xed, 0x3f, 0xdb, 0x76, 0x82, - 0xc8, 0x75, 0xda, 0xf5, 0x6e, 0xb3, 0x49, 0xc3, 0xb0, 0xd2, 0x7f, 0xa5, 0x74, 0x7d, 0x74, 0xf1, - 0xda, 0xf1, 0x51, 0xb5, 0xea, 0xb0, 0xe2, 0x46, 0x87, 0x97, 0x37, 0x42, 0x8e, 0xa0, 0x31, 0xca, - 0xa2, 0xb7, 0xfe, 0x74, 0x18, 0xca, 0xab, 0x7e, 0x18, 0x2d, 0xb1, 0x11, 0xb5, 0xe9, 0x4f, 0xba, - 0x34, 0x8c, 0xc8, 0x35, 0x18, 0x66, 0xb0, 0xb5, 0xe5, 0x4a, 0xe9, 0x4a, 0xe9, 0xfa, 0xd8, 0xe2, - 0xf8, 0xf1, 0x51, 0x75, 0xe4, 0xc0, 0x0f, 0xa3, 0x86, 0xdb, 0xb2, 0x45, 0x11, 0x79, 0x03, 0x46, - 0x37, 0xfd, 0x16, 0xdd, 0x74, 0x0e, 0x29, 0xb6, 0x62, 0x6c, 0x71, 0xf2, 0xf8, 0xa8, 0x3a, 0xe6, - 0xf9, 0x2d, 0xda, 0xf0, 0x9c, 0x43, 0x6a, 0xab, 0x62, 0xb2, 0x07, 0x83, 0xb6, 0xdf, 0xa6, 0x95, - 0x01, 0x44, 0x5b, 0x3c, 0x3e, 0xaa, 0x0e, 0x06, 0x7e, 0x9b, 0xfe, 0xe2, 0xa8, 0xfa, 0xee, 0xbe, - 0x1b, 0x1d, 0x74, 0x1f, 0xdd, 0x6c, 0xfa, 0x87, 0xb7, 0xf6, 0x03, 0xe7, 0xa9, 0xcb, 0x27, 0xa1, - 0xd3, 0xbe, 0x15, 0x4f, 0xd5, 0x8e, 0x2b, 0xc6, 0xbd, 0xfe, 0x3c, 0x8c, 0xe8, 0x21, 0xe3, 0x64, - 0x23, 0x3f, 0xf2, 0x10, 0x66, 0x6a, 0xad, 0x96, 0xcb, 0x29, 0xb6, 0x03, 0xd7, 0x6b, 0xba, 0x1d, - 0xa7, 0x1d, 0x56, 0x06, 0xaf, 0x0c, 0x5c, 0x1f, 0x13, 0x42, 0x51, 0xe5, 0x8d, 0x8e, 0x42, 0xd0, - 0x84, 0x92, 0xc9, 0x80, 0xbc, 0x05, 0xa3, 0xcb, 0x9b, 0x75, 0xd6, 0xf6, 0xb0, 0x32, 0x84, 0xcc, - 0xe6, 0x8e, 0x8f, 0xaa, 0xd3, 0x2d, 0x2f, 0xc4, 0xae, 0xe9, 0x0c, 0x14, 0x22, 0x79, 0x17, 0x26, - 0xb6, 0xbb, 0x8f, 0xda, 0x6e, 0x73, 0x67, 0xbd, 0xfe, 0x80, 0x3e, 0xaf, 0x0c, 0x5f, 0x29, 0x5d, - 0x9f, 0x58, 0x24, 0xc7, 0x47, 0xd5, 0xa9, 0x0e, 0xc2, 0x1b, 0x51, 0x3b, 0x6c, 0x3c, 0xa1, 0xcf, - 0x6d, 0x03, 0x2f, 0xa6, 0xab, 0xd7, 0x57, 0x19, 0xdd, 0x48, 0x8a, 0x2e, 0x0c, 0x0f, 0x74, 0x3a, - 0x8e, 0x47, 0x6e, 0x01, 0xd8, 0xf4, 0xd0, 0x8f, 0x68, 0xad, 0xd5, 0x0a, 0x2a, 0xa3, 0x28, 0xdb, - 0x33, 0xc7, 0x47, 0xd5, 0xf1, 0x00, 0xa1, 0x0d, 0xa7, 0xd5, 0x0a, 0x6c, 0x0d, 0x85, 0x2c, 0xc1, - 0xa8, 0xed, 0x73, 0x01, 0x57, 0xc6, 0xae, 0x94, 0xae, 0x8f, 0x2f, 0x9c, 0x11, 0xd3, 0x50, 0x82, - 0x17, 0xcf, 0x1d, 0x1f, 0x55, 0x49, 0x20, 0x7e, 0xe9, 0xbd, 0x94, 0x18, 0xa4, 0x0a, 0x23, 0x9b, - 0xfe, 0x92, 0xd3, 0x3c, 0xa0, 0x15, 0xc0, 0xb9, 0x37, 0x74, 0x7c, 0x54, 0x2d, 0x7d, 0xdf, 0x96, - 0x50, 0xf2, 0x14, 0xc6, 0xe3, 0x81, 0x0a, 0x2b, 0xe3, 0x28, 0xbe, 0x9d, 0xe3, 0xa3, 0xea, 0xb9, - 0x10, 0xc1, 0x0d, 0x36, 0xf4, 0x9a, 0x04, 0xbf, 0xc5, 0x2c, 0xd0, 0x2b, 0x22, 0x5f, 0xc3, 0x6c, - 0xfc, 0xb3, 0x16, 0x86, 0x34, 0x60, 0x3c, 0xd6, 0x96, 0x2b, 0x93, 0x28, 0x99, 0xd7, 0x8e, 0x8f, - 0xaa, 0x96, 0xd6, 0x82, 0x86, 0x23, 0x51, 0x1a, 0x6e, 0x4b, 0xeb, 0x69, 0x36, 0x93, 0xfb, 0x83, - 0xa3, 0x13, 0xe5, 0x49, 0xfb, 0xd2, 0xae, 0x17, 0x46, 0xce, 0xa3, 0x36, 0xcd, 0x44, 0xb2, 0xfe, - 0xa6, 0x04, 0x64, 0xab, 0x43, 0xbd, 0x7a, 0x7d, 0x95, 0x7d, 0x4f, 0xf2, 0x73, 0x7a, 0x13, 0xc6, - 0xf8, 0xc0, 0xb1, 0xd1, 0xed, 0xc7, 0xd1, 0x9d, 0x3a, 0x3e, 0xaa, 0x82, 0x18, 0x5d, 0x36, 0xb2, - 0x31, 0x02, 0x79, 0x15, 0x06, 0x76, 0x76, 0xd6, 0xf1, 0x5b, 0x19, 0x58, 0x9c, 0x3e, 0x3e, 0xaa, - 0x0e, 0x44, 0x51, 0xfb, 0x17, 0x47, 0xd5, 0xd1, 0xe5, 0x6e, 0x80, 0x62, 0xb1, 0x59, 0x39, 0x79, - 0x15, 0x46, 0x96, 0xda, 0xdd, 0x30, 0xa2, 0x41, 0x65, 0x30, 0xfe, 0x48, 0x9b, 0x1c, 0x64, 0xcb, - 0x32, 0xf2, 0x3d, 0x18, 0xdc, 0x0d, 0x69, 0x50, 0x19, 0xc2, 0xf1, 0x9e, 0x14, 0xe3, 0xcd, 0x40, - 0x7b, 0x0b, 0x8b, 0xa3, 0xec, 0x4b, 0xec, 0x86, 0x34, 0xb0, 0x11, 0x89, 0xdc, 0x84, 0x21, 0x3e, - 0x68, 0xc3, 0xb8, 0x48, 0x4d, 0xaa, 0xd9, 0xd1, 0xa6, 0x7b, 0xef, 0x2e, 0x8e, 0x1d, 0x1f, 0x55, - 0x87, 0x70, 0xf0, 0x6c, 0x8e, 0x76, 0x7f, 0x70, 0xb4, 0x54, 0xee, 0xb7, 0x47, 0x19, 0x2d, 0xfb, - 0x2c, 0xac, 0xef, 0xc1, 0xb8, 0xd6, 0x7d, 0x72, 0x11, 0x06, 0xd9, 0xff, 0xb8, 0x88, 0x4c, 0xf0, - 0xca, 0xd8, 0xc6, 0x61, 0x23, 0xd4, 0xfa, 0xff, 0xa6, 0xa1, 0xcc, 0x28, 0x8d, 0x95, 0xe7, 0xa6, - 0x2e, 0x2a, 0x4e, 0x57, 0x36, 0x45, 0x55, 0x29, 0xe9, 0xc2, 0xba, 0x0e, 0xaa, 0x76, 0xb1, 0x08, - 0x4d, 0x1c, 0x1f, 0x55, 0x47, 0xbb, 0x02, 0x16, 0xb7, 0x8d, 0xd4, 0x61, 0x64, 0xe5, 0x9b, 0x8e, - 0x1b, 0xd0, 0x10, 0x45, 0x3b, 0xbe, 0x30, 0x7f, 0x93, 0x6f, 0x97, 0x37, 0xe5, 0x76, 0x79, 0x73, - 0x47, 0x6e, 0x97, 0x8b, 0x97, 0xc4, 0x62, 0x7c, 0x96, 0x72, 0x92, 0x78, 0x7e, 0xfc, 0xee, 0x5f, - 0x56, 0x4b, 0xb6, 0xe4, 0x44, 0xde, 0x84, 0xe1, 0xbb, 0x7e, 0x70, 0xe8, 0x44, 0x62, 0x0c, 0x66, - 0x8e, 0x8f, 0xaa, 0xe5, 0xc7, 0x08, 0xd1, 0xa6, 0x94, 0xc0, 0x21, 0x77, 0x61, 0xca, 0xf6, 0xbb, - 0x11, 0xdd, 0xf1, 0xe5, 0xc8, 0x0d, 0x21, 0xd5, 0xe5, 0xe3, 0xa3, 0xea, 0x7c, 0xc0, 0x4a, 0x1a, - 0x91, 0xdf, 0x10, 0x43, 0xa8, 0xd1, 0x27, 0xa8, 0xc8, 0x0a, 0x4c, 0xd5, 0x70, 0xf5, 0x16, 0x52, - 0xe3, 0xe3, 0x35, 0xb6, 0x78, 0xe9, 0xf8, 0xa8, 0x7a, 0xde, 0xc1, 0x92, 0x46, 0x20, 0x8a, 0x74, - 0x36, 0x26, 0x11, 0xd9, 0x84, 0xb3, 0x0f, 0xba, 0x8f, 0x68, 0xe0, 0xd1, 0x88, 0x86, 0xb2, 0x45, - 0x23, 0xd8, 0xa2, 0x2b, 0xc7, 0x47, 0xd5, 0x8b, 0x4f, 0x54, 0x61, 0x46, 0x9b, 0xd2, 0xa4, 0x84, - 0xc2, 0x19, 0xd1, 0xd0, 0x65, 0x27, 0x72, 0x1e, 0x39, 0x21, 0xc5, 0x45, 0x69, 0x7c, 0xe1, 0x1c, - 0x17, 0xf1, 0xcd, 0x44, 0xe9, 0xe2, 0x35, 0x21, 0xe5, 0x0b, 0xaa, 0xef, 0x2d, 0x51, 0xa4, 0x55, - 0x94, 0xe4, 0xc9, 0xd6, 0x66, 0xb5, 0xef, 0x8c, 0x61, 0x6b, 0x71, 0x6d, 0x56, 0xfb, 0x8e, 0xbe, - 0x6a, 0xa9, 0x1d, 0x68, 0x1d, 0x86, 0x76, 0xd9, 0xee, 0x8c, 0x6b, 0xd6, 0xd4, 0xc2, 0x55, 0xd1, - 0xa2, 0xe4, 0xfc, 0xbb, 0xc9, 0x7e, 0x20, 0x22, 0x7e, 0x79, 0x67, 0x70, 0x47, 0xd7, 0xf7, 0x62, - 0x2c, 0x23, 0x9f, 0x01, 0x88, 0x56, 0xd5, 0x3a, 0x9d, 0xca, 0x38, 0x76, 0xf2, 0xac, 0xd9, 0xc9, - 0x5a, 0xa7, 0xb3, 0x78, 0x59, 0xf4, 0xef, 0x9c, 0xea, 0x9f, 0xd3, 0xe9, 0x68, 0xdc, 0x34, 0x26, - 0xe4, 0x13, 0x98, 0xc0, 0x25, 0x4d, 0x8e, 0xe8, 0x04, 0x8e, 0xe8, 0x85, 0xe3, 0xa3, 0xea, 0x1c, - 0xae, 0x56, 0x19, 0xe3, 0x69, 0x10, 0x90, 0xdf, 0x80, 0x59, 0xc1, 0xee, 0xa1, 0xeb, 0xb5, 0xfc, - 0x67, 0xe1, 0x32, 0x0d, 0x9f, 0x44, 0x7e, 0x07, 0x97, 0xbf, 0xf1, 0x85, 0x8b, 0x66, 0xf3, 0x4c, - 0x9c, 0xc5, 0x1b, 0xa2, 0xa5, 0x96, 0x6a, 0xe9, 0x33, 0x8e, 0xd0, 0x68, 0x71, 0x0c, 0x7d, 0x81, - 0xcc, 0x64, 0x41, 0xd6, 0xe0, 0xcc, 0x6e, 0x48, 0x8d, 0x3e, 0x4c, 0xe1, 0xfe, 0x50, 0x65, 0x23, - 0xdc, 0x0d, 0x69, 0x23, 0xaf, 0x1f, 0x49, 0x3a, 0x62, 0x03, 0x59, 0x0e, 0xfc, 0x4e, 0x62, 0x8e, - 0x9f, 0x41, 0x89, 0x58, 0xc7, 0x47, 0xd5, 0xcb, 0xad, 0xc0, 0xef, 0x34, 0xf2, 0x27, 0x7a, 0x06, - 0x35, 0xf9, 0x11, 0x9c, 0x5b, 0xf2, 0x3d, 0x8f, 0x36, 0xd9, 0x0a, 0xba, 0xec, 0x3a, 0xfb, 0x9e, - 0x1f, 0x46, 0x6e, 0x73, 0x6d, 0xb9, 0x52, 0x8e, 0xb7, 0x87, 0xa6, 0xc2, 0x68, 0xb4, 0x14, 0x8a, - 0xb9, 0x3d, 0xe4, 0x70, 0x21, 0x5f, 0xc1, 0xa4, 0xa8, 0x8b, 0x06, 0x38, 0x35, 0xcf, 0x16, 0x4f, - 0x34, 0x85, 0xcc, 0x37, 0xfa, 0x40, 0xfe, 0xe4, 0xaa, 0x93, 0xc9, 0x8b, 0x7c, 0x0d, 0xe3, 0x1b, - 0x77, 0x6b, 0x36, 0x0d, 0x3b, 0xbe, 0x17, 0xd2, 0x0a, 0xc1, 0x11, 0xbd, 0x2c, 0x58, 0x6f, 0xdc, - 0xad, 0xd5, 0xba, 0xd1, 0x01, 0xf5, 0x22, 0xb7, 0xe9, 0x44, 0x54, 0x62, 0x2d, 0xce, 0xb3, 0x99, - 0x77, 0xf8, 0xd8, 0x69, 0x04, 0x02, 0xa2, 0xf5, 0x42, 0x67, 0x47, 0xe6, 0x61, 0xb4, 0x5e, 0x5f, - 0x5d, 0xf7, 0xf7, 0x5d, 0xaf, 0x32, 0xcd, 0x84, 0x61, 0xab, 0xdf, 0xe4, 0x31, 0xcc, 0x6a, 0x67, - 0x83, 0x06, 0xfb, 0x9f, 0x1e, 0x52, 0x2f, 0xaa, 0xcc, 0x60, 0x1b, 0xbe, 0xaf, 0x0e, 0x37, 0x37, - 0xf5, 0x23, 0xc4, 0xd3, 0x3b, 0x37, 0x6b, 0xf1, 0xcf, 0xba, 0x24, 0x5a, 0xec, 0xaf, 0x94, 0xec, - 0x19, 0x27, 0xa3, 0x84, 0xec, 0xc0, 0xc8, 0x76, 0x37, 0xe8, 0xf8, 0x21, 0xad, 0xcc, 0xa2, 0xe0, - 0xae, 0x15, 0x7d, 0xa1, 0x02, 0x75, 0x71, 0x96, 0x2d, 0xd1, 0x1d, 0xfe, 0x43, 0xeb, 0x9d, 0x64, - 0x45, 0x3e, 0x85, 0x89, 0x7a, 0x7d, 0x35, 0xde, 0x50, 0xce, 0xe1, 0x86, 0x72, 0xf1, 0xf8, 0xa8, - 0x5a, 0x61, 0x2a, 0x55, 0xbc, 0xa9, 0xe8, 0x5f, 0x95, 0x4e, 0xc1, 0x38, 0xec, 0xac, 0xd7, 0x63, - 0x0e, 0x73, 0x31, 0x07, 0xa6, 0xcc, 0x65, 0x73, 0xd0, 0x29, 0xc8, 0x3f, 0x28, 0xc1, 0x15, 0x9d, - 0x65, 0x96, 0x60, 0x2a, 0xe7, 0x5f, 0x44, 0x9a, 0x0b, 0xc7, 0x47, 0xd5, 0x9b, 0x66, 0x3f, 0x1a, - 0x99, 0x83, 0xa5, 0xb5, 0xad, 0x67, 0x53, 0xb0, 0xbd, 0x7a, 0x07, 0x32, 0xdb, 0x3b, 0xff, 0xc2, - 0xed, 0x35, 0xa5, 0xd6, 0xbb, 0xbd, 0xbd, 0x9a, 0x62, 0x7d, 0x0e, 0x63, 0x6a, 0xd1, 0x26, 0x23, - 0x30, 0x50, 0x6b, 0xb7, 0xcb, 0x7d, 0xec, 0x8f, 0x7a, 0x7d, 0xb5, 0x5c, 0x22, 0x53, 0x00, 0xf1, - 0x4e, 0x55, 0xee, 0x27, 0x13, 0x30, 0x2a, 0x77, 0x92, 0xf2, 0x00, 0xe2, 0x77, 0x3a, 0xe5, 0x41, - 0x42, 0x60, 0xca, 0x5c, 0xcf, 0xca, 0x43, 0xd6, 0xef, 0x95, 0x60, 0x4c, 0x7d, 0x87, 0xe4, 0x0c, - 0x8c, 0xef, 0x6e, 0xd6, 0xb7, 0x57, 0x96, 0xd6, 0xee, 0xae, 0xad, 0x2c, 0x97, 0xfb, 0xc8, 0x25, - 0x38, 0xbf, 0x53, 0x5f, 0x6d, 0x2c, 0x2f, 0x36, 0xd6, 0xb7, 0x96, 0x6a, 0xeb, 0x8d, 0x6d, 0x7b, - 0xeb, 0xf3, 0x2f, 0x1a, 0x3b, 0xbb, 0x9b, 0x9b, 0x2b, 0xeb, 0xe5, 0x12, 0xa9, 0xc0, 0x0c, 0x2b, - 0x7e, 0xb0, 0xbb, 0xb8, 0xa2, 0x23, 0x94, 0xfb, 0xc9, 0x55, 0xb8, 0x94, 0x55, 0xd2, 0x58, 0x5d, - 0xa9, 0x2d, 0xaf, 0xaf, 0xd4, 0xeb, 0xe5, 0x01, 0x32, 0x07, 0xd3, 0x0c, 0xa5, 0xb6, 0xbd, 0x6d, - 0xd0, 0x0e, 0x5a, 0x6d, 0x18, 0xd7, 0x3e, 0x00, 0x72, 0x11, 0x2a, 0x4b, 0x2b, 0xf6, 0x4e, 0x63, - 0x7b, 0xd7, 0xde, 0xde, 0xaa, 0xaf, 0x34, 0xcc, 0x16, 0x26, 0x4b, 0xd7, 0xb7, 0xee, 0xad, 0x6d, - 0x36, 0x18, 0xa8, 0x5e, 0x2e, 0xb1, 0x66, 0x18, 0xa5, 0xf5, 0xb5, 0xcd, 0x7b, 0xeb, 0x2b, 0x8d, - 0xdd, 0xfa, 0x8a, 0x40, 0xe9, 0xb7, 0x7e, 0xab, 0x3f, 0xb5, 0xa5, 0x93, 0x05, 0x18, 0xaf, 0x73, - 0x7b, 0x05, 0x2e, 0x73, 0xfc, 0x80, 0xc8, 0x74, 0xb4, 0x09, 0x61, 0xc6, 0xe0, 0x2b, 0x98, 0x8e, - 0xc4, 0xb4, 0xb4, 0x6d, 0xf6, 0x35, 0x37, 0xfd, 0xb6, 0xae, 0xa5, 0x75, 0x04, 0xcc, 0x56, 0xa5, - 0x64, 0x41, 0xd3, 0xe7, 0xf8, 0x69, 0x11, 0x4f, 0x24, 0x52, 0x9f, 0xd3, 0xf7, 0x76, 0xa5, 0xd9, - 0x2d, 0xc4, 0x43, 0x2a, 0xd4, 0x30, 0xa4, 0xc9, 0xd0, 0x25, 0x14, 0x1e, 0x79, 0x43, 0x6a, 0xba, - 0xfc, 0x74, 0x87, 0x9b, 0x7d, 0xe2, 0x5c, 0x22, 0x94, 0x5c, 0xab, 0x9b, 0xb3, 0xb1, 0x92, 0x0f, - 0x93, 0x73, 0x46, 0x08, 0x03, 0x99, 0x25, 0xf6, 0x4f, 0x3b, 0x81, 0x4a, 0xaa, 0x30, 0xc4, 0x57, - 0x5c, 0x2e, 0x0f, 0xd4, 0xad, 0xdb, 0x0c, 0x60, 0x73, 0xb8, 0xf5, 0xfb, 0x03, 0xba, 0x92, 0xc1, - 0x74, 0x69, 0x4d, 0xde, 0xa8, 0x4b, 0xa3, 0x9c, 0x11, 0xca, 0x8e, 0x82, 0xfc, 0x2b, 0xc1, 0xa3, - 0xe0, 0x40, 0x7c, 0x14, 0x14, 0x9f, 0x1a, 0x3f, 0x0a, 0xc6, 0x28, 0x6c, 0x14, 0x85, 0xda, 0x86, - 0x5c, 0x07, 0xe3, 0x51, 0x14, 0xaa, 0x9e, 0x18, 0x45, 0x0d, 0x89, 0x7c, 0x00, 0x50, 0x7b, 0x58, - 0xc7, 0x33, 0x8f, 0xbd, 0x29, 0x54, 0x57, 0xdc, 0x64, 0x9c, 0x67, 0xa1, 0x38, 0x52, 0x05, 0xfa, - 0x99, 0x51, 0xc3, 0x26, 0x8b, 0x30, 0x59, 0xfb, 0x69, 0x37, 0xa0, 0x6b, 0x2d, 0xb6, 0x4f, 0x45, - 0xfc, 0x70, 0x3c, 0xc6, 0x17, 0x52, 0x87, 0x15, 0x34, 0x5c, 0x51, 0xa2, 0x31, 0x30, 0x49, 0xc8, - 0x16, 0x9c, 0xbd, 0xb7, 0xb4, 0x2d, 0xe6, 0x55, 0xad, 0xd9, 0xf4, 0xbb, 0x5e, 0x24, 0xf4, 0xd5, - 0xab, 0xc7, 0x47, 0xd5, 0x4b, 0xfb, 0xcd, 0x4e, 0x43, 0xce, 0x41, 0x87, 0x17, 0xeb, 0x0a, 0x6b, - 0x8a, 0x96, 0x5c, 0x83, 0x81, 0x5d, 0x7b, 0x4d, 0x9c, 0x9c, 0xcf, 0x1e, 0x1f, 0x55, 0x27, 0xbb, - 0x81, 0xab, 0x91, 0xb0, 0xd2, 0xfb, 0x83, 0xa3, 0xfd, 0xe5, 0x01, 0x7b, 0xac, 0x4e, 0xc3, 0x90, - 0x1f, 0xf2, 0xda, 0x30, 0x75, 0x8f, 0x46, 0x6c, 0xf6, 0xc9, 0x43, 0x4b, 0xf1, 0xd8, 0x7c, 0x04, - 0xe3, 0x0f, 0xdd, 0xe8, 0xa0, 0x4e, 0x9b, 0x01, 0x8d, 0xa4, 0xc1, 0x06, 0xe5, 0xf6, 0xcc, 0x8d, - 0x0e, 0x1a, 0x21, 0x87, 0xeb, 0x9b, 0xb3, 0x86, 0x6e, 0xad, 0xc0, 0x19, 0x51, 0x9b, 0x3a, 0x23, - 0x2d, 0x98, 0x0c, 0x4b, 0xc8, 0x10, 0xc7, 0x4e, 0x67, 0x68, 0xb2, 0xf9, 0xc7, 0xfd, 0x30, 0xbb, - 0x74, 0xe0, 0x78, 0xfb, 0x74, 0xdb, 0x09, 0xc3, 0x67, 0x7e, 0xd0, 0xd2, 0x1a, 0x8f, 0x07, 0xc4, - 0x54, 0xe3, 0xf1, 0x44, 0xb8, 0x00, 0xe3, 0x5b, 0xed, 0x96, 0xa4, 0x11, 0x87, 0x57, 0xac, 0xcb, - 0x6f, 0xb7, 0x1a, 0x1d, 0xc9, 0x4b, 0x47, 0x62, 0x34, 0x9b, 0xf4, 0x99, 0xa2, 0x19, 0x88, 0x69, - 0x3c, 0xfa, 0x4c, 0xa3, 0xd1, 0x90, 0xc8, 0x0a, 0x9c, 0xad, 0xd3, 0xa6, 0xef, 0xb5, 0xee, 0x3a, - 0xcd, 0xc8, 0x0f, 0x76, 0xfc, 0x27, 0xd4, 0x13, 0xb3, 0x12, 0xb5, 0xfb, 0x10, 0x0b, 0x1b, 0x8f, - 0xb1, 0xb4, 0x11, 0xb1, 0x62, 0x3b, 0x4d, 0x41, 0xb6, 0x60, 0xf4, 0xa1, 0x30, 0xfb, 0x89, 0x13, - 0xef, 0xab, 0x37, 0x95, 0x1d, 0x70, 0x29, 0xa0, 0x38, 0x95, 0x9c, 0xb6, 0x3a, 0xb3, 0x2b, 0x65, - 0x09, 0xd7, 0x23, 0x89, 0x69, 0x2b, 0x26, 0xd6, 0x2e, 0x4c, 0x6e, 0xb7, 0xbb, 0xfb, 0xae, 0xc7, - 0x56, 0x8e, 0x3a, 0xfd, 0x09, 0x59, 0x06, 0x88, 0x01, 0xc2, 0x98, 0x37, 0x2d, 0xce, 0xc9, 0x71, - 0xc1, 0xde, 0x5b, 0xe2, 0xf3, 0x43, 0x08, 0x1e, 0x6b, 0x6c, 0x8d, 0xce, 0xfa, 0x6f, 0x03, 0x40, - 0xc4, 0x00, 0xe0, 0x4e, 0x56, 0xa7, 0x11, 0xdb, 0x63, 0xce, 0x41, 0xbf, 0xb2, 0xb9, 0x0d, 0x1f, - 0x1f, 0x55, 0xfb, 0xdd, 0x96, 0xdd, 0xbf, 0xb6, 0x4c, 0xde, 0x86, 0x21, 0x44, 0x43, 0xf9, 0x4f, - 0xa9, 0xfa, 0x74, 0x0e, 0x7c, 0x05, 0xc1, 0x2d, 0xd4, 0xe6, 0xc8, 0xe4, 0x1d, 0x18, 0x5b, 0xa6, - 0x6d, 0xba, 0xef, 0x44, 0xbe, 0x5c, 0x13, 0xb8, 0x15, 0x4b, 0x02, 0xb5, 0x39, 0x17, 0x63, 0xb2, - 0x33, 0xad, 0x4d, 0x9d, 0xd0, 0xf7, 0xf4, 0x33, 0x6d, 0x80, 0x10, 0xfd, 0x4c, 0xcb, 0x71, 0xc8, - 0xff, 0x53, 0x82, 0xf1, 0x9a, 0xe7, 0x09, 0xeb, 0x50, 0x28, 0xa4, 0x3e, 0x7b, 0x53, 0x99, 0x53, - 0xd7, 0x9d, 0x47, 0xb4, 0xbd, 0xe7, 0xb4, 0xbb, 0x34, 0x5c, 0xfc, 0x9a, 0x1d, 0x33, 0xfe, 0xed, - 0x51, 0xf5, 0xc3, 0x53, 0xd8, 0x7b, 0x62, 0xc3, 0xec, 0x4e, 0xe0, 0xb8, 0x51, 0x78, 0x7c, 0x54, - 0x9d, 0x75, 0xe2, 0x0a, 0xf5, 0xef, 0x46, 0x6b, 0x47, 0xbc, 0xc0, 0x0f, 0xf7, 0x5a, 0xe0, 0xc9, - 0x21, 0x9c, 0xa9, 0x85, 0x61, 0xf7, 0x90, 0xd6, 0x23, 0x27, 0x88, 0x76, 0xdc, 0x43, 0x8a, 0xab, - 0x4a, 0xb1, 0x85, 0xe0, 0xf5, 0x9f, 0x1d, 0x55, 0x4b, 0xec, 0x64, 0xe3, 0x20, 0x29, 0x53, 0x5e, - 0x82, 0xa8, 0x11, 0xb9, 0xfa, 0x1e, 0x85, 0xb6, 0x82, 0x24, 0x6f, 0xeb, 0x9a, 0xd2, 0x2a, 0xd6, - 0x96, 0xf3, 0x46, 0xdc, 0x5a, 0x82, 0x8b, 0xf7, 0x68, 0x64, 0xd3, 0x90, 0x46, 0xf2, 0x1b, 0xc1, - 0x19, 0x1e, 0x5b, 0x68, 0x47, 0xf0, 0xb7, 0x22, 0xc6, 0xe1, 0xe7, 0xdf, 0x85, 0x2c, 0xb1, 0xfe, - 0x97, 0x12, 0x54, 0x97, 0x02, 0xca, 0x0f, 0x05, 0x39, 0x8c, 0x8a, 0xd7, 0xae, 0x8b, 0x30, 0xb8, - 0xf3, 0xbc, 0x23, 0x4d, 0x2b, 0x58, 0xca, 0x06, 0xc5, 0x46, 0xe8, 0x09, 0x2d, 0x55, 0xd6, 0x63, - 0x98, 0xb5, 0xa9, 0x47, 0x9f, 0x39, 0x8f, 0xda, 0xd4, 0x30, 0xf6, 0x54, 0x61, 0x88, 0x7f, 0xe8, - 0xa9, 0x2e, 0x70, 0xf8, 0xe9, 0x0c, 0x67, 0xd6, 0x24, 0x8c, 0x6f, 0xbb, 0xde, 0xbe, 0xe0, 0x6e, - 0xfd, 0xd5, 0x20, 0x4c, 0xf0, 0xdf, 0xe2, 0x9c, 0x93, 0xd8, 0xf3, 0x4a, 0x27, 0xd9, 0xf3, 0xde, - 0x83, 0x49, 0xb6, 0x69, 0xd0, 0x60, 0x8f, 0x06, 0x6c, 0xfd, 0x17, 0x92, 0xc0, 0x33, 0x5b, 0x88, - 0x05, 0x8d, 0xa7, 0xbc, 0xc4, 0x36, 0x11, 0xc9, 0x3a, 0x4c, 0x71, 0xc0, 0x5d, 0xea, 0x44, 0xdd, - 0xd8, 0xec, 0x74, 0x46, 0x1c, 0x6c, 0x24, 0x98, 0x4f, 0x4d, 0xc1, 0xeb, 0xb1, 0x00, 0xda, 0x09, - 0x5a, 0xf2, 0x09, 0x9c, 0xd9, 0x0e, 0xfc, 0x6f, 0x9e, 0x6b, 0xbb, 0x3c, 0xff, 0x3a, 0xf9, 0x11, - 0x88, 0x15, 0x35, 0xf4, 0xbd, 0x3e, 0x89, 0x4d, 0xde, 0x80, 0xd1, 0xb5, 0x70, 0xd1, 0x0f, 0x5c, - 0x6f, 0x1f, 0xbf, 0xd1, 0x51, 0x6e, 0xad, 0x77, 0xc3, 0xc6, 0x23, 0x04, 0xda, 0xaa, 0x38, 0x61, - 0x57, 0x1e, 0xe9, 0x6d, 0x57, 0xbe, 0x0d, 0xb0, 0xee, 0x3b, 0xad, 0x5a, 0xbb, 0xbd, 0x54, 0x0b, - 0x71, 0x3b, 0x15, 0xfb, 0x51, 0xdb, 0x77, 0x5a, 0x0d, 0xa7, 0xdd, 0x6e, 0x34, 0x9d, 0xd0, 0xd6, - 0x70, 0xc8, 0x97, 0x70, 0x3e, 0x74, 0xf7, 0x3d, 0xec, 0x5c, 0xc3, 0x69, 0xef, 0xfb, 0x81, 0x1b, - 0x1d, 0x1c, 0x36, 0xc2, 0xae, 0x1b, 0x71, 0xa3, 0xce, 0xd4, 0xc2, 0x65, 0xb1, 0xc8, 0xd5, 0x25, - 0x5e, 0x4d, 0xa2, 0xd5, 0x19, 0x96, 0x3d, 0x17, 0x66, 0x17, 0x90, 0x87, 0x30, 0xb9, 0xee, 0x36, - 0xa9, 0x17, 0x52, 0xb4, 0xd2, 0x3d, 0x47, 0x93, 0x4f, 0xf1, 0xc7, 0xcc, 0x84, 0x38, 0xd9, 0xd6, - 0x89, 0xf0, 0xd3, 0x35, 0xf9, 0xdc, 0x1f, 0x1c, 0x1d, 0x2e, 0x8f, 0xd8, 0x67, 0x04, 0xf0, 0xa1, - 0x13, 0x78, 0xae, 0xb7, 0x1f, 0x5a, 0xff, 0xf0, 0x2c, 0x8c, 0xaa, 0x71, 0xba, 0xa9, 0x1f, 0x37, - 0xc4, 0xd6, 0x8c, 0x53, 0x36, 0x36, 0xa6, 0xd9, 0x1a, 0x06, 0x39, 0x8f, 0x07, 0x10, 0xa1, 0x14, - 0x8c, 0xb0, 0x4f, 0xc8, 0xe9, 0x74, 0x6c, 0x06, 0x63, 0x4b, 0xc3, 0xf2, 0x22, 0x4e, 0x9a, 0x51, - 0xbe, 0x34, 0xb4, 0x1e, 0xd9, 0xfd, 0xcb, 0x8b, 0xec, 0x9b, 0xdc, 0x5a, 0x5b, 0x5e, 0xc2, 0xf1, - 0x1f, 0xe5, 0xdf, 0xa4, 0xef, 0xb6, 0x9a, 0x36, 0x42, 0x59, 0x69, 0xbd, 0xb6, 0xb1, 0x2e, 0xc6, - 0x18, 0x4b, 0x43, 0xe7, 0xb0, 0x6d, 0x23, 0x94, 0xa9, 0xac, 0xdc, 0x2e, 0xb2, 0xe4, 0x7b, 0x51, - 0xe0, 0xb7, 0x43, 0xd4, 0xc3, 0x46, 0xf9, 0x1c, 0x14, 0x06, 0x95, 0xa6, 0x28, 0xb2, 0x13, 0xa8, - 0xe4, 0x21, 0xcc, 0xd5, 0x5a, 0x4f, 0x1d, 0xaf, 0x49, 0x5b, 0xbc, 0xe4, 0xa1, 0x1f, 0x3c, 0x79, - 0xdc, 0xf6, 0x9f, 0x85, 0x38, 0x49, 0x46, 0x85, 0xfd, 0x51, 0xa0, 0x48, 0xfb, 0xcc, 0x33, 0x89, - 0x64, 0xe7, 0x51, 0xb3, 0x75, 0x60, 0xa9, 0xed, 0x77, 0x5b, 0x62, 0xea, 0xe0, 0x3a, 0xd0, 0x64, - 0x00, 0x9b, 0xc3, 0x99, 0x94, 0x56, 0xeb, 0x1b, 0x38, 0x31, 0x84, 0x94, 0x0e, 0xc2, 0x43, 0x9b, - 0xc1, 0xc8, 0xab, 0x30, 0x22, 0xb5, 0x6f, 0x7e, 0x1d, 0x81, 0x66, 0x70, 0xa9, 0x75, 0xcb, 0x32, - 0xf6, 0x1d, 0xdb, 0xb4, 0xe9, 0x3f, 0xa5, 0xc1, 0xf3, 0x25, 0xbf, 0x45, 0xa5, 0x6d, 0x4a, 0xd8, - 0x5e, 0x78, 0x41, 0xa3, 0xc9, 0x4a, 0x6c, 0x13, 0x91, 0x55, 0xc0, 0x37, 0xee, 0xb0, 0x72, 0x26, - 0xae, 0x80, 0x6f, 0xec, 0xa1, 0x2d, 0xcb, 0xc8, 0x32, 0x9c, 0xad, 0x75, 0x23, 0xff, 0xd0, 0x89, - 0xdc, 0xe6, 0x6e, 0x67, 0x3f, 0x70, 0x58, 0x25, 0x65, 0x24, 0xc0, 0xd3, 0x88, 0x23, 0x0b, 0x1b, - 0x5d, 0x51, 0x6a, 0xa7, 0x09, 0xc8, 0xbb, 0x30, 0xb1, 0x16, 0x72, 0xfb, 0xa3, 0x13, 0xd2, 0x16, - 0x1a, 0x91, 0x44, 0x2b, 0xdd, 0xb0, 0x81, 0xd6, 0xc8, 0x06, 0x3b, 0xbf, 0xb4, 0x6c, 0x03, 0x8f, - 0x58, 0x30, 0x5c, 0x0b, 0x43, 0x37, 0x8c, 0xd0, 0x36, 0x34, 0xba, 0x08, 0xc7, 0x47, 0xd5, 0x61, - 0x07, 0x21, 0xb6, 0x28, 0x21, 0x0f, 0x61, 0x7c, 0x99, 0x32, 0xf5, 0x77, 0x27, 0xe8, 0x86, 0x11, - 0x5a, 0x7a, 0xc6, 0x17, 0xce, 0x8b, 0xd5, 0x48, 0x2b, 0x11, 0x73, 0x99, 0xab, 0xa8, 0x2d, 0x84, - 0x37, 0x22, 0x56, 0xa0, 0x6f, 0xb5, 0x1a, 0x3e, 0xd3, 0xed, 0x05, 0xcd, 0xaa, 0xdb, 0x62, 0xeb, - 0xcb, 0x0c, 0xb6, 0x01, 0x75, 0x7b, 0xb1, 0xa0, 0x35, 0x0e, 0xb0, 0x44, 0xd7, 0xed, 0x0d, 0x12, - 0xd2, 0x4c, 0x99, 0xb4, 0x67, 0x0d, 0xb3, 0xa5, 0x59, 0x28, 0x9b, 0x78, 0x4a, 0x83, 0xf7, 0x47, - 0x30, 0xbe, 0xd4, 0x0d, 0x23, 0xff, 0x70, 0xe7, 0x80, 0x1e, 0x52, 0xb4, 0x06, 0x89, 0x13, 0x4c, - 0x13, 0xc1, 0x8d, 0x88, 0xc1, 0xf5, 0x6e, 0x6a, 0xe8, 0xe4, 0x33, 0x20, 0xf2, 0x28, 0x72, 0x8f, - 0xcd, 0x0f, 0x8f, 0xcd, 0x65, 0x34, 0x08, 0x8d, 0xf2, 0xf3, 0x87, 0x3c, 0xc1, 0x34, 0xf6, 0x55, - 0xb1, 0x6e, 0x94, 0x4c, 0x13, 0xb3, 0x06, 0xf1, 0x26, 0xde, 0x0b, 0x9c, 0xce, 0x41, 0xa5, 0x12, - 0x1f, 0x0d, 0x44, 0xa7, 0xf6, 0x19, 0xdc, 0x50, 0x71, 0x62, 0x74, 0x52, 0x07, 0xe0, 0x3f, 0xd7, - 0xd9, 0xc0, 0x73, 0x13, 0x52, 0xc5, 0x90, 0x17, 0x2b, 0x90, 0xb2, 0x3a, 0x8f, 0x8a, 0x13, 0x67, - 0xdb, 0x76, 0x8d, 0xd1, 0xd4, 0xd8, 0x90, 0x27, 0x50, 0xe6, 0xbf, 0x36, 0x7c, 0xcf, 0x8d, 0xf8, - 0x7e, 0x31, 0x6f, 0xd8, 0x1b, 0x93, 0xc5, 0xb2, 0x02, 0xb4, 0xf3, 0x8a, 0x0a, 0x0e, 0x55, 0xa9, - 0x56, 0x4d, 0x8a, 0x31, 0xd9, 0x86, 0xf1, 0xed, 0xc0, 0x6f, 0x75, 0x9b, 0x11, 0x6a, 0x19, 0x17, - 0x70, 0xe1, 0x27, 0xa2, 0x1e, 0xad, 0x84, 0xcb, 0xa4, 0xc3, 0x01, 0x0d, 0xb6, 0x2f, 0xe8, 0x32, - 0xd1, 0x10, 0xc9, 0x22, 0x0c, 0x6f, 0xfb, 0x6d, 0xb7, 0xf9, 0xbc, 0x72, 0x11, 0x1b, 0x3d, 0x23, - 0x99, 0x21, 0x50, 0x36, 0x15, 0x55, 0xda, 0x0e, 0x82, 0x74, 0x95, 0x96, 0x23, 0x91, 0x1a, 0x4c, - 0x7e, 0xc6, 0x26, 0x8c, 0xeb, 0x7b, 0x9e, 0xe3, 0x06, 0xb4, 0x72, 0x09, 0xc7, 0x05, 0x6d, 0xf1, - 0x3f, 0xd1, 0x0b, 0xf4, 0xe9, 0x6c, 0x50, 0x90, 0x35, 0x38, 0xb3, 0x16, 0xd6, 0xa3, 0xc0, 0xed, - 0xd0, 0x0d, 0xc7, 0x73, 0xf6, 0x69, 0xab, 0x72, 0x39, 0x36, 0x86, 0xbb, 0x61, 0x23, 0xc4, 0xb2, - 0xc6, 0x21, 0x2f, 0xd4, 0x8d, 0xe1, 0x09, 0x3a, 0xf2, 0x39, 0xcc, 0xac, 0x7c, 0x13, 0xb1, 0x19, - 0xd3, 0xae, 0x75, 0x5b, 0x6e, 0x54, 0x8f, 0xfc, 0xc0, 0xd9, 0xa7, 0x95, 0x2a, 0xf2, 0x7b, 0xe5, - 0xf8, 0xa8, 0x7a, 0x85, 0x8a, 0xf2, 0x86, 0xc3, 0x10, 0x1a, 0x21, 0xc7, 0xd0, 0x2f, 0xb9, 0xb3, - 0x38, 0x30, 0xe9, 0xd7, 0xbb, 0x1d, 0xa6, 0x6d, 0xa3, 0xf4, 0xaf, 0x18, 0xd2, 0xd7, 0x4a, 0xb8, - 0xf4, 0x43, 0x0e, 0x48, 0x49, 0x5f, 0x43, 0x24, 0x36, 0x90, 0xfb, 0xbe, 0xeb, 0xd5, 0x9a, 0x91, - 0xfb, 0x94, 0x8a, 0x13, 0x73, 0x58, 0xb9, 0x8a, 0x2d, 0x45, 0xc3, 0xfd, 0xaf, 0xfa, 0xae, 0xd7, - 0x70, 0xb0, 0xb8, 0x11, 0x8a, 0x72, 0xfd, 0x1b, 0x49, 0x53, 0x93, 0x1f, 0xc1, 0xb9, 0x0d, 0xff, - 0x91, 0xdb, 0xa6, 0x7c, 0xc9, 0xe1, 0x62, 0x41, 0x23, 0xa4, 0x85, 0x7c, 0xd1, 0x70, 0x7f, 0x88, - 0x18, 0x0d, 0xb1, 0x5a, 0x1d, 0x2a, 0x1c, 0xdd, 0x70, 0x9f, 0xcd, 0x85, 0xac, 0xc0, 0x04, 0x7e, - 0x97, 0x6d, 0xfc, 0x19, 0x56, 0xae, 0xe1, 0x91, 0xee, 0x6a, 0x42, 0x4b, 0xbb, 0xb9, 0xa2, 0xe1, - 0xac, 0x78, 0x51, 0xf0, 0xdc, 0x36, 0xc8, 0xc8, 0xc7, 0x30, 0x9f, 0x9c, 0xde, 0x4b, 0xbe, 0xf7, - 0xd8, 0xdd, 0xef, 0x06, 0xb4, 0x55, 0x79, 0x85, 0x35, 0xd5, 0x2e, 0xc0, 0x98, 0x7f, 0x08, 0x67, - 0x53, 0x55, 0x90, 0x32, 0x0c, 0x3c, 0x11, 0xf7, 0xa0, 0x63, 0x36, 0xfb, 0x93, 0xbc, 0x09, 0x43, - 0x4f, 0xd9, 0x59, 0x0a, 0x35, 0x86, 0xf8, 0x66, 0x4d, 0x23, 0x5d, 0xf3, 0x1e, 0xfb, 0x36, 0x47, - 0xfa, 0xa0, 0xff, 0xbd, 0xd2, 0xfd, 0xc1, 0xd1, 0xf1, 0xf2, 0x04, 0xbf, 0xbe, 0xbe, 0x3f, 0x38, - 0x3a, 0x59, 0x9e, 0xb2, 0x6a, 0x70, 0x26, 0x81, 0x4f, 0x2a, 0x30, 0x42, 0x3d, 0xa6, 0x9f, 0xb7, - 0xb8, 0xce, 0x62, 0xcb, 0x9f, 0x64, 0x06, 0x86, 0xda, 0xee, 0xa1, 0x1b, 0x61, 0x85, 0x43, 0x36, - 0xff, 0x61, 0xfd, 0x41, 0x09, 0x48, 0x7a, 0xcb, 0x20, 0xb7, 0x12, 0x6c, 0xb8, 0x76, 0x2a, 0x40, - 0xba, 0x81, 0x5e, 0x72, 0xff, 0x0c, 0xa6, 0xf9, 0x98, 0xc9, 0xcd, 0x4d, 0xab, 0x8b, 0x2f, 0xaa, - 0x19, 0xc5, 0xba, 0x51, 0x47, 0x14, 0xe3, 0x56, 0xb8, 0x8e, 0x4d, 0xeb, 0xc2, 0x6c, 0xe6, 0x66, - 0x41, 0x36, 0x60, 0xf6, 0xd0, 0xf7, 0xa2, 0x83, 0xf6, 0x73, 0xb9, 0x57, 0x88, 0xda, 0x4a, 0x58, - 0x1b, 0xae, 0x8f, 0x99, 0x08, 0xf6, 0xb4, 0x00, 0x0b, 0x8e, 0x58, 0x8f, 0xb0, 0x0b, 0xc9, 0x9e, - 0x58, 0x36, 0x9c, 0x4d, 0xad, 0xb9, 0xe4, 0x87, 0x30, 0xd1, 0xc4, 0xf3, 0x97, 0x51, 0x13, 0xdf, - 0x71, 0x34, 0xb8, 0xfe, 0x39, 0x71, 0x38, 0xef, 0xca, 0xdf, 0x2d, 0xc1, 0x5c, 0xce, 0x6a, 0x7b, - 0x7a, 0x51, 0x7f, 0x01, 0xe7, 0x0e, 0x9d, 0x6f, 0x1a, 0x01, 0x1e, 0xaf, 0x1b, 0x81, 0xe3, 0x25, - 0xa4, 0x8d, 0x2b, 0x49, 0x36, 0x86, 0xee, 0x43, 0x74, 0xe8, 0x7c, 0x63, 0x23, 0x82, 0xcd, 0xca, - 0x79, 0x3b, 0x3f, 0x85, 0x49, 0x63, 0x7d, 0x3d, 0x75, 0xe3, 0xac, 0x3b, 0x70, 0x76, 0x99, 0xb6, - 0x69, 0x44, 0x4f, 0x6c, 0x56, 0xb3, 0xb6, 0x01, 0xea, 0xf4, 0xd0, 0xe9, 0x1c, 0xf8, 0x4c, 0xef, - 0x5e, 0xd4, 0x7f, 0x09, 0xb3, 0x0c, 0x91, 0x27, 0x08, 0x59, 0xb0, 0xf7, 0x16, 0xd7, 0xc5, 0x43, - 0x85, 0x69, 0x6b, 0x54, 0xd6, 0xbf, 0xec, 0x07, 0x22, 0x16, 0xc8, 0x80, 0x3a, 0x87, 0xb2, 0x19, - 0xef, 0xc3, 0x04, 0x3f, 0x44, 0x73, 0x30, 0x36, 0x67, 0x7c, 0x61, 0x5a, 0x7c, 0x79, 0x7a, 0xd1, - 0x6a, 0x9f, 0x6d, 0xa0, 0x32, 0x52, 0x9b, 0xf2, 0xd3, 0x3f, 0x92, 0xf6, 0x1b, 0xa4, 0x7a, 0x11, - 0x23, 0xd5, 0x7f, 0x93, 0x4f, 0x60, 0x6a, 0xc9, 0x3f, 0xec, 0x30, 0x99, 0x08, 0xe2, 0x01, 0x61, - 0x59, 0x11, 0xf5, 0x1a, 0x85, 0xab, 0x7d, 0x76, 0x02, 0x9d, 0x6c, 0xc2, 0xf4, 0xdd, 0x76, 0x37, - 0x3c, 0xa8, 0x79, 0xad, 0xa5, 0xb6, 0x1f, 0x4a, 0x2e, 0x83, 0xe2, 0x30, 0x24, 0x96, 0xb7, 0x34, - 0xc6, 0x6a, 0x9f, 0x9d, 0x45, 0x48, 0x5e, 0x85, 0xa1, 0x95, 0xa7, 0x6c, 0xd9, 0x95, 0x9e, 0x24, - 0xc2, 0xd1, 0x6d, 0xcb, 0xa3, 0x5b, 0x8f, 0x57, 0xfb, 0x6c, 0x5e, 0xba, 0x38, 0x06, 0x23, 0xf2, - 0x00, 0x7e, 0x8b, 0xa9, 0xc4, 0x4a, 0x9c, 0xf5, 0xc8, 0x89, 0xba, 0x21, 0x99, 0x87, 0xd1, 0xdd, - 0x0e, 0x3b, 0x17, 0x4a, 0xcb, 0x85, 0xad, 0x7e, 0x5b, 0x6f, 0x9a, 0x92, 0x26, 0x17, 0x21, 0x36, - 0xbb, 0x0a, 0x64, 0xcd, 0x0e, 0xbb, 0x6a, 0x0a, 0xb7, 0x18, 0xdb, 0xa8, 0xb7, 0x3f, 0x51, 0x6f, - 0x39, 0x29, 0x6b, 0x6b, 0x36, 0x53, 0x78, 0xd6, 0xe7, 0x70, 0x79, 0xb7, 0x13, 0xd2, 0x20, 0xaa, - 0x75, 0x3a, 0x6d, 0xb7, 0xc9, 0x6f, 0xa2, 0xf0, 0xa0, 0x2e, 0x27, 0xcb, 0xbb, 0x30, 0xcc, 0x01, - 0x62, 0x9a, 0xc8, 0x39, 0x58, 0xeb, 0x74, 0x84, 0x79, 0xe0, 0x2d, 0xae, 0x9c, 0xf3, 0x03, 0xbf, - 0x2d, 0xb0, 0xad, 0xdf, 0x2d, 0xc1, 0x65, 0xfe, 0x05, 0xe4, 0xb2, 0xfe, 0x1e, 0x8c, 0xa1, 0x9f, - 0x59, 0xc7, 0x69, 0xca, 0x6f, 0x82, 0x3b, 0xdc, 0x49, 0xa0, 0x1d, 0x97, 0x6b, 0x1e, 0x7c, 0xfd, - 0xf9, 0x1e, 0x7c, 0xf2, 0x03, 0x1b, 0xc8, 0xfc, 0xc0, 0x3e, 0x03, 0x4b, 0xb4, 0xa8, 0xdd, 0x4e, - 0x35, 0x2a, 0x7c, 0x91, 0x56, 0x59, 0xff, 0xa9, 0x1f, 0xe6, 0xee, 0x51, 0x8f, 0x06, 0x0e, 0xf6, - 0xd3, 0x30, 0x44, 0xe9, 0x9e, 0x3c, 0xa5, 0x42, 0x4f, 0x9e, 0xaa, 0x34, 0xed, 0xf5, 0xa3, 0x69, - 0x2f, 0xe5, 0x96, 0xc4, 0x8e, 0x8b, 0xbb, 0xf6, 0x9a, 0xe8, 0x16, 0x1e, 0x17, 0xbb, 0x81, 0x8b, - 0xd6, 0x7c, 0xb2, 0x16, 0x7b, 0x01, 0x0d, 0xf6, 0x34, 0x0b, 0x4c, 0x0b, 0xaf, 0x88, 0x11, 0xe1, - 0x05, 0x64, 0xfa, 0xfe, 0x6c, 0xc2, 0x30, 0xb7, 0x48, 0xe2, 0x1d, 0xd2, 0xf8, 0xc2, 0x0d, 0xf1, - 0x4d, 0xe5, 0x74, 0x50, 0x98, 0x2f, 0x71, 0x63, 0xe7, 0x53, 0x20, 0x42, 0x80, 0x2d, 0xb8, 0xcc, - 0x7f, 0x06, 0xe3, 0x1a, 0xca, 0x49, 0xf6, 0x7e, 0x65, 0x19, 0x65, 0x1a, 0xa3, 0xb7, 0xcf, 0x8d, - 0xac, 0xda, 0xde, 0x6f, 0x7d, 0x08, 0x95, 0x74, 0x6b, 0x84, 0x35, 0xac, 0x97, 0xf1, 0xcd, 0x5a, - 0x86, 0x99, 0x7b, 0x34, 0xc2, 0x89, 0x8b, 0x1f, 0x91, 0xe6, 0xcd, 0x96, 0xf8, 0xce, 0xe4, 0xaa, - 0x8a, 0x40, 0x36, 0xc1, 0xb4, 0xaf, 0xb4, 0x0e, 0xb3, 0x09, 0x2e, 0xa2, 0xfe, 0x0f, 0x60, 0x44, - 0x80, 0xd4, 0x8a, 0x2a, 0x5c, 0x62, 0xe9, 0x23, 0x51, 0xb0, 0xb7, 0xc0, 0xe7, 0xad, 0xe0, 0x6c, - 0x4b, 0x02, 0xeb, 0x00, 0xce, 0xb1, 0x6d, 0x36, 0xe6, 0xaa, 0xa6, 0xe3, 0x05, 0x18, 0xeb, 0x30, - 0x45, 0x21, 0x74, 0x7f, 0xca, 0xa7, 0xd1, 0x90, 0x3d, 0xca, 0x00, 0x75, 0xf7, 0xa7, 0x94, 0x5c, - 0x02, 0xc0, 0x42, 0xec, 0xa6, 0x58, 0x05, 0x10, 0x9d, 0x5b, 0x1b, 0x09, 0xa0, 0x2f, 0x1c, 0x9f, - 0x37, 0x36, 0xfe, 0x6d, 0x05, 0x30, 0x97, 0xaa, 0x49, 0x74, 0xe0, 0x16, 0x8c, 0x4a, 0x15, 0x36, - 0x71, 0x0f, 0xa0, 0xf7, 0xc0, 0x56, 0x48, 0xe4, 0x35, 0x38, 0xe3, 0xd1, 0x6f, 0xa2, 0x46, 0xaa, - 0x0d, 0x93, 0x0c, 0xbc, 0x2d, 0xdb, 0x61, 0xfd, 0x0a, 0xda, 0x7e, 0xeb, 0x9e, 0xff, 0xec, 0x71, - 0xdb, 0x79, 0x42, 0x53, 0x15, 0xff, 0x10, 0x46, 0xeb, 0xbd, 0x2b, 0xe6, 0x9f, 0x8f, 0xac, 0xdc, - 0x56, 0x24, 0x56, 0x1b, 0xe6, 0x59, 0x97, 0xea, 0xb5, 0x8d, 0xf5, 0xb5, 0xd6, 0xf6, 0x77, 0x2d, - 0xc0, 0xa7, 0x70, 0x21, 0xb3, 0xb6, 0xef, 0x5a, 0x88, 0x7f, 0x32, 0x08, 0x73, 0x7c, 0x33, 0x49, - 0xcf, 0xe0, 0x93, 0x2f, 0x35, 0xbf, 0x94, 0x7b, 0xd5, 0xdb, 0x19, 0xf7, 0xaa, 0x48, 0xa2, 0xdf, - 0xab, 0x1a, 0xb7, 0xa9, 0xef, 0x65, 0xdf, 0xa6, 0xa2, 0x9d, 0xc8, 0xbc, 0x4d, 0x4d, 0xde, 0xa1, - 0xae, 0xe4, 0xdf, 0xa1, 0xe2, 0xdd, 0x50, 0xc6, 0x1d, 0x6a, 0xd6, 0xcd, 0x69, 0xc2, 0x21, 0x69, - 0xf4, 0xe5, 0x3a, 0x24, 0xbd, 0x06, 0x23, 0xb5, 0x4e, 0x47, 0x73, 0xf0, 0xc3, 0xe1, 0x71, 0x3a, - 0x1d, 0x2e, 0x3c, 0x59, 0x28, 0xd7, 0x79, 0xc8, 0x58, 0xe7, 0xdf, 0x07, 0x58, 0xc2, 0x67, 0x08, - 0x38, 0x70, 0xe3, 0x88, 0x81, 0x1a, 0x3e, 0x7f, 0x9c, 0x80, 0x03, 0xa7, 0x5b, 0x40, 0x62, 0x64, - 0xae, 0xd8, 0x5b, 0x7b, 0x50, 0x49, 0x4f, 0x9f, 0x97, 0xb0, 0x74, 0xfd, 0x71, 0x09, 0x2e, 0x09, - 0x25, 0x27, 0xf1, 0x81, 0x9f, 0x7e, 0x76, 0xbe, 0x03, 0x13, 0x82, 0x76, 0x27, 0xfe, 0x10, 0xf8, - 0x45, 0xb6, 0x5c, 0x8c, 0xf9, 0x8a, 0x6e, 0xa0, 0x91, 0x77, 0x60, 0x14, 0xff, 0x88, 0xef, 0x6e, - 0x98, 0x64, 0xc6, 0x10, 0xb5, 0x91, 0xbc, 0xc1, 0x51, 0xa8, 0xd6, 0xd7, 0x70, 0x39, 0xaf, 0xe1, - 0x2f, 0x41, 0x2e, 0xff, 0xb4, 0x04, 0x17, 0x04, 0x7b, 0x63, 0xa9, 0x78, 0xa1, 0x5d, 0xe7, 0x14, - 0x6e, 0xc1, 0xf7, 0x61, 0x9c, 0x55, 0x28, 0xdb, 0x3d, 0x20, 0xb6, 0x56, 0x71, 0x72, 0x88, 0x4b, - 0x96, 0x9d, 0xc8, 0x11, 0x6e, 0x2e, 0xce, 0x61, 0x5b, 0x1a, 0x2f, 0x6c, 0x9d, 0xd8, 0xfa, 0x12, - 0x2e, 0x66, 0x77, 0xe1, 0x25, 0xc8, 0xe7, 0x3e, 0xcc, 0x67, 0x6c, 0x0a, 0x2f, 0xb6, 0x27, 0x7f, - 0x01, 0x17, 0x32, 0x79, 0xbd, 0x84, 0x66, 0xae, 0x32, 0x8d, 0x23, 0x7a, 0x09, 0x43, 0x68, 0x3d, - 0x84, 0xf3, 0x19, 0x9c, 0x5e, 0x42, 0x13, 0xef, 0xc1, 0x9c, 0xd2, 0xb4, 0xbf, 0x55, 0x0b, 0x37, - 0xe0, 0x12, 0x67, 0xf4, 0x72, 0x46, 0xe5, 0x01, 0x5c, 0x10, 0xec, 0x5e, 0x82, 0xf4, 0x56, 0xe1, - 0x62, 0x7c, 0xa0, 0xce, 0xd0, 0x93, 0x4e, 0xbc, 0xc8, 0x58, 0xeb, 0x70, 0x25, 0xe6, 0x94, 0xa3, - 0x34, 0x9c, 0x9c, 0x1b, 0x57, 0x07, 0xe3, 0x51, 0x7a, 0x29, 0x23, 0xfa, 0x10, 0xce, 0x19, 0x4c, - 0x5f, 0x9a, 0xaa, 0xb4, 0x06, 0xd3, 0x9c, 0xb1, 0xa9, 0x3a, 0x2f, 0xe8, 0xaa, 0xf3, 0xf8, 0xc2, - 0xd9, 0x98, 0x25, 0x82, 0xf7, 0xde, 0xca, 0xd0, 0xa6, 0x37, 0x50, 0x9b, 0x96, 0x28, 0x71, 0x0b, - 0xdf, 0x81, 0x61, 0x0e, 0x11, 0xed, 0xcb, 0x60, 0xc6, 0x0f, 0x0b, 0x9c, 0x4c, 0x20, 0x5b, 0x3f, - 0x82, 0x4b, 0xfc, 0x24, 0x1a, 0xdf, 0x25, 0x9a, 0xa7, 0xc5, 0x1f, 0x26, 0x0e, 0xa2, 0xe7, 0x05, - 0xdf, 0x24, 0x7e, 0xce, 0x79, 0xf4, 0x91, 0x9c, 0xdb, 0x79, 0xfc, 0x4f, 0xf4, 0x44, 0x4c, 0x1e, - 0x30, 0xfb, 0x33, 0x0f, 0x98, 0xd7, 0xe0, 0xaa, 0x3a, 0x60, 0x26, 0xab, 0x91, 0x53, 0xcb, 0xfa, - 0x12, 0x2e, 0xf0, 0x8e, 0x4a, 0xd7, 0x3d, 0xb3, 0x19, 0x1f, 0x26, 0xba, 0x39, 0x27, 0xba, 0x69, - 0x62, 0xe7, 0x74, 0xf2, 0xff, 0x28, 0xc9, 0x4f, 0x2e, 0x9b, 0xf9, 0x2f, 0xfb, 0xc4, 0xbd, 0x09, - 0x55, 0x25, 0x10, 0xb3, 0x45, 0x2f, 0x76, 0xdc, 0xde, 0x80, 0x59, 0x9d, 0x8d, 0xdb, 0xa4, 0x7b, - 0x77, 0xf0, 0x92, 0xe7, 0x6d, 0xf6, 0x59, 0x20, 0x40, 0x4e, 0xbb, 0x4a, 0x86, 0xdc, 0x10, 0xdf, - 0x56, 0x98, 0x56, 0x03, 0x2e, 0xa6, 0x87, 0xc2, 0x6d, 0x4a, 0xbf, 0x7d, 0xf2, 0x09, 0xfb, 0x84, - 0x11, 0x22, 0x06, 0x23, 0x97, 0xa9, 0xfc, 0x8e, 0x39, 0xb9, 0xa4, 0xb2, 0x2c, 0xb9, 0xd4, 0x24, - 0xfa, 0xcf, 0x6a, 0x97, 0xf3, 0xe1, 0xd7, 0x81, 0xc8, 0xa2, 0xa5, 0xba, 0x2d, 0xab, 0x3e, 0x0f, - 0x03, 0x4b, 0x75, 0x5b, 0x3c, 0x18, 0x42, 0x4d, 0xb0, 0x19, 0x06, 0x36, 0x83, 0x25, 0x35, 0xf2, - 0xfe, 0x13, 0x68, 0xe4, 0xf7, 0x07, 0x47, 0x07, 0xca, 0x83, 0x36, 0xa9, 0xbb, 0xfb, 0xde, 0x43, - 0x37, 0x3a, 0x50, 0x15, 0xd6, 0xac, 0xaf, 0x60, 0xda, 0xa8, 0x5e, 0x7c, 0xc5, 0x85, 0x2f, 0x9d, - 0x98, 0x3e, 0xbb, 0x54, 0x43, 0xcf, 0x17, 0x34, 0x59, 0x4c, 0xf0, 0xf5, 0xa6, 0xe9, 0x34, 0xf0, - 0x19, 0xad, 0x2d, 0x0b, 0xad, 0xbf, 0x33, 0xa8, 0x71, 0xd7, 0xde, 0x8f, 0x15, 0xf4, 0xee, 0x0e, - 0x00, 0x9f, 0x21, 0x5a, 0xe7, 0x98, 0x02, 0x38, 0x2e, 0x1c, 0x4a, 0xf8, 0x92, 0x6c, 0x6b, 0x48, - 0x27, 0x7d, 0x5f, 0x26, 0xfc, 0x7c, 0x39, 0x91, 0x7c, 0x52, 0xa9, 0xfc, 0x7c, 0x05, 0xeb, 0xd0, - 0xd6, 0x91, 0xc8, 0x8f, 0x92, 0x8f, 0x20, 0x86, 0xf0, 0x4e, 0xe9, 0x15, 0x79, 0xc9, 0x9c, 0xee, - 0xdb, 0xe9, 0xde, 0x41, 0x3c, 0x83, 0x59, 0x46, 0xeb, 0x3e, 0xc6, 0x83, 0xc5, 0xca, 0x37, 0x11, - 0xf5, 0xf8, 0xda, 0x3e, 0x8c, 0xf5, 0xbc, 0x5a, 0x50, 0x4f, 0x8c, 0x2c, 0xec, 0xef, 0x31, 0x9f, - 0x06, 0x55, 0x65, 0x76, 0x36, 0x7f, 0x9c, 0x44, 0xf6, 0xfa, 0x8a, 0xd7, 0xea, 0xf8, 0xae, 0x3a, - 0x30, 0xf1, 0x49, 0x14, 0xb4, 0x1b, 0x54, 0xc0, 0x6d, 0x1d, 0xc9, 0x7a, 0xad, 0xd0, 0x7b, 0x7c, - 0x14, 0x06, 0x77, 0x96, 0x76, 0xd6, 0xcb, 0x25, 0xeb, 0x16, 0x80, 0x56, 0x13, 0xc0, 0xf0, 0xe6, - 0x96, 0xbd, 0x51, 0x5b, 0x2f, 0xf7, 0x91, 0x59, 0x38, 0xfb, 0x70, 0x6d, 0x73, 0x79, 0xeb, 0x61, - 0xbd, 0x51, 0xdf, 0xa8, 0xd9, 0x3b, 0x4b, 0x35, 0x7b, 0xb9, 0x5c, 0xb2, 0xbe, 0x86, 0x19, 0xb3, - 0x87, 0x2f, 0x75, 0x12, 0x46, 0x30, 0xad, 0xf4, 0x99, 0xfb, 0x0f, 0x77, 0x34, 0xa7, 0x53, 0x71, - 0xf8, 0x4b, 0x3a, 0x4f, 0x89, 0x63, 0xa2, 0xf8, 0x8c, 0x34, 0x24, 0xf2, 0x06, 0x57, 0x0b, 0x92, - 0x2f, 0x84, 0x99, 0x5a, 0xd0, 0x88, 0xf5, 0x02, 0x5c, 0xfa, 0x7e, 0x00, 0x33, 0x66, 0xad, 0x27, - 0xb5, 0x52, 0xbd, 0x82, 0xde, 0xb8, 0xda, 0xf3, 0x21, 0x42, 0xf4, 0x6b, 0x03, 0xb1, 0xb2, 0xfe, - 0x00, 0xca, 0x02, 0x2b, 0xde, 0x79, 0xaf, 0x49, 0x33, 0x62, 0x29, 0xe3, 0xb1, 0xa3, 0x74, 0xfe, - 0xf6, 0xa1, 0xcc, 0x56, 0x4c, 0x41, 0xc9, 0x2b, 0x98, 0x81, 0xa1, 0xf5, 0xf8, 0x3a, 0xc7, 0xe6, - 0x3f, 0xf0, 0x15, 0x4d, 0xe4, 0x04, 0x91, 0x74, 0x55, 0x1b, 0xb3, 0xd5, 0x6f, 0xf2, 0x06, 0x0c, - 0xdf, 0x75, 0xdb, 0x91, 0x30, 0x8d, 0xc4, 0x9b, 0x3c, 0x63, 0xcb, 0x0b, 0x6c, 0x81, 0x60, 0xd9, - 0x70, 0x56, 0xab, 0xf0, 0x14, 0x4d, 0x25, 0x15, 0x18, 0xd9, 0xa4, 0xdf, 0x68, 0xf5, 0xcb, 0x9f, - 0xd6, 0xbb, 0x70, 0x56, 0xb8, 0x01, 0x6a, 0x62, 0xba, 0x2a, 0xde, 0x64, 0x97, 0x8c, 0x87, 0xa1, - 0x82, 0x25, 0x16, 0x31, 0xba, 0xdd, 0x4e, 0xeb, 0x05, 0xe9, 0xd8, 0x46, 0x71, 0x4a, 0xba, 0xd7, - 0xe5, 0x2d, 0x50, 0xaf, 0xe1, 0xfc, 0xdf, 0xfa, 0xa1, 0x92, 0xb0, 0x32, 0x2c, 0x1d, 0x38, 0xed, - 0x36, 0xf5, 0xf6, 0x29, 0xb9, 0x0e, 0x83, 0x3b, 0x5b, 0x3b, 0xdb, 0xc2, 0x4a, 0x2a, 0x1d, 0x00, - 0x18, 0x48, 0xe1, 0xd8, 0x88, 0x41, 0x1e, 0xc0, 0x59, 0xe9, 0xe8, 0xab, 0x8a, 0xc4, 0x08, 0x5d, - 0x2a, 0x76, 0x1b, 0x4e, 0xd3, 0x91, 0xb7, 0x85, 0x49, 0xe4, 0x27, 0x5d, 0x37, 0xa0, 0x2d, 0xb4, - 0xfc, 0xc4, 0xb7, 0xe9, 0x5a, 0x89, 0xad, 0xa3, 0x91, 0x1f, 0xc0, 0x44, 0xbd, 0xbe, 0x15, 0xd7, - 0x3e, 0x64, 0xdc, 0x10, 0xe9, 0x45, 0xb6, 0x81, 0xc8, 0x9f, 0xde, 0x5a, 0x7f, 0x52, 0x82, 0xb9, - 0x1c, 0x73, 0x0b, 0x79, 0xc3, 0x90, 0xc3, 0xb4, 0x26, 0x07, 0x89, 0xb2, 0xda, 0x27, 0x04, 0xb1, - 0xa4, 0xb9, 0x4d, 0x0f, 0x9c, 0xc2, 0x6d, 0x7a, 0xb5, 0x2f, 0x76, 0x95, 0x26, 0xaf, 0xc1, 0x40, - 0xbd, 0xbe, 0x25, 0xcc, 0xea, 0x24, 0xee, 0x81, 0x86, 0xcc, 0x10, 0x16, 0x01, 0x46, 0x25, 0xc8, - 0x3a, 0x03, 0x93, 0xc6, 0xc0, 0x58, 0x16, 0x4c, 0xe8, 0x2d, 0x64, 0xa3, 0xbf, 0xe4, 0xb7, 0xd4, - 0xe8, 0xb3, 0xbf, 0xad, 0x6d, 0x53, 0x66, 0xe4, 0x12, 0x80, 0xbc, 0xaf, 0x75, 0x5b, 0xf2, 0xe6, - 0x47, 0x40, 0xd6, 0x5a, 0xe4, 0x2a, 0x4c, 0x04, 0xb4, 0xe5, 0x06, 0xb4, 0x19, 0x35, 0xba, 0x81, - 0x78, 0x80, 0x62, 0x8f, 0x4b, 0xd8, 0x6e, 0xd0, 0xb6, 0x16, 0x61, 0x5c, 0x6b, 0x68, 0x2f, 0x86, - 0x33, 0x30, 0xa4, 0x1b, 0x1e, 0xf9, 0x0f, 0xeb, 0xf7, 0x4a, 0x30, 0x83, 0x23, 0xbb, 0xef, 0xb2, - 0x15, 0x3f, 0x6e, 0xde, 0x82, 0x31, 0x0e, 0x17, 0x8d, 0x71, 0x48, 0xe0, 0xaa, 0x01, 0xf9, 0x20, - 0x35, 0x20, 0x17, 0xb3, 0x06, 0x04, 0xbf, 0x6a, 0xd7, 0xf7, 0xf4, 0x71, 0xd0, 0x6f, 0xe0, 0xfe, - 0xa0, 0x04, 0xd3, 0x5a, 0x9b, 0x54, 0x07, 0xef, 0x18, 0x4d, 0xba, 0x90, 0xd1, 0xa4, 0xd4, 0x14, - 0x59, 0x4c, 0xb5, 0xe8, 0x95, 0xa2, 0x16, 0x65, 0xcd, 0x10, 0x63, 0xe4, 0xff, 0xaa, 0x04, 0xb3, - 0x99, 0x32, 0x20, 0xe7, 0x98, 0x4a, 0xdf, 0x0c, 0x68, 0x24, 0x24, 0x2f, 0x7e, 0x31, 0xf8, 0x5a, - 0x18, 0x76, 0x69, 0x20, 0xe4, 0x2e, 0x7e, 0x91, 0x57, 0x60, 0x72, 0x9b, 0x06, 0xae, 0xdf, 0xe2, - 0xcf, 0x01, 0xb8, 0x9f, 0xed, 0xa4, 0x6d, 0x02, 0xc9, 0x45, 0x18, 0x53, 0x7e, 0xa2, 0xdc, 0x2c, - 0x6b, 0xc7, 0x00, 0xc6, 0x7b, 0xd9, 0xdd, 0xe7, 0x77, 0x39, 0x8c, 0x58, 0xfc, 0x62, 0x6b, 0xaa, - 0x34, 0x92, 0x0e, 0xf3, 0x35, 0x55, 0x5a, 0x40, 0xcf, 0xc1, 0xf0, 0x67, 0x36, 0x4e, 0x4d, 0x0c, - 0xd7, 0x60, 0x8b, 0x5f, 0x64, 0x0a, 0x1d, 0xba, 0xf1, 0x49, 0x09, 0x3a, 0x72, 0x7f, 0x00, 0x33, - 0x59, 0x72, 0xcd, 0x9a, 0xd8, 0x82, 0xb6, 0x5f, 0xd1, 0x7e, 0x09, 0xd3, 0xb5, 0x56, 0x6b, 0xe3, - 0x6e, 0x8d, 0xbb, 0x5a, 0x88, 0x51, 0xe5, 0x9f, 0x3e, 0x37, 0x53, 0x0a, 0x4d, 0x75, 0x70, 0xcd, - 0x73, 0x23, 0x7b, 0x7a, 0xe5, 0x1b, 0x37, 0x8c, 0x5c, 0x6f, 0x5f, 0xb3, 0xa5, 0xda, 0xe7, 0x36, - 0xe9, 0xb3, 0x8c, 0x29, 0xc0, 0x94, 0x08, 0x93, 0x37, 0x87, 0x67, 0x30, 0x9f, 0xd1, 0xd8, 0xc6, - 0xab, 0xd1, 0x9c, 0xc9, 0x37, 0x2e, 0x18, 0xa8, 0x35, 0x9f, 0x58, 0x3f, 0x80, 0x73, 0x7c, 0x25, - 0x2f, 0x6a, 0xbc, 0x68, 0xb6, 0x6e, 0xfa, 0xb5, 0xde, 0x93, 0xc6, 0x99, 0xc2, 0x96, 0xd9, 0x13, - 0x46, 0x5b, 0xb0, 0xca, 0xff, 0x58, 0x82, 0xf9, 0x04, 0x69, 0xfd, 0xb9, 0xd7, 0x94, 0xdb, 0xc8, - 0x6b, 0x49, 0x87, 0x79, 0x54, 0x7f, 0xb8, 0xcd, 0xd3, 0x6d, 0x29, 0x9f, 0x79, 0x72, 0x0b, 0x80, - 0x13, 0x6b, 0x5a, 0x0b, 0x5a, 0xfc, 0x85, 0x6f, 0x11, 0xea, 0x2d, 0x1a, 0x0a, 0xe9, 0x42, 0x96, - 0xdc, 0xc5, 0x37, 0xd2, 0xcb, 0x24, 0x8e, 0x21, 0x4a, 0xa8, 0x20, 0x6f, 0xe4, 0xd8, 0xc6, 0xb3, - 0xf8, 0x5b, 0xff, 0xe7, 0x00, 0xcc, 0xe9, 0x03, 0xf8, 0x22, 0x7d, 0xdd, 0x86, 0xf1, 0x25, 0xdf, - 0x8b, 0xe8, 0x37, 0x91, 0x16, 0x22, 0x82, 0x28, 0x07, 0x03, 0x55, 0x22, 0x34, 0x66, 0x0e, 0x68, - 0x30, 0xf5, 0xcd, 0xf0, 0x91, 0x8c, 0x11, 0xc9, 0x12, 0x4c, 0x6e, 0xd2, 0x67, 0x29, 0x01, 0xa2, - 0x9f, 0xa6, 0x47, 0x9f, 0x35, 0x34, 0x21, 0xea, 0xce, 0x73, 0x06, 0x0d, 0x79, 0x04, 0x53, 0x72, - 0x72, 0x19, 0xc2, 0x9c, 0xd7, 0x37, 0x53, 0x73, 0x3a, 0xf3, 0x10, 0x0a, 0xac, 0x86, 0x1c, 0x19, - 0x26, 0x38, 0xb2, 0xae, 0xf3, 0x1a, 0x79, 0x54, 0x00, 0x73, 0xb7, 0xd6, 0x4a, 0x0c, 0x2f, 0xd8, - 0x64, 0x34, 0x00, 0x9d, 0x85, 0xb5, 0x0d, 0x95, 0xf4, 0x78, 0x88, 0xda, 0xde, 0x86, 0x61, 0x0e, - 0x15, 0xda, 0x8f, 0x8c, 0xfe, 0xa3, 0xb0, 0xb9, 0x79, 0x82, 0x57, 0x63, 0x0b, 0x5c, 0x6b, 0x15, - 0x4d, 0x46, 0x0a, 0x47, 0xe9, 0x9f, 0xb7, 0x93, 0xc3, 0x8b, 0x0e, 0xc6, 0x72, 0x78, 0x75, 0xf7, - 0x1a, 0xf9, 0x10, 0x64, 0x09, 0xad, 0x6e, 0x3a, 0x27, 0xd1, 0xb0, 0x1b, 0x30, 0x22, 0x40, 0x89, - 0xb8, 0x44, 0xf1, 0xe7, 0x27, 0x11, 0xac, 0x0f, 0xe0, 0x3c, 0x9a, 0x00, 0x5d, 0x6f, 0xbf, 0x4d, - 0x77, 0x43, 0xe3, 0x29, 0x47, 0xaf, 0xcf, 0xfa, 0x23, 0x98, 0xcf, 0xa2, 0xed, 0xf9, 0x65, 0xf3, - 0x48, 0x21, 0x7f, 0xd1, 0x0f, 0x33, 0x6b, 0xa1, 0xae, 0x43, 0xa9, 0x68, 0x21, 0x19, 0x11, 0x2c, - 0x50, 0x26, 0xab, 0x7d, 0x59, 0x11, 0x2a, 0xde, 0xd6, 0x5e, 0x8a, 0xf6, 0x17, 0x85, 0xa6, 0x60, - 0xdb, 0x96, 0x7a, 0x2b, 0xfa, 0x1a, 0x0c, 0x6e, 0xb2, 0xa5, 0x7a, 0x40, 0x8c, 0x1d, 0xa7, 0x60, - 0x20, 0x7c, 0xa9, 0xc9, 0xb6, 0x48, 0xf6, 0x83, 0xdc, 0x4d, 0xbd, 0x07, 0x1d, 0xec, 0x1d, 0x7a, - 0x61, 0xb5, 0x2f, 0xf5, 0x34, 0xf4, 0x5d, 0x18, 0xaf, 0xb5, 0x0e, 0xb9, 0x23, 0xa4, 0xef, 0x25, - 0x3e, 0x4b, 0xad, 0x64, 0xb5, 0xcf, 0xd6, 0x11, 0xd9, 0xc1, 0xbe, 0xd6, 0xe9, 0xe0, 0x46, 0x95, - 0x15, 0x8e, 0x82, 0xe9, 0x5f, 0xb5, 0x4e, 0x67, 0x71, 0x14, 0x86, 0x77, 0x9c, 0x60, 0x9f, 0x46, - 0xd6, 0x97, 0x30, 0x2f, 0x7c, 0x73, 0xb8, 0xc1, 0x13, 0x3d, 0x78, 0xc2, 0xd8, 0xfd, 0xaa, 0xc8, - 0x9f, 0xe6, 0x32, 0x00, 0x1e, 0x6f, 0xd6, 0xbc, 0x16, 0xfd, 0x46, 0x38, 0x07, 0x6a, 0x10, 0xeb, - 0x1d, 0x18, 0x53, 0x12, 0x42, 0x1d, 0x5e, 0xdb, 0xec, 0x50, 0x5a, 0x33, 0xc6, 0x03, 0x58, 0xf9, - 0xea, 0xf5, 0xbc, 0xd1, 0x77, 0x11, 0x60, 0x86, 0x2b, 0xfd, 0x2e, 0xcc, 0x26, 0x26, 0x41, 0x1c, - 0xbf, 0x40, 0xa9, 0xdd, 0xdc, 0x7b, 0x51, 0xfd, 0x4e, 0x6a, 0xe5, 0xfd, 0x27, 0xd2, 0xca, 0xad, - 0xbf, 0xdf, 0x8f, 0xe7, 0xc5, 0x94, 0x3c, 0x12, 0xa6, 0x37, 0xdd, 0xfc, 0xb7, 0x08, 0x63, 0xd8, - 0xfb, 0x65, 0xf9, 0x4c, 0xaf, 0xd8, 0xb5, 0x64, 0xf4, 0x67, 0x47, 0xd5, 0x3e, 0xf4, 0x27, 0x89, - 0xc9, 0xc8, 0xc7, 0x30, 0xb2, 0xe2, 0xb5, 0x90, 0xc3, 0xc0, 0x29, 0x38, 0x48, 0x22, 0x36, 0x26, - 0xd8, 0xe4, 0x1d, 0xf6, 0x09, 0x73, 0x8b, 0x8d, 0xad, 0x41, 0xe2, 0x83, 0xeb, 0x50, 0xde, 0xc1, - 0x75, 0x38, 0x71, 0x70, 0xb5, 0x60, 0x68, 0x2b, 0x68, 0x89, 0xb0, 0x30, 0x53, 0x0b, 0x13, 0x42, - 0x70, 0x08, 0xb3, 0x79, 0x91, 0xf5, 0x9f, 0x4b, 0x30, 0x77, 0x8f, 0x46, 0x99, 0x73, 0xc8, 0x90, - 0x4a, 0xe9, 0x5b, 0x4b, 0xa5, 0xff, 0x45, 0xa4, 0xa2, 0x7a, 0x3d, 0x90, 0xd7, 0xeb, 0xc1, 0xbc, - 0x5e, 0x0f, 0xe5, 0xf7, 0xfa, 0x1e, 0x0c, 0xf3, 0xae, 0xb2, 0xc3, 0xf9, 0x5a, 0x44, 0x0f, 0xe3, - 0xc3, 0xb9, 0xee, 0x18, 0x67, 0xf3, 0x32, 0xa6, 0x48, 0xae, 0x3b, 0xa1, 0x7e, 0x38, 0x17, 0x3f, - 0xad, 0x1f, 0xe3, 0x03, 0xdf, 0x75, 0xbf, 0xf9, 0x44, 0x33, 0xf2, 0x8e, 0xf0, 0x2f, 0x34, 0x79, - 0x29, 0xc0, 0xb0, 0x78, 0x89, 0x2d, 0x31, 0xc8, 0x15, 0x18, 0x5f, 0xf3, 0xee, 0xfa, 0x41, 0x93, - 0x6e, 0x79, 0x6d, 0xce, 0x7d, 0xd4, 0xd6, 0x41, 0xc2, 0xf8, 0x21, 0x6a, 0x88, 0x2d, 0x0a, 0x08, - 0x48, 0x58, 0x14, 0x18, 0x6c, 0x6f, 0xc1, 0xe6, 0x65, 0xc2, 0xb6, 0xc2, 0xfe, 0x2e, 0x3a, 0x8c, - 0xab, 0x53, 0x7b, 0x2f, 0xc4, 0x47, 0x70, 0xde, 0xa6, 0x9d, 0xb6, 0xc3, 0x74, 0xba, 0x43, 0x9f, - 0xe3, 0xab, 0x3e, 0x5f, 0xc9, 0x78, 0x9c, 0x67, 0xba, 0x49, 0xa8, 0x26, 0xf7, 0x17, 0x34, 0xf9, - 0x10, 0xae, 0xde, 0xa3, 0x91, 0xb9, 0xa0, 0xc6, 0x26, 0x64, 0xd1, 0xf9, 0x55, 0x18, 0x0d, 0x4d, - 0xf3, 0xb7, 0x7c, 0x6c, 0x96, 0x49, 0xb8, 0xf7, 0x96, 0xbc, 0x20, 0x12, 0x7c, 0xd4, 0x5f, 0xd6, - 0x27, 0x50, 0xcd, 0xab, 0xee, 0x64, 0x5e, 0xac, 0x2e, 0x5c, 0xc9, 0x67, 0x20, 0x9a, 0xbb, 0x02, - 0xd2, 0x54, 0x2e, 0x3e, 0xa1, 0x5e, 0xad, 0x35, 0xad, 0xeb, 0xe2, 0x0f, 0x6b, 0x51, 0xfa, 0xf3, - 0x7d, 0x8b, 0xe6, 0x36, 0xf0, 0x16, 0xda, 0x64, 0x10, 0xcb, 0xb5, 0x06, 0xa3, 0x12, 0x26, 0xe4, - 0x3a, 0x97, 0xd9, 0x52, 0x29, 0xd0, 0x96, 0x64, 0xa0, 0xc8, 0xac, 0x1f, 0xcb, 0x1b, 0x19, 0x93, - 0xe2, 0x64, 0xaf, 0x55, 0x4f, 0x72, 0x05, 0x63, 0xf9, 0x70, 0xde, 0xe4, 0xad, 0x5b, 0xda, 0xcb, - 0x9a, 0xa5, 0x9d, 0x1b, 0xd8, 0xaf, 0x98, 0x96, 0x5f, 0x61, 0x3c, 0xd0, 0x40, 0xe4, 0xb2, 0x6e, - 0x4f, 0x9f, 0x48, 0x3f, 0x7f, 0xbd, 0x0d, 0xf3, 0x59, 0x15, 0x6a, 0xe7, 0x40, 0x65, 0xb4, 0x15, - 0xfa, 0xce, 0x32, 0x5c, 0x96, 0x81, 0x99, 0x7c, 0x3f, 0x0a, 0xa3, 0xc0, 0xe9, 0xd4, 0x9b, 0x81, - 0xdb, 0x89, 0xa9, 0x2c, 0x18, 0xe6, 0x10, 0x21, 0x09, 0x7e, 0xbb, 0xc5, 0x71, 0x44, 0x89, 0xf5, - 0x9b, 0x25, 0xb0, 0x0c, 0xd7, 0x2b, 0x1c, 0xe7, 0xed, 0xc0, 0x7f, 0xea, 0xb6, 0xb4, 0x1b, 0xa5, - 0x37, 0x0c, 0x6b, 0x26, 0x7f, 0x09, 0x98, 0xf4, 0xfa, 0x16, 0x6b, 0xe6, 0xed, 0x84, 0x85, 0x91, - 0x2b, 0x9e, 0xe8, 0x8e, 0x65, 0x46, 0xc0, 0x51, 0x96, 0xc7, 0xff, 0x5a, 0x82, 0x6b, 0x85, 0x6d, - 0x10, 0xfd, 0x79, 0x04, 0xe5, 0x64, 0x99, 0x98, 0x41, 0x55, 0xcd, 0x15, 0x23, 0xcd, 0x61, 0xef, - 0x0e, 0x77, 0x2d, 0x97, 0x2e, 0x4b, 0x1d, 0xc5, 0x39, 0xc5, 0xef, 0xf4, 0xad, 0x27, 0xef, 0x03, - 0xec, 0xf8, 0x91, 0xd3, 0x5e, 0x42, 0x03, 0xc0, 0x40, 0xfc, 0x4c, 0x20, 0x62, 0xd0, 0x46, 0x32, - 0xc2, 0x84, 0x86, 0x6c, 0x7d, 0x8a, 0xdf, 0x75, 0x76, 0xa3, 0x4f, 0xf6, 0xa9, 0x2d, 0xc1, 0xb5, - 0x84, 0x3b, 0xc0, 0x0b, 0x30, 0x89, 0x60, 0x96, 0x89, 0x9f, 0xe9, 0xde, 0xf7, 0x02, 0xbf, 0xdb, - 0xf9, 0xe5, 0x8c, 0xfa, 0x9f, 0x96, 0xb8, 0x7f, 0xa6, 0x5e, 0xad, 0x18, 0xe8, 0x25, 0x80, 0x18, - 0x9a, 0xf0, 0xd3, 0x57, 0x05, 0x7b, 0x77, 0xf8, 0x91, 0x1b, 0x2f, 0x0a, 0xf6, 0x39, 0x03, 0x8d, - 0xec, 0x97, 0x3b, 0x92, 0x6f, 0xa1, 0x0f, 0x80, 0xaa, 0xfd, 0x64, 0x72, 0x7f, 0x57, 0xda, 0x3f, - 0x4e, 0x49, 0x77, 0x00, 0x33, 0x6c, 0x05, 0xa8, 0x75, 0xa3, 0x03, 0x3f, 0x70, 0x23, 0xf9, 0xe2, - 0x84, 0x6c, 0x8b, 0x77, 0xf8, 0x9c, 0xea, 0xa3, 0x5f, 0x1c, 0x55, 0xdf, 0x3b, 0x4d, 0xc8, 0x4c, - 0xc9, 0x73, 0x47, 0xbd, 0xdd, 0xb7, 0xe6, 0x60, 0x60, 0xc9, 0x5e, 0xc7, 0x05, 0xcf, 0x5e, 0x57, - 0x0b, 0x9e, 0xbd, 0x6e, 0xfd, 0x75, 0x3f, 0x54, 0x79, 0xa4, 0x10, 0x74, 0x1d, 0x89, 0xad, 0x16, - 0x9a, 0x2f, 0xca, 0x49, 0x0d, 0x0c, 0x89, 0x48, 0x20, 0xfd, 0x27, 0x89, 0x04, 0xf2, 0x6b, 0x90, - 0x63, 0xb2, 0x3a, 0x81, 0x15, 0xe0, 0xf5, 0xe3, 0xa3, 0xea, 0xb5, 0xd8, 0x0a, 0xc0, 0x4b, 0xb3, - 0xcc, 0x01, 0x39, 0x55, 0xa4, 0xed, 0x17, 0x83, 0x2f, 0x60, 0xbf, 0xb8, 0x0d, 0x23, 0x78, 0x98, - 0x59, 0xdb, 0x16, 0xce, 0x9c, 0x38, 0x3d, 0x31, 0xb8, 0x4f, 0xc3, 0xd5, 0x23, 0xe9, 0x49, 0x34, - 0xeb, 0xf7, 0xfb, 0xe1, 0x4a, 0xbe, 0xcc, 0x45, 0xdb, 0x96, 0x01, 0x62, 0xa7, 0x95, 0x22, 0x27, - 0x19, 0xfc, 0x76, 0x9e, 0xd1, 0x47, 0xca, 0x49, 0x4d, 0xa3, 0x63, 0xba, 0x8f, 0x7c, 0xdf, 0x9c, - 0xb8, 0x21, 0x31, 0x9e, 0x3d, 0x8b, 0x40, 0xb0, 0x02, 0x64, 0x04, 0x82, 0x15, 0x30, 0xf2, 0x08, - 0xe6, 0xb6, 0x03, 0xf7, 0xa9, 0x13, 0xd1, 0x07, 0xf4, 0x39, 0x7f, 0xff, 0xb3, 0x22, 0x1e, 0xfd, - 0xf0, 0x47, 0xeb, 0xd7, 0x8f, 0x8f, 0xaa, 0xaf, 0x74, 0x38, 0x0a, 0x06, 0xfb, 0xe2, 0x2f, 0x2e, - 0x1b, 0xe9, 0x77, 0x40, 0x79, 0x8c, 0xac, 0x7f, 0x51, 0x82, 0x0b, 0xa8, 0x96, 0x0b, 0xb3, 0xab, - 0xac, 0xfc, 0x85, 0x7c, 0x25, 0xf5, 0x0e, 0x8a, 0xb9, 0x88, 0xbe, 0x92, 0xc6, 0xfb, 0x6f, 0xdb, - 0x40, 0x23, 0x6b, 0x30, 0x2e, 0x7e, 0xe3, 0xf7, 0x37, 0x80, 0x07, 0x82, 0x59, 0x6d, 0xc1, 0xc2, - 0xa9, 0xce, 0x4d, 0x45, 0x38, 0xb1, 0x05, 0x33, 0x7c, 0x26, 0x69, 0xeb, 0xb4, 0xd6, 0xcf, 0xfb, - 0xe1, 0xe2, 0x1e, 0x0d, 0xdc, 0xc7, 0xcf, 0x73, 0x3a, 0xb3, 0x05, 0x33, 0x12, 0xc4, 0xa3, 0x85, - 0x18, 0x9f, 0x18, 0x0f, 0x05, 0x29, 0x9b, 0x2a, 0xc2, 0x8d, 0xc8, 0x2f, 0x2e, 0x93, 0xf0, 0x14, - 0x5e, 0x90, 0x6f, 0xc3, 0x68, 0x22, 0x5e, 0x0f, 0x8e, 0xbf, 0xfc, 0x42, 0xe3, 0xa1, 0x5a, 0xed, - 0xb3, 0x15, 0x26, 0xf9, 0xed, 0xfc, 0xdb, 0x27, 0x61, 0xfa, 0xe8, 0x65, 0xff, 0xc4, 0x0f, 0x96, - 0x7d, 0xac, 0x8e, 0x56, 0x9a, 0xf1, 0xc1, 0xae, 0xf6, 0xd9, 0x79, 0x35, 0x2d, 0x8e, 0xc3, 0x58, - 0x0d, 0xaf, 0xe2, 0xd8, 0xc9, 0xfd, 0xbf, 0xf4, 0xc3, 0x65, 0xf9, 0x96, 0x27, 0x47, 0xcc, 0x9f, - 0xc3, 0x9c, 0x04, 0xd5, 0x3a, 0x4c, 0x61, 0xa0, 0x2d, 0x53, 0xd2, 0x3c, 0x1c, 0xab, 0x94, 0xb4, - 0x23, 0x70, 0x62, 0x61, 0xe7, 0x91, 0xbf, 0x1c, 0xeb, 0xe7, 0xc7, 0x59, 0xd1, 0x93, 0xd0, 0x0a, - 0xa9, 0xaf, 0x99, 0x86, 0x68, 0x8c, 0xf5, 0xb3, 0x95, 0xb2, 0x9e, 0x0e, 0x7e, 0x5b, 0xeb, 0xe9, - 0x6a, 0x5f, 0xd2, 0x7e, 0xba, 0x38, 0x05, 0x13, 0x9b, 0xf4, 0x59, 0x2c, 0xf7, 0xff, 0xb5, 0x94, - 0x08, 0xb0, 0xc0, 0x34, 0x0c, 0x1e, 0x69, 0xa1, 0x14, 0x07, 0xe0, 0xc1, 0x00, 0x0b, 0xba, 0x86, - 0xc1, 0x51, 0xd7, 0x60, 0x84, 0xdf, 0x4f, 0xb7, 0x4e, 0x70, 0xc2, 0x57, 0x8f, 0x72, 0xf8, 0x4b, - 0xc9, 0x16, 0x3f, 0xec, 0x0b, 0x7a, 0xeb, 0x01, 0x5c, 0x15, 0x6e, 0xdb, 0xe6, 0xe0, 0x63, 0x45, - 0xa7, 0xdc, 0xbe, 0x2c, 0x07, 0x2e, 0xdf, 0xa3, 0xc9, 0xa5, 0xc7, 0x78, 0xb4, 0xf4, 0x09, 0x9c, - 0x31, 0xe0, 0x8a, 0x23, 0x6a, 0xa5, 0x6a, 0x0e, 0x29, 0xd6, 0x49, 0x6c, 0xeb, 0x4a, 0x56, 0x15, - 0x7a, 0x63, 0x2d, 0x8a, 0x71, 0x55, 0x83, 0xf8, 0x8a, 0x2d, 0x3c, 0xc5, 0xaa, 0x77, 0x5d, 0xfb, - 0xae, 0xf9, 0x8a, 0xc7, 0x03, 0xef, 0xc9, 0x9d, 0x57, 0x95, 0x5a, 0x93, 0xc6, 0x5d, 0x80, 0x35, - 0x05, 0x13, 0xb2, 0xa8, 0x4d, 0xc3, 0xd0, 0xfa, 0x77, 0x43, 0x60, 0x09, 0xc1, 0x66, 0x5d, 0xba, - 0x4b, 0x79, 0x3c, 0x4a, 0x35, 0x56, 0x6c, 0x54, 0xe7, 0xf4, 0x70, 0x9e, 0x71, 0x29, 0x9f, 0x79, - 0xa8, 0xe7, 0x35, 0x63, 0xa8, 0x31, 0xf3, 0x52, 0xbd, 0xff, 0x2a, 0x67, 0x99, 0xe4, 0x1f, 0xdb, - 0xab, 0xc7, 0x47, 0xd5, 0xab, 0x39, 0xcb, 0xa4, 0xc1, 0x37, 0x7b, 0xc9, 0xb4, 0xcd, 0x2b, 0x91, - 0x81, 0x17, 0xb9, 0x12, 0x61, 0x5f, 0xa4, 0x7e, 0x29, 0xb2, 0x6b, 0xca, 0x52, 0x7c, 0x8f, 0xf2, - 0x42, 0x5e, 0x2f, 0x12, 0x71, 0x0e, 0x34, 0x88, 0xc1, 0xd5, 0x60, 0x43, 0x5c, 0x28, 0x6b, 0x36, - 0xcb, 0xa5, 0x03, 0xda, 0x7c, 0x22, 0x6c, 0xc5, 0xf2, 0x42, 0x37, 0xcb, 0x66, 0xce, 0x43, 0x3b, - 0xf3, 0xef, 0x9c, 0x17, 0x34, 0x9a, 0x8c, 0x54, 0x8f, 0xd3, 0x90, 0x64, 0x4b, 0x7e, 0x0a, 0xd3, - 0x6a, 0xa8, 0x13, 0x5e, 0x57, 0xe3, 0x0b, 0xaf, 0xc4, 0x51, 0x40, 0x0f, 0x1f, 0x3b, 0x37, 0x9f, - 0xde, 0xb9, 0x99, 0x81, 0xcb, 0x9f, 0xff, 0x37, 0x65, 0x81, 0xe6, 0x72, 0xa5, 0x5f, 0x74, 0x65, - 0x10, 0x92, 0x2f, 0x60, 0xa6, 0x5e, 0xdf, 0xe2, 0xef, 0x33, 0x6c, 0x79, 0x67, 0x6f, 0xaf, 0x0b, - 0x1f, 0x2c, 0x1c, 0xee, 0x30, 0xf4, 0x1b, 0xe2, 0x5d, 0x87, 0x7e, 0xd3, 0xaf, 0x07, 0x40, 0xc8, - 0x62, 0xa1, 0xdf, 0x94, 0xff, 0xdf, 0xea, 0xf9, 0x01, 0x53, 0x45, 0xdc, 0x36, 0x15, 0xef, 0x88, - 0xe4, 0xc4, 0xce, 0xb9, 0xe5, 0x2b, 0x7d, 0xc7, 0xb7, 0x7c, 0xff, 0xa8, 0x5f, 0x3e, 0xba, 0x48, - 0x5f, 0xb4, 0x9e, 0xfa, 0xb2, 0x2f, 0xb3, 0x07, 0x27, 0xda, 0xa7, 0x33, 0x1b, 0x47, 0x16, 0xe5, - 0x55, 0xa9, 0x0a, 0x11, 0x36, 0xa5, 0xae, 0x1d, 0xe2, 0x02, 0xe3, 0xf6, 0x14, 0xb5, 0x22, 0x8d, - 0x2a, 0x79, 0x0f, 0x37, 0xf0, 0xed, 0xef, 0xe1, 0xfe, 0xc9, 0x18, 0x9c, 0xdd, 0x76, 0xf6, 0x5d, - 0x8f, 0xed, 0x07, 0x36, 0x0d, 0xfd, 0x6e, 0xd0, 0xa4, 0xa4, 0x06, 0x53, 0xa6, 0x47, 0x6d, 0x0f, - 0x7f, 0x61, 0xb6, 0xe5, 0x99, 0x30, 0xb2, 0x00, 0x63, 0xea, 0x15, 0xaf, 0xd8, 0xa7, 0x32, 0x5e, - 0xf7, 0xae, 0xf6, 0xd9, 0x31, 0x1a, 0x79, 0xdf, 0xb8, 0x3a, 0x3a, 0xa3, 0x1e, 0xa4, 0x23, 0xee, - 0x02, 0x77, 0x79, 0xf4, 0xfc, 0x96, 0xb9, 0xd7, 0xf2, 0xfb, 0x91, 0x1f, 0xa7, 0x6e, 0x93, 0x86, - 0x8c, 0x16, 0xa7, 0x4c, 0x6a, 0xa8, 0x66, 0xe4, 0x86, 0xed, 0xce, 0xb8, 0x67, 0xfa, 0x12, 0xc6, - 0x1f, 0x74, 0x1f, 0x51, 0x79, 0x6f, 0x36, 0x2c, 0xb6, 0xde, 0xa4, 0x9f, 0xb8, 0x28, 0xdf, 0x7b, - 0x8b, 0x8f, 0xc1, 0x93, 0xee, 0x23, 0x9a, 0x8e, 0x07, 0xcf, 0xd6, 0x3c, 0x8d, 0x19, 0x39, 0x80, - 0x72, 0xd2, 0xa5, 0x5b, 0x04, 0xd5, 0x2b, 0x70, 0x44, 0xc7, 0xe0, 0x28, 0x5a, 0xd4, 0x79, 0xee, - 0x68, 0x6a, 0x54, 0x92, 0xe2, 0x4a, 0x7e, 0x1d, 0x66, 0x33, 0x0d, 0x9a, 0xea, 0x51, 0x5a, 0xb1, - 0xad, 0x14, 0x17, 0x90, 0x84, 0xd4, 0xe4, 0x0b, 0x38, 0xa3, 0xe6, 0xec, 0x5a, 0x48, 0x0b, 0xce, - 0x24, 0x5c, 0x95, 0x45, 0x6a, 0x8d, 0x7c, 0xe7, 0x67, 0xdc, 0xf3, 0x64, 0x74, 0xda, 0xcc, 0xba, - 0x92, 0x2c, 0xc9, 0x3a, 0x8c, 0x29, 0x4b, 0x82, 0x88, 0x67, 0x96, 0x65, 0x35, 0xa9, 0x1c, 0x1f, - 0x55, 0x67, 0x62, 0xab, 0x89, 0xc1, 0x33, 0x66, 0x40, 0x7e, 0x03, 0xae, 0xaa, 0x29, 0xba, 0x15, - 0x64, 0xdb, 0x97, 0x44, 0x54, 0xfb, 0x1b, 0xc9, 0x19, 0x9e, 0x87, 0xbf, 0x77, 0x67, 0xb1, 0xbf, - 0x52, 0x5a, 0xed, 0xb3, 0x7b, 0xb3, 0x26, 0xbf, 0x55, 0x82, 0x73, 0x39, 0xb5, 0x4e, 0x60, 0xad, - 0x3d, 0x8d, 0x7e, 0x78, 0x6e, 0xc0, 0x87, 0x58, 0x6e, 0x2b, 0x7e, 0xb0, 0x28, 0xad, 0x7f, 0x46, - 0xbf, 0x73, 0x6a, 0x22, 0x6f, 0xc2, 0x30, 0x1e, 0xbf, 0xc3, 0xca, 0x24, 0x2a, 0xa8, 0x18, 0x13, - 0x08, 0x0f, 0xe9, 0xfa, 0x96, 0x24, 0x70, 0xc8, 0x2a, 0x53, 0xf4, 0x70, 0x4b, 0x94, 0x8a, 0x99, - 0x88, 0x20, 0x26, 0x0e, 0x0b, 0xbc, 0x48, 0xc6, 0x0d, 0x31, 0xd2, 0x17, 0x98, 0x64, 0x8b, 0x00, - 0xa3, 0x81, 0x58, 0x95, 0xee, 0x0f, 0x8e, 0x0e, 0x96, 0x87, 0xf8, 0x87, 0x23, 0x7d, 0xe0, 0x7f, - 0x67, 0x94, 0x3f, 0x98, 0xdd, 0xf5, 0xdc, 0xc7, 0x6e, 0xbc, 0x80, 0xe9, 0x86, 0xbb, 0x38, 0x8f, - 0x90, 0x50, 0xab, 0x73, 0x32, 0x06, 0x29, 0x1b, 0x5f, 0x7f, 0x4f, 0x1b, 0xdf, 0x5b, 0xda, 0x6d, - 0x98, 0x16, 0x29, 0x94, 0xab, 0x4f, 0xa6, 0x4d, 0x2d, 0xbe, 0x26, 0xfb, 0x1a, 0x86, 0x31, 0xb8, - 0x27, 0xbf, 0x6a, 0x1c, 0x5f, 0xb8, 0x29, 0x96, 0xed, 0x82, 0xe6, 0xf3, 0x68, 0xa0, 0xe2, 0x11, - 0x3c, 0x97, 0x38, 0x02, 0x0c, 0x89, 0x23, 0x84, 0xec, 0xc0, 0xf4, 0x36, 0xdb, 0xcd, 0xb9, 0x27, - 0x76, 0x27, 0x10, 0x76, 0x0f, 0x6e, 0x51, 0x41, 0x6d, 0xa2, 0x23, 0x8b, 0x1b, 0x54, 0x95, 0xeb, - 0x1b, 0x6a, 0x06, 0x39, 0x59, 0x81, 0xa9, 0x3a, 0x75, 0x82, 0xe6, 0xc1, 0x03, 0xfa, 0x9c, 0x69, - 0x52, 0x46, 0xea, 0x8c, 0x10, 0x4b, 0x58, 0x7f, 0xb1, 0x48, 0x77, 0x1f, 0x31, 0x89, 0xc8, 0xa7, - 0x30, 0x5c, 0xf7, 0x83, 0x68, 0xf1, 0xb9, 0x58, 0xd4, 0xe4, 0x65, 0x14, 0x07, 0x2e, 0x9e, 0x97, - 0xe9, 0x43, 0x42, 0x3f, 0x88, 0x1a, 0x8f, 0x8c, 0x20, 0x53, 0x1c, 0x85, 0x3c, 0x87, 0x19, 0x73, - 0x41, 0x11, 0x0e, 0xc2, 0xa3, 0x42, 0x83, 0xcb, 0x5a, 0xb5, 0x38, 0xca, 0xe2, 0x75, 0xc1, 0xfd, - 0x4a, 0x72, 0xd9, 0x7a, 0x8c, 0xe5, 0xba, 0xda, 0x93, 0x45, 0x4f, 0x36, 0x30, 0xef, 0x0a, 0xef, - 0x51, 0x2d, 0xe4, 0x8e, 0xc5, 0x63, 0x71, 0x18, 0xb3, 0x2e, 0x2e, 0x4a, 0x28, 0x09, 0x27, 0x4c, - 0x26, 0xeb, 0xb1, 0x53, 0xa4, 0x64, 0x1b, 0xce, 0xee, 0x86, 0x74, 0x3b, 0xa0, 0x4f, 0x5d, 0xfa, - 0x4c, 0xf2, 0x83, 0x38, 0xe6, 0x13, 0xe3, 0xd7, 0xe1, 0xa5, 0x59, 0x0c, 0xd3, 0xc4, 0xe4, 0x7d, - 0x80, 0x6d, 0xd7, 0xf3, 0x68, 0x0b, 0x6f, 0x34, 0xc7, 0x91, 0x15, 0x5a, 0x6b, 0x3b, 0x08, 0x6d, - 0xf8, 0x5e, 0x5b, 0x17, 0xa9, 0x86, 0x4c, 0x16, 0x61, 0x72, 0xcd, 0x6b, 0xb6, 0xbb, 0xc2, 0xf3, - 0x20, 0xc4, 0x05, 0x45, 0xc4, 0xa2, 0x73, 0x79, 0x41, 0x23, 0xf5, 0x91, 0x9b, 0x24, 0xe4, 0x01, - 0x10, 0x01, 0x10, 0xb3, 0xd6, 0x79, 0xd4, 0xa6, 0xe2, 0x73, 0x47, 0x2b, 0x8c, 0x64, 0x84, 0xd3, - 0xdd, 0x08, 0xf1, 0x96, 0x22, 0x9b, 0x7f, 0x1f, 0xc6, 0xb5, 0x39, 0x9f, 0x11, 0xd5, 0x61, 0x46, - 0x8f, 0xea, 0x30, 0xa6, 0x47, 0x6f, 0xf8, 0xff, 0x4b, 0x70, 0x31, 0xfb, 0x5b, 0x12, 0x0a, 0xd8, - 0x16, 0x8c, 0x29, 0xa0, 0x7a, 0xc7, 0x23, 0x4f, 0x15, 0x09, 0x0d, 0x88, 0x7f, 0xd0, 0x72, 0xe5, - 0xd1, 0x7b, 0x1f, 0xf3, 0x78, 0x01, 0x53, 0xff, 0xff, 0x3e, 0x0a, 0x33, 0xe8, 0xaf, 0x9e, 0x5c, - 0xa7, 0x3e, 0xc1, 0xe8, 0x2c, 0x08, 0xd3, 0x2c, 0xd7, 0xc2, 0x88, 0xc5, 0xe1, 0xc9, 0x50, 0x62, - 0x06, 0x01, 0x79, 0x47, 0x77, 0xb7, 0xe8, 0xd7, 0xf2, 0xbc, 0x48, 0xa0, 0xde, 0x85, 0xd8, 0x0f, - 0xe3, 0x0d, 0xe3, 0xb6, 0xff, 0xc4, 0x8b, 0xde, 0xe0, 0x49, 0x17, 0xbd, 0x5d, 0xb5, 0xe8, 0xf1, - 0xa8, 0x1f, 0xaf, 0x6b, 0x8b, 0xde, 0xcb, 0x5f, 0xed, 0x86, 0x5f, 0xf6, 0x6a, 0x37, 0xf2, 0xed, - 0x56, 0xbb, 0xd1, 0x17, 0x5c, 0xed, 0xee, 0xc2, 0xd4, 0x26, 0xa5, 0x2d, 0xed, 0x0e, 0x66, 0x2c, - 0xde, 0x3d, 0x3d, 0x8a, 0xd6, 0xb5, 0xac, 0x8b, 0x98, 0x04, 0x55, 0xee, 0xaa, 0x09, 0x7f, 0x3b, - 0xab, 0xe6, 0xf8, 0x4b, 0x5e, 0x35, 0x27, 0xbe, 0xcd, 0xaa, 0x99, 0x5a, 0xfa, 0x26, 0x4f, 0xbd, - 0xf4, 0x7d, 0x9b, 0xd5, 0xea, 0x63, 0xf4, 0x56, 0xac, 0xd7, 0x57, 0x85, 0x63, 0x8a, 0xe6, 0x09, - 0xb2, 0xea, 0x87, 0xd2, 0x99, 0x1b, 0xff, 0x66, 0xb0, 0x6d, 0x3f, 0x90, 0xb7, 0xe9, 0xf8, 0xb7, - 0xb5, 0x88, 0x3e, 0x8a, 0x3a, 0xbd, 0x7a, 0xc7, 0x30, 0x22, 0x1e, 0x41, 0x8a, 0x35, 0x2e, 0x79, - 0x8c, 0xb2, 0x65, 0xb9, 0xf5, 0x17, 0x25, 0x7e, 0xdf, 0xf9, 0x3f, 0xe2, 0x52, 0xf9, 0x6d, 0xee, - 0x20, 0x7f, 0x3b, 0x0e, 0x8e, 0x20, 0x02, 0x39, 0x04, 0x4e, 0xf3, 0x49, 0x7c, 0x09, 0xfc, 0x23, - 0xf6, 0x9d, 0xeb, 0x05, 0x18, 0xaa, 0x36, 0x3e, 0x2b, 0x9a, 0x85, 0x7b, 0x77, 0xe4, 0x02, 0x20, - 0x62, 0x44, 0x70, 0xb0, 0xb9, 0x00, 0xe8, 0x04, 0xe8, 0x86, 0x77, 0xc6, 0xb2, 0xf9, 0xdb, 0xfe, - 0xcc, 0x16, 0xbc, 0x9b, 0x7e, 0x9d, 0x8e, 0x87, 0x91, 0xf8, 0x75, 0xba, 0x2e, 0xc6, 0xf8, 0x9d, - 0xfa, 0x2e, 0x5c, 0xb0, 0xe9, 0xa1, 0xff, 0x94, 0xbe, 0x5c, 0xb6, 0x5f, 0xc1, 0x79, 0x93, 0x21, - 0x7f, 0xc7, 0xc4, 0xe3, 0xe2, 0x7f, 0x9c, 0x1d, 0x4d, 0x5f, 0x10, 0xf0, 0x68, 0xfa, 0x3c, 0x28, - 0x37, 0xfb, 0x53, 0xdf, 0x37, 0xb0, 0xcc, 0xf2, 0xe1, 0xa2, 0xc9, 0xbc, 0xd6, 0x6a, 0x61, 0x56, - 0xcd, 0xa6, 0xdb, 0x71, 0xbc, 0x88, 0x6c, 0xc1, 0xb8, 0xf6, 0x33, 0x61, 0x2a, 0xd0, 0x4a, 0x84, - 0x4e, 0x13, 0x03, 0x8c, 0xa0, 0xa6, 0x31, 0xd8, 0xa2, 0x50, 0x4d, 0x8a, 0x87, 0x89, 0x4c, 0xaf, - 0x73, 0x11, 0x26, 0xb5, 0x9f, 0xca, 0x1a, 0x8a, 0x1f, 0xbf, 0x56, 0x83, 0x29, 0x30, 0x93, 0xc4, - 0x6a, 0xc2, 0x7c, 0x96, 0xd0, 0x78, 0xf4, 0x6b, 0xb2, 0x12, 0x47, 0xce, 0xea, 0xed, 0xc8, 0x77, - 0x26, 0x2f, 0x6a, 0x96, 0xf5, 0x7f, 0x0d, 0xc2, 0x05, 0x31, 0x18, 0x2f, 0x73, 0xc4, 0xc9, 0x8f, - 0x61, 0x5c, 0x1b, 0x63, 0x21, 0xf4, 0x2b, 0xf2, 0x15, 0x52, 0xde, 0x5c, 0xe0, 0x26, 0x8d, 0x2e, - 0x02, 0x1a, 0x89, 0xe1, 0x5e, 0xed, 0xb3, 0x75, 0x96, 0xa4, 0x0d, 0x53, 0xe6, 0x40, 0x0b, 0xab, - 0xce, 0xb5, 0xcc, 0x4a, 0x4c, 0x54, 0x19, 0x1a, 0xbb, 0xd5, 0xc8, 0x1c, 0xee, 0xd5, 0x3e, 0x3b, - 0xc1, 0x9b, 0x7c, 0x03, 0x67, 0x53, 0xa3, 0x2c, 0x8c, 0x75, 0xaf, 0x65, 0x56, 0x98, 0xc2, 0xe6, - 0x96, 0xde, 0x00, 0xc1, 0xb9, 0xd5, 0xa6, 0x2b, 0x21, 0x2d, 0x98, 0xd0, 0x07, 0x5e, 0x98, 0x9d, - 0xae, 0x16, 0x88, 0x92, 0x23, 0x72, 0xe5, 0x4e, 0xc8, 0x12, 0xc7, 0xfe, 0xb9, 0x69, 0xbd, 0x36, - 0x90, 0x47, 0x61, 0x98, 0xff, 0x66, 0x4b, 0xc0, 0x76, 0x40, 0x43, 0xea, 0x35, 0xa9, 0xe1, 0xfb, - 0xfd, 0x2d, 0x97, 0x80, 0x7f, 0x5e, 0x82, 0x4a, 0x16, 0xdf, 0x3a, 0xf5, 0x5a, 0x64, 0x1b, 0xca, - 0xc9, 0x8a, 0xc4, 0xac, 0xb6, 0x54, 0xf4, 0xe1, 0xdc, 0x26, 0xad, 0xf6, 0xd9, 0x29, 0x6a, 0xb2, - 0x09, 0x67, 0x35, 0x98, 0x30, 0xae, 0xf6, 0x9f, 0xc4, 0xb8, 0xca, 0x46, 0x21, 0x45, 0xaa, 0xdb, - 0xa6, 0x57, 0x71, 0x67, 0x5c, 0xf6, 0x0f, 0x1d, 0xd7, 0x63, 0x8a, 0xae, 0x16, 0x3c, 0x0b, 0x62, - 0xa8, 0x90, 0x0d, 0xb7, 0xb6, 0x22, 0x54, 0xbe, 0x55, 0x51, 0x28, 0xd6, 0x47, 0xb8, 0x82, 0x0b, - 0x1b, 0x1d, 0x7f, 0xf0, 0xab, 0x98, 0x5d, 0x81, 0xa1, 0x9d, 0xf5, 0xfa, 0x52, 0x4d, 0x3c, 0x1f, - 0xe6, 0x41, 0x27, 0xda, 0x61, 0xa3, 0xe9, 0xd8, 0xbc, 0xc0, 0xfa, 0x10, 0xc8, 0x3d, 0x1a, 0x89, - 0xf0, 0xf7, 0x8a, 0xee, 0x55, 0x18, 0x11, 0x20, 0x41, 0x89, 0x5e, 0x77, 0x22, 0x98, 0xbe, 0x2d, - 0xcb, 0xac, 0x6d, 0x79, 0x4e, 0x68, 0x53, 0x27, 0xd4, 0x36, 0xe6, 0xf7, 0x60, 0x34, 0x10, 0x30, - 0xb1, 0x2f, 0x4f, 0xa9, 0xec, 0x26, 0x08, 0xe6, 0xf6, 0x6c, 0x89, 0x63, 0xab, 0xbf, 0xac, 0x75, - 0x0c, 0x10, 0xb3, 0xb5, 0xb6, 0xbc, 0xc4, 0xa4, 0x2a, 0x84, 0x25, 0x87, 0xe3, 0x16, 0xba, 0xa7, - 0x47, 0x54, 0x7f, 0x3c, 0x8c, 0xa2, 0xc1, 0x8f, 0x5c, 0x84, 0x45, 0xd2, 0x50, 0xac, 0xb7, 0x54, - 0xb8, 0x99, 0x0c, 0x6e, 0x79, 0x59, 0x3a, 0x36, 0x31, 0x90, 0xce, 0x3d, 0xf4, 0xc4, 0x79, 0x19, - 0x8d, 0x70, 0x60, 0x9e, 0x6f, 0xf3, 0xac, 0x57, 0x22, 0xd1, 0xa0, 0xaf, 0x96, 0xc6, 0x25, 0x18, - 0x53, 0x30, 0x75, 0xad, 0xc6, 0x65, 0x65, 0xe0, 0xef, 0xbd, 0xc5, 0xdf, 0x59, 0x37, 0x15, 0x83, - 0x98, 0x8e, 0x55, 0xc1, 0xbf, 0xbb, 0xef, 0xb8, 0x8a, 0x90, 0x06, 0xd1, 0x77, 0x5a, 0x45, 0x1c, - 0x69, 0xe9, 0x34, 0x55, 0x18, 0xf8, 0x7b, 0x0b, 0x27, 0x11, 0xd4, 0x77, 0x5c, 0x05, 0x13, 0xd4, - 0x77, 0x57, 0x05, 0x95, 0x21, 0xa9, 0xf8, 0x24, 0x4d, 0x55, 0xb2, 0x92, 0xae, 0x44, 0x1a, 0xae, - 0x13, 0x14, 0x85, 0xe3, 0x41, 0xe1, 0x22, 0x17, 0xd6, 0x2f, 0xa1, 0x1a, 0x26, 0xb0, 0xef, 0xb6, - 0x9a, 0xff, 0xb7, 0xc4, 0x03, 0x64, 0xd5, 0xb7, 0xb4, 0x14, 0x9f, 0xde, 0x63, 0x5f, 0xbb, 0xf5, - 0xd7, 0xbe, 0xf6, 0x07, 0xae, 0xd7, 0xd2, 0x6f, 0xfd, 0x9d, 0x6e, 0x74, 0xa0, 0x02, 0x48, 0x3f, - 0x71, 0xbd, 0x96, 0x9d, 0xc4, 0x26, 0xef, 0xc3, 0xa4, 0x06, 0x52, 0xda, 0x1a, 0xcf, 0xc2, 0xa1, - 0x93, 0xbb, 0x2d, 0xdb, 0xc4, 0xb4, 0xfe, 0xa6, 0x04, 0xd3, 0x19, 0xc9, 0xa7, 0xd1, 0x98, 0x81, - 0xa7, 0x20, 0xb5, 0x50, 0x89, 0xbc, 0x59, 0x18, 0xab, 0xc3, 0xd8, 0x24, 0x15, 0x22, 0xe6, 0x1f, - 0xd0, 0x12, 0x65, 0xf7, 0x6b, 0x29, 0xdd, 0xb2, 0x93, 0x63, 0xeb, 0xe8, 0x24, 0x04, 0x88, 0x5b, - 0x22, 0xcc, 0xc6, 0x75, 0xa6, 0xd2, 0x6a, 0x59, 0xb6, 0x5f, 0x4a, 0x9a, 0x6f, 0xad, 0x1a, 0xeb, - 0xb7, 0xfb, 0xe1, 0x5c, 0x46, 0xff, 0xeb, 0x34, 0xfa, 0xdb, 0x10, 0x41, 0x22, 0xd7, 0xf9, 0xc0, - 0x2f, 0x29, 0xd7, 0xb9, 0xf5, 0x6f, 0xfa, 0xe1, 0xdc, 0x6e, 0x27, 0xc4, 0xc7, 0x5b, 0x6b, 0xde, - 0x53, 0xea, 0x45, 0x7e, 0xf0, 0x1c, 0x1f, 0x9c, 0x90, 0x77, 0x60, 0x68, 0x95, 0xb6, 0xdb, 0xbe, - 0x98, 0xff, 0x97, 0xa4, 0xe3, 0x45, 0x12, 0x1b, 0x91, 0x56, 0xfb, 0x6c, 0x8e, 0x4d, 0xde, 0x87, - 0xb1, 0x55, 0xea, 0x04, 0xd1, 0x23, 0xea, 0xc8, 0x23, 0x8b, 0xcc, 0x0d, 0xa2, 0x91, 0x08, 0x84, - 0xd5, 0x3e, 0x3b, 0xc6, 0x26, 0x0b, 0xec, 0x34, 0xef, 0xed, 0xab, 0x87, 0xea, 0x39, 0x15, 0x32, - 0x9c, 0xd5, 0x3e, 0x1b, 0x71, 0xc9, 0x06, 0x4c, 0xd6, 0xf6, 0xa9, 0x17, 0x6d, 0xd0, 0xc8, 0x69, - 0x39, 0x91, 0x23, 0x54, 0xdb, 0x57, 0xf3, 0x88, 0x0d, 0xe4, 0xd5, 0x3e, 0xdb, 0xa4, 0x26, 0x1f, - 0xc2, 0xc8, 0x3d, 0xdf, 0x6f, 0x3d, 0x7a, 0x2e, 0x23, 0x28, 0x54, 0xf3, 0x18, 0x09, 0xb4, 0xd5, - 0x3e, 0x5b, 0x52, 0x2c, 0x0e, 0xc1, 0xc0, 0x46, 0xb8, 0x6f, 0x1d, 0x95, 0xa0, 0xb2, 0xec, 0x3f, - 0xf3, 0x32, 0xa5, 0xfa, 0x03, 0x53, 0xaa, 0x92, 0x7d, 0x06, 0x7e, 0x42, 0xae, 0x6f, 0xc3, 0xe0, - 0xb6, 0xeb, 0xed, 0x27, 0x54, 0xc1, 0x0c, 0x3a, 0x86, 0x85, 0xe2, 0x71, 0xbd, 0x7d, 0xb2, 0x2e, - 0x75, 0x70, 0x61, 0x6b, 0x1c, 0x30, 0x14, 0xff, 0x0c, 0x6a, 0x1d, 0x3b, 0xd6, 0xb5, 0xf9, 0x6f, - 0xd9, 0xc1, 0x37, 0x60, 0x2e, 0xa7, 0x5e, 0xf1, 0xf2, 0x9c, 0xf5, 0x6d, 0x10, 0x15, 0x9b, 0xd7, - 0x61, 0x36, 0x73, 0xfc, 0x52, 0x88, 0x7f, 0x2f, 0x6b, 0x22, 0xf2, 0x9e, 0x57, 0x60, 0x44, 0x26, - 0xcd, 0xe2, 0xb6, 0x1f, 0xf9, 0x13, 0xdf, 0x5e, 0xc9, 0x0f, 0x55, 0x86, 0x4a, 0x91, 0xdf, 0xe3, - 0x9e, 0x16, 0x9a, 0x8a, 0x7f, 0x4e, 0x1f, 0x7c, 0x8b, 0x8f, 0x46, 0xf1, 0x62, 0x75, 0xae, 0xfa, - 0x61, 0xe4, 0x29, 0xa7, 0x5e, 0x5b, 0xfd, 0x26, 0x37, 0xa0, 0x2c, 0x13, 0x64, 0x88, 0x4c, 0x3c, - 0x22, 0x33, 0xbb, 0x9d, 0x82, 0x93, 0xf7, 0x60, 0x2e, 0x09, 0x93, 0xbd, 0xe4, 0x8f, 0xe7, 0xf2, - 0x8a, 0xad, 0x3f, 0xef, 0xc7, 0xe8, 0xe1, 0x05, 0xf3, 0x9a, 0x49, 0x77, 0xab, 0x2e, 0xa4, 0xd5, - 0xbf, 0x55, 0x27, 0x17, 0x61, 0x6c, 0xab, 0x6e, 0x64, 0x1e, 0xb3, 0x63, 0x00, 0x6b, 0x36, 0xeb, - 0x42, 0x2d, 0x68, 0x1e, 0xb8, 0x11, 0x6d, 0x46, 0xdd, 0x40, 0xac, 0xc2, 0x76, 0x0a, 0x4e, 0x2c, - 0x98, 0xb8, 0xd7, 0x76, 0x1f, 0x35, 0x25, 0x33, 0x2e, 0x02, 0x03, 0x46, 0x5e, 0x83, 0xa9, 0x35, - 0x2f, 0x8c, 0x9c, 0x76, 0x7b, 0x83, 0x46, 0x07, 0x7e, 0x4b, 0x24, 0x47, 0xb5, 0x13, 0x50, 0x56, - 0xef, 0x92, 0xef, 0x45, 0x8e, 0xeb, 0xd1, 0xc0, 0xee, 0x7a, 0x91, 0x7b, 0x48, 0x45, 0xdf, 0x53, - 0x70, 0xf2, 0x36, 0xcc, 0x2a, 0xd8, 0x56, 0xd0, 0x3c, 0xa0, 0x61, 0x14, 0x60, 0x3e, 0x42, 0x74, - 0xdf, 0xb1, 0xb3, 0x0b, 0xb1, 0x86, 0xb6, 0xdf, 0x6d, 0xad, 0x78, 0x4f, 0xdd, 0xc0, 0xf7, 0x30, - 0xdb, 0xc7, 0xa8, 0xa8, 0x21, 0x01, 0xb7, 0xfe, 0x68, 0x34, 0xf3, 0xb3, 0xfd, 0x36, 0x73, 0xf0, - 0x0b, 0x98, 0x58, 0x72, 0x3a, 0xce, 0x23, 0xb7, 0xed, 0x46, 0xae, 0x4a, 0xdc, 0xf6, 0x4e, 0x8f, - 0x6f, 0x5e, 0xa6, 0x4c, 0xa1, 0x2d, 0x9d, 0xd8, 0x36, 0x58, 0xcd, 0xff, 0xf5, 0x30, 0xcc, 0x66, - 0xe2, 0x91, 0xeb, 0x22, 0xc3, 0x9b, 0x5a, 0x57, 0x45, 0xfa, 0x30, 0x3b, 0x09, 0x66, 0x63, 0x89, - 0xa0, 0xa5, 0x36, 0x75, 0xbc, 0xae, 0x48, 0x1e, 0x66, 0x1b, 0x30, 0x36, 0x96, 0x4c, 0x6f, 0xd0, - 0x98, 0xa1, 0x4f, 0xb6, 0x9d, 0x80, 0x92, 0x2b, 0x30, 0xce, 0x20, 0x92, 0xd5, 0x20, 0x7f, 0x3d, - 0xa8, 0x81, 0x18, 0xa7, 0x4d, 0xbf, 0x45, 0x35, 0x4e, 0x43, 0x9c, 0x93, 0x09, 0x65, 0x9c, 0x18, - 0x44, 0x72, 0x1a, 0xe6, 0x9c, 0x34, 0x10, 0x79, 0x05, 0x26, 0x6b, 0x9d, 0x8e, 0xc6, 0x08, 0xb3, - 0x86, 0xd9, 0x26, 0x90, 0x5c, 0x06, 0xa8, 0x75, 0x3a, 0x92, 0x0d, 0x66, 0x04, 0xb3, 0x35, 0x08, - 0xb9, 0x19, 0x07, 0x80, 0xd3, 0x58, 0xe1, 0x75, 0x82, 0x9d, 0x51, 0xc2, 0xe4, 0xaa, 0xa2, 0x65, - 0x09, 0xa6, 0xc0, 0xe5, 0x9a, 0x00, 0x93, 0x8f, 0xe0, 0x7c, 0xc2, 0xef, 0x42, 0xab, 0x00, 0x4d, - 0xfd, 0x76, 0x3e, 0x02, 0x79, 0x17, 0xce, 0x25, 0x0a, 0x65, 0x75, 0x68, 0xd5, 0xb7, 0x73, 0x4a, - 0xc9, 0x07, 0x50, 0x49, 0xbc, 0x08, 0x8f, 0x2b, 0x45, 0x0b, 0xbe, 0x9d, 0x5b, 0xce, 0xbe, 0xae, - 0xc4, 0xd3, 0x32, 0x51, 0x25, 0x5e, 0x56, 0xda, 0xd9, 0x85, 0x64, 0x15, 0xaa, 0x99, 0xbe, 0x2c, - 0x5a, 0xc5, 0x98, 0xe9, 0xcc, 0xee, 0x85, 0x46, 0x16, 0xe1, 0x62, 0x26, 0x8a, 0x6c, 0x06, 0xe6, - 0x3f, 0xb3, 0x0b, 0x71, 0xc8, 0x02, 0xcc, 0xc4, 0x3e, 0x3d, 0x5a, 0x13, 0x30, 0xf5, 0x99, 0x9d, - 0x59, 0x46, 0xde, 0x34, 0xdf, 0xfd, 0xf3, 0xca, 0x30, 0xf3, 0x99, 0x9d, 0x2e, 0xb0, 0x8e, 0x4b, - 0x70, 0x31, 0x73, 0xa3, 0x94, 0xfa, 0xfc, 0x7c, 0x52, 0x71, 0xd4, 0xd6, 0x82, 0x1b, 0x30, 0x88, - 0x0a, 0x3e, 0xb7, 0x15, 0x4b, 0x37, 0x56, 0xa4, 0xe7, 0xac, 0x58, 0xa9, 0x8d, 0x38, 0xe4, 0x9e, - 0xba, 0x1b, 0x1c, 0x40, 0x4b, 0xc6, 0xad, 0xa4, 0x02, 0x95, 0x51, 0xb9, 0x7e, 0x47, 0x28, 0x6f, - 0x03, 0xbf, 0xcd, 0x35, 0xcc, 0x9f, 0x97, 0xa0, 0xda, 0x43, 0x3f, 0x50, 0x7d, 0x2a, 0x9d, 0xa0, - 0x4f, 0xf7, 0x55, 0x9f, 0xf8, 0xb3, 0xdb, 0x85, 0x93, 0xe9, 0x20, 0x2f, 0xbb, 0x5b, 0x7f, 0x53, - 0x02, 0x92, 0xd6, 0x43, 0xc9, 0xf7, 0x61, 0xac, 0x5e, 0x5f, 0x35, 0x3c, 0xfa, 0x52, 0xb7, 0x43, - 0x31, 0x06, 0xb9, 0x7d, 0x22, 0x17, 0x3e, 0xdd, 0x81, 0xef, 0x93, 0x94, 0xdf, 0xe0, 0x40, 0xa1, - 0xdf, 0x60, 0xca, 0x6b, 0x70, 0x25, 0xc3, 0x11, 0x6e, 0xb0, 0x87, 0x23, 0x5c, 0xda, 0xcb, 0xcd, - 0x5a, 0x86, 0x4a, 0x9e, 0x2a, 0x8b, 0x2b, 0x1c, 0x0f, 0x9b, 0xa6, 0xdd, 0x70, 0xf1, 0x15, 0xce, - 0x04, 0x5b, 0xef, 0xc2, 0x39, 0x45, 0xcd, 0xf3, 0xb1, 0x68, 0xc1, 0x0d, 0xc4, 0xf9, 0x57, 0x05, - 0x51, 0x88, 0x01, 0xd6, 0x9f, 0x0d, 0xa6, 0x08, 0xeb, 0xdd, 0xc3, 0x43, 0x27, 0x78, 0x4e, 0x6a, - 0x26, 0xe1, 0x40, 0xcf, 0x23, 0xc7, 0xe2, 0xe0, 0xcf, 0x8e, 0xaa, 0x7d, 0x1a, 0x77, 0xb6, 0x2f, - 0xa0, 0x86, 0xe1, 0x35, 0x29, 0xbf, 0x1b, 0xeb, 0xe7, 0x01, 0x9c, 0x0c, 0x20, 0xd9, 0x83, 0x49, - 0xb1, 0x77, 0xe3, 0x6f, 0xf9, 0x8d, 0xdd, 0x4e, 0x7e, 0x63, 0x46, 0xf3, 0x6e, 0x1a, 0x24, 0x7c, - 0x36, 0x9a, 0x6c, 0xc8, 0x17, 0x30, 0x25, 0x35, 0x35, 0xc1, 0x98, 0x7b, 0x33, 0xdd, 0x29, 0x66, - 0x6c, 0xd2, 0x70, 0xce, 0x09, 0x46, 0xac, 0xc9, 0x72, 0xb1, 0xe3, 0x9c, 0x87, 0x4e, 0xd2, 0x64, - 0x83, 0x44, 0x34, 0xd9, 0x80, 0xcd, 0x7f, 0x0a, 0x24, 0xdd, 0xaf, 0x5e, 0x9f, 0xd3, 0xa4, 0xf6, - 0x39, 0xcd, 0xd7, 0x60, 0x3a, 0xa3, 0x03, 0xa7, 0x62, 0xf1, 0x29, 0x90, 0x74, 0x4b, 0x4f, 0xc3, - 0xc1, 0xba, 0x0e, 0xaf, 0x29, 0x11, 0xa8, 0xd9, 0x60, 0xf0, 0x94, 0x16, 0xf0, 0xdf, 0xec, 0x87, - 0x6a, 0x0f, 0x54, 0xf2, 0x87, 0xa5, 0xa4, 0xb4, 0xf9, 0x6c, 0x7c, 0x3f, 0x29, 0xed, 0x6c, 0xfa, - 0x0c, 0xb1, 0x2f, 0x7e, 0xf0, 0x5b, 0x7f, 0xf9, 0xc2, 0x27, 0x8f, 0xf4, 0x90, 0x9d, 0x5e, 0x5a, - 0x83, 0xba, 0xb4, 0x6c, 0x98, 0x31, 0xce, 0x6c, 0x27, 0xd9, 0xbc, 0x2e, 0x03, 0x88, 0xec, 0xad, - 0xeb, 0xfe, 0xbe, 0xd0, 0x13, 0x35, 0x88, 0x75, 0x17, 0x66, 0x13, 0x3c, 0x85, 0x55, 0xfe, 0xfb, - 0xa0, 0x1e, 0xb1, 0x23, 0xd3, 0x81, 0xc5, 0xb3, 0xbf, 0x38, 0xaa, 0x4e, 0x32, 0x95, 0xfe, 0x66, - 0x9c, 0x1a, 0x40, 0xfe, 0x65, 0x6d, 0xe8, 0xf7, 0x0a, 0xb5, 0xb6, 0x1e, 0xdc, 0x87, 0xdc, 0x81, - 0x61, 0x0e, 0x49, 0x04, 0xe0, 0xd6, 0xb1, 0xc5, 0x9a, 0x20, 0x10, 0xad, 0x59, 0x7c, 0x72, 0x8b, - 0x3f, 0x6a, 0x71, 0x88, 0x08, 0x6b, 0x97, 0x27, 0xa4, 0x89, 0xc1, 0x2a, 0xc8, 0xf7, 0x60, 0x2d, - 0x0e, 0x65, 0x21, 0x9d, 0x40, 0x24, 0x9e, 0xe7, 0x3f, 0x6b, 0xd3, 0x16, 0x4f, 0xf6, 0xb7, 0x38, - 0x21, 0x9c, 0x40, 0x06, 0x1d, 0xc6, 0x00, 0xc9, 0xac, 0x4f, 0x60, 0x96, 0x69, 0x0a, 0x41, 0xb2, - 0x3e, 0x4c, 0x43, 0xc1, 0x60, 0xa6, 0x67, 0xbd, 0xc3, 0x40, 0xe8, 0x59, 0x2f, 0x0a, 0xad, 0x75, - 0x38, 0xcf, 0xad, 0x92, 0x7a, 0x97, 0xe2, 0x3b, 0x80, 0x21, 0xfc, 0x9d, 0x78, 0xb0, 0x99, 0xd1, - 0x7b, 0x8e, 0x67, 0x7d, 0x8c, 0x2f, 0x82, 0xc4, 0x24, 0x75, 0x7d, 0x2f, 0x36, 0x41, 0x9e, 0xec, - 0x09, 0xf1, 0xff, 0x0c, 0x17, 0x6b, 0x9d, 0x0e, 0xf5, 0x5a, 0x31, 0xe1, 0x4e, 0xe0, 0x9c, 0x30, - 0xc0, 0x03, 0xa9, 0xc1, 0x10, 0x62, 0xab, 0x0b, 0x54, 0xd1, 0xdc, 0x8c, 0xe6, 0x20, 0x9e, 0x88, - 0xc8, 0x8a, 0x15, 0x70, 0x4a, 0xab, 0x05, 0x73, 0xf5, 0xee, 0xa3, 0x43, 0x37, 0x42, 0x7f, 0x7c, - 0x0c, 0x92, 0x22, 0xeb, 0x5e, 0x93, 0x39, 0xc4, 0xb8, 0x30, 0xae, 0xc7, 0x2f, 0x47, 0xd0, 0xa5, - 0x5f, 0x04, 0x4e, 0x79, 0x7a, 0xe7, 0x66, 0x4c, 0x8a, 0xe6, 0x17, 0x5e, 0x0b, 0x16, 0x8b, 0x3c, - 0x63, 0xd6, 0x34, 0x9c, 0xd5, 0x2f, 0xa3, 0xf8, 0x0c, 0x99, 0x85, 0x69, 0xf3, 0x92, 0x89, 0x83, - 0xbf, 0x86, 0x19, 0x6e, 0x04, 0xe7, 0x11, 0xd5, 0x17, 0xe2, 0xe0, 0xe1, 0xfd, 0x7b, 0x0b, 0x89, - 0x87, 0x00, 0xe8, 0x1f, 0xac, 0x72, 0x65, 0xec, 0x2d, 0xf0, 0x57, 0x9d, 0x4f, 0x17, 0x8c, 0xab, - 0xcc, 0xfe, 0xbd, 0x85, 0xc5, 0x11, 0x11, 0x99, 0x96, 0x71, 0xe7, 0xc3, 0xff, 0x9d, 0x70, 0x5f, - 0xc0, 0x40, 0x02, 0xab, 0xd4, 0xc1, 0x47, 0x3f, 0xd9, 0xcf, 0xb1, 0xa7, 0xa0, 0x5f, 0xc5, 0xa9, - 0xec, 0x77, 0x5b, 0xd6, 0x1f, 0x97, 0xe0, 0x3a, 0x57, 0xc6, 0xb2, 0xe9, 0xf0, 0xc6, 0x29, 0x87, - 0x98, 0xbc, 0x07, 0x43, 0xa1, 0xe6, 0x1d, 0x61, 0x89, 0x96, 0x17, 0x71, 0xe2, 0x04, 0xa4, 0x06, - 0x13, 0xfa, 0xdb, 0x96, 0x93, 0x85, 0xc0, 0xb3, 0xc7, 0x0f, 0x1f, 0x3b, 0xea, 0xbd, 0xcb, 0x13, - 0xb8, 0xb0, 0xf2, 0x0d, 0x9b, 0x10, 0x62, 0x77, 0x12, 0x27, 0x87, 0xf8, 0xb9, 0xef, 0x99, 0x1d, - 0x31, 0x63, 0xcc, 0x63, 0x7d, 0x12, 0xcc, 0xce, 0xc8, 0x72, 0x83, 0x53, 0xea, 0xfb, 0x98, 0x6d, - 0xc0, 0xac, 0x3f, 0x2b, 0xc1, 0xc5, 0xec, 0xda, 0xc4, 0xc2, 0xb2, 0x06, 0x67, 0x97, 0x1c, 0xcf, - 0xf7, 0xdc, 0xa6, 0xd3, 0xae, 0x37, 0x0f, 0x68, 0xab, 0xab, 0xe2, 0xd7, 0xaa, 0x55, 0x66, 0x9f, - 0x7a, 0x92, 0x5c, 0xa2, 0xd8, 0x69, 0x2a, 0x76, 0x3a, 0xc4, 0xe7, 0x11, 0x7c, 0xed, 0x6d, 0xd3, - 0x40, 0xf1, 0xe3, 0x2d, 0xcb, 0x29, 0x25, 0xb7, 0xa5, 0xb5, 0xbf, 0xb5, 0xeb, 0xb9, 0x91, 0x22, - 0xe2, 0x66, 0x9e, 0xac, 0x22, 0xeb, 0x5f, 0x95, 0xe0, 0x3c, 0xa6, 0xac, 0x32, 0x92, 0x60, 0xc6, - 0x61, 0x9c, 0x65, 0x24, 0xe2, 0x92, 0xf1, 0xdc, 0xc3, 0xc0, 0x36, 0x43, 0x12, 0x93, 0x37, 0x61, - 0xb0, 0x2e, 0xbd, 0xb5, 0xa6, 0x12, 0x19, 0x86, 0x05, 0x05, 0x2b, 0xb7, 0x11, 0x8b, 0xed, 0x39, - 0xcb, 0x34, 0x6c, 0x52, 0x0f, 0x53, 0x41, 0x73, 0xab, 0x83, 0x06, 0x89, 0xc3, 0x31, 0x0d, 0xe6, - 0x85, 0x63, 0x1a, 0x32, 0xc3, 0x31, 0x59, 0x4f, 0x79, 0xc2, 0xaa, 0x64, 0x87, 0xc4, 0x20, 0x7d, - 0x9c, 0xca, 0x1c, 0xcd, 0xf7, 0x81, 0x73, 0x59, 0x3d, 0x63, 0x0a, 0x7a, 0x22, 0x29, 0x74, 0x7e, - 0xd8, 0xe4, 0x6d, 0x78, 0xc5, 0xc0, 0xad, 0xb5, 0xdb, 0xfe, 0x33, 0xda, 0xda, 0x0e, 0xfc, 0x43, - 0x3f, 0x32, 0x12, 0xf6, 0x88, 0xd4, 0xe9, 0xf1, 0x7d, 0x8e, 0x98, 0x95, 0x09, 0xb0, 0xf5, 0x3f, - 0xc1, 0xab, 0x3d, 0x38, 0x8a, 0x4e, 0xd5, 0xe1, 0xac, 0x93, 0x28, 0x93, 0x6e, 0x37, 0xaf, 0x66, - 0xf5, 0x2b, 0xc9, 0x28, 0xb4, 0xd3, 0xf4, 0x37, 0x76, 0x8c, 0x6c, 0xcb, 0xa4, 0x02, 0x33, 0xdb, - 0xf6, 0xd6, 0xf2, 0xee, 0xd2, 0x4e, 0x63, 0xe7, 0x8b, 0xed, 0x95, 0xc6, 0xee, 0xe6, 0x83, 0xcd, - 0xad, 0x87, 0x9b, 0x3c, 0xee, 0xb8, 0x51, 0xb2, 0xb3, 0x52, 0xdb, 0x28, 0x97, 0xc8, 0x0c, 0x94, - 0x0d, 0xf0, 0xca, 0xee, 0x62, 0xb9, 0xff, 0xc6, 0xd7, 0x46, 0x16, 0x61, 0x72, 0x11, 0x2a, 0xf5, - 0xdd, 0xed, 0xed, 0x2d, 0x5b, 0x71, 0xd5, 0xa3, 0x9e, 0xcf, 0xc2, 0x59, 0xa3, 0xf4, 0xae, 0xbd, - 0xb2, 0x52, 0x2e, 0xb1, 0xa6, 0x18, 0xe0, 0x6d, 0x7b, 0x65, 0x63, 0x6d, 0x77, 0xa3, 0xdc, 0x7f, - 0xa3, 0xa1, 0xbf, 0x31, 0x23, 0x17, 0x60, 0x6e, 0x79, 0x65, 0x6f, 0x6d, 0x69, 0x25, 0x8b, 0xf7, - 0x0c, 0x94, 0xf5, 0xc2, 0x9d, 0xad, 0x9d, 0x6d, 0xce, 0x5a, 0x87, 0x3e, 0x5c, 0x59, 0xac, 0xed, - 0xee, 0xac, 0x6e, 0x96, 0x07, 0xac, 0xc1, 0xd1, 0xfe, 0x72, 0xff, 0x8d, 0x1f, 0x1b, 0x0f, 0xd0, - 0x58, 0xf3, 0x05, 0xfa, 0x6e, 0xbd, 0x76, 0x2f, 0xbf, 0x0a, 0x5e, 0xba, 0x71, 0xb7, 0x56, 0x2e, - 0x91, 0x4b, 0x70, 0xde, 0x80, 0x6e, 0xd7, 0xea, 0xf5, 0x87, 0x5b, 0xf6, 0xf2, 0xfa, 0x4a, 0xbd, - 0x5e, 0xee, 0xbf, 0xb1, 0x67, 0x84, 0xa0, 0x63, 0x35, 0x6c, 0xdc, 0xad, 0x35, 0xec, 0x95, 0xcf, - 0x76, 0xd7, 0xec, 0x95, 0xe5, 0x74, 0x0d, 0x46, 0xe9, 0x17, 0x2b, 0xf5, 0x72, 0x89, 0x4c, 0xc3, - 0x19, 0x03, 0xba, 0xb9, 0x55, 0xee, 0xbf, 0xf1, 0x9a, 0x88, 0x52, 0x46, 0xa6, 0x00, 0x96, 0x57, - 0xea, 0x4b, 0x2b, 0x9b, 0xcb, 0x6b, 0x9b, 0xf7, 0xca, 0x7d, 0x64, 0x12, 0xc6, 0x6a, 0xea, 0x67, - 0xe9, 0xc6, 0x07, 0x70, 0x26, 0x71, 0xb4, 0x67, 0x18, 0xea, 0x50, 0x5c, 0xee, 0x43, 0xf1, 0xcb, - 0x9f, 0x68, 0x5f, 0xe5, 0xa7, 0xf4, 0x72, 0xe9, 0xc6, 0xa2, 0xcc, 0x6a, 0xab, 0x7d, 0xe7, 0x64, - 0x1c, 0x46, 0x96, 0x57, 0xee, 0xd6, 0x76, 0xd7, 0x77, 0xca, 0x7d, 0xec, 0xc7, 0x92, 0xbd, 0x52, - 0xdb, 0x59, 0x59, 0x2e, 0x97, 0xc8, 0x18, 0x0c, 0xd5, 0x77, 0x6a, 0x3b, 0x2b, 0xe5, 0x7e, 0x32, - 0x0a, 0x83, 0xbb, 0xf5, 0x15, 0xbb, 0x3c, 0xb0, 0xf0, 0xcf, 0xfe, 0xb0, 0xc4, 0x8d, 0x8c, 0xf2, - 0x31, 0xd3, 0xd7, 0xda, 0x61, 0x52, 0x2c, 0x79, 0x22, 0x85, 0x67, 0xee, 0xc9, 0x11, 0xb5, 0x80, - 0xf9, 0x82, 0x5b, 0x17, 0x44, 0xb8, 0x5e, 0xba, 0x5d, 0x22, 0x36, 0x7a, 0xa9, 0x24, 0xce, 0x56, - 0x8a, 0x73, 0xf6, 0xf1, 0x77, 0xfe, 0x52, 0xe1, 0x91, 0x8c, 0xfc, 0x1a, 0x58, 0x3a, 0xcf, 0x9c, - 0x13, 0xc8, 0xf7, 0x4f, 0x76, 0xd2, 0x90, 0x75, 0xbe, 0x76, 0x32, 0x74, 0x72, 0x1f, 0x26, 0x99, - 0x6e, 0xae, 0xd0, 0xc8, 0x85, 0x24, 0xa1, 0x76, 0x1c, 0x98, 0xbf, 0x98, 0x5d, 0xa8, 0xb2, 0xec, - 0x4c, 0x60, 0x47, 0xf8, 0xc1, 0x3a, 0x24, 0x32, 0x92, 0x85, 0x84, 0xf0, 0x15, 0x7f, 0xfe, 0x6c, - 0x02, 0xbc, 0x77, 0xe7, 0x76, 0x89, 0xd4, 0x31, 0x8c, 0x9c, 0xa1, 0xe4, 0x13, 0xf9, 0xba, 0x2e, - 0xad, 0xfd, 0xf3, 0xd6, 0x54, 0x55, 0x4e, 0xcc, 0x9c, 0xd3, 0xc1, 0x26, 0x90, 0xb4, 0xee, 0x4c, - 0xae, 0xc4, 0xf3, 0x20, 0x5b, 0xad, 0x9e, 0x3f, 0x97, 0x72, 0x3e, 0x5c, 0x61, 0xda, 0x13, 0x59, - 0x81, 0x29, 0xf1, 0x4c, 0x5d, 0x68, 0xf3, 0xa4, 0xe8, 0x3c, 0x90, 0xcb, 0xe6, 0x1e, 0xca, 0x49, - 0x9d, 0x08, 0xc8, 0x7c, 0xdc, 0x8f, 0xe4, 0x31, 0x61, 0xfe, 0x42, 0x66, 0x99, 0xe8, 0xdf, 0x5d, - 0x98, 0x32, 0x0f, 0x17, 0x44, 0x0e, 0x50, 0xe6, 0x99, 0x23, 0xb7, 0x41, 0x0d, 0x98, 0xdb, 0x70, - 0x5c, 0xbc, 0x2b, 0x11, 0x2e, 0x6e, 0xd2, 0x41, 0x8d, 0x54, 0x0b, 0x3c, 0xd6, 0xea, 0xd4, 0x6b, - 0xa9, 0x41, 0xc8, 0x8b, 0x98, 0x8f, 0x9f, 0x4d, 0x5d, 0xea, 0xc8, 0xa6, 0x83, 0x1f, 0xb1, 0xcc, - 0x3c, 0xc7, 0x59, 0x3e, 0x9b, 0xf3, 0x79, 0x6e, 0xc6, 0x64, 0x03, 0x95, 0xf4, 0x04, 0x47, 0x6d, - 0x4e, 0x9c, 0x9a, 0x5d, 0x05, 0x83, 0x25, 0x68, 0xf9, 0xe1, 0x45, 0x61, 0x48, 0x72, 0x04, 0x97, - 0xcb, 0xec, 0x76, 0x89, 0x7c, 0x8d, 0x5f, 0x75, 0x26, 0xbb, 0x87, 0x6e, 0x74, 0x20, 0xb4, 0x9f, - 0x0b, 0x99, 0x0c, 0xc4, 0x87, 0x52, 0xc0, 0xdd, 0x86, 0x99, 0x2c, 0xcf, 0x66, 0x25, 0xd0, 0x02, - 0xb7, 0xe7, 0xdc, 0x59, 0x60, 0xb3, 0xa3, 0x46, 0x2b, 0x7f, 0x90, 0x0a, 0x1c, 0x6b, 0x73, 0x79, - 0x7e, 0x04, 0x53, 0x6c, 0x96, 0x3c, 0xa0, 0xb4, 0x53, 0x6b, 0xbb, 0x4f, 0x69, 0x48, 0x64, 0x0c, - 0x60, 0x05, 0xca, 0xa3, 0xbd, 0x5e, 0x22, 0xdf, 0x83, 0xf1, 0x87, 0x4e, 0xd4, 0x3c, 0x10, 0xb1, - 0x30, 0x65, 0xa8, 0x4c, 0x84, 0xcd, 0xcb, 0x5f, 0x58, 0x78, 0xbb, 0x44, 0x7e, 0x08, 0x23, 0xf7, - 0x68, 0x84, 0xaf, 0x9b, 0xaf, 0x2a, 0x27, 0x3f, 0x6e, 0x9b, 0x5c, 0xf3, 0xd4, 0x13, 0x1e, 0xd9, - 0xe0, 0xa4, 0x21, 0x97, 0xdc, 0x02, 0xe0, 0x0b, 0x02, 0x72, 0x48, 0x16, 0xcf, 0xa7, 0x9a, 0x4d, - 0xee, 0x31, 0xe5, 0xa1, 0x4d, 0x23, 0x7a, 0xd2, 0x2a, 0xf3, 0x64, 0xb4, 0x0e, 0x53, 0x2a, 0x31, - 0xd1, 0x26, 0x86, 0x2c, 0xb1, 0x12, 0xcc, 0xc2, 0x53, 0x70, 0xfb, 0x80, 0x7d, 0x15, 0x3c, 0x2b, - 0x2f, 0xc6, 0xb6, 0xc0, 0x95, 0x74, 0x4e, 0x0f, 0x90, 0xa1, 0x2f, 0xa1, 0x52, 0x88, 0x1c, 0x4d, - 0xa3, 0x5d, 0xf5, 0xc3, 0xc8, 0xa4, 0x55, 0x90, 0x6c, 0xda, 0x5f, 0x85, 0x79, 0xbd, 0x5e, 0x33, - 0x18, 0x73, 0xbc, 0xe6, 0xe6, 0xc5, 0x78, 0x9e, 0xbf, 0x5a, 0x80, 0x21, 0xce, 0x6f, 0x03, 0xbf, - 0xd3, 0x5f, 0xc2, 0xe5, 0x64, 0x19, 0xa6, 0x65, 0x5d, 0x5b, 0x1d, 0xea, 0xd5, 0xeb, 0xab, 0x98, - 0x84, 0x46, 0xba, 0x94, 0x68, 0x30, 0xc9, 0x9d, 0xa4, 0x8b, 0xd8, 0xd6, 0x67, 0xc4, 0xb0, 0x20, - 0x45, 0x91, 0x2d, 0xe2, 0xad, 0x2f, 0x33, 0x4a, 0xf0, 0x03, 0x6e, 0x54, 0x32, 0x94, 0xff, 0xbd, - 0x05, 0x52, 0x70, 0x00, 0x9a, 0xcf, 0x39, 0x42, 0xdc, 0x2e, 0x91, 0x2f, 0x80, 0xa4, 0x8f, 0x24, - 0x4a, 0x84, 0xb9, 0xc7, 0x2f, 0x25, 0xc2, 0x82, 0xf3, 0xcc, 0x0a, 0x4c, 0xab, 0x08, 0x36, 0x71, - 0x39, 0xc9, 0x69, 0x4b, 0xc1, 0x0e, 0x36, 0x9b, 0xc1, 0x66, 0x6f, 0xa1, 0x80, 0x51, 0x26, 0x9c, - 0x7c, 0x02, 0xd3, 0x62, 0xee, 0x1b, 0xed, 0x29, 0xab, 0x65, 0x4c, 0x1c, 0x6e, 0x72, 0x5b, 0x72, - 0x1f, 0x66, 0xeb, 0x09, 0xc1, 0x73, 0x87, 0xfa, 0xf3, 0x26, 0x0b, 0x04, 0xd6, 0x69, 0xc4, 0x25, - 0x9f, 0xcd, 0xeb, 0x01, 0x10, 0x6e, 0x5b, 0x92, 0xec, 0x9e, 0xba, 0xf4, 0x19, 0xb9, 0x94, 0x68, - 0x3a, 0x03, 0x22, 0x1a, 0xae, 0x83, 0xb9, 0x3d, 0xdb, 0xe1, 0xa9, 0xa9, 0x11, 0x6a, 0x5c, 0xc5, - 0x5f, 0x31, 0x08, 0x8c, 0xdb, 0x7c, 0x31, 0x8e, 0xe7, 0x73, 0x31, 0xc8, 0x6f, 0x60, 0x04, 0xda, - 0xe2, 0xd3, 0x19, 0xf9, 0x5e, 0xd6, 0x21, 0x3a, 0xe7, 0x7c, 0x39, 0xff, 0xe6, 0xc9, 0x90, 0xd5, - 0x79, 0x78, 0xf2, 0x1e, 0x8d, 0xb6, 0xdb, 0xdd, 0x7d, 0x17, 0x93, 0x96, 0x12, 0x65, 0x7b, 0x52, - 0x20, 0x31, 0xbd, 0x65, 0xe0, 0xb7, 0xb8, 0xa0, 0x4e, 0x7f, 0x42, 0xd6, 0xa0, 0xcc, 0xb7, 0x11, - 0x8d, 0xc5, 0xa5, 0x14, 0x0b, 0x81, 0xe2, 0x04, 0xce, 0x61, 0x98, 0x3b, 0x5a, 0xb7, 0xb8, 0xef, - 0x13, 0x91, 0x9f, 0xb6, 0xae, 0xa7, 0x4e, 0x1b, 0x30, 0x15, 0x95, 0x9f, 0x8d, 0x88, 0x4d, 0x43, - 0x1a, 0xc9, 0x50, 0x37, 0x3c, 0x65, 0xed, 0xb5, 0x58, 0x67, 0x48, 0x97, 0xc6, 0x2b, 0x48, 0x22, - 0x2c, 0xdb, 0xde, 0x5b, 0x44, 0xa5, 0xf1, 0xcd, 0x60, 0xfa, 0x9a, 0xa1, 0xda, 0x9c, 0x8e, 0xef, - 0xdb, 0xb8, 0x95, 0x61, 0x78, 0x9f, 0xd9, 0xb8, 0x6d, 0xec, 0xb7, 0xa4, 0x9a, 0xd4, 0xa8, 0xf6, - 0x16, 0x70, 0x65, 0x64, 0x7b, 0x2d, 0xd3, 0x84, 0xbb, 0x41, 0x40, 0x3d, 0x4e, 0x9c, 0xa7, 0xb6, - 0x64, 0x51, 0x7f, 0x8c, 0x2b, 0x98, 0x46, 0xcd, 0xdf, 0xfd, 0xf5, 0x62, 0xc1, 0x53, 0x2c, 0xdd, - 0x2e, 0x91, 0xf7, 0x60, 0x54, 0xb4, 0x91, 0x11, 0x19, 0x8d, 0x0e, 0x0b, 0x5a, 0x8d, 0x94, 0xc0, - 0x85, 0x84, 0x6d, 0x36, 0x71, 0xf2, 0x46, 0x9f, 0xb7, 0xf9, 0x3d, 0xb6, 0x67, 0xb7, 0x5e, 0x84, - 0x72, 0x49, 0x6e, 0xde, 0x48, 0x59, 0x51, 0x21, 0x61, 0x24, 0xa8, 0xc7, 0x2e, 0xcb, 0x99, 0x30, - 0xf5, 0x1b, 0xe3, 0x2a, 0xaa, 0xf0, 0x68, 0x4a, 0xfd, 0x36, 0xc0, 0xbd, 0xb6, 0xec, 0x35, 0x28, - 0xd7, 0x9a, 0xb8, 0xa1, 0xd4, 0xe9, 0xa1, 0xd3, 0x39, 0xf0, 0x03, 0xaa, 0xce, 0x3e, 0xc9, 0x02, - 0xc9, 0x6b, 0x56, 0x29, 0x28, 0xa2, 0x60, 0x9d, 0x3a, 0x18, 0x7c, 0x7a, 0x4e, 0x69, 0x28, 0x89, - 0xa2, 0x6c, 0x8a, 0x82, 0xb3, 0xce, 0xcc, 0x12, 0x3b, 0x9d, 0xb5, 0xbf, 0x1d, 0x9b, 0x0f, 0x70, - 0xc1, 0x50, 0xc8, 0xa1, 0xda, 0x21, 0x14, 0x48, 0x9d, 0x0a, 0xe5, 0x13, 0x20, 0x85, 0x5a, 0x93, - 0x57, 0xcf, 0xb1, 0x58, 0xf2, 0xa8, 0xf3, 0xaa, 0xff, 0x01, 0x4c, 0xad, 0xb0, 0x05, 0xbd, 0xdb, - 0x72, 0x79, 0xc0, 0x7d, 0x62, 0x46, 0x50, 0xcf, 0x25, 0x5c, 0x95, 0x59, 0xcd, 0x90, 0x54, 0x58, - 0x10, 0xe4, 0x9e, 0xa2, 0xc1, 0xe4, 0x78, 0xcc, 0x48, 0xb6, 0x22, 0xe7, 0x01, 0x9e, 0xf0, 0x85, - 0xc9, 0x60, 0x8e, 0x2b, 0x96, 0xb5, 0x4e, 0xa7, 0x2d, 0x2d, 0xdb, 0xfc, 0xfa, 0xfe, 0x55, 0xe3, - 0x24, 0x9a, 0x2a, 0x97, 0xbc, 0xd3, 0xba, 0xe7, 0xe7, 0x5a, 0x96, 0xe1, 0x1c, 0x9e, 0x39, 0xe5, - 0xbd, 0xe6, 0xa2, 0x0a, 0x91, 0x5d, 0x6b, 0xb7, 0x53, 0xc4, 0x21, 0x79, 0xc3, 0xe4, 0x9e, 0x85, - 0xd3, 0xab, 0x06, 0x3c, 0xe9, 0x73, 0xe5, 0xad, 0xd6, 0xe9, 0xf0, 0xc5, 0xf2, 0xb2, 0x5a, 0x30, - 0xcc, 0x82, 0xf4, 0x49, 0x3f, 0x59, 0x2e, 0xd6, 0xf6, 0xfb, 0x38, 0xcd, 0xe2, 0x54, 0xc4, 0x44, - 0x3f, 0x37, 0x27, 0x33, 0x31, 0x2b, 0x5d, 0x2e, 0x51, 0xa8, 0xf6, 0x89, 0x33, 0xa8, 0x41, 0xc5, - 0x79, 0x8d, 0x95, 0x81, 0x27, 0x01, 0x97, 0xfc, 0x2e, 0xe7, 0x15, 0x2b, 0x83, 0x6b, 0x39, 0x99, - 0xee, 0x5d, 0x75, 0x39, 0x9d, 0x07, 0xde, 0xec, 0x72, 0x6e, 0x9e, 0xf8, 0xfb, 0x50, 0x4e, 0x66, - 0x9a, 0x56, 0x4c, 0x73, 0x52, 0x50, 0xe7, 0x8e, 0xc9, 0x5d, 0x98, 0xd1, 0x47, 0x54, 0xf5, 0x3b, - 0x6f, 0xf5, 0xcf, 0xe3, 0xb3, 0x03, 0xb3, 0x99, 0x89, 0xa1, 0xd5, 0x16, 0x5b, 0x94, 0x36, 0x3a, - 0x97, 0x2b, 0x85, 0x73, 0xd9, 0xb9, 0xe1, 0xc9, 0x2b, 0xa6, 0xfd, 0x20, 0x3b, 0x53, 0xf6, 0xfc, - 0xab, 0x3d, 0xb0, 0x84, 0x40, 0xbf, 0xc6, 0x1d, 0x30, 0x55, 0xc7, 0x55, 0xcd, 0xa2, 0x90, 0x53, - 0x81, 0x55, 0x84, 0xa2, 0xe6, 0xc0, 0x4c, 0x46, 0x71, 0xbe, 0x88, 0xaf, 0xe5, 0xf3, 0x8c, 0x27, - 0xd6, 0x9e, 0x8c, 0x04, 0x9d, 0x2b, 0x99, 0xc2, 0x1c, 0xe2, 0x05, 0x47, 0xd2, 0x79, 0x35, 0x1f, - 0x4e, 0xde, 0xe4, 0x3c, 0x6e, 0x2d, 0x65, 0xfd, 0x31, 0x12, 0x7c, 0x27, 0xad, 0x3f, 0x59, 0x89, - 0xc9, 0x95, 0x18, 0x8a, 0x52, 0xdf, 0xf3, 0xdd, 0xf8, 0x2b, 0x6e, 0x0e, 0x32, 0xab, 0xd0, 0xcd, - 0x41, 0x99, 0xfc, 0xaf, 0xe4, 0x23, 0xe8, 0xcc, 0x1d, 0x7e, 0xf7, 0x9b, 0xc8, 0x50, 0x4e, 0xf4, - 0x13, 0x57, 0x76, 0xf6, 0x72, 0x35, 0x37, 0x32, 0x51, 0xf4, 0x2a, 0x1e, 0xca, 0x6f, 0x30, 0x47, - 0x4a, 0x05, 0xe9, 0xdb, 0x8b, 0xd5, 0x94, 0x2d, 0xa8, 0xc4, 0x83, 0x99, 0xe8, 0xc0, 0x29, 0x87, - 0x52, 0x0a, 0xe3, 0x7c, 0x6e, 0xd2, 0x76, 0xf2, 0x7a, 0xea, 0x4b, 0xcf, 0x11, 0x4c, 0x61, 0x15, - 0x7c, 0x3d, 0xd7, 0x22, 0x4b, 0x5f, 0x88, 0x6d, 0xc1, 0x7a, 0x7e, 0xf7, 0xd4, 0x7a, 0x9e, 0x91, - 0xfc, 0xfd, 0x1e, 0xea, 0xc5, 0x5a, 0x02, 0xf7, 0xdc, 0x5e, 0x5f, 0xca, 0xe2, 0x13, 0xa6, 0x57, - 0x5c, 0xad, 0x5d, 0x52, 0x4f, 0x4b, 0x16, 0x9c, 0x66, 0xc5, 0x3d, 0x49, 0xd3, 0xf2, 0xf8, 0x2c, - 0xc3, 0xb8, 0x96, 0xf9, 0x9d, 0x9c, 0x37, 0xc4, 0x64, 0xec, 0xa1, 0xf3, 0x46, 0xe7, 0xcc, 0xed, - 0x73, 0x09, 0x2d, 0xd2, 0x2a, 0x7f, 0x7c, 0x6e, 0x2b, 0x2e, 0xa4, 0x79, 0x18, 0xd6, 0x68, 0x25, - 0x05, 0xde, 0x9a, 0x8b, 0x49, 0xe1, 0x18, 0x0d, 0xca, 0xef, 0x12, 0xd1, 0x45, 0xd3, 0xa3, 0x49, - 0xf9, 0xfa, 0xeb, 0xb4, 0x48, 0x2f, 0x8b, 0xe9, 0x60, 0x64, 0xe8, 0xc0, 0x73, 0xca, 0xb4, 0xa6, - 0x41, 0x0b, 0x2c, 0x1d, 0xdb, 0xf8, 0x02, 0x25, 0x23, 0x15, 0xbe, 0x5a, 0x61, 0x0b, 0x33, 0xe5, - 0x67, 0xe8, 0x6e, 0x6a, 0xcd, 0xce, 0xe5, 0x58, 0x98, 0x1b, 0x3f, 0xb7, 0xa5, 0x3f, 0xd2, 0xd6, - 0xec, 0x54, 0xc2, 0x7b, 0x72, 0x3d, 0xa9, 0xb8, 0xe5, 0xe5, 0xc4, 0x2f, 0xd8, 0x13, 0x66, 0xb2, - 0x72, 0xe5, 0x6b, 0xe6, 0xe1, 0xdc, 0x44, 0xfa, 0x19, 0x52, 0xb0, 0xe5, 0xfc, 0xcf, 0xe1, 0x56, - 0x90, 0x39, 0x3f, 0xb7, 0x85, 0x5f, 0x6a, 0x0b, 0x5d, 0x22, 0xc3, 0xbd, 0x3a, 0x8e, 0xf7, 0x48, - 0x81, 0x9f, 0xcb, 0x7b, 0x13, 0xdf, 0x2c, 0xa5, 0xd3, 0xd3, 0x2b, 0xcd, 0xa6, 0x28, 0x79, 0x7d, - 0xa6, 0xf5, 0x78, 0x36, 0xdd, 0x45, 0xc6, 0xef, 0x5c, 0xc2, 0xf6, 0xdb, 0xab, 0x61, 0x5f, 0xcb, - 0xc5, 0x38, 0x23, 0xad, 0x7d, 0x62, 0x31, 0xce, 0x4f, 0x7c, 0x5f, 0x70, 0x0c, 0x3a, 0x53, 0x77, - 0xf7, 0x3d, 0x2d, 0x2b, 0xbd, 0x3a, 0x04, 0xa5, 0x13, 0xe5, 0xab, 0x25, 0x26, 0x2b, 0x89, 0xfd, - 0x16, 0xd3, 0x7f, 0xb8, 0xf6, 0xae, 0xe7, 0x17, 0x27, 0xf3, 0xf9, 0x69, 0xd5, 0xd5, 0x72, 0x93, - 0x99, 0x90, 0x5c, 0x63, 0xa8, 0x27, 0xf7, 0x56, 0x0c, 0x33, 0xf2, 0x8c, 0x2b, 0x86, 0x99, 0xd9, - 0xc0, 0x6f, 0xa1, 0xd5, 0xc5, 0xf6, 0xdb, 0x54, 0xb7, 0xba, 0x68, 0xd9, 0xa2, 0x13, 0x46, 0x0f, - 0xf2, 0x21, 0x9a, 0x3c, 0x8a, 0xed, 0x24, 0x73, 0x26, 0x27, 0xdd, 0xb3, 0x64, 0x4c, 0xa5, 0xe2, - 0x56, 0x36, 0xf6, 0x64, 0x36, 0xf0, 0xf9, 0x4a, 0xba, 0x40, 0xd0, 0xbf, 0x23, 0xad, 0x26, 0xd8, - 0xe0, 0x8a, 0x69, 0x6d, 0xca, 0x6f, 0xf3, 0x3b, 0xd2, 0x64, 0x62, 0x90, 0xa5, 0x12, 0x71, 0x27, - 0xc9, 0x7e, 0x00, 0x13, 0x71, 0xd2, 0xed, 0xbd, 0x05, 0x8d, 0x30, 0x91, 0x89, 0x3b, 0x49, 0xf8, - 0x9e, 0xbc, 0x56, 0xc1, 0xfa, 0xcc, 0xc2, 0x62, 0x15, 0xe0, 0x63, 0x69, 0xa2, 0x31, 0x5a, 0x9a, - 0x4a, 0xe1, 0x5d, 0xb0, 0x72, 0x4f, 0xe8, 0x29, 0x33, 0xd5, 0xbc, 0xc8, 0x48, 0x7a, 0xab, 0xe6, - 0x45, 0x56, 0xd2, 0xda, 0xf8, 0xda, 0xe1, 0x0b, 0x69, 0x8f, 0x88, 0x99, 0x5e, 0x32, 0x9a, 0x95, - 0xe2, 0x7b, 0x39, 0xaf, 0x38, 0xc9, 0xba, 0x0e, 0xe5, 0x64, 0x7e, 0x4f, 0x75, 0x98, 0xcb, 0x49, - 0xc4, 0xaa, 0x4e, 0x88, 0xb9, 0x89, 0x41, 0xb7, 0xa5, 0x71, 0xdd, 0xe4, 0x7b, 0x35, 0xbb, 0x51, - 0x3a, 0xeb, 0x7c, 0x6b, 0xfb, 0xa4, 0x91, 0xea, 0x53, 0x3f, 0x66, 0xa7, 0x52, 0x89, 0xea, 0x6a, - 0x59, 0x46, 0x76, 0x50, 0x57, 0x46, 0x9d, 0xca, 0x4e, 0xb4, 0xfe, 0x86, 0x79, 0xfe, 0x2d, 0x88, - 0x0b, 0xdf, 0xf3, 0x0a, 0x9a, 0xfc, 0x0a, 0xcc, 0xe5, 0xc4, 0xb9, 0x26, 0xaf, 0x26, 0xcc, 0xb4, - 0xd9, 0x71, 0xb0, 0xd5, 0x04, 0xc9, 0xcc, 0xc1, 0xbd, 0x81, 0xbe, 0x0b, 0x46, 0x7c, 0x89, 0xd4, - 0x7d, 0xe0, 0x43, 0x37, 0x3a, 0xe0, 0xa9, 0xa6, 0xb5, 0x35, 0x37, 0x33, 0x30, 0x05, 0xa9, 0xe3, - 0x41, 0xc6, 0x80, 0x66, 0x5c, 0x09, 0x66, 0x30, 0x9c, 0xcf, 0x66, 0xc8, 0xd6, 0x0e, 0x36, 0x17, - 0x32, 0x82, 0x7f, 0xa8, 0xb9, 0x90, 0x1f, 0x18, 0x24, 0xb7, 0x99, 0xdb, 0x52, 0xc1, 0xca, 0xe6, - 0x98, 0x1f, 0x07, 0x24, 0x97, 0xe3, 0x7d, 0xc6, 0x31, 0x15, 0xda, 0x83, 0xe4, 0xa0, 0x17, 0xaf, - 0x1e, 0xb6, 0xdc, 0xaf, 0x4d, 0xaa, 0x05, 0xad, 0x7d, 0x79, 0x41, 0x44, 0x72, 0xdb, 0xb7, 0x22, - 0xbf, 0xa7, 0xec, 0xf6, 0x9d, 0x74, 0xc7, 0x56, 0x97, 0x67, 0x89, 0xe8, 0x32, 0x46, 0x47, 0x35, - 0xf8, 0x7c, 0x0e, 0x9c, 0x6c, 0xa2, 0x33, 0x52, 0x12, 0xaa, 0x9d, 0x68, 0xb3, 0xc3, 0xd7, 0xe4, - 0xf2, 0xe3, 0xf3, 0xd8, 0x08, 0xff, 0x71, 0x9a, 0x79, 0x9c, 0x88, 0x1b, 0x22, 0xe6, 0xb1, 0x01, - 0x3d, 0xdd, 0x3c, 0x4e, 0x30, 0x34, 0xe7, 0x71, 0xb2, 0x99, 0x49, 0x33, 0x41, 0xee, 0xa8, 0x26, - 0x9b, 0xa9, 0xe6, 0x71, 0x36, 0xc7, 0xfc, 0x30, 0x2d, 0xb9, 0x1c, 0xd5, 0x3c, 0x36, 0x39, 0xe6, - 0xa0, 0x9f, 0x70, 0x1e, 0x27, 0x2b, 0x31, 0xe7, 0xf1, 0xa9, 0xda, 0xa7, 0xe6, 0x71, 0x76, 0xfb, - 0x4e, 0x3d, 0x8f, 0x13, 0x71, 0x8d, 0x8c, 0x8e, 0x66, 0xcd, 0xe3, 0x24, 0x3e, 0x9f, 0xc7, 0x49, - 0x68, 0xc2, 0x32, 0x53, 0x30, 0x8f, 0x93, 0x94, 0x9f, 0x21, 0xbf, 0x44, 0x4c, 0x96, 0x93, 0xcc, - 0xe4, 0xdc, 0x70, 0x2e, 0xe4, 0x21, 0xda, 0x06, 0x13, 0xf0, 0x93, 0xcd, 0xe6, 0x8b, 0x79, 0x4c, - 0x71, 0x3e, 0xef, 0x49, 0x21, 0x26, 0x9b, 0x6b, 0x1a, 0xbe, 0xb2, 0x43, 0xd2, 0x14, 0x34, 0x78, - 0x8f, 0xcd, 0x9b, 0x56, 0x01, 0xdf, 0xa2, 0x88, 0x3a, 0x05, 0x7c, 0xd5, 0x39, 0x28, 0xc9, 0x37, - 0x97, 0xa4, 0x78, 0x7e, 0x7f, 0x2e, 0x6f, 0x47, 0x92, 0x74, 0x0b, 0x89, 0x93, 0xd5, 0xa9, 0x5b, - 0xaa, 0x4e, 0x58, 0xc9, 0x96, 0x9e, 0x76, 0x9e, 0x6f, 0x48, 0xed, 0x21, 0x15, 0x8a, 0x2b, 0xd1, - 0x69, 0x7d, 0xae, 0xe7, 0x96, 0x90, 0x1d, 0x34, 0x04, 0xa7, 0xe1, 0x9a, 0x11, 0x39, 0x2f, 0xe6, - 0x57, 0x4f, 0xae, 0xa9, 0xa0, 0x42, 0x3a, 0xd7, 0xbc, 0x88, 0x43, 0x8a, 0x6b, 0x9a, 0xfa, 0x13, - 0x34, 0x9d, 0x89, 0x17, 0x5f, 0xde, 0x63, 0x3f, 0xff, 0x9c, 0x33, 0x6d, 0x38, 0x4c, 0x31, 0x5c, - 0xf4, 0x53, 0xfb, 0x48, 0x5c, 0xff, 0x49, 0x60, 0xae, 0xf0, 0xb3, 0xe8, 0xc9, 0x27, 0x50, 0x16, - 0xcb, 0x5b, 0xcc, 0x20, 0x0b, 0x31, 0x77, 0xe8, 0x16, 0xa5, 0xc5, 0xee, 0x04, 0x2d, 0x38, 0x89, - 0xa5, 0xee, 0x24, 0x92, 0xc8, 0x37, 0x6b, 0xb1, 0xed, 0x70, 0x27, 0xe8, 0x86, 0x11, 0x6d, 0xa5, - 0xcd, 0x51, 0x66, 0x63, 0xa4, 0x5b, 0x85, 0x89, 0xbe, 0xb7, 0x40, 0xd6, 0x70, 0x6d, 0x33, 0xc1, - 0x45, 0xf6, 0xba, 0x6c, 0x36, 0xb8, 0xf4, 0xac, 0xaa, 0xa7, 0x45, 0x66, 0x9b, 0xf2, 0xea, 0xce, - 0x6f, 0x94, 0x12, 0xd1, 0x09, 0x7b, 0x97, 0x27, 0x22, 0x7e, 0xa0, 0xe6, 0xb6, 0xc3, 0x5e, 0x92, - 0x49, 0x3e, 0x76, 0x22, 0x9f, 0xc2, 0x98, 0x24, 0xee, 0x2d, 0x90, 0x24, 0x35, 0x0a, 0x64, 0x19, - 0x26, 0x8d, 0x97, 0x5c, 0xea, 0x74, 0x93, 0xf5, 0xbe, 0xab, 0x60, 0x9c, 0x27, 0x8d, 0x17, 0x5b, - 0x8a, 0x4b, 0xd6, 0x3b, 0xae, 0x5c, 0x2e, 0x3f, 0x84, 0x71, 0x21, 0xd2, 0x42, 0x69, 0xe4, 0x1b, - 0xeb, 0x66, 0x35, 0xaf, 0xe8, 0x6e, 0xcb, 0x8d, 0x96, 0x7c, 0xef, 0xb1, 0xbb, 0xdf, 0x53, 0x30, - 0x69, 0x92, 0xbd, 0x05, 0xf2, 0x15, 0x26, 0x66, 0x96, 0xe9, 0xb2, 0x69, 0xf4, 0xcc, 0x0f, 0x9e, - 0xb8, 0xde, 0x7e, 0x0f, 0x96, 0x57, 0x4c, 0x96, 0x49, 0x3a, 0xe9, 0x78, 0xf2, 0x15, 0xcc, 0xd7, - 0xf3, 0x99, 0xf7, 0x64, 0x52, 0xbc, 0xbd, 0xd4, 0xe1, 0x22, 0xba, 0xde, 0x9c, 0xb6, 0xed, 0x85, - 0x4c, 0xbf, 0xe0, 0xd1, 0x1c, 0xa5, 0xa1, 0xbf, 0xe9, 0x07, 0xad, 0xde, 0x1c, 0xab, 0xa6, 0x33, - 0x6f, 0x82, 0x4c, 0x0a, 0xe3, 0x0b, 0x38, 0x5f, 0xcf, 0x65, 0xdd, 0x8b, 0x45, 0x2f, 0x4d, 0xf2, - 0x02, 0x8a, 0xe2, 0x94, 0xed, 0x2e, 0xe4, 0xb9, 0x86, 0x6b, 0x1a, 0xdb, 0x87, 0xb6, 0x03, 0xfa, - 0x98, 0x06, 0xe8, 0x32, 0xde, 0xcb, 0x59, 0xda, 0x44, 0x97, 0x3d, 0x5f, 0x83, 0xb3, 0xf5, 0x14, - 0xab, 0x3c, 0x92, 0x5e, 0x97, 0x47, 0xd3, 0xd8, 0xd3, 0x13, 0xb6, 0xab, 0x87, 0x8b, 0xd1, 0xf8, - 0x3d, 0x1a, 0xed, 0xae, 0xf5, 0x90, 0x92, 0x7c, 0xd3, 0x20, 0x11, 0xf7, 0xee, 0x30, 0xca, 0xba, - 0x46, 0x99, 0xc6, 0xc8, 0xfd, 0x78, 0x3f, 0x95, 0x17, 0x29, 0x3d, 0xab, 0xcd, 0xe3, 0xf0, 0x16, - 0xae, 0x85, 0xc2, 0x6d, 0x5a, 0x33, 0x41, 0x72, 0x48, 0x6c, 0xaa, 0xd3, 0x3c, 0xa8, 0x43, 0x52, - 0xe3, 0xc7, 0x3f, 0x3e, 0x3d, 0x04, 0xec, 0x72, 0xca, 0x9d, 0xbe, 0x90, 0x05, 0x37, 0xa1, 0xae, - 0xfb, 0xcd, 0x27, 0xba, 0x09, 0x55, 0x4b, 0xdd, 0x3f, 0x6f, 0x26, 0xd6, 0x17, 0x2b, 0x3e, 0x66, - 0xd7, 0xd7, 0xbd, 0xc6, 0xf4, 0xe4, 0xfd, 0xba, 0x09, 0x55, 0xc0, 0x85, 0x05, 0xe9, 0x2d, 0x69, - 0x5b, 0xc4, 0x0a, 0x4d, 0xce, 0xb9, 0xa2, 0x51, 0x66, 0x45, 0x24, 0x32, 0xcd, 0x8a, 0x7a, 0x43, - 0xf3, 0x2f, 0x02, 0x88, 0x4d, 0x3b, 0x6d, 0xf4, 0xc4, 0x3e, 0xf4, 0x39, 0x4d, 0xec, 0x9c, 0x9b, - 0x2e, 0xea, 0xed, 0xfc, 0x35, 0x2d, 0x5c, 0x86, 0x0c, 0xc1, 0xab, 0x88, 0xc8, 0xe9, 0xb2, 0x58, - 0x94, 0xba, 0x27, 0xd3, 0xed, 0x12, 0xd9, 0x84, 0x73, 0xf7, 0x68, 0x24, 0xd6, 0x38, 0x9b, 0x86, - 0x51, 0xe0, 0x36, 0xa3, 0xc2, 0x5b, 0x45, 0x79, 0x36, 0xc9, 0xa0, 0xd9, 0x7b, 0x9b, 0xf1, 0xab, - 0x67, 0xf3, 0x2b, 0xa4, 0x2b, 0xf0, 0xaf, 0x15, 0x57, 0x15, 0xa7, 0x69, 0x62, 0xfe, 0x14, 0x1f, - 0xe1, 0xee, 0x3b, 0xf9, 0xa4, 0xe5, 0x38, 0xfa, 0x8a, 0x38, 0x6d, 0xdd, 0x84, 0x61, 0x4e, 0x94, - 0xbb, 0xa1, 0x4e, 0xe8, 0x34, 0xe4, 0x0e, 0x8c, 0x29, 0xff, 0x1b, 0x62, 0x14, 0xe5, 0xb6, 0xeb, - 0x0e, 0x8c, 0xf1, 0xa3, 0xd5, 0xc9, 0x49, 0x3e, 0x84, 0x31, 0xe5, 0xb0, 0x73, 0xea, 0x9d, 0xfe, - 0x13, 0x98, 0xd4, 0x5d, 0x77, 0x4e, 0x2f, 0xc8, 0x1f, 0xe2, 0xdd, 0xaf, 0xbc, 0x62, 0xc9, 0xa7, - 0x9f, 0x4d, 0x04, 0xa5, 0x11, 0x22, 0xe5, 0x0b, 0xa4, 0x04, 0xe6, 0x36, 0xff, 0x6c, 0x8a, 0x9a, - 0x7c, 0x28, 0x5f, 0x53, 0x29, 0xe2, 0x34, 0x52, 0x81, 0xcc, 0xa6, 0xb8, 0x98, 0x5f, 0x84, 0x58, - 0x2d, 0xb0, 0x3d, 0x9b, 0x7d, 0x92, 0x3b, 0xea, 0xde, 0xa2, 0xcb, 0xe3, 0xb2, 0x85, 0x5a, 0x5a, - 0x2a, 0x19, 0x5e, 0x3e, 0xa3, 0xcb, 0xf9, 0xf9, 0xf3, 0x70, 0x30, 0xee, 0xe3, 0x29, 0x30, 0x55, - 0x9a, 0xdb, 0xbd, 0x82, 0x7c, 0x7c, 0xf1, 0xb1, 0x37, 0xcd, 0xae, 0x80, 0xac, 0xe8, 0x14, 0x2d, - 0xde, 0x88, 0xbe, 0x14, 0x76, 0x6b, 0xd2, 0x03, 0xf2, 0xe4, 0x9d, 0xcd, 0x6f, 0xd9, 0x85, 0x8c, - 0x5b, 0xf1, 0x9e, 0x63, 0x91, 0xc7, 0xee, 0x57, 0x50, 0x3b, 0xcc, 0x8c, 0x4a, 0x96, 0xcf, 0xec, - 0xba, 0xe6, 0x58, 0x91, 0x49, 0xa9, 0x36, 0xbd, 0x27, 0xf8, 0x4c, 0x2d, 0x3b, 0x5d, 0xe0, 0x6b, - 0x3d, 0xb8, 0x48, 0x49, 0xbc, 0xde, 0x13, 0x4f, 0xdd, 0xb1, 0x5e, 0xe0, 0x3b, 0x6c, 0x76, 0x7d, - 0x3d, 0xd2, 0x1f, 0x66, 0x5c, 0x7b, 0x2b, 0xf7, 0xd2, 0x6c, 0x86, 0xa6, 0x7b, 0x69, 0x61, 0x1f, - 0xf2, 0xc4, 0xff, 0x19, 0x54, 0x63, 0xef, 0x91, 0xd3, 0x0d, 0x42, 0xbe, 0x57, 0x23, 0x49, 0x49, - 0x2a, 0x24, 0x45, 0xf9, 0x80, 0xe6, 0xaf, 0xe6, 0x49, 0x38, 0xd4, 0xdc, 0x92, 0x84, 0x57, 0x5c, - 0x22, 0x71, 0x66, 0x5e, 0x0a, 0xce, 0x02, 0x3b, 0xac, 0x78, 0xb7, 0xf7, 0x52, 0x18, 0xa5, 0x47, - 0xfb, 0xf4, 0x8c, 0x94, 0x73, 0x47, 0x82, 0x91, 0x55, 0x30, 0xbc, 0xbd, 0xaf, 0x1e, 0x2b, 0x39, - 0xe3, 0x7a, 0xfa, 0x01, 0x75, 0xe2, 0xb7, 0x6a, 0x89, 0x20, 0x86, 0xfa, 0xfb, 0xe0, 0x74, 0x51, - 0xf2, 0xa1, 0x55, 0x16, 0x86, 0xf2, 0xa8, 0xaa, 0xc8, 0x2a, 0x18, 0x9c, 0x1d, 0x45, 0xfc, 0xc0, - 0x8d, 0x9e, 0x2f, 0xd9, 0xeb, 0xb1, 0x59, 0x41, 0x2f, 0x90, 0xbc, 0x41, 0x16, 0xda, 0xeb, 0xe4, - 0x4b, 0x5c, 0x4a, 0x04, 0xfb, 0x45, 0xdf, 0x8f, 0xc2, 0x28, 0x70, 0x3a, 0xf5, 0x66, 0xe0, 0x76, - 0xa2, 0xdc, 0x4e, 0xc7, 0x0e, 0xe0, 0x59, 0x64, 0x9a, 0x3f, 0xaa, 0x08, 0x72, 0x9f, 0x15, 0x7d, - 0x47, 0xbd, 0xc9, 0xc9, 0x2a, 0x2c, 0x38, 0xb9, 0xd4, 0x65, 0x58, 0xfb, 0x97, 0xc9, 0xb4, 0x01, - 0x73, 0x39, 0x31, 0x8b, 0xd4, 0xed, 0x6d, 0x71, 0x4c, 0xa3, 0xf9, 0xe2, 0x8a, 0xc9, 0x57, 0x30, - 0x9b, 0x19, 0xd4, 0x48, 0x59, 0xa0, 0x8b, 0x42, 0x1e, 0xf5, 0x62, 0xfe, 0x04, 0x2a, 0xfc, 0x35, - 0x08, 0x3a, 0x3d, 0x1b, 0xf1, 0x6d, 0xe2, 0x37, 0x42, 0x39, 0x08, 0xc9, 0xf5, 0x3a, 0x1f, 0x4f, - 0x3d, 0x78, 0x9f, 0xc1, 0xc0, 0x26, 0x89, 0x94, 0xef, 0xea, 0xc3, 0xcb, 0x2a, 0x2c, 0x7a, 0x88, - 0xb4, 0x0d, 0xb3, 0x7b, 0x34, 0x70, 0x1f, 0x3f, 0x4f, 0x32, 0x94, 0x92, 0xc9, 0x2c, 0x2d, 0xe2, - 0xf8, 0x39, 0xcc, 0x2d, 0xf9, 0x87, 0x1d, 0xf1, 0xe4, 0xcf, 0xe0, 0xa9, 0xae, 0xe2, 0xb3, 0xcb, - 0x7b, 0x3b, 0x42, 0xcd, 0xe7, 0x27, 0xe7, 0x57, 0xfe, 0x6f, 0x3d, 0xf3, 0xf7, 0xab, 0x87, 0x6b, - 0x26, 0xfd, 0x0e, 0x4e, 0xc2, 0xac, 0x6c, 0xfd, 0xfa, 0x24, 0x2c, 0xc8, 0xe6, 0x9f, 0xf3, 0x80, - 0x6c, 0x2e, 0x27, 0x41, 0x7f, 0x01, 0xd7, 0x13, 0xb4, 0x76, 0x53, 0xee, 0x2d, 0x66, 0xbe, 0xf1, - 0x84, 0xc7, 0x75, 0x66, 0x32, 0xf2, 0xcc, 0x76, 0x6a, 0x91, 0x1d, 0xda, 0xed, 0x02, 0x15, 0x8b, - 0xe8, 0xa1, 0x1d, 0x18, 0x26, 0x1a, 0xf1, 0x27, 0x75, 0xda, 0xa2, 0xd5, 0x3a, 0x45, 0x8c, 0x4a, - 0xed, 0x07, 0x30, 0x51, 0xd7, 0x2b, 0xcf, 0xa8, 0x24, 0x77, 0x52, 0xa8, 0x27, 0x44, 0xbd, 0xdb, - 0x5e, 0xe0, 0x48, 0xaa, 0x36, 0x9e, 0x13, 0xf5, 0x22, 0xd7, 0x75, 0xc6, 0x48, 0x1e, 0xa7, 0x76, - 0x81, 0xac, 0xdc, 0x8e, 0xca, 0x75, 0x26, 0x3b, 0xdf, 0x5c, 0x83, 0xa7, 0xbb, 0x49, 0xa6, 0xee, - 0x24, 0x56, 0xef, 0x1c, 0xb9, 0xca, 0xa1, 0xbe, 0x30, 0xf7, 0x27, 0xf7, 0xf3, 0x89, 0xd3, 0xe5, - 0xe9, 0x7e, 0x3e, 0xa9, 0x24, 0x7c, 0xba, 0x9f, 0x4f, 0x46, 0x86, 0xbd, 0x15, 0xe4, 0x15, 0xe7, - 0x09, 0x2a, 0x30, 0x46, 0x28, 0x36, 0x19, 0xe9, 0x88, 0x1e, 0xe8, 0x01, 0x42, 0x78, 0x76, 0xa1, - 0x02, 0x5b, 0x6b, 0x32, 0x30, 0x48, 0x22, 0x1d, 0xd1, 0x5d, 0x28, 0xf3, 0x44, 0x0b, 0x71, 0x4c, - 0xc5, 0xd8, 0x6f, 0x30, 0x9d, 0xff, 0xa1, 0x60, 0x50, 0xcb, 0xc9, 0x68, 0x74, 0xca, 0x64, 0x96, - 0x13, 0xa6, 0xae, 0x60, 0xaa, 0x42, 0x1c, 0x73, 0x4e, 0x19, 0xa6, 0x52, 0x61, 0xe8, 0xe6, 0xcf, - 0x67, 0x94, 0x28, 0x95, 0x72, 0x42, 0x8f, 0x50, 0xa7, 0xba, 0x94, 0x11, 0xb6, 0x6e, 0xfe, 0x42, - 0x66, 0x99, 0x60, 0x14, 0xf1, 0x34, 0xd1, 0xd9, 0xc9, 0xad, 0xe3, 0x57, 0x60, 0x05, 0x38, 0xb2, - 0x9a, 0x1b, 0x27, 0x41, 0x15, 0xb5, 0x52, 0x95, 0x25, 0x29, 0x23, 0xa3, 0xf6, 0xeb, 0x19, 0x0f, - 0x35, 0x0c, 0x8c, 0xd8, 0x1b, 0xac, 0x38, 0xbd, 0x37, 0x79, 0x28, 0xb3, 0xd6, 0xe4, 0xd4, 0xd4, - 0x8b, 0x41, 0xee, 0x08, 0x3e, 0x94, 0x79, 0x6a, 0x5e, 0x36, 0xe3, 0x47, 0x70, 0x31, 0xf1, 0xfa, - 0xc3, 0x64, 0x7c, 0x23, 0xfb, 0x89, 0x48, 0xa6, 0x78, 0xf2, 0x75, 0xf6, 0x2b, 0xe9, 0x57, 0x22, - 0x89, 0x71, 0x3f, 0xed, 0x9a, 0xb7, 0x01, 0x53, 0xb8, 0xcc, 0xc8, 0xdc, 0xf0, 0x71, 0x7c, 0x1a, - 0x13, 0x9c, 0x0c, 0x94, 0x94, 0x2c, 0x55, 0x2e, 0xb3, 0x13, 0xe2, 0x45, 0x31, 0xcf, 0x34, 0x3f, - 0x6f, 0x3e, 0x33, 0x46, 0x60, 0xd6, 0x2e, 0x26, 0x12, 0xd8, 0x93, 0x1f, 0xc2, 0x99, 0xf8, 0xa1, - 0x31, 0x67, 0x91, 0x81, 0x56, 0x60, 0x28, 0x3b, 0x13, 0xbf, 0x36, 0x3e, 0x3d, 0xf9, 0xaa, 0xdc, - 0x8a, 0x62, 0xf2, 0x4b, 0xa9, 0xb7, 0x32, 0x46, 0x1f, 0x4e, 0xb2, 0x23, 0x69, 0xb2, 0x3d, 0xed, - 0xe8, 0x34, 0xf1, 0x73, 0xcb, 0x0e, 0xbd, 0xa8, 0x7f, 0x6e, 0x85, 0xe1, 0x21, 0x95, 0xfa, 0x9b, - 0xc3, 0x67, 0x03, 0xae, 0x61, 0xb8, 0x96, 0x6d, 0x1e, 0xa0, 0x2f, 0x1b, 0x2b, 0xbf, 0xed, 0xc9, - 0x20, 0x2f, 0x6d, 0xb8, 0xda, 0x33, 0xf6, 0x24, 0xb9, 0x65, 0xb8, 0xb8, 0xf4, 0x8e, 0x52, 0x59, - 0x70, 0xf2, 0x98, 0xc9, 0x0a, 0xe1, 0xa8, 0xf6, 0xd9, 0x82, 0x68, 0x92, 0x6a, 0x9f, 0x2d, 0x8c, - 0x01, 0xf9, 0x39, 0xa6, 0x82, 0x12, 0x7b, 0x14, 0x86, 0x60, 0xa2, 0x1e, 0x0f, 0x4a, 0x5d, 0x78, - 0xed, 0x73, 0xd5, 0xbc, 0x14, 0x4d, 0x11, 0xe2, 0x99, 0xe6, 0xb2, 0x38, 0x89, 0xe5, 0x31, 0xef, - 0xcd, 0xa4, 0xc0, 0xb5, 0xfa, 0x32, 0x9f, 0x80, 0xa7, 0x6e, 0x79, 0x0e, 0x7c, 0x71, 0xf9, 0x67, - 0xff, 0xe1, 0x72, 0xe9, 0x67, 0x3f, 0xbf, 0x5c, 0xfa, 0xd7, 0x3f, 0xbf, 0x5c, 0xfa, 0xf7, 0x3f, - 0xbf, 0x5c, 0xfa, 0x72, 0xe1, 0x64, 0xa1, 0x91, 0x9b, 0x6d, 0x97, 0x7a, 0xd1, 0x2d, 0xce, 0x6e, - 0x18, 0xff, 0x7b, 0xeb, 0xbf, 0x07, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x66, 0x4b, 0x5c, 0x15, 0xeb, - 0x00, 0x00, + // 15036 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x59, 0x6c, 0x64, 0x49, + 0x76, 0x18, 0xca, 0x4c, 0xee, 0x87, 0x4b, 0x65, 0x05, 0xc9, 0x62, 0x16, 0x6b, 0xc9, 0xaa, 0x5b, + 0xbd, 0x54, 0xd7, 0xf4, 0xd4, 0xc2, 0x5e, 0xa6, 0xb7, 0xe9, 0xee, 0xe4, 0x52, 0x24, 0xab, 0xb8, + 0xf5, 0x4d, 0x92, 0xd5, 0x9b, 0x26, 0xe7, 0x32, 0x33, 0x8a, 0xbc, 0xaa, 0xe4, 0xbd, 0x39, 0xf7, + 0xde, 0xac, 0xea, 0x1a, 0x3d, 0xe9, 0x41, 0xd2, 0x5b, 0xf4, 0xf3, 0xde, 0x93, 0x80, 0xf7, 0x04, + 0xbd, 0xf7, 0x3e, 0x64, 0x03, 0x36, 0x60, 0x18, 0xb0, 0xe1, 0x1f, 0x43, 0x3f, 0x16, 0x0c, 0x7f, + 0x79, 0x2c, 0xc0, 0xb0, 0x0d, 0x49, 0x3f, 0x06, 0x4c, 0xd9, 0x03, 0xe8, 0x87, 0xb0, 0x3f, 0x04, + 0xc3, 0x06, 0x3c, 0x80, 0x00, 0x23, 0x4e, 0x2c, 0x37, 0xe2, 0x2e, 0x99, 0x64, 0x75, 0xf5, 0xc8, + 0x3f, 0x55, 0xcc, 0x13, 0xe7, 0x9c, 0x88, 0x7b, 0x62, 0x3b, 0x71, 0xe2, 0xc4, 0x39, 0x70, 0x3b, + 0xa2, 0x2d, 0xda, 0xf6, 0x83, 0xe8, 0x4e, 0x8b, 0x1e, 0x38, 0x8d, 0xe7, 0x77, 0x1a, 0x2d, 0x97, + 0x7a, 0xd1, 0x9d, 0x76, 0xe0, 0x47, 0xfe, 0x1d, 0xa7, 0x13, 0x1d, 0x86, 0x34, 0x78, 0xea, 0x36, + 0xe8, 0x6d, 0x84, 0x90, 0x41, 0xfc, 0x6f, 0x6e, 0xfa, 0xc0, 0x3f, 0xf0, 0x39, 0x0e, 0xfb, 0x8b, + 0x17, 0xce, 0x5d, 0x3a, 0xf0, 0xfd, 0x83, 0x16, 0xe5, 0xc4, 0xfb, 0x9d, 0xc7, 0x77, 0xe8, 0x51, + 0x3b, 0x7a, 0x2e, 0x0a, 0x2b, 0xc9, 0xc2, 0xc8, 0x3d, 0xa2, 0x61, 0xe4, 0x1c, 0xb5, 0x05, 0xc2, + 0x1b, 0xaa, 0x29, 0x4e, 0x14, 0xb1, 0x92, 0xc8, 0xf5, 0xbd, 0x3b, 0x4f, 0xef, 0xe9, 0x3f, 0x05, + 0xea, 0xcd, 0xae, 0xad, 0x6e, 0xd0, 0x20, 0x0a, 0x4f, 0x85, 0x49, 0x9f, 0x52, 0x2f, 0x4a, 0x55, + 0x2f, 0x30, 0xa3, 0xe7, 0x6d, 0x1a, 0x72, 0x14, 0xf9, 0x9f, 0x40, 0xbd, 0x9e, 0x8d, 0x8a, 0xff, + 0x0a, 0x94, 0xef, 0x67, 0xa3, 0x3c, 0xa3, 0xfb, 0x4c, 0xa6, 0x9e, 0xfa, 0xa3, 0x07, 0x7a, 0xe0, + 0xb4, 0xdb, 0x34, 0x88, 0xff, 0x10, 0xe8, 0x17, 0x15, 0xfa, 0xd1, 0x63, 0x87, 0x89, 0xe8, 0xe8, + 0xb1, 0x93, 0xfa, 0x8c, 0x4e, 0xe8, 0x1c, 0x50, 0xd1, 0xfc, 0xa7, 0xf7, 0xf4, 0x9f, 0x1c, 0xd5, + 0xfa, 0xc3, 0x02, 0x0c, 0x3e, 0x72, 0xa2, 0xc6, 0x21, 0xf9, 0x04, 0x06, 0x1f, 0xba, 0x5e, 0x33, + 0x2c, 0x17, 0xae, 0xf5, 0xdf, 0x1c, 0x9b, 0x2f, 0xdd, 0xe6, 0x9f, 0x82, 0x85, 0xac, 0x60, 0x61, + 0xf6, 0x67, 0xc7, 0x95, 0xbe, 0x93, 0xe3, 0xca, 0xb9, 0x27, 0x0c, 0xed, 0x4d, 0xff, 0xc8, 0x8d, + 0xb0, 0x6f, 0x6d, 0x4e, 0x47, 0x76, 0x61, 0xaa, 0xda, 0x6a, 0xf9, 0xcf, 0xb6, 0x9d, 0x20, 0x72, + 0x9d, 0x56, 0xad, 0xd3, 0x68, 0xd0, 0x30, 0x2c, 0x17, 0xaf, 0x15, 0x6e, 0x8e, 0x2c, 0xdc, 0x38, + 0x39, 0xae, 0x54, 0x1c, 0x56, 0x5c, 0x6f, 0xf3, 0xf2, 0x7a, 0xc8, 0x11, 0x34, 0x46, 0x59, 0xf4, + 0xd6, 0x9f, 0x0c, 0x41, 0x69, 0xd5, 0x0f, 0xa3, 0x45, 0xd6, 0xa3, 0x36, 0xfd, 0x49, 0x87, 0x86, + 0x11, 0xb9, 0x01, 0x43, 0x0c, 0xb6, 0xb6, 0x54, 0x2e, 0x5c, 0x2b, 0xdc, 0x1c, 0x5d, 0x18, 0x3b, + 0x39, 0xae, 0x0c, 0x1f, 0xfa, 0x61, 0x54, 0x77, 0x9b, 0xb6, 0x28, 0x22, 0x6f, 0xc0, 0xc8, 0xa6, + 0xdf, 0xa4, 0x9b, 0xce, 0x11, 0xc5, 0x56, 0x8c, 0x2e, 0x4c, 0x9c, 0x1c, 0x57, 0x46, 0x3d, 0xbf, + 0x49, 0xeb, 0x9e, 0x73, 0x44, 0x6d, 0x55, 0x4c, 0xf6, 0x60, 0xc0, 0xf6, 0x5b, 0xb4, 0xdc, 0x8f, + 0x68, 0x0b, 0x27, 0xc7, 0x95, 0x81, 0xc0, 0x6f, 0xd1, 0x5f, 0x1c, 0x57, 0xde, 0x3d, 0x70, 0xa3, + 0xc3, 0xce, 0xfe, 0xed, 0x86, 0x7f, 0x74, 0xe7, 0x20, 0x70, 0x9e, 0xba, 0x7c, 0x10, 0x3a, 0xad, + 0x3b, 0xf1, 0x50, 0x6d, 0xbb, 0xa2, 0xdf, 0x6b, 0xcf, 0xc3, 0x88, 0x1e, 0x31, 0x4e, 0x36, 0xf2, + 0x23, 0x8f, 0x60, 0xba, 0xda, 0x6c, 0xba, 0x9c, 0x62, 0x3b, 0x70, 0xbd, 0x86, 0xdb, 0x76, 0x5a, + 0x61, 0x79, 0xe0, 0x5a, 0xff, 0xcd, 0x51, 0x21, 0x14, 0x55, 0x5e, 0x6f, 0x2b, 0x04, 0x4d, 0x28, + 0x99, 0x0c, 0xc8, 0x5b, 0x30, 0xb2, 0xb4, 0x59, 0x63, 0x6d, 0x0f, 0xcb, 0x83, 0xc8, 0x6c, 0xf6, + 0xe4, 0xb8, 0x32, 0xd5, 0xf4, 0x42, 0xfc, 0x34, 0x9d, 0x81, 0x42, 0x24, 0xef, 0xc2, 0xf8, 0x76, + 0x67, 0xbf, 0xe5, 0x36, 0x76, 0xd6, 0x6b, 0x0f, 0xe9, 0xf3, 0xf2, 0xd0, 0xb5, 0xc2, 0xcd, 0xf1, + 0x05, 0x72, 0x72, 0x5c, 0x99, 0x6c, 0x23, 0xbc, 0x1e, 0xb5, 0xc2, 0xfa, 0x13, 0xfa, 0xdc, 0x36, + 0xf0, 0x62, 0xba, 0x5a, 0x6d, 0x95, 0xd1, 0x0d, 0xa7, 0xe8, 0xc2, 0xf0, 0x50, 0xa7, 0xe3, 0x78, + 0xe4, 0x0e, 0x80, 0x4d, 0x8f, 0xfc, 0x88, 0x56, 0x9b, 0xcd, 0xa0, 0x3c, 0x82, 0xb2, 0x3d, 0x77, + 0x72, 0x5c, 0x19, 0x0b, 0x10, 0x5a, 0x77, 0x9a, 0xcd, 0xc0, 0xd6, 0x50, 0xc8, 0x22, 0x8c, 0xd8, + 0x3e, 0x17, 0x70, 0x79, 0xf4, 0x5a, 0xe1, 0xe6, 0xd8, 0xfc, 0x39, 0x31, 0x0c, 0x25, 0x78, 0xe1, + 0xc2, 0xc9, 0x71, 0x85, 0x04, 0xe2, 0x97, 0xfe, 0x95, 0x12, 0x83, 0x54, 0x60, 0x78, 0xd3, 0x5f, + 0x74, 0x1a, 0x87, 0xb4, 0x0c, 0x38, 0xf6, 0x06, 0x4f, 0x8e, 0x2b, 0x85, 0xef, 0xdb, 0x12, 0x4a, + 0x9e, 0xc2, 0x58, 0xdc, 0x51, 0x61, 0x79, 0x0c, 0xc5, 0xb7, 0x73, 0x72, 0x5c, 0xb9, 0x10, 0x22, + 0xb8, 0xce, 0xba, 0x5e, 0x93, 0xe0, 0xb7, 0x18, 0x05, 0x7a, 0x45, 0xe4, 0x6b, 0x98, 0x89, 0x7f, + 0x56, 0xc3, 0x90, 0x06, 0x8c, 0xc7, 0xda, 0x52, 0x79, 0x02, 0x25, 0xf3, 0xda, 0xc9, 0x71, 0xc5, + 0xd2, 0x5a, 0x50, 0x77, 0x24, 0x4a, 0xdd, 0x6d, 0x6a, 0x5f, 0x9a, 0xcd, 0xe4, 0xc1, 0xc0, 0xc8, + 0x78, 0x69, 0xc2, 0xbe, 0xb2, 0xeb, 0x85, 0x91, 0xb3, 0xdf, 0xa2, 0x99, 0x48, 0xd6, 0x5f, 0x17, + 0x80, 0x6c, 0xb5, 0xa9, 0x57, 0xab, 0xad, 0xb2, 0xf9, 0x24, 0xa7, 0xd3, 0x9b, 0x30, 0xca, 0x3b, + 0x8e, 0xf5, 0x6e, 0x11, 0x7b, 0x77, 0xf2, 0xe4, 0xb8, 0x02, 0xa2, 0x77, 0x59, 0xcf, 0xc6, 0x08, + 0xe4, 0x55, 0xe8, 0xdf, 0xd9, 0x59, 0xc7, 0xb9, 0xd2, 0xbf, 0x30, 0x75, 0x72, 0x5c, 0xe9, 0x8f, + 0xa2, 0xd6, 0x2f, 0x8e, 0x2b, 0x23, 0x4b, 0x9d, 0x00, 0xc5, 0x62, 0xb3, 0x72, 0xf2, 0x2a, 0x0c, + 0x2f, 0xb6, 0x3a, 0x61, 0x44, 0x83, 0xf2, 0x40, 0x3c, 0x49, 0x1b, 0x1c, 0x64, 0xcb, 0x32, 0xf2, + 0x3d, 0x18, 0xd8, 0x0d, 0x69, 0x50, 0x1e, 0xc4, 0xfe, 0x9e, 0x10, 0xfd, 0xcd, 0x40, 0x7b, 0xf3, + 0x0b, 0x23, 0x6c, 0x26, 0x76, 0x42, 0x1a, 0xd8, 0x88, 0x44, 0x6e, 0xc3, 0x20, 0xef, 0xb4, 0x21, + 0x5c, 0xa4, 0x26, 0xd4, 0xe8, 0x68, 0xd1, 0xbd, 0x77, 0x17, 0x46, 0x4f, 0x8e, 0x2b, 0x83, 0xd8, + 0x79, 0x36, 0x47, 0x7b, 0x30, 0x30, 0x52, 0x28, 0x15, 0xed, 0x11, 0x46, 0xcb, 0xa6, 0x85, 0xf5, + 0x3d, 0x18, 0xd3, 0x3e, 0x9f, 0x5c, 0x86, 0x01, 0xf6, 0x3f, 0x2e, 0x22, 0xe3, 0xbc, 0x32, 0xb6, + 0x71, 0xd8, 0x08, 0xb5, 0xfe, 0xd6, 0x14, 0x94, 0x18, 0xa5, 0xb1, 0xf2, 0xdc, 0xd6, 0x45, 0xc5, + 0xe9, 0x4a, 0xa6, 0xa8, 0xca, 0x05, 0x5d, 0x58, 0x37, 0x41, 0xd5, 0x2e, 0x16, 0xa1, 0xf1, 0x93, + 0xe3, 0xca, 0x48, 0x47, 0xc0, 0xe2, 0xb6, 0x91, 0x1a, 0x0c, 0x2f, 0x7f, 0xd3, 0x76, 0x03, 0x1a, + 0xa2, 0x68, 0xc7, 0xe6, 0xe7, 0x6e, 0xf3, 0xed, 0xf2, 0xb6, 0xdc, 0x2e, 0x6f, 0xef, 0xc8, 0xed, + 0x72, 0xe1, 0x8a, 0x58, 0x8c, 0xcf, 0x53, 0x4e, 0x12, 0x8f, 0x8f, 0xdf, 0xfd, 0x8b, 0x4a, 0xc1, + 0x96, 0x9c, 0xc8, 0x9b, 0x30, 0x74, 0xdf, 0x0f, 0x8e, 0x9c, 0x48, 0xf4, 0xc1, 0xf4, 0xc9, 0x71, + 0xa5, 0xf4, 0x18, 0x21, 0xda, 0x90, 0x12, 0x38, 0xe4, 0x3e, 0x4c, 0xda, 0x7e, 0x27, 0xa2, 0x3b, + 0xbe, 0xec, 0xb9, 0x41, 0xa4, 0xba, 0x7a, 0x72, 0x5c, 0x99, 0x0b, 0x58, 0x49, 0x3d, 0xf2, 0xeb, + 0xa2, 0x0b, 0x35, 0xfa, 0x04, 0x15, 0x59, 0x86, 0xc9, 0x2a, 0xae, 0xde, 0x42, 0x6a, 0xbc, 0xbf, + 0x46, 0x17, 0xae, 0x9c, 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, 0x8c, 0x2d, + 0xba, 0x76, 0x72, 0x5c, 0xb9, 0xfc, 0x44, 0x15, 0x66, 0xb4, 0x29, 0x4d, 0x4a, 0x28, 0x9c, 0x13, + 0x0d, 0x5d, 0x72, 0x22, 0x67, 0xdf, 0x09, 0x29, 0x2e, 0x4a, 0x63, 0xf3, 0x17, 0xb8, 0x88, 0x6f, + 0x27, 0x4a, 0x17, 0x6e, 0x08, 0x29, 0x5f, 0x52, 0xdf, 0xde, 0x14, 0x45, 0x5a, 0x45, 0x49, 0x9e, + 0x6c, 0x6d, 0x56, 0xfb, 0xce, 0x28, 0xb6, 0x16, 0xd7, 0x66, 0xb5, 0xef, 0xe8, 0xab, 0x96, 0xda, + 0x81, 0xd6, 0x61, 0x70, 0x97, 0xed, 0xce, 0xb8, 0x66, 0x4d, 0xce, 0x5f, 0x17, 0x2d, 0x4a, 0x8e, + 0xbf, 0xdb, 0xec, 0x07, 0x22, 0xe2, 0xcc, 0x3b, 0x87, 0x3b, 0xba, 0xbe, 0x17, 0x63, 0x19, 0xf9, + 0x0c, 0x40, 0xb4, 0xaa, 0xda, 0x6e, 0x97, 0xc7, 0xf0, 0x23, 0xcf, 0x9b, 0x1f, 0x59, 0x6d, 0xb7, + 0x17, 0xae, 0x8a, 0xef, 0xbb, 0xa0, 0xbe, 0xcf, 0x69, 0xb7, 0x35, 0x6e, 0x1a, 0x13, 0xf2, 0x09, + 0x8c, 0xe3, 0x92, 0x26, 0x7b, 0x74, 0x1c, 0x7b, 0xf4, 0xd2, 0xc9, 0x71, 0x65, 0x16, 0x57, 0xab, + 0x8c, 0xfe, 0x34, 0x08, 0xc8, 0x6f, 0xc0, 0x8c, 0x60, 0xf7, 0xc8, 0xf5, 0x9a, 0xfe, 0xb3, 0x70, + 0x89, 0x86, 0x4f, 0x22, 0xbf, 0x8d, 0xcb, 0xdf, 0xd8, 0xfc, 0x65, 0xb3, 0x79, 0x26, 0xce, 0xc2, + 0x2d, 0xd1, 0x52, 0x4b, 0xb5, 0xf4, 0x19, 0x47, 0xa8, 0x37, 0x39, 0x86, 0xbe, 0x40, 0x66, 0xb2, + 0x20, 0x6b, 0x70, 0x6e, 0x37, 0xa4, 0xc6, 0x37, 0x4c, 0xe2, 0xfe, 0x50, 0x61, 0x3d, 0xdc, 0x09, + 0x69, 0x3d, 0xef, 0x3b, 0x92, 0x74, 0xc4, 0x06, 0xb2, 0x14, 0xf8, 0xed, 0xc4, 0x18, 0x3f, 0x87, + 0x12, 0xb1, 0x4e, 0x8e, 0x2b, 0x57, 0x9b, 0x81, 0xdf, 0xae, 0xe7, 0x0f, 0xf4, 0x0c, 0x6a, 0xf2, + 0x23, 0xb8, 0xb0, 0xe8, 0x7b, 0x1e, 0x6d, 0xb0, 0x15, 0x74, 0xc9, 0x75, 0x0e, 0x3c, 0x3f, 0x8c, + 0xdc, 0xc6, 0xda, 0x52, 0xb9, 0x14, 0x6f, 0x0f, 0x0d, 0x85, 0x51, 0x6f, 0x2a, 0x14, 0x73, 0x7b, + 0xc8, 0xe1, 0x42, 0xbe, 0x82, 0x09, 0x51, 0x17, 0x0d, 0x70, 0x68, 0x9e, 0xef, 0x3e, 0xd0, 0x14, + 0x32, 0xdf, 0xe8, 0x03, 0xf9, 0x93, 0xab, 0x4e, 0x26, 0x2f, 0xf2, 0x35, 0x8c, 0x6d, 0xdc, 0xaf, + 0xda, 0x34, 0x6c, 0xfb, 0x5e, 0x48, 0xcb, 0x04, 0x7b, 0xf4, 0xaa, 0x60, 0xbd, 0x71, 0xbf, 0x5a, + 0xed, 0x44, 0x87, 0xd4, 0x8b, 0xdc, 0x86, 0x13, 0x51, 0x89, 0xb5, 0x30, 0xc7, 0x46, 0xde, 0xd1, + 0x63, 0xa7, 0x1e, 0x08, 0x88, 0xf6, 0x15, 0x3a, 0x3b, 0x32, 0x07, 0x23, 0xb5, 0xda, 0xea, 0xba, + 0x7f, 0xe0, 0x7a, 0xe5, 0x29, 0x26, 0x0c, 0x5b, 0xfd, 0x26, 0x8f, 0x61, 0x46, 0x3b, 0x1b, 0xd4, + 0xd9, 0xff, 0xf4, 0x88, 0x7a, 0x51, 0x79, 0x1a, 0xdb, 0xf0, 0x7d, 0x75, 0xb8, 0xb9, 0xad, 0x1f, + 0x21, 0x9e, 0xde, 0xbb, 0x5d, 0x8d, 0x7f, 0xd6, 0x24, 0xd1, 0x42, 0xb1, 0x5c, 0xb0, 0xa7, 0x9d, + 0x8c, 0x12, 0xb2, 0x03, 0xc3, 0xdb, 0x9d, 0xa0, 0xed, 0x87, 0xb4, 0x3c, 0x83, 0x82, 0xbb, 0xd1, + 0x6d, 0x86, 0x0a, 0xd4, 0x85, 0x19, 0xb6, 0x44, 0xb7, 0xf9, 0x0f, 0xed, 0xeb, 0x24, 0x2b, 0xf2, + 0x29, 0x8c, 0xd7, 0x6a, 0xab, 0xf1, 0x86, 0x72, 0x01, 0x37, 0x94, 0xcb, 0x27, 0xc7, 0x95, 0x32, + 0x53, 0xa9, 0xe2, 0x4d, 0x45, 0x9f, 0x55, 0x3a, 0x05, 0xe3, 0xb0, 0xb3, 0x5e, 0x8b, 0x39, 0xcc, + 0xc6, 0x1c, 0x98, 0x32, 0x97, 0xcd, 0x41, 0xa7, 0x20, 0xff, 0xa0, 0x00, 0xd7, 0x74, 0x96, 0x59, + 0x82, 0x29, 0x5f, 0x7c, 0x11, 0x69, 0xce, 0x9f, 0x1c, 0x57, 0x6e, 0x9b, 0xdf, 0x51, 0xcf, 0xec, + 0x2c, 0xad, 0x6d, 0x3d, 0x9b, 0x82, 0xed, 0xd5, 0x3f, 0x20, 0xb3, 0xbd, 0x73, 0x2f, 0xdc, 0x5e, + 0x53, 0x6a, 0xbd, 0xdb, 0xdb, 0xab, 0x29, 0xd6, 0xe7, 0x30, 0xaa, 0x16, 0x6d, 0x32, 0x0c, 0xfd, + 0xd5, 0x56, 0xab, 0xd4, 0xc7, 0xfe, 0xa8, 0xd5, 0x56, 0x4b, 0x05, 0x32, 0x09, 0x10, 0xef, 0x54, + 0xa5, 0x22, 0x19, 0x87, 0x11, 0xb9, 0x93, 0x94, 0xfa, 0x11, 0xbf, 0xdd, 0x2e, 0x0d, 0x10, 0x02, + 0x93, 0xe6, 0x7a, 0x56, 0x1a, 0xb4, 0x7e, 0xaf, 0x00, 0xa3, 0x6a, 0x1e, 0x92, 0x73, 0x30, 0xb6, + 0xbb, 0x59, 0xdb, 0x5e, 0x5e, 0x5c, 0xbb, 0xbf, 0xb6, 0xbc, 0x54, 0xea, 0x23, 0x57, 0xe0, 0xe2, + 0x4e, 0x6d, 0xb5, 0xbe, 0xb4, 0x50, 0x5f, 0xdf, 0x5a, 0xac, 0xae, 0xd7, 0xb7, 0xed, 0xad, 0xcf, + 0xbf, 0xa8, 0xef, 0xec, 0x6e, 0x6e, 0x2e, 0xaf, 0x97, 0x0a, 0xa4, 0x0c, 0xd3, 0xac, 0xf8, 0xe1, + 0xee, 0xc2, 0xb2, 0x8e, 0x50, 0x2a, 0x92, 0xeb, 0x70, 0x25, 0xab, 0xa4, 0xbe, 0xba, 0x5c, 0x5d, + 0x5a, 0x5f, 0xae, 0xd5, 0x4a, 0xfd, 0x64, 0x16, 0xa6, 0x18, 0x4a, 0x75, 0x7b, 0xdb, 0xa0, 0x1d, + 0xb0, 0x5a, 0x30, 0xa6, 0x4d, 0x00, 0x72, 0x19, 0xca, 0x8b, 0xcb, 0xf6, 0x4e, 0x7d, 0x7b, 0xd7, + 0xde, 0xde, 0xaa, 0x2d, 0xd7, 0xcd, 0x16, 0x26, 0x4b, 0xd7, 0xb7, 0x56, 0xd6, 0x36, 0xeb, 0x0c, + 0x54, 0x2b, 0x15, 0x58, 0x33, 0x8c, 0xd2, 0xda, 0xda, 0xe6, 0xca, 0xfa, 0x72, 0x7d, 0xb7, 0xb6, + 0x2c, 0x50, 0x8a, 0xd6, 0x6f, 0x15, 0x53, 0x5b, 0x3a, 0x99, 0x87, 0xb1, 0x1a, 0xb7, 0x57, 0xe0, + 0x32, 0xc7, 0x0f, 0x88, 0x4c, 0x47, 0x1b, 0x17, 0x66, 0x0c, 0xbe, 0x82, 0xe9, 0x48, 0x4c, 0x4b, + 0xdb, 0x66, 0xb3, 0xb9, 0xe1, 0xb7, 0x74, 0x2d, 0xad, 0x2d, 0x60, 0xb6, 0x2a, 0x25, 0xf3, 0x9a, + 0x3e, 0xc7, 0x4f, 0x8b, 0x78, 0x22, 0x91, 0xfa, 0x9c, 0xbe, 0xb7, 0x2b, 0xcd, 0x6e, 0x3e, 0xee, + 0x52, 0xa1, 0x86, 0x21, 0x4d, 0x86, 0x2e, 0xa1, 0xf0, 0xc8, 0x1b, 0x52, 0xd3, 0xe5, 0xa7, 0x3b, + 0xdc, 0xec, 0x13, 0xe7, 0x12, 0xa1, 0xe4, 0x5a, 0x9d, 0x9c, 0x8d, 0x95, 0x7c, 0x98, 0x1c, 0x33, + 0x42, 0x18, 0xc8, 0x2c, 0xb1, 0x7f, 0xda, 0x09, 0x54, 0x52, 0x81, 0x41, 0xbe, 0xe2, 0x72, 0x79, + 0xa0, 0x6e, 0xdd, 0x62, 0x00, 0x9b, 0xc3, 0xad, 0xdf, 0xef, 0xd7, 0x95, 0x0c, 0xa6, 0x4b, 0x6b, + 0xf2, 0x46, 0x5d, 0x1a, 0xe5, 0x8c, 0x50, 0x76, 0x14, 0xe4, 0xb3, 0x04, 0x8f, 0x82, 0xfd, 0xf1, + 0x51, 0x50, 0x4c, 0x35, 0x7e, 0x14, 0x8c, 0x51, 0x58, 0x2f, 0x0a, 0xb5, 0x0d, 0xb9, 0x0e, 0xc4, + 0xbd, 0x28, 0x54, 0x3d, 0xd1, 0x8b, 0x1a, 0x12, 0xf9, 0x00, 0xa0, 0xfa, 0xa8, 0x86, 0x67, 0x1e, + 0x7b, 0x53, 0xa8, 0xae, 0xb8, 0xc9, 0x38, 0xcf, 0x42, 0x71, 0xa4, 0x0a, 0xf4, 0x33, 0xa3, 0x86, + 0x4d, 0x16, 0x60, 0xa2, 0xfa, 0xd3, 0x4e, 0x40, 0xd7, 0x9a, 0x6c, 0x9f, 0x8a, 0xf8, 0xe1, 0x78, + 0x94, 0x2f, 0xa4, 0x0e, 0x2b, 0xa8, 0xbb, 0xa2, 0x44, 0x63, 0x60, 0x92, 0x90, 0x2d, 0x38, 0xbf, + 0xb2, 0xb8, 0x2d, 0xc6, 0x55, 0xb5, 0xd1, 0xf0, 0x3b, 0x5e, 0x24, 0xf4, 0xd5, 0xeb, 0x27, 0xc7, + 0x95, 0x2b, 0x07, 0x8d, 0x76, 0x5d, 0x8e, 0x41, 0x87, 0x17, 0xeb, 0x0a, 0x6b, 0x8a, 0x96, 0xdc, + 0x80, 0xfe, 0x5d, 0x7b, 0x4d, 0x9c, 0x9c, 0xcf, 0x9f, 0x1c, 0x57, 0x26, 0x3a, 0x81, 0xab, 0x91, + 0xb0, 0xd2, 0x07, 0x03, 0x23, 0xc5, 0x52, 0xbf, 0x3d, 0x5a, 0xa3, 0x61, 0xc8, 0x0f, 0x79, 0x2d, + 0x98, 0x5c, 0xa1, 0x11, 0x1b, 0x7d, 0xf2, 0xd0, 0xd2, 0xbd, 0x6f, 0x3e, 0x82, 0xb1, 0x47, 0x6e, + 0x74, 0x58, 0xa3, 0x8d, 0x80, 0x46, 0xd2, 0x60, 0x83, 0x72, 0x7b, 0xe6, 0x46, 0x87, 0xf5, 0x90, + 0xc3, 0xf5, 0xcd, 0x59, 0x43, 0xb7, 0x96, 0xe1, 0x9c, 0xa8, 0x4d, 0x9d, 0x91, 0xe6, 0x4d, 0x86, + 0x05, 0x64, 0x88, 0x7d, 0xa7, 0x33, 0x34, 0xd9, 0xfc, 0xe3, 0x22, 0xcc, 0x2c, 0x1e, 0x3a, 0xde, + 0x01, 0xdd, 0x76, 0xc2, 0xf0, 0x99, 0x1f, 0x34, 0xb5, 0xc6, 0xe3, 0x01, 0x31, 0xd5, 0x78, 0x3c, + 0x11, 0xce, 0xc3, 0xd8, 0x56, 0xab, 0x29, 0x69, 0xc4, 0xe1, 0x15, 0xeb, 0xf2, 0x5b, 0xcd, 0x7a, + 0x5b, 0xf2, 0xd2, 0x91, 0x18, 0xcd, 0x26, 0x7d, 0xa6, 0x68, 0xfa, 0x63, 0x1a, 0x8f, 0x3e, 0xd3, + 0x68, 0x34, 0x24, 0xb2, 0x0c, 0xe7, 0x6b, 0xb4, 0xe1, 0x7b, 0xcd, 0xfb, 0x4e, 0x23, 0xf2, 0x83, + 0x1d, 0xff, 0x09, 0xf5, 0xc4, 0xa8, 0x44, 0xed, 0x3e, 0xc4, 0xc2, 0xfa, 0x63, 0x2c, 0xad, 0x47, + 0xac, 0xd8, 0x4e, 0x53, 0x90, 0x2d, 0x18, 0x79, 0x24, 0xcc, 0x7e, 0xe2, 0xc4, 0xfb, 0xea, 0x6d, + 0x65, 0x07, 0x5c, 0x0c, 0x28, 0x0e, 0x25, 0xa7, 0xa5, 0xce, 0xec, 0x4a, 0x59, 0xc2, 0xf5, 0x48, + 0x62, 0xda, 0x8a, 0x89, 0xb5, 0x0b, 0x13, 0xdb, 0xad, 0xce, 0x81, 0xeb, 0xb1, 0x95, 0xa3, 0x46, + 0x7f, 0x42, 0x96, 0x00, 0x62, 0x80, 0x30, 0xe6, 0x4d, 0x89, 0x73, 0x72, 0x5c, 0xb0, 0xf7, 0x96, + 0x98, 0x7e, 0x08, 0xc1, 0x63, 0x8d, 0xad, 0xd1, 0x59, 0xff, 0xad, 0x1f, 0x88, 0xe8, 0x00, 0xdc, + 0xc9, 0x6a, 0x34, 0x62, 0x7b, 0xcc, 0x05, 0x28, 0x2a, 0x9b, 0xdb, 0xd0, 0xc9, 0x71, 0xa5, 0xe8, + 0x36, 0xed, 0xe2, 0xda, 0x12, 0x79, 0x1b, 0x06, 0x11, 0x0d, 0xe5, 0x3f, 0xa9, 0xea, 0xd3, 0x39, + 0xf0, 0x15, 0x04, 0xb7, 0x50, 0x9b, 0x23, 0x93, 0x77, 0x60, 0x74, 0x89, 0xb6, 0xe8, 0x81, 0x13, + 0xf9, 0x72, 0x4d, 0xe0, 0x56, 0x2c, 0x09, 0xd4, 0xc6, 0x5c, 0x8c, 0xc9, 0xce, 0xb4, 0x36, 0x75, + 0x42, 0xdf, 0xd3, 0xcf, 0xb4, 0x01, 0x42, 0xf4, 0x33, 0x2d, 0xc7, 0x21, 0xff, 0x4f, 0x01, 0xc6, + 0xaa, 0x9e, 0x27, 0xac, 0x43, 0xa1, 0x90, 0xfa, 0xcc, 0x6d, 0x65, 0x4e, 0x5d, 0x77, 0xf6, 0x69, + 0x6b, 0xcf, 0x69, 0x75, 0x68, 0xb8, 0xf0, 0x35, 0x3b, 0x66, 0xfc, 0xdb, 0xe3, 0xca, 0x87, 0x67, + 0xb0, 0xf7, 0xc4, 0x86, 0xd9, 0x9d, 0xc0, 0x71, 0xa3, 0xf0, 0xe4, 0xb8, 0x32, 0xe3, 0xc4, 0x15, + 0xea, 0xf3, 0x46, 0x6b, 0x47, 0xbc, 0xc0, 0x0f, 0xf5, 0x5a, 0xe0, 0xc9, 0x11, 0x9c, 0xab, 0x86, + 0x61, 0xe7, 0x88, 0xd6, 0x22, 0x27, 0x88, 0x76, 0xdc, 0x23, 0x8a, 0xab, 0x4a, 0x77, 0x0b, 0xc1, + 0xeb, 0x3f, 0x3b, 0xae, 0x14, 0xd8, 0xc9, 0xc6, 0x41, 0x52, 0xa6, 0xbc, 0x04, 0x51, 0x3d, 0x72, + 0xf5, 0x3d, 0x0a, 0x6d, 0x05, 0x49, 0xde, 0xd6, 0x0d, 0xa5, 0x55, 0xac, 0x2d, 0xe5, 0xf5, 0xb8, + 0xb5, 0x08, 0x97, 0x57, 0x68, 0x64, 0xd3, 0x90, 0x46, 0x72, 0x8e, 0xe0, 0x08, 0x8f, 0x2d, 0xb4, + 0xc3, 0xf8, 0x5b, 0x11, 0x63, 0xf7, 0xf3, 0x79, 0x21, 0x4b, 0xac, 0xff, 0xa5, 0x00, 0x95, 0xc5, + 0x80, 0xf2, 0x43, 0x41, 0x0e, 0xa3, 0xee, 0x6b, 0xd7, 0x65, 0x18, 0xd8, 0x79, 0xde, 0x96, 0xa6, + 0x15, 0x2c, 0x65, 0x9d, 0x62, 0x23, 0xf4, 0x94, 0x96, 0x2a, 0xeb, 0x31, 0xcc, 0xd8, 0xd4, 0xa3, + 0xcf, 0x9c, 0xfd, 0x16, 0x35, 0x8c, 0x3d, 0x15, 0x18, 0xe4, 0x13, 0x3d, 0xf5, 0x09, 0x1c, 0x7e, + 0x36, 0xc3, 0x99, 0x35, 0x01, 0x63, 0xdb, 0xae, 0x77, 0x20, 0xb8, 0x5b, 0x7f, 0x39, 0x00, 0xe3, + 0xfc, 0xb7, 0x38, 0xe7, 0x24, 0xf6, 0xbc, 0xc2, 0x69, 0xf6, 0xbc, 0xf7, 0x60, 0x82, 0x6d, 0x1a, + 0x34, 0xd8, 0xa3, 0x01, 0x5b, 0xff, 0x85, 0x24, 0xf0, 0xcc, 0x16, 0x62, 0x41, 0xfd, 0x29, 0x2f, + 0xb1, 0x4d, 0x44, 0xb2, 0x0e, 0x93, 0x1c, 0x70, 0x9f, 0x3a, 0x51, 0x27, 0x36, 0x3b, 0x9d, 0x13, + 0x07, 0x1b, 0x09, 0xe6, 0x43, 0x53, 0xf0, 0x7a, 0x2c, 0x80, 0x76, 0x82, 0x96, 0x7c, 0x02, 0xe7, + 0xb6, 0x03, 0xff, 0x9b, 0xe7, 0xda, 0x2e, 0xcf, 0x67, 0x27, 0x3f, 0x02, 0xb1, 0xa2, 0xba, 0xbe, + 0xd7, 0x27, 0xb1, 0xc9, 0x1b, 0x30, 0xb2, 0x16, 0x2e, 0xf8, 0x81, 0xeb, 0x1d, 0xe0, 0x1c, 0x1d, + 0xe1, 0xd6, 0x7a, 0x37, 0xac, 0xef, 0x23, 0xd0, 0x56, 0xc5, 0x09, 0xbb, 0xf2, 0x70, 0x6f, 0xbb, + 0xf2, 0x5d, 0x80, 0x75, 0xdf, 0x69, 0x56, 0x5b, 0xad, 0xc5, 0x6a, 0x88, 0xdb, 0xa9, 0xd8, 0x8f, + 0x5a, 0xbe, 0xd3, 0xac, 0x3b, 0xad, 0x56, 0xbd, 0xe1, 0x84, 0xb6, 0x86, 0x43, 0xbe, 0x84, 0x8b, + 0xa1, 0x7b, 0xe0, 0xe1, 0xc7, 0xd5, 0x9d, 0xd6, 0x81, 0x1f, 0xb8, 0xd1, 0xe1, 0x51, 0x3d, 0xec, + 0xb8, 0x11, 0x37, 0xea, 0x4c, 0xce, 0x5f, 0x15, 0x8b, 0x5c, 0x4d, 0xe2, 0x55, 0x25, 0x5a, 0x8d, + 0x61, 0xd9, 0xb3, 0x61, 0x76, 0x01, 0x79, 0x04, 0x13, 0xeb, 0x6e, 0x83, 0x7a, 0x21, 0x45, 0x2b, + 0xdd, 0x73, 0x34, 0xf9, 0x74, 0x9f, 0xcc, 0x4c, 0x88, 0x13, 0x2d, 0x9d, 0x08, 0xa7, 0xae, 0xc9, + 0xe7, 0xc1, 0xc0, 0xc8, 0x50, 0x69, 0xd8, 0x3e, 0x27, 0x80, 0x8f, 0x9c, 0xc0, 0x73, 0xbd, 0x83, + 0xd0, 0xfa, 0x87, 0xe7, 0x61, 0x44, 0xf5, 0xd3, 0x6d, 0xfd, 0xb8, 0x21, 0xb6, 0x66, 0x1c, 0xb2, + 0xb1, 0x31, 0xcd, 0xd6, 0x30, 0xc8, 0x45, 0x3c, 0x80, 0x08, 0xa5, 0x60, 0x98, 0x4d, 0x21, 0xa7, + 0xdd, 0xb6, 0x19, 0x8c, 0x2d, 0x0d, 0x4b, 0x0b, 0x38, 0x68, 0x46, 0xf8, 0xd2, 0xd0, 0xdc, 0xb7, + 0x8b, 0x4b, 0x0b, 0x6c, 0x4e, 0x6e, 0xad, 0x2d, 0x2d, 0x62, 0xff, 0x8f, 0xf0, 0x39, 0xe9, 0xbb, + 0xcd, 0x86, 0x8d, 0x50, 0x56, 0x5a, 0xab, 0x6e, 0xac, 0x8b, 0x3e, 0xc6, 0xd2, 0xd0, 0x39, 0x6a, + 0xd9, 0x08, 0x65, 0x2a, 0x2b, 0xb7, 0x8b, 0x2c, 0xfa, 0x5e, 0x14, 0xf8, 0xad, 0x10, 0xf5, 0xb0, + 0x11, 0x3e, 0x06, 0x85, 0x41, 0xa5, 0x21, 0x8a, 0xec, 0x04, 0x2a, 0x79, 0x04, 0xb3, 0xd5, 0xe6, + 0x53, 0xc7, 0x6b, 0xd0, 0x26, 0x2f, 0x79, 0xe4, 0x07, 0x4f, 0x1e, 0xb7, 0xfc, 0x67, 0x21, 0x0e, + 0x92, 0x11, 0x61, 0x7f, 0x14, 0x28, 0xd2, 0x3e, 0xf3, 0x4c, 0x22, 0xd9, 0x79, 0xd4, 0x6c, 0x1d, + 0x58, 0x6c, 0xf9, 0x9d, 0xa6, 0x18, 0x3a, 0xb8, 0x0e, 0x34, 0x18, 0xc0, 0xe6, 0x70, 0x26, 0xa5, + 0xd5, 0xda, 0x06, 0x0e, 0x0c, 0x21, 0xa5, 0xc3, 0xf0, 0xc8, 0x66, 0x30, 0xf2, 0x2a, 0x0c, 0x4b, + 0xed, 0x9b, 0x5f, 0x47, 0xa0, 0x19, 0x5c, 0x6a, 0xdd, 0xb2, 0x8c, 0xcd, 0x63, 0x9b, 0x36, 0xfc, + 0xa7, 0x34, 0x78, 0xbe, 0xe8, 0x37, 0xa9, 0xb4, 0x4d, 0x09, 0xdb, 0x0b, 0x2f, 0xa8, 0x37, 0x58, + 0x89, 0x6d, 0x22, 0xb2, 0x0a, 0xf8, 0xc6, 0x1d, 0x96, 0xcf, 0xc5, 0x15, 0xf0, 0x8d, 0x3d, 0xb4, + 0x65, 0x19, 0x59, 0x82, 0xf3, 0xd5, 0x4e, 0xe4, 0x1f, 0x39, 0x91, 0xdb, 0xd8, 0x6d, 0x1f, 0x04, + 0x0e, 0xab, 0xa4, 0x84, 0x04, 0x78, 0x1a, 0x71, 0x64, 0x61, 0xbd, 0x23, 0x4a, 0xed, 0x34, 0x01, + 0x79, 0x17, 0xc6, 0xd7, 0x42, 0x6e, 0x7f, 0x74, 0x42, 0xda, 0x44, 0x23, 0x92, 0x68, 0xa5, 0x1b, + 0xd6, 0xd1, 0x1a, 0x59, 0x67, 0xe7, 0x97, 0xa6, 0x6d, 0xe0, 0x11, 0x0b, 0x86, 0xaa, 0x61, 0xe8, + 0x86, 0x11, 0xda, 0x86, 0x46, 0x16, 0xe0, 0xe4, 0xb8, 0x32, 0xe4, 0x20, 0xc4, 0x16, 0x25, 0xe4, + 0x11, 0x8c, 0x2d, 0x51, 0xa6, 0xfe, 0xee, 0x04, 0x9d, 0x30, 0x42, 0x4b, 0xcf, 0xd8, 0xfc, 0x45, + 0xb1, 0x1a, 0x69, 0x25, 0x62, 0x2c, 0x73, 0x15, 0xb5, 0x89, 0xf0, 0x7a, 0xc4, 0x0a, 0xf4, 0xad, + 0x56, 0xc3, 0x67, 0xba, 0xbd, 0xa0, 0x59, 0x75, 0x9b, 0x6c, 0x7d, 0x99, 0xc6, 0x36, 0xa0, 0x6e, + 0x2f, 0x16, 0xb4, 0xfa, 0x21, 0x96, 0xe8, 0xba, 0xbd, 0x41, 0x42, 0x1a, 0x29, 0x93, 0xf6, 0x8c, + 0x61, 0xb6, 0x34, 0x0b, 0x65, 0x13, 0xcf, 0x68, 0xf0, 0xfe, 0x08, 0xc6, 0x16, 0x3b, 0x61, 0xe4, + 0x1f, 0xed, 0x1c, 0xd2, 0x23, 0x8a, 0xd6, 0x20, 0x71, 0x82, 0x69, 0x20, 0xb8, 0x1e, 0x31, 0xb8, + 0xfe, 0x99, 0x1a, 0x3a, 0xf9, 0x0c, 0x88, 0x3c, 0x8a, 0xac, 0xb0, 0xf1, 0xe1, 0xb1, 0xb1, 0x8c, + 0x06, 0xa1, 0x11, 0x7e, 0xfe, 0x90, 0x27, 0x98, 0xfa, 0x81, 0x2a, 0xd6, 0x8d, 0x92, 0x69, 0x62, + 0xd6, 0x20, 0xde, 0xc4, 0x95, 0xc0, 0x69, 0x1f, 0x96, 0xcb, 0xf1, 0xd1, 0x40, 0x7c, 0xd4, 0x01, + 0x83, 0x1b, 0x2a, 0x4e, 0x8c, 0x4e, 0x6a, 0x00, 0xfc, 0xe7, 0x3a, 0xeb, 0x78, 0x6e, 0x42, 0x2a, + 0x1b, 0xf2, 0x62, 0x05, 0x52, 0x56, 0x17, 0x51, 0x71, 0xe2, 0x6c, 0x5b, 0xae, 0xd1, 0x9b, 0x1a, + 0x1b, 0xf2, 0x04, 0x4a, 0xfc, 0xd7, 0x86, 0xef, 0xb9, 0x11, 0xdf, 0x2f, 0xe6, 0x0c, 0x7b, 0x63, + 0xb2, 0x58, 0x56, 0x80, 0x76, 0x5e, 0x51, 0xc1, 0x91, 0x2a, 0xd5, 0xaa, 0x49, 0x31, 0x26, 0xdb, + 0x30, 0xb6, 0x1d, 0xf8, 0xcd, 0x4e, 0x23, 0x42, 0x2d, 0xe3, 0x12, 0x2e, 0xfc, 0x44, 0xd4, 0xa3, + 0x95, 0x70, 0x99, 0xb4, 0x39, 0xa0, 0xce, 0xf6, 0x05, 0x5d, 0x26, 0x1a, 0x22, 0x59, 0x80, 0xa1, + 0x6d, 0xbf, 0xe5, 0x36, 0x9e, 0x97, 0x2f, 0x63, 0xa3, 0xa7, 0x25, 0x33, 0x04, 0xca, 0xa6, 0xa2, + 0x4a, 0xdb, 0x46, 0x90, 0xae, 0xd2, 0x72, 0x24, 0x52, 0x85, 0x89, 0xcf, 0xd8, 0x80, 0x71, 0x7d, + 0xcf, 0x73, 0xdc, 0x80, 0x96, 0xaf, 0x60, 0xbf, 0xa0, 0x2d, 0xfe, 0x27, 0x7a, 0x81, 0x3e, 0x9c, + 0x0d, 0x0a, 0xb2, 0x06, 0xe7, 0xd6, 0xc2, 0x5a, 0x14, 0xb8, 0x6d, 0xba, 0xe1, 0x78, 0xce, 0x01, + 0x6d, 0x96, 0xaf, 0xc6, 0xc6, 0x70, 0x37, 0xac, 0x87, 0x58, 0x56, 0x3f, 0xe2, 0x85, 0xba, 0x31, + 0x3c, 0x41, 0x47, 0x3e, 0x87, 0xe9, 0xe5, 0x6f, 0x22, 0x36, 0x62, 0x5a, 0xd5, 0x4e, 0xd3, 0x8d, + 0x6a, 0x91, 0x1f, 0x38, 0x07, 0xb4, 0x5c, 0x41, 0x7e, 0xaf, 0x9c, 0x1c, 0x57, 0xae, 0x51, 0x51, + 0x5e, 0x77, 0x18, 0x42, 0x3d, 0xe4, 0x18, 0xfa, 0x25, 0x77, 0x16, 0x07, 0x26, 0xfd, 0x5a, 0xa7, + 0xcd, 0xb4, 0x6d, 0x94, 0xfe, 0x35, 0x43, 0xfa, 0x5a, 0x09, 0x97, 0x7e, 0xc8, 0x01, 0x29, 0xe9, + 0x6b, 0x88, 0xc4, 0x06, 0xf2, 0xc0, 0x77, 0xbd, 0x6a, 0x23, 0x72, 0x9f, 0x52, 0x71, 0x62, 0x0e, + 0xcb, 0xd7, 0xb1, 0xa5, 0x68, 0xb8, 0xff, 0x55, 0xdf, 0xf5, 0xea, 0x0e, 0x16, 0xd7, 0x43, 0x51, + 0xae, 0xcf, 0x91, 0x34, 0x35, 0xf9, 0x11, 0x5c, 0xd8, 0xf0, 0xf7, 0xdd, 0x16, 0xe5, 0x4b, 0x0e, + 0x17, 0x0b, 0x1a, 0x21, 0x2d, 0xe4, 0x8b, 0x86, 0xfb, 0x23, 0xc4, 0xa8, 0x8b, 0xd5, 0xea, 0x48, + 0xe1, 0xe8, 0x86, 0xfb, 0x6c, 0x2e, 0x64, 0x19, 0xc6, 0x71, 0x5e, 0xb6, 0xf0, 0x67, 0x58, 0xbe, + 0x81, 0x47, 0xba, 0xeb, 0x09, 0x2d, 0xed, 0xf6, 0xb2, 0x86, 0xb3, 0xec, 0x45, 0xc1, 0x73, 0xdb, + 0x20, 0x23, 0x1f, 0xc3, 0x5c, 0x72, 0x78, 0x2f, 0xfa, 0xde, 0x63, 0xf7, 0xa0, 0x13, 0xd0, 0x66, + 0xf9, 0x15, 0xd6, 0x54, 0xbb, 0x0b, 0xc6, 0xdc, 0x23, 0x38, 0x9f, 0xaa, 0x82, 0x94, 0xa0, 0xff, + 0x89, 0xb8, 0x07, 0x1d, 0xb5, 0xd9, 0x9f, 0xe4, 0x4d, 0x18, 0x7c, 0xca, 0xce, 0x52, 0xa8, 0x31, + 0xc4, 0x37, 0x6b, 0x1a, 0xe9, 0x9a, 0xf7, 0xd8, 0xb7, 0x39, 0xd2, 0x07, 0xc5, 0xf7, 0x0a, 0x0f, + 0x06, 0x46, 0xc6, 0x4a, 0xe3, 0xfc, 0xfa, 0xfa, 0xc1, 0xc0, 0xc8, 0x44, 0x69, 0xd2, 0xaa, 0xc2, + 0xb9, 0x04, 0x3e, 0x29, 0xc3, 0x30, 0xf5, 0x98, 0x7e, 0xde, 0xe4, 0x3a, 0x8b, 0x2d, 0x7f, 0x92, + 0x69, 0x18, 0x6c, 0xb9, 0x47, 0x6e, 0x84, 0x15, 0x0e, 0xda, 0xfc, 0x87, 0xf5, 0x07, 0x05, 0x20, + 0xe9, 0x2d, 0x83, 0xdc, 0x49, 0xb0, 0xe1, 0xda, 0xa9, 0x00, 0xe9, 0x06, 0x7a, 0xc9, 0xfd, 0x33, + 0x98, 0xe2, 0x7d, 0x26, 0x37, 0x37, 0xad, 0x2e, 0xbe, 0xa8, 0x66, 0x14, 0xeb, 0x46, 0x1d, 0x51, + 0x8c, 0x5b, 0xe1, 0x3a, 0x36, 0xad, 0x03, 0x33, 0x99, 0x9b, 0x05, 0xd9, 0x80, 0x99, 0x23, 0xdf, + 0x8b, 0x0e, 0x5b, 0xcf, 0xe5, 0x5e, 0x21, 0x6a, 0x2b, 0x60, 0x6d, 0xb8, 0x3e, 0x66, 0x22, 0xd8, + 0x53, 0x02, 0x2c, 0x38, 0x62, 0x3d, 0xc2, 0x2e, 0x24, 0xbf, 0xc4, 0xb2, 0xe1, 0x7c, 0x6a, 0xcd, + 0x25, 0x3f, 0x84, 0xf1, 0x06, 0x9e, 0xbf, 0x8c, 0x9a, 0xf8, 0x8e, 0xa3, 0xc1, 0xf5, 0xe9, 0xc4, + 0xe1, 0xfc, 0x53, 0xfe, 0x6e, 0x01, 0x66, 0x73, 0x56, 0xdb, 0xb3, 0x8b, 0xfa, 0x0b, 0xb8, 0x70, + 0xe4, 0x7c, 0x53, 0x0f, 0xf0, 0x78, 0x5d, 0x0f, 0x1c, 0x2f, 0x21, 0x6d, 0x5c, 0x49, 0xb2, 0x31, + 0x74, 0x1f, 0xa2, 0x23, 0xe7, 0x1b, 0x1b, 0x11, 0x6c, 0x56, 0xce, 0xdb, 0xf9, 0x29, 0x4c, 0x18, + 0xeb, 0xeb, 0x99, 0x1b, 0x67, 0xdd, 0x83, 0xf3, 0x4b, 0xb4, 0x45, 0x23, 0x7a, 0x6a, 0xb3, 0x9a, + 0xb5, 0x0d, 0x50, 0xa3, 0x47, 0x4e, 0xfb, 0xd0, 0x67, 0x7a, 0xf7, 0x82, 0xfe, 0x4b, 0x98, 0x65, + 0x88, 0x3c, 0x41, 0xc8, 0x82, 0xbd, 0xb7, 0xb8, 0x2e, 0x1e, 0x2a, 0x4c, 0x5b, 0xa3, 0xb2, 0xfe, + 0x65, 0x11, 0x88, 0x58, 0x20, 0x03, 0xea, 0x1c, 0xc9, 0x66, 0xbc, 0x0f, 0xe3, 0xfc, 0x10, 0xcd, + 0xc1, 0xd8, 0x9c, 0xb1, 0xf9, 0x29, 0x31, 0xf3, 0xf4, 0xa2, 0xd5, 0x3e, 0xdb, 0x40, 0x65, 0xa4, + 0x36, 0xe5, 0xa7, 0x7f, 0x24, 0x2d, 0x1a, 0xa4, 0x7a, 0x11, 0x23, 0xd5, 0x7f, 0x93, 0x4f, 0x60, + 0x72, 0xd1, 0x3f, 0x6a, 0x33, 0x99, 0x08, 0xe2, 0x7e, 0x61, 0x59, 0x11, 0xf5, 0x1a, 0x85, 0xab, + 0x7d, 0x76, 0x02, 0x9d, 0x6c, 0xc2, 0xd4, 0xfd, 0x56, 0x27, 0x3c, 0xac, 0x7a, 0xcd, 0xc5, 0x96, + 0x1f, 0x4a, 0x2e, 0x03, 0xe2, 0x30, 0x24, 0x96, 0xb7, 0x34, 0xc6, 0x6a, 0x9f, 0x9d, 0x45, 0x48, + 0x5e, 0x85, 0xc1, 0xe5, 0xa7, 0x6c, 0xd9, 0x95, 0x9e, 0x24, 0xc2, 0xd1, 0x6d, 0xcb, 0xa3, 0x5b, + 0x8f, 0x57, 0xfb, 0x6c, 0x5e, 0xba, 0x30, 0x0a, 0xc3, 0xf2, 0x00, 0x7e, 0x87, 0xa9, 0xc4, 0x4a, + 0x9c, 0xb5, 0xc8, 0x89, 0x3a, 0x21, 0x99, 0x83, 0x91, 0xdd, 0x36, 0x3b, 0x17, 0x4a, 0xcb, 0x85, + 0xad, 0x7e, 0x5b, 0x6f, 0x9a, 0x92, 0x26, 0x97, 0x21, 0x36, 0xbb, 0x0a, 0x64, 0xcd, 0x0e, 0xbb, + 0x6a, 0x0a, 0xb7, 0x3b, 0xb6, 0x51, 0x6f, 0x31, 0x51, 0x6f, 0x29, 0x29, 0x6b, 0x6b, 0x26, 0x53, + 0x78, 0xd6, 0xe7, 0x70, 0x75, 0xb7, 0x1d, 0xd2, 0x20, 0xaa, 0xb6, 0xdb, 0x2d, 0xb7, 0xc1, 0x6f, + 0xa2, 0xf0, 0xa0, 0x2e, 0x07, 0xcb, 0xbb, 0x30, 0xc4, 0x01, 0x62, 0x98, 0xc8, 0x31, 0x58, 0x6d, + 0xb7, 0x85, 0x79, 0xe0, 0x2d, 0xae, 0x9c, 0xf3, 0x03, 0xbf, 0x2d, 0xb0, 0xad, 0xdf, 0x2d, 0xc0, + 0x55, 0x3e, 0x03, 0x72, 0x59, 0x7f, 0x0f, 0x46, 0xd1, 0xcf, 0xac, 0xed, 0x34, 0xe4, 0x9c, 0xe0, + 0x0e, 0x77, 0x12, 0x68, 0xc7, 0xe5, 0x9a, 0x07, 0x5f, 0x31, 0xdf, 0x83, 0x4f, 0x4e, 0xb0, 0xfe, + 0xcc, 0x09, 0xf6, 0x19, 0x58, 0xa2, 0x45, 0xad, 0x56, 0xaa, 0x51, 0xe1, 0x8b, 0xb4, 0xca, 0xfa, + 0x4f, 0x45, 0x98, 0x5d, 0xa1, 0x1e, 0x0d, 0x1c, 0xfc, 0x4e, 0xc3, 0x10, 0xa5, 0x7b, 0xf2, 0x14, + 0xba, 0x7a, 0xf2, 0x54, 0xa4, 0x69, 0xaf, 0x88, 0xa6, 0xbd, 0x94, 0x5b, 0x12, 0x3b, 0x2e, 0xee, + 0xda, 0x6b, 0xe2, 0xb3, 0xf0, 0xb8, 0xd8, 0x09, 0x5c, 0xb4, 0xe6, 0x93, 0xb5, 0xd8, 0x0b, 0x68, + 0xa0, 0xa7, 0x59, 0x60, 0x4a, 0x78, 0x45, 0x0c, 0x0b, 0x2f, 0x20, 0xd3, 0xf7, 0x67, 0x13, 0x86, + 0xb8, 0x45, 0x12, 0xef, 0x90, 0xc6, 0xe6, 0x6f, 0x89, 0x39, 0x95, 0xf3, 0x81, 0xc2, 0x7c, 0x89, + 0x1b, 0x3b, 0x1f, 0x02, 0x11, 0x02, 0x6c, 0xc1, 0x65, 0xee, 0x33, 0x18, 0xd3, 0x50, 0x4e, 0xb3, + 0xf7, 0x2b, 0xcb, 0x28, 0xd3, 0x18, 0xbd, 0x03, 0x6e, 0x64, 0xd5, 0xf6, 0x7e, 0xeb, 0x43, 0x28, + 0xa7, 0x5b, 0x23, 0xac, 0x61, 0xbd, 0x8c, 0x6f, 0xd6, 0x12, 0x4c, 0xaf, 0xd0, 0x08, 0x07, 0x2e, + 0x4e, 0x22, 0xcd, 0x9b, 0x2d, 0x31, 0xcf, 0xe4, 0xaa, 0x8a, 0x40, 0x36, 0xc0, 0xb4, 0x59, 0x5a, + 0x83, 0x99, 0x04, 0x17, 0x51, 0xff, 0x07, 0x30, 0x2c, 0x40, 0x6a, 0x45, 0x15, 0x2e, 0xb1, 0x74, + 0x5f, 0x14, 0xec, 0xcd, 0xf3, 0x71, 0x2b, 0x38, 0xdb, 0x92, 0xc0, 0x3a, 0x84, 0x0b, 0x6c, 0x9b, + 0x8d, 0xb9, 0xaa, 0xe1, 0x78, 0x09, 0x46, 0xdb, 0x4c, 0x51, 0x08, 0xdd, 0x9f, 0xf2, 0x61, 0x34, + 0x68, 0x8f, 0x30, 0x40, 0xcd, 0xfd, 0x29, 0x25, 0x57, 0x00, 0xb0, 0x10, 0x3f, 0x53, 0xac, 0x02, + 0x88, 0xce, 0xad, 0x8d, 0x04, 0xd0, 0x17, 0x8e, 0x8f, 0x1b, 0x1b, 0xff, 0xb6, 0x02, 0x98, 0x4d, + 0xd5, 0x24, 0x3e, 0xe0, 0x0e, 0x8c, 0x48, 0x15, 0x36, 0x71, 0x0f, 0xa0, 0x7f, 0x81, 0xad, 0x90, + 0xc8, 0x6b, 0x70, 0xce, 0xa3, 0xdf, 0x44, 0xf5, 0x54, 0x1b, 0x26, 0x18, 0x78, 0x5b, 0xb6, 0xc3, + 0xfa, 0x15, 0xb4, 0xfd, 0xd6, 0x3c, 0xff, 0xd9, 0xe3, 0x96, 0xf3, 0x84, 0xa6, 0x2a, 0xfe, 0x21, + 0x8c, 0xd4, 0x7a, 0x57, 0xcc, 0xa7, 0x8f, 0xac, 0xdc, 0x56, 0x24, 0x56, 0x0b, 0xe6, 0xd8, 0x27, + 0xd5, 0xaa, 0x1b, 0xeb, 0x6b, 0xcd, 0xed, 0xef, 0x5a, 0x80, 0x4f, 0xe1, 0x52, 0x66, 0x6d, 0xdf, + 0xb5, 0x10, 0xff, 0x78, 0x00, 0x66, 0xf9, 0x66, 0x92, 0x1e, 0xc1, 0xa7, 0x5f, 0x6a, 0x7e, 0x29, + 0xf7, 0xaa, 0x77, 0x33, 0xee, 0x55, 0x91, 0x44, 0xbf, 0x57, 0x35, 0x6e, 0x53, 0xdf, 0xcb, 0xbe, + 0x4d, 0x45, 0x3b, 0x91, 0x79, 0x9b, 0x9a, 0xbc, 0x43, 0x5d, 0xce, 0xbf, 0x43, 0xc5, 0xbb, 0xa1, + 0x8c, 0x3b, 0xd4, 0xac, 0x9b, 0xd3, 0x84, 0x43, 0xd2, 0xc8, 0xcb, 0x75, 0x48, 0x7a, 0x0d, 0x86, + 0xab, 0xed, 0xb6, 0xe6, 0xe0, 0x87, 0xdd, 0xe3, 0xb4, 0xdb, 0x5c, 0x78, 0xb2, 0x50, 0xae, 0xf3, + 0x90, 0xb1, 0xce, 0xbf, 0x0f, 0xb0, 0x88, 0xcf, 0x10, 0xb0, 0xe3, 0xc6, 0x10, 0x03, 0x35, 0x7c, + 0xfe, 0x38, 0x01, 0x3b, 0x4e, 0xb7, 0x80, 0xc4, 0xc8, 0x5c, 0xb1, 0xb7, 0xf6, 0xa0, 0x9c, 0x1e, + 0x3e, 0x2f, 0x61, 0xe9, 0xfa, 0xa3, 0x02, 0x5c, 0x11, 0x4a, 0x4e, 0x62, 0x82, 0x9f, 0x7d, 0x74, + 0xbe, 0x03, 0xe3, 0x82, 0x76, 0x27, 0x9e, 0x08, 0xfc, 0x22, 0x5b, 0x2e, 0xc6, 0x7c, 0x45, 0x37, + 0xd0, 0xc8, 0x3b, 0x30, 0x82, 0x7f, 0xc4, 0x77, 0x37, 0x4c, 0x32, 0xa3, 0x88, 0x5a, 0x4f, 0xde, + 0xe0, 0x28, 0x54, 0xeb, 0x6b, 0xb8, 0x9a, 0xd7, 0xf0, 0x97, 0x20, 0x97, 0x7f, 0x56, 0x80, 0x4b, + 0x82, 0xbd, 0xb1, 0x54, 0xbc, 0xd0, 0xae, 0x73, 0x06, 0xb7, 0xe0, 0x07, 0x30, 0xc6, 0x2a, 0x94, + 0xed, 0xee, 0x17, 0x5b, 0xab, 0x38, 0x39, 0xc4, 0x25, 0x4b, 0x4e, 0xe4, 0x08, 0x37, 0x17, 0xe7, + 0xa8, 0x25, 0x8d, 0x17, 0xb6, 0x4e, 0x6c, 0x7d, 0x09, 0x97, 0xb3, 0x3f, 0xe1, 0x25, 0xc8, 0xe7, + 0x01, 0xcc, 0x65, 0x6c, 0x0a, 0x2f, 0xb6, 0x27, 0x7f, 0x01, 0x97, 0x32, 0x79, 0xbd, 0x84, 0x66, + 0xae, 0x32, 0x8d, 0x23, 0x7a, 0x09, 0x5d, 0x68, 0x3d, 0x82, 0x8b, 0x19, 0x9c, 0x5e, 0x42, 0x13, + 0x57, 0x60, 0x56, 0x69, 0xda, 0xdf, 0xaa, 0x85, 0x1b, 0x70, 0x85, 0x33, 0x7a, 0x39, 0xbd, 0xf2, + 0x10, 0x2e, 0x09, 0x76, 0x2f, 0x41, 0x7a, 0xab, 0x70, 0x39, 0x3e, 0x50, 0x67, 0xe8, 0x49, 0xa7, + 0x5e, 0x64, 0xac, 0x75, 0xb8, 0x16, 0x73, 0xca, 0x51, 0x1a, 0x4e, 0xcf, 0x8d, 0xab, 0x83, 0x71, + 0x2f, 0xbd, 0x94, 0x1e, 0x7d, 0x04, 0x17, 0x0c, 0xa6, 0x2f, 0x4d, 0x55, 0x5a, 0x83, 0x29, 0xce, + 0xd8, 0x54, 0x9d, 0xe7, 0x75, 0xd5, 0x79, 0x6c, 0xfe, 0x7c, 0xcc, 0x12, 0xc1, 0x7b, 0x6f, 0x65, + 0x68, 0xd3, 0x1b, 0xa8, 0x4d, 0x4b, 0x94, 0xb8, 0x85, 0xef, 0xc0, 0x10, 0x87, 0x88, 0xf6, 0x65, + 0x30, 0xe3, 0x87, 0x05, 0x4e, 0x26, 0x90, 0xad, 0x1f, 0xc1, 0x15, 0x7e, 0x12, 0x8d, 0xef, 0x12, + 0xcd, 0xd3, 0xe2, 0x0f, 0x13, 0x07, 0xd1, 0x8b, 0x82, 0x6f, 0x12, 0x3f, 0xe7, 0x3c, 0xba, 0x2f, + 0xc7, 0x76, 0x1e, 0xff, 0x53, 0x3d, 0x11, 0x93, 0x07, 0xcc, 0x62, 0xe6, 0x01, 0xf3, 0x06, 0x5c, + 0x57, 0x07, 0xcc, 0x64, 0x35, 0x72, 0x68, 0x59, 0x5f, 0xc2, 0x25, 0xfe, 0xa1, 0xd2, 0x75, 0xcf, + 0x6c, 0xc6, 0x87, 0x89, 0xcf, 0x9c, 0x15, 0x9f, 0x69, 0x62, 0xe7, 0x7c, 0xe4, 0xff, 0x51, 0x90, + 0x53, 0x2e, 0x9b, 0xf9, 0x2f, 0xfb, 0xc4, 0xbd, 0x09, 0x15, 0x25, 0x10, 0xb3, 0x45, 0x2f, 0x76, + 0xdc, 0xde, 0x80, 0x19, 0x9d, 0x8d, 0xdb, 0xa0, 0x7b, 0xf7, 0xf0, 0x92, 0xe7, 0x6d, 0x36, 0x2d, + 0x10, 0x20, 0x87, 0x5d, 0x39, 0x43, 0x6e, 0x88, 0x6f, 0x2b, 0x4c, 0xab, 0x0e, 0x97, 0xd3, 0x5d, + 0xe1, 0x36, 0xa4, 0xdf, 0x3e, 0xf9, 0x84, 0x4d, 0x61, 0x84, 0x88, 0xce, 0xc8, 0x65, 0x2a, 0xe7, + 0x31, 0x27, 0x97, 0x54, 0x96, 0x25, 0x97, 0x9a, 0xc4, 0xf7, 0xb3, 0xda, 0xe5, 0x78, 0xf8, 0x75, + 0x20, 0xb2, 0x68, 0xb1, 0x66, 0xcb, 0xaa, 0x2f, 0x42, 0xff, 0x62, 0xcd, 0x16, 0x0f, 0x86, 0x50, + 0x13, 0x6c, 0x84, 0x81, 0xcd, 0x60, 0x49, 0x8d, 0xbc, 0x78, 0x0a, 0x8d, 0xfc, 0xc1, 0xc0, 0x48, + 0x7f, 0x69, 0xc0, 0x26, 0x35, 0xf7, 0xc0, 0x7b, 0xe4, 0x46, 0x87, 0xaa, 0xc2, 0xaa, 0xf5, 0x15, + 0x4c, 0x19, 0xd5, 0x8b, 0x59, 0xdc, 0xf5, 0xa5, 0x13, 0xd3, 0x67, 0x17, 0xab, 0xe8, 0xf9, 0x82, + 0x26, 0x8b, 0x71, 0xbe, 0xde, 0x34, 0x9c, 0x3a, 0x3e, 0xa3, 0xb5, 0x65, 0xa1, 0xf5, 0x77, 0x06, + 0x34, 0xee, 0xda, 0xfb, 0xb1, 0x2e, 0x5f, 0x77, 0x0f, 0x80, 0x8f, 0x10, 0xed, 0xe3, 0x98, 0x02, + 0x38, 0x26, 0x1c, 0x4a, 0xf8, 0x92, 0x6c, 0x6b, 0x48, 0xa7, 0x7d, 0x5f, 0x26, 0xfc, 0x7c, 0x39, + 0x91, 0x7c, 0x52, 0xa9, 0xfc, 0x7c, 0x05, 0xeb, 0xd0, 0xd6, 0x91, 0xc8, 0x8f, 0x92, 0x8f, 0x20, + 0x06, 0xf1, 0x4e, 0xe9, 0x15, 0x79, 0xc9, 0x9c, 0xfe, 0xb6, 0xb3, 0xbd, 0x83, 0x78, 0x06, 0x33, + 0x8c, 0xd6, 0x7d, 0x8c, 0x07, 0x8b, 0xe5, 0x6f, 0x22, 0xea, 0xf1, 0xb5, 0x7d, 0x08, 0xeb, 0x79, + 0xb5, 0x4b, 0x3d, 0x31, 0xb2, 0xb0, 0xbf, 0xc7, 0x7c, 0xea, 0x54, 0x95, 0xd9, 0xd9, 0xfc, 0x71, + 0x10, 0xd9, 0xeb, 0xcb, 0x5e, 0xb3, 0xed, 0xbb, 0xea, 0xc0, 0xc4, 0x07, 0x51, 0xd0, 0xaa, 0x53, + 0x01, 0xb7, 0x75, 0x24, 0xeb, 0xb5, 0xae, 0xde, 0xe3, 0x23, 0x30, 0xb0, 0xb3, 0xb8, 0xb3, 0x5e, + 0x2a, 0x58, 0x77, 0x00, 0xb4, 0x9a, 0x00, 0x86, 0x36, 0xb7, 0xec, 0x8d, 0xea, 0x7a, 0xa9, 0x8f, + 0xcc, 0xc0, 0xf9, 0x47, 0x6b, 0x9b, 0x4b, 0x5b, 0x8f, 0x6a, 0xf5, 0xda, 0x46, 0xd5, 0xde, 0x59, + 0xac, 0xda, 0x4b, 0xa5, 0x82, 0xf5, 0x35, 0x4c, 0x9b, 0x5f, 0xf8, 0x52, 0x07, 0x61, 0x04, 0x53, + 0x4a, 0x9f, 0x79, 0xf0, 0x68, 0x47, 0x73, 0x3a, 0x15, 0x87, 0xbf, 0xa4, 0xf3, 0x94, 0x38, 0x26, + 0x8a, 0x69, 0xa4, 0x21, 0x91, 0x37, 0xb8, 0x5a, 0x90, 0x7c, 0x21, 0xcc, 0xd4, 0x82, 0x7a, 0xac, + 0x17, 0xe0, 0xd2, 0xf7, 0x03, 0x98, 0x36, 0x6b, 0x3d, 0xad, 0x95, 0xea, 0x15, 0xf4, 0xc6, 0xd5, + 0x9e, 0x0f, 0x11, 0xa2, 0x5f, 0x1b, 0x88, 0x95, 0xf5, 0x07, 0x50, 0x12, 0x58, 0xf1, 0xce, 0x7b, + 0x43, 0x9a, 0x11, 0x0b, 0x19, 0x8f, 0x1d, 0xa5, 0xf3, 0xb7, 0x0f, 0x25, 0xb6, 0x62, 0x0a, 0x4a, + 0x5e, 0xc1, 0x34, 0x0c, 0xae, 0xc7, 0xd7, 0x39, 0x36, 0xff, 0x81, 0xaf, 0x68, 0x22, 0x27, 0x88, + 0xa4, 0xab, 0xda, 0xa8, 0xad, 0x7e, 0x93, 0x37, 0x60, 0xe8, 0xbe, 0xdb, 0x8a, 0x84, 0x69, 0x24, + 0xde, 0xe4, 0x19, 0x5b, 0x5e, 0x60, 0x0b, 0x04, 0xcb, 0x86, 0xf3, 0x5a, 0x85, 0x67, 0x68, 0x2a, + 0x29, 0xc3, 0xf0, 0x26, 0xfd, 0x46, 0xab, 0x5f, 0xfe, 0xb4, 0xde, 0x85, 0xf3, 0xc2, 0x0d, 0x50, + 0x13, 0xd3, 0x75, 0xf1, 0x26, 0xbb, 0x60, 0x3c, 0x0c, 0x15, 0x2c, 0xb1, 0x88, 0xd1, 0xed, 0xb6, + 0x9b, 0x2f, 0x48, 0xc7, 0x36, 0x8a, 0x33, 0xd2, 0xbd, 0x2e, 0x6f, 0x81, 0x7a, 0x75, 0xe7, 0xff, + 0x56, 0x84, 0x72, 0xc2, 0xca, 0xb0, 0x78, 0xe8, 0xb4, 0x5a, 0xd4, 0x3b, 0xa0, 0xe4, 0x26, 0x0c, + 0xec, 0x6c, 0xed, 0x6c, 0x0b, 0x2b, 0xa9, 0x74, 0x00, 0x60, 0x20, 0x85, 0x63, 0x23, 0x06, 0x79, + 0x08, 0xe7, 0xa5, 0xa3, 0xaf, 0x2a, 0x12, 0x3d, 0x74, 0xa5, 0xbb, 0xdb, 0x70, 0x9a, 0x8e, 0xbc, + 0x2d, 0x4c, 0x22, 0x3f, 0xe9, 0xb8, 0x01, 0x6d, 0xa2, 0xe5, 0x27, 0xbe, 0x4d, 0xd7, 0x4a, 0x6c, + 0x1d, 0x8d, 0xfc, 0x00, 0xc6, 0x6b, 0xb5, 0xad, 0xb8, 0xf6, 0x41, 0xe3, 0x86, 0x48, 0x2f, 0xb2, + 0x0d, 0x44, 0xfe, 0xf4, 0xd6, 0xfa, 0xe3, 0x02, 0xcc, 0xe6, 0x98, 0x5b, 0xc8, 0x1b, 0x86, 0x1c, + 0xa6, 0x34, 0x39, 0x48, 0x94, 0xd5, 0x3e, 0x21, 0x88, 0x45, 0xcd, 0x6d, 0xba, 0xff, 0x0c, 0x6e, + 0xd3, 0xab, 0x7d, 0xb1, 0xab, 0x34, 0x79, 0x0d, 0xfa, 0x6b, 0xb5, 0x2d, 0x61, 0x56, 0x27, 0xf1, + 0x17, 0x68, 0xc8, 0x0c, 0x61, 0x01, 0x60, 0x44, 0x82, 0xac, 0x73, 0x30, 0x61, 0x74, 0x8c, 0x65, + 0xc1, 0xb8, 0xde, 0x42, 0xd6, 0xfb, 0x8b, 0x7e, 0x53, 0xf5, 0x3e, 0xfb, 0xdb, 0xda, 0x36, 0x65, + 0x46, 0xae, 0x00, 0xc8, 0xfb, 0x5a, 0xb7, 0x29, 0x6f, 0x7e, 0x04, 0x64, 0xad, 0x49, 0xae, 0xc3, + 0x78, 0x40, 0x9b, 0x6e, 0x40, 0x1b, 0x51, 0xbd, 0x13, 0x88, 0x07, 0x28, 0xf6, 0x98, 0x84, 0xed, + 0x06, 0x2d, 0x6b, 0x01, 0xc6, 0xb4, 0x86, 0xf6, 0x62, 0x38, 0x0d, 0x83, 0xba, 0xe1, 0x91, 0xff, + 0xb0, 0x7e, 0xaf, 0x00, 0xd3, 0xd8, 0xb3, 0x07, 0x2e, 0x5b, 0xf1, 0xe3, 0xe6, 0xcd, 0x1b, 0xfd, + 0x70, 0xd9, 0xe8, 0x87, 0x04, 0xae, 0xea, 0x90, 0x0f, 0x52, 0x1d, 0x72, 0x39, 0xab, 0x43, 0x70, + 0x56, 0xbb, 0xbe, 0xa7, 0xf7, 0x83, 0x7e, 0x03, 0xf7, 0x07, 0x05, 0x98, 0xd2, 0xda, 0xa4, 0x3e, + 0xf0, 0x9e, 0xd1, 0xa4, 0x4b, 0x19, 0x4d, 0x4a, 0x0d, 0x91, 0x85, 0x54, 0x8b, 0x5e, 0xe9, 0xd6, + 0xa2, 0xac, 0x11, 0x62, 0xf4, 0xfc, 0x5f, 0x16, 0x60, 0x26, 0x53, 0x06, 0xe4, 0x02, 0x53, 0xe9, + 0x1b, 0x01, 0x8d, 0x84, 0xe4, 0xc5, 0x2f, 0x06, 0x5f, 0x0b, 0xc3, 0x0e, 0x0d, 0x84, 0xdc, 0xc5, + 0x2f, 0xf2, 0x0a, 0x4c, 0x6c, 0xd3, 0xc0, 0xf5, 0x9b, 0xfc, 0x39, 0x00, 0xf7, 0xb3, 0x9d, 0xb0, + 0x4d, 0x20, 0xb9, 0x0c, 0xa3, 0xca, 0x4f, 0x94, 0x9b, 0x65, 0xed, 0x18, 0xc0, 0x78, 0x2f, 0xb9, + 0x07, 0xfc, 0x2e, 0x87, 0x11, 0x8b, 0x5f, 0x6c, 0x4d, 0x95, 0x46, 0xd2, 0x21, 0xbe, 0xa6, 0x4a, + 0x0b, 0xe8, 0x05, 0x18, 0xfa, 0xcc, 0xc6, 0xa1, 0x89, 0xe1, 0x1a, 0x6c, 0xf1, 0x8b, 0x4c, 0xa2, + 0x43, 0x37, 0x3e, 0x29, 0x41, 0x47, 0xee, 0x0f, 0x60, 0x3a, 0x4b, 0xae, 0x59, 0x03, 0x5b, 0xd0, + 0x16, 0x15, 0xed, 0x97, 0x30, 0x55, 0x6d, 0x36, 0x37, 0xee, 0x57, 0xb9, 0xab, 0x85, 0xe8, 0x55, + 0x3e, 0xf5, 0xb9, 0x99, 0x52, 0x68, 0xaa, 0x03, 0x6b, 0x9e, 0x1b, 0xd9, 0x53, 0xcb, 0xdf, 0xb8, + 0x61, 0xe4, 0x7a, 0x07, 0x9a, 0x2d, 0xd5, 0xbe, 0xb0, 0x49, 0x9f, 0x65, 0x0c, 0x01, 0xa6, 0x44, + 0x98, 0xbc, 0x39, 0x3c, 0x83, 0xf9, 0xb4, 0xc6, 0x36, 0x5e, 0x8d, 0x66, 0x4d, 0xbe, 0x71, 0x41, + 0x7f, 0xb5, 0xf1, 0xc4, 0xfa, 0x01, 0x5c, 0xe0, 0x2b, 0x79, 0xb7, 0xc6, 0x8b, 0x66, 0xeb, 0xa6, + 0x5f, 0xeb, 0x3d, 0x69, 0x9c, 0xe9, 0xda, 0x32, 0x7b, 0xdc, 0x68, 0x0b, 0x56, 0xf9, 0x1f, 0x0b, + 0x30, 0x97, 0x20, 0xad, 0x3d, 0xf7, 0x1a, 0x72, 0x1b, 0x79, 0x2d, 0xe9, 0x30, 0x8f, 0xea, 0x0f, + 0xb7, 0x79, 0xba, 0x4d, 0xe5, 0x33, 0x4f, 0xee, 0x00, 0x70, 0x62, 0x4d, 0x6b, 0x41, 0x8b, 0xbf, + 0xf0, 0x2d, 0x42, 0xbd, 0x45, 0x43, 0x21, 0x1d, 0xc8, 0x92, 0xbb, 0x98, 0x23, 0xbd, 0x4c, 0xe2, + 0x18, 0xa2, 0x84, 0x0a, 0xf2, 0x7a, 0x8e, 0x6d, 0x3c, 0x8b, 0xbf, 0xf5, 0x7f, 0xf6, 0xc3, 0xac, + 0xde, 0x81, 0x2f, 0xf2, 0xad, 0xdb, 0x30, 0xb6, 0xe8, 0x7b, 0x11, 0xfd, 0x26, 0xd2, 0x42, 0x44, + 0x10, 0xe5, 0x60, 0xa0, 0x4a, 0x84, 0xc6, 0xcc, 0x01, 0x75, 0xa6, 0xbe, 0x19, 0x3e, 0x92, 0x31, + 0x22, 0x59, 0x84, 0x89, 0x4d, 0xfa, 0x2c, 0x25, 0x40, 0xf4, 0xd3, 0xf4, 0xe8, 0xb3, 0xba, 0x26, + 0x44, 0xdd, 0x79, 0xce, 0xa0, 0x21, 0xfb, 0x30, 0x29, 0x07, 0x97, 0x21, 0xcc, 0x39, 0x7d, 0x33, + 0x35, 0x87, 0x33, 0x0f, 0xa1, 0xc0, 0x6a, 0xc8, 0x91, 0x61, 0x82, 0x23, 0xfb, 0x74, 0x5e, 0x23, + 0x8f, 0x0a, 0x60, 0xee, 0xd6, 0x5a, 0x89, 0xe1, 0x05, 0x9b, 0x8c, 0x06, 0xa0, 0xb3, 0xb0, 0xb6, + 0xa1, 0x9c, 0xee, 0x0f, 0x51, 0xdb, 0xdb, 0x30, 0xc4, 0xa1, 0x42, 0xfb, 0x91, 0xd1, 0x7f, 0x14, + 0x36, 0x37, 0x4f, 0xf0, 0x6a, 0x6c, 0x81, 0x6b, 0xad, 0xa2, 0xc9, 0x48, 0xe1, 0x28, 0xfd, 0xf3, + 0x6e, 0xb2, 0x7b, 0xd1, 0xc1, 0x58, 0x76, 0xaf, 0xee, 0x5e, 0x23, 0x1f, 0x82, 0x2c, 0xa2, 0xd5, + 0x4d, 0xe7, 0x24, 0x1a, 0x76, 0x0b, 0x86, 0x05, 0x28, 0x11, 0x97, 0x28, 0x9e, 0x7e, 0x12, 0xc1, + 0xfa, 0x00, 0x2e, 0xa2, 0x09, 0xd0, 0xf5, 0x0e, 0x5a, 0x74, 0x37, 0x34, 0x9e, 0x72, 0xf4, 0x9a, + 0xd6, 0x1f, 0xc1, 0x5c, 0x16, 0x6d, 0xcf, 0x99, 0xcd, 0x23, 0x85, 0xfc, 0x79, 0x11, 0xa6, 0xd7, + 0x42, 0x5d, 0x87, 0x52, 0xd1, 0x42, 0x32, 0x22, 0x58, 0xa0, 0x4c, 0x56, 0xfb, 0xb2, 0x22, 0x54, + 0xbc, 0xad, 0xbd, 0x14, 0x2d, 0x76, 0x0b, 0x4d, 0xc1, 0xb6, 0x2d, 0xf5, 0x56, 0xf4, 0x35, 0x18, + 0xd8, 0x64, 0x4b, 0x75, 0xbf, 0xe8, 0x3b, 0x4e, 0xc1, 0x40, 0xf8, 0x52, 0x93, 0x6d, 0x91, 0xec, + 0x07, 0xb9, 0x9f, 0x7a, 0x0f, 0x3a, 0xd0, 0x3b, 0xf4, 0xc2, 0x6a, 0x5f, 0xea, 0x69, 0xe8, 0xbb, + 0x30, 0x56, 0x6d, 0x1e, 0x71, 0x47, 0x48, 0xdf, 0x4b, 0x4c, 0x4b, 0xad, 0x64, 0xb5, 0xcf, 0xd6, + 0x11, 0xd9, 0xc1, 0xbe, 0xda, 0x6e, 0xe3, 0x46, 0x95, 0x15, 0x8e, 0x82, 0xe9, 0x5f, 0xd5, 0x76, + 0x7b, 0x61, 0x04, 0x86, 0x76, 0x9c, 0xe0, 0x80, 0x46, 0xd6, 0x97, 0x30, 0x27, 0x7c, 0x73, 0xb8, + 0xc1, 0x13, 0x3d, 0x78, 0xc2, 0xd8, 0xfd, 0xaa, 0x9b, 0x3f, 0xcd, 0x55, 0x00, 0x3c, 0xde, 0xac, + 0x79, 0x4d, 0xfa, 0x8d, 0x70, 0x0e, 0xd4, 0x20, 0xd6, 0x3b, 0x30, 0xaa, 0x24, 0x84, 0x3a, 0xbc, + 0xb6, 0xd9, 0xa1, 0xb4, 0xa6, 0x8d, 0x07, 0xb0, 0xf2, 0xd5, 0xeb, 0x45, 0xe3, 0xdb, 0x45, 0x80, + 0x19, 0xae, 0xf4, 0xbb, 0x30, 0x93, 0x18, 0x04, 0x71, 0xfc, 0x02, 0xa5, 0x76, 0x73, 0xef, 0x45, + 0xf5, 0x3b, 0xa9, 0x95, 0x17, 0x4f, 0xa5, 0x95, 0x5b, 0x7f, 0xbf, 0x88, 0xe7, 0xc5, 0x94, 0x3c, + 0x12, 0xa6, 0x37, 0xdd, 0xfc, 0xb7, 0x00, 0xa3, 0xf8, 0xf5, 0x4b, 0xf2, 0x99, 0x5e, 0x77, 0xd7, + 0x92, 0x91, 0x9f, 0x1d, 0x57, 0xfa, 0xd0, 0x9f, 0x24, 0x26, 0x23, 0x1f, 0xc3, 0xf0, 0xb2, 0xd7, + 0x44, 0x0e, 0xfd, 0x67, 0xe0, 0x20, 0x89, 0x58, 0x9f, 0x60, 0x93, 0x77, 0xd8, 0x14, 0xe6, 0x16, + 0x1b, 0x5b, 0x83, 0xc4, 0x07, 0xd7, 0xc1, 0xbc, 0x83, 0xeb, 0x50, 0xe2, 0xe0, 0x6a, 0xc1, 0xe0, + 0x56, 0xd0, 0x14, 0x61, 0x61, 0x26, 0xe7, 0xc7, 0x85, 0xe0, 0x10, 0x66, 0xf3, 0x22, 0xeb, 0x3f, + 0x17, 0x60, 0x76, 0x85, 0x46, 0x99, 0x63, 0xc8, 0x90, 0x4a, 0xe1, 0x5b, 0x4b, 0xa5, 0xf8, 0x22, + 0x52, 0x51, 0x5f, 0xdd, 0x9f, 0xf7, 0xd5, 0x03, 0x79, 0x5f, 0x3d, 0x98, 0xff, 0xd5, 0x2b, 0x30, + 0xc4, 0x3f, 0x95, 0x1d, 0xce, 0xd7, 0x22, 0x7a, 0x14, 0x1f, 0xce, 0x75, 0xc7, 0x38, 0x9b, 0x97, + 0x31, 0x45, 0x72, 0xdd, 0x09, 0xf5, 0xc3, 0xb9, 0xf8, 0x69, 0xfd, 0x18, 0x1f, 0xf8, 0xae, 0xfb, + 0x8d, 0x27, 0x9a, 0x91, 0x77, 0x98, 0xcf, 0xd0, 0xe4, 0xa5, 0x00, 0xc3, 0xe2, 0x25, 0xb6, 0xc4, + 0x20, 0xd7, 0x60, 0x6c, 0xcd, 0xbb, 0xef, 0x07, 0x0d, 0xba, 0xe5, 0xb5, 0x38, 0xf7, 0x11, 0x5b, + 0x07, 0x09, 0xe3, 0x87, 0xa8, 0x21, 0xb6, 0x28, 0x20, 0x20, 0x61, 0x51, 0x60, 0xb0, 0xbd, 0x79, + 0x9b, 0x97, 0x09, 0xdb, 0x0a, 0xfb, 0xbb, 0xdb, 0x61, 0x5c, 0x9d, 0xda, 0x7b, 0x21, 0xee, 0xc3, + 0x45, 0x9b, 0xb6, 0x5b, 0x0e, 0xd3, 0xe9, 0x8e, 0x7c, 0x8e, 0xaf, 0xbe, 0xf9, 0x5a, 0xc6, 0xe3, + 0x3c, 0xd3, 0x4d, 0x42, 0x35, 0xb9, 0xd8, 0xa5, 0xc9, 0x47, 0x70, 0x7d, 0x85, 0x46, 0xe6, 0x82, + 0x1a, 0x9b, 0x90, 0xc5, 0xc7, 0xaf, 0xc2, 0x48, 0x68, 0x9a, 0xbf, 0xe5, 0x63, 0xb3, 0x4c, 0xc2, + 0xbd, 0xb7, 0xe4, 0x05, 0x91, 0xe0, 0xa3, 0xfe, 0xb2, 0x3e, 0x81, 0x4a, 0x5e, 0x75, 0xa7, 0xf3, + 0x62, 0x75, 0xe1, 0x5a, 0x3e, 0x03, 0xd1, 0xdc, 0x65, 0x90, 0xa6, 0x72, 0x31, 0x85, 0x7a, 0xb5, + 0xd6, 0xb4, 0xae, 0x8b, 0x3f, 0xac, 0x05, 0xe9, 0xcf, 0xf7, 0x2d, 0x9a, 0x5b, 0xc7, 0x5b, 0x68, + 0x93, 0x41, 0x2c, 0xd7, 0x2a, 0x8c, 0x48, 0x98, 0x90, 0xeb, 0x6c, 0x66, 0x4b, 0xa5, 0x40, 0x9b, + 0x92, 0x81, 0x22, 0xb3, 0x7e, 0x2c, 0x6f, 0x64, 0x4c, 0x8a, 0xd3, 0xbd, 0x56, 0x3d, 0xcd, 0x15, + 0x8c, 0xe5, 0xc3, 0x45, 0x93, 0xb7, 0x6e, 0x69, 0x2f, 0x69, 0x96, 0x76, 0x6e, 0x60, 0xbf, 0x66, + 0x5a, 0x7e, 0x85, 0xf1, 0x40, 0x03, 0x91, 0xab, 0xba, 0x3d, 0x7d, 0x3c, 0xfd, 0xfc, 0xf5, 0x2e, + 0xcc, 0x65, 0x55, 0xa8, 0x9d, 0x03, 0x95, 0xd1, 0x56, 0xe8, 0x3b, 0x4b, 0x70, 0x55, 0x06, 0x66, + 0xf2, 0xfd, 0x28, 0x8c, 0x02, 0xa7, 0x5d, 0x6b, 0x04, 0x6e, 0x3b, 0xa6, 0xb2, 0x60, 0x88, 0x43, + 0x84, 0x24, 0xf8, 0xed, 0x16, 0xc7, 0x11, 0x25, 0xd6, 0x6f, 0x16, 0xc0, 0x32, 0x5c, 0xaf, 0xb0, + 0x9f, 0xb7, 0x03, 0xff, 0xa9, 0xdb, 0xd4, 0x6e, 0x94, 0xde, 0x30, 0xac, 0x99, 0xfc, 0x25, 0x60, + 0xd2, 0xeb, 0x5b, 0xac, 0x99, 0x77, 0x13, 0x16, 0x46, 0xae, 0x78, 0xa2, 0x3b, 0x96, 0x19, 0x01, + 0x47, 0x59, 0x1e, 0xff, 0x6b, 0x01, 0x6e, 0x74, 0x6d, 0x83, 0xf8, 0x9e, 0x7d, 0x28, 0x25, 0xcb, + 0xc4, 0x08, 0xaa, 0x68, 0xae, 0x18, 0x69, 0x0e, 0x7b, 0xf7, 0xb8, 0x6b, 0xb9, 0x74, 0x59, 0x6a, + 0x2b, 0xce, 0x29, 0x7e, 0x67, 0x6f, 0x3d, 0x79, 0x1f, 0x60, 0xc7, 0x8f, 0x9c, 0xd6, 0x22, 0x1a, + 0x00, 0xfa, 0xe3, 0x67, 0x02, 0x11, 0x83, 0xd6, 0x93, 0x11, 0x26, 0x34, 0x64, 0xeb, 0x53, 0x9c, + 0xd7, 0xd9, 0x8d, 0x3e, 0xdd, 0x54, 0x5b, 0x84, 0x1b, 0x09, 0x77, 0x80, 0x17, 0x60, 0x12, 0xc1, + 0x0c, 0x13, 0x3f, 0xd3, 0xbd, 0x57, 0x02, 0xbf, 0xd3, 0xfe, 0xe5, 0xf4, 0xfa, 0x9f, 0x14, 0xb8, + 0x7f, 0xa6, 0x5e, 0xad, 0xe8, 0xe8, 0x45, 0x80, 0x18, 0x9a, 0xf0, 0xd3, 0x57, 0x05, 0x7b, 0xf7, + 0xf8, 0x91, 0x1b, 0x2f, 0x0a, 0x0e, 0x38, 0x03, 0x8d, 0xec, 0x97, 0xdb, 0x93, 0x6f, 0xa1, 0x0f, + 0x80, 0xaa, 0xfd, 0x74, 0x72, 0x7f, 0x57, 0xda, 0x3f, 0xce, 0x48, 0x77, 0x08, 0xd3, 0x6c, 0x05, + 0xa8, 0x76, 0xa2, 0x43, 0x3f, 0x70, 0x23, 0xf9, 0xe2, 0x84, 0x6c, 0x8b, 0x77, 0xf8, 0x9c, 0xea, + 0xa3, 0x5f, 0x1c, 0x57, 0xde, 0x3b, 0x4b, 0xc8, 0x4c, 0xc9, 0x73, 0x47, 0xbd, 0xdd, 0xb7, 0x66, + 0xa1, 0x7f, 0xd1, 0x5e, 0xc7, 0x05, 0xcf, 0x5e, 0x57, 0x0b, 0x9e, 0xbd, 0x6e, 0xfd, 0x55, 0x11, + 0x2a, 0x3c, 0x52, 0x08, 0xba, 0x8e, 0xc4, 0x56, 0x0b, 0xcd, 0x17, 0xe5, 0xb4, 0x06, 0x86, 0x44, + 0x24, 0x90, 0xe2, 0x69, 0x22, 0x81, 0xfc, 0x1a, 0xe4, 0x98, 0xac, 0x4e, 0x61, 0x05, 0x78, 0xfd, + 0xe4, 0xb8, 0x72, 0x23, 0xb6, 0x02, 0xf0, 0xd2, 0x2c, 0x73, 0x40, 0x4e, 0x15, 0x69, 0xfb, 0xc5, + 0xc0, 0x0b, 0xd8, 0x2f, 0xee, 0xc2, 0x30, 0x1e, 0x66, 0xd6, 0xb6, 0x85, 0x33, 0x27, 0x0e, 0x4f, + 0x0c, 0xee, 0x53, 0x77, 0xf5, 0x48, 0x7a, 0x12, 0xcd, 0xfa, 0xfd, 0x22, 0x5c, 0xcb, 0x97, 0xb9, + 0x68, 0xdb, 0x12, 0x40, 0xec, 0xb4, 0xd2, 0xcd, 0x49, 0x06, 0xe7, 0xce, 0x33, 0xba, 0xaf, 0x9c, + 0xd4, 0x34, 0x3a, 0xa6, 0xfb, 0xc8, 0xf7, 0xcd, 0x89, 0x1b, 0x12, 0xe3, 0xd9, 0xb3, 0x08, 0x04, + 0x2b, 0x40, 0x46, 0x20, 0x58, 0x01, 0x23, 0xfb, 0x30, 0xbb, 0x1d, 0xb8, 0x4f, 0x9d, 0x88, 0x3e, + 0xa4, 0xcf, 0xf9, 0xfb, 0x9f, 0x65, 0xf1, 0xe8, 0x87, 0x3f, 0x5a, 0xbf, 0x79, 0x72, 0x5c, 0x79, + 0xa5, 0xcd, 0x51, 0x30, 0xd8, 0x17, 0x7f, 0x71, 0x59, 0x4f, 0xbf, 0x03, 0xca, 0x63, 0x64, 0xfd, + 0x8b, 0x02, 0x5c, 0x42, 0xb5, 0x5c, 0x98, 0x5d, 0x65, 0xe5, 0x2f, 0xe4, 0x2b, 0xa9, 0x7f, 0xa0, + 0x18, 0x8b, 0xe8, 0x2b, 0x69, 0xbc, 0xff, 0xb6, 0x0d, 0x34, 0xb2, 0x06, 0x63, 0xe2, 0x37, 0xce, + 0xbf, 0x7e, 0x3c, 0x10, 0xcc, 0x68, 0x0b, 0x16, 0x0e, 0x75, 0x6e, 0x2a, 0xc2, 0x81, 0x2d, 0x98, + 0xe1, 0x33, 0x49, 0x5b, 0xa7, 0xb5, 0x7e, 0x5e, 0x84, 0xcb, 0x7b, 0x34, 0x70, 0x1f, 0x3f, 0xcf, + 0xf9, 0x98, 0x2d, 0x98, 0x96, 0x20, 0x1e, 0x2d, 0xc4, 0x98, 0x62, 0x3c, 0x14, 0xa4, 0x6c, 0xaa, + 0x08, 0x37, 0x22, 0x67, 0x5c, 0x26, 0xe1, 0x19, 0xbc, 0x20, 0xdf, 0x86, 0x91, 0x44, 0xbc, 0x1e, + 0xec, 0x7f, 0x39, 0x43, 0xe3, 0xae, 0x5a, 0xed, 0xb3, 0x15, 0x26, 0xf9, 0xed, 0xfc, 0xdb, 0x27, + 0x61, 0xfa, 0xe8, 0x65, 0xff, 0xc4, 0x09, 0xcb, 0x26, 0xab, 0xa3, 0x95, 0x66, 0x4c, 0xd8, 0xd5, + 0x3e, 0x3b, 0xaf, 0xa6, 0x85, 0x31, 0x18, 0xad, 0xe2, 0x55, 0x1c, 0x3b, 0xb9, 0xff, 0x97, 0x22, + 0x5c, 0x95, 0x6f, 0x79, 0x72, 0xc4, 0xfc, 0x39, 0xcc, 0x4a, 0x50, 0xb5, 0xcd, 0x14, 0x06, 0xda, + 0x34, 0x25, 0xcd, 0xc3, 0xb1, 0x4a, 0x49, 0x3b, 0x02, 0x27, 0x16, 0x76, 0x1e, 0xf9, 0xcb, 0xb1, + 0x7e, 0x7e, 0x9c, 0x15, 0x3d, 0x09, 0xad, 0x90, 0xfa, 0x9a, 0x69, 0x88, 0xc6, 0x58, 0x3f, 0x9b, + 0x29, 0xeb, 0xe9, 0xc0, 0xb7, 0xb5, 0x9e, 0xae, 0xf6, 0x25, 0xed, 0xa7, 0x0b, 0x93, 0x30, 0xbe, + 0x49, 0x9f, 0xc5, 0x72, 0xff, 0x5f, 0x0b, 0x89, 0x00, 0x0b, 0x4c, 0xc3, 0xe0, 0x91, 0x16, 0x0a, + 0x71, 0x00, 0x1e, 0x0c, 0xb0, 0xa0, 0x6b, 0x18, 0x1c, 0x75, 0x0d, 0x86, 0xf9, 0xfd, 0x74, 0xf3, + 0x14, 0x27, 0x7c, 0xf5, 0x28, 0x87, 0xbf, 0x94, 0x6c, 0xf2, 0xc3, 0xbe, 0xa0, 0xb7, 0x1e, 0xc2, + 0x75, 0xe1, 0xb6, 0x6d, 0x76, 0x3e, 0x56, 0x74, 0xc6, 0xed, 0xcb, 0x72, 0xe0, 0xea, 0x0a, 0x4d, + 0x2e, 0x3d, 0xc6, 0xa3, 0xa5, 0x4f, 0xe0, 0x9c, 0x01, 0x57, 0x1c, 0x51, 0x2b, 0x55, 0x63, 0x48, + 0xb1, 0x4e, 0x62, 0x5b, 0xd7, 0xb2, 0xaa, 0xd0, 0x1b, 0x6b, 0x51, 0x8c, 0xab, 0x1a, 0xc4, 0x57, + 0x6c, 0xe1, 0x19, 0x56, 0xbd, 0x9b, 0xda, 0xbc, 0xe6, 0x2b, 0x1e, 0x0f, 0xbc, 0x27, 0x77, 0x5e, + 0x55, 0x6a, 0x4d, 0x18, 0x77, 0x01, 0xd6, 0x24, 0x8c, 0xcb, 0xa2, 0x16, 0x0d, 0x43, 0xeb, 0xdf, + 0x0d, 0x82, 0x25, 0x04, 0x9b, 0x75, 0xe9, 0x2e, 0xe5, 0xb1, 0x9f, 0x6a, 0xac, 0xd8, 0xa8, 0x2e, + 0xe8, 0xe1, 0x3c, 0xe3, 0x52, 0x3e, 0xf2, 0x50, 0xcf, 0x6b, 0xc4, 0x50, 0x63, 0xe4, 0xa5, 0xbe, + 0xfe, 0xab, 0x9c, 0x65, 0x92, 0x4f, 0xb6, 0x57, 0x4f, 0x8e, 0x2b, 0xd7, 0x73, 0x96, 0x49, 0x83, + 0x6f, 0xf6, 0x92, 0x69, 0x9b, 0x57, 0x22, 0xfd, 0x2f, 0x72, 0x25, 0xc2, 0x66, 0xa4, 0x7e, 0x29, + 0xb2, 0x6b, 0xca, 0x52, 0xcc, 0x47, 0x79, 0x21, 0xaf, 0x17, 0x89, 0x38, 0x07, 0x1a, 0xc4, 0xe0, + 0x6a, 0xb0, 0x21, 0x2e, 0x94, 0x34, 0x9b, 0xe5, 0xe2, 0x21, 0x6d, 0x3c, 0x11, 0xb6, 0x62, 0x79, + 0xa1, 0x9b, 0x65, 0x33, 0xe7, 0xa1, 0x9d, 0xf9, 0x3c, 0xe7, 0x05, 0xf5, 0x06, 0x23, 0xd5, 0xe3, + 0x34, 0x24, 0xd9, 0x92, 0x9f, 0xc2, 0x94, 0xea, 0xea, 0x84, 0xd7, 0xd5, 0xd8, 0xfc, 0x2b, 0x71, + 0x14, 0xd0, 0xa3, 0xc7, 0xce, 0xed, 0xa7, 0xf7, 0x6e, 0x67, 0xe0, 0xf2, 0xe7, 0xff, 0x0d, 0x59, + 0xa0, 0xb9, 0x5c, 0xe9, 0x17, 0x5d, 0x19, 0x84, 0xe4, 0x0b, 0x98, 0xae, 0xd5, 0xb6, 0xf8, 0xfb, + 0x0c, 0x5b, 0xde, 0xd9, 0xdb, 0xeb, 0xc2, 0x07, 0x0b, 0xbb, 0x3b, 0x0c, 0xfd, 0xba, 0x78, 0xd7, + 0xa1, 0xdf, 0xf4, 0xeb, 0x01, 0x10, 0xb2, 0x58, 0xe8, 0x37, 0xe5, 0xff, 0xb7, 0x7a, 0x7e, 0xc0, + 0x54, 0x11, 0xb7, 0x45, 0xc5, 0x3b, 0x22, 0x39, 0xb0, 0x73, 0x6e, 0xf9, 0x0a, 0xdf, 0xf1, 0x2d, + 0xdf, 0x3f, 0x2a, 0xca, 0x47, 0x17, 0xe9, 0x8b, 0xd6, 0x33, 0x5f, 0xf6, 0x65, 0x7e, 0xc1, 0xa9, + 0xf6, 0xe9, 0xcc, 0xc6, 0x91, 0x05, 0x79, 0x55, 0xaa, 0x42, 0x84, 0x4d, 0xaa, 0x6b, 0x87, 0xb8, + 0xc0, 0xb8, 0x3d, 0x45, 0xad, 0x48, 0xa3, 0x4a, 0xde, 0xc3, 0xf5, 0x7f, 0xfb, 0x7b, 0xb8, 0x7f, + 0x32, 0x0a, 0xe7, 0xb7, 0x9d, 0x03, 0xd7, 0x63, 0xfb, 0x81, 0x4d, 0x43, 0xbf, 0x13, 0x34, 0x28, + 0xa9, 0xc2, 0xa4, 0xe9, 0x51, 0xdb, 0xc3, 0x5f, 0x98, 0x6d, 0x79, 0x26, 0x8c, 0xcc, 0xc3, 0xa8, + 0x7a, 0xc5, 0x2b, 0xf6, 0xa9, 0x8c, 0xd7, 0xbd, 0xab, 0x7d, 0x76, 0x8c, 0x46, 0xde, 0x37, 0xae, + 0x8e, 0xce, 0xa9, 0x07, 0xe9, 0x88, 0x3b, 0xcf, 0x5d, 0x1e, 0x3d, 0xbf, 0x69, 0xee, 0xb5, 0xfc, + 0x7e, 0xe4, 0xc7, 0xa9, 0xdb, 0xa4, 0x41, 0xa3, 0xc5, 0x29, 0x93, 0x1a, 0xaa, 0x19, 0xb9, 0x61, + 0xbb, 0x33, 0xee, 0x99, 0xbe, 0x84, 0xb1, 0x87, 0x9d, 0x7d, 0x2a, 0xef, 0xcd, 0x86, 0xc4, 0xd6, + 0x9b, 0xf4, 0x13, 0x17, 0xe5, 0x7b, 0x6f, 0xf1, 0x3e, 0x78, 0xd2, 0xd9, 0xa7, 0xe9, 0x78, 0xf0, + 0x6c, 0xcd, 0xd3, 0x98, 0x91, 0x43, 0x28, 0x25, 0x5d, 0xba, 0x45, 0x50, 0xbd, 0x2e, 0x8e, 0xe8, + 0x18, 0x1c, 0x45, 0x8b, 0x3a, 0xcf, 0x1d, 0x4d, 0x8d, 0x4a, 0x52, 0x5c, 0xc9, 0xaf, 0xc3, 0x4c, + 0xa6, 0x41, 0x53, 0x3d, 0x4a, 0xeb, 0x6e, 0x2b, 0xc5, 0x05, 0x24, 0x21, 0x35, 0xf9, 0x02, 0xce, + 0xa8, 0x39, 0xbb, 0x16, 0xd2, 0x84, 0x73, 0x09, 0x57, 0x65, 0x91, 0x5a, 0x23, 0xdf, 0xf9, 0x19, + 0xf7, 0x3c, 0x19, 0x9d, 0x36, 0xb3, 0xae, 0x24, 0x4b, 0xb2, 0x0e, 0xa3, 0xca, 0x92, 0x20, 0xe2, + 0x99, 0x65, 0x59, 0x4d, 0xca, 0x27, 0xc7, 0x95, 0xe9, 0xd8, 0x6a, 0x62, 0xf0, 0x8c, 0x19, 0x90, + 0xdf, 0x80, 0xeb, 0x6a, 0x88, 0x6e, 0x05, 0xd9, 0xf6, 0x25, 0x11, 0xd5, 0xfe, 0x56, 0x72, 0x84, + 0xe7, 0xe1, 0xef, 0xdd, 0x5b, 0x28, 0x96, 0x0b, 0xab, 0x7d, 0x76, 0x6f, 0xd6, 0xe4, 0xb7, 0x0a, + 0x70, 0x21, 0xa7, 0xd6, 0x71, 0xac, 0xb5, 0xa7, 0xd1, 0x0f, 0xcf, 0x0d, 0xf8, 0x10, 0xcb, 0x6d, + 0xc6, 0x0f, 0x16, 0xa5, 0xf5, 0xcf, 0xf8, 0xee, 0x9c, 0x9a, 0xc8, 0x9b, 0x30, 0x84, 0xc7, 0xef, + 0xb0, 0x3c, 0x81, 0x0a, 0x2a, 0xc6, 0x04, 0xc2, 0x43, 0xba, 0xbe, 0x25, 0x09, 0x1c, 0xb2, 0xca, + 0x14, 0x3d, 0xdc, 0x12, 0xa5, 0x62, 0x26, 0x22, 0x88, 0x89, 0xc3, 0x02, 0x2f, 0x92, 0x71, 0x43, + 0x8c, 0xf4, 0x05, 0x26, 0xd9, 0x02, 0xc0, 0x48, 0x20, 0x56, 0xa5, 0x07, 0x03, 0x23, 0x03, 0xa5, + 0x41, 0x3e, 0x71, 0xa4, 0x0f, 0xfc, 0xef, 0x8c, 0xf0, 0x07, 0xb3, 0xbb, 0x9e, 0xfb, 0xd8, 0x8d, + 0x17, 0x30, 0xdd, 0x70, 0x17, 0xe7, 0x11, 0x12, 0x6a, 0x75, 0x4e, 0xc6, 0x20, 0x65, 0xe3, 0x2b, + 0xf6, 0xb4, 0xf1, 0xbd, 0xa5, 0xdd, 0x86, 0x69, 0x91, 0x42, 0xb9, 0xfa, 0x64, 0xda, 0xd4, 0xe2, + 0x6b, 0xb2, 0xaf, 0x61, 0x08, 0x83, 0x7b, 0xf2, 0xab, 0xc6, 0xb1, 0xf9, 0xdb, 0x62, 0xd9, 0xee, + 0xd2, 0x7c, 0x1e, 0x0d, 0x54, 0x3c, 0x82, 0xe7, 0x12, 0x47, 0x80, 0x21, 0x71, 0x84, 0x90, 0x1d, + 0x98, 0xda, 0x66, 0xbb, 0x39, 0xf7, 0xc4, 0x6e, 0x07, 0xc2, 0xee, 0xc1, 0x2d, 0x2a, 0xa8, 0x4d, + 0xb4, 0x65, 0x71, 0x9d, 0xaa, 0x72, 0x7d, 0x43, 0xcd, 0x20, 0x27, 0xcb, 0x30, 0x59, 0xa3, 0x4e, + 0xd0, 0x38, 0x7c, 0x48, 0x9f, 0x33, 0x4d, 0xca, 0x48, 0x9d, 0x11, 0x62, 0x09, 0xfb, 0x5e, 0x2c, + 0xd2, 0xdd, 0x47, 0x4c, 0x22, 0xf2, 0x29, 0x0c, 0xd5, 0xfc, 0x20, 0x5a, 0x78, 0x2e, 0x16, 0x35, + 0x79, 0x19, 0xc5, 0x81, 0x0b, 0x17, 0x65, 0xfa, 0x90, 0xd0, 0x0f, 0xa2, 0xfa, 0xbe, 0x11, 0x64, + 0x8a, 0xa3, 0x90, 0xe7, 0x30, 0x6d, 0x2e, 0x28, 0xc2, 0x41, 0x78, 0x44, 0x68, 0x70, 0x59, 0xab, + 0x16, 0x47, 0x59, 0xb8, 0x29, 0xb8, 0x5f, 0x4b, 0x2e, 0x5b, 0x8f, 0xb1, 0x5c, 0x57, 0x7b, 0xb2, + 0xe8, 0xc9, 0x06, 0xe6, 0x5d, 0xe1, 0x5f, 0x54, 0x0d, 0xb9, 0x63, 0xf1, 0x68, 0x1c, 0xc6, 0xac, + 0x83, 0x8b, 0x12, 0x4a, 0xc2, 0x09, 0x93, 0xc9, 0x7a, 0xec, 0x14, 0x29, 0xd9, 0x86, 0xf3, 0xbb, + 0x21, 0xdd, 0x0e, 0xe8, 0x53, 0x97, 0x3e, 0x93, 0xfc, 0x20, 0x8e, 0xf9, 0xc4, 0xf8, 0xb5, 0x79, + 0x69, 0x16, 0xc3, 0x34, 0x31, 0x79, 0x1f, 0x60, 0xdb, 0xf5, 0x3c, 0xda, 0xc4, 0x1b, 0xcd, 0x31, + 0x64, 0x85, 0xd6, 0xda, 0x36, 0x42, 0xeb, 0xbe, 0xd7, 0xd2, 0x45, 0xaa, 0x21, 0x93, 0x05, 0x98, + 0x58, 0xf3, 0x1a, 0xad, 0x8e, 0xf0, 0x3c, 0x08, 0x71, 0x41, 0x11, 0xb1, 0xe8, 0x5c, 0x5e, 0x50, + 0x4f, 0x4d, 0x72, 0x93, 0x84, 0x3c, 0x04, 0x22, 0x00, 0x62, 0xd4, 0x3a, 0xfb, 0x2d, 0x2a, 0xa6, + 0x3b, 0x5a, 0x61, 0x24, 0x23, 0x1c, 0xee, 0x46, 0x88, 0xb7, 0x14, 0xd9, 0xdc, 0xfb, 0x30, 0xa6, + 0x8d, 0xf9, 0x8c, 0xa8, 0x0e, 0xd3, 0x7a, 0x54, 0x87, 0x51, 0x3d, 0x7a, 0xc3, 0xdf, 0x2e, 0xc0, + 0xe5, 0xec, 0xb9, 0x24, 0x14, 0xb0, 0x2d, 0x18, 0x55, 0x40, 0xf5, 0x8e, 0x47, 0x9e, 0x2a, 0x12, + 0x1a, 0x10, 0x9f, 0xd0, 0x72, 0xe5, 0xd1, 0xbf, 0x3e, 0xe6, 0xf1, 0x02, 0xa6, 0xfe, 0xff, 0x7d, + 0x04, 0xa6, 0xd1, 0x5f, 0x3d, 0xb9, 0x4e, 0x7d, 0x82, 0xd1, 0x59, 0x10, 0xa6, 0x59, 0xae, 0x85, + 0x11, 0x8b, 0xc3, 0x93, 0xa1, 0xc4, 0x0c, 0x02, 0xf2, 0x8e, 0xee, 0x6e, 0x51, 0xd4, 0xf2, 0xbc, + 0x48, 0xa0, 0xfe, 0x09, 0xb1, 0x1f, 0xc6, 0x1b, 0xc6, 0x6d, 0xff, 0xa9, 0x17, 0xbd, 0x81, 0xd3, + 0x2e, 0x7a, 0xbb, 0x6a, 0xd1, 0xe3, 0x51, 0x3f, 0x5e, 0xd7, 0x16, 0xbd, 0x97, 0xbf, 0xda, 0x0d, + 0xbd, 0xec, 0xd5, 0x6e, 0xf8, 0xdb, 0xad, 0x76, 0x23, 0x2f, 0xb8, 0xda, 0xdd, 0x87, 0xc9, 0x4d, + 0x4a, 0x9b, 0xda, 0x1d, 0xcc, 0x68, 0xbc, 0x7b, 0x7a, 0x14, 0xad, 0x6b, 0x59, 0x17, 0x31, 0x09, + 0xaa, 0xdc, 0x55, 0x13, 0xfe, 0x66, 0x56, 0xcd, 0xb1, 0x97, 0xbc, 0x6a, 0x8e, 0x7f, 0x9b, 0x55, + 0x33, 0xb5, 0xf4, 0x4d, 0x9c, 0x79, 0xe9, 0xfb, 0x36, 0xab, 0xd5, 0xc7, 0xe8, 0xad, 0x58, 0xab, + 0xad, 0x0a, 0xc7, 0x14, 0xcd, 0x13, 0x64, 0xd5, 0x0f, 0xa5, 0x33, 0x37, 0xfe, 0xcd, 0x60, 0xdb, + 0x7e, 0x20, 0x6f, 0xd3, 0xf1, 0x6f, 0x6b, 0x01, 0x7d, 0x14, 0x75, 0x7a, 0xf5, 0x8e, 0x61, 0x58, + 0x3c, 0x82, 0x14, 0x6b, 0x5c, 0xf2, 0x18, 0x65, 0xcb, 0x72, 0xeb, 0xcf, 0x0b, 0xfc, 0xbe, 0xf3, + 0x7f, 0xc4, 0xa5, 0xf2, 0xdb, 0xdc, 0x41, 0xfe, 0x76, 0x1c, 0x1c, 0x41, 0x04, 0x72, 0x08, 0x9c, + 0xc6, 0x93, 0xf8, 0x12, 0xf8, 0x47, 0x6c, 0x9e, 0xeb, 0x05, 0x18, 0xaa, 0x36, 0x3e, 0x2b, 0x9a, + 0x85, 0x7b, 0xf7, 0xe4, 0x02, 0x20, 0x62, 0x44, 0x70, 0xb0, 0xb9, 0x00, 0xe8, 0x04, 0xe8, 0x86, + 0x77, 0xce, 0xb2, 0xf9, 0xdb, 0xfe, 0xcc, 0x16, 0xbc, 0x9b, 0x7e, 0x9d, 0x8e, 0x87, 0x91, 0xf8, + 0x75, 0xba, 0x2e, 0xc6, 0xf8, 0x9d, 0xfa, 0x2e, 0x5c, 0xb2, 0xe9, 0x91, 0xff, 0x94, 0xbe, 0x5c, + 0xb6, 0x5f, 0xc1, 0x45, 0x93, 0x21, 0x7f, 0xc7, 0xc4, 0xe3, 0xe2, 0x7f, 0x9c, 0x1d, 0x4d, 0x5f, + 0x10, 0xf0, 0x68, 0xfa, 0x3c, 0x28, 0x37, 0xfb, 0x53, 0xdf, 0x37, 0xb0, 0xcc, 0xf2, 0xe1, 0xb2, + 0xc9, 0xbc, 0xda, 0x6c, 0x62, 0x56, 0xcd, 0x86, 0xdb, 0x76, 0xbc, 0x88, 0x6c, 0xc1, 0x98, 0xf6, + 0x33, 0x61, 0x2a, 0xd0, 0x4a, 0x84, 0x4e, 0x13, 0x03, 0x8c, 0xa0, 0xa6, 0x31, 0xd8, 0xa2, 0x50, + 0x49, 0x8a, 0x87, 0x89, 0x4c, 0xaf, 0x73, 0x01, 0x26, 0xb4, 0x9f, 0xca, 0x1a, 0x8a, 0x93, 0x5f, + 0xab, 0xc1, 0x14, 0x98, 0x49, 0x62, 0x35, 0x60, 0x2e, 0x4b, 0x68, 0x3c, 0xfa, 0x35, 0x59, 0x8e, + 0x23, 0x67, 0xf5, 0x76, 0xe4, 0x3b, 0x97, 0x17, 0x35, 0xcb, 0xfa, 0xbf, 0x06, 0xe0, 0x92, 0xe8, + 0x8c, 0x97, 0xd9, 0xe3, 0xe4, 0xc7, 0x30, 0xa6, 0xf5, 0xb1, 0x10, 0xfa, 0x35, 0xf9, 0x0a, 0x29, + 0x6f, 0x2c, 0x70, 0x93, 0x46, 0x07, 0x01, 0xf5, 0x44, 0x77, 0xaf, 0xf6, 0xd9, 0x3a, 0x4b, 0xd2, + 0x82, 0x49, 0xb3, 0xa3, 0x85, 0x55, 0xe7, 0x46, 0x66, 0x25, 0x26, 0xaa, 0x0c, 0x8d, 0xdd, 0xac, + 0x67, 0x76, 0xf7, 0x6a, 0x9f, 0x9d, 0xe0, 0x4d, 0xbe, 0x81, 0xf3, 0xa9, 0x5e, 0x16, 0xc6, 0xba, + 0xd7, 0x32, 0x2b, 0x4c, 0x61, 0x73, 0x4b, 0x6f, 0x80, 0xe0, 0xdc, 0x6a, 0xd3, 0x95, 0x90, 0x26, + 0x8c, 0xeb, 0x1d, 0x2f, 0xcc, 0x4e, 0xd7, 0xbb, 0x88, 0x92, 0x23, 0x72, 0xe5, 0x4e, 0xc8, 0x12, + 0xfb, 0xfe, 0xb9, 0x69, 0xbd, 0x36, 0x90, 0x47, 0x60, 0x88, 0xff, 0x66, 0x4b, 0xc0, 0x76, 0x40, + 0x43, 0xea, 0x35, 0xa8, 0xe1, 0xfb, 0xfd, 0x2d, 0x97, 0x80, 0x7f, 0x5e, 0x80, 0x72, 0x16, 0xdf, + 0x1a, 0xf5, 0x9a, 0x64, 0x1b, 0x4a, 0xc9, 0x8a, 0xc4, 0xa8, 0xb6, 0x54, 0xf4, 0xe1, 0xdc, 0x26, + 0xad, 0xf6, 0xd9, 0x29, 0x6a, 0xb2, 0x09, 0xe7, 0x35, 0x98, 0x30, 0xae, 0x16, 0x4f, 0x63, 0x5c, + 0x65, 0xbd, 0x90, 0x22, 0xd5, 0x6d, 0xd3, 0xab, 0xb8, 0x33, 0x2e, 0xf9, 0x47, 0x8e, 0xeb, 0x31, + 0x45, 0x57, 0x0b, 0x9e, 0x05, 0x31, 0x54, 0xc8, 0x86, 0x5b, 0x5b, 0x11, 0x2a, 0xdf, 0xaa, 0x28, + 0x14, 0xeb, 0x23, 0x5c, 0xc1, 0x85, 0x8d, 0x8e, 0x3f, 0xf8, 0x55, 0xcc, 0xae, 0xc1, 0xe0, 0xce, + 0x7a, 0x6d, 0xb1, 0x2a, 0x9e, 0x0f, 0xf3, 0xa0, 0x13, 0xad, 0xb0, 0xde, 0x70, 0x6c, 0x5e, 0x60, + 0x7d, 0x08, 0x64, 0x85, 0x46, 0x22, 0xfc, 0xbd, 0xa2, 0x7b, 0x15, 0x86, 0x05, 0x48, 0x50, 0xa2, + 0xd7, 0x9d, 0x08, 0xa6, 0x6f, 0xcb, 0x32, 0x6b, 0x5b, 0x9e, 0x13, 0x5a, 0xd4, 0x09, 0xb5, 0x8d, + 0xf9, 0x3d, 0x18, 0x09, 0x04, 0x4c, 0xec, 0xcb, 0x93, 0x2a, 0xbb, 0x09, 0x82, 0xb9, 0x3d, 0x5b, + 0xe2, 0xd8, 0xea, 0x2f, 0x6b, 0x1d, 0x03, 0xc4, 0x6c, 0xad, 0x2d, 0x2d, 0x32, 0xa9, 0x0a, 0x61, + 0xc9, 0xee, 0xb8, 0x83, 0xee, 0xe9, 0x11, 0xd5, 0x1f, 0x0f, 0xa3, 0x68, 0x70, 0x92, 0x8b, 0xb0, + 0x48, 0x1a, 0x8a, 0xf5, 0x96, 0x0a, 0x37, 0x93, 0xc1, 0x2d, 0x2f, 0x4b, 0xc7, 0x26, 0x06, 0xd2, + 0x59, 0x41, 0x4f, 0x9c, 0x97, 0xd1, 0x08, 0x07, 0xe6, 0xf8, 0x36, 0xcf, 0xbe, 0x4a, 0x24, 0x1a, + 0xf4, 0xd5, 0xd2, 0xb8, 0x08, 0xa3, 0x0a, 0xa6, 0xae, 0xd5, 0xb8, 0xac, 0x0c, 0xfc, 0xbd, 0xb7, + 0xf8, 0x3b, 0xeb, 0x86, 0x62, 0x10, 0xd3, 0xb1, 0x2a, 0xf8, 0xbc, 0xfb, 0x8e, 0xab, 0x08, 0x69, + 0x10, 0x7d, 0xa7, 0x55, 0xc4, 0x91, 0x96, 0xce, 0x52, 0x85, 0x81, 0xbf, 0x37, 0x7f, 0x1a, 0x41, + 0x7d, 0xc7, 0x55, 0x30, 0x41, 0x7d, 0x77, 0x55, 0x50, 0x19, 0x92, 0x8a, 0x0f, 0xd2, 0x54, 0x25, + 0xcb, 0xe9, 0x4a, 0xa4, 0xe1, 0x3a, 0x41, 0xd1, 0xb5, 0x3f, 0x28, 0x5c, 0xe6, 0xc2, 0xfa, 0x25, + 0x54, 0xc3, 0x04, 0xf6, 0xdd, 0x56, 0xf3, 0xff, 0x16, 0x78, 0x80, 0xac, 0xda, 0x96, 0x96, 0xe2, + 0xd3, 0x7b, 0xec, 0x6b, 0xb7, 0xfe, 0xda, 0x6c, 0x7f, 0xe8, 0x7a, 0x4d, 0xfd, 0xd6, 0xdf, 0xe9, + 0x44, 0x87, 0x2a, 0x80, 0xf4, 0x13, 0xd7, 0x6b, 0xda, 0x49, 0x6c, 0xf2, 0x3e, 0x4c, 0x68, 0x20, + 0xa5, 0xad, 0xf1, 0x2c, 0x1c, 0x3a, 0xb9, 0xdb, 0xb4, 0x4d, 0x4c, 0xeb, 0xaf, 0x0b, 0x30, 0x95, + 0x91, 0x7c, 0x1a, 0x8d, 0x19, 0x78, 0x0a, 0x52, 0x0b, 0x95, 0xc8, 0x9b, 0x85, 0xb1, 0x3a, 0x8c, + 0x4d, 0x52, 0x21, 0x62, 0xfe, 0x01, 0x2d, 0x51, 0x76, 0x51, 0x4b, 0xe9, 0x96, 0x9d, 0x1c, 0x5b, + 0x47, 0x27, 0x21, 0x40, 0xdc, 0x12, 0x61, 0x36, 0xae, 0x31, 0x95, 0x56, 0xcb, 0xb2, 0xfd, 0x52, + 0xd2, 0x7c, 0x6b, 0xd5, 0x58, 0xbf, 0x5d, 0x84, 0x0b, 0x19, 0xdf, 0x5f, 0xa3, 0xd1, 0xdf, 0x84, + 0x08, 0x12, 0xb9, 0xce, 0xfb, 0x7f, 0x49, 0xb9, 0xce, 0xad, 0x7f, 0x53, 0x84, 0x0b, 0xbb, 0xed, + 0x10, 0x1f, 0x6f, 0xad, 0x79, 0x4f, 0xa9, 0x17, 0xf9, 0xc1, 0x73, 0x7c, 0x70, 0x42, 0xde, 0x81, + 0xc1, 0x55, 0xda, 0x6a, 0xf9, 0x62, 0xfc, 0x5f, 0x91, 0x8e, 0x17, 0x49, 0x6c, 0x44, 0x5a, 0xed, + 0xb3, 0x39, 0x36, 0x79, 0x1f, 0x46, 0x57, 0xa9, 0x13, 0x44, 0xfb, 0xd4, 0x91, 0x47, 0x16, 0x99, + 0x1b, 0x44, 0x23, 0x11, 0x08, 0xab, 0x7d, 0x76, 0x8c, 0x4d, 0xe6, 0xd9, 0x69, 0xde, 0x3b, 0x50, + 0x0f, 0xd5, 0x73, 0x2a, 0x64, 0x38, 0xab, 0x7d, 0x36, 0xe2, 0x92, 0x0d, 0x98, 0xa8, 0x1e, 0x50, + 0x2f, 0xda, 0xa0, 0x91, 0xd3, 0x74, 0x22, 0x47, 0xa8, 0xb6, 0xaf, 0xe6, 0x11, 0x1b, 0xc8, 0xab, + 0x7d, 0xb6, 0x49, 0x4d, 0x3e, 0x84, 0xe1, 0x15, 0xdf, 0x6f, 0xee, 0x3f, 0x97, 0x11, 0x14, 0x2a, + 0x79, 0x8c, 0x04, 0xda, 0x6a, 0x9f, 0x2d, 0x29, 0x16, 0x06, 0xa1, 0x7f, 0x23, 0x3c, 0xb0, 0x8e, + 0x0b, 0x50, 0x5e, 0xf2, 0x9f, 0x79, 0x99, 0x52, 0xfd, 0x81, 0x29, 0x55, 0xc9, 0x3e, 0x03, 0x3f, + 0x21, 0xd7, 0xb7, 0x61, 0x60, 0xdb, 0xf5, 0x0e, 0x12, 0xaa, 0x60, 0x06, 0x1d, 0xc3, 0x42, 0xf1, + 0xb8, 0xde, 0x01, 0x59, 0x97, 0x3a, 0xb8, 0xb0, 0x35, 0xf6, 0x1b, 0x8a, 0x7f, 0x06, 0xb5, 0x8e, + 0x1d, 0xeb, 0xda, 0xfc, 0xb7, 0xfc, 0xc0, 0x37, 0x60, 0x36, 0xa7, 0x5e, 0xf1, 0xf2, 0x9c, 0x7d, + 0xdb, 0x00, 0x2a, 0x36, 0xaf, 0xc3, 0x4c, 0x66, 0xff, 0xa5, 0x10, 0xff, 0x5e, 0xd6, 0x40, 0xe4, + 0x5f, 0x5e, 0x86, 0x61, 0x99, 0x34, 0x8b, 0xdb, 0x7e, 0xe4, 0x4f, 0x7c, 0x7b, 0x25, 0x27, 0xaa, + 0x0c, 0x95, 0x22, 0xe7, 0xe3, 0x9e, 0x16, 0x9a, 0x8a, 0x4f, 0xa7, 0x0f, 0xbe, 0xc5, 0xa4, 0x51, + 0xbc, 0x58, 0x9d, 0xab, 0x7e, 0x18, 0x79, 0xca, 0xa9, 0xd7, 0x56, 0xbf, 0xc9, 0x2d, 0x28, 0xc9, + 0x04, 0x19, 0x22, 0x13, 0x8f, 0xc8, 0xcc, 0x6e, 0xa7, 0xe0, 0xe4, 0x3d, 0x98, 0x4d, 0xc2, 0xe4, + 0x57, 0xf2, 0xc7, 0x73, 0x79, 0xc5, 0xd6, 0x9f, 0x15, 0x31, 0x7a, 0x78, 0x97, 0x71, 0xcd, 0xa4, + 0xbb, 0x55, 0x13, 0xd2, 0x2a, 0x6e, 0xd5, 0xc8, 0x65, 0x18, 0xdd, 0xaa, 0x19, 0x99, 0xc7, 0xec, + 0x18, 0xc0, 0x9a, 0xcd, 0x3e, 0xa1, 0x1a, 0x34, 0x0e, 0xdd, 0x88, 0x36, 0xa2, 0x4e, 0x20, 0x56, + 0x61, 0x3b, 0x05, 0x27, 0x16, 0x8c, 0xaf, 0xb4, 0xdc, 0xfd, 0x86, 0x64, 0xc6, 0x45, 0x60, 0xc0, + 0xc8, 0x6b, 0x30, 0xb9, 0xe6, 0x85, 0x91, 0xd3, 0x6a, 0x6d, 0xd0, 0xe8, 0xd0, 0x6f, 0x8a, 0xe4, + 0xa8, 0x76, 0x02, 0xca, 0xea, 0x5d, 0xf4, 0xbd, 0xc8, 0x71, 0x3d, 0x1a, 0xd8, 0x1d, 0x2f, 0x72, + 0x8f, 0xa8, 0xf8, 0xf6, 0x14, 0x9c, 0xbc, 0x0d, 0x33, 0x0a, 0xb6, 0x15, 0x34, 0x0e, 0x69, 0x18, + 0x05, 0x98, 0x8f, 0x10, 0xdd, 0x77, 0xec, 0xec, 0x42, 0xac, 0xa1, 0xe5, 0x77, 0x9a, 0xcb, 0xde, + 0x53, 0x37, 0xf0, 0x3d, 0xcc, 0xf6, 0x31, 0x22, 0x6a, 0x48, 0xc0, 0xad, 0x3f, 0x1c, 0xc9, 0x9c, + 0xb6, 0xdf, 0x66, 0x0c, 0x7e, 0x01, 0xe3, 0x8b, 0x4e, 0xdb, 0xd9, 0x77, 0x5b, 0x6e, 0xe4, 0xaa, + 0xc4, 0x6d, 0xef, 0xf4, 0x98, 0xf3, 0x32, 0x65, 0x0a, 0x6d, 0xea, 0xc4, 0xb6, 0xc1, 0x6a, 0xee, + 0xaf, 0x86, 0x60, 0x26, 0x13, 0x8f, 0xdc, 0x14, 0x19, 0xde, 0xd4, 0xba, 0x2a, 0xd2, 0x87, 0xd9, + 0x49, 0x30, 0xeb, 0x4b, 0x04, 0x2d, 0xb6, 0xa8, 0xe3, 0x75, 0x44, 0xf2, 0x30, 0xdb, 0x80, 0xb1, + 0xbe, 0x64, 0x7a, 0x83, 0xc6, 0x0c, 0x7d, 0xb2, 0xed, 0x04, 0x94, 0x5c, 0x83, 0x31, 0x06, 0x91, + 0xac, 0x06, 0xf8, 0xeb, 0x41, 0x0d, 0xc4, 0x38, 0x6d, 0xfa, 0x4d, 0xaa, 0x71, 0x1a, 0xe4, 0x9c, + 0x4c, 0x28, 0xe3, 0xc4, 0x20, 0x92, 0xd3, 0x10, 0xe7, 0xa4, 0x81, 0xc8, 0x2b, 0x30, 0x51, 0x6d, + 0xb7, 0x35, 0x46, 0x98, 0x35, 0xcc, 0x36, 0x81, 0xe4, 0x2a, 0x40, 0xb5, 0xdd, 0x96, 0x6c, 0x30, + 0x23, 0x98, 0xad, 0x41, 0xc8, 0xed, 0x38, 0x00, 0x9c, 0xc6, 0x0a, 0xaf, 0x13, 0xec, 0x8c, 0x12, + 0x26, 0x57, 0x15, 0x2d, 0x4b, 0x30, 0x05, 0x2e, 0xd7, 0x04, 0x98, 0x7c, 0x04, 0x17, 0x13, 0x7e, + 0x17, 0x5a, 0x05, 0x68, 0xea, 0xb7, 0xf3, 0x11, 0xc8, 0xbb, 0x70, 0x21, 0x51, 0x28, 0xab, 0x43, + 0xab, 0xbe, 0x9d, 0x53, 0x4a, 0x3e, 0x80, 0x72, 0xe2, 0x45, 0x78, 0x5c, 0x29, 0x5a, 0xf0, 0xed, + 0xdc, 0x72, 0x36, 0xbb, 0x12, 0x4f, 0xcb, 0x44, 0x95, 0x78, 0x59, 0x69, 0x67, 0x17, 0x92, 0x55, + 0xa8, 0x64, 0xfa, 0xb2, 0x68, 0x15, 0x63, 0xa6, 0x33, 0xbb, 0x17, 0x1a, 0x59, 0x80, 0xcb, 0x99, + 0x28, 0xb2, 0x19, 0x98, 0xff, 0xcc, 0xee, 0x8a, 0x43, 0xe6, 0x61, 0x3a, 0xf6, 0xe9, 0xd1, 0x9a, + 0x80, 0xa9, 0xcf, 0xec, 0xcc, 0x32, 0xf2, 0xa6, 0xf9, 0xee, 0x9f, 0x57, 0x86, 0x99, 0xcf, 0xec, + 0x74, 0x81, 0x75, 0x52, 0x80, 0xcb, 0x99, 0x1b, 0xa5, 0xd4, 0xe7, 0xe7, 0x92, 0x8a, 0xa3, 0xb6, + 0x16, 0xdc, 0x82, 0x01, 0x54, 0xf0, 0xb9, 0xad, 0x58, 0xba, 0xb1, 0x22, 0x3d, 0x67, 0xc5, 0x4a, + 0x6d, 0xc4, 0x21, 0x2b, 0xea, 0x6e, 0xb0, 0x1f, 0x2d, 0x19, 0x77, 0x92, 0x0a, 0x54, 0x46, 0xe5, + 0xfa, 0x1d, 0xa1, 0xbc, 0x0d, 0xfc, 0x36, 0xd7, 0x30, 0x7f, 0x56, 0x80, 0x4a, 0x0f, 0xfd, 0x40, + 0x7d, 0x53, 0xe1, 0x14, 0xdf, 0xf4, 0x40, 0x7d, 0x13, 0x7f, 0x76, 0x3b, 0x7f, 0x3a, 0x1d, 0xe4, + 0x65, 0x7f, 0xd6, 0x5f, 0x17, 0x80, 0xa4, 0xf5, 0x50, 0xf2, 0x7d, 0x18, 0xad, 0xd5, 0x56, 0x0d, + 0x8f, 0xbe, 0xd4, 0xed, 0x50, 0x8c, 0x41, 0xee, 0x9e, 0xca, 0x85, 0x4f, 0x77, 0xe0, 0xfb, 0x24, + 0xe5, 0x37, 0xd8, 0xdf, 0xd5, 0x6f, 0x30, 0xe5, 0x35, 0xb8, 0x9c, 0xe1, 0x08, 0x37, 0xd0, 0xc3, + 0x11, 0x2e, 0xed, 0xe5, 0x66, 0x2d, 0x41, 0x39, 0x4f, 0x95, 0xc5, 0x15, 0x8e, 0x87, 0x4d, 0xd3, + 0x6e, 0xb8, 0xf8, 0x0a, 0x67, 0x82, 0xad, 0x77, 0xe1, 0x82, 0xa2, 0xe6, 0xf9, 0x58, 0xb4, 0xe0, + 0x06, 0xe2, 0xfc, 0xab, 0x82, 0x28, 0xc4, 0x00, 0xeb, 0x4f, 0x07, 0x52, 0x84, 0xb5, 0xce, 0xd1, + 0x91, 0x13, 0x3c, 0x27, 0x55, 0x93, 0xb0, 0xbf, 0xe7, 0x91, 0x63, 0x61, 0xe0, 0x67, 0xc7, 0x95, + 0x3e, 0x8d, 0x3b, 0xdb, 0x17, 0x50, 0xc3, 0xf0, 0x1a, 0x94, 0xdf, 0x8d, 0x15, 0x79, 0x00, 0x27, + 0x03, 0x48, 0xf6, 0x60, 0x42, 0xec, 0xdd, 0xf8, 0x5b, 0xce, 0xb1, 0xbb, 0xc9, 0x39, 0x66, 0x34, + 0xef, 0xb6, 0x41, 0xc2, 0x47, 0xa3, 0xc9, 0x86, 0x7c, 0x01, 0x93, 0x52, 0x53, 0x13, 0x8c, 0xb9, + 0x37, 0xd3, 0xbd, 0xee, 0x8c, 0x4d, 0x1a, 0xce, 0x39, 0xc1, 0x88, 0x35, 0x59, 0x2e, 0x76, 0x9c, + 0xf3, 0xe0, 0x69, 0x9a, 0x6c, 0x90, 0x88, 0x26, 0x1b, 0xb0, 0xb9, 0x4f, 0x81, 0xa4, 0xbf, 0xab, + 0xd7, 0x74, 0x9a, 0xd0, 0xa6, 0xd3, 0x5c, 0x15, 0xa6, 0x32, 0x3e, 0xe0, 0x4c, 0x2c, 0x3e, 0x05, + 0x92, 0x6e, 0xe9, 0x59, 0x38, 0x58, 0x37, 0xe1, 0x35, 0x25, 0x02, 0x35, 0x1a, 0x0c, 0x9e, 0xd2, + 0x02, 0xfe, 0x9b, 0x45, 0xa8, 0xf4, 0x40, 0x25, 0xff, 0x7f, 0x21, 0x29, 0x6d, 0x3e, 0x1a, 0xdf, + 0x4f, 0x4a, 0x3b, 0x9b, 0x3e, 0x43, 0xec, 0x0b, 0x1f, 0xfc, 0xd6, 0x5f, 0xbc, 0xf0, 0xc9, 0x23, + 0xdd, 0x65, 0x67, 0x97, 0xd6, 0x80, 0x2e, 0x2d, 0x1b, 0xa6, 0x8d, 0x33, 0xdb, 0x69, 0x36, 0xaf, + 0xab, 0x00, 0x22, 0x7b, 0xeb, 0xba, 0x7f, 0x20, 0xf4, 0x44, 0x0d, 0x62, 0xdd, 0x87, 0x99, 0x04, + 0x4f, 0x61, 0x95, 0xff, 0x3e, 0xa8, 0x47, 0xec, 0xc8, 0xb4, 0x7f, 0xe1, 0xfc, 0x2f, 0x8e, 0x2b, + 0x13, 0x4c, 0xa5, 0xbf, 0x1d, 0xa7, 0x06, 0x90, 0x7f, 0x59, 0x1b, 0xfa, 0xbd, 0x42, 0xb5, 0xa5, + 0x07, 0xf7, 0x21, 0xf7, 0x60, 0x88, 0x43, 0x12, 0x01, 0xb8, 0x75, 0x6c, 0xb1, 0x26, 0x08, 0x44, + 0x6b, 0x06, 0x9f, 0xdc, 0xe2, 0x8f, 0x6a, 0x1c, 0x22, 0xc2, 0xda, 0xe5, 0x09, 0x69, 0x62, 0xb0, + 0x0a, 0xf2, 0x3d, 0x50, 0x8d, 0x43, 0x59, 0x48, 0x27, 0x10, 0x89, 0xe7, 0xf9, 0xcf, 0x5a, 0xb4, + 0xc9, 0x93, 0xfd, 0x2d, 0x8c, 0x0b, 0x27, 0x90, 0x01, 0x87, 0x31, 0x40, 0x32, 0xeb, 0x13, 0x98, + 0x61, 0x9a, 0x42, 0x90, 0xac, 0x0f, 0xd3, 0x50, 0x30, 0x98, 0xe9, 0x59, 0xef, 0x30, 0x10, 0x7a, + 0xd6, 0x8b, 0x42, 0x6b, 0x1d, 0x2e, 0x72, 0xab, 0xa4, 0xfe, 0x49, 0xf1, 0x1d, 0xc0, 0x20, 0xfe, + 0x4e, 0x3c, 0xd8, 0xcc, 0xf8, 0x7a, 0x8e, 0x67, 0x7d, 0x8c, 0x2f, 0x82, 0xc4, 0x20, 0x75, 0x7d, + 0x2f, 0x36, 0x41, 0x9e, 0xee, 0x09, 0xf1, 0xff, 0x0c, 0x97, 0xab, 0xed, 0x36, 0xf5, 0x9a, 0x31, + 0xe1, 0x4e, 0xe0, 0x9c, 0x32, 0xc0, 0x03, 0xa9, 0xc2, 0x20, 0x62, 0xab, 0x0b, 0x54, 0xd1, 0xdc, + 0x8c, 0xe6, 0x20, 0x9e, 0x88, 0xc8, 0x8a, 0x15, 0x70, 0x4a, 0xab, 0x09, 0xb3, 0xb5, 0xce, 0xfe, + 0x91, 0x1b, 0xa1, 0x3f, 0x3e, 0x06, 0x49, 0x91, 0x75, 0xaf, 0xc9, 0x1c, 0x62, 0x5c, 0x18, 0x37, + 0xe3, 0x97, 0x23, 0xe8, 0xd2, 0x2f, 0x02, 0xa7, 0x3c, 0xbd, 0x77, 0x3b, 0x26, 0x45, 0xf3, 0x0b, + 0xaf, 0x05, 0x8b, 0x45, 0x9e, 0x31, 0x6b, 0x0a, 0xce, 0xeb, 0x97, 0x51, 0x7c, 0x84, 0xcc, 0xc0, + 0x94, 0x79, 0xc9, 0xc4, 0xc1, 0x5f, 0xc3, 0x34, 0x37, 0x82, 0xf3, 0x88, 0xea, 0xf3, 0x71, 0xf0, + 0xf0, 0xe2, 0xde, 0x7c, 0xe2, 0x21, 0x00, 0xfa, 0x07, 0xab, 0x5c, 0x19, 0x7b, 0xf3, 0xfc, 0x55, + 0xe7, 0xd3, 0x79, 0xe3, 0x2a, 0xb3, 0xb8, 0x37, 0xbf, 0x30, 0x2c, 0x22, 0xd3, 0x32, 0xee, 0xbc, + 0xfb, 0xbf, 0x13, 0xee, 0xf3, 0x18, 0x48, 0x60, 0x95, 0x3a, 0xf8, 0xe8, 0x27, 0xfb, 0x39, 0xf6, + 0x24, 0x14, 0x55, 0x9c, 0xca, 0xa2, 0xdb, 0xb4, 0xfe, 0xa8, 0x00, 0x37, 0xb9, 0x32, 0x96, 0x4d, + 0x87, 0x37, 0x4e, 0x39, 0xc4, 0xe4, 0x3d, 0x18, 0x0c, 0x35, 0xef, 0x08, 0x4b, 0xb4, 0xbc, 0x1b, + 0x27, 0x4e, 0x40, 0xaa, 0x30, 0xae, 0xbf, 0x6d, 0x39, 0x5d, 0x08, 0x3c, 0x7b, 0xec, 0xe8, 0xb1, + 0xa3, 0xde, 0xbb, 0x3c, 0x81, 0x4b, 0xcb, 0xdf, 0xb0, 0x01, 0x21, 0x76, 0x27, 0x71, 0x72, 0x88, + 0x9f, 0xfb, 0x9e, 0xdb, 0x11, 0x23, 0xc6, 0x3c, 0xd6, 0x27, 0xc1, 0xec, 0x8c, 0x2c, 0x37, 0x38, + 0xa5, 0xbe, 0x8f, 0xda, 0x06, 0xcc, 0xfa, 0xd3, 0x02, 0x5c, 0xce, 0xae, 0x4d, 0x2c, 0x2c, 0x6b, + 0x70, 0x7e, 0xd1, 0xf1, 0x7c, 0xcf, 0x6d, 0x38, 0xad, 0x5a, 0xe3, 0x90, 0x36, 0x3b, 0x2a, 0x7e, + 0xad, 0x5a, 0x65, 0x0e, 0xa8, 0x27, 0xc9, 0x25, 0x8a, 0x9d, 0xa6, 0x62, 0xa7, 0x43, 0x7c, 0x1e, + 0xc1, 0xd7, 0xde, 0x16, 0x0d, 0x14, 0x3f, 0xde, 0xb2, 0x9c, 0x52, 0x72, 0x57, 0x5a, 0xfb, 0x9b, + 0xbb, 0x9e, 0x1b, 0x29, 0x22, 0x6e, 0xe6, 0xc9, 0x2a, 0xb2, 0xfe, 0x55, 0x01, 0x2e, 0x62, 0xca, + 0x2a, 0x23, 0x09, 0x66, 0x1c, 0xc6, 0x59, 0x46, 0x22, 0x2e, 0x18, 0xcf, 0x3d, 0x0c, 0x6c, 0x33, + 0x24, 0x31, 0x79, 0x13, 0x06, 0x6a, 0xd2, 0x5b, 0x6b, 0x32, 0x91, 0x61, 0x58, 0x50, 0xb0, 0x72, + 0x1b, 0xb1, 0xd8, 0x9e, 0xb3, 0x44, 0xc3, 0x06, 0xf5, 0x30, 0x15, 0x34, 0xb7, 0x3a, 0x68, 0x90, + 0x38, 0x1c, 0xd3, 0x40, 0x5e, 0x38, 0xa6, 0x41, 0x33, 0x1c, 0x93, 0xf5, 0x94, 0x27, 0xac, 0x4a, + 0x7e, 0x90, 0xe8, 0xa4, 0x8f, 0x53, 0x99, 0xa3, 0xf9, 0x3e, 0x70, 0x21, 0xeb, 0xcb, 0x98, 0x82, + 0x9e, 0x48, 0x0a, 0x9d, 0x1f, 0x36, 0x79, 0x1b, 0x5e, 0x31, 0x70, 0xab, 0xad, 0x96, 0xff, 0x8c, + 0x36, 0xb7, 0x03, 0xff, 0xc8, 0x8f, 0x8c, 0x84, 0x3d, 0x22, 0x75, 0x7a, 0x7c, 0x9f, 0x23, 0x46, + 0x65, 0x02, 0x6c, 0xfd, 0x4f, 0xf0, 0x6a, 0x0f, 0x8e, 0xe2, 0xa3, 0x6a, 0x70, 0xde, 0x49, 0x94, + 0x49, 0xb7, 0x9b, 0x57, 0xb3, 0xbe, 0x2b, 0xc9, 0x28, 0xb4, 0xd3, 0xf4, 0xb7, 0x76, 0x8c, 0x6c, + 0xcb, 0xa4, 0x0c, 0xd3, 0xdb, 0xf6, 0xd6, 0xd2, 0xee, 0xe2, 0x4e, 0x7d, 0xe7, 0x8b, 0xed, 0xe5, + 0xfa, 0xee, 0xe6, 0xc3, 0xcd, 0xad, 0x47, 0x9b, 0x3c, 0xee, 0xb8, 0x51, 0xb2, 0xb3, 0x5c, 0xdd, + 0x28, 0x15, 0xc8, 0x34, 0x94, 0x0c, 0xf0, 0xf2, 0xee, 0x42, 0xa9, 0x78, 0xeb, 0x6b, 0x23, 0x8b, + 0x30, 0xb9, 0x0c, 0xe5, 0xda, 0xee, 0xf6, 0xf6, 0x96, 0xad, 0xb8, 0xea, 0x51, 0xcf, 0x67, 0xe0, + 0xbc, 0x51, 0x7a, 0xdf, 0x5e, 0x5e, 0x2e, 0x15, 0x58, 0x53, 0x0c, 0xf0, 0xb6, 0xbd, 0xbc, 0xb1, + 0xb6, 0xbb, 0x51, 0x2a, 0xde, 0xaa, 0xeb, 0x6f, 0xcc, 0xc8, 0x25, 0x98, 0x5d, 0x5a, 0xde, 0x5b, + 0x5b, 0x5c, 0xce, 0xe2, 0x3d, 0x0d, 0x25, 0xbd, 0x70, 0x67, 0x6b, 0x67, 0x9b, 0xb3, 0xd6, 0xa1, + 0x8f, 0x96, 0x17, 0xaa, 0xbb, 0x3b, 0xab, 0x9b, 0xa5, 0x7e, 0x6b, 0x60, 0xa4, 0x58, 0x2a, 0xde, + 0xfa, 0xb1, 0xf1, 0x00, 0x8d, 0x35, 0x5f, 0xa0, 0xef, 0xd6, 0xaa, 0x2b, 0xf9, 0x55, 0xf0, 0xd2, + 0x8d, 0xfb, 0xd5, 0x52, 0x81, 0x5c, 0x81, 0x8b, 0x06, 0x74, 0xbb, 0x5a, 0xab, 0x3d, 0xda, 0xb2, + 0x97, 0xd6, 0x97, 0x6b, 0xb5, 0x52, 0xf1, 0xd6, 0x9e, 0x11, 0x82, 0x8e, 0xd5, 0xb0, 0x71, 0xbf, + 0x5a, 0xb7, 0x97, 0x3f, 0xdb, 0x5d, 0xb3, 0x97, 0x97, 0xd2, 0x35, 0x18, 0xa5, 0x5f, 0x2c, 0xd7, + 0x4a, 0x05, 0x32, 0x05, 0xe7, 0x0c, 0xe8, 0xe6, 0x56, 0xa9, 0x78, 0xeb, 0x35, 0x11, 0xa5, 0x8c, + 0x4c, 0x02, 0x2c, 0x2d, 0xd7, 0x16, 0x97, 0x37, 0x97, 0xd6, 0x36, 0x57, 0x4a, 0x7d, 0x64, 0x02, + 0x46, 0xab, 0xea, 0x67, 0xe1, 0xd6, 0x07, 0x70, 0x2e, 0x71, 0xb4, 0x67, 0x18, 0xea, 0x50, 0x5c, + 0xea, 0x43, 0xf1, 0xcb, 0x9f, 0x68, 0x5f, 0xe5, 0xa7, 0xf4, 0x52, 0xe1, 0xd6, 0x82, 0xcc, 0x6a, + 0xab, 0xcd, 0x73, 0x32, 0x06, 0xc3, 0x4b, 0xcb, 0xf7, 0xab, 0xbb, 0xeb, 0x3b, 0xa5, 0x3e, 0xf6, + 0x63, 0xd1, 0x5e, 0xae, 0xee, 0x2c, 0x2f, 0x95, 0x0a, 0x64, 0x14, 0x06, 0x6b, 0x3b, 0xd5, 0x9d, + 0xe5, 0x52, 0x91, 0x8c, 0xc0, 0xc0, 0x6e, 0x6d, 0xd9, 0x2e, 0xf5, 0xcf, 0xff, 0xd3, 0xff, 0xaf, + 0xc0, 0x8d, 0x8c, 0xf2, 0x31, 0xd3, 0xd7, 0xda, 0x61, 0x52, 0x2c, 0x79, 0x22, 0x85, 0x67, 0xee, + 0xc9, 0x11, 0xb5, 0x80, 0xb9, 0x2e, 0xb7, 0x2e, 0x88, 0x70, 0xb3, 0x70, 0xb7, 0x40, 0x6c, 0xf4, + 0x52, 0x49, 0x9c, 0xad, 0x14, 0xe7, 0xec, 0xe3, 0xef, 0xdc, 0x95, 0xae, 0x47, 0x32, 0xf2, 0x6b, + 0x60, 0xe9, 0x3c, 0x73, 0x4e, 0x20, 0xdf, 0x3f, 0xdd, 0x49, 0x43, 0xd6, 0xf9, 0xda, 0xe9, 0xd0, + 0xc9, 0x03, 0x98, 0x60, 0xba, 0xb9, 0x42, 0x23, 0x97, 0x92, 0x84, 0xda, 0x71, 0x60, 0xee, 0x72, + 0x76, 0xa1, 0xca, 0xb2, 0x33, 0x8e, 0x1f, 0xc2, 0x0f, 0xd6, 0x21, 0x91, 0x91, 0x2c, 0x24, 0x84, + 0xaf, 0xf8, 0x73, 0xe7, 0x13, 0xe0, 0xbd, 0x7b, 0x77, 0x0b, 0xa4, 0x86, 0x61, 0xe4, 0x0c, 0x25, + 0x9f, 0xc8, 0xd7, 0x75, 0x69, 0xed, 0x9f, 0xb7, 0xa6, 0xa2, 0x72, 0x62, 0xe6, 0x9c, 0x0e, 0x36, + 0x81, 0xa4, 0x75, 0x67, 0x72, 0x2d, 0x1e, 0x07, 0xd9, 0x6a, 0xf5, 0xdc, 0x85, 0x94, 0xf3, 0xe1, + 0x32, 0xd3, 0x9e, 0xc8, 0x32, 0x4c, 0x8a, 0x67, 0xea, 0x42, 0x9b, 0x27, 0xdd, 0xce, 0x03, 0xb9, + 0x6c, 0x56, 0x50, 0x4e, 0xea, 0x44, 0x40, 0xe6, 0xe2, 0xef, 0x48, 0x1e, 0x13, 0xe6, 0x2e, 0x65, + 0x96, 0x89, 0xef, 0xbb, 0x0f, 0x93, 0xe6, 0xe1, 0x82, 0xc8, 0x0e, 0xca, 0x3c, 0x73, 0xe4, 0x36, + 0xa8, 0x0e, 0xb3, 0x1b, 0x8e, 0x8b, 0x77, 0x25, 0xc2, 0xc5, 0x4d, 0x3a, 0xa8, 0x91, 0x4a, 0x17, + 0x8f, 0xb5, 0x1a, 0xf5, 0x9a, 0xaa, 0x13, 0xf2, 0x22, 0xe6, 0xe3, 0xb4, 0xa9, 0x49, 0x1d, 0xd9, + 0x74, 0xf0, 0x23, 0x96, 0x99, 0xe7, 0x38, 0xcb, 0x67, 0x73, 0x2e, 0xcf, 0xcd, 0x98, 0x6c, 0xa0, + 0x92, 0x9e, 0xe0, 0xa8, 0x8d, 0x89, 0x33, 0xb3, 0x2b, 0x63, 0xb0, 0x04, 0x2d, 0x3f, 0xbc, 0x28, + 0x0c, 0x49, 0x8e, 0xe0, 0x72, 0x99, 0xdd, 0x2d, 0x90, 0xaf, 0x71, 0x56, 0x67, 0xb2, 0x7b, 0xe4, + 0x46, 0x87, 0x42, 0xfb, 0xb9, 0x94, 0xc9, 0x40, 0x4c, 0x94, 0x2e, 0xdc, 0x6d, 0x98, 0xce, 0xf2, + 0x6c, 0x56, 0x02, 0xed, 0xe2, 0xf6, 0x9c, 0x3b, 0x0a, 0x6c, 0x76, 0xd4, 0x68, 0xe6, 0x77, 0x52, + 0x17, 0xc7, 0xda, 0x5c, 0x9e, 0x1f, 0xc1, 0x24, 0x1b, 0x25, 0x0f, 0x29, 0x6d, 0x57, 0x5b, 0xee, + 0x53, 0x1a, 0x12, 0x19, 0x03, 0x58, 0x81, 0xf2, 0x68, 0x6f, 0x16, 0xc8, 0xf7, 0x60, 0xec, 0x91, + 0x13, 0x35, 0x0e, 0x45, 0x2c, 0x4c, 0x19, 0x2a, 0x13, 0x61, 0x73, 0xf2, 0x17, 0x16, 0xde, 0x2d, + 0x90, 0x1f, 0xc2, 0xf0, 0x0a, 0x8d, 0xf0, 0x75, 0xf3, 0x75, 0xe5, 0xe4, 0xc7, 0x6d, 0x93, 0x6b, + 0x9e, 0x7a, 0xc2, 0x23, 0x1b, 0x9c, 0x34, 0xe4, 0x92, 0x3b, 0x00, 0x7c, 0x41, 0x40, 0x0e, 0xc9, + 0xe2, 0xb9, 0x54, 0xb3, 0xc9, 0x0a, 0x53, 0x1e, 0x5a, 0x34, 0xa2, 0xa7, 0xad, 0x32, 0x4f, 0x46, + 0xeb, 0x30, 0xa9, 0x12, 0x13, 0x6d, 0x62, 0xc8, 0x12, 0x2b, 0xc1, 0x2c, 0x3c, 0x03, 0xb7, 0x0f, + 0xd8, 0xac, 0xe0, 0x59, 0x79, 0x31, 0xb6, 0x05, 0xae, 0xa4, 0xb3, 0x7a, 0x80, 0x0c, 0x7d, 0x09, + 0x95, 0x42, 0xe4, 0x68, 0x1a, 0xed, 0xaa, 0x1f, 0x46, 0x26, 0xad, 0x82, 0x64, 0xd3, 0xfe, 0x2a, + 0xcc, 0xe9, 0xf5, 0x9a, 0xc1, 0x98, 0xe3, 0x35, 0x37, 0x2f, 0xc6, 0xf3, 0xdc, 0xf5, 0x2e, 0x18, + 0xe2, 0xfc, 0xd6, 0xff, 0x3b, 0xc5, 0x02, 0x2e, 0x27, 0x4b, 0x30, 0x25, 0xeb, 0xda, 0x6a, 0x53, + 0xaf, 0x56, 0x5b, 0xc5, 0x24, 0x34, 0xd2, 0xa5, 0x44, 0x83, 0x49, 0xee, 0x24, 0x5d, 0xc4, 0xb6, + 0x3e, 0x23, 0x86, 0x05, 0xe9, 0x16, 0xd9, 0x22, 0xde, 0xfa, 0x32, 0xa3, 0x04, 0x3f, 0xe4, 0x46, + 0x25, 0x43, 0xf9, 0xdf, 0x9b, 0x27, 0x5d, 0x0e, 0x40, 0x73, 0x39, 0x47, 0x88, 0xbb, 0x05, 0xf2, + 0x05, 0x90, 0xf4, 0x91, 0x44, 0x89, 0x30, 0xf7, 0xf8, 0xa5, 0x44, 0xd8, 0xe5, 0x3c, 0xb3, 0x02, + 0x33, 0x2a, 0x82, 0x8d, 0x56, 0xeb, 0x3c, 0xc9, 0x69, 0x4d, 0x5e, 0x2b, 0xc9, 0x27, 0x30, 0x25, + 0x06, 0xad, 0x5e, 0x40, 0x4a, 0x6a, 0xfd, 0x11, 0xa7, 0x92, 0xdc, 0x71, 0xfa, 0x00, 0x66, 0x6a, + 0x09, 0x89, 0x71, 0x4f, 0xf8, 0x8b, 0x26, 0x0b, 0x04, 0xd6, 0x68, 0xc4, 0x45, 0x96, 0xcd, 0xeb, + 0x21, 0x10, 0x6e, 0x14, 0x92, 0xec, 0x9e, 0xba, 0xf4, 0x19, 0xb9, 0x92, 0x68, 0x3a, 0x03, 0x22, + 0x1a, 0x2e, 0x60, 0xb9, 0x5f, 0xb6, 0xc3, 0x73, 0x4a, 0x23, 0xd4, 0xb8, 0x43, 0xbf, 0x66, 0x10, + 0x18, 0xd7, 0xf0, 0xa2, 0x03, 0x2e, 0xe6, 0x62, 0x90, 0xdf, 0xc0, 0xd0, 0xb1, 0xdd, 0x8f, 0x55, + 0xe4, 0x7b, 0x59, 0xa7, 0xdf, 0x9c, 0x83, 0xe1, 0xdc, 0x9b, 0xa7, 0x43, 0x56, 0x07, 0xd9, 0x89, + 0x15, 0x1a, 0x6d, 0xb7, 0x3a, 0x07, 0x2e, 0x66, 0x1b, 0x25, 0xca, 0x68, 0xa4, 0x40, 0x62, 0x5c, + 0xca, 0x88, 0x6d, 0x71, 0x41, 0x8d, 0xfe, 0x84, 0xac, 0x41, 0x89, 0xaf, 0xff, 0x1a, 0x8b, 0x2b, + 0x29, 0x16, 0x02, 0xc5, 0x09, 0x9c, 0xa3, 0x30, 0xb7, 0xb7, 0xee, 0x70, 0xa7, 0x25, 0x22, 0xe7, + 0xa4, 0xae, 0x60, 0x4e, 0x19, 0x30, 0x15, 0x4e, 0x9f, 0xf5, 0x88, 0x4d, 0x43, 0x1a, 0xc9, 0x18, + 0x35, 0x3c, 0xd7, 0xec, 0x8d, 0x78, 0xb3, 0x4f, 0x97, 0xc6, 0x53, 0x3f, 0x11, 0x4f, 0x6d, 0xef, + 0x2d, 0xa2, 0xf2, 0xef, 0x66, 0x30, 0x7d, 0xcd, 0xd0, 0x49, 0xce, 0xc6, 0xf7, 0x6d, 0xdc, 0x83, + 0x30, 0x2e, 0xcf, 0x4c, 0xdc, 0x36, 0xf6, 0x5b, 0x52, 0x4d, 0x68, 0x54, 0x7b, 0xf3, 0xb8, 0xa4, + 0xb1, 0x4d, 0x92, 0xa9, 0xb0, 0x9d, 0x20, 0xa0, 0x1e, 0x27, 0xce, 0xd3, 0x37, 0xb2, 0xa8, 0x3f, + 0xc6, 0xa5, 0x47, 0xa3, 0xe6, 0x0f, 0xf6, 0x7a, 0xb1, 0xe0, 0xb9, 0x91, 0xee, 0x16, 0xc8, 0x7b, + 0x30, 0x22, 0xda, 0xc8, 0x88, 0x8c, 0x46, 0x87, 0x5d, 0x5a, 0x8d, 0x94, 0xc0, 0x85, 0x84, 0x6d, + 0x36, 0x71, 0xf2, 0x7a, 0x9f, 0xb7, 0xf9, 0x3d, 0xb6, 0xd9, 0x36, 0x5f, 0x84, 0x72, 0x51, 0xee, + 0xba, 0x48, 0x59, 0x56, 0xb1, 0x5c, 0x24, 0xa8, 0xc7, 0xf6, 0xc8, 0x99, 0x30, 0xbd, 0x19, 0x03, + 0x22, 0xaa, 0xb8, 0x66, 0x4a, 0x6f, 0x36, 0xc0, 0xbd, 0xf6, 0xda, 0x35, 0x28, 0x55, 0x1b, 0xb8, + 0x13, 0xd4, 0xe8, 0x91, 0xd3, 0x3e, 0xf4, 0x03, 0xaa, 0x0e, 0x2d, 0xc9, 0x02, 0xc9, 0x6b, 0x46, + 0x69, 0x16, 0xa2, 0x60, 0x9d, 0x3a, 0x18, 0x35, 0x7a, 0x56, 0xa9, 0x16, 0x89, 0xa2, 0x6c, 0x8a, + 0x2e, 0x87, 0x94, 0xe9, 0x45, 0x76, 0xac, 0x6a, 0x7d, 0x3b, 0x36, 0x1f, 0xe0, 0x82, 0xa1, 0x90, + 0x43, 0xb5, 0x43, 0x28, 0x90, 0x3a, 0xce, 0xc9, 0xb7, 0x3b, 0x0a, 0xb5, 0x2a, 0xef, 0x8c, 0x63, + 0xb1, 0xe4, 0x51, 0xe7, 0x55, 0xff, 0x03, 0x98, 0x5c, 0x66, 0x0b, 0x7a, 0xa7, 0xe9, 0xf2, 0x48, + 0xf9, 0xc4, 0x0c, 0x7d, 0x9e, 0x4b, 0xb8, 0x2a, 0xd3, 0x91, 0x21, 0xa9, 0x38, 0xfa, 0xcb, 0x3d, + 0x45, 0x83, 0xc9, 0xfe, 0x98, 0x96, 0x6c, 0x45, 0xb2, 0x02, 0x3c, 0x9a, 0x8b, 0xb3, 0xfe, 0x2c, + 0xd7, 0x08, 0xab, 0xed, 0x76, 0x4b, 0x9a, 0xa4, 0xf9, 0xbd, 0xfb, 0xab, 0xc6, 0x11, 0x32, 0x55, + 0x2e, 0x79, 0xa7, 0x95, 0xc6, 0xcf, 0xb5, 0xf4, 0xc0, 0x39, 0x3c, 0x73, 0xca, 0x7b, 0x8d, 0x45, + 0x15, 0xdb, 0xba, 0xda, 0x6a, 0xa5, 0x88, 0x43, 0xf2, 0x86, 0xc9, 0x3d, 0x0b, 0xa7, 0x57, 0x0d, + 0x78, 0x44, 0xe7, 0x5a, 0x57, 0xb5, 0xdd, 0xe6, 0x8b, 0xe5, 0x55, 0xb5, 0x60, 0x98, 0x05, 0xe9, + 0x23, 0x7a, 0xb2, 0x5c, 0xac, 0xed, 0x0f, 0x70, 0x98, 0xc5, 0x39, 0x84, 0x89, 0x7e, 0xe0, 0x4d, + 0xa6, 0x50, 0x56, 0x4a, 0x58, 0xa2, 0x50, 0xed, 0x13, 0xe7, 0x50, 0xf5, 0x89, 0x13, 0x12, 0x2b, + 0xcb, 0x4c, 0x02, 0x2e, 0xf9, 0x5d, 0xcd, 0x2b, 0x56, 0x96, 0xd2, 0x52, 0x32, 0x4f, 0xbb, 0xfa, + 0xe4, 0x9c, 0xfc, 0xff, 0xea, 0x93, 0x73, 0x13, 0xbc, 0x3f, 0x80, 0x52, 0x32, 0x45, 0xb4, 0x62, + 0x9a, 0x93, 0x3b, 0x3a, 0xb7, 0x4f, 0xee, 0xc3, 0xb4, 0xde, 0xa3, 0xea, 0xbb, 0xf3, 0x56, 0xff, + 0x3c, 0x3e, 0x3b, 0x30, 0x93, 0x99, 0xd1, 0x59, 0x6d, 0xb1, 0xdd, 0xf2, 0x3d, 0xe7, 0x72, 0xa5, + 0x70, 0x21, 0x3b, 0xa9, 0x3b, 0x79, 0xc5, 0x3c, 0xf8, 0x67, 0xa7, 0xb8, 0x9e, 0x7b, 0xb5, 0x07, + 0x96, 0x10, 0xe8, 0xd7, 0xb8, 0x03, 0xa6, 0xea, 0xb8, 0xae, 0x99, 0x02, 0x72, 0x2a, 0xb0, 0xba, + 0xa1, 0xa8, 0x31, 0x30, 0x9d, 0x51, 0x9c, 0x2f, 0xe2, 0x1b, 0xf9, 0x3c, 0xe3, 0x81, 0xb5, 0x27, + 0x43, 0x38, 0xe7, 0x4a, 0xa6, 0x6b, 0xf2, 0xef, 0x2e, 0x67, 0xc9, 0x39, 0x35, 0x1e, 0x4e, 0xdf, + 0xe4, 0x3c, 0x6e, 0x4d, 0x65, 0xb6, 0x31, 0x32, 0x73, 0x27, 0xcd, 0x36, 0x59, 0x19, 0xc5, 0x95, + 0x18, 0xba, 0xe5, 0xac, 0xe7, 0xbb, 0xf1, 0x57, 0xdc, 0x8e, 0x63, 0x56, 0xa1, 0xdb, 0x71, 0x32, + 0xf9, 0x5f, 0xcb, 0x47, 0xd0, 0x99, 0x3b, 0xfc, 0xd2, 0x36, 0x91, 0x5a, 0x9c, 0xe8, 0x47, 0xa5, + 0xec, 0xb4, 0xe3, 0x6a, 0x6c, 0x64, 0xa2, 0xe8, 0x55, 0x3c, 0x92, 0x73, 0x30, 0x47, 0x4a, 0x5d, + 0xf2, 0xae, 0x77, 0x57, 0x53, 0xb6, 0xa0, 0x1c, 0x77, 0x66, 0xe2, 0x03, 0xce, 0xd8, 0x95, 0x52, + 0x18, 0x17, 0x73, 0xb3, 0xad, 0x93, 0xd7, 0x53, 0x33, 0x3d, 0x47, 0x30, 0x5d, 0xab, 0xe0, 0xeb, + 0xb9, 0x16, 0x12, 0xfa, 0x52, 0x6c, 0xc4, 0xd5, 0x13, 0xb3, 0xa7, 0xd6, 0xf3, 0x8c, 0xac, 0xed, + 0x2b, 0xa8, 0x17, 0x6b, 0x99, 0xd7, 0x73, 0xbf, 0xfa, 0x4a, 0x16, 0x9f, 0x30, 0xbd, 0xe2, 0x6a, + 0xed, 0x92, 0x7a, 0x5a, 0xb2, 0xe0, 0x2c, 0x2b, 0xee, 0x69, 0x9a, 0x96, 0xc7, 0x67, 0x09, 0xc6, + 0xb4, 0x94, 0xed, 0xe4, 0xa2, 0x21, 0x26, 0x63, 0x0f, 0x9d, 0x33, 0x3e, 0xce, 0xdc, 0x3e, 0x17, + 0xd1, 0x94, 0xac, 0x12, 0xbf, 0xe7, 0xb6, 0xe2, 0x52, 0x9a, 0x87, 0x61, 0x46, 0x56, 0x52, 0xe0, + 0xad, 0xb9, 0x9c, 0x14, 0x8e, 0xd1, 0xa0, 0xfc, 0x4f, 0x22, 0xba, 0x68, 0x7a, 0x34, 0x29, 0x5f, + 0x7f, 0x9d, 0x12, 0x79, 0x61, 0x31, 0x8f, 0x8b, 0x8c, 0xf9, 0x77, 0x41, 0xd9, 0xc4, 0x34, 0x28, + 0x1a, 0x28, 0xb2, 0xd9, 0x6c, 0xe3, 0xd3, 0x91, 0x8c, 0x1c, 0xf6, 0x6a, 0x85, 0xed, 0x9a, 0xe2, + 0x3e, 0x43, 0x77, 0x53, 0x6b, 0x76, 0x2e, 0xc7, 0xae, 0x49, 0xed, 0x73, 0x5b, 0xfa, 0x23, 0x6d, + 0xcd, 0x4e, 0x65, 0xaa, 0x27, 0x37, 0x93, 0x8a, 0x5b, 0x5e, 0x32, 0xfb, 0x2e, 0x7b, 0xc2, 0x74, + 0x56, 0x92, 0x7b, 0xcd, 0xae, 0x9b, 0x9b, 0x01, 0x3f, 0x43, 0x0a, 0xb6, 0x1c, 0xff, 0x39, 0xdc, + 0xba, 0xa4, 0xbc, 0xcf, 0x6d, 0xe1, 0x97, 0xda, 0x42, 0x97, 0x48, 0x4d, 0xaf, 0x8e, 0xe3, 0x3d, + 0x72, 0xd7, 0xe7, 0xf2, 0xde, 0xc4, 0xc7, 0x46, 0xe9, 0xbc, 0xf2, 0x4a, 0xb3, 0xe9, 0x96, 0x75, + 0x3e, 0xd3, 0xec, 0x3b, 0x93, 0xfe, 0x44, 0xc6, 0xef, 0x42, 0xc2, 0x68, 0xdb, 0xab, 0x61, 0x5f, + 0xcb, 0xc5, 0x38, 0x23, 0x1f, 0x7d, 0x62, 0x31, 0xce, 0xcf, 0x58, 0xdf, 0xe5, 0x18, 0x74, 0xae, + 0xe6, 0x1e, 0x78, 0x5a, 0x3a, 0x79, 0x75, 0x08, 0x4a, 0x67, 0xb8, 0x57, 0x4b, 0x4c, 0x56, 0xf6, + 0xf9, 0x2d, 0xa6, 0xff, 0x70, 0xed, 0x5d, 0x4f, 0x0c, 0x4e, 0xe6, 0xf2, 0xf3, 0xa1, 0xab, 0xe5, + 0x26, 0x33, 0x93, 0xb8, 0xc6, 0x50, 0xcf, 0xca, 0xad, 0x18, 0x66, 0x24, 0x08, 0x57, 0x0c, 0x33, + 0xd3, 0x78, 0xdf, 0x41, 0xab, 0x8b, 0xed, 0xb7, 0xa8, 0x6e, 0x75, 0xd1, 0xd2, 0x3c, 0x27, 0x8c, + 0x1e, 0xe4, 0x63, 0x18, 0x55, 0x69, 0xb0, 0x95, 0x7d, 0x3b, 0x99, 0x89, 0x7b, 0xae, 0x9c, 0x2e, + 0x10, 0x15, 0xbe, 0x23, 0x0d, 0x1f, 0x58, 0x67, 0xd9, 0x34, 0x18, 0xe5, 0x57, 0xfb, 0x8e, 0xb4, + 0x7a, 0x18, 0x64, 0xa9, 0x24, 0xd8, 0x49, 0xb2, 0x1f, 0xc0, 0x78, 0x9c, 0xf0, 0x7a, 0x6f, 0x5e, + 0x23, 0x4c, 0x64, 0xc1, 0x4e, 0x12, 0xbe, 0x27, 0xaf, 0x34, 0xb0, 0x3e, 0xb3, 0xb0, 0xfb, 0x2e, + 0xfe, 0xb1, 0xb4, 0xb2, 0x18, 0x2d, 0x4d, 0xa5, 0xcf, 0xee, 0xb2, 0xf8, 0x8e, 0xeb, 0xe9, 0x2a, + 0x55, 0xd7, 0x66, 0x24, 0x9c, 0x55, 0x5d, 0x9b, 0x95, 0x30, 0x36, 0x36, 0xf9, 0x7f, 0x21, 0x4d, + 0x0a, 0x31, 0xd3, 0x2b, 0x46, 0xb3, 0x52, 0x7c, 0xaf, 0xe6, 0x15, 0x27, 0x59, 0xd7, 0xa0, 0x94, + 0xcc, 0xad, 0xa9, 0xce, 0x63, 0x39, 0x49, 0x50, 0xd5, 0x21, 0x2f, 0x37, 0x29, 0xe7, 0xb6, 0xb4, + 0x8f, 0x9b, 0x7c, 0xaf, 0x67, 0x37, 0x4a, 0x67, 0x9d, 0x6f, 0x30, 0x9f, 0x30, 0xd2, 0x6c, 0xea, + 0x27, 0xe5, 0x54, 0x1a, 0x4f, 0x5d, 0xb3, 0xca, 0xc8, 0xcc, 0xe9, 0xca, 0x88, 0x4f, 0xd9, 0x49, + 0xce, 0xdf, 0x30, 0x8f, 0xb0, 0x5d, 0x62, 0xb2, 0xf7, 0xbc, 0xfe, 0x25, 0xbf, 0x02, 0xb3, 0x39, + 0x31, 0xa6, 0xc9, 0xab, 0x09, 0x4b, 0x6b, 0x76, 0x0c, 0x6a, 0x35, 0x40, 0x32, 0xf3, 0x5f, 0x6f, + 0xa0, 0xdf, 0x80, 0x11, 0xdb, 0x21, 0x75, 0x17, 0xf7, 0xc8, 0x8d, 0x0e, 0x79, 0x9a, 0x67, 0x6d, + 0xd9, 0xcc, 0x0c, 0x0a, 0x41, 0x6a, 0x78, 0x16, 0x31, 0xa0, 0x19, 0xd7, 0x71, 0x19, 0x0c, 0xe7, + 0xb2, 0x19, 0xb2, 0xb5, 0x83, 0x8d, 0x85, 0x8c, 0xc0, 0x1b, 0x6a, 0x2c, 0xe4, 0x07, 0xe5, 0xc8, + 0x6d, 0xe6, 0xb6, 0xd4, 0x91, 0xb2, 0x39, 0xe6, 0xc7, 0xe0, 0xc8, 0xe5, 0xf8, 0x80, 0x71, 0x4c, + 0x85, 0xd5, 0x20, 0x39, 0xe8, 0xdd, 0x57, 0x0f, 0x5b, 0x6e, 0xb9, 0x26, 0xd5, 0xbc, 0xd6, 0xbe, + 0xbc, 0x00, 0x1e, 0xb9, 0xed, 0x5b, 0x96, 0xf3, 0x29, 0xbb, 0x7d, 0xa7, 0xdd, 0x74, 0xd5, 0xfd, + 0x57, 0x22, 0xb2, 0x8b, 0xf1, 0xa1, 0x1a, 0x7c, 0x2e, 0x07, 0x4e, 0x36, 0xd1, 0x11, 0x28, 0x09, + 0xd5, 0x0e, 0xa5, 0xd9, 0xa1, 0x63, 0x72, 0xf9, 0xf1, 0x71, 0x6c, 0x84, 0xde, 0x38, 0xcb, 0x38, + 0x4e, 0xc4, 0xec, 0x10, 0xe3, 0xd8, 0x80, 0x9e, 0x6d, 0x1c, 0x27, 0x18, 0x9a, 0xe3, 0x38, 0xd9, + 0xcc, 0xe4, 0x49, 0x3f, 0xb7, 0x57, 0x93, 0xcd, 0x54, 0xe3, 0x38, 0x9b, 0x63, 0x7e, 0x88, 0x94, + 0x5c, 0x8e, 0x6a, 0x1c, 0x9b, 0x1c, 0x73, 0xd0, 0x4f, 0x39, 0x8e, 0x93, 0x95, 0x98, 0xe3, 0xf8, + 0x4c, 0xed, 0x53, 0xe3, 0x38, 0xbb, 0x7d, 0x67, 0x1e, 0xc7, 0x89, 0x98, 0x42, 0xc6, 0x87, 0x66, + 0x8d, 0xe3, 0x24, 0x3e, 0x1f, 0xc7, 0x49, 0x68, 0xc2, 0xb8, 0xd2, 0x65, 0x1c, 0x27, 0x29, 0x3f, + 0x43, 0x7e, 0x89, 0x78, 0x28, 0xa7, 0x19, 0xc9, 0xb9, 0xa1, 0x54, 0xc8, 0x23, 0x34, 0xef, 0x25, + 0xe0, 0xa7, 0x1b, 0xcd, 0x97, 0xf3, 0x98, 0xe2, 0x78, 0xde, 0x93, 0x42, 0x4c, 0x36, 0xd7, 0xb4, + 0x5d, 0x65, 0x87, 0x83, 0xe9, 0xd2, 0xe0, 0x3d, 0x36, 0x6e, 0x9a, 0x5d, 0xf8, 0x76, 0x8b, 0x66, + 0xd3, 0x85, 0xaf, 0x3a, 0xca, 0x24, 0xf9, 0xe6, 0x92, 0x74, 0x1f, 0xdf, 0x9f, 0xcb, 0x0b, 0x8e, + 0x24, 0xdd, 0x7c, 0xe2, 0x70, 0x74, 0xe6, 0x96, 0xaa, 0x43, 0x52, 0xb2, 0xa5, 0x67, 0x1d, 0xe7, + 0x1b, 0x52, 0x7b, 0x48, 0x85, 0xc1, 0x4a, 0x7c, 0xb4, 0x3e, 0xd6, 0x73, 0x4b, 0xc8, 0x0e, 0xda, + 0x72, 0xd3, 0x70, 0xcd, 0x0e, 0x9c, 0x17, 0x6f, 0xab, 0x27, 0xd7, 0x54, 0x40, 0x1f, 0x9d, 0x6b, + 0x5e, 0xb4, 0x1f, 0xc5, 0x35, 0x4d, 0xfd, 0x09, 0x5a, 0xbf, 0xc4, 0x6b, 0x2b, 0xef, 0xb1, 0x9f, + 0x6f, 0x49, 0x99, 0x32, 0x9c, 0x95, 0x18, 0x2e, 0xfa, 0x88, 0x7d, 0x24, 0x6e, 0xf0, 0x24, 0x30, + 0x57, 0xf8, 0x59, 0xf4, 0xe4, 0x13, 0x28, 0x89, 0xe5, 0x2d, 0x66, 0x90, 0x85, 0x98, 0xdb, 0x75, + 0x0b, 0xd2, 0xe8, 0x76, 0x8a, 0x16, 0x9c, 0xc6, 0xd8, 0x76, 0x1a, 0x49, 0xe4, 0x5b, 0xa6, 0xd8, + 0x76, 0xb8, 0x13, 0x74, 0xc2, 0x88, 0x36, 0xd3, 0x16, 0x25, 0xb3, 0x31, 0xd2, 0x33, 0xc2, 0x44, + 0xdf, 0x9b, 0x27, 0x6b, 0xb8, 0xb6, 0x99, 0xe0, 0x6e, 0x26, 0xb7, 0x6c, 0x36, 0xb8, 0xf4, 0xac, + 0xaa, 0x67, 0x3d, 0x66, 0x9b, 0xf2, 0xea, 0xce, 0x6f, 0x94, 0x12, 0xd1, 0x29, 0xbf, 0x2e, 0x4f, + 0x44, 0x1f, 0xa2, 0x1b, 0x00, 0x37, 0xff, 0xf5, 0x92, 0x4c, 0xf2, 0xa1, 0x11, 0xf9, 0x14, 0x46, + 0x25, 0x71, 0x6f, 0x81, 0x24, 0xa9, 0x51, 0x20, 0x4b, 0x30, 0x61, 0xbc, 0xa2, 0x52, 0xa7, 0x9b, + 0xac, 0xb7, 0x55, 0x5d, 0xfa, 0x79, 0xc2, 0x78, 0x2d, 0xa5, 0xb8, 0x64, 0xbd, 0xa1, 0xca, 0xe5, + 0xf2, 0x43, 0x18, 0x13, 0x22, 0xed, 0x2a, 0x8d, 0x7c, 0x7b, 0xdb, 0x8c, 0xe6, 0x91, 0xdc, 0x69, + 0xba, 0xd1, 0xa2, 0xef, 0x3d, 0x76, 0x0f, 0x7a, 0x0a, 0x26, 0x4d, 0xb2, 0x37, 0x4f, 0xbe, 0xc2, + 0xa4, 0xc8, 0x32, 0x55, 0x35, 0x8d, 0x9e, 0xf9, 0xc1, 0x13, 0xd7, 0x3b, 0xe8, 0xc1, 0xf2, 0x9a, + 0xc9, 0x32, 0x49, 0x27, 0x7d, 0x47, 0xbe, 0x82, 0xb9, 0x5a, 0x3e, 0xf3, 0x9e, 0x4c, 0xba, 0x6f, + 0x2f, 0x35, 0xb8, 0x8c, 0xde, 0x33, 0x67, 0x6d, 0x7b, 0x57, 0xa6, 0x5f, 0xf0, 0x48, 0x8a, 0xd2, + 0x56, 0xdf, 0xf0, 0x83, 0x66, 0x6f, 0x8e, 0x15, 0xd3, 0x91, 0x36, 0x41, 0x26, 0x85, 0xf1, 0x05, + 0x5c, 0xac, 0xe5, 0xb2, 0xee, 0xc5, 0xa2, 0x97, 0x26, 0x79, 0x09, 0x45, 0x71, 0xc6, 0x76, 0x77, + 0xe5, 0xb9, 0x86, 0x6b, 0x1a, 0xdb, 0x87, 0xb6, 0x03, 0xfa, 0x98, 0x06, 0xe8, 0xae, 0xdd, 0xcb, + 0x51, 0xd9, 0x44, 0x97, 0x5f, 0xbe, 0x06, 0xe7, 0x6b, 0x29, 0x56, 0x79, 0x24, 0xbd, 0xee, 0x7f, + 0xa6, 0xf0, 0x4b, 0x4f, 0xd9, 0xae, 0x1e, 0x5e, 0x42, 0x63, 0x2b, 0x34, 0xda, 0x5d, 0xeb, 0x21, + 0x25, 0xf9, 0x9e, 0x40, 0x22, 0xee, 0xdd, 0x63, 0x94, 0x35, 0x8d, 0x32, 0x8d, 0x91, 0x3b, 0x79, + 0x3f, 0x95, 0x77, 0x21, 0x3d, 0xab, 0xcd, 0xe3, 0xf0, 0x16, 0xae, 0x85, 0xc2, 0x65, 0x79, 0x36, + 0x56, 0x01, 0x38, 0x24, 0x36, 0xd5, 0x69, 0xde, 0xcb, 0x21, 0xa9, 0xf2, 0xe3, 0x1f, 0x1f, 0x1e, + 0x02, 0x76, 0x35, 0xe5, 0xca, 0xde, 0x95, 0x05, 0xb7, 0x82, 0xae, 0xfb, 0x8d, 0x27, 0xba, 0x15, + 0x54, 0x4b, 0x9b, 0x3f, 0x67, 0x26, 0xb5, 0x17, 0x2b, 0x3e, 0x66, 0xb6, 0xd7, 0x1d, 0xbf, 0xf4, + 0xc4, 0xf9, 0x73, 0xb3, 0x29, 0xb8, 0xb0, 0x20, 0xbd, 0x25, 0x6d, 0x8b, 0x58, 0xa1, 0xc9, 0x39, + 0x57, 0x34, 0xca, 0xac, 0x88, 0x44, 0xa6, 0x59, 0x51, 0x6f, 0x68, 0xbe, 0x2d, 0x9f, 0xa4, 0x73, + 0xfc, 0xab, 0xc3, 0x4a, 0x6e, 0xfa, 0xff, 0x2e, 0xfe, 0x5b, 0x53, 0xc2, 0xeb, 0xc7, 0x10, 0xbc, + 0x8a, 0x46, 0x9c, 0x2e, 0x8b, 0x45, 0xa9, 0x3b, 0x23, 0xdd, 0x2d, 0x90, 0x4d, 0xb8, 0xb0, 0x42, + 0x23, 0xb1, 0xc6, 0xd9, 0x34, 0x8c, 0x02, 0xb7, 0x11, 0x75, 0xbd, 0x18, 0x94, 0x67, 0x93, 0x0c, + 0x9a, 0xbd, 0xb7, 0x19, 0xbf, 0x5a, 0x36, 0xbf, 0xae, 0x74, 0x5d, 0x5c, 0x64, 0xc5, 0x6d, 0xc3, + 0x59, 0x9a, 0x98, 0x3f, 0xc4, 0x87, 0xb9, 0x07, 0x4e, 0x3e, 0x69, 0x29, 0x8e, 0x7c, 0x22, 0x4e, + 0x5b, 0xb7, 0x61, 0x88, 0x13, 0xe5, 0x6e, 0xa8, 0xe3, 0x3a, 0x0d, 0xb9, 0x07, 0xa3, 0xca, 0x85, + 0x86, 0x18, 0x45, 0xb9, 0xed, 0xba, 0x07, 0xa3, 0xfc, 0x68, 0x75, 0x7a, 0x92, 0x0f, 0x61, 0x54, + 0xf9, 0xdc, 0x9c, 0x79, 0xa7, 0xff, 0x04, 0x26, 0x74, 0xef, 0x9b, 0xb3, 0x0b, 0xf2, 0x87, 0x78, + 0x7d, 0x2b, 0x6f, 0x49, 0xf2, 0xe9, 0x67, 0x12, 0x01, 0x61, 0x84, 0x48, 0xf9, 0x02, 0x29, 0x81, + 0xb9, 0xcd, 0x3f, 0x9f, 0xa2, 0x26, 0x1f, 0xca, 0x97, 0x4c, 0x8a, 0x38, 0x8d, 0xd4, 0x45, 0x66, + 0x93, 0x5c, 0xcc, 0x2f, 0x42, 0xac, 0x16, 0xd8, 0x9e, 0xcd, 0x3e, 0xcd, 0x35, 0x73, 0x6f, 0xd1, + 0xe5, 0x71, 0xd9, 0x42, 0x2d, 0x2d, 0x95, 0x88, 0x2e, 0x9f, 0xd1, 0xd5, 0xfc, 0xdc, 0x75, 0xd8, + 0x19, 0x0f, 0xf0, 0x14, 0x98, 0x2a, 0xcd, 0xfd, 0xbc, 0x2e, 0xb9, 0xf0, 0xe2, 0x63, 0x6f, 0x9a, + 0x5d, 0x17, 0xb2, 0x6e, 0xa7, 0x68, 0xf1, 0x3e, 0xf3, 0xa5, 0xb0, 0x5b, 0x93, 0x4e, 0x8c, 0xa7, + 0xff, 0xd8, 0xfc, 0x96, 0x5d, 0xca, 0xb8, 0xd8, 0xee, 0xd9, 0x17, 0x79, 0xec, 0x7e, 0x05, 0xb5, + 0xc3, 0xcc, 0x88, 0x60, 0xf9, 0xcc, 0x6e, 0x6a, 0xbe, 0x11, 0x99, 0x94, 0x6a, 0xd3, 0x7b, 0x82, + 0x4f, 0xc4, 0xb2, 0x53, 0xf5, 0xbd, 0xd6, 0x83, 0x8b, 0x94, 0xc4, 0xeb, 0x3d, 0xf1, 0xd4, 0x35, + 0xe9, 0x25, 0xbe, 0xc3, 0x66, 0xd7, 0xd7, 0x23, 0xf5, 0x60, 0xc6, 0xcd, 0xb5, 0xf2, 0x10, 0xcd, + 0x66, 0x68, 0x7a, 0x88, 0x76, 0xfd, 0x86, 0x3c, 0xf1, 0x7f, 0x06, 0x95, 0xd8, 0x01, 0xe4, 0x6c, + 0x9d, 0x90, 0xef, 0x98, 0x48, 0x52, 0x92, 0x0a, 0x49, 0xb7, 0x5c, 0x3c, 0x73, 0xd7, 0xf3, 0x24, + 0xac, 0x3f, 0x83, 0x11, 0x8e, 0x6d, 0x89, 0xa4, 0x95, 0x79, 0xe9, 0x2f, 0xbb, 0xd8, 0x61, 0xc5, + 0x9b, 0xb9, 0x97, 0xc2, 0x28, 0xdd, 0xdb, 0x67, 0x67, 0xa4, 0xfc, 0x33, 0x12, 0x8c, 0xac, 0x2e, + 0xdd, 0xdb, 0xfb, 0xea, 0xb1, 0x9c, 0xd3, 0xaf, 0x67, 0xef, 0x50, 0x27, 0x7e, 0x27, 0x96, 0x08, + 0x20, 0xa8, 0xbf, 0xcd, 0x4d, 0x17, 0x25, 0x1f, 0x39, 0x65, 0x61, 0x28, 0xa7, 0xa8, 0xb2, 0xac, + 0x82, 0xc1, 0xd9, 0x51, 0xc4, 0x0f, 0xdc, 0xe8, 0xf9, 0xa2, 0xbd, 0x1e, 0x9b, 0x15, 0xf4, 0x02, + 0xc9, 0x1b, 0x64, 0xa1, 0xbd, 0x4e, 0xbe, 0xc4, 0xa5, 0x44, 0xb0, 0x5f, 0xf0, 0xfd, 0x28, 0x8c, + 0x02, 0xa7, 0x5d, 0x6b, 0x04, 0x6e, 0x3b, 0xca, 0xfd, 0xe8, 0xd8, 0x87, 0x3b, 0x8b, 0x4c, 0x73, + 0x29, 0x15, 0x01, 0xe6, 0xb3, 0x22, 0xdf, 0xa8, 0x67, 0x35, 0x59, 0x85, 0x5d, 0x4e, 0x2e, 0x35, + 0x19, 0x52, 0xfe, 0x65, 0x32, 0xad, 0xc3, 0x6c, 0x4e, 0xbc, 0x20, 0x75, 0x7b, 0xdb, 0x3d, 0x9e, + 0xd0, 0x5c, 0xf7, 0x8a, 0xc9, 0x57, 0x30, 0x93, 0x19, 0x50, 0x48, 0x59, 0xa0, 0xbb, 0x85, 0x1b, + 0xea, 0xc5, 0xfc, 0x09, 0x94, 0xf9, 0x83, 0x0e, 0xf4, 0x5b, 0x36, 0x62, 0xcb, 0xc4, 0xcf, 0x7c, + 0x72, 0x10, 0x92, 0xeb, 0x75, 0x3e, 0x9e, 0x7a, 0x6c, 0x3e, 0x8d, 0x41, 0x45, 0x12, 0xe9, 0xd6, + 0xd5, 0xc4, 0xcb, 0x2a, 0xec, 0xf6, 0x96, 0x68, 0x1b, 0x66, 0xf6, 0x68, 0xe0, 0x3e, 0x7e, 0x9e, + 0x64, 0x28, 0x25, 0x93, 0x59, 0xda, 0x8d, 0xe3, 0xe7, 0x30, 0xbb, 0xe8, 0x1f, 0xb5, 0xc5, 0xab, + 0x3d, 0x83, 0xa7, 0xba, 0x8a, 0xcf, 0x2e, 0xef, 0xed, 0xcb, 0x34, 0x97, 0x9f, 0x18, 0x5f, 0xb9, + 0xb0, 0xf5, 0xcc, 0x9d, 0xaf, 0xde, 0x9e, 0x99, 0xf4, 0x3b, 0x38, 0x08, 0xb3, 0x32, 0xe5, 0xeb, + 0x83, 0xb0, 0x4b, 0x26, 0xfd, 0x9c, 0x37, 0x60, 0xb3, 0x39, 0xc9, 0xf1, 0xbb, 0x70, 0x3d, 0x45, + 0x6b, 0x37, 0xe5, 0xde, 0x62, 0xe6, 0xfa, 0x4e, 0x38, 0x4d, 0x67, 0x26, 0x02, 0xcf, 0x6c, 0xa7, + 0x16, 0x55, 0xa1, 0xd5, 0xea, 0xa2, 0x62, 0x11, 0x3d, 0xac, 0x02, 0xc3, 0x44, 0x23, 0xfe, 0x84, + 0x4e, 0xdb, 0x6d, 0xb5, 0x4e, 0x11, 0xa3, 0x52, 0xfb, 0x01, 0x8c, 0xd7, 0xf4, 0xca, 0x33, 0x2a, + 0xc9, 0x1d, 0x14, 0xea, 0x15, 0x50, 0xef, 0xb6, 0x77, 0xf1, 0x05, 0x55, 0x1b, 0xcf, 0xa9, 0xbe, + 0x22, 0xd7, 0x75, 0xc6, 0x48, 0xdc, 0xa6, 0x76, 0x81, 0xac, 0xbc, 0x8a, 0xca, 0x75, 0x26, 0x3b, + 0xd7, 0x5b, 0x9d, 0xa7, 0x9a, 0x49, 0xa6, 0xcd, 0x24, 0x56, 0xef, 0xfc, 0xb4, 0xca, 0x27, 0xbe, + 0x6b, 0xde, 0x4d, 0xee, 0xe7, 0x13, 0xa7, 0xaa, 0xd3, 0xfd, 0x7c, 0x52, 0x09, 0xf0, 0x74, 0x3f, + 0x9f, 0x8c, 0xec, 0x76, 0xcb, 0xc8, 0x2b, 0xce, 0xd1, 0xd3, 0xc5, 0x18, 0xa1, 0xd8, 0x64, 0xa4, + 0x02, 0x7a, 0xa8, 0x07, 0xe7, 0xe0, 0x99, 0x7d, 0xba, 0xd8, 0x5a, 0x93, 0x41, 0x39, 0x12, 0xa9, + 0x80, 0xee, 0x43, 0x89, 0x27, 0x39, 0x88, 0xe3, 0x19, 0xc6, 0xae, 0x7f, 0xe9, 0xdc, 0x0b, 0x5d, + 0x3a, 0xb5, 0x94, 0x8c, 0x04, 0xa7, 0x4c, 0x66, 0x39, 0x21, 0xe2, 0xba, 0x0c, 0x55, 0x88, 0xe3, + 0xbd, 0x29, 0xc3, 0x54, 0x2a, 0x04, 0xdc, 0xdc, 0xc5, 0x8c, 0x12, 0xa5, 0x52, 0x8e, 0xeb, 0xd1, + 0xe1, 0xd4, 0x27, 0x65, 0x84, 0x8c, 0x9b, 0xbb, 0x94, 0x59, 0x26, 0x18, 0x45, 0x3c, 0x45, 0x73, + 0x76, 0x62, 0xe9, 0xf8, 0x21, 0x57, 0x17, 0x1c, 0x59, 0xcd, 0xad, 0xd3, 0xa0, 0x8a, 0x5a, 0xa9, + 0xca, 0x50, 0x94, 0x91, 0xcd, 0xfa, 0xf5, 0x8c, 0xb7, 0x16, 0x06, 0x46, 0xec, 0x0d, 0xd6, 0x3d, + 0xb5, 0x36, 0x79, 0x24, 0x33, 0xc6, 0xe4, 0xd4, 0xd4, 0x8b, 0x41, 0x6e, 0x0f, 0x3e, 0x92, 0x39, + 0x62, 0x5e, 0x36, 0xe3, 0x7d, 0xb8, 0x9c, 0x78, 0xc0, 0x61, 0x32, 0xbe, 0x95, 0xfd, 0xca, 0x23, + 0x53, 0x3c, 0xf9, 0x3a, 0xfb, 0xb5, 0xf4, 0x43, 0x8f, 0x44, 0xbf, 0x9f, 0x75, 0xcd, 0xdb, 0x80, + 0x49, 0x5c, 0x66, 0x64, 0x5e, 0xf6, 0x38, 0x36, 0x8c, 0x09, 0x4e, 0x06, 0x29, 0x4a, 0x96, 0xaa, + 0xf7, 0xe3, 0xe3, 0xe2, 0x51, 0x30, 0xcf, 0xf2, 0x3e, 0x67, 0xbe, 0x14, 0x46, 0x60, 0xd6, 0x2e, + 0x26, 0x92, 0xc7, 0x93, 0x1f, 0xc2, 0xb9, 0xf8, 0xad, 0x30, 0x67, 0x91, 0x81, 0xd6, 0xc5, 0x50, + 0x76, 0x2e, 0x7e, 0x30, 0x7c, 0x76, 0xf2, 0x55, 0xb9, 0x15, 0xc5, 0xe4, 0x57, 0x52, 0xcf, 0x5d, + 0x8c, 0x6f, 0x38, 0xcd, 0x8e, 0xa4, 0xc9, 0xf6, 0xac, 0xbd, 0xd3, 0xc0, 0xe9, 0x96, 0x1d, 0xf6, + 0x50, 0x9f, 0x6e, 0x5d, 0x43, 0x33, 0x2a, 0xf5, 0x37, 0x87, 0xcf, 0x06, 0xdc, 0xc0, 0x50, 0x29, + 0xdb, 0x3c, 0x38, 0x5e, 0x36, 0x56, 0x7e, 0xdb, 0x93, 0x01, 0x56, 0x5a, 0x70, 0xbd, 0x67, 0xdc, + 0x47, 0x72, 0xc7, 0x70, 0x71, 0xe9, 0x1d, 0x21, 0xb2, 0xcb, 0xc9, 0x63, 0x3a, 0x2b, 0x7c, 0xa2, + 0xda, 0x67, 0xbb, 0x44, 0x72, 0x54, 0xfb, 0x6c, 0xd7, 0xf8, 0x8b, 0x9f, 0x63, 0x1a, 0x26, 0xb1, + 0x47, 0x61, 0xf8, 0x23, 0xea, 0xf1, 0x80, 0xd0, 0x5d, 0xaf, 0x7d, 0xae, 0x9b, 0x97, 0xa2, 0x29, + 0x42, 0x3c, 0xd3, 0x5c, 0x15, 0x27, 0xb1, 0x3c, 0xe6, 0xbd, 0x99, 0x74, 0x71, 0xad, 0xbe, 0xca, + 0x07, 0xe0, 0x99, 0x5b, 0x9e, 0x03, 0x5f, 0x58, 0xfa, 0xd9, 0x7f, 0xb8, 0x5a, 0xf8, 0xd9, 0xcf, + 0xaf, 0x16, 0xfe, 0xf5, 0xcf, 0xaf, 0x16, 0xfe, 0xfd, 0xcf, 0xaf, 0x16, 0xbe, 0x9c, 0x3f, 0x5d, + 0x58, 0xe2, 0x46, 0xcb, 0xa5, 0x5e, 0x74, 0x87, 0xb3, 0x1b, 0xc2, 0xff, 0xde, 0xfa, 0xef, 0x01, + 0x00, 0x00, 0xff, 0xff, 0x61, 0x3e, 0x6a, 0x54, 0x91, 0xea, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -16807,10 +16805,6 @@ type AuthServiceClient interface { GetAccessRequestsV2(ctx context.Context, in *types.AccessRequestFilter, opts ...grpc.CallOption) (AuthService_GetAccessRequestsV2Client, error) // ListAccessRequests gets access requests with pagination and sorting. ListAccessRequests(ctx context.Context, in *ListAccessRequestsRequest, opts ...grpc.CallOption) (*ListAccessRequestsResponse, error) - // CreateAccessRequest creates a new access request. - // Deprecated: use CreateAccessRequestV2 instead. - // DELETE IN v15.0.0. - CreateAccessRequest(ctx context.Context, in *types.AccessRequestV3, opts ...grpc.CallOption) (*emptypb.Empty, error) // CreateAccessRequestV2 creates a new access request. CreateAccessRequestV2(ctx context.Context, in *types.AccessRequestV3, opts ...grpc.CallOption) (*types.AccessRequestV3, error) // DeleteAccessRequest deletes an access request. @@ -16975,10 +16969,6 @@ type AuthServiceClient interface { GenerateSnowflakeJWT(ctx context.Context, in *SnowflakeJWTRequest, opts ...grpc.CallOption) (*SnowflakeJWTResponse, error) // GetRole retrieves a role described by the given request. GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*types.RoleV6, error) - // GetRole retrieves all roles. - // - // DELETE IN 17.0 - GetRoles(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetRolesResponse, error) // ListRoles is a paginated role getter. ListRoles(ctx context.Context, in *ListRolesRequest, opts ...grpc.CallOption) (*ListRolesResponse, error) // CreateRole creates a new role. @@ -17894,15 +17884,6 @@ func (c *authServiceClient) ListAccessRequests(ctx context.Context, in *ListAcce return out, nil } -func (c *authServiceClient) CreateAccessRequest(ctx context.Context, in *types.AccessRequestV3, opts ...grpc.CallOption) (*emptypb.Empty, error) { - out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, "/proto.AuthService/CreateAccessRequest", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *authServiceClient) CreateAccessRequestV2(ctx context.Context, in *types.AccessRequestV3, opts ...grpc.CallOption) (*types.AccessRequestV3, error) { out := new(types.AccessRequestV3) err := c.cc.Invoke(ctx, "/proto.AuthService/CreateAccessRequestV2", in, out, opts...) @@ -18604,15 +18585,6 @@ func (c *authServiceClient) GetRole(ctx context.Context, in *GetRoleRequest, opt return out, nil } -func (c *authServiceClient) GetRoles(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetRolesResponse, error) { - out := new(GetRolesResponse) - err := c.cc.Invoke(ctx, "/proto.AuthService/GetRoles", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *authServiceClient) ListRoles(ctx context.Context, in *ListRolesRequest, opts ...grpc.CallOption) (*ListRolesResponse, error) { out := new(ListRolesResponse) err := c.cc.Invoke(ctx, "/proto.AuthService/ListRoles", in, out, opts...) @@ -20211,10 +20183,6 @@ type AuthServiceServer interface { GetAccessRequestsV2(*types.AccessRequestFilter, AuthService_GetAccessRequestsV2Server) error // ListAccessRequests gets access requests with pagination and sorting. ListAccessRequests(context.Context, *ListAccessRequestsRequest) (*ListAccessRequestsResponse, error) - // CreateAccessRequest creates a new access request. - // Deprecated: use CreateAccessRequestV2 instead. - // DELETE IN v15.0.0. - CreateAccessRequest(context.Context, *types.AccessRequestV3) (*emptypb.Empty, error) // CreateAccessRequestV2 creates a new access request. CreateAccessRequestV2(context.Context, *types.AccessRequestV3) (*types.AccessRequestV3, error) // DeleteAccessRequest deletes an access request. @@ -20379,10 +20347,6 @@ type AuthServiceServer interface { GenerateSnowflakeJWT(context.Context, *SnowflakeJWTRequest) (*SnowflakeJWTResponse, error) // GetRole retrieves a role described by the given request. GetRole(context.Context, *GetRoleRequest) (*types.RoleV6, error) - // GetRole retrieves all roles. - // - // DELETE IN 17.0 - GetRoles(context.Context, *emptypb.Empty) (*GetRolesResponse, error) // ListRoles is a paginated role getter. ListRoles(context.Context, *ListRolesRequest) (*ListRolesResponse, error) // CreateRole creates a new role. @@ -20907,9 +20871,6 @@ func (*UnimplementedAuthServiceServer) GetAccessRequestsV2(req *types.AccessRequ func (*UnimplementedAuthServiceServer) ListAccessRequests(ctx context.Context, req *ListAccessRequestsRequest) (*ListAccessRequestsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListAccessRequests not implemented") } -func (*UnimplementedAuthServiceServer) CreateAccessRequest(ctx context.Context, req *types.AccessRequestV3) (*emptypb.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method CreateAccessRequest not implemented") -} func (*UnimplementedAuthServiceServer) CreateAccessRequestV2(ctx context.Context, req *types.AccessRequestV3) (*types.AccessRequestV3, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateAccessRequestV2 not implemented") } @@ -21117,9 +21078,6 @@ func (*UnimplementedAuthServiceServer) GenerateSnowflakeJWT(ctx context.Context, func (*UnimplementedAuthServiceServer) GetRole(ctx context.Context, req *GetRoleRequest) (*types.RoleV6, error) { return nil, status.Errorf(codes.Unimplemented, "method GetRole not implemented") } -func (*UnimplementedAuthServiceServer) GetRoles(ctx context.Context, req *emptypb.Empty) (*GetRolesResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetRoles not implemented") -} func (*UnimplementedAuthServiceServer) ListRoles(ctx context.Context, req *ListRolesRequest) (*ListRolesResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListRoles not implemented") } @@ -22180,24 +22138,6 @@ func _AuthService_ListAccessRequests_Handler(srv interface{}, ctx context.Contex return interceptor(ctx, in, info, handler) } -func _AuthService_CreateAccessRequest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(types.AccessRequestV3) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AuthServiceServer).CreateAccessRequest(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/proto.AuthService/CreateAccessRequest", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AuthServiceServer).CreateAccessRequest(ctx, req.(*types.AccessRequestV3)) - } - return interceptor(ctx, in, info, handler) -} - func _AuthService_CreateAccessRequestV2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(types.AccessRequestV3) if err := dec(in); err != nil { @@ -23454,24 +23394,6 @@ func _AuthService_GetRole_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } -func _AuthService_GetRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(emptypb.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AuthServiceServer).GetRoles(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/proto.AuthService/GetRoles", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AuthServiceServer).GetRoles(ctx, req.(*emptypb.Empty)) - } - return interceptor(ctx, in, info, handler) -} - func _AuthService_ListRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListRolesRequest) if err := dec(in); err != nil { @@ -26393,10 +26315,6 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ MethodName: "ListAccessRequests", Handler: _AuthService_ListAccessRequests_Handler, }, - { - MethodName: "CreateAccessRequest", - Handler: _AuthService_CreateAccessRequest_Handler, - }, { MethodName: "CreateAccessRequestV2", Handler: _AuthService_CreateAccessRequestV2_Handler, @@ -26661,10 +26579,6 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetRole", Handler: _AuthService_GetRole_Handler, }, - { - MethodName: "GetRoles", - Handler: _AuthService_GetRoles_Handler, - }, { MethodName: "ListRoles", Handler: _AuthService_ListRoles_Handler, diff --git a/api/proto/teleport/legacy/client/proto/authservice.proto b/api/proto/teleport/legacy/client/proto/authservice.proto index 4f4a4dff614bf..44faf9dd1993a 100644 --- a/api/proto/teleport/legacy/client/proto/authservice.proto +++ b/api/proto/teleport/legacy/client/proto/authservice.proto @@ -2832,10 +2832,6 @@ service AuthService { // ListAccessRequests gets access requests with pagination and sorting. rpc ListAccessRequests(ListAccessRequestsRequest) returns (ListAccessRequestsResponse); - // CreateAccessRequest creates a new access request. - // Deprecated: use CreateAccessRequestV2 instead. - // DELETE IN v15.0.0. - rpc CreateAccessRequest(types.AccessRequestV3) returns (google.protobuf.Empty); // CreateAccessRequestV2 creates a new access request. rpc CreateAccessRequestV2(types.AccessRequestV3) returns (types.AccessRequestV3); // DeleteAccessRequest deletes an access request. @@ -3043,10 +3039,6 @@ service AuthService { // GetRole retrieves a role described by the given request. rpc GetRole(GetRoleRequest) returns (types.RoleV6); - // GetRole retrieves all roles. - // - // DELETE IN 17.0 - rpc GetRoles(google.protobuf.Empty) returns (GetRolesResponse); // ListRoles is a paginated role getter. rpc ListRoles(ListRolesRequest) returns (ListRolesResponse); // CreateRole creates a new role. From 239723afc87f8ca636d8c3bfdc1d6442158ebd78 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Mon, 28 Oct 2024 09:09:23 -0600 Subject: [PATCH 08/22] Improve Teleport's ability to reconnect to LDAP (#36281) * Always attempt desktop discovery, even if LDAP is not ready If Teleport loses it's connection to the LDAP server, it will attempt to initiate a new condition when: 1. The user tries to connect to a desktop and Teleport fails to obtain the user's SID. 2. The periodic desktop discovery routine attempts to search LDAP for desktops. In some circumstances, #2 never gets the chance to apply, since discovery is skipped when LDAP is not ready. Additionally, if LDAP is not ready, then you can't connect to a desktop, so #1 can't happen either, which means Teleport won't connect again until it is restarted. * Periodically use the LDAP connection when discovery is not enabled If LDAP-based discovery is not enabled then we may go long periods of time without trying to use the LDAP connection, which prevents us from detecting disconnects (and restoring the connection) in a timely manner. When discovery is disabled, perform a read every 5 minutes and reconnect if we detect a connection problem. * Address review comments --- lib/srv/desktop/discovery.go | 11 ++++---- lib/srv/desktop/windows_server.go | 43 ++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/lib/srv/desktop/discovery.go b/lib/srv/desktop/discovery.go index c44bcc0a9cabb..6050309b35bbe 100644 --- a/lib/srv/desktop/discovery.go +++ b/lib/srv/desktop/discovery.go @@ -99,11 +99,6 @@ func (s *WindowsService) ldapSearchFilter() string { // getDesktopsFromLDAP discovers Windows hosts via LDAP func (s *WindowsService) getDesktopsFromLDAP() map[string]types.WindowsDesktop { - if !s.ldapReady() { - s.cfg.Logger.WarnContext(context.Background(), "skipping desktop discovery: LDAP not yet initialized") - return nil - } - filter := s.ldapSearchFilter() s.cfg.Logger.DebugContext(context.Background(), "searching for desktops", "filter", filter) @@ -250,7 +245,11 @@ func (s *WindowsService) lookupDesktop(ctx context.Context, hostname string) ([] // ldapEntryToWindowsDesktop generates the Windows Desktop resource // from an LDAP search result -func (s *WindowsService) ldapEntryToWindowsDesktop(ctx context.Context, entry *ldap.Entry, getHostLabels func(string) map[string]string) (types.WindowsDesktop, error) { +func (s *WindowsService) ldapEntryToWindowsDesktop( + ctx context.Context, + entry *ldap.Entry, + getHostLabels func(string) map[string]string, +) (types.WindowsDesktop, error) { hostname := entry.GetAttributeValue(windows.AttrDNSHostName) if hostname == "" { attrs := make([]string, len(entry.Attributes)) diff --git a/lib/srv/desktop/windows_server.go b/lib/srv/desktop/windows_server.go index 791f477861666..77b272acd0696 100644 --- a/lib/srv/desktop/windows_server.go +++ b/lib/srv/desktop/windows_server.go @@ -425,10 +425,47 @@ func NewWindowsService(cfg WindowsServiceConfig) (*WindowsService, error) { s.cfg.Logger.InfoContext(ctx, "desktop discovery via LDAP is disabled, set 'base_dn' to enable") } + // if LDAP-based discovery is not enabled, but we have configured LDAP + // then it's important that we periodically try to use the LDAP connection + // to detect connection closure + if s.ldapConfigured && len(s.cfg.DiscoveryBaseDN) == 0 { + s.startLDAPConnectionCheck(ctx) + } + ok = true return s, nil } +// startLDAPConnectionCheck starts a background process that +// periodically reads from the LDAP connection in order to detect +// connection closure, and reconnects if necessary. +// This is useful when LDAP-based discovery is disabled, because without +// discovery the connection goes idle and may be closed by the server. +func (s *WindowsService) startLDAPConnectionCheck(ctx context.Context) { + s.cfg.Logger.DebugContext(ctx, "starting LDAP connection checker") + go func() { + t := s.cfg.Clock.NewTicker(5 * time.Minute) + defer t.Stop() + + for { + select { + case <-t.Chan(): + // attempt to read CAs in the NTAuth store (we know we have permissions to do so) + ntAuthDN := "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration," + s.cfg.LDAPConfig.DomainDN() + _, err := s.lc.Read(ntAuthDN, "certificationAuthority", []string{"cACertificate"}) + if trace.IsConnectionProblem(err) { + s.cfg.Logger.DebugContext(ctx, "detected broken LDAP connection, will reconnect") + if err := s.initializeLDAP(); err != nil { + s.cfg.Logger.WarnContext(ctx, "failed to reconnect to LDAP", "error", err) + } + } + case <-ctx.Done(): + return + } + } + }() +} + func (s *WindowsService) newSessionRecorder(recConfig types.SessionRecordingConfig, sessionID string) (libevents.SessionPreparerRecorder, error) { return recorder.New(recorder.Config{ SessionID: session.ID(sessionID), @@ -693,12 +730,6 @@ func (s *WindowsService) readyForConnections() bool { return s.ldapInitialized } -func (s *WindowsService) ldapReady() bool { - s.mu.Lock() - defer s.mu.Unlock() - return s.ldapInitialized -} - // handleConnection handles TLS connections from a Teleport proxy. // It authenticates and authorizes the connection, and then begins // translating the TDP messages from the proxy into native RDP. From 37c13586c07c8475527afee39f2cf64ba5830295 Mon Sep 17 00:00:00 2001 From: David Boslee Date: Mon, 28 Oct 2024 11:32:56 -0400 Subject: [PATCH 09/22] kms: allow multi-region kms keys to be enabled (#47672) * kms: allow multi-region kms keys to be enabled * add unit tests * fix logging key lint --------- Co-authored-by: Nic Klaassen --- lib/auth/keystore/aws_kms.go | 31 +++++---- lib/auth/keystore/aws_kms_test.go | 58 ++++++++++++++++ lib/auth/keystore/keystore_test.go | 103 +++++++++++++++++------------ lib/config/configuration.go | 1 + lib/config/fileconf.go | 5 ++ lib/service/servicecfg/auth.go | 5 ++ 6 files changed, 148 insertions(+), 55 deletions(-) diff --git a/lib/auth/keystore/aws_kms.go b/lib/auth/keystore/aws_kms.go index 3024dad363832..fc27478c3e031 100644 --- a/lib/auth/keystore/aws_kms.go +++ b/lib/auth/keystore/aws_kms.go @@ -57,12 +57,13 @@ const ( ) type awsKMSKeystore struct { - kms kmsClient - clusterName types.ClusterName - awsAccount string - awsRegion string - clock clockwork.Clock - logger *slog.Logger + kms kmsClient + clusterName types.ClusterName + awsAccount string + awsRegion string + multiRegionEnabled bool + clock clockwork.Clock + logger *slog.Logger } func newAWSKMSKeystore(ctx context.Context, cfg *servicecfg.AWSKMSConfig, opts *Options) (*awsKMSKeystore, error) { @@ -99,12 +100,13 @@ func newAWSKMSKeystore(ctx context.Context, cfg *servicecfg.AWSKMSConfig, opts * clock = clockwork.NewRealClock() } return &awsKMSKeystore{ - clusterName: opts.ClusterName, - awsAccount: cfg.AWSAccount, - awsRegion: cfg.AWSRegion, - kms: kmsClient, - clock: clock, - logger: opts.Logger, + clusterName: opts.ClusterName, + awsAccount: cfg.AWSAccount, + awsRegion: cfg.AWSRegion, + multiRegionEnabled: cfg.MultiRegion.Enabled, + kms: kmsClient, + clock: clock, + logger: opts.Logger, }, nil } @@ -126,7 +128,9 @@ func (a *awsKMSKeystore) generateKey(ctx context.Context, algorithm cryptosuites return nil, nil, trace.Wrap(err) } - a.logger.InfoContext(ctx, "Creating new AWS KMS keypair.", "algorithm", alg) + a.logger.InfoContext(ctx, "Creating new AWS KMS keypair.", + slog.Any("algorithm", algorithm), + slog.Bool("multi_region", a.multiRegionEnabled)) output, err := a.kms.CreateKey(ctx, &kms.CreateKeyInput{ Description: aws.String("Teleport CA key"), @@ -138,6 +142,7 @@ func (a *awsKMSKeystore) generateKey(ctx context.Context, algorithm cryptosuites TagValue: aws.String(a.clusterName.GetClusterName()), }, }, + MultiRegion: aws.Bool(a.multiRegionEnabled), }) if err != nil { return nil, nil, trace.Wrap(err) diff --git a/lib/auth/keystore/aws_kms_test.go b/lib/auth/keystore/aws_kms_test.go index b09a3f5a11c86..dd5940b170979 100644 --- a/lib/auth/keystore/aws_kms_test.go +++ b/lib/auth/keystore/aws_kms_test.go @@ -211,6 +211,60 @@ func TestAWSKMS_RetryWhilePending(t *testing.T) { require.Error(t, err) } +// TestMultiRegionKeys asserts that a keystore created with multi-region enabled +// correctly passes this argument to the AWS client. This gives very little real +// coverage since the AWS KMS service here is faked, but at least we know the +// keystore passed the bool to the client correctly. TestBackends and +// TestManager are both able to run with a real AWS KMS client and you can +// confirm the keys are really multi-region there. +func TestMultiRegionKeys(t *testing.T) { + ctx := context.Background() + clock := clockwork.NewFakeClock() + + const pageSize int = 4 + fakeKMS := newFakeAWSKMSService(t, clock, "123456789012", "us-west-2", pageSize) + clusterName, err := services.NewClusterNameWithRandomID(types.ClusterNameSpecV2{ClusterName: "test-cluster"}) + require.NoError(t, err) + opts := &Options{ + ClusterName: clusterName, + HostUUID: "uuid", + AuthPreferenceGetter: &fakeAuthPreferenceGetter{types.SignatureAlgorithmSuite_SIGNATURE_ALGORITHM_SUITE_HSM_V1}, + awsKMSClient: fakeKMS, + awsSTSClient: &fakeAWSSTSClient{ + account: "123456789012", + }, + clockworkOverride: clock, + } + + for _, multiRegion := range []bool{false, true} { + t.Run(fmt.Sprint(multiRegion), func(t *testing.T) { + cfg := servicecfg.KeystoreConfig{ + AWSKMS: servicecfg.AWSKMSConfig{ + AWSAccount: "123456789012", + AWSRegion: "us-west-2", + MultiRegion: struct{ Enabled bool }{ + Enabled: multiRegion, + }, + }, + } + keyStore, err := NewManager(ctx, &cfg, opts) + require.NoError(t, err) + + sshKeyPair, err := keyStore.NewSSHKeyPair(ctx, cryptosuites.UserCASSH) + require.NoError(t, err) + + keyID, err := parseAWSKMSKeyID(sshKeyPair.PrivateKey) + require.NoError(t, err) + + if multiRegion { + assert.Contains(t, keyID.arn, "mrk-") + } else { + assert.NotContains(t, keyID.arn, "mrk-") + } + }) + } +} + type fakeAWSKMSService struct { keys []*fakeAWSKMSKey clock clockwork.Clock @@ -239,6 +293,10 @@ type fakeAWSKMSKey struct { func (f *fakeAWSKMSService) CreateKey(_ context.Context, input *kms.CreateKeyInput, _ ...func(*kms.Options)) (*kms.CreateKeyOutput, error) { id := uuid.NewString() + if aws.ToBool(input.MultiRegion) { + // AWS does this https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id-key-ARN + id = "mrk-" + id + } a := arn.ARN{ Partition: "aws", Service: "kms", diff --git a/lib/auth/keystore/keystore_test.go b/lib/auth/keystore/keystore_test.go index 0b9e880677762..3780c73296157 100644 --- a/lib/auth/keystore/keystore_test.go +++ b/lib/auth/keystore/keystore_test.go @@ -604,6 +604,7 @@ func newTestPack(ctx context.Context, t *testing.T) *testPack { }) } + // Test with real GCP account if environment is enabled. if config, ok := gcpKMSTestConfig(t); ok { opts := baseOpts opts.kmsClient = nil @@ -621,6 +622,7 @@ func newTestPack(ctx context.Context, t *testing.T) *testPack { }.marshal(), }) } + // Always test with fake GCP client. fakeGCPKMSConfig := servicecfg.KeystoreConfig{ GCPKMS: servicecfg.GCPKMSConfig{ ProtectionLevel: "HSM", @@ -640,61 +642,78 @@ func newTestPack(ctx context.Context, t *testing.T) *testPack { }.marshal(), }) - if config, ok := awsKMSTestConfig(t); ok { - opts := baseOpts - // Unset the fake clients so this test can use the real AWS clients. - opts.awsKMSClient = nil - opts.awsSTSClient = nil - - backend, err := newAWSKMSKeystore(ctx, &config.AWSKMS, &opts) + // Test AWS with and without multi-region keys + for _, multiRegion := range []bool{false, true} { + // Test with real AWS account if environment is enabled. + if config, ok := awsKMSTestConfig(t); ok { + config.AWSKMS.MultiRegion.Enabled = multiRegion + opts := baseOpts + // Unset the fake clients so this test can use the real AWS clients. + opts.awsKMSClient = nil + opts.awsSTSClient = nil + + backend, err := newAWSKMSKeystore(ctx, &config.AWSKMS, &opts) + require.NoError(t, err) + name := "aws_kms" + if multiRegion { + name += "_multi_region" + } + backends = append(backends, &backendDesc{ + name: name, + config: config, + opts: &opts, + backend: backend, + expectedKeyType: types.PrivateKeyType_AWS_KMS, + unusedRawKey: awsKMSKeyID{ + arn: arn.ARN{ + Partition: "aws", + Service: "kms", + Region: config.AWSKMS.AWSRegion, + AccountID: config.AWSKMS.AWSAccount, + Resource: "unused", + }.String(), + account: config.AWSKMS.AWSAccount, + region: config.AWSKMS.AWSRegion, + }.marshal(), + }) + } + + // Always test with fake AWS client. + fakeAWSKMSConfig := servicecfg.KeystoreConfig{ + AWSKMS: servicecfg.AWSKMSConfig{ + AWSAccount: "123456789012", + AWSRegion: "us-west-2", + MultiRegion: struct{ Enabled bool }{ + Enabled: multiRegion, + }, + }, + } + fakeAWSKMSBackend, err := newAWSKMSKeystore(ctx, &fakeAWSKMSConfig.AWSKMS, &baseOpts) require.NoError(t, err) + name := "fake_aws_kms" + if multiRegion { + name += "_multi_region" + } backends = append(backends, &backendDesc{ - name: "aws_kms", - config: config, - opts: &opts, - backend: backend, + name: name, + config: fakeAWSKMSConfig, + opts: &baseOpts, + backend: fakeAWSKMSBackend, expectedKeyType: types.PrivateKeyType_AWS_KMS, unusedRawKey: awsKMSKeyID{ arn: arn.ARN{ Partition: "aws", Service: "kms", - Region: config.AWSKMS.AWSRegion, - AccountID: config.AWSKMS.AWSAccount, + Region: "us-west-2", + AccountID: "123456789012", Resource: "unused", }.String(), - account: config.AWSKMS.AWSAccount, - region: config.AWSKMS.AWSRegion, + account: "123456789012", + region: "us-west-2", }.marshal(), }) } - fakeAWSKMSConfig := servicecfg.KeystoreConfig{ - AWSKMS: servicecfg.AWSKMSConfig{ - AWSAccount: "123456789012", - AWSRegion: "us-west-2", - }, - } - fakeAWSKMSBackend, err := newAWSKMSKeystore(ctx, &fakeAWSKMSConfig.AWSKMS, &baseOpts) - require.NoError(t, err) - backends = append(backends, &backendDesc{ - name: "fake_aws_kms", - config: fakeAWSKMSConfig, - opts: &baseOpts, - backend: fakeAWSKMSBackend, - expectedKeyType: types.PrivateKeyType_AWS_KMS, - unusedRawKey: awsKMSKeyID{ - arn: arn.ARN{ - Partition: "aws", - Service: "kms", - Region: "us-west-2", - AccountID: "123456789012", - Resource: "unused", - }.String(), - account: "123456789012", - region: "us-west-2", - }.marshal(), - }) - return &testPack{ backends: backends, clock: clock, diff --git a/lib/config/configuration.go b/lib/config/configuration.go index 0f23047f64f74..5ef37af409f81 100644 --- a/lib/config/configuration.go +++ b/lib/config/configuration.go @@ -1169,6 +1169,7 @@ func applyAWSKMSConfig(kmsConfig *AWSKMS, cfg *servicecfg.Config) error { return trace.BadParameter("must set region in ca_key_params.aws_kms") } cfg.Auth.KeyStore.AWSKMS.AWSRegion = kmsConfig.Region + cfg.Auth.KeyStore.AWSKMS.MultiRegion = kmsConfig.MultiRegion return nil } diff --git a/lib/config/fileconf.go b/lib/config/fileconf.go index 34ea2a60f2607..8a666b8221803 100644 --- a/lib/config/fileconf.go +++ b/lib/config/fileconf.go @@ -919,6 +919,11 @@ type AWSKMS struct { Account string `yaml:"account"` // Region is the AWS region to use. Region string `yaml:"region"` + // MultiRegion contains configuration for multi-region AWS KMS. + MultiRegion struct { + // Enabled configures new keys to be multi-region. + Enabled bool + } `yaml:"multi_region,omitempty"` } // TrustedCluster struct holds configuration values under "trusted_clusters" key diff --git a/lib/service/servicecfg/auth.go b/lib/service/servicecfg/auth.go index 5c56d18b117c1..3663ea25ae0ea 100644 --- a/lib/service/servicecfg/auth.go +++ b/lib/service/servicecfg/auth.go @@ -278,6 +278,11 @@ type AWSKMSConfig struct { AWSAccount string // AWSRegion is the AWS region where the keys will reside. AWSRegion string + // MultiRegion contains configuration for multi-region AWS KMS. + MultiRegion struct { + // Enabled configures new keys to be multi-region. + Enabled bool + } } // CheckAndSetDefaults checks that required parameters of the config are From 7f07c40d5ac96427a7ab097b592ff3694d88c1d5 Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Mon, 28 Oct 2024 11:36:52 -0400 Subject: [PATCH 10/22] Add a timeout to Lint (Docs) dep installation (#47994) For reasons that are unclear, the dependency installation step in the Lint (Docs) GitHub Actions job occasionally takes an indefinite time to complete, and must be canceled manually or after reaching the maximum GitHub Actions runtime. To prevent this situation, this change adds a timeout of 10 minutes to the step that installs NodeJS dependencies for the Lint (Docs) job. This step tends to take around 7 minutes to complete, so a 10-minute timeout should be reasonable. --- .github/workflows/doc-tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/doc-tests.yaml b/.github/workflows/doc-tests.yaml index 5030bebe367b1..272c2de479c5c 100644 --- a/.github/workflows/doc-tests.yaml +++ b/.github/workflows/doc-tests.yaml @@ -48,6 +48,8 @@ jobs: path: "docs" - name: Prepare docs site configuration + # Prevent occasional `yarn install` executions that run indefinitely + timeout-minutes: 10 # The environment we use for linting the docs differs from the one we # use for the live docs site in that we only test a single version of # the content. From 8044b98a0d509a683016e5f3cc0235bc176cf471 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 28 Oct 2024 08:48:20 -0700 Subject: [PATCH 11/22] Web: add support for requesting for kube namespaces (#47345) --- web/packages/design/src/DataTable/Table.tsx | 28 +- web/packages/design/src/DataTable/types.ts | 8 + web/packages/design/src/Link/Link.jsx | 1 - .../NewRequest/CheckableOption.tsx | 48 +++ .../NewRequest/RequestCheckout/CrossIcon.tsx | 58 +++ .../RequestCheckout/KubeNamespaceSelector.tsx | 207 ++++++++++ .../RequestCheckout/RequestCheckout.story.tsx | 21 + .../RequestCheckout/RequestCheckout.test.tsx | 2 + .../RequestCheckout/RequestCheckout.tsx | 385 ++++++++++++------ .../NewRequest/ResourceList/Apps.tsx | 4 +- .../NewRequest/ResourceList/ResourceList.tsx | 6 +- .../AccessRequests/NewRequest/index.ts | 2 +- .../AccessRequests/NewRequest/kube.test.ts | 61 +++ .../AccessRequests/NewRequest/kube.ts | 94 +++++ .../AccessRequests/NewRequest/resource.ts | 10 +- .../components/AccessRequests/Shared/utils.ts | 3 +- .../components/FieldSelect/FieldSelect.tsx | 52 ++- .../shared/components/FieldSelect/shared.tsx | 14 +- .../services/accessRequests/accessRequests.ts | 4 +- web/packages/shared/utils/text.test.ts | 38 +- web/packages/shared/utils/text.ts | 25 ++ .../teleport/src/AccessRequests/service.ts | 5 +- .../teleport/src/AccessRequests/types.ts | 8 +- web/packages/teleport/src/config.ts | 2 +- .../AccessRequestCheckout.tsx | 5 + .../NewRequest/NewRequest.tsx | 1 + 26 files changed, 923 insertions(+), 169 deletions(-) create mode 100644 web/packages/shared/components/AccessRequests/NewRequest/CheckableOption.tsx create mode 100644 web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/CrossIcon.tsx create mode 100644 web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/KubeNamespaceSelector.tsx create mode 100644 web/packages/shared/components/AccessRequests/NewRequest/kube.test.ts create mode 100644 web/packages/shared/components/AccessRequests/NewRequest/kube.ts diff --git a/web/packages/design/src/DataTable/Table.tsx b/web/packages/design/src/DataTable/Table.tsx index 8f3b9bc8bcaa5..d028e1b18a844 100644 --- a/web/packages/design/src/DataTable/Table.tsx +++ b/web/packages/design/src/DataTable/Table.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import React, { ReactNode } from 'react'; +import React, { ReactNode, PropsWithChildren } from 'react'; import { Box, Flex, Indicator, P1, Text } from 'design'; import * as Icons from 'design/Icon'; @@ -108,6 +108,22 @@ export default function Table(props: TableProps) { return ; } data.map((item, rowIdx) => { + const TableRow: React.FC = ({ children }) => ( + row?.onClick?.(item)} + style={row?.getStyle?.(item)} + > + {children} + + ); + + const customRow = row?.customRow?.(item); + if (customRow) { + rows.push({customRow}); + return; + } + const cells = columns.flatMap((column, columnIdx) => { if (column.isNonRender) { return []; // does not include this column. @@ -125,15 +141,7 @@ export default function Table(props: TableProps) { ); }); - rows.push( - row?.onClick?.(item)} - style={row?.getStyle?.(item)} - > - {cells} - - ); + rows.push({cells}); }); if (rows.length) { diff --git a/web/packages/design/src/DataTable/types.ts b/web/packages/design/src/DataTable/types.ts index afe803116613a..9f5ec0490653c 100644 --- a/web/packages/design/src/DataTable/types.ts +++ b/web/packages/design/src/DataTable/types.ts @@ -79,6 +79,14 @@ export type TableProps = { * conditionally style a row (eg: cursor: pointer, disabled) */ getStyle?(row: T): React.CSSProperties; + /** + * conditionally render a custom row + * use case: by default all columns are represented by cells + * but certain rows you need all the columns to be merged + * into one cell to render other related elements like a + * dropdown selector. + */ + customRow?(row: T): JSX.Element; }; }; diff --git a/web/packages/design/src/Link/Link.jsx b/web/packages/design/src/Link/Link.jsx index 957be80a5f7be..260c31f85094b 100644 --- a/web/packages/design/src/Link/Link.jsx +++ b/web/packages/design/src/Link/Link.jsx @@ -31,7 +31,6 @@ const StyledButtonLink = styled.a.attrs({ rel: 'noreferrer', })` color: ${({ theme }) => theme.colors.buttons.link.default}; - font-weight: normal; background: none; text-decoration: underline; text-transform: none; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/CheckableOption.tsx b/web/packages/shared/components/AccessRequests/NewRequest/CheckableOption.tsx new file mode 100644 index 0000000000000..f10b940050628 --- /dev/null +++ b/web/packages/shared/components/AccessRequests/NewRequest/CheckableOption.tsx @@ -0,0 +1,48 @@ +/** + * 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 from 'react'; +import { Flex, Text } from 'design'; +import { components, OptionProps } from 'react-select'; + +import { Option as BaseOption } from 'shared/components/Select'; + +export type Option = BaseOption & { + isAdded?: boolean; + kind: 'app' | 'user_group' | 'namespace'; +}; + +export const CheckableOptionComponent = ( + props: OptionProps + ); + } + } + + return ( + + {({ validator }) => ( + <> + {showRequestRoleErrBanner && + fetchResourceRequestRolesAttempt.status === 'failed' && ( + + )} + {hasUnsupportedKubeRequestModes && ( + + + You can only request Kubernetes resource{' '} + {pluralize(unsupportedKubeRequestModes.length, 'kind')}{' '} + {listToSentence(unsupportedKubeRequestModes)} for + cluster {affectedKubeClusterName}. Requesting those + resource kinds is currently only supported through the{' '} + + tsh CLI tool + + . Use the{' '} + + tsh request search + {' '} + command that will help you construct the request. + + + Example: + - - {({ validator }) => ( + + )} + {fetchStatus === 'loading' && ( + + + + )} + + {fetchStatus === 'loaded' && ( +
+ {createAttempt.status === 'success' ? ( + <> + + +

Resources Requested Successfully

+ + You've successfully requested {numRequestedResources}{' '} + {pluralize(numRequestedResources, 'resource')} + +
+ + + +
+ + + ) : ( + <> + {Header?.() || DefaultHeader()} + {createAttempt.status === 'failed' && ( + + )} + d.kind !== 'namespace' + )} + row={{ + customRow, + }} + columns={[ + { + key: 'clusterName', + headerText: 'Cluster Name', + isNonRender: !showClusterNameColumn, + }, + { + key: 'kind', + headerText: 'Type', + render: item => ( + {getPrettyResourceKind(item.kind)} + ), + }, + { + key: 'name', + headerText: 'Name', + }, + { + altKey: 'delete-btn', + render: resource => ( + + + + ), + }, + ]} + emptyText="No resources are selected" + /> + {userGroupFetchAttempt?.status === 'processing' && ( + + + + )} + {userGroupFetchAttempt?.status === 'failed' && ( + {userGroupFetchAttempt.statusText} + )} + {userGroupFetchAttempt?.status === 'success' && + appsGrantedByUserGroup.length > 0 && ( + + )} + {isResourceRequest && ( + + )} + + r.name) ?? [] + } + selectedReviewers={selectedReviewers} + setSelectedReviewers={setSelectedReviewers} + /> + {dryRunResponse && ( @@ -394,19 +487,19 @@ export function RequestCheckout({ reset(); onClose(); }} - disabled={submitBtnDisabled} + disabled={cancelBtnDisabled} > Cancel - )} - - + + )} +
)} - + )} - +
); } @@ -549,7 +642,7 @@ function ResourceRequestRoles({ {roles.map((roleName, index) => { const checked = selectedRoles.includes(roleName); return ( - + ; export interface PendingListItem { - kind: ResourceKind; + kind: RequestableResourceKind; /** Name of the resource, for presentation purposes only. */ name: string; /** Identifier of the resource. Should be sent in requests. */ id: string; clusterName?: string; + /** + * This field must be defined if a user is requesting subresources. + * + * Example: + * "kube_cluster" resource can have subresources such as "namespace". + * Example PendingListItem values if user is requesting a kubes namespace: + * - kind: const "namespace" + * - id: name of the kube_cluster + * - subResourceName: name of the kube_cluster's namespace + * - clusterName: name of teleport cluster where kube_cluster is located + * - name: same as subResourceName as this is what we want to display to user + * */ + subResourceName?: string; } +export type PendingKubeResourceItem = Omit & { + kind: Extract; +}; + export type RequestCheckoutProps = { onClose(): void; @@ -816,6 +928,11 @@ export type RequestCheckoutProps = Header?: () => JSX.Element; startTime: Date; onStartTimeChange(t?: Date): void; + fetchKubeNamespaces(p: KubeNamespaceRequest): Promise; + bulkToggleKubeResources( + kubeResources: PendingKubeResourceItem[], + kubeCluster: T + ): void; }; type SuccessComponentParams = { diff --git a/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/Apps.tsx b/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/Apps.tsx index 33e01c9fa7675..5488ceeedaefd 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/Apps.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/Apps.tsx @@ -30,7 +30,7 @@ import Select, { } from 'shared/components/Select'; import { ToolTipInfo } from 'shared/components/ToolTip'; -import { ResourceMap, ResourceKind } from '../resource'; +import { ResourceMap, RequestableResourceKind } from '../resource'; import { ListProps, StyledTable } from './ResourceList'; @@ -125,7 +125,7 @@ function ActionCell({ agent: App; addedResources: ResourceMap; addOrRemoveResource: ( - kind: ResourceKind, + kind: RequestableResourceKind, resourceId: string, resourceName?: string ) => void; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/ResourceList.tsx b/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/ResourceList.tsx index 1828fce8d7298..2981f1175ebd3 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/ResourceList.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/ResourceList/ResourceList.tsx @@ -30,7 +30,7 @@ import { CustomSort } from 'design/DataTable/types'; import { ResourceLabel, UnifiedResource } from 'teleport/services/agents'; -import { ResourceMap, ResourceKind } from '../resource'; +import { ResourceMap, RequestableResourceKind } from '../resource'; import { Apps } from './Apps'; import { Databases } from './Databases'; @@ -126,7 +126,7 @@ export type ListProps = { onLabelClick: (label: ResourceLabel) => void; addedResources: ResourceMap; addOrRemoveResource: ( - kind: ResourceKind, + kind: RequestableResourceKind, resourceId: string, resourceName?: string ) => void; @@ -135,7 +135,7 @@ export type ListProps = { export type ResourceListProps = { agents: UnifiedResource[]; - selectedResource: ResourceKind; + selectedResource: RequestableResourceKind; // disableRows disable clicking on any buttons (when fetching). disableRows: boolean; } & ListProps; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/index.ts b/web/packages/shared/components/AccessRequests/NewRequest/index.ts index 46181260d19f7..44057733335fa 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/index.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/index.ts @@ -18,5 +18,5 @@ export * from './RequestCheckout'; export * from './ResourceList'; -export type { ResourceMap, ResourceKind } from './resource'; +export type { ResourceMap, RequestableResourceKind } from './resource'; export { getEmptyResourceState } from './resource'; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/kube.test.ts b/web/packages/shared/components/AccessRequests/NewRequest/kube.test.ts new file mode 100644 index 0000000000000..33e136e0dc038 --- /dev/null +++ b/web/packages/shared/components/AccessRequests/NewRequest/kube.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 { checkForUnsupportedKubeRequestModes } from './kube'; + +test('checkForUnsupportedKubeRequestModes: non failed status', () => { + const { + affectedKubeClusterName, + unsupportedKubeRequestModes, + requiresNamespaceSelect, + } = checkForUnsupportedKubeRequestModes({ status: '' }); + + expect(affectedKubeClusterName).toBeFalsy(); + expect(unsupportedKubeRequestModes).toBeFalsy(); + expect(requiresNamespaceSelect).toBeFalsy(); +}); + +test('checkForUnsupportedKubeRequestModes: failed status with unsupported kinds', () => { + const { + affectedKubeClusterName, + unsupportedKubeRequestModes, + requiresNamespaceSelect, + } = checkForUnsupportedKubeRequestModes({ + status: 'failed', + statusText: `Your Teleport roles request_mode field restricts you from requesting kinds [kube_cluster] for Kubernetes cluster "pumpkin-kube-cluster". Allowed kinds: [pod secret]`, + }); + + expect(affectedKubeClusterName).toEqual(`pumpkin-kube-cluster`); + expect(unsupportedKubeRequestModes).toEqual(['pod', 'secret']); + expect(requiresNamespaceSelect).toBeFalsy(); +}); + +test('checkForUnsupportedKubeRequestModes: failed status with supported namespace', () => { + const { + affectedKubeClusterName, + unsupportedKubeRequestModes, + requiresNamespaceSelect, + } = checkForUnsupportedKubeRequestModes({ + status: 'failed', + statusText: `Your Teleport roles request_mode field restricts you from requesting kinds [kube_cluster] for Kubernetes cluster "pumpkin-kube-cluster". Allowed kinds: [pod secret namespace]`, + }); + + expect(affectedKubeClusterName).toEqual(`pumpkin-kube-cluster`); + expect(unsupportedKubeRequestModes).toBeFalsy(); + expect(requiresNamespaceSelect).toBeTruthy(); +}); diff --git a/web/packages/shared/components/AccessRequests/NewRequest/kube.ts b/web/packages/shared/components/AccessRequests/NewRequest/kube.ts new file mode 100644 index 0000000000000..e84ed46c972b4 --- /dev/null +++ b/web/packages/shared/components/AccessRequests/NewRequest/kube.ts @@ -0,0 +1,94 @@ +/** + * 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 { Attempt } from 'shared/hooks/useAttemptNext'; + +import { PendingListItem } from './RequestCheckout'; + +export type KubeNamespaceRequest = { + kubeCluster: string; + search: string; +}; + +/** + * Returns true if the item is a kube cluster or is a namespace + * of the item. + * + * Technically you can request for both a kube_cluster and its subresources + * but it's probably not what a user would expect from the web UI because + * requesting for subresources means narrowing access versus requesting + * access to the whole kube_cluster. + */ +export function isKubeClusterWithNamespaces( + item: PendingListItem, + allItems: PendingListItem[] +) { + return ( + item.kind === 'kube_cluster' && + allItems.find(a => a.kind === 'namespace' && a.id == item.id) + ); +} + +/** + * Checks each data for kube_cluster or namespace + */ +export function checkForUnsupportedKubeRequestModes( + requestRoleAttempt: Attempt +) { + let unsupportedKubeRequestModes: string[]; + let affectedKubeClusterName = ''; + let requiresNamespaceSelect = false; + + if (requestRoleAttempt.status === 'failed') { + const errMsg = requestRoleAttempt.statusText.toLowerCase(); + + if (errMsg.includes('request_mode') && errMsg.includes('allowed kinds: ')) { + let allowedKinds = errMsg.split('allowed kinds: ')[1]; + + // Web UI supports selecting namespace and wildcard + // which basically means requiring namespace. + if (allowedKinds.includes('*') || allowedKinds.includes('namespace')) { + requiresNamespaceSelect = true; + } else { + if (allowedKinds.startsWith('[')) { + allowedKinds = allowedKinds.slice(1, -1); + } + unsupportedKubeRequestModes = allowedKinds.split(' '); + } + + const initialSplit = errMsg.split('for kubernetes cluster "'); + if (initialSplit.length > 1) { + affectedKubeClusterName = initialSplit[1] + .split('". allowed kinds')[0] + .trim(); + } + + return { + affectedKubeClusterName, + requiresNamespaceSelect, + unsupportedKubeRequestModes, + }; + } + } + + return { + affectedKubeClusterName, + unsupportedKubeRequestModes, + requiresNamespaceSelect, + }; +} diff --git a/web/packages/shared/components/AccessRequests/NewRequest/resource.ts b/web/packages/shared/components/AccessRequests/NewRequest/resource.ts index 42070e9448283..f56ad58110d25 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/resource.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/resource.ts @@ -17,16 +17,21 @@ */ import { ResourceIdKind } from 'teleport/services/agents'; +import { KubeResourceKind } from 'teleport/services/kube'; /** Available request kinds for resource-based and role-based access requests. */ -export type ResourceKind = ResourceIdKind | 'role' | 'resource'; +export type RequestableResourceKind = + | ResourceIdKind + | 'role' + | 'resource' + | Exclude; /** * Maps a resource ID (usually agent name) to resource description (usually the * same, but not necessarily). */ export type ResourceMap = { - [K in ResourceIdKind | 'role']: Record; + [K in Exclude]: Record; }; export function getEmptyResourceState(): ResourceMap { @@ -39,5 +44,6 @@ export function getEmptyResourceState(): ResourceMap { windows_desktop: {}, role: {}, saml_idp_service_provider: {}, + namespace: {}, }; } diff --git a/web/packages/shared/components/AccessRequests/Shared/utils.ts b/web/packages/shared/components/AccessRequests/Shared/utils.ts index 1ac9a291328bf..6185e568c4c21 100644 --- a/web/packages/shared/components/AccessRequests/Shared/utils.ts +++ b/web/packages/shared/components/AccessRequests/Shared/utils.ts @@ -40,6 +40,7 @@ export function getNumAddedResources(addedResources: ResourceMap) { Object.keys(addedResources.kube_cluster).length + Object.keys(addedResources.user_group).length + Object.keys(addedResources.windows_desktop).length + - Object.keys(addedResources.saml_idp_service_provider).length + Object.keys(addedResources.saml_idp_service_provider).length + + Object.keys(addedResources.namespace).length ); } diff --git a/web/packages/shared/components/FieldSelect/FieldSelect.tsx b/web/packages/shared/components/FieldSelect/FieldSelect.tsx index 90e875ee9868c..66007b24f18fc 100644 --- a/web/packages/shared/components/FieldSelect/FieldSelect.tsx +++ b/web/packages/shared/components/FieldSelect/FieldSelect.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { GroupBase } from 'react-select'; +import { GroupBase, OptionsOrGroups } from 'react-select'; import { useAsync } from 'shared/hooks/useAsync'; @@ -69,7 +69,28 @@ export function FieldSelectAsync< Opt = Option, IsMulti extends boolean = false, Group extends GroupBase = GroupBase, ->(props: AsyncSelectProps & FieldProps) { +>( + props: AsyncSelectProps & + FieldProps & { + /** + * A function that sets the initial options, after the initial options are + * finished fetching (triggered by when user clicks on the select component + * that renders the dropdown menu). + * + * Select async doesn't provide an option for "on menu open, load options". + * There is only "on render load, or provide default array of options". + * There are some cases where there can be many select async components rendered + * (eg: bulk adding kube clusters to an access request) and users may not be + * required to select anything from the select async dropdown, so this provides + * a way to load options only on need (menu open) and save wasteful api calls. + * + * Requires: + * - base.onMenuOpen to be defined + * - defaultOptions to be an array + */ + initOptionsOnMenuOpen?(options: OptionsOrGroups): void; + } +) { const { base, wrapper, others } = splitSelectProps< Opt, IsMulti, @@ -78,15 +99,35 @@ export function FieldSelectAsync< >(props, { defaultOptions: true, }); - const { defaultOptions, loadOptions, ...styles } = others; + const { defaultOptions, loadOptions, initOptionsOnMenuOpen, ...styles } = + others; const [attempt, runAttempt] = useAsync(resolveUndefinedOptions(loadOptions)); + + async function onMenuOpen() { + if (!base.onMenuOpen) return; + + base.onMenuOpen(); + + if ( + initOptionsOnMenuOpen && + defaultOptions && + Array.isArray(defaultOptions) && + defaultOptions.length == 0 + ) { + const [options, error] = await runAttempt('', null); + if (!error) { + return others.initOptionsOnMenuOpen(options); + } + } + } + return ( {...base} + onMenuOpen={onMenuOpen} defaultOptions={defaultOptions} loadOptions={async (value, callback) => { - console.log('loading'); const [options, error] = await runAttempt(value, callback); if (error) { return []; @@ -97,6 +138,9 @@ export function FieldSelectAsync< if (attempt.status === 'error') { return `Could not load options: ${attempt.statusText}`; } + if (attempt.status === 'processing') { + return 'Loading...'; + } return base.noOptionsMessage?.(obj) ?? 'No options'; }} /> diff --git a/web/packages/shared/components/FieldSelect/shared.tsx b/web/packages/shared/components/FieldSelect/shared.tsx index a25768f5c2df1..03857ea3ac2ee 100644 --- a/web/packages/shared/components/FieldSelect/shared.tsx +++ b/web/packages/shared/components/FieldSelect/shared.tsx @@ -191,6 +191,10 @@ export function splitSelectProps< markAsError, maxMenuHeight, menuIsOpen, + onMenuOpen, + onMenuClose, + closeMenuOnSelect, + hideSelectedOptions, menuPosition, name, noOptionsMessage, @@ -222,8 +226,12 @@ export function splitSelectProps< isMulti, isSearchable, maxMenuHeight, - menuIsOpen, menuPosition, + menuIsOpen, + onMenuOpen, + onMenuClose, + closeMenuOnSelect, + hideSelectedOptions, name, noOptionsMessage, onBlur, @@ -267,6 +275,10 @@ type KeysRemovedFromOthers = | 'maxMenuHeight' | 'menuIsOpen' | 'menuPosition' + | 'onMenuOpen' + | 'onMenuClose' + | 'closeMenuOnSelect' + | 'hideSelectedOptions' | 'name' | 'noOptionsMessage' | 'onBlur' diff --git a/web/packages/shared/services/accessRequests/accessRequests.ts b/web/packages/shared/services/accessRequests/accessRequests.ts index 3b5517c393b4b..855e71e777ca3 100644 --- a/web/packages/shared/services/accessRequests/accessRequests.ts +++ b/web/packages/shared/services/accessRequests/accessRequests.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { ResourceIdKind } from 'teleport/services/agents'; +import { RequestableResourceKind } from 'shared/components/AccessRequests/NewRequest/resource'; export type RequestState = | 'NONE' @@ -76,7 +76,7 @@ export type Resource = { // ResourceID is a unique identifier for a teleport resource. export type ResourceId = { // kind is the resource (agent) kind. - kind: ResourceIdKind; + kind: RequestableResourceKind; // name is the name of the specific resource. name: string; // clusterName is the name of cluster. diff --git a/web/packages/shared/utils/text.test.ts b/web/packages/shared/utils/text.test.ts index 0cd297f7b20d5..a76bb90fbb594 100644 --- a/web/packages/shared/utils/text.test.ts +++ b/web/packages/shared/utils/text.test.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { pluralize, capitalizeFirstLetter } from './text'; +import { pluralize, capitalizeFirstLetter, listToSentence } from './text'; test('pluralize', () => { expect(pluralize(0, 'apple')).toBe('apples'); @@ -30,3 +30,39 @@ test('capitalizeFirstLetter', () => { expect(capitalizeFirstLetter('hello')).toBe('Hello'); expect(capitalizeFirstLetter('')).toBe(''); }); + +describe('listToSentence()', () => { + const testCases = [ + { + name: 'no words', + list: [], + expected: '', + }, + { + name: 'one word', + list: ['a'], + expected: 'a', + }, + { + name: 'two words', + list: ['a', 'b'], + expected: 'a and b', + }, + { + name: 'three words', + list: ['a', 'b', 'c'], + expected: 'a, b and c', + }, + { + name: 'lost of words', + list: ['a', 'b', 'c', 'd', 'e', 'f', 'g'], + expected: 'a, b, c, d, e, f and g', + }, + ]; + + test.each(testCases)('$name', ({ list, expected }) => { + const originalList = [...list]; + expect(listToSentence(list)).toEqual(expected); + expect(list).toEqual(originalList); + }); +}); diff --git a/web/packages/shared/utils/text.ts b/web/packages/shared/utils/text.ts index a424ea5bd9b14..37635c4c0bad2 100644 --- a/web/packages/shared/utils/text.ts +++ b/web/packages/shared/utils/text.ts @@ -39,3 +39,28 @@ export function capitalizeFirstLetter(str: string) { } return str[0].toUpperCase() + str.slice(1); } + +/** + * Takes a list of words and converts it into a sentence. + * eg: given list ["apple", "banana", "carrot"], converts + * to string "apple, banana and carrot" + * + * Does not modify original list. + */ +export function listToSentence(listOfWords: string[]) { + if (!listOfWords || !listOfWords.length) { + return ''; + } + + if (listOfWords.length == 1) { + return listOfWords[0]; + } + + if (listOfWords.length == 2) { + return `${listOfWords[0]} and ${listOfWords[1]}`; + } + + const copiedList = [...listOfWords]; + const lastWord = copiedList.pop(); + return `${copiedList.join(', ')} and ${lastWord}`; +} diff --git a/web/packages/teleport/src/AccessRequests/service.ts b/web/packages/teleport/src/AccessRequests/service.ts index 20637193ef24a..03b7e158d3f3b 100644 --- a/web/packages/teleport/src/AccessRequests/service.ts +++ b/web/packages/teleport/src/AccessRequests/service.ts @@ -18,7 +18,8 @@ import { formatDuration } from 'date-fns'; -import { ResourceIdKind } from 'teleport/services/agents'; +import { RequestableResourceKind } from 'shared/components/AccessRequests/NewRequest/resource'; + import api from 'teleport/services/api'; import cfg from 'teleport/config'; import { @@ -41,7 +42,7 @@ export async function createAccessRequest( reason, roles, resourceIds: resources.map(item => ({ - kind: item.type as ResourceIdKind, + kind: item.type as RequestableResourceKind, name: item.id, clusterName: clusterId, })), diff --git a/web/packages/teleport/src/AccessRequests/types.ts b/web/packages/teleport/src/AccessRequests/types.ts index 38fa71386729e..de08d61605961 100644 --- a/web/packages/teleport/src/AccessRequests/types.ts +++ b/web/packages/teleport/src/AccessRequests/types.ts @@ -16,15 +16,15 @@ * along with this program. If not, see . */ -import type { Option } from 'shared/components/Select'; +import { RequestableResourceKind } from 'shared/components/AccessRequests/NewRequest/resource'; -import type { ResourceIdKind } from 'teleport/services/agents'; +import type { Option } from 'shared/components/Select'; export type DurationOption = Option; export interface Resource { id: { - kind: ResourceIdKind; + kind: RequestableResourceKind; name: string; clusterName: string; subResourceName?: string; @@ -38,7 +38,7 @@ export interface Resource { type RequestState = 'NONE' | 'PENDING' | 'APPROVED' | 'DENIED' | 'APPLIED' | ''; export interface ResourceId { - kind: ResourceIdKind; + kind: RequestableResourceKind; name: string; clusterName: string; subResourceName?: string; diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index b1e184d7d821d..a429bc7f60ef0 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -1270,7 +1270,7 @@ export interface UrlKubeResourcesParams { searchAsRoles?: 'yes' | ''; kubeNamespace?: string; kubeCluster: string; - kind: KubeResourceKind; + kind: Omit; } export interface UrlDeployServiceIamConfigureScriptParams { diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx index 44e81b59b3822..8e0904efbeee2 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx @@ -270,6 +270,11 @@ export function AccessRequestCheckout() { setPendingRequestTtl={setPendingRequestTtl} startTime={startTime} onStartTimeChange={onStartTimeChange} + // TODO: these are placeholders to satisy linters. + // There is a split PR that handles teleterm support + // that will be merged right after this one (once both are approved) + bulkToggleKubeResources={() => null} + fetchKubeNamespaces={() => null} /> )} diff --git a/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/NewRequest.tsx b/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/NewRequest.tsx index ba0b18fe7ad42..64bf86013b3b7 100644 --- a/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/NewRequest.tsx +++ b/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/NewRequest.tsx @@ -258,6 +258,7 @@ function toResourceMap(request: PendingAccessRequest): ResourceMap { db: {}, app: {}, saml_idp_service_provider: {}, + namespace: {}, }; if (request.kind === 'role') { request.roles.forEach(role => { From c394da09d304c3b42b996075803177eca1642da6 Mon Sep 17 00:00:00 2001 From: Stephen Levine Date: Mon, 28 Oct 2024 12:05:29 -0400 Subject: [PATCH 12/22] [teleport-update] Add linking into /usr/local (#47879) * clean up download logic * Finish installer tests * fips and ent support * feedback * move enterprise/fips to webapi * wip * wip2 * add cleanup * fix extract * wip * fix tests * remove safety * cleanup * cleanup extract * cleanup * cleanup * fix bugs * cleanup --- lib/autoupdate/agent/installer.go | 162 ++++++++++- lib/autoupdate/agent/installer_test.go | 267 +++++++++++++++++- .../already_disabled.golden | 1 + .../TestUpdater_Disable/enabled.golden | 1 + .../TestUpdater_Enable/already_enabled.golden | 1 + .../backup_version_kept_for_validation.golden | 10 + .../backup_version_removed_on_install.golden | 10 + .../config_does_not_exist.golden | 1 + .../config_from_file.golden | 1 + .../config_from_user.golden | 1 + .../version_already_installed.golden | 1 + lib/autoupdate/agent/updater.go | 56 +++- lib/autoupdate/agent/updater_test.go | 59 +++- lib/utils/unpack.go | 66 ++++- tool/teleport-update/main.go | 20 +- 15 files changed, 618 insertions(+), 39 deletions(-) create mode 100644 lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_kept_for_validation.golden create mode 100644 lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_removed_on_install.golden diff --git a/lib/autoupdate/agent/installer.go b/lib/autoupdate/agent/installer.go index e31813866eacf..4da41e8e55509 100644 --- a/lib/autoupdate/agent/installer.go +++ b/lib/autoupdate/agent/installer.go @@ -34,6 +34,7 @@ import ( "text/template" "time" + "github.com/google/renameio/v2" "github.com/gravitational/trace" "github.com/gravitational/teleport/lib/utils" @@ -44,11 +45,33 @@ const ( checksumHexLen = sha256.Size * 2 // bytes to hex ) +var ( + // tgzExtractPaths describes how to extract the Teleport tgz. + // See utils.Extract for more details on how this list is parsed. + // Paths must use tarball-style / separators (not filepath). + tgzExtractPaths = []utils.ExtractPath{ + {Src: "teleport/examples/systemd/teleport.service", Dst: "etc/systemd/teleport.service"}, + {Src: "teleport/examples", Skip: true}, + {Src: "teleport/install", Skip: true}, + {Src: "teleport/README.md", Dst: "share/README.md"}, + {Src: "teleport/CHANGELOG.md", Dst: "share/CHANGELOG.md"}, + {Src: "teleport/VERSION", Dst: "share/VERSION"}, + {Src: "teleport", Dst: "bin"}, + } + + // servicePath contains the path to the Teleport SystemD service within the version directory. + servicePath = filepath.Join("etc", "systemd", "teleport.service") +) + // LocalInstaller manages the creation and removal of installations // of Teleport. type LocalInstaller struct { // InstallDir contains each installation, named by version. InstallDir string + // LinkBinDir contains symlinks to the linked installation's binaries. + LinkBinDir string + // LinkServiceDir contains a symlink to the linked installation's systemd service. + LinkServiceDir string // HTTP is an HTTP client for downloading Teleport. HTTP *http.Client // Log contains a logger. @@ -59,15 +82,32 @@ type LocalInstaller struct { ReservedFreeInstallDisk uint64 } +// ErrLinked is returned when a linked version cannot be removed. +var ErrLinked = errors.New("linked version cannot be removed") + // Remove a Teleport version directory from InstallDir. // This function is idempotent. func (li *LocalInstaller) Remove(ctx context.Context, version string) error { - versionDir := filepath.Join(li.InstallDir, version) - sumPath := filepath.Join(versionDir, checksumType) + // os.RemoveAll is dangerous because it can remove an entire directory tree. + // We must validate the version to ensure that we remove only a single path + // element under the InstallDir, and not InstallDir or its parents. + // versionDir performs these validations. + versionDir, err := li.versionDir(version) + if err != nil { + return trace.Wrap(err) + } + + linked, err := li.isLinked(versionDir) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return trace.Errorf("failed to determine if linked: %w", err) + } + if linked { + return trace.Wrap(ErrLinked) + } // invalidate checksum first, to protect against partially-removed // directory with valid checksum. - err := os.Remove(sumPath) + err = os.Remove(filepath.Join(versionDir, checksumType)) if err != nil && !errors.Is(err, os.ErrNotExist) { return trace.Wrap(err) } @@ -80,7 +120,10 @@ func (li *LocalInstaller) Remove(ctx context.Context, version string) error { // Install a Teleport version directory in InstallDir. // This function is idempotent. func (li *LocalInstaller) Install(ctx context.Context, version, template string, flags InstallFlags) error { - versionDir := filepath.Join(li.InstallDir, version) + versionDir, err := li.versionDir(version) + if err != nil { + return trace.Wrap(err) + } sumPath := filepath.Join(versionDir, checksumType) // generate download URI from template @@ -154,7 +197,7 @@ func (li *LocalInstaller) Install(ctx context.Context, version, template string, return trace.Errorf("failed to extract teleport: %w", err) } // Write the checksum last. This marks the version directory as valid. - err = os.WriteFile(sumPath, []byte(hex.EncodeToString(newSum)), 0755) + err = renameio.WriteFile(sumPath, []byte(hex.EncodeToString(newSum)), 0755) if err != nil { return trace.Errorf("failed to write checksum: %w", err) } @@ -208,6 +251,7 @@ func readChecksum(path string) ([]byte, error) { func (li *LocalInstaller) getChecksum(ctx context.Context, url string) ([]byte, error) { ctx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, trace.Wrap(err) @@ -292,8 +336,7 @@ func (li *LocalInstaller) extract(ctx context.Context, dstDir string, src io.Rea } li.Log.InfoContext(ctx, "Extracting Teleport tarball.", "path", dstDir, "size", max) - // TODO(sclevine): add variadic arg to Extract to extract teleport/ subdir into bin/. - err = utils.Extract(zr, dstDir) + err = utils.Extract(zr, dstDir, tgzExtractPaths...) if err != nil { return trace.Wrap(err) } @@ -315,3 +358,108 @@ func uncompressedSize(f io.Reader) (int64, error) { } return n, nil } + +// List installed versions of Teleport. +func (li *LocalInstaller) List(ctx context.Context) (versions []string, err error) { + entries, err := os.ReadDir(li.InstallDir) + if err != nil { + return nil, trace.Wrap(err) + } + for _, entry := range entries { + if !entry.IsDir() { + continue + } + versions = append(versions, entry.Name()) + } + return versions, nil +} + +// Link the specified version into the system LinkBinDir. +func (li *LocalInstaller) Link(ctx context.Context, version string) error { + versionDir, err := li.versionDir(version) + if err != nil { + return trace.Wrap(err) + } + + // ensure target directories exist before trying to create links + err = os.MkdirAll(li.LinkBinDir, 0755) + if err != nil { + return trace.Wrap(err) + } + err = os.MkdirAll(li.LinkServiceDir, 0755) + if err != nil { + return trace.Wrap(err) + } + + // create binary links + binDir := filepath.Join(versionDir, "bin") + entries, err := os.ReadDir(binDir) + if err != nil { + return trace.Errorf("failed to find Teleport binary directory: %w", err) + } + var linked int + for _, entry := range entries { + if entry.IsDir() { + continue + } + err := renameio.Symlink(filepath.Join(binDir, entry.Name()), filepath.Join(li.LinkBinDir, entry.Name())) + if err != nil { + return trace.Wrap(err) + } + linked++ + } + if linked == 0 { + return trace.Errorf("no binaries available to link") + } + + // create systemd service link + service := filepath.Join(versionDir, servicePath) + err = renameio.Symlink(service, filepath.Join(li.LinkServiceDir, filepath.Base(servicePath))) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// versionDir returns the storage directory for a Teleport version. +// versionDir will fail if the version cannot be used to construct the directory name. +// For example, it ensures that ".." cannot be provided to return a system directory. +func (li *LocalInstaller) versionDir(version string) (string, error) { + installDir, err := filepath.Abs(li.InstallDir) + if err != nil { + return "", trace.Wrap(err) + } + versionDir := filepath.Join(installDir, version) + if filepath.Dir(versionDir) != filepath.Clean(installDir) { + return "", trace.Errorf("refusing to directory outside of version directory") + } + return versionDir, nil +} + +// isLinked returns true if any binaries or services in versionDir are linked. +// Returns os.ErrNotExist error if the versionDir does not exist. +func (li *LocalInstaller) isLinked(versionDir string) (bool, error) { + binDir := filepath.Join(versionDir, "bin") + entries, err := os.ReadDir(binDir) + if err != nil { + return false, trace.Wrap(err) + } + for _, entry := range entries { + if entry.IsDir() { + continue + } + v, err := os.Readlink(filepath.Join(li.LinkBinDir, entry.Name())) + if err != nil { + continue + } + if filepath.Clean(v) == filepath.Join(binDir, entry.Name()) { + return true, nil + } + } + v, err := os.Readlink(filepath.Join(li.LinkServiceDir, filepath.Base(servicePath))) + if err != nil { + return false, nil + } + return filepath.Clean(v) == + filepath.Join(versionDir, servicePath), nil +} diff --git a/lib/autoupdate/agent/installer_test.go b/lib/autoupdate/agent/installer_test.go index be778f7bcf16a..2602704208855 100644 --- a/lib/autoupdate/agent/installer_test.go +++ b/lib/autoupdate/agent/installer_test.go @@ -40,7 +40,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestTeleportInstaller_Install(t *testing.T) { +func TestLocalInstaller_Install(t *testing.T) { t.Parallel() const version = "new-version" @@ -136,13 +136,15 @@ func TestTeleportInstaller_Install(t *testing.T) { require.Equal(t, expectedPath, dlPath) require.Equal(t, expectedPath+"."+checksumType, shaPath) - teleportVersion, err := os.ReadFile(filepath.Join(dir, version, "teleport")) - require.NoError(t, err) - require.Equal(t, version, string(teleportVersion)) - - tshVersion, err := os.ReadFile(filepath.Join(dir, version, "tsh")) - require.NoError(t, err) - require.Equal(t, version, string(tshVersion)) + for _, p := range []string{ + filepath.Join(dir, version, "etc", "systemd", "teleport.service"), + filepath.Join(dir, version, "bin", "teleport"), + filepath.Join(dir, version, "bin", "tsh"), + } { + v, err := os.ReadFile(p) + require.NoError(t, err) + require.Equal(t, version, string(v)) + } sum, err := os.ReadFile(filepath.Join(dir, version, checksumType)) require.NoError(t, err) @@ -163,8 +165,9 @@ func testTGZ(t *testing.T, version string) (tgz *bytes.Buffer, shasum string) { var files = []struct { Name, Body string }{ - {"teleport", version}, - {"tsh", version}, + {"teleport/examples/systemd/teleport.service", version}, + {"teleport/teleport", version}, + {"teleport/tsh", version}, } for _, file := range files { hdr := &tar.Header{ @@ -187,3 +190,247 @@ func testTGZ(t *testing.T, version string) (tgz *bytes.Buffer, shasum string) { } return &buf, hex.EncodeToString(sha.Sum(nil)) } + +func TestLocalInstaller_Link(t *testing.T) { + t.Parallel() + const version = "new-version" + + tests := []struct { + name string + dirs []string + files []string + + links []string + errMatch string + }{ + { + name: "present", + dirs: []string{ + "bin", + "bin/somedir", + "etc", + "etc/systemd", + "etc/systemd/somedir", + "somedir", + }, + files: []string{ + "bin/teleport", + "bin/tsh", + "bin/tbot", + servicePath, + "README", + }, + + links: []string{ + "bin/teleport", + "bin/tsh", + "bin/tbot", + "lib/systemd/system/teleport.service", + }, + }, + { + name: "no links", + files: []string{"README"}, + dirs: []string{"bin"}, + + errMatch: "no binaries", + }, + { + name: "no bin directory", + files: []string{"README"}, + + errMatch: "binary directory", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + versionsDir := t.TempDir() + versionDir := filepath.Join(versionsDir, version) + err := os.MkdirAll(versionDir, 0o755) + require.NoError(t, err) + + for _, d := range tt.dirs { + err := os.Mkdir(filepath.Join(versionDir, d), os.ModePerm) + require.NoError(t, err) + } + for _, n := range tt.files { + err := os.WriteFile(filepath.Join(versionDir, n), []byte(filepath.Base(n)), os.ModePerm) + require.NoError(t, err) + } + + linkDir := t.TempDir() + + installer := &LocalInstaller{ + InstallDir: versionsDir, + LinkBinDir: filepath.Join(linkDir, "bin"), + LinkServiceDir: filepath.Join(linkDir, "lib/systemd/system"), + Log: slog.Default(), + } + ctx := context.Background() + err = installer.Link(ctx, version) + if tt.errMatch != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.errMatch) + return + } + require.NoError(t, err) + + for _, link := range tt.links { + v, err := os.ReadFile(filepath.Join(linkDir, link)) + require.NoError(t, err) + require.Equal(t, filepath.Base(link), string(v)) + } + }) + } +} + +func TestLocalInstaller_Remove(t *testing.T) { + t.Parallel() + const version = "existing-version" + + tests := []struct { + name string + dirs []string + files []string + createVersion string + linkedVersion string + removeVersion string + + errMatch string + }{ + { + name: "present", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: version, + }, + { + name: "present missing checksum", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{"bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: version, + }, + { + name: "not present", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: "missing-version", + }, + { + name: "version linked", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + linkedVersion: version, + removeVersion: version, + + errMatch: ErrLinked.Error(), + }, + { + name: "version empty", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: "", + + errMatch: "outside", + }, + { + name: "version has path", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: "one/two", + + errMatch: "outside", + }, + { + name: "version is ..", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: "..", + + errMatch: "outside", + }, + { + name: "version is .", + dirs: []string{"bin", "bin/somedir", "somedir"}, + files: []string{checksumType, "bin/teleport", "bin/tsh", "bin/tbot", "README"}, + createVersion: version, + removeVersion: ".", + + errMatch: "outside", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + versionsDir := t.TempDir() + versionDir := filepath.Join(versionsDir, tt.createVersion) + err := os.MkdirAll(versionDir, 0o755) + require.NoError(t, err) + + for _, d := range tt.dirs { + err := os.Mkdir(filepath.Join(versionDir, d), os.ModePerm) + require.NoError(t, err) + } + for _, n := range tt.files { + err := os.WriteFile(filepath.Join(versionDir, n), []byte(filepath.Base(n)), os.ModePerm) + require.NoError(t, err) + } + + linkDir := t.TempDir() + + installer := &LocalInstaller{ + InstallDir: versionsDir, + LinkBinDir: linkDir, + LinkServiceDir: linkDir, + Log: slog.Default(), + } + ctx := context.Background() + + if tt.linkedVersion != "" { + err = installer.Link(ctx, tt.linkedVersion) + require.NoError(t, err) + } + err = installer.Remove(ctx, tt.removeVersion) + if tt.errMatch != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.errMatch) + return + } + require.NoError(t, err) + _, err = os.Stat(filepath.Join(versionDir, "bin", tt.removeVersion)) + require.ErrorIs(t, err, os.ErrNotExist) + }) + } +} + +func TestLocalInstaller_List(t *testing.T) { + installDir := t.TempDir() + versions := []string{"v1", "v2"} + + for _, d := range versions { + err := os.Mkdir(filepath.Join(installDir, d), os.ModePerm) + require.NoError(t, err) + } + for _, n := range []string{"file1", "file2"} { + err := os.WriteFile(filepath.Join(installDir, n), []byte(filepath.Base(n)), os.ModePerm) + require.NoError(t, err) + } + installer := &LocalInstaller{ + InstallDir: installDir, + Log: slog.Default(), + } + ctx := context.Background() + versions, err := installer.List(ctx) + require.NoError(t, err) + require.Equal(t, []string{"v1", "v2"}, versions) +} diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Disable/already_disabled.golden b/lib/autoupdate/agent/testdata/TestUpdater_Disable/already_disabled.golden index e8773a6d88b7f..2ddb840b01794 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Disable/already_disabled.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Disable/already_disabled.golden @@ -7,3 +7,4 @@ spec: enabled: false status: active_version: "" + backup_version: "" diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Disable/enabled.golden b/lib/autoupdate/agent/testdata/TestUpdater_Disable/enabled.golden index e8773a6d88b7f..2ddb840b01794 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Disable/enabled.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Disable/enabled.golden @@ -7,3 +7,4 @@ spec: enabled: false status: active_version: "" + backup_version: "" diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/already_enabled.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/already_enabled.golden index e03f369eb1017..9dd03b7888da4 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Enable/already_enabled.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/already_enabled.golden @@ -7,3 +7,4 @@ spec: enabled: true status: active_version: 16.3.0 + backup_version: old-version diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_kept_for_validation.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_kept_for_validation.golden new file mode 100644 index 0000000000000..77829fb91706a --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_kept_for_validation.golden @@ -0,0 +1,10 @@ +version: v1 +kind: update_config +spec: + proxy: localhost + group: "" + url_template: "" + enabled: true +status: + active_version: 16.3.0 + backup_version: backup-version diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_removed_on_install.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_removed_on_install.golden new file mode 100644 index 0000000000000..9dd03b7888da4 --- /dev/null +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/backup_version_removed_on_install.golden @@ -0,0 +1,10 @@ +version: v1 +kind: update_config +spec: + proxy: localhost + group: "" + url_template: "" + enabled: true +status: + active_version: 16.3.0 + backup_version: old-version diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_does_not_exist.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_does_not_exist.golden index e03f369eb1017..d9e09a2c95d71 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_does_not_exist.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_does_not_exist.golden @@ -7,3 +7,4 @@ spec: enabled: true status: active_version: 16.3.0 + backup_version: "" diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_file.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_file.golden index b172d858bc55a..61e41f76ca234 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_file.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_file.golden @@ -7,3 +7,4 @@ spec: enabled: true status: active_version: 16.3.0 + backup_version: old-version diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_user.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_user.golden index bb9ce8b9d8fa8..c1f0fd166b497 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_user.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/config_from_user.golden @@ -7,3 +7,4 @@ spec: enabled: true status: active_version: new-version + backup_version: old-version diff --git a/lib/autoupdate/agent/testdata/TestUpdater_Enable/version_already_installed.golden b/lib/autoupdate/agent/testdata/TestUpdater_Enable/version_already_installed.golden index e03f369eb1017..d9e09a2c95d71 100644 --- a/lib/autoupdate/agent/testdata/TestUpdater_Enable/version_already_installed.golden +++ b/lib/autoupdate/agent/testdata/TestUpdater_Enable/version_already_installed.golden @@ -7,3 +7,4 @@ spec: enabled: true status: active_version: 16.3.0 + backup_version: "" diff --git a/lib/autoupdate/agent/updater.go b/lib/autoupdate/agent/updater.go index 59df5f0b3ba85..ade0704607cb9 100644 --- a/lib/autoupdate/agent/updater.go +++ b/lib/autoupdate/agent/updater.go @@ -86,6 +86,8 @@ type UpdateSpec struct { type UpdateStatus struct { // ActiveVersion is the currently active Teleport version. ActiveVersion string `yaml:"active_version"` + // BackupVersion is the last working version of Teleport. + BackupVersion string `yaml:"backup_version"` } // NewLocalUpdater returns a new Updater that auto-updates local @@ -112,15 +114,23 @@ func NewLocalUpdater(cfg LocalUpdaterConfig) (*Updater, error) { if cfg.Log == nil { cfg.Log = slog.Default() } + if cfg.LinkDir == "" { + cfg.LinkDir = "/usr/local" + } + if cfg.VersionsDir == "" { + cfg.VersionsDir = filepath.Join(libdefaults.DataDir, "versions") + } return &Updater{ Log: cfg.Log, Pool: certPool, InsecureSkipVerify: cfg.InsecureSkipVerify, ConfigPath: filepath.Join(cfg.VersionsDir, updateConfigName), Installer: &LocalInstaller{ - InstallDir: cfg.VersionsDir, - HTTP: client, - Log: cfg.Log, + InstallDir: cfg.VersionsDir, + LinkBinDir: filepath.Join(cfg.LinkDir, "bin"), + LinkServiceDir: filepath.Join(cfg.LinkDir, "lib", "systemd", "system"), + HTTP: client, + Log: cfg.Log, ReservedFreeTmpDisk: reservedFreeDisk, ReservedFreeInstallDisk: reservedFreeDisk, @@ -140,6 +150,8 @@ type LocalUpdaterConfig struct { DownloadTimeout time.Duration // VersionsDir for installing Teleport (usually /var/lib/teleport/versions). VersionsDir string + // LinkDir for installing Teleport (usually /usr/local). + LinkDir string } // Updater implements the agent-local logic for Teleport agent auto-updates. @@ -161,6 +173,11 @@ type Installer interface { // Install the Teleport agent at version from the download template. // This function must be idempotent. Install(ctx context.Context, version, template string, flags InstallFlags) error + // Link the Teleport agent at version into the system location. + // This function must be idempotent. + Link(ctx context.Context, version string) error + // List the installed versions of Teleport. + List(ctx context.Context) (versions []string, err error) // Remove the Teleport agent at version. // This function must be idempotent. Remove(ctx context.Context, version string) error @@ -242,6 +259,19 @@ func (u *Updater) Enable(ctx context.Context, override OverrideConfig) error { if desiredVersion == "" { return trace.Errorf("agent version not available from Teleport cluster") } + switch cfg.Status.BackupVersion { + case "", desiredVersion, cfg.Status.ActiveVersion: + default: + if desiredVersion == cfg.Status.ActiveVersion { + // Keep backup version if we are only verifying active version + break + } + err := u.Installer.Remove(ctx, cfg.Status.BackupVersion) + if err != nil { + // this could happen if it was already removed due to a failed installation + u.Log.WarnContext(ctx, "Failed to remove backup version of Teleport before new install.", "error", err) + } + } // If the active version and target don't match, kick off upgrade. template := cfg.Spec.URLTemplate if template == "" { @@ -249,14 +279,30 @@ func (u *Updater) Enable(ctx context.Context, override OverrideConfig) error { } err = u.Installer.Install(ctx, desiredVersion, template, 0) // TODO(sclevine): add web API for flags if err != nil { - return trace.Wrap(err) + return trace.Errorf("failed to install: %w", err) + } + err = u.Installer.Link(ctx, desiredVersion) + if err != nil { + return trace.Errorf("failed to link: %w", err) } if cfg.Status.ActiveVersion != desiredVersion { + cfg.Status.BackupVersion = cfg.Status.ActiveVersion + cfg.Status.ActiveVersion = desiredVersion u.Log.InfoContext(ctx, "Target version successfully installed.", "version", desiredVersion) } else { u.Log.InfoContext(ctx, "Target version successfully validated.", "version", desiredVersion) } - cfg.Status.ActiveVersion = desiredVersion + if v := cfg.Status.BackupVersion; v != "" { + u.Log.InfoContext(ctx, "Backup version set.", "version", v) + } + + versions, err := u.Installer.List(ctx) + if err != nil { + return trace.Errorf("failed to list installed versions: %w", err) + } + if n := len(versions); n > 2 { + u.Log.WarnContext(ctx, "More than 2 versions of Teleport installed. Version directory may need cleanup to save space.", "count", n) + } // Always write the configuration file if enable succeeds. if err := u.writeConfig(u.ConfigPath, cfg); err != nil { diff --git a/lib/autoupdate/agent/updater_test.go b/lib/autoupdate/agent/updater_test.go index 6568fbaede9e2..d6d0128316c20 100644 --- a/lib/autoupdate/agent/updater_test.go +++ b/lib/autoupdate/agent/updater_test.go @@ -130,6 +130,7 @@ func TestUpdater_Enable(t *testing.T) { userCfg OverrideConfig installErr error + removedVersion string installedVersion string installedTemplate string errMatch string @@ -221,6 +222,34 @@ func TestUpdater_Enable(t *testing.T) { installedVersion: "16.3.0", installedTemplate: cdnURITemplate, }, + { + name: "backup version removed on install", + cfg: &UpdateConfig{ + Version: updateConfigVersion, + Kind: updateConfigKind, + Status: UpdateStatus{ + ActiveVersion: "old-version", + BackupVersion: "backup-version", + }, + }, + installedVersion: "16.3.0", + installedTemplate: cdnURITemplate, + removedVersion: "backup-version", + }, + { + name: "backup version kept for validation", + cfg: &UpdateConfig{ + Version: updateConfigVersion, + Kind: updateConfigKind, + Status: UpdateStatus{ + ActiveVersion: "16.3.0", + BackupVersion: "backup-version", + }, + }, + installedVersion: "16.3.0", + installedTemplate: cdnURITemplate, + removedVersion: "", + }, { name: "config does not exist", installedVersion: "16.3.0", @@ -263,13 +292,29 @@ func TestUpdater_Enable(t *testing.T) { }) require.NoError(t, err) - var installedVersion, installedTemplate string + var ( + installedVersion string + installedTemplate string + linkedVersion string + removedVersion string + ) updater.Installer = &testInstaller{ FuncInstall: func(_ context.Context, version, template string, _ InstallFlags) error { installedVersion = version installedTemplate = template return tt.installErr }, + FuncLink: func(_ context.Context, version string) error { + linkedVersion = version + return nil + }, + FuncList: func(_ context.Context) (versions []string, err error) { + return []string{"old"}, nil + }, + FuncRemove: func(_ context.Context, version string) error { + removedVersion = version + return nil + }, } ctx := context.Background() @@ -282,6 +327,8 @@ func TestUpdater_Enable(t *testing.T) { require.NoError(t, err) require.Equal(t, tt.installedVersion, installedVersion) require.Equal(t, tt.installedTemplate, installedTemplate) + require.Equal(t, tt.installedVersion, linkedVersion) + require.Equal(t, tt.removedVersion, removedVersion) data, err := os.ReadFile(cfgPath) require.NoError(t, err) @@ -304,6 +351,8 @@ func blankTestAddr(s []byte) []byte { type testInstaller struct { FuncInstall func(ctx context.Context, version, template string, flags InstallFlags) error FuncRemove func(ctx context.Context, version string) error + FuncLink func(ctx context.Context, version string) error + FuncList func(ctx context.Context) (versions []string, err error) } func (ti *testInstaller) Install(ctx context.Context, version, template string, flags InstallFlags) error { @@ -313,3 +362,11 @@ func (ti *testInstaller) Install(ctx context.Context, version, template string, func (ti *testInstaller) Remove(ctx context.Context, version string) error { return ti.FuncRemove(ctx, version) } + +func (ti *testInstaller) Link(ctx context.Context, version string) error { + return ti.FuncLink(ctx, version) +} + +func (ti *testInstaller) List(ctx context.Context) (versions []string, err error) { + return ti.FuncList(ctx) +} diff --git a/lib/utils/unpack.go b/lib/utils/unpack.go index a32cff6ef76b9..78b111daf8992 100644 --- a/lib/utils/unpack.go +++ b/lib/utils/unpack.go @@ -23,6 +23,7 @@ import ( "errors" "io" "os" + "path" "path/filepath" "strings" @@ -36,7 +37,10 @@ import ( // resulting files and directories are created using the current user context. // Extract will only unarchive files into dir, and will fail if the tarball // tries to write files outside of dir. -func Extract(r io.Reader, dir string) error { +// +// If any paths are specified, only the specified paths are extracted. +// The destination specified in the first matching path is selected. +func Extract(r io.Reader, dir string, paths ...ExtractPath) error { tarball := tar.NewReader(r) for { @@ -46,7 +50,9 @@ func Extract(r io.Reader, dir string) error { } else if err != nil { return trace.Wrap(err) } - + if ok := filterHeader(header, paths); !ok { + continue + } err = sanitizeTarPath(header, dir) if err != nil { return trace.Wrap(err) @@ -59,6 +65,62 @@ func Extract(r io.Reader, dir string) error { return nil } +// ExtractPath specifies a path to be extracted. +type ExtractPath struct { + // Src path and Dst path within the archive to extract files to. + // Directories in the Src path are not included in the extraction dir. + // For example, given foo/bar/file.txt with Src=foo/bar Dst=baz, baz/file.txt results. + // Trailing slashes are always ignored. + Src, Dst string + // Skip extracting the Src path and ignore Dst. + Skip bool +} + +// filterHeader modifies the tar header by filtering it through the ExtractPaths. +// filterHeader returns false if the tar header should be skipped. +func filterHeader(hdr *tar.Header, paths []ExtractPath) (include bool) { + name := path.Clean(hdr.Name) + for _, p := range paths { + src := path.Clean(p.Src) + switch hdr.Typeflag { + case tar.TypeDir: + // If name is a directory, then + // assume src is a directory prefix, or the directory itself, + // and replace that prefix with dst. + if src != "/" { + src += "/" // ensure HasPrefix does not match partial names + } + if !strings.HasPrefix(name, src) { + continue + } + dst := path.Join(p.Dst, strings.TrimPrefix(name, src)) + if dst != "/" { + dst += "/" // tar directory headers end in / + } + hdr.Name = dst + return !p.Skip + default: + // If name is a file, then + // if src is an exact match to the file name, assume src is a file and write directly to dst, + // otherwise, assume src is a directory prefix, and replace that prefix with dst. + if src == name { + hdr.Name = path.Clean(p.Dst) + return !p.Skip + } + if src != "/" { + src += "/" // ensure HasPrefix does not match partial names + } + if !strings.HasPrefix(name, src) { + continue + } + hdr.Name = path.Join(p.Dst, strings.TrimPrefix(name, src)) + return !p.Skip + + } + } + return len(paths) == 0 +} + // extractFile extracts a single file or directory from tarball into dir. // Uses header to determine the type of item to create // Based on https://github.com/mholt/archiver diff --git a/tool/teleport-update/main.go b/tool/teleport-update/main.go index 11aee2aae3906..300da6736471a 100644 --- a/tool/teleport-update/main.go +++ b/tool/teleport-update/main.go @@ -81,16 +81,8 @@ type cliConfig struct { LogFormat string // DataDir for Teleport (usually /var/lib/teleport) DataDir string -} - -func (c *cliConfig) CheckAndSetDefaults() error { - if c.DataDir == "" { - c.DataDir = libdefaults.DataDir - } - if c.LogFormat == "" { - c.LogFormat = libutils.LogFormatText - } - return nil + // LinkDir for linking binaries and systemd services + LinkDir string } func Run(args []string) error { @@ -105,6 +97,8 @@ func Run(args []string) error { Default(libdefaults.DataDir).StringVar(&ccfg.DataDir) app.Flag("log-format", "Controls the format of output logs. Can be `json` or `text`. Defaults to `text`."). Default(libutils.LogFormatText).EnumVar(&ccfg.LogFormat, libutils.LogFormatJSON, libutils.LogFormatText) + app.Flag("link-dir", "Directory to create system symlinks to binaries and services."). + Default(filepath.Join("usr", "local")).Hidden().StringVar(&ccfg.LinkDir) app.HelpFlag.Short('h') @@ -138,10 +132,6 @@ func Run(args []string) error { return trace.Errorf("failed to set up logger") } - if err := ccfg.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - switch command { case enableCmd.FullCommand(): err = cmdEnable(ctx, &ccfg) @@ -194,6 +184,7 @@ func cmdDisable(ctx context.Context, ccfg *cliConfig) error { }() updater, err := autoupdate.NewLocalUpdater(autoupdate.LocalUpdaterConfig{ VersionsDir: versionsDir, + LinkDir: ccfg.LinkDir, Log: plog, }) if err != nil { @@ -225,6 +216,7 @@ func cmdEnable(ctx context.Context, ccfg *cliConfig) error { updater, err := autoupdate.NewLocalUpdater(autoupdate.LocalUpdaterConfig{ VersionsDir: versionsDir, + LinkDir: ccfg.LinkDir, Log: plog, }) if err != nil { From 6d2e33af38f9aed412aec2d7232e7da1b6be464b Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 28 Oct 2024 10:00:45 -0700 Subject: [PATCH 13/22] Add CTA_OKTA_SCIM enum event (#46649) * Add CTA_OKTA_SCIM enum event * Rebase with cloud proto file --- .../proto/go/usageevents/v1/usageevents.pb.go | 674 +++---- .../teleport/usageevents/v1/usageevents.proto | 1 + gen/proto/go/prehog/v1alpha/teleport.pb.go | 1699 +++++++++-------- gen/proto/ts/prehog/v1alpha/teleport_pb.ts | 127 +- proto/prehog/v1alpha/teleport.proto | 32 +- .../teleport/src/services/userEvent/types.ts | 1 + 6 files changed, 1395 insertions(+), 1139 deletions(-) diff --git a/api/gen/proto/go/usageevents/v1/usageevents.pb.go b/api/gen/proto/go/usageevents/v1/usageevents.pb.go index 007fcdf51420e..3ac0962122ea6 100644 --- a/api/gen/proto/go/usageevents/v1/usageevents.pb.go +++ b/api/gen/proto/go/usageevents/v1/usageevents.pb.go @@ -230,6 +230,7 @@ const ( CTA_CTA_EXTERNAL_AUDIT_STORAGE CTA = 10 CTA_CTA_OKTA_USER_SYNC CTA = 11 CTA_CTA_ENTRA_ID CTA = 12 + CTA_CTA_OKTA_SCIM CTA = 13 ) var CTA_name = map[int32]string{ @@ -246,6 +247,7 @@ var CTA_name = map[int32]string{ 10: "CTA_EXTERNAL_AUDIT_STORAGE", 11: "CTA_OKTA_USER_SYNC", 12: "CTA_ENTRA_ID", + 13: "CTA_OKTA_SCIM", } var CTA_value = map[string]int32{ @@ -262,6 +264,7 @@ var CTA_value = map[string]int32{ "CTA_EXTERNAL_AUDIT_STORAGE": 10, "CTA_OKTA_USER_SYNC": 11, "CTA_ENTRA_ID": 12, + "CTA_OKTA_SCIM": 13, } func (x CTA) String() string { @@ -5443,341 +5446,342 @@ func init() { } var fileDescriptor_94cf2ca1c69fd564 = []byte{ - // 5340 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7c, 0x4d, 0x6c, 0xe3, 0x48, - 0x76, 0xbf, 0xe8, 0x8f, 0x6e, 0xbb, 0xda, 0xed, 0x66, 0xb3, 0xdb, 0xb6, 0xdc, 0x6e, 0xf7, 0x87, - 0xfa, 0xdb, 0x33, 0x63, 0x4f, 0xbb, 0x67, 0x77, 0x7a, 0x67, 0xe6, 0xff, 0x9f, 0xd0, 0x14, 0x2d, - 0xb1, 0x2d, 0x89, 0x9a, 0x22, 0xd5, 0xbd, 0x9e, 0xc5, 0xa2, 0x42, 0x93, 0x65, 0x37, 0x63, 0x49, - 0xd4, 0x92, 0x94, 0x3d, 0x4e, 0x10, 0xec, 0xe6, 0x6b, 0x11, 0x64, 0x77, 0xb3, 0x09, 0x10, 0x2c, - 0x02, 0x2c, 0x10, 0x24, 0xc8, 0x07, 0x72, 0x08, 0x90, 0x53, 0xb0, 0xd7, 0x2c, 0x90, 0x43, 0x8e, - 0x01, 0x72, 0xcc, 0x25, 0xd8, 0x5c, 0x72, 0xcb, 0x29, 0x01, 0xf2, 0x85, 0x04, 0xf5, 0x41, 0x89, - 0x92, 0x28, 0x91, 0x33, 0xe9, 0xc5, 0x02, 0xdd, 0x37, 0xa9, 0xea, 0xbd, 0x7a, 0xbf, 0x7a, 0xf5, - 0xea, 0xd5, 0xab, 0x7a, 0x4f, 0x02, 0x8f, 0x42, 0xdc, 0xc4, 0x1d, 0xcf, 0x0f, 0xb7, 0xba, 0x81, - 0x75, 0x84, 0xf1, 0x09, 0x6e, 0x87, 0xc1, 0xd6, 0xc9, 0xe3, 0xf8, 0xd7, 0xcd, 0x8e, 0xef, 0x85, - 0x9e, 0xb4, 0x12, 0x91, 0x6e, 0xc6, 0xfb, 0x4e, 0x1e, 0x17, 0x36, 0x80, 0xd4, 0xd0, 0x76, 0xac, - 0x76, 0x1b, 0xfb, 0x4a, 0xd3, 0xb5, 0x8f, 0x55, 0xd2, 0x23, 0x5d, 0x05, 0xb3, 0x56, 0x13, 0xfb, - 0x61, 0x5e, 0xb8, 0x25, 0x3c, 0x9c, 0x87, 0xec, 0x4b, 0x61, 0x17, 0x3c, 0x6c, 0x68, 0x7a, 0xfb, - 0xc0, 0xb3, 0x7c, 0x47, 0xf1, 0x5a, 0x9d, 0x26, 0x0e, 0x71, 0xc9, 0x33, 0xbd, 0xa2, 0x15, 0xbc, - 0x64, 0x8d, 0xfd, 0x11, 0xae, 0x81, 0xb9, 0x6e, 0x80, 0xfd, 0xb6, 0xd5, 0xc2, 0x7c, 0x90, 0xde, - 0xf7, 0xc2, 0x3d, 0x70, 0xa7, 0x37, 0x8e, 0xec, 0x38, 0xbb, 0xae, 0x1f, 0x84, 0x10, 0x07, 0x5e, - 0xd7, 0xb7, 0x71, 0x7f, 0x88, 0xc2, 0x46, 0x4c, 0xdc, 0x30, 0x59, 0xc5, 0x0a, 0xe3, 0x80, 0x0b, - 0x1f, 0x83, 0xdb, 0x3d, 0x5a, 0x03, 0x87, 0x8a, 0x8f, 0x1d, 0xdc, 0x0e, 0x5d, 0xab, 0x69, 0x74, - 0x0f, 0x5a, 0x6e, 0x98, 0x8e, 0x29, 0x3e, 0xc0, 0x27, 0x5d, 0x1c, 0x84, 0xae, 0xd7, 0x6e, 0x5b, - 0xae, 0x8f, 0xb3, 0x0e, 0xf0, 0xcb, 0xe0, 0x5e, 0x6f, 0x00, 0x88, 0x8f, 0xdc, 0x80, 0x00, 0x7c, - 0x69, 0x35, 0x9b, 0xb8, 0x7d, 0x94, 0x75, 0x10, 0x69, 0x15, 0xcc, 0xb5, 0x0e, 0x2d, 0x14, 0x9e, - 0x75, 0x70, 0x7e, 0x8a, 0xf6, 0x9d, 0x6f, 0x1d, 0x5a, 0xe6, 0x59, 0x07, 0x4b, 0xeb, 0x00, 0x34, - 0xbd, 0x23, 0xb7, 0x8d, 0x0e, 0x9b, 0xde, 0x69, 0x7e, 0x9a, 0x76, 0xce, 0xd3, 0x96, 0xdd, 0xa6, - 0x77, 0xca, 0xf0, 0x43, 0x6c, 0x7b, 0x27, 0xd8, 0x3f, 0x53, 0x3c, 0x07, 0x07, 0x8a, 0xd7, 0x0e, - 0xdd, 0x76, 0x17, 0x67, 0x5c, 0x94, 0x0f, 0xc1, 0xfa, 0xc8, 0x00, 0x9d, 0xb3, 0x8c, 0xcc, 0x1f, - 0x81, 0x1b, 0x43, 0xcc, 0x75, 0xdf, 0x6d, 0x87, 0x19, 0xb9, 0x0b, 0x40, 0x2c, 0xba, 0x01, 0x65, - 0xae, 0xe2, 0xd0, 0x72, 0xac, 0xd0, 0x92, 0x16, 0xc1, 0x94, 0xeb, 0x70, 0xca, 0x29, 0xd7, 0x29, - 0x58, 0x20, 0x1f, 0xd1, 0x44, 0x36, 0xd0, 0xa3, 0x55, 0xc1, 0x9c, 0xcf, 0xdb, 0x28, 0xc7, 0xe2, - 0xf6, 0xa3, 0xcd, 0x31, 0xf6, 0xbe, 0x39, 0x3c, 0x08, 0xec, 0xb1, 0x16, 0x8e, 0x81, 0x14, 0xf5, - 0x1a, 0x21, 0xee, 0x18, 0xa1, 0x15, 0x76, 0x03, 0xe9, 0x63, 0x70, 0x2e, 0xa0, 0x9f, 0xf8, 0xd0, - 0x0f, 0x52, 0x87, 0x66, 0x8c, 0x90, 0xb3, 0x91, 0xbd, 0x84, 0x7d, 0xdf, 0xf3, 0xf9, 0x82, 0xb2, - 0x2f, 0x85, 0x3f, 0x11, 0xc0, 0x72, 0x43, 0x8b, 0xb1, 0xf8, 0x21, 0x76, 0x98, 0xaa, 0x54, 0x30, - 0xd7, 0xe2, 0x53, 0xa3, 0x32, 0x2f, 0x64, 0x98, 0x4e, 0xa4, 0x0b, 0xd8, 0x63, 0x95, 0x94, 0x1e, - 0xf0, 0x29, 0x3a, 0xc8, 0x5b, 0x19, 0x80, 0x47, 0xb3, 0x8e, 0xc0, 0x17, 0xfe, 0x5b, 0x00, 0xb7, - 0xfa, 0x30, 0x23, 0xa5, 0x19, 0xb8, 0x89, 0x6d, 0xb2, 0x43, 0x5e, 0x29, 0xe0, 0x6a, 0x6c, 0x19, - 0x19, 0xe4, 0xc7, 0x99, 0x97, 0xb1, 0x3f, 0x5c, 0x34, 0x44, 0x6c, 0xfe, 0xd3, 0x5f, 0x7c, 0xfe, - 0xbf, 0x31, 0x45, 0x9c, 0x50, 0x44, 0xa0, 0xb5, 0x43, 0x7c, 0xe4, 0x5b, 0x64, 0xe6, 0xf2, 0x0b, - 0x43, 0xd7, 0x8a, 0x8a, 0xe2, 0xb5, 0xdb, 0xd8, 0x0e, 0x5f, 0x7b, 0x3d, 0xfc, 0x68, 0x2a, 0x6e, - 0x07, 0x45, 0x2b, 0xb4, 0x0e, 0xac, 0x00, 0xc3, 0xa2, 0xa1, 0xb6, 0x7d, 0xaf, 0xd9, 0x7c, 0xdd, - 0xe7, 0x2f, 0x3d, 0x05, 0xf9, 0x80, 0x1a, 0x3d, 0x76, 0x50, 0x34, 0x72, 0x80, 0x6c, 0xaf, 0xdb, - 0x0e, 0xf3, 0x33, 0xb7, 0x84, 0x87, 0xd3, 0x70, 0x39, 0xea, 0x8f, 0xa0, 0x04, 0x0a, 0xe9, 0x2d, - 0xfc, 0xbb, 0x00, 0xae, 0xf7, 0x35, 0xb7, 0xd7, 0x3d, 0xc0, 0xea, 0xde, 0x1b, 0xa2, 0xb5, 0xc2, - 0x33, 0x90, 0x6f, 0x68, 0x8a, 0xd5, 0x6c, 0x9a, 0x9e, 0x4c, 0xfd, 0x45, 0xec, 0x40, 0xd8, 0x04, - 0xd3, 0x36, 0x9f, 0xf1, 0xe2, 0xf6, 0xf5, 0xb1, 0xa3, 0x2b, 0xa6, 0x0c, 0x09, 0x61, 0xe1, 0x7b, - 0xb3, 0x71, 0x3d, 0x16, 0x71, 0xa7, 0xe9, 0x9d, 0x19, 0xd8, 0x3f, 0x71, 0x6d, 0xfc, 0xda, 0x5b, - 0xdf, 0x11, 0xb8, 0xe8, 0xd0, 0x09, 0xa3, 0x16, 0x0e, 0x5f, 0x7a, 0x0e, 0x35, 0xb9, 0xc5, 0xed, - 0x9d, 0xb1, 0x63, 0x4d, 0x52, 0xd4, 0x26, 0x6b, 0xaa, 0xd2, 0x91, 0xe0, 0x82, 0x13, 0xfb, 0x26, - 0x59, 0xe0, 0x02, 0x17, 0x44, 0x43, 0x90, 0x59, 0x2a, 0xe6, 0xe7, 0xfe, 0x2f, 0x62, 0x48, 0xec, - 0x02, 0x81, 0xd3, 0xfb, 0x5c, 0x40, 0x60, 0x21, 0x0e, 0x40, 0x5a, 0x07, 0xab, 0x45, 0xb5, 0x5e, - 0xd1, 0xf7, 0x51, 0x55, 0x35, 0xcb, 0x7a, 0x11, 0x35, 0x6a, 0x46, 0x5d, 0x55, 0xb4, 0x5d, 0x4d, - 0x2d, 0x8a, 0x39, 0x69, 0x19, 0x48, 0x83, 0xdd, 0x72, 0xc3, 0xd4, 0x45, 0x41, 0xca, 0x83, 0xab, - 0x83, 0xed, 0x55, 0xb9, 0xd6, 0x90, 0x2b, 0xe2, 0x54, 0x01, 0x03, 0xd0, 0x17, 0x2d, 0xad, 0x81, - 0x15, 0x4e, 0x67, 0xee, 0xd7, 0xd5, 0xa1, 0xc1, 0x6f, 0x80, 0x6b, 0xf1, 0x4e, 0xad, 0x66, 0x98, - 0x72, 0xa5, 0x82, 0x0c, 0x05, 0x6a, 0x75, 0x53, 0x14, 0xa4, 0x6b, 0x60, 0x39, 0xde, 0x2f, 0x57, - 0xe5, 0x4f, 0xf5, 0x1a, 0x52, 0x15, 0x43, 0x9c, 0x2a, 0xfc, 0x70, 0x06, 0xdc, 0xed, 0xcf, 0x5f, - 0xf1, 0xb1, 0x15, 0xe2, 0xe8, 0xdb, 0x99, 0xe2, 0xb5, 0x0f, 0xdd, 0xa3, 0xd7, 0xde, 0x2e, 0x3d, - 0x70, 0xd1, 0xa6, 0x33, 0x1d, 0xb4, 0xcb, 0x67, 0x19, 0x0c, 0x66, 0xbc, 0xc2, 0x36, 0xd9, 0xe7, - 0xc8, 0x3e, 0xed, 0xd8, 0xb7, 0xc2, 0x9f, 0x09, 0x60, 0x21, 0xde, 0x4d, 0xac, 0x47, 0xd1, 0x6b, - 0xbb, 0x5a, 0x29, 0xd9, 0x7a, 0x46, 0xba, 0xe5, 0x17, 0x06, 0x52, 0x95, 0x6d, 0x64, 0x18, 0x55, - 0x51, 0x20, 0xeb, 0x9f, 0xdc, 0xad, 0x6a, 0x8a, 0x2a, 0x4e, 0x25, 0xb3, 0xc3, 0xa2, 0x41, 0x4d, - 0x60, 0x5a, 0x5a, 0x05, 0x4b, 0x09, 0xec, 0x7b, 0x86, 0x38, 0x53, 0xf8, 0x2f, 0x01, 0xdc, 0x4c, - 0x38, 0x2f, 0xf9, 0xbd, 0xe0, 0xb5, 0x77, 0xfc, 0xbf, 0x32, 0x15, 0xdf, 0x1c, 0xd1, 0xf4, 0xd9, - 0xca, 0x75, 0x7d, 0x5c, 0x35, 0x2b, 0xc6, 0x6b, 0xaf, 0x83, 0xdf, 0x9e, 0x02, 0x8f, 0xe3, 0x0e, - 0x32, 0x38, 0x0e, 0xbd, 0x0e, 0x39, 0x06, 0x4f, 0x70, 0xd1, 0xf5, 0xb1, 0x1d, 0x7a, 0xfe, 0x99, - 0xe9, 0x79, 0xcd, 0x40, 0x6b, 0x07, 0xa1, 0xf5, 0x06, 0x44, 0x03, 0xdf, 0x99, 0x02, 0x9b, 0x69, - 0x0a, 0xe9, 0x99, 0xc8, 0x6b, 0xaf, 0x8d, 0xbf, 0x98, 0x02, 0xf7, 0xfb, 0xda, 0x90, 0xbb, 0xa1, - 0x17, 0x7d, 0x8e, 0x85, 0x90, 0xaf, 0xfd, 0x09, 0xf2, 0x00, 0x5c, 0x4a, 0x0e, 0xa7, 0x17, 0xfd, - 0xc1, 0x30, 0xfa, 0x5b, 0x53, 0xe0, 0x4e, 0x5f, 0x5d, 0xaa, 0xb2, 0x4d, 0x77, 0x4d, 0xfb, 0x4d, - 0xba, 0x8b, 0xfe, 0x9b, 0x00, 0x56, 0x87, 0x23, 0x2e, 0x72, 0x50, 0xbd, 0x61, 0x13, 0x67, 0x91, - 0x43, 0xcd, 0x73, 0x5e, 0x7f, 0x1f, 0xf1, 0x9f, 0x02, 0xb8, 0x31, 0x3c, 0x71, 0xb9, 0xd3, 0x21, - 0x61, 0xf6, 0x1b, 0x10, 0x44, 0x7c, 0x7b, 0x0a, 0x3c, 0x9a, 0x10, 0x44, 0x68, 0x72, 0xb5, 0xee, - 0x35, 0x5d, 0xfb, 0xec, 0xb5, 0x57, 0xc4, 0xff, 0x08, 0xa0, 0xd0, 0x57, 0x44, 0xdd, 0x77, 0xdb, - 0xb6, 0xdb, 0xb1, 0x9a, 0xc1, 0x9b, 0x73, 0x58, 0xfe, 0x87, 0x00, 0xd6, 0xfb, 0x1a, 0x30, 0x71, - 0x10, 0xf2, 0x87, 0xb7, 0x37, 0xc1, 0xef, 0xff, 0xab, 0x00, 0xf2, 0x31, 0x2f, 0xc0, 0x13, 0x2f, - 0xce, 0x6b, 0x3f, 0xef, 0x35, 0xe2, 0xf5, 0xb9, 0xb7, 0xc7, 0xa7, 0xd0, 0x6b, 0xc6, 0x93, 0x43, - 0x37, 0x89, 0x41, 0x0c, 0x74, 0x1a, 0xd6, 0x49, 0x9c, 0xe0, 0x36, 0xb9, 0x80, 0x0d, 0x72, 0x93, - 0x70, 0xa1, 0x19, 0x23, 0x79, 0x1b, 0x6c, 0x0c, 0x91, 0x3c, 0x77, 0xf1, 0x69, 0xd1, 0xb3, 0xbb, - 0x2d, 0xdc, 0x0e, 0xad, 0xc1, 0x07, 0xab, 0xc2, 0x5f, 0x09, 0x60, 0x49, 0x0e, 0x02, 0x97, 0xd8, - 0x1e, 0x5d, 0x82, 0x9e, 0xed, 0x3d, 0x00, 0x97, 0x6c, 0xaf, 0x7d, 0x82, 0xfd, 0x80, 0xf2, 0xa0, - 0x5e, 0xe2, 0x62, 0x31, 0xde, 0xac, 0x39, 0xd2, 0x6d, 0xb0, 0x10, 0x7a, 0xa1, 0xd5, 0x44, 0xa1, - 0x77, 0x8c, 0xdb, 0xec, 0x61, 0x7e, 0x1a, 0x5e, 0xa0, 0x6d, 0x26, 0x6d, 0x92, 0xee, 0x80, 0x8b, - 0x1d, 0xdf, 0x6b, 0x75, 0xc2, 0x88, 0x66, 0x9a, 0xd2, 0x2c, 0xb0, 0x46, 0x4e, 0xf4, 0x16, 0xb8, - 0x6c, 0xf7, 0x30, 0x44, 0x84, 0x2c, 0x6e, 0x12, 0xfb, 0x1d, 0x8c, 0xb8, 0xf0, 0xf7, 0x02, 0xb8, - 0xca, 0x70, 0xab, 0x9f, 0x61, 0xbb, 0xfb, 0x05, 0x60, 0xaf, 0x03, 0xd0, 0xf6, 0x1c, 0xcc, 0xe3, - 0x33, 0x06, 0x7a, 0x9e, 0xb4, 0xd0, 0xd0, 0x6c, 0x64, 0x56, 0xd3, 0x19, 0x66, 0x35, 0x93, 0x75, - 0x56, 0xb3, 0x63, 0x66, 0xf5, 0x14, 0x5c, 0x63, 0x93, 0xaa, 0xe1, 0x53, 0x25, 0x06, 0xb7, 0x97, - 0x6d, 0xb2, 0xad, 0x10, 0x1f, 0x79, 0xfe, 0x59, 0x94, 0x6d, 0x8a, 0xbe, 0x17, 0xfe, 0x52, 0x00, - 0x57, 0x18, 0xab, 0x6c, 0xdb, 0x38, 0x08, 0x20, 0xfe, 0x46, 0x17, 0x07, 0x21, 0xc1, 0x18, 0xd9, - 0x2f, 0x7b, 0xfd, 0x62, 0x8c, 0x0b, 0x51, 0x23, 0x7d, 0x4e, 0xfa, 0x99, 0xac, 0xe0, 0x0f, 0x05, - 0xb0, 0x10, 0x21, 0x26, 0xcd, 0xd2, 0x32, 0x38, 0x67, 0xd1, 0x4f, 0x1c, 0x23, 0xff, 0xf6, 0xb3, - 0x41, 0x77, 0x17, 0x48, 0x4c, 0x91, 0x15, 0x37, 0x08, 0xc7, 0xe6, 0xef, 0xbe, 0x06, 0xc4, 0x3e, - 0x15, 0xdb, 0x73, 0x52, 0x69, 0xc4, 0x77, 0x8d, 0xf7, 0x13, 0xa3, 0x22, 0xfa, 0xde, 0x6b, 0x70, - 0xf0, 0x46, 0xc7, 0xf9, 0xe9, 0x0d, 0x5e, 0xc4, 0xc4, 0xf7, 0xbe, 0xba, 0xc1, 0x2d, 0xb0, 0x1c, - 0xef, 0x6f, 0x1d, 0x44, 0x61, 0xde, 0x4f, 0x55, 0xc4, 0xab, 0x56, 0x51, 0x82, 0x88, 0x57, 0xad, - 0xa8, 0x5f, 0x8c, 0x8b, 0x28, 0xf9, 0x56, 0x3b, 0x0c, 0x4c, 0xaf, 0x11, 0x60, 0x5f, 0xda, 0x04, - 0x57, 0xa8, 0x63, 0x42, 0xbe, 0xd7, 0xc4, 0x01, 0x3a, 0x22, 0x7d, 0x98, 0x99, 0xde, 0x2c, 0xbc, - 0x4c, 0xbb, 0x88, 0x6b, 0x0f, 0x4a, 0xac, 0x43, 0x7a, 0x17, 0x5c, 0x65, 0xf4, 0xa1, 0x6f, 0xb9, - 0x61, 0x9f, 0x61, 0x8a, 0x32, 0x48, 0xb4, 0xcf, 0xa4, 0x5d, 0x9c, 0xa3, 0xf0, 0x83, 0xe9, 0xb8, - 0x70, 0x88, 0x4f, 0x5c, 0x7c, 0xfa, 0x8a, 0x57, 0x49, 0x7a, 0x0a, 0x56, 0x1d, 0xeb, 0x2c, 0x40, - 0x1d, 0x2b, 0x08, 0x51, 0x1b, 0x7f, 0x16, 0x22, 0xab, 0xeb, 0xb8, 0x21, 0x22, 0x0b, 0xc5, 0xa1, - 0x2d, 0x11, 0x82, 0xba, 0x45, 0x5c, 0xde, 0x67, 0xa1, 0x4c, 0x7a, 0x8b, 0x04, 0xc2, 0x2e, 0xb8, - 0xd9, 0xa2, 0x2a, 0x0f, 0x5e, 0xba, 0x1d, 0xe4, 0xe3, 0x6f, 0x74, 0x5d, 0x1f, 0x93, 0x03, 0x2c, - 0x40, 0xf6, 0x4b, 0xab, 0x7d, 0x84, 0x1d, 0xba, 0xc7, 0xe7, 0xe0, 0x7a, 0x9f, 0x0c, 0xc6, 0xa8, - 0x14, 0x46, 0x24, 0x3d, 0x05, 0x79, 0x9f, 0x4e, 0x0d, 0x1d, 0x92, 0x41, 0x70, 0xdb, 0x3e, 0xeb, - 0x0d, 0x30, 0x43, 0x07, 0x58, 0x66, 0xfd, 0xbb, 0x51, 0x77, 0xc4, 0xf9, 0x11, 0x58, 0xe3, 0x9c, - 0x8e, 0x75, 0x86, 0xbc, 0x43, 0xd4, 0xf2, 0xda, 0xe1, 0xcb, 0x1e, 0xf3, 0x2c, 0x65, 0x5e, 0x61, - 0x24, 0x45, 0xeb, 0x4c, 0x3f, 0xac, 0x92, 0xfe, 0x88, 0xfb, 0x2b, 0x60, 0xb5, 0xdd, 0x25, 0xc0, - 0x08, 0xa7, 0x8f, 0x5b, 0xde, 0x09, 0x76, 0x10, 0x87, 0x9a, 0x3f, 0x47, 0x67, 0xbe, 0xcc, 0x08, - 0xf4, 0x43, 0xc8, 0xba, 0x99, 0x89, 0x05, 0x85, 0xdf, 0x13, 0x46, 0x17, 0xe6, 0x15, 0x1b, 0x9e, - 0xf4, 0x18, 0x2c, 0x59, 0xb4, 0x1f, 0x35, 0xdd, 0x20, 0x44, 0x7c, 0xa2, 0xae, 0xc3, 0xd3, 0xf9, - 0x92, 0x35, 0x24, 0x5f, 0x73, 0x0a, 0xdf, 0x15, 0xc0, 0x6a, 0x2c, 0x55, 0xcc, 0x92, 0x7d, 0xe3, - 0x3c, 0xa3, 0xb4, 0x03, 0x66, 0x8e, 0xdd, 0x36, 0x1b, 0x6f, 0x71, 0x7b, 0x73, 0x2c, 0xca, 0x91, - 0x11, 0xf7, 0xdc, 0xb6, 0x03, 0x29, 0xaf, 0xb4, 0x06, 0xe6, 0xbb, 0x01, 0xf6, 0x11, 0x2d, 0xaf, - 0x98, 0xee, 0x97, 0x57, 0xd4, 0xac, 0x16, 0x2e, 0x78, 0x24, 0x54, 0x1a, 0xe1, 0xa6, 0x25, 0x07, - 0xec, 0xb4, 0xac, 0x8d, 0xe8, 0x6a, 0x3b, 0x3b, 0x8a, 0x84, 0xbd, 0xea, 0x83, 0x5b, 0x09, 0x02, - 0xa3, 0xc0, 0xf5, 0xa7, 0x23, 0xf3, 0x1f, 0x04, 0x70, 0xa5, 0x57, 0x43, 0x44, 0xf7, 0x26, 0x93, - 0x93, 0xe9, 0x54, 0x8f, 0xbd, 0x42, 0x21, 0xcf, 0x77, 0x8f, 0xdc, 0x36, 0x5f, 0xdd, 0xde, 0x2b, - 0x94, 0x4e, 0x5b, 0xa5, 0x7b, 0x60, 0xd1, 0x6e, 0x7a, 0x5d, 0x07, 0x75, 0x7c, 0xef, 0xc4, 0x75, - 0xb0, 0xcf, 0x95, 0x7d, 0x91, 0xb6, 0xd6, 0x79, 0xa3, 0xa4, 0x83, 0x39, 0x87, 0x5f, 0x57, 0xe9, - 0xd6, 0xb9, 0xb0, 0xfd, 0x24, 0x35, 0x00, 0xc6, 0x4e, 0x74, 0xc3, 0xed, 0xcf, 0x2e, 0x1a, 0xa4, - 0xf0, 0x1c, 0x5c, 0x1b, 0x4f, 0x27, 0xad, 0x80, 0xf3, 0xce, 0x41, 0x7c, 0x76, 0xe7, 0x9c, 0x03, - 0x3a, 0xaf, 0x9b, 0xe0, 0x82, 0x73, 0x80, 0x68, 0x05, 0x98, 0xed, 0x35, 0xf9, 0x9c, 0x80, 0x73, - 0x50, 0xe7, 0x2d, 0x85, 0x7f, 0x11, 0xc0, 0xb5, 0x5d, 0x6c, 0x85, 0x5d, 0x1f, 0x43, 0x6c, 0x7b, - 0xad, 0x16, 0x6e, 0x3b, 0xb1, 0x30, 0x6a, 0xc0, 0xac, 0x84, 0x41, 0xb3, 0x92, 0x3e, 0x00, 0xe7, - 0x0f, 0x19, 0x2b, 0x37, 0xdd, 0x5b, 0x63, 0xe7, 0x18, 0x89, 0x88, 0x18, 0xa4, 0xcf, 0xc0, 0x3a, - 0xff, 0x88, 0xfc, 0x01, 0xb9, 0x28, 0x76, 0x6d, 0x58, 0xdc, 0x7e, 0x2f, 0x75, 0xc4, 0x01, 0x66, - 0x7e, 0x7f, 0x58, 0x3b, 0x1c, 0xdf, 0x59, 0x38, 0x05, 0x57, 0x4d, 0xb9, 0xc4, 0x22, 0x61, 0xfc, - 0x49, 0x17, 0xfb, 0xfc, 0xf9, 0xe0, 0x26, 0x60, 0x61, 0x12, 0x22, 0x71, 0x2d, 0xab, 0xf5, 0x99, - 0x86, 0x80, 0x36, 0xd5, 0x48, 0x4b, 0x9f, 0x00, 0x3b, 0x47, 0x38, 0x0a, 0xad, 0x18, 0x81, 0x4a, - 0x5a, 0x48, 0x94, 0xec, 0x06, 0x28, 0xe8, 0x52, 0x7f, 0xc0, 0x5d, 0xee, 0xbc, 0x1b, 0x18, 0xac, - 0xa1, 0xf0, 0xcf, 0xd3, 0x60, 0x85, 0x39, 0x9a, 0x92, 0x6f, 0x75, 0x5e, 0xca, 0x2f, 0x0c, 0xc3, - 0xb6, 0xda, 0x51, 0x2e, 0xfc, 0x0a, 0x1f, 0xdb, 0xde, 0x46, 0x2e, 0x7f, 0xd8, 0x64, 0x20, 0x66, - 0xe0, 0x65, 0x26, 0xc3, 0xee, 0xbd, 0x78, 0xc6, 0xb0, 0x90, 0xc5, 0x60, 0x58, 0x66, 0x38, 0x16, - 0x72, 0x24, 0x06, 0xfd, 0x40, 0xf0, 0xc8, 0xf7, 0xba, 0x1d, 0x86, 0x66, 0x86, 0x07, 0x82, 0x25, - 0xda, 0xd4, 0x1f, 0x83, 0x1e, 0x9b, 0xd4, 0x4c, 0xa3, 0x31, 0xe8, 0x71, 0x49, 0x6c, 0x9d, 0x11, - 0x74, 0xbc, 0xa6, 0x6b, 0xbb, 0x98, 0xc5, 0xe2, 0x33, 0xf0, 0x22, 0x6d, 0xad, 0xf3, 0x46, 0xe9, - 0x6d, 0x20, 0x71, 0xec, 0xc7, 0x01, 0xb2, 0x9b, 0xdd, 0x20, 0x8c, 0xfc, 0xf6, 0x0c, 0x14, 0x19, - 0xf4, 0xe3, 0x40, 0xe1, 0xed, 0xfd, 0x99, 0xfa, 0x4e, 0x10, 0x9b, 0xe9, 0xf9, 0xd8, 0x4c, 0xa1, - 0x13, 0xf4, 0x67, 0xfa, 0x10, 0xb0, 0x31, 0x50, 0xf0, 0x04, 0x1d, 0x74, 0xed, 0x63, 0x1c, 0x06, - 0xf9, 0x39, 0x4a, 0xcc, 0xc0, 0x19, 0x4f, 0x76, 0x58, 0x2b, 0x39, 0xd6, 0x39, 0xa5, 0xd5, 0x6a, - 0xf6, 0xf6, 0x67, 0x90, 0x9f, 0xa7, 0xd4, 0x0c, 0xa3, 0x61, 0xb5, 0x9a, 0xd1, 0x26, 0x8d, 0x71, - 0x78, 0xae, 0x63, 0xc7, 0x38, 0x40, 0x8c, 0x43, 0x77, 0x1d, 0xbb, 0xcf, 0xd1, 0x53, 0x89, 0x65, - 0xd3, 0x30, 0x21, 0xc8, 0x5f, 0x88, 0xa9, 0x44, 0xe6, 0x8d, 0x85, 0x1f, 0x08, 0xe0, 0x6e, 0x43, - 0x8b, 0x2d, 0xb6, 0xe2, 0x7b, 0xa7, 0xed, 0x67, 0xf8, 0x14, 0x37, 0x8b, 0xee, 0xe1, 0x21, 0xb9, - 0x64, 0xb2, 0x75, 0x7f, 0x0a, 0xf2, 0xd6, 0xe1, 0xe1, 0x60, 0x55, 0x09, 0x8a, 0x15, 0xb2, 0xcd, - 0xc3, 0xe5, 0xa8, 0xbf, 0x57, 0x7a, 0xc5, 0x2e, 0xd8, 0xef, 0x81, 0xe5, 0x51, 0xce, 0x58, 0xd9, - 0xe0, 0xd5, 0x61, 0x3e, 0x9a, 0x7b, 0xdf, 0x05, 0xd7, 0x0d, 0x6c, 0x77, 0x7d, 0x37, 0x3c, 0x83, - 0x74, 0x5b, 0x95, 0x70, 0x08, 0x71, 0xd0, 0x6d, 0xf2, 0x83, 0x40, 0x02, 0x33, 0xb1, 0xad, 0x4e, - 0x3f, 0x93, 0x36, 0x12, 0x77, 0xf0, 0x18, 0x84, 0x7e, 0x2e, 0x58, 0xe0, 0x4a, 0x2f, 0x73, 0xbb, - 0x8b, 0x43, 0xfb, 0x25, 0x63, 0x1f, 0xf5, 0x8e, 0x42, 0x92, 0x77, 0x1c, 0x71, 0xc9, 0x53, 0xa3, - 0x2e, 0xb9, 0xf0, 0x7d, 0x01, 0x48, 0xc4, 0x96, 0x4d, 0x2b, 0x38, 0x26, 0x5b, 0x17, 0xf7, 0x3c, - 0x52, 0x68, 0x05, 0xc7, 0x71, 0x67, 0x37, 0x47, 0x1a, 0xa2, 0x12, 0x49, 0x37, 0x08, 0xba, 0x03, - 0xa3, 0xce, 0xd3, 0x16, 0xda, 0x7d, 0x15, 0xcc, 0x12, 0xef, 0x12, 0x1d, 0x90, 0xec, 0x0b, 0xf1, - 0xfd, 0x3d, 0x3b, 0x8c, 0x65, 0x20, 0x66, 0xe1, 0x62, 0xaf, 0x99, 0x65, 0x20, 0xfe, 0xe6, 0x03, - 0x70, 0xa9, 0x41, 0xbc, 0x10, 0x45, 0xa2, 0xb7, 0xb1, 0x7e, 0x28, 0x35, 0xc0, 0xa5, 0xae, 0x8b, - 0x0e, 0x68, 0xf9, 0x2c, 0xb2, 0x9b, 0xae, 0x7d, 0x9c, 0x1a, 0x6c, 0x8c, 0x56, 0xdb, 0x96, 0x73, - 0xf0, 0x62, 0xd7, 0x8d, 0xb5, 0x4a, 0x3f, 0x14, 0xc0, 0xa3, 0xae, 0x8b, 0x3c, 0x56, 0x4d, 0x8a, - 0xf8, 0x95, 0x0b, 0xa3, 0x23, 0x0f, 0x85, 0x1e, 0x72, 0xa2, 0x72, 0x5b, 0x2e, 0x91, 0x3d, 0xb1, - 0xc8, 0x13, 0x24, 0x66, 0xab, 0xd9, 0x2d, 0xe7, 0xe0, 0x9d, 0xae, 0x9b, 0x4a, 0x2b, 0x7d, 0x47, - 0x00, 0x77, 0x62, 0xe8, 0x2c, 0xc7, 0x41, 0x87, 0xae, 0x4f, 0x63, 0x23, 0xbe, 0xaa, 0x0c, 0x17, - 0x3b, 0xf9, 0x3e, 0x4a, 0xc7, 0x35, 0xbe, 0x06, 0xb8, 0x9c, 0x83, 0x37, 0x7a, 0x90, 0x12, 0xc9, - 0x86, 0x75, 0x95, 0x80, 0xa6, 0x69, 0x85, 0xbd, 0xd5, 0x99, 0xcd, 0xaa, 0xab, 0x94, 0x82, 0xe3, - 0x01, 0x5d, 0x8d, 0xa7, 0x95, 0x7e, 0x5d, 0x00, 0xb7, 0x62, 0xe8, 0x02, 0x1c, 0x22, 0xbb, 0x57, - 0x9b, 0x8c, 0x02, 0x5a, 0x16, 0x4c, 0x9d, 0xe5, 0x85, 0xed, 0x0f, 0xd2, 0x41, 0x8d, 0xab, 0x6c, - 0x2e, 0xe7, 0xe0, 0xf5, 0x1e, 0x9a, 0x04, 0x22, 0xe9, 0x77, 0x04, 0x70, 0x37, 0x06, 0xc3, 0xe7, - 0x75, 0x08, 0x24, 0x44, 0x67, 0x05, 0xca, 0x11, 0x94, 0xf3, 0x14, 0xca, 0xff, 0x4f, 0x87, 0x32, - 0xa9, 0xc4, 0xb9, 0x9c, 0x83, 0xb7, 0x7a, 0x70, 0xc6, 0x10, 0x46, 0x9a, 0xf1, 0x79, 0xd1, 0x30, - 0xb2, 0xc9, 0x29, 0x8b, 0x6c, 0x5e, 0xb4, 0xcc, 0x97, 0x6b, 0x2e, 0x55, 0x33, 0x29, 0x25, 0xcf, - 0x4c, 0x33, 0xe3, 0x89, 0xa4, 0xcf, 0xc0, 0xf5, 0x24, 0x14, 0x9d, 0x33, 0x8e, 0x60, 0x9e, 0x22, - 0xf8, 0x72, 0x76, 0x04, 0xf1, 0x9a, 0xe9, 0x72, 0x0e, 0xe6, 0x47, 0xa4, 0x73, 0x02, 0xe9, 0x97, - 0xc0, 0xfa, 0xa8, 0xe4, 0x8e, 0xef, 0xb6, 0x43, 0x2e, 0x1a, 0x50, 0xd1, 0xef, 0x67, 0x15, 0x3d, - 0x54, 0x71, 0x5d, 0xce, 0xc1, 0xd5, 0x21, 0xd9, 0x7d, 0x0a, 0xa9, 0x09, 0x56, 0xbb, 0x2e, 0x72, - 0xb8, 0x13, 0x27, 0x51, 0x97, 0x4f, 0x8e, 0x12, 0x3a, 0x38, 0x3d, 0xd4, 0x2e, 0x6c, 0x6f, 0x65, - 0xa8, 0xe2, 0x89, 0xd7, 0x2d, 0x97, 0x73, 0x70, 0xb9, 0xeb, 0x26, 0x56, 0x34, 0x7f, 0x87, 0x99, - 0x5f, 0x4f, 0x5c, 0xff, 0xac, 0x8b, 0x92, 0xb7, 0x5c, 0xf2, 0x02, 0x95, 0xfc, 0x95, 0x0c, 0x92, - 0x93, 0x4b, 0x91, 0x99, 0xe5, 0xa5, 0x94, 0x2b, 0x7f, 0x93, 0x1a, 0x5e, 0x0f, 0x0c, 0x2f, 0x78, - 0x0b, 0x58, 0xed, 0x1a, 0x07, 0x72, 0x91, 0x02, 0xf9, 0xd2, 0x17, 0xaa, 0x7c, 0x63, 0x36, 0x37, - 0xa1, 0x52, 0xf1, 0x37, 0x99, 0x03, 0xed, 0x23, 0xe0, 0x01, 0x7d, 0x7f, 0x5f, 0x32, 0x10, 0x8b, - 0x14, 0xc4, 0xd3, 0x2c, 0x20, 0x92, 0x0a, 0x8c, 0xca, 0x39, 0x78, 0x33, 0x86, 0x23, 0xb1, 0x06, - 0xe9, 0xf7, 0x99, 0xf7, 0x1c, 0x85, 0x62, 0x47, 0xb9, 0x25, 0xd4, 0x0a, 0x9b, 0x01, 0x07, 0x74, - 0x89, 0x02, 0xfa, 0x7f, 0x9f, 0x03, 0xd0, 0x68, 0xc9, 0x4f, 0x39, 0x07, 0xef, 0x8e, 0xa2, 0xea, - 0xd3, 0x85, 0x4d, 0x5e, 0xf5, 0xf0, 0x63, 0x01, 0x3c, 0x1d, 0x5c, 0x27, 0x5a, 0x30, 0x82, 0x2c, - 0x5a, 0x31, 0x82, 0x9c, 0xa8, 0x64, 0x04, 0x85, 0x9e, 0xd7, 0xe4, 0xc1, 0x64, 0xb3, 0xc9, 0x91, - 0x8a, 0x14, 0xe9, 0xb3, 0x4c, 0xeb, 0x97, 0xa9, 0x30, 0xa7, 0x9c, 0x83, 0x8f, 0xe3, 0x8b, 0x9a, - 0xad, 0x9a, 0xe7, 0x47, 0x02, 0x78, 0x2f, 0xd3, 0x1c, 0xfa, 0xea, 0x66, 0xf8, 0x2f, 0x53, 0xfc, - 0xa5, 0x2f, 0x8c, 0x7f, 0x30, 0x35, 0x58, 0xce, 0xc1, 0xcd, 0x34, 0xf0, 0x43, 0xc9, 0xc4, 0x3f, - 0x10, 0xc0, 0x5b, 0x71, 0xe4, 0x56, 0x97, 0x44, 0x1e, 0xbd, 0x3b, 0x68, 0xac, 0x08, 0x9a, 0x01, - 0x96, 0x28, 0xe0, 0x8f, 0x33, 0x00, 0x9e, 0x54, 0xea, 0x52, 0xce, 0xc1, 0xfb, 0x7d, 0xa0, 0x13, - 0x8b, 0x62, 0xfe, 0x5c, 0x00, 0x5b, 0x29, 0x96, 0xeb, 0x5a, 0x2d, 0x76, 0x79, 0x39, 0xe3, 0x20, - 0xaf, 0x50, 0x90, 0x3b, 0x5f, 0xc4, 0x7e, 0x07, 0xb3, 0xcd, 0xe5, 0x1c, 0x7c, 0x34, 0xc1, 0x88, - 0x35, 0xab, 0x15, 0x4f, 0x4d, 0xff, 0xae, 0x00, 0xee, 0xc7, 0xa1, 0x76, 0x7a, 0x19, 0xdc, 0x91, - 0x75, 0xbf, 0x4a, 0x11, 0x7e, 0x98, 0x01, 0xe1, 0xb8, 0x34, 0x70, 0x39, 0x07, 0x0b, 0x7d, 0x68, - 0x63, 0x93, 0xc5, 0xbf, 0x2a, 0x80, 0xdb, 0x71, 0x4c, 0x21, 0x0e, 0x42, 0x82, 0xa6, 0x3d, 0xe0, - 0x8f, 0x97, 0x52, 0x4f, 0xbf, 0x09, 0x39, 0xd9, 0x72, 0x0e, 0xae, 0xf7, 0x91, 0x24, 0x25, 0x6d, - 0x7d, 0xb0, 0x16, 0xc7, 0x10, 0xc5, 0xb9, 0xd1, 0x39, 0xb4, 0x9c, 0x92, 0x88, 0x1c, 0x97, 0x14, - 0x65, 0xc7, 0xee, 0x98, 0x84, 0x69, 0x13, 0xe4, 0xbb, 0x2e, 0x09, 0xc2, 0xac, 0x10, 0xa3, 0x36, - 0x3e, 0xa5, 0xf7, 0x5f, 0x7e, 0xe2, 0xae, 0xa4, 0x3c, 0x44, 0x8d, 0x4d, 0x47, 0x96, 0x73, 0xf0, - 0x6a, 0xd7, 0x1d, 0xed, 0x94, 0xce, 0xe8, 0x21, 0x3f, 0x2c, 0x2d, 0xb0, 0x4e, 0x22, 0x91, 0xf9, - 0x54, 0x0d, 0x4f, 0x48, 0x72, 0xb2, 0x89, 0x26, 0x13, 0x48, 0xdf, 0x04, 0x37, 0x93, 0x26, 0x4a, - 0x93, 0xa0, 0x5c, 0xf8, 0x6a, 0xea, 0x01, 0x33, 0x31, 0x81, 0x5a, 0xce, 0xc1, 0x6b, 0xc3, 0xb3, - 0xee, 0x93, 0x48, 0x7f, 0xc4, 0x5c, 0xc8, 0x30, 0x02, 0xf6, 0x50, 0x1c, 0x4f, 0xb2, 0x72, 0x34, - 0xd7, 0x28, 0x1a, 0x25, 0x2b, 0x9a, 0x09, 0xb9, 0xda, 0x72, 0x0e, 0xde, 0x1b, 0x02, 0x96, 0x4c, - 0x2d, 0xfd, 0xa9, 0x00, 0x36, 0xe3, 0x26, 0xe8, 0xf6, 0x9f, 0x1a, 0x91, 0x75, 0x1a, 0xb0, 0xa7, - 0x01, 0xbe, 0x2d, 0xb8, 0x55, 0xae, 0xa5, 0x5e, 0x21, 0xb2, 0xfd, 0x5c, 0xa8, 0x9c, 0x83, 0x0f, - 0xfb, 0x56, 0x1a, 0xa7, 0x3d, 0x0d, 0x74, 0xd7, 0xb1, 0x07, 0x7e, 0x5a, 0xf4, 0x5d, 0x01, 0xdc, - 0x4b, 0x0e, 0x19, 0x9c, 0x00, 0x61, 0xfa, 0x28, 0xca, 0xe1, 0x5d, 0xcf, 0x1c, 0x42, 0x25, 0xff, - 0x8a, 0x67, 0x30, 0x84, 0xea, 0xd1, 0x38, 0x41, 0xfc, 0x37, 0x2b, 0x21, 0x33, 0x6b, 0x72, 0xde, - 0x86, 0x1e, 0x62, 0xd9, 0x47, 0xb6, 0x8a, 0x1c, 0xc5, 0x7a, 0xea, 0xd6, 0x4d, 0xfe, 0x59, 0x08, - 0xb7, 0xe8, 0xe4, 0x9f, 0x8c, 0x7c, 0x1d, 0x5c, 0xb6, 0x68, 0x1a, 0x14, 0xf5, 0x93, 0x90, 0xf9, - 0x1b, 0x54, 0xd2, 0xf8, 0x67, 0xf3, 0xc4, 0x94, 0x7d, 0x39, 0x07, 0x45, 0x6b, 0xa8, 0x23, 0x72, - 0x89, 0x71, 0x13, 0xe0, 0x9a, 0xa5, 0xe1, 0x31, 0x9f, 0xd9, 0xcd, 0xd4, 0x0d, 0x3b, 0xe1, 0xa9, - 0x9d, 0xb9, 0xc4, 0x49, 0x6f, 0xf1, 0x3c, 0x54, 0x4e, 0x00, 0xd1, 0x7b, 0x05, 0x60, 0x38, 0x6e, - 0xa5, 0xae, 0xf3, 0xe4, 0x17, 0x78, 0xb6, 0xce, 0x29, 0xaf, 0xf4, 0xbf, 0x26, 0x50, 0x27, 0x12, - 0xdd, 0x1b, 0xbf, 0x11, 0xff, 0x61, 0x6c, 0x74, 0x65, 0xbc, 0x9d, 0xf5, 0xf6, 0x3a, 0xee, 0x67, - 0xb5, 0x03, 0xb7, 0xd7, 0x04, 0x22, 0xe9, 0x53, 0xc0, 0x17, 0x0b, 0xe1, 0xa8, 0x82, 0x21, 0x5f, - 0xa0, 0x52, 0xdf, 0x49, 0x59, 0xf6, 0xc1, 0x8a, 0x87, 0x72, 0x0e, 0x5e, 0xb2, 0x06, 0xdb, 0xa5, - 0x16, 0x58, 0xe1, 0x63, 0x13, 0x07, 0x15, 0x2f, 0x7c, 0xc8, 0xdf, 0x49, 0x79, 0xb9, 0x1f, 0x5f, - 0x7f, 0x50, 0xce, 0xc1, 0x25, 0x2b, 0xa9, 0x57, 0x3a, 0x00, 0x4b, 0xfd, 0x57, 0x12, 0xe6, 0x18, - 0xd9, 0x72, 0xde, 0xa5, 0xc2, 0xde, 0x1e, 0x2b, 0x2c, 0x21, 0xb7, 0x51, 0xce, 0xc1, 0x2b, 0x7e, - 0x42, 0xca, 0xe3, 0x14, 0x5c, 0x1f, 0xf3, 0xb8, 0xce, 0x44, 0xdd, 0x4b, 0x99, 0xd7, 0xf8, 0x84, - 0x00, 0x71, 0xf8, 0x87, 0xe3, 0xd3, 0x05, 0x07, 0x80, 0xcf, 0x1a, 0xf1, 0x8c, 0x99, 0xcf, 0x4a, - 0x2b, 0xf2, 0xf7, 0x53, 0x26, 0x97, 0x50, 0x8e, 0x41, 0x26, 0x67, 0x25, 0x54, 0x69, 0x54, 0xc0, - 0xc5, 0x9e, 0x0c, 0xba, 0x4a, 0x0f, 0xe8, 0xd8, 0xf7, 0x52, 0xc7, 0x26, 0xc4, 0xe5, 0x1c, 0x5c, - 0xb0, 0xe2, 0x85, 0x14, 0xfb, 0x40, 0x8a, 0x27, 0xf7, 0xd8, 0x8a, 0xe4, 0x1f, 0xa6, 0xd4, 0x51, - 0x0d, 0x17, 0x32, 0x50, 0x6f, 0x32, 0x5c, 0xdc, 0x30, 0x34, 0x74, 0x97, 0xa6, 0xdc, 0xf3, 0x8f, - 0x32, 0x0f, 0xcd, 0x72, 0xf4, 0x83, 0x43, 0xf3, 0xbc, 0xfd, 0xd0, 0xd0, 0x0e, 0xcd, 0x78, 0xe6, - 0x37, 0x32, 0x0f, 0xcd, 0x52, 0xa4, 0x83, 0x43, 0xf3, 0xb4, 0x69, 0x13, 0xac, 0xc6, 0x87, 0x66, - 0x69, 0xd8, 0x48, 0x2f, 0x6f, 0xa5, 0xbc, 0x0b, 0x24, 0x57, 0x32, 0x94, 0x73, 0x70, 0xd9, 0x4a, - 0xae, 0x71, 0x48, 0x96, 0xc6, 0x55, 0xf5, 0xf6, 0xe7, 0x94, 0xd6, 0x53, 0xd8, 0x88, 0x34, 0xae, - 0xb6, 0x64, 0x69, 0x5c, 0x7b, 0xef, 0x7c, 0x4e, 0x69, 0x3d, 0x1d, 0x8e, 0x48, 0xe3, 0x9a, 0x6c, - 0x81, 0x6b, 0x71, 0x69, 0xb4, 0xca, 0x20, 0x20, 0xa7, 0x65, 0x37, 0xc0, 0x7e, 0x7e, 0x33, 0xb3, - 0xb8, 0x78, 0xad, 0xc3, 0xa0, 0xb8, 0x81, 0x2a, 0x88, 0xdf, 0x12, 0x40, 0x21, 0x1e, 0x20, 0xc4, - 0x33, 0x49, 0xfd, 0x67, 0x96, 0xfc, 0x56, 0xea, 0x9b, 0x6c, 0x6a, 0x89, 0x3d, 0x7b, 0x93, 0xed, - 0x91, 0xd9, 0xa3, 0x64, 0xd2, 0x31, 0x58, 0x49, 0x78, 0x61, 0xc1, 0xae, 0x8d, 0xf3, 0xef, 0xa6, - 0x86, 0xd8, 0x63, 0x0a, 0xdc, 0x59, 0x88, 0x3d, 0xd4, 0xe9, 0xda, 0x78, 0x58, 0x58, 0x14, 0x6e, - 0x7a, 0x0e, 0xce, 0x3f, 0xce, 0x2c, 0x6c, 0xa8, 0xa8, 0x7c, 0x50, 0x58, 0xbf, 0x53, 0xfa, 0x1a, - 0xb8, 0x1c, 0x5a, 0x47, 0xfc, 0x1c, 0xc2, 0xe4, 0x40, 0xf4, 0xcf, 0xf2, 0xdb, 0x29, 0x67, 0x51, - 0x52, 0xc2, 0x91, 0x9c, 0x45, 0xa1, 0x75, 0x14, 0x6f, 0x97, 0x42, 0x70, 0x2d, 0xe0, 0xe9, 0x19, - 0xe4, 0xd3, 0x91, 0xd0, 0x11, 0xa6, 0x0f, 0xd9, 0xdd, 0x66, 0x98, 0x7f, 0x92, 0xf2, 0x24, 0x35, - 0x29, 0xb3, 0x53, 0xce, 0xc1, 0x95, 0x20, 0xb9, 0x7f, 0x78, 0x5b, 0xf0, 0x02, 0x07, 0xbe, 0xe5, - 0xdf, 0xcb, 0x6c, 0xa7, 0xf1, 0xb2, 0x98, 0x41, 0x3b, 0x1d, 0x28, 0x98, 0x49, 0x96, 0xc6, 0x37, - 0xe1, 0x97, 0x3e, 0xa7, 0xb4, 0xa4, 0x4d, 0x38, 0x50, 0x05, 0x72, 0x00, 0x96, 0x22, 0xc3, 0x38, - 0x43, 0x87, 0x38, 0xb4, 0x5f, 0xf2, 0x33, 0xf0, 0xcb, 0x29, 0x27, 0x52, 0x42, 0x7a, 0x8b, 0x9c, - 0x48, 0x4e, 0x42, 0xd6, 0xeb, 0x7b, 0x43, 0xaf, 0x79, 0xdc, 0x00, 0xfb, 0x72, 0xd9, 0x1d, 0x3f, - 0xff, 0x7e, 0xe6, 0xc7, 0xb3, 0xf1, 0xbf, 0x8d, 0x1c, 0x7c, 0xd2, 0x4b, 0xa4, 0x93, 0xbe, 0x35, - 0x74, 0xb3, 0x3f, 0xee, 0x1e, 0x60, 0x9a, 0x9c, 0x1d, 0xb8, 0x26, 0x3c, 0xcd, 0xfc, 0xc0, 0x39, - 0xfa, 0x93, 0xf5, 0xc1, 0x07, 0x4e, 0xda, 0x7f, 0x3c, 0x70, 0x3d, 0xf8, 0x76, 0xb2, 0x4a, 0xac, - 0x4e, 0x87, 0x3e, 0xb3, 0xf6, 0x1e, 0x38, 0xbf, 0x92, 0xfa, 0xc2, 0x3d, 0xe9, 0xb7, 0x0f, 0x83, - 0x8e, 0x28, 0xf1, 0xd7, 0x11, 0x1d, 0xb0, 0xc6, 0xad, 0xed, 0xc8, 0xb7, 0x3a, 0x2f, 0xe9, 0x95, - 0x2e, 0xb0, 0xad, 0x28, 0x12, 0xfa, 0x80, 0xca, 0x7f, 0x37, 0xc5, 0xde, 0x46, 0xf2, 0xf5, 0x64, - 0x37, 0x59, 0xb1, 0xae, 0xd3, 0xa0, 0x9f, 0xca, 0xff, 0x3e, 0xbb, 0xa8, 0x0d, 0x48, 0xb5, 0x7d, - 0xef, 0xb4, 0x8d, 0x7e, 0x01, 0x9f, 0xe2, 0x26, 0x72, 0xdc, 0xc3, 0x43, 0x7a, 0x05, 0xce, 0x7f, - 0x98, 0x6a, 0x0f, 0xe9, 0x19, 0x64, 0x66, 0x0f, 0x13, 0xe9, 0xa4, 0x9f, 0x07, 0x4b, 0xb4, 0x88, - 0x83, 0xe6, 0x4d, 0x69, 0xce, 0x93, 0xcf, 0xfe, 0xa3, 0xb4, 0x4c, 0xe5, 0x48, 0xfa, 0xb5, 0x9c, - 0x83, 0x52, 0x77, 0xa4, 0x75, 0xe7, 0x3c, 0x98, 0xa5, 0x5c, 0xcf, 0x66, 0xe6, 0xa6, 0xc4, 0x69, - 0x62, 0x1b, 0xbd, 0x1b, 0x03, 0xf1, 0x5f, 0x51, 0x72, 0x81, 0xde, 0x0f, 0x37, 0xfe, 0xfa, 0x52, - 0xff, 0xdf, 0x5e, 0xa2, 0xa0, 0x56, 0xba, 0x0d, 0xd6, 0x8b, 0x9a, 0xa1, 0xe8, 0xcf, 0x55, 0x88, - 0xa0, 0x6a, 0xe8, 0x0d, 0xa8, 0x0c, 0xff, 0x56, 0xfb, 0x3a, 0xc8, 0x8f, 0x92, 0x18, 0x2a, 0x7c, - 0xae, 0x42, 0x51, 0x90, 0x6e, 0x81, 0xeb, 0xa3, 0xbd, 0x7b, 0x8d, 0x1d, 0x15, 0xd6, 0x54, 0x53, - 0x35, 0xc4, 0x29, 0xe9, 0x09, 0xd8, 0x1a, 0xa5, 0x28, 0xca, 0xa6, 0xbc, 0x23, 0x1b, 0x2a, 0xaa, - 0xeb, 0x86, 0x59, 0x82, 0xaa, 0x81, 0x0c, 0xb5, 0xb2, 0x8b, 0xca, 0xba, 0x61, 0xaa, 0x45, 0x71, - 0x5a, 0x7a, 0x17, 0xbc, 0x3d, 0x81, 0xa9, 0xba, 0x6f, 0x7c, 0x52, 0x19, 0xe0, 0x98, 0x91, 0xb6, - 0xc1, 0xe6, 0x24, 0x0e, 0xbd, 0x56, 0xd2, 0x8b, 0x3b, 0x03, 0x3c, 0xb3, 0xd2, 0x5b, 0xe0, 0x41, - 0x16, 0x68, 0xb0, 0x68, 0x88, 0xe7, 0xa4, 0x87, 0xe0, 0x6e, 0x2a, 0x24, 0x42, 0x79, 0x5e, 0xba, - 0x0f, 0x0a, 0xa3, 0x94, 0x72, 0xbd, 0x5e, 0xd1, 0x14, 0xd9, 0xd4, 0xf4, 0x1a, 0x2a, 0x9b, 0x66, - 0x5d, 0x9c, 0x93, 0xee, 0x81, 0xdb, 0x93, 0xe9, 0x4c, 0xa5, 0x2e, 0xce, 0x27, 0x93, 0xbd, 0xd0, - 0x6a, 0x45, 0xfd, 0x85, 0x81, 0x8a, 0xaa, 0xb1, 0x67, 0xea, 0x75, 0x11, 0x48, 0x6f, 0x83, 0x87, - 0x13, 0xf0, 0x19, 0x9f, 0x54, 0xd8, 0x9a, 0x51, 0x8c, 0x17, 0x52, 0x14, 0xdc, 0x9f, 0xba, 0x5a, - 0x34, 0xca, 0xda, 0xae, 0x29, 0x2e, 0x48, 0xef, 0x81, 0x77, 0x33, 0x8d, 0x1f, 0x57, 0xf1, 0xc5, - 0x14, 0x39, 0x50, 0x2d, 0x6a, 0x83, 0x4b, 0xbf, 0x98, 0x75, 0x51, 0x4a, 0x4a, 0x5d, 0xbc, 0x94, - 0x69, 0x51, 0x08, 0xa5, 0x98, 0x59, 0x3d, 0x84, 0xfa, 0xb2, 0xf4, 0x21, 0x78, 0xff, 0xf3, 0xa8, - 0x87, 0xef, 0x87, 0x8a, 0x6a, 0x18, 0xa2, 0x24, 0xbd, 0x03, 0x1e, 0x65, 0x61, 0x96, 0x3f, 0x6d, - 0x40, 0x55, 0xbc, 0x22, 0x3d, 0x00, 0x77, 0x26, 0x90, 0x17, 0xf7, 0x6b, 0x72, 0x55, 0x2f, 0xee, - 0x88, 0x57, 0x53, 0x4c, 0x5c, 0x91, 0x0d, 0x43, 0xae, 0x15, 0xa1, 0x8c, 0xf6, 0xd4, 0x7d, 0xa3, - 0x2e, 0x2b, 0xaa, 0x21, 0x2e, 0xa5, 0xac, 0x5a, 0x9f, 0x27, 0xbe, 0x06, 0xcb, 0xd2, 0x53, 0xf0, - 0xde, 0x04, 0x2e, 0xb5, 0x22, 0x1b, 0xa6, 0xa6, 0x18, 0xaa, 0x0c, 0x95, 0xf2, 0x00, 0xe7, 0x4a, - 0xa6, 0xf5, 0xe6, 0xfc, 0xb2, 0x52, 0x56, 0xc5, 0x7c, 0x8a, 0xb6, 0x18, 0x47, 0x55, 0xad, 0xea, - 0x70, 0xbf, 0xb8, 0x23, 0xae, 0x66, 0x12, 0x40, 0x35, 0x8b, 0x98, 0x80, 0x6b, 0x29, 0x93, 0x61, - 0x1c, 0x4a, 0xa5, 0x61, 0x98, 0x43, 0xc6, 0xbb, 0x26, 0x6d, 0x80, 0xfb, 0xa9, 0xd6, 0xc5, 0x56, - 0xf1, 0xba, 0xb4, 0x09, 0x36, 0x32, 0xd9, 0x17, 0xa3, 0x5f, 0x4f, 0x59, 0xcc, 0x3e, 0x7d, 0x55, - 0x53, 0xa0, 0x6e, 0xe8, 0xbb, 0xa6, 0x78, 0x43, 0xfa, 0x32, 0xd8, 0x9e, 0xb4, 0x98, 0xba, 0xb2, - 0x07, 0x75, 0x59, 0x29, 0x0f, 0xf9, 0xb9, 0x9b, 0x29, 0xb6, 0x1f, 0xf9, 0x46, 0xd9, 0xac, 0xc8, - 0x86, 0x78, 0x2b, 0x65, 0x4f, 0x19, 0x35, 0xfd, 0xc5, 0x6e, 0x45, 0xde, 0x53, 0xc5, 0xdb, 0x63, - 0xc6, 0xd5, 0x95, 0x98, 0x76, 0x8b, 0x06, 0xaa, 0x43, 0xfd, 0xab, 0xfb, 0x62, 0x61, 0x8c, 0x29, - 0xc6, 0xa9, 0xcb, 0x5a, 0xa9, 0x8c, 0xe4, 0xe7, 0xb2, 0x56, 0x91, 0x77, 0xb4, 0x8a, 0x66, 0xee, - 0x8b, 0x77, 0xa4, 0xf7, 0xc1, 0x93, 0x14, 0x2e, 0xba, 0x43, 0x34, 0x05, 0x41, 0xb5, 0xa4, 0x19, - 0x26, 0xa4, 0xae, 0x53, 0xbc, 0x9b, 0xec, 0x85, 0x0d, 0xb9, 0x5a, 0x89, 0xbb, 0x58, 0xf1, 0x9e, - 0x54, 0x00, 0x37, 0x46, 0xe9, 0x54, 0x65, 0x9b, 0xfd, 0x2b, 0x49, 0x4d, 0x51, 0xc5, 0xfb, 0x63, - 0x8c, 0x4e, 0x57, 0x86, 0xdd, 0x30, 0xaa, 0xe9, 0x35, 0x24, 0x17, 0xc5, 0x07, 0xd2, 0x5d, 0x70, - 0x6b, 0xd2, 0xb9, 0x48, 0xff, 0xad, 0xe2, 0x61, 0xb2, 0xed, 0xc7, 0x4f, 0x00, 0xf9, 0x85, 0x81, - 0x14, 0xbd, 0x66, 0xe8, 0x15, 0x55, 0x7c, 0xb4, 0xf1, 0xc7, 0x02, 0x58, 0x1c, 0xfc, 0xb3, 0x33, - 0xe9, 0x26, 0x58, 0xeb, 0x8d, 0x60, 0x98, 0xb2, 0xd9, 0x30, 0x86, 0x8e, 0xef, 0x35, 0xb0, 0x32, - 0x4c, 0x60, 0x34, 0x14, 0x85, 0x78, 0x2a, 0x21, 0xb1, 0x73, 0x4f, 0xab, 0xd7, 0xd5, 0xa2, 0x38, - 0x25, 0xad, 0x82, 0xa5, 0xe1, 0x4e, 0x15, 0x42, 0x1d, 0x8a, 0xd3, 0x49, 0x7c, 0xf2, 0x8e, 0x0e, - 0xe9, 0x49, 0xbc, 0xf1, 0xe3, 0x29, 0x30, 0xad, 0x98, 0xb2, 0x74, 0x05, 0x5c, 0x52, 0x4c, 0x79, - 0xf4, 0x6f, 0x65, 0x48, 0xa3, 0xdc, 0x30, 0xcb, 0x64, 0x62, 0x35, 0x55, 0x31, 0x75, 0x12, 0x47, - 0xac, 0x80, 0x2b, 0xb4, 0x5d, 0x31, 0xb5, 0xe7, 0x24, 0xbc, 0x30, 0x0c, 0x4d, 0xaf, 0x91, 0xf0, - 0xa1, 0xd7, 0x41, 0x20, 0x23, 0xa8, 0x7e, 0xd2, 0x50, 0x0d, 0xd3, 0x10, 0xa7, 0xa3, 0x8e, 0x3a, - 0x54, 0xab, 0x5a, 0xa3, 0x8a, 0x8c, 0x46, 0xbd, 0xae, 0x43, 0x53, 0x9c, 0x89, 0x3a, 0x4c, 0x48, - 0xb6, 0x74, 0x11, 0x15, 0xd5, 0xe7, 0x1a, 0xf1, 0x85, 0xb3, 0x91, 0xec, 0x46, 0xbd, 0x04, 0xe5, - 0xa2, 0x8a, 0x76, 0xe4, 0x5a, 0x4d, 0x85, 0xe2, 0xb9, 0x88, 0x61, 0x47, 0xab, 0x54, 0xb4, 0x5a, - 0x09, 0x19, 0x8d, 0x6a, 0x55, 0x86, 0xfb, 0xe2, 0xf9, 0x68, 0x06, 0x5c, 0x76, 0x45, 0x33, 0x4c, - 0x71, 0x8e, 0xfe, 0xf9, 0x48, 0xbf, 0xb1, 0xaa, 0xd7, 0x34, 0x53, 0x87, 0x5a, 0xad, 0x24, 0xce, - 0xd3, 0xbf, 0x35, 0x31, 0x65, 0xa4, 0x7e, 0xd5, 0x54, 0x61, 0x4d, 0xae, 0x20, 0xb9, 0x51, 0xd4, - 0x4c, 0x64, 0x98, 0x3a, 0x94, 0x4b, 0xaa, 0x08, 0x22, 0x00, 0xfa, 0x1e, 0x41, 0x61, 0x10, 0xdd, - 0xed, 0xd7, 0x14, 0xf1, 0x82, 0x24, 0x82, 0x05, 0xca, 0x57, 0x33, 0xa1, 0x8c, 0xb4, 0xa2, 0xb8, - 0xb0, 0xf1, 0x4f, 0x73, 0x60, 0x29, 0xb1, 0xee, 0x9c, 0x9c, 0x16, 0x5a, 0xcd, 0x54, 0x4b, 0xcc, - 0xce, 0x91, 0x5a, 0x83, 0x7a, 0xa5, 0x82, 0xf6, 0xb4, 0xda, 0xf0, 0x5f, 0xb0, 0xdc, 0x06, 0xeb, - 0xe3, 0x08, 0x8d, 0x8a, 0xac, 0xec, 0x89, 0x02, 0x31, 0xd2, 0x71, 0x24, 0xc4, 0xf0, 0x74, 0xad, - 0xa8, 0x88, 0x53, 0x24, 0xfe, 0x18, 0x47, 0x55, 0x97, 0x4b, 0x2a, 0x2c, 0x36, 0xcc, 0x7d, 0x71, - 0x7a, 0x92, 0x3c, 0xb5, 0x2a, 0x6b, 0x15, 0x71, 0x86, 0x04, 0x8b, 0xe3, 0x48, 0x9e, 0x69, 0x50, - 0x16, 0x67, 0xa5, 0x3b, 0xe0, 0xe6, 0x38, 0x0a, 0x6a, 0x70, 0xb0, 0x28, 0x9e, 0x23, 0x3b, 0x7b, - 0x1c, 0x51, 0x55, 0x36, 0x4d, 0x15, 0x56, 0x75, 0xc3, 0x14, 0xcf, 0x4f, 0x9a, 0x5e, 0xd5, 0x40, - 0xa6, 0x2a, 0x57, 0x0d, 0x71, 0x6e, 0x12, 0x95, 0x5e, 0x37, 0x4a, 0x6a, 0x4d, 0x53, 0xc5, 0xf9, - 0x49, 0xd0, 0xc9, 0x72, 0x8a, 0x60, 0xe2, 0xe4, 0xe4, 0xea, 0xae, 0x78, 0x61, 0x32, 0x6e, 0xa5, - 0xac, 0xd5, 0x54, 0xba, 0xf8, 0xd2, 0x97, 0xc0, 0xe3, 0x74, 0x3a, 0x54, 0xd2, 0xcc, 0x72, 0x63, - 0x87, 0xee, 0x18, 0xb2, 0x53, 0x2e, 0x4a, 0x5b, 0xe0, 0xad, 0x0c, 0x6c, 0x8a, 0x06, 0x95, 0x8a, - 0xaa, 0x68, 0xe2, 0x22, 0xf1, 0x3e, 0xd9, 0xe4, 0x54, 0xe4, 0x1d, 0xf1, 0x12, 0x39, 0xe1, 0x32, - 0x90, 0x3f, 0x53, 0x6b, 0x7b, 0x5a, 0xcd, 0x10, 0xc5, 0x8c, 0xf4, 0x72, 0xcd, 0xd0, 0x76, 0x2a, - 0xaa, 0x78, 0x79, 0x92, 0x7a, 0xc8, 0x59, 0xa8, 0x29, 0x6a, 0x4d, 0x7f, 0x21, 0x4a, 0x93, 0x16, - 0xac, 0xb7, 0x83, 0xae, 0x90, 0x73, 0x63, 0xac, 0x25, 0xc9, 0xa6, 0x5c, 0xd4, 0x4b, 0x48, 0xab, - 0x29, 0x5a, 0x51, 0xad, 0x99, 0xa8, 0x2a, 0xd7, 0xe4, 0x92, 0x5a, 0x55, 0x6b, 0xa6, 0x78, 0x95, - 0x1c, 0xfa, 0x59, 0x60, 0xbf, 0x20, 0xd1, 0x55, 0x36, 0x5a, 0x12, 0x52, 0x2e, 0x93, 0xc3, 0x32, - 0xcb, 0xb8, 0x34, 0x3c, 0xa0, 0x71, 0x54, 0x06, 0x6a, 0x1a, 0xe6, 0x55, 0x48, 0x7c, 0x9e, 0x97, - 0x1e, 0x83, 0x77, 0x32, 0x70, 0xc4, 0xae, 0x66, 0xab, 0x1b, 0x1f, 0x83, 0xf3, 0x3c, 0xe7, 0x40, - 0x7c, 0xe0, 0xae, 0x2a, 0x9b, 0x24, 0x6e, 0x1a, 0x39, 0x3f, 0xa2, 0x8e, 0x61, 0x8f, 0x2a, 0x6c, - 0xfc, 0xa1, 0x00, 0xd6, 0x26, 0xfc, 0x22, 0x80, 0x58, 0x58, 0xc4, 0x0c, 0x55, 0x45, 0xaf, 0x56, - 0xd5, 0x5a, 0x91, 0xc1, 0x4b, 0x3c, 0xab, 0x36, 0xc0, 0xfd, 0xc9, 0xe4, 0x35, 0xdd, 0x64, 0xb4, - 0x02, 0xb1, 0x96, 0xc9, 0xb4, 0x45, 0xbd, 0xa6, 0x8a, 0x53, 0x3b, 0x5f, 0xff, 0xdb, 0x9f, 0xdc, - 0x10, 0xfe, 0xee, 0x27, 0x37, 0x84, 0x7f, 0xfc, 0xc9, 0x0d, 0xe1, 0x53, 0xfd, 0xc8, 0x0d, 0x5f, - 0x76, 0x0f, 0x36, 0x6d, 0xaf, 0xb5, 0x75, 0xe4, 0x5b, 0x27, 0x2e, 0xcb, 0x49, 0x5b, 0xcd, 0xad, - 0xde, 0x5f, 0xfa, 0x5a, 0x1d, 0x77, 0xeb, 0x08, 0xb7, 0xb7, 0xe8, 0xaf, 0x37, 0xb6, 0x8e, 0xbc, - 0xa1, 0xff, 0xf8, 0xfd, 0x30, 0xf6, 0xf5, 0xe4, 0xf1, 0xc1, 0x39, 0x4a, 0xf6, 0xe4, 0x7f, 0x03, - 0x00, 0x00, 0xff, 0xff, 0x30, 0xe3, 0x6d, 0x74, 0x13, 0x58, 0x00, 0x00, + // 5350 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7c, 0x4d, 0x8c, 0xdb, 0x48, + 0x76, 0xbf, 0xd8, 0x1f, 0x76, 0xbb, 0x6c, 0xb7, 0x69, 0xda, 0x6e, 0xab, 0xdd, 0x6e, 0x7f, 0xc8, + 0xdf, 0x3d, 0x33, 0xdd, 0xe3, 0xf6, 0xec, 0x8e, 0x77, 0x66, 0xfe, 0xff, 0x09, 0x9b, 0x62, 0x4b, + 0x74, 0x4b, 0xa2, 0xa6, 0x48, 0xd9, 0xdb, 0xb3, 0x58, 0x54, 0xd8, 0x64, 0x75, 0x9b, 0x69, 0x49, + 0xd4, 0x92, 0x54, 0xf7, 0x74, 0x82, 0x60, 0x37, 0x5f, 0x8b, 0x20, 0xbb, 0x9b, 0x4d, 0x80, 0x60, + 0x11, 0x60, 0x81, 0x20, 0x41, 0x3e, 0x90, 0x43, 0x80, 0x9c, 0x82, 0xbd, 0x26, 0x40, 0x0e, 0x39, + 0x06, 0x48, 0x6e, 0xb9, 0x04, 0x9b, 0x4b, 0x6e, 0x39, 0x25, 0x40, 0xbe, 0x90, 0xa0, 0x3e, 0x48, + 0x51, 0x12, 0x25, 0x72, 0x26, 0x5e, 0x2c, 0x60, 0xdf, 0xa4, 0xaa, 0xf7, 0xea, 0xfd, 0xea, 0xd5, + 0xab, 0x57, 0xaf, 0xea, 0x3d, 0x09, 0x3c, 0x0a, 0x71, 0x1b, 0xf7, 0x3c, 0x3f, 0xdc, 0xe8, 0x07, + 0xd6, 0x01, 0xc6, 0x47, 0xb8, 0x1b, 0x06, 0x1b, 0x47, 0x8f, 0x93, 0x5f, 0xd7, 0x7b, 0xbe, 0x17, + 0x7a, 0xd2, 0xd5, 0x88, 0x74, 0x3d, 0xd9, 0x77, 0xf4, 0xb8, 0xb4, 0x06, 0xa4, 0x96, 0xb6, 0x65, + 0x75, 0xbb, 0xd8, 0x57, 0xda, 0xae, 0x7d, 0xa8, 0x92, 0x1e, 0xe9, 0x32, 0x98, 0xb7, 0xda, 0xd8, + 0x0f, 0x8b, 0xc2, 0x2d, 0xe1, 0xe1, 0x19, 0xc8, 0xbe, 0x94, 0xb6, 0xc1, 0xc3, 0x96, 0xa6, 0x77, + 0xf7, 0x3c, 0xcb, 0x77, 0x14, 0xaf, 0xd3, 0x6b, 0xe3, 0x10, 0x57, 0x3c, 0xd3, 0x2b, 0x5b, 0xc1, + 0x4b, 0xd6, 0x38, 0x18, 0xe1, 0x1a, 0x58, 0xe8, 0x07, 0xd8, 0xef, 0x5a, 0x1d, 0xcc, 0x07, 0x89, + 0xbf, 0x97, 0xee, 0x81, 0x3b, 0xf1, 0x38, 0xb2, 0xe3, 0x6c, 0xbb, 0x7e, 0x10, 0x42, 0x1c, 0x78, + 0x7d, 0xdf, 0xc6, 0x83, 0x21, 0x4a, 0x6b, 0x09, 0x71, 0xa3, 0x64, 0x35, 0x2b, 0x4c, 0x02, 0x2e, + 0x7d, 0x0c, 0x6e, 0xc7, 0xb4, 0x06, 0x0e, 0x15, 0x1f, 0x3b, 0xb8, 0x1b, 0xba, 0x56, 0xdb, 0xe8, + 0xef, 0x75, 0xdc, 0x30, 0x1b, 0x53, 0x72, 0x80, 0x4f, 0xfa, 0x38, 0x08, 0x5d, 0xaf, 0xdb, 0xb5, + 0x5c, 0x1f, 0xe7, 0x1d, 0xe0, 0x17, 0xc1, 0xbd, 0x78, 0x00, 0x88, 0x0f, 0xdc, 0x80, 0x00, 0x7c, + 0x69, 0xb5, 0xdb, 0xb8, 0x7b, 0x90, 0x77, 0x10, 0x69, 0x19, 0x2c, 0x74, 0xf6, 0x2d, 0x14, 0x9e, + 0xf4, 0x70, 0x71, 0x86, 0xf6, 0x9d, 0xee, 0xec, 0x5b, 0xe6, 0x49, 0x0f, 0x4b, 0xab, 0x00, 0xb4, + 0xbd, 0x03, 0xb7, 0x8b, 0xf6, 0xdb, 0xde, 0x71, 0x71, 0x96, 0x76, 0x9e, 0xa1, 0x2d, 0xdb, 0x6d, + 0xef, 0x98, 0xe1, 0x87, 0xd8, 0xf6, 0x8e, 0xb0, 0x7f, 0xa2, 0x78, 0x0e, 0x0e, 0x14, 0xaf, 0x1b, + 0xba, 0xdd, 0x3e, 0xce, 0xb9, 0x28, 0x1f, 0x82, 0xd5, 0xb1, 0x01, 0x7a, 0x27, 0x39, 0x99, 0x3f, + 0x02, 0x37, 0x46, 0x98, 0x9b, 0xbe, 0xdb, 0x0d, 0x73, 0x72, 0x97, 0x80, 0x58, 0x76, 0x03, 0xca, + 0x5c, 0xc7, 0xa1, 0xe5, 0x58, 0xa1, 0x25, 0x2d, 0x82, 0x19, 0xd7, 0xe1, 0x94, 0x33, 0xae, 0x53, + 0xb2, 0x40, 0x31, 0xa2, 0x89, 0x6c, 0x20, 0xa6, 0x55, 0xc1, 0x82, 0xcf, 0xdb, 0x28, 0xc7, 0xe2, + 0xe6, 0xa3, 0xf5, 0x09, 0xf6, 0xbe, 0x3e, 0x3a, 0x08, 0x8c, 0x59, 0x4b, 0x87, 0x40, 0x8a, 0x7a, + 0x8d, 0x10, 0xf7, 0x8c, 0xd0, 0x0a, 0xfb, 0x81, 0xf4, 0x31, 0x38, 0x15, 0xd0, 0x4f, 0x7c, 0xe8, + 0x07, 0x99, 0x43, 0x33, 0x46, 0xc8, 0xd9, 0xc8, 0x5e, 0xc2, 0xbe, 0xef, 0xf9, 0x7c, 0x41, 0xd9, + 0x97, 0xd2, 0x1f, 0x09, 0x60, 0xa9, 0xa5, 0x25, 0x58, 0xfc, 0x10, 0x3b, 0x4c, 0x55, 0x2a, 0x58, + 0xe8, 0xf0, 0xa9, 0x51, 0x99, 0x67, 0x73, 0x4c, 0x27, 0xd2, 0x05, 0x8c, 0x59, 0x25, 0x25, 0x06, + 0x3e, 0x43, 0x07, 0x79, 0x2b, 0x07, 0xf0, 0x68, 0xd6, 0x11, 0xf8, 0xd2, 0x7f, 0x0b, 0xe0, 0xd6, + 0x00, 0x66, 0xa4, 0x34, 0x03, 0xb7, 0xb1, 0x4d, 0x76, 0xc8, 0x2b, 0x05, 0x5c, 0x4f, 0x2c, 0x23, + 0x83, 0xfc, 0x38, 0xf7, 0x32, 0x0e, 0x86, 0x8b, 0x86, 0x48, 0xcc, 0x7f, 0xf6, 0x8b, 0xcf, 0xff, + 0xd7, 0x66, 0x88, 0x13, 0x8a, 0x08, 0xb4, 0x6e, 0x88, 0x0f, 0x7c, 0x8b, 0xcc, 0x5c, 0x7e, 0x61, + 0xe8, 0x5a, 0x59, 0x51, 0xbc, 0x6e, 0x17, 0xdb, 0xe1, 0x6b, 0xaf, 0x87, 0x1f, 0xcd, 0x24, 0xed, + 0xa0, 0x6c, 0x85, 0xd6, 0x9e, 0x15, 0x60, 0x58, 0x36, 0xd4, 0xae, 0xef, 0xb5, 0xdb, 0xaf, 0xfb, + 0xfc, 0xa5, 0xa7, 0xa0, 0x18, 0x50, 0xa3, 0xc7, 0x0e, 0x8a, 0x46, 0x0e, 0x90, 0xed, 0xf5, 0xbb, + 0x61, 0x71, 0xee, 0x96, 0xf0, 0x70, 0x16, 0x2e, 0x45, 0xfd, 0x11, 0x94, 0x40, 0x21, 0xbd, 0xa5, + 0x7f, 0x17, 0xc0, 0xf5, 0x81, 0xe6, 0x76, 0xfa, 0x7b, 0x58, 0xdd, 0x79, 0x43, 0xb4, 0x56, 0x7a, + 0x06, 0x8a, 0x2d, 0x4d, 0xb1, 0xda, 0x6d, 0xd3, 0x93, 0xa9, 0xbf, 0x48, 0x1c, 0x08, 0xeb, 0x60, + 0xd6, 0xe6, 0x33, 0x5e, 0xdc, 0xbc, 0x3e, 0x71, 0x74, 0xc5, 0x94, 0x21, 0x21, 0x2c, 0x7d, 0x6f, + 0x3e, 0xa9, 0xc7, 0x32, 0xee, 0xb5, 0xbd, 0x13, 0x03, 0xfb, 0x47, 0xae, 0x8d, 0x5f, 0x7b, 0xeb, + 0x3b, 0x00, 0xe7, 0x1d, 0x3a, 0x61, 0xd4, 0xc1, 0xe1, 0x4b, 0xcf, 0xa1, 0x26, 0xb7, 0xb8, 0xb9, + 0x35, 0x71, 0xac, 0x69, 0x8a, 0x5a, 0x67, 0x4d, 0x75, 0x3a, 0x12, 0x3c, 0xe7, 0x24, 0xbe, 0x49, + 0x16, 0x38, 0xcb, 0x05, 0xd1, 0x10, 0x64, 0x9e, 0x8a, 0xf9, 0x99, 0xff, 0x8b, 0x18, 0x12, 0xbb, + 0x40, 0xe0, 0xc4, 0x9f, 0x4b, 0x08, 0x9c, 0x4b, 0x02, 0x90, 0x56, 0xc1, 0x72, 0x59, 0x6d, 0xd6, + 0xf4, 0x5d, 0x54, 0x57, 0xcd, 0xaa, 0x5e, 0x46, 0xad, 0x86, 0xd1, 0x54, 0x15, 0x6d, 0x5b, 0x53, + 0xcb, 0x62, 0x41, 0x5a, 0x02, 0xd2, 0x70, 0xb7, 0xdc, 0x32, 0x75, 0x51, 0x90, 0x8a, 0xe0, 0xf2, + 0x70, 0x7b, 0x5d, 0x6e, 0xb4, 0xe4, 0x9a, 0x38, 0x53, 0xc2, 0x00, 0x0c, 0x44, 0x4b, 0x2b, 0xe0, + 0x2a, 0xa7, 0x33, 0x77, 0x9b, 0xea, 0xc8, 0xe0, 0x37, 0xc0, 0xb5, 0x64, 0xa7, 0xd6, 0x30, 0x4c, + 0xb9, 0x56, 0x43, 0x86, 0x02, 0xb5, 0xa6, 0x29, 0x0a, 0xd2, 0x35, 0xb0, 0x94, 0xec, 0x97, 0xeb, + 0xf2, 0xa7, 0x7a, 0x03, 0xa9, 0x8a, 0x21, 0xce, 0x94, 0x7e, 0x38, 0x07, 0xee, 0x0e, 0xe6, 0xaf, + 0xf8, 0xd8, 0x0a, 0x71, 0xf4, 0xed, 0x44, 0xf1, 0xba, 0xfb, 0xee, 0xc1, 0x6b, 0x6f, 0x97, 0x1e, + 0x38, 0x6f, 0xd3, 0x99, 0x0e, 0xdb, 0xe5, 0xb3, 0x1c, 0x06, 0x33, 0x59, 0x61, 0xeb, 0xec, 0x73, + 0x64, 0x9f, 0x76, 0xe2, 0x5b, 0xe9, 0x4f, 0x04, 0x70, 0x2e, 0xd9, 0x4d, 0xac, 0x47, 0xd1, 0x1b, + 0xdb, 0x5a, 0x25, 0xdd, 0x7a, 0xc6, 0xba, 0xe5, 0x17, 0x06, 0x52, 0x95, 0x4d, 0x64, 0x18, 0x75, + 0x51, 0x20, 0xeb, 0x9f, 0xde, 0xad, 0x6a, 0x8a, 0x2a, 0xce, 0xa4, 0xb3, 0xc3, 0xb2, 0x41, 0x4d, + 0x60, 0x56, 0x5a, 0x06, 0x57, 0x52, 0xd8, 0x77, 0x0c, 0x71, 0xae, 0xf4, 0x5f, 0x02, 0xb8, 0x99, + 0x72, 0x5e, 0xf2, 0x7b, 0xc1, 0x6b, 0xef, 0xf8, 0x7f, 0x69, 0x26, 0xb9, 0x39, 0xa2, 0xe9, 0xb3, + 0x95, 0xeb, 0xfb, 0xb8, 0x6e, 0xd6, 0x8c, 0xd7, 0x5e, 0x07, 0xbf, 0x39, 0x03, 0x1e, 0x27, 0x1d, + 0x64, 0x70, 0x18, 0x7a, 0x3d, 0x72, 0x0c, 0x1e, 0xe1, 0xb2, 0xeb, 0x63, 0x3b, 0xf4, 0xfc, 0x13, + 0xd3, 0xf3, 0xda, 0x81, 0xd6, 0x0d, 0x42, 0xeb, 0x0d, 0x88, 0x06, 0xbe, 0x33, 0x03, 0xd6, 0xb3, + 0x14, 0x12, 0x9b, 0xc8, 0x6b, 0xaf, 0x8d, 0x3f, 0x9b, 0x01, 0xf7, 0x07, 0xda, 0x90, 0xfb, 0xa1, + 0x17, 0x7d, 0x4e, 0x84, 0x90, 0xaf, 0xfd, 0x09, 0xf2, 0x00, 0x5c, 0x48, 0x0f, 0xa7, 0x17, 0xfd, + 0xe1, 0x30, 0xfa, 0x5b, 0x33, 0xe0, 0xce, 0x40, 0x5d, 0xaa, 0xb2, 0x49, 0x77, 0x4d, 0xf7, 0x4d, + 0xba, 0x8b, 0xfe, 0x9b, 0x00, 0x96, 0x47, 0x23, 0x2e, 0x72, 0x50, 0xbd, 0x61, 0x13, 0x67, 0x91, + 0x43, 0xc3, 0x73, 0x5e, 0x7f, 0x1f, 0xf1, 0x9f, 0x02, 0xb8, 0x31, 0x3a, 0x71, 0xb9, 0xd7, 0x23, + 0x61, 0xf6, 0x1b, 0x10, 0x44, 0x7c, 0x7b, 0x06, 0x3c, 0x9a, 0x12, 0x44, 0x68, 0x72, 0xbd, 0xe9, + 0xb5, 0x5d, 0xfb, 0xe4, 0xb5, 0x57, 0xc4, 0xff, 0x08, 0xa0, 0x34, 0x50, 0x44, 0xd3, 0x77, 0xbb, + 0xb6, 0xdb, 0xb3, 0xda, 0xc1, 0x9b, 0x73, 0x58, 0xfe, 0x87, 0x00, 0x56, 0x07, 0x1a, 0x30, 0x71, + 0x10, 0xf2, 0x87, 0xb7, 0x37, 0xc1, 0xef, 0xff, 0xab, 0x00, 0x8a, 0x09, 0x2f, 0xc0, 0x13, 0x2f, + 0xce, 0x6b, 0x3f, 0xef, 0x15, 0xe2, 0xf5, 0xb9, 0xb7, 0xc7, 0xc7, 0xd0, 0x6b, 0x27, 0x93, 0x43, + 0x37, 0x89, 0x41, 0x0c, 0x75, 0x1a, 0xd6, 0x51, 0x92, 0xe0, 0x36, 0xb9, 0x80, 0x0d, 0x73, 0x93, + 0x70, 0xa1, 0x9d, 0x20, 0x79, 0x1b, 0xac, 0x8d, 0x90, 0x3c, 0x77, 0xf1, 0x71, 0xd9, 0xb3, 0xfb, + 0x1d, 0xdc, 0x0d, 0xad, 0xe1, 0x07, 0xab, 0xd2, 0x5f, 0x08, 0xe0, 0x8a, 0x1c, 0x04, 0x2e, 0xb1, + 0x3d, 0xba, 0x04, 0xb1, 0xed, 0x3d, 0x00, 0x17, 0x6c, 0xaf, 0x7b, 0x84, 0xfd, 0x80, 0xf2, 0xa0, + 0x38, 0x71, 0xb1, 0x98, 0x6c, 0xd6, 0x1c, 0xe9, 0x36, 0x38, 0x17, 0x7a, 0xa1, 0xd5, 0x46, 0xa1, + 0x77, 0x88, 0xbb, 0xec, 0x61, 0x7e, 0x16, 0x9e, 0xa5, 0x6d, 0x26, 0x6d, 0x92, 0xee, 0x80, 0xf3, + 0x3d, 0xdf, 0xeb, 0xf4, 0xc2, 0x88, 0x66, 0x96, 0xd2, 0x9c, 0x63, 0x8d, 0x9c, 0xe8, 0x2d, 0x70, + 0xd1, 0x8e, 0x31, 0x44, 0x84, 0x2c, 0x6e, 0x12, 0x07, 0x1d, 0x8c, 0xb8, 0xf4, 0x77, 0x02, 0xb8, + 0xcc, 0x70, 0xab, 0x9f, 0x61, 0xbb, 0xff, 0x05, 0x60, 0xaf, 0x02, 0xd0, 0xf5, 0x1c, 0xcc, 0xe3, + 0x33, 0x06, 0xfa, 0x0c, 0x69, 0xa1, 0xa1, 0xd9, 0xd8, 0xac, 0x66, 0x73, 0xcc, 0x6a, 0x2e, 0xef, + 0xac, 0xe6, 0x27, 0xcc, 0xea, 0x29, 0xb8, 0xc6, 0x26, 0xd5, 0xc0, 0xc7, 0x4a, 0x02, 0x6e, 0x9c, + 0x6d, 0xb2, 0xad, 0x10, 0x1f, 0x78, 0xfe, 0x49, 0x94, 0x6d, 0x8a, 0xbe, 0x97, 0xfe, 0x5c, 0x00, + 0x97, 0x18, 0xab, 0x6c, 0xdb, 0x38, 0x08, 0x20, 0xfe, 0x46, 0x1f, 0x07, 0x21, 0xc1, 0x18, 0xd9, + 0x2f, 0x7b, 0xfd, 0x62, 0x8c, 0xe7, 0xa2, 0x46, 0xfa, 0x9c, 0xf4, 0x53, 0x59, 0xc1, 0x1f, 0x0a, + 0xe0, 0x5c, 0x84, 0x98, 0x34, 0x4b, 0x4b, 0xe0, 0x94, 0x45, 0x3f, 0x71, 0x8c, 0xfc, 0xdb, 0x4f, + 0x07, 0xdd, 0x5d, 0x20, 0x31, 0x45, 0xd6, 0xdc, 0x20, 0x9c, 0x98, 0xbf, 0xfb, 0x1a, 0x10, 0x07, + 0x54, 0x6c, 0xcf, 0x49, 0x95, 0x31, 0xdf, 0x35, 0xd9, 0x4f, 0x8c, 0x8b, 0x18, 0x78, 0xaf, 0xe1, + 0xc1, 0x5b, 0x3d, 0xe7, 0x27, 0x37, 0x78, 0x19, 0x13, 0xdf, 0xfb, 0xea, 0x06, 0xb7, 0xc0, 0x52, + 0xb2, 0xbf, 0xb3, 0x17, 0x85, 0x79, 0x3f, 0x51, 0x11, 0xaf, 0x5a, 0x45, 0x29, 0x22, 0x5e, 0xb5, + 0xa2, 0x7e, 0x3e, 0x29, 0xa2, 0xe2, 0x5b, 0xdd, 0x30, 0x30, 0xbd, 0x56, 0x80, 0x7d, 0x69, 0x1d, + 0x5c, 0xa2, 0x8e, 0x09, 0xf9, 0x5e, 0x1b, 0x07, 0xe8, 0x80, 0xf4, 0x61, 0x66, 0x7a, 0xf3, 0xf0, + 0x22, 0xed, 0x22, 0xae, 0x3d, 0xa8, 0xb0, 0x0e, 0xe9, 0x5d, 0x70, 0x99, 0xd1, 0x87, 0xbe, 0xe5, + 0x86, 0x03, 0x86, 0x19, 0xca, 0x20, 0xd1, 0x3e, 0x93, 0x76, 0x71, 0x8e, 0xd2, 0x0f, 0x66, 0x93, + 0xc2, 0x21, 0x3e, 0x72, 0xf1, 0xf1, 0x2b, 0x5e, 0x25, 0xe9, 0x29, 0x58, 0x76, 0xac, 0x93, 0x00, + 0xf5, 0xac, 0x20, 0x44, 0x5d, 0xfc, 0x59, 0x88, 0xac, 0xbe, 0xe3, 0x86, 0x88, 0x2c, 0x14, 0x87, + 0x76, 0x85, 0x10, 0x34, 0x2d, 0xe2, 0xf2, 0x3e, 0x0b, 0x65, 0xd2, 0x5b, 0x26, 0x10, 0xb6, 0xc1, + 0xcd, 0x0e, 0x55, 0x79, 0xf0, 0xd2, 0xed, 0x21, 0x1f, 0x7f, 0xa3, 0xef, 0xfa, 0x98, 0x1c, 0x60, + 0x01, 0xb2, 0x5f, 0x5a, 0xdd, 0x03, 0xec, 0xd0, 0x3d, 0xbe, 0x00, 0x57, 0x07, 0x64, 0x30, 0x41, + 0xa5, 0x30, 0x22, 0xe9, 0x29, 0x28, 0xfa, 0x74, 0x6a, 0x68, 0x9f, 0x0c, 0x82, 0xbb, 0xf6, 0x49, + 0x3c, 0xc0, 0x1c, 0x1d, 0x60, 0x89, 0xf5, 0x6f, 0x47, 0xdd, 0x11, 0xe7, 0x47, 0x60, 0x85, 0x73, + 0x3a, 0xd6, 0x09, 0xf2, 0xf6, 0x51, 0xc7, 0xeb, 0x86, 0x2f, 0x63, 0xe6, 0x79, 0xca, 0x7c, 0x95, + 0x91, 0x94, 0xad, 0x13, 0x7d, 0xbf, 0x4e, 0xfa, 0x23, 0xee, 0xaf, 0x80, 0xe5, 0x6e, 0x9f, 0x00, + 0x23, 0x9c, 0x3e, 0xee, 0x78, 0x47, 0xd8, 0x41, 0x1c, 0x6a, 0xf1, 0x14, 0x9d, 0xf9, 0x12, 0x23, + 0xd0, 0xf7, 0x21, 0xeb, 0x66, 0x26, 0x16, 0x94, 0x7e, 0x47, 0x18, 0x5f, 0x98, 0x57, 0x6c, 0x78, + 0xd2, 0x63, 0x70, 0xc5, 0xa2, 0xfd, 0xa8, 0xed, 0x06, 0x21, 0xe2, 0x13, 0x75, 0x1d, 0x9e, 0xce, + 0x97, 0xac, 0x11, 0xf9, 0x9a, 0x53, 0xfa, 0xae, 0x00, 0x96, 0x13, 0xa9, 0x62, 0x96, 0xec, 0x9b, + 0xe4, 0x19, 0xa5, 0x2d, 0x30, 0x77, 0xe8, 0x76, 0xd9, 0x78, 0x8b, 0x9b, 0xeb, 0x13, 0x51, 0x8e, + 0x8d, 0xb8, 0xe3, 0x76, 0x1d, 0x48, 0x79, 0xa5, 0x15, 0x70, 0xa6, 0x1f, 0x60, 0x1f, 0xd1, 0xf2, + 0x8a, 0xd9, 0x41, 0x79, 0x45, 0xc3, 0xea, 0xe0, 0x92, 0x47, 0x42, 0xa5, 0x31, 0x6e, 0x5a, 0x72, + 0xc0, 0x4e, 0xcb, 0xc6, 0x98, 0xae, 0x36, 0xf3, 0xa3, 0x48, 0xd9, 0xab, 0x3e, 0xb8, 0x95, 0x22, + 0x30, 0x0a, 0x5c, 0x7f, 0x32, 0x32, 0xff, 0x41, 0x00, 0x97, 0xe2, 0x1a, 0x22, 0xba, 0x37, 0x99, + 0x9c, 0x5c, 0xa7, 0x7a, 0xe2, 0x15, 0x0a, 0x79, 0xbe, 0x7b, 0xe0, 0x76, 0xf9, 0xea, 0xc6, 0xaf, + 0x50, 0x3a, 0x6d, 0x95, 0xee, 0x81, 0x45, 0xbb, 0xed, 0xf5, 0x1d, 0xd4, 0xf3, 0xbd, 0x23, 0xd7, + 0xc1, 0x3e, 0x57, 0xf6, 0x79, 0xda, 0xda, 0xe4, 0x8d, 0x92, 0x0e, 0x16, 0x1c, 0x7e, 0x5d, 0xa5, + 0x5b, 0xe7, 0xec, 0xe6, 0x93, 0xcc, 0x00, 0x18, 0x3b, 0xd1, 0x0d, 0x77, 0x30, 0xbb, 0x68, 0x90, + 0xd2, 0x73, 0x70, 0x6d, 0x32, 0x9d, 0x74, 0x15, 0x9c, 0x76, 0xf6, 0x92, 0xb3, 0x3b, 0xe5, 0xec, + 0xd1, 0x79, 0xdd, 0x04, 0x67, 0x9d, 0x3d, 0x44, 0x2b, 0xc0, 0x6c, 0xaf, 0xcd, 0xe7, 0x04, 0x9c, + 0xbd, 0x26, 0x6f, 0x29, 0xfd, 0x8b, 0x00, 0xae, 0x6d, 0x63, 0x2b, 0xec, 0xfb, 0x18, 0x62, 0xdb, + 0xeb, 0x74, 0x70, 0xd7, 0x49, 0x84, 0x51, 0x43, 0x66, 0x25, 0x0c, 0x9b, 0x95, 0xf4, 0x01, 0x38, + 0xbd, 0xcf, 0x58, 0xb9, 0xe9, 0xde, 0x9a, 0x38, 0xc7, 0x48, 0x44, 0xc4, 0x20, 0x7d, 0x06, 0x56, + 0xf9, 0x47, 0xe4, 0x0f, 0xc9, 0x45, 0x89, 0x6b, 0xc3, 0xe2, 0xe6, 0x7b, 0x99, 0x23, 0x0e, 0x31, + 0xf3, 0xfb, 0xc3, 0xca, 0xfe, 0xe4, 0xce, 0xd2, 0x31, 0xb8, 0x6c, 0xca, 0x15, 0x16, 0x09, 0xe3, + 0x4f, 0xfa, 0xd8, 0xe7, 0xcf, 0x07, 0x37, 0x01, 0x0b, 0x93, 0x10, 0x89, 0x6b, 0x59, 0xad, 0xcf, + 0x2c, 0x04, 0xb4, 0xa9, 0x41, 0x5a, 0x06, 0x04, 0xd8, 0x39, 0xc0, 0x51, 0x68, 0xc5, 0x08, 0x54, + 0xd2, 0x42, 0xa2, 0x64, 0x37, 0x40, 0x41, 0x9f, 0xfa, 0x03, 0xee, 0x72, 0xcf, 0xb8, 0x81, 0xc1, + 0x1a, 0x4a, 0xff, 0x3c, 0x0b, 0xae, 0x32, 0x47, 0x53, 0xf1, 0xad, 0xde, 0x4b, 0xf9, 0x85, 0x61, + 0xd8, 0x56, 0x37, 0xca, 0x85, 0x5f, 0xe2, 0x63, 0xdb, 0x9b, 0xc8, 0xe5, 0x0f, 0x9b, 0x0c, 0xc4, + 0x1c, 0xbc, 0xc8, 0x64, 0xd8, 0xf1, 0x8b, 0x67, 0x02, 0x0b, 0x59, 0x0c, 0x86, 0x65, 0x8e, 0x63, + 0x21, 0x47, 0x62, 0x30, 0x08, 0x04, 0x0f, 0x7c, 0xaf, 0xdf, 0x63, 0x68, 0xe6, 0x78, 0x20, 0x58, + 0xa1, 0x4d, 0x83, 0x31, 0xe8, 0xb1, 0x49, 0xcd, 0x34, 0x1a, 0x83, 0x1e, 0x97, 0xc4, 0xd6, 0x19, + 0x41, 0xcf, 0x6b, 0xbb, 0xb6, 0x8b, 0x59, 0x2c, 0x3e, 0x07, 0xcf, 0xd3, 0xd6, 0x26, 0x6f, 0x94, + 0xde, 0x06, 0x12, 0xc7, 0x7e, 0x18, 0x20, 0xbb, 0xdd, 0x0f, 0xc2, 0xc8, 0x6f, 0xcf, 0x41, 0x91, + 0x41, 0x3f, 0x0c, 0x14, 0xde, 0x3e, 0x98, 0xa9, 0xef, 0x04, 0x89, 0x99, 0x9e, 0x4e, 0xcc, 0x14, + 0x3a, 0xc1, 0x60, 0xa6, 0x0f, 0x01, 0x1b, 0x03, 0x05, 0x4f, 0xd0, 0x5e, 0xdf, 0x3e, 0xc4, 0x61, + 0x50, 0x5c, 0xa0, 0xc4, 0x0c, 0x9c, 0xf1, 0x64, 0x8b, 0xb5, 0x92, 0x63, 0x9d, 0x53, 0x5a, 0x9d, + 0x76, 0xbc, 0x3f, 0x83, 0xe2, 0x19, 0x4a, 0xcd, 0x30, 0x1a, 0x56, 0xa7, 0x1d, 0x6d, 0xd2, 0x04, + 0x87, 0xe7, 0x3a, 0x76, 0x82, 0x03, 0x24, 0x38, 0x74, 0xd7, 0xb1, 0x07, 0x1c, 0xb1, 0x4a, 0x2c, + 0x9b, 0x86, 0x09, 0x41, 0xf1, 0x6c, 0x42, 0x25, 0x32, 0x6f, 0x2c, 0xfd, 0x40, 0x00, 0x77, 0x5b, + 0x5a, 0x62, 0xb1, 0x15, 0xdf, 0x3b, 0xee, 0x3e, 0xc3, 0xc7, 0xb8, 0x5d, 0x76, 0xf7, 0xf7, 0xc9, + 0x25, 0x93, 0xad, 0xfb, 0x53, 0x50, 0xb4, 0xf6, 0xf7, 0x87, 0xab, 0x4a, 0x50, 0xa2, 0x90, 0xed, + 0x0c, 0x5c, 0x8a, 0xfa, 0xe3, 0xd2, 0x2b, 0x76, 0xc1, 0x7e, 0x0f, 0x2c, 0x8d, 0x73, 0x26, 0xca, + 0x06, 0x2f, 0x8f, 0xf2, 0xd1, 0xdc, 0xfb, 0x36, 0xb8, 0x6e, 0x60, 0xbb, 0xef, 0xbb, 0xe1, 0x09, + 0xa4, 0xdb, 0xaa, 0x82, 0x43, 0x88, 0x83, 0x7e, 0x9b, 0x1f, 0x04, 0x12, 0x98, 0x4b, 0x6c, 0x75, + 0xfa, 0x99, 0xb4, 0x91, 0xb8, 0x83, 0xc7, 0x20, 0xf4, 0x73, 0xc9, 0x02, 0x97, 0xe2, 0xcc, 0xed, + 0x36, 0x0e, 0xed, 0x97, 0x8c, 0x7d, 0xdc, 0x3b, 0x0a, 0x69, 0xde, 0x71, 0xcc, 0x25, 0xcf, 0x8c, + 0xbb, 0xe4, 0xd2, 0xf7, 0x05, 0x20, 0x11, 0x5b, 0x36, 0xad, 0xe0, 0x90, 0x6c, 0x5d, 0x1c, 0x7b, + 0xa4, 0xd0, 0x0a, 0x0e, 0x93, 0xce, 0x6e, 0x81, 0x34, 0x44, 0x25, 0x92, 0x6e, 0x10, 0xf4, 0x87, + 0x46, 0x3d, 0x43, 0x5b, 0x68, 0xf7, 0x65, 0x30, 0x4f, 0xbc, 0x4b, 0x74, 0x40, 0xb2, 0x2f, 0xc4, + 0xf7, 0xc7, 0x76, 0x98, 0xc8, 0x40, 0xcc, 0xc3, 0xc5, 0xb8, 0x99, 0x65, 0x20, 0xfe, 0xfa, 0x03, + 0x70, 0xa1, 0x45, 0xbc, 0x10, 0x45, 0xa2, 0x77, 0xb1, 0xbe, 0x2f, 0xb5, 0xc0, 0x85, 0xbe, 0x8b, + 0xf6, 0x68, 0xf9, 0x2c, 0xb2, 0xdb, 0xae, 0x7d, 0x98, 0x19, 0x6c, 0x8c, 0x57, 0xdb, 0x56, 0x0b, + 0xf0, 0x7c, 0xdf, 0x4d, 0xb4, 0x4a, 0x3f, 0x14, 0xc0, 0xa3, 0xbe, 0x8b, 0x3c, 0x56, 0x4d, 0x8a, + 0xf8, 0x95, 0x0b, 0xa3, 0x03, 0x0f, 0x85, 0x1e, 0x72, 0xa2, 0x72, 0x5b, 0x2e, 0x91, 0x3d, 0xb1, + 0xc8, 0x53, 0x24, 0xe6, 0xab, 0xd9, 0xad, 0x16, 0xe0, 0x9d, 0xbe, 0x9b, 0x49, 0x2b, 0x7d, 0x47, + 0x00, 0x77, 0x12, 0xe8, 0x2c, 0xc7, 0x41, 0xfb, 0xae, 0x4f, 0x63, 0x23, 0xbe, 0xaa, 0x0c, 0x17, + 0x3b, 0xf9, 0x3e, 0xca, 0xc6, 0x35, 0xb9, 0x06, 0xb8, 0x5a, 0x80, 0x37, 0x62, 0x48, 0xa9, 0x64, + 0xa3, 0xba, 0x4a, 0x41, 0xd3, 0xb6, 0xc2, 0x78, 0x75, 0xe6, 0xf3, 0xea, 0x2a, 0xa3, 0xe0, 0x78, + 0x48, 0x57, 0x93, 0x69, 0xa5, 0x5f, 0x15, 0xc0, 0xad, 0x04, 0xba, 0x00, 0x87, 0xc8, 0x8e, 0x6b, + 0x93, 0x51, 0x40, 0xcb, 0x82, 0xa9, 0xb3, 0x3c, 0xbb, 0xf9, 0x41, 0x36, 0xa8, 0x49, 0x95, 0xcd, + 0xd5, 0x02, 0xbc, 0x1e, 0xa3, 0x49, 0x21, 0x92, 0x7e, 0x4b, 0x00, 0x77, 0x13, 0x30, 0x7c, 0x5e, + 0x87, 0x40, 0x42, 0x74, 0x56, 0xa0, 0x1c, 0x41, 0x39, 0x4d, 0xa1, 0xfc, 0xff, 0x6c, 0x28, 0xd3, + 0x4a, 0x9c, 0xab, 0x05, 0x78, 0x2b, 0x86, 0x33, 0x81, 0x30, 0xd2, 0x8c, 0xcf, 0x8b, 0x86, 0x91, + 0x4d, 0x4e, 0x59, 0x64, 0xf3, 0xa2, 0x65, 0xbe, 0x5c, 0x0b, 0x99, 0x9a, 0xc9, 0x28, 0x79, 0x66, + 0x9a, 0x99, 0x4c, 0x24, 0x7d, 0x06, 0xae, 0xa7, 0xa1, 0xe8, 0x9d, 0x70, 0x04, 0x67, 0x28, 0x82, + 0x2f, 0xe7, 0x47, 0x90, 0xac, 0x99, 0xae, 0x16, 0x60, 0x71, 0x4c, 0x3a, 0x27, 0x90, 0x7e, 0x01, + 0xac, 0x8e, 0x4b, 0xee, 0xf9, 0x6e, 0x37, 0xe4, 0xa2, 0x01, 0x15, 0xfd, 0x7e, 0x5e, 0xd1, 0x23, + 0x15, 0xd7, 0xd5, 0x02, 0x5c, 0x1e, 0x91, 0x3d, 0xa0, 0x90, 0xda, 0x60, 0xb9, 0xef, 0x22, 0x87, + 0x3b, 0x71, 0x12, 0x75, 0xf9, 0xe4, 0x28, 0xa1, 0x83, 0xd3, 0x43, 0xed, 0xec, 0xe6, 0x46, 0x8e, + 0x2a, 0x9e, 0x64, 0xdd, 0x72, 0xb5, 0x00, 0x97, 0xfa, 0x6e, 0x6a, 0x45, 0xf3, 0x77, 0x98, 0xf9, + 0xc5, 0xe2, 0x06, 0x67, 0x5d, 0x94, 0xbc, 0xe5, 0x92, 0xcf, 0x51, 0xc9, 0x5f, 0xc9, 0x21, 0x39, + 0xbd, 0x14, 0x99, 0x59, 0x5e, 0x46, 0xb9, 0xf2, 0x37, 0xa9, 0xe1, 0xc5, 0x60, 0x78, 0xc1, 0x5b, + 0xc0, 0x6a, 0xd7, 0x38, 0x90, 0xf3, 0x14, 0xc8, 0x97, 0xbe, 0x50, 0xe5, 0x1b, 0xb3, 0xb9, 0x29, + 0x95, 0x8a, 0xbf, 0xce, 0x1c, 0xe8, 0x00, 0x01, 0x0f, 0xe8, 0x07, 0xfb, 0x92, 0x81, 0x58, 0xa4, + 0x20, 0x9e, 0xe6, 0x01, 0x91, 0x56, 0x60, 0x54, 0x2d, 0xc0, 0x9b, 0x09, 0x1c, 0xa9, 0x35, 0x48, + 0xbf, 0xcb, 0xbc, 0xe7, 0x38, 0x14, 0x3b, 0xca, 0x2d, 0xa1, 0x4e, 0xd8, 0x0e, 0x38, 0xa0, 0x0b, + 0x14, 0xd0, 0xff, 0xfb, 0x1c, 0x80, 0xc6, 0x4b, 0x7e, 0xaa, 0x05, 0x78, 0x77, 0x1c, 0xd5, 0x80, + 0x2e, 0x6c, 0xf3, 0xaa, 0x87, 0xbf, 0x12, 0xc0, 0xd3, 0xe1, 0x75, 0xa2, 0x05, 0x23, 0xc8, 0xa2, + 0x15, 0x23, 0xc8, 0x89, 0x4a, 0x46, 0x50, 0xe8, 0x79, 0x6d, 0x1e, 0x4c, 0xb6, 0xdb, 0x1c, 0xa9, + 0x48, 0x91, 0x3e, 0xcb, 0xb5, 0x7e, 0xb9, 0x0a, 0x73, 0xaa, 0x05, 0xf8, 0x38, 0xb9, 0xa8, 0xf9, + 0xaa, 0x79, 0x7e, 0x24, 0x80, 0xf7, 0x72, 0xcd, 0x61, 0xa0, 0x6e, 0x86, 0xff, 0x22, 0xc5, 0x5f, + 0xf9, 0xc2, 0xf8, 0x87, 0x53, 0x83, 0xd5, 0x02, 0x5c, 0xcf, 0x02, 0x3f, 0x92, 0x4c, 0xfc, 0x3d, + 0x01, 0xbc, 0x95, 0x44, 0x6e, 0xf5, 0x49, 0xe4, 0x11, 0xdf, 0x41, 0x13, 0x45, 0xd0, 0x0c, 0xb0, + 0x44, 0x01, 0x7f, 0x9c, 0x03, 0xf0, 0xb4, 0x52, 0x97, 0x6a, 0x01, 0xde, 0x1f, 0x00, 0x9d, 0x5a, + 0x14, 0xf3, 0xa7, 0x02, 0xd8, 0xc8, 0xb0, 0x5c, 0xd7, 0xea, 0xb0, 0xcb, 0xcb, 0x09, 0x07, 0x79, + 0x89, 0x82, 0xdc, 0xfa, 0x22, 0xf6, 0x3b, 0x9c, 0x6d, 0xae, 0x16, 0xe0, 0xa3, 0x29, 0x46, 0xac, + 0x59, 0x9d, 0x64, 0x6a, 0xfa, 0xb7, 0x05, 0x70, 0x3f, 0x09, 0xb5, 0x17, 0x67, 0x70, 0xc7, 0xd6, + 0xfd, 0x32, 0x45, 0xf8, 0x61, 0x0e, 0x84, 0x93, 0xd2, 0xc0, 0xd5, 0x02, 0x2c, 0x0d, 0xa0, 0x4d, + 0x4c, 0x16, 0xff, 0xb2, 0x00, 0x6e, 0x27, 0x31, 0x85, 0x38, 0x08, 0x09, 0x9a, 0xee, 0x90, 0x3f, + 0xbe, 0x92, 0x79, 0xfa, 0x4d, 0xc9, 0xc9, 0x56, 0x0b, 0x70, 0x75, 0x80, 0x24, 0x2d, 0x69, 0xeb, + 0x83, 0x95, 0x24, 0x86, 0x28, 0xce, 0x8d, 0xce, 0xa1, 0xa5, 0x8c, 0x44, 0xe4, 0xa4, 0xa4, 0x28, + 0x3b, 0x76, 0x27, 0x24, 0x4c, 0xdb, 0xa0, 0xd8, 0x77, 0x49, 0x10, 0x66, 0x85, 0x18, 0x75, 0xf1, + 0x31, 0xbd, 0xff, 0xf2, 0x13, 0xf7, 0x6a, 0xc6, 0x43, 0xd4, 0xc4, 0x74, 0x64, 0xb5, 0x00, 0x2f, + 0xf7, 0xdd, 0xf1, 0x4e, 0xe9, 0x84, 0x1e, 0xf2, 0xa3, 0xd2, 0x02, 0xeb, 0x28, 0x12, 0x59, 0xcc, + 0xd4, 0xf0, 0x94, 0x24, 0x27, 0x9b, 0x68, 0x3a, 0x81, 0xf4, 0x4d, 0x70, 0x33, 0x6d, 0xa2, 0x34, + 0x09, 0xca, 0x85, 0x2f, 0x67, 0x1e, 0x30, 0x53, 0x13, 0xa8, 0xd5, 0x02, 0xbc, 0x36, 0x3a, 0xeb, + 0x01, 0x89, 0xf4, 0x07, 0xcc, 0x85, 0x8c, 0x22, 0x60, 0x0f, 0xc5, 0xc9, 0x24, 0x2b, 0x47, 0x73, + 0x8d, 0xa2, 0x51, 0xf2, 0xa2, 0x99, 0x92, 0xab, 0xad, 0x16, 0xe0, 0xbd, 0x11, 0x60, 0xe9, 0xd4, + 0xd2, 0x1f, 0x0b, 0x60, 0x3d, 0x69, 0x82, 0xee, 0xe0, 0xa9, 0x11, 0x59, 0xc7, 0x01, 0x7b, 0x1a, + 0xe0, 0xdb, 0x82, 0x5b, 0xe5, 0x4a, 0xe6, 0x15, 0x22, 0xdf, 0xcf, 0x85, 0xaa, 0x05, 0xf8, 0x70, + 0x60, 0xa5, 0x49, 0xda, 0xe3, 0x40, 0x77, 0x1d, 0x7b, 0xe8, 0xa7, 0x45, 0xdf, 0x15, 0xc0, 0xbd, + 0xf4, 0x90, 0xc1, 0x09, 0x10, 0xa6, 0x8f, 0xa2, 0x1c, 0xde, 0xf5, 0xdc, 0x21, 0x54, 0xfa, 0xaf, + 0x78, 0x86, 0x43, 0xa8, 0x98, 0xc6, 0x09, 0x92, 0xbf, 0x59, 0x09, 0x99, 0x59, 0x93, 0xf3, 0x36, + 0xf4, 0x10, 0xcb, 0x3e, 0xb2, 0x55, 0xe4, 0x28, 0x56, 0x33, 0xb7, 0x6e, 0xfa, 0xcf, 0x42, 0xb8, + 0x45, 0xa7, 0xff, 0x64, 0xe4, 0xeb, 0xe0, 0xa2, 0x45, 0xd3, 0xa0, 0x68, 0x90, 0x84, 0x2c, 0xde, + 0xa0, 0x92, 0x26, 0x3f, 0x9b, 0xa7, 0xa6, 0xec, 0xab, 0x05, 0x28, 0x5a, 0x23, 0x1d, 0x91, 0x4b, + 0x4c, 0x9a, 0x00, 0xd7, 0x2c, 0x0d, 0x8f, 0xf9, 0xcc, 0x6e, 0x66, 0x6e, 0xd8, 0x29, 0x4f, 0xed, + 0xcc, 0x25, 0x4e, 0x7b, 0x8b, 0xe7, 0xa1, 0x72, 0x0a, 0x88, 0xf8, 0x15, 0x80, 0xe1, 0xb8, 0x95, + 0xb9, 0xce, 0xd3, 0x5f, 0xe0, 0xd9, 0x3a, 0x67, 0xbc, 0xd2, 0xff, 0x8a, 0x40, 0x9d, 0x48, 0x74, + 0x6f, 0xfc, 0x46, 0xf2, 0x87, 0xb1, 0xd1, 0x95, 0xf1, 0x76, 0xde, 0xdb, 0xeb, 0xa4, 0x9f, 0xd5, + 0x0e, 0xdd, 0x5e, 0x53, 0x88, 0xa4, 0x4f, 0x01, 0x5f, 0x2c, 0x84, 0xa3, 0x0a, 0x86, 0x62, 0x89, + 0x4a, 0x7d, 0x27, 0x63, 0xd9, 0x87, 0x2b, 0x1e, 0xaa, 0x05, 0x78, 0xc1, 0x1a, 0x6e, 0x97, 0x3a, + 0xe0, 0x2a, 0x1f, 0x9b, 0x38, 0xa8, 0x64, 0xe1, 0x43, 0xf1, 0x4e, 0xc6, 0xcb, 0xfd, 0xe4, 0xfa, + 0x83, 0x6a, 0x01, 0x5e, 0xb1, 0xd2, 0x7a, 0xa5, 0x3d, 0x70, 0x65, 0xf0, 0x4a, 0xc2, 0x1c, 0x23, + 0x5b, 0xce, 0xbb, 0x54, 0xd8, 0xdb, 0x13, 0x85, 0xa5, 0xe4, 0x36, 0xaa, 0x05, 0x78, 0xc9, 0x4f, + 0x49, 0x79, 0x1c, 0x83, 0xeb, 0x13, 0x1e, 0xd7, 0x99, 0xa8, 0x7b, 0x19, 0xf3, 0x9a, 0x9c, 0x10, + 0x20, 0x0e, 0x7f, 0x7f, 0x72, 0xba, 0x60, 0x0f, 0xf0, 0x59, 0x23, 0x9e, 0x31, 0xf3, 0x59, 0x69, + 0x45, 0xf1, 0x7e, 0xc6, 0xe4, 0x52, 0xca, 0x31, 0xc8, 0xe4, 0xac, 0x94, 0x2a, 0x8d, 0x1a, 0x38, + 0x1f, 0xcb, 0xa0, 0xab, 0xf4, 0x80, 0x8e, 0x7d, 0x2f, 0x73, 0x6c, 0x42, 0x5c, 0x2d, 0xc0, 0x73, + 0x56, 0xb2, 0x90, 0x62, 0x17, 0x48, 0xc9, 0xe4, 0x1e, 0x5b, 0x91, 0xe2, 0xc3, 0x8c, 0x3a, 0xaa, + 0xd1, 0x42, 0x06, 0xea, 0x4d, 0x46, 0x8b, 0x1b, 0x46, 0x86, 0xee, 0xd3, 0x94, 0x7b, 0xf1, 0x51, + 0xee, 0xa1, 0x59, 0x8e, 0x7e, 0x78, 0x68, 0x9e, 0xb7, 0x1f, 0x19, 0xda, 0xa1, 0x19, 0xcf, 0xe2, + 0x5a, 0xee, 0xa1, 0x59, 0x8a, 0x74, 0x78, 0x68, 0x9e, 0x36, 0x6d, 0x83, 0xe5, 0xe4, 0xd0, 0x2c, + 0x0d, 0x1b, 0xe9, 0xe5, 0xad, 0x8c, 0x77, 0x81, 0xf4, 0x4a, 0x86, 0x6a, 0x01, 0x2e, 0x59, 0xe9, + 0x35, 0x0e, 0xe9, 0xd2, 0xb8, 0xaa, 0xde, 0xfe, 0x9c, 0xd2, 0x62, 0x85, 0x8d, 0x49, 0xe3, 0x6a, + 0x4b, 0x97, 0xc6, 0xb5, 0xf7, 0xce, 0xe7, 0x94, 0x16, 0xeb, 0x70, 0x4c, 0x1a, 0xd7, 0x64, 0x07, + 0x5c, 0x4b, 0x4a, 0xa3, 0x55, 0x06, 0x01, 0x39, 0x2d, 0xfb, 0x01, 0xf6, 0x8b, 0xeb, 0xb9, 0xc5, + 0x25, 0x6b, 0x1d, 0x86, 0xc5, 0x0d, 0x55, 0x41, 0xfc, 0x86, 0x00, 0x4a, 0xc9, 0x00, 0x21, 0x99, + 0x49, 0x1a, 0x3c, 0xb3, 0x14, 0x37, 0x32, 0xdf, 0x64, 0x33, 0x4b, 0xec, 0xd9, 0x9b, 0x6c, 0x4c, + 0x66, 0x8f, 0x93, 0x49, 0x87, 0xe0, 0x6a, 0xca, 0x0b, 0x0b, 0x76, 0x6d, 0x5c, 0x7c, 0x37, 0x33, + 0xc4, 0x9e, 0x50, 0xe0, 0xce, 0x42, 0xec, 0x91, 0x4e, 0xd7, 0xc6, 0xa3, 0xc2, 0xa2, 0x70, 0xd3, + 0x73, 0x70, 0xf1, 0x71, 0x6e, 0x61, 0x23, 0x45, 0xe5, 0xc3, 0xc2, 0x06, 0x9d, 0xd2, 0xd7, 0xc0, + 0xc5, 0xd0, 0x3a, 0xe0, 0xe7, 0x10, 0x26, 0x07, 0xa2, 0x7f, 0x52, 0xdc, 0xcc, 0x38, 0x8b, 0xd2, + 0x12, 0x8e, 0xe4, 0x2c, 0x0a, 0xad, 0x83, 0x64, 0xbb, 0x14, 0x82, 0x6b, 0x01, 0x4f, 0xcf, 0x20, + 0x9f, 0x8e, 0x84, 0x0e, 0x30, 0x7d, 0xc8, 0xee, 0xb7, 0xc3, 0xe2, 0x93, 0x8c, 0x27, 0xa9, 0x69, + 0x99, 0x9d, 0x6a, 0x01, 0x5e, 0x0d, 0xd2, 0xfb, 0x47, 0xb7, 0x05, 0x2f, 0x70, 0xe0, 0x5b, 0xfe, + 0xbd, 0xdc, 0x76, 0x9a, 0x2c, 0x8b, 0x19, 0xb6, 0xd3, 0xa1, 0x82, 0x99, 0x74, 0x69, 0x7c, 0x13, + 0x7e, 0xe9, 0x73, 0x4a, 0x4b, 0xdb, 0x84, 0x43, 0x55, 0x20, 0x7b, 0xe0, 0x4a, 0x64, 0x18, 0x27, + 0x68, 0x1f, 0x87, 0xf6, 0x4b, 0x7e, 0x06, 0x7e, 0x39, 0xe3, 0x44, 0x4a, 0x49, 0x6f, 0x91, 0x13, + 0xc9, 0x49, 0xc9, 0x7a, 0x7d, 0x6f, 0xe4, 0x35, 0x8f, 0x1b, 0xe0, 0x40, 0x2e, 0xbb, 0xe3, 0x17, + 0xdf, 0xcf, 0xfd, 0x78, 0x36, 0xf9, 0xb7, 0x91, 0xc3, 0x4f, 0x7a, 0xa9, 0x74, 0xd2, 0xb7, 0x46, + 0x6e, 0xf6, 0x87, 0xfd, 0x3d, 0x4c, 0x93, 0xb3, 0x43, 0xd7, 0x84, 0xa7, 0xb9, 0x1f, 0x38, 0xc7, + 0x7f, 0xb2, 0x3e, 0xfc, 0xc0, 0x49, 0xfb, 0x0f, 0x87, 0xae, 0x07, 0xdf, 0x4e, 0x57, 0x89, 0xd5, + 0xeb, 0xd1, 0x67, 0xd6, 0xf8, 0x81, 0xf3, 0x2b, 0x99, 0x2f, 0xdc, 0xd3, 0x7e, 0xfb, 0x30, 0xec, + 0x88, 0x52, 0x7f, 0x1d, 0xd1, 0x03, 0x2b, 0xdc, 0xda, 0x0e, 0x7c, 0xab, 0xf7, 0x92, 0x5e, 0xe9, + 0x02, 0xdb, 0x8a, 0x22, 0xa1, 0x0f, 0xa8, 0xfc, 0x77, 0x33, 0xec, 0x6d, 0x2c, 0x5f, 0x4f, 0x76, + 0x93, 0x95, 0xe8, 0x3a, 0x0e, 0x06, 0xa9, 0xfc, 0xef, 0xb3, 0x8b, 0xda, 0x90, 0x54, 0xdb, 0xf7, + 0x8e, 0xbb, 0xe8, 0xe7, 0xf0, 0x31, 0x6e, 0x23, 0xc7, 0xdd, 0xdf, 0xa7, 0x57, 0xe0, 0xe2, 0x87, + 0x99, 0xf6, 0x90, 0x9d, 0x41, 0x66, 0xf6, 0x30, 0x95, 0x4e, 0xfa, 0x59, 0x70, 0x85, 0x16, 0x71, + 0xd0, 0xbc, 0x29, 0xcd, 0x79, 0xf2, 0xd9, 0x7f, 0x94, 0x95, 0xa9, 0x1c, 0x4b, 0xbf, 0x56, 0x0b, + 0x50, 0xea, 0x8f, 0xb5, 0x6e, 0x9d, 0x06, 0xf3, 0x94, 0xeb, 0xd9, 0xdc, 0xc2, 0x8c, 0x38, 0x4b, + 0x6c, 0x23, 0xbe, 0x31, 0x10, 0xff, 0x15, 0x25, 0x17, 0xe8, 0xfd, 0x70, 0xed, 0x2f, 0x2f, 0x0c, + 0xfe, 0xed, 0x25, 0x0a, 0x6a, 0xa5, 0xdb, 0x60, 0xb5, 0xac, 0x19, 0x8a, 0xfe, 0x5c, 0x85, 0x08, + 0xaa, 0x86, 0xde, 0x82, 0xca, 0xe8, 0x6f, 0xb5, 0xaf, 0x83, 0xe2, 0x38, 0x89, 0xa1, 0xc2, 0xe7, + 0x2a, 0x14, 0x05, 0xe9, 0x16, 0xb8, 0x3e, 0xde, 0xbb, 0xd3, 0xda, 0x52, 0x61, 0x43, 0x35, 0x55, + 0x43, 0x9c, 0x91, 0x9e, 0x80, 0x8d, 0x71, 0x8a, 0xb2, 0x6c, 0xca, 0x5b, 0xb2, 0xa1, 0xa2, 0xa6, + 0x6e, 0x98, 0x15, 0xa8, 0x1a, 0xc8, 0x50, 0x6b, 0xdb, 0xa8, 0xaa, 0x1b, 0xa6, 0x5a, 0x16, 0x67, + 0xa5, 0x77, 0xc1, 0xdb, 0x53, 0x98, 0xea, 0xbb, 0xc6, 0x27, 0xb5, 0x21, 0x8e, 0x39, 0x69, 0x13, + 0xac, 0x4f, 0xe3, 0xd0, 0x1b, 0x15, 0xbd, 0xbc, 0x35, 0xc4, 0x33, 0x2f, 0xbd, 0x05, 0x1e, 0xe4, + 0x81, 0x06, 0xcb, 0x86, 0x78, 0x4a, 0x7a, 0x08, 0xee, 0x66, 0x42, 0x22, 0x94, 0xa7, 0xa5, 0xfb, + 0xa0, 0x34, 0x4e, 0x29, 0x37, 0x9b, 0x35, 0x4d, 0x91, 0x4d, 0x4d, 0x6f, 0xa0, 0xaa, 0x69, 0x36, + 0xc5, 0x05, 0xe9, 0x1e, 0xb8, 0x3d, 0x9d, 0xce, 0x54, 0x9a, 0xe2, 0x99, 0x74, 0xb2, 0x17, 0x5a, + 0xa3, 0xac, 0xbf, 0x30, 0x50, 0x59, 0x35, 0x76, 0x4c, 0xbd, 0x29, 0x02, 0xe9, 0x6d, 0xf0, 0x70, + 0x0a, 0x3e, 0xe3, 0x93, 0x1a, 0x5b, 0x33, 0x8a, 0xf1, 0x6c, 0x86, 0x82, 0x07, 0x53, 0x57, 0xcb, + 0x46, 0x55, 0xdb, 0x36, 0xc5, 0x73, 0xd2, 0x7b, 0xe0, 0xdd, 0x5c, 0xe3, 0x27, 0x55, 0x7c, 0x3e, + 0x43, 0x0e, 0x54, 0xcb, 0xda, 0xf0, 0xd2, 0x2f, 0xe6, 0x5d, 0x94, 0x8a, 0xd2, 0x14, 0x2f, 0xe4, + 0x5a, 0x14, 0x42, 0x29, 0xe6, 0x56, 0x0f, 0xa1, 0xbe, 0x28, 0x7d, 0x08, 0xde, 0xff, 0x3c, 0xea, + 0xe1, 0xfb, 0xa1, 0xa6, 0x1a, 0x86, 0x28, 0x49, 0xef, 0x80, 0x47, 0x79, 0x98, 0xe5, 0x4f, 0x5b, + 0x50, 0x15, 0x2f, 0x49, 0x0f, 0xc0, 0x9d, 0x29, 0xe4, 0xe5, 0xdd, 0x86, 0x5c, 0xd7, 0xcb, 0x5b, + 0xe2, 0xe5, 0x0c, 0x13, 0x57, 0x64, 0xc3, 0x90, 0x1b, 0x65, 0x28, 0xa3, 0x1d, 0x75, 0xd7, 0x68, + 0xca, 0x8a, 0x6a, 0x88, 0x57, 0x32, 0x56, 0x6d, 0xc0, 0x93, 0x5c, 0x83, 0x25, 0xe9, 0x29, 0x78, + 0x6f, 0x0a, 0x97, 0x5a, 0x93, 0x0d, 0x53, 0x53, 0x0c, 0x55, 0x86, 0x4a, 0x75, 0x88, 0xf3, 0x6a, + 0xae, 0xf5, 0xe6, 0xfc, 0xb2, 0x52, 0x55, 0xc5, 0x62, 0x86, 0xb6, 0x18, 0x47, 0x5d, 0xad, 0xeb, + 0x70, 0xb7, 0xbc, 0x25, 0x2e, 0xe7, 0x12, 0x40, 0x35, 0x8b, 0x98, 0x80, 0x6b, 0x19, 0x93, 0x61, + 0x1c, 0x4a, 0xad, 0x65, 0x98, 0x23, 0xc6, 0xbb, 0x22, 0xad, 0x81, 0xfb, 0x99, 0xd6, 0xc5, 0x56, + 0xf1, 0xba, 0xb4, 0x0e, 0xd6, 0x72, 0xd9, 0x17, 0xa3, 0x5f, 0xcd, 0x58, 0xcc, 0x01, 0x7d, 0x5d, + 0x53, 0xa0, 0x6e, 0xe8, 0xdb, 0xa6, 0x78, 0x43, 0xfa, 0x32, 0xd8, 0x9c, 0xb6, 0x98, 0xba, 0xb2, + 0x03, 0x75, 0x59, 0xa9, 0x8e, 0xf8, 0xb9, 0x9b, 0x19, 0xb6, 0x1f, 0xf9, 0x46, 0xd9, 0xac, 0xc9, + 0x86, 0x78, 0x2b, 0x63, 0x4f, 0x19, 0x0d, 0xfd, 0xc5, 0x76, 0x4d, 0xde, 0x51, 0xc5, 0xdb, 0x13, + 0xc6, 0xd5, 0x95, 0x84, 0x76, 0xcb, 0x06, 0x6a, 0x42, 0xfd, 0xab, 0xbb, 0x62, 0x69, 0x82, 0x29, + 0x26, 0xa9, 0xab, 0x5a, 0xa5, 0x8a, 0xe4, 0xe7, 0xb2, 0x56, 0x93, 0xb7, 0xb4, 0x9a, 0x66, 0xee, + 0x8a, 0x77, 0xa4, 0xf7, 0xc1, 0x93, 0x0c, 0x2e, 0xba, 0x43, 0x34, 0x05, 0x41, 0xb5, 0xa2, 0x19, + 0x26, 0xa4, 0xae, 0x53, 0xbc, 0x9b, 0xee, 0x85, 0x0d, 0xb9, 0x5e, 0x4b, 0xba, 0x58, 0xf1, 0x9e, + 0x54, 0x02, 0x37, 0xc6, 0xe9, 0x54, 0x65, 0x93, 0xfd, 0x2b, 0x49, 0x43, 0x51, 0xc5, 0xfb, 0x13, + 0x8c, 0x4e, 0x57, 0x46, 0xdd, 0x30, 0x6a, 0xe8, 0x0d, 0x24, 0x97, 0xc5, 0x07, 0xd2, 0x5d, 0x70, + 0x6b, 0xda, 0xb9, 0x48, 0xff, 0xad, 0xe2, 0x61, 0xba, 0xed, 0x27, 0x4f, 0x00, 0xf9, 0x85, 0x81, + 0x14, 0xbd, 0x61, 0xe8, 0x35, 0x55, 0x7c, 0xb4, 0xf6, 0x87, 0x02, 0x58, 0x1c, 0xfe, 0xb3, 0x33, + 0xe9, 0x26, 0x58, 0x89, 0x47, 0x30, 0x4c, 0xd9, 0x6c, 0x19, 0x23, 0xc7, 0xf7, 0x0a, 0xb8, 0x3a, + 0x4a, 0x60, 0xb4, 0x14, 0x85, 0x78, 0x2a, 0x21, 0xb5, 0x73, 0x47, 0x6b, 0x36, 0xd5, 0xb2, 0x38, + 0x23, 0x2d, 0x83, 0x2b, 0xa3, 0x9d, 0x2a, 0x84, 0x3a, 0x14, 0x67, 0xd3, 0xf8, 0xe4, 0x2d, 0x1d, + 0xd2, 0x93, 0x78, 0xed, 0xef, 0x67, 0xc0, 0xac, 0x62, 0xca, 0xd2, 0x25, 0x70, 0x41, 0x31, 0xe5, + 0xf1, 0xbf, 0x95, 0x21, 0x8d, 0x72, 0xcb, 0xac, 0x92, 0x89, 0x35, 0x54, 0xc5, 0xd4, 0x49, 0x1c, + 0x71, 0x15, 0x5c, 0xa2, 0xed, 0x8a, 0xa9, 0x3d, 0x27, 0xe1, 0x85, 0x61, 0x68, 0x7a, 0x83, 0x84, + 0x0f, 0x71, 0x07, 0x81, 0x8c, 0xa0, 0xfa, 0x49, 0x4b, 0x35, 0x4c, 0x43, 0x9c, 0x8d, 0x3a, 0x9a, + 0x50, 0xad, 0x6b, 0xad, 0x3a, 0x32, 0x5a, 0xcd, 0xa6, 0x0e, 0x4d, 0x71, 0x2e, 0xea, 0x30, 0x21, + 0xd9, 0xd2, 0x65, 0x54, 0x56, 0x9f, 0x6b, 0xc4, 0x17, 0xce, 0x47, 0xb2, 0x5b, 0xcd, 0x0a, 0x94, + 0xcb, 0x2a, 0xda, 0x92, 0x1b, 0x0d, 0x15, 0x8a, 0xa7, 0x22, 0x86, 0x2d, 0xad, 0x56, 0xd3, 0x1a, + 0x15, 0x64, 0xb4, 0xea, 0x75, 0x19, 0xee, 0x8a, 0xa7, 0xa3, 0x19, 0x70, 0xd9, 0x35, 0xcd, 0x30, + 0xc5, 0x05, 0xfa, 0xe7, 0x23, 0x83, 0xc6, 0xba, 0xde, 0xd0, 0x4c, 0x1d, 0x6a, 0x8d, 0x8a, 0x78, + 0x86, 0xfe, 0xad, 0x89, 0x29, 0x23, 0xf5, 0xab, 0xa6, 0x0a, 0x1b, 0x72, 0x0d, 0xc9, 0xad, 0xb2, + 0x66, 0x22, 0xc3, 0xd4, 0xa1, 0x5c, 0x51, 0x45, 0x10, 0x01, 0xd0, 0x77, 0x08, 0x0a, 0x83, 0xe8, + 0x6e, 0xb7, 0xa1, 0x88, 0x67, 0x25, 0x11, 0x9c, 0xa3, 0x7c, 0x0d, 0x13, 0xca, 0x48, 0x2b, 0x8b, + 0xe7, 0xa4, 0x8b, 0xe0, 0x7c, 0x4c, 0x69, 0x28, 0x5a, 0x5d, 0x3c, 0xbf, 0xf6, 0x4f, 0x0b, 0xe0, + 0x4a, 0x6a, 0x29, 0x3a, 0x39, 0x40, 0xb4, 0x86, 0xa9, 0x56, 0x98, 0xe9, 0x23, 0xb5, 0x01, 0xf5, + 0x5a, 0x0d, 0xed, 0x68, 0x8d, 0xd1, 0x7f, 0x65, 0xb9, 0x0d, 0x56, 0x27, 0x11, 0x1a, 0x35, 0x59, + 0xd9, 0x11, 0x05, 0x62, 0xb7, 0x93, 0x48, 0x88, 0x2d, 0xea, 0x5a, 0x59, 0x11, 0x67, 0x48, 0x48, + 0x32, 0x89, 0xaa, 0x29, 0x57, 0x54, 0x58, 0x6e, 0x99, 0xbb, 0xe2, 0xec, 0x34, 0x79, 0x6a, 0x5d, + 0xd6, 0x6a, 0xe2, 0x1c, 0x89, 0x1f, 0x27, 0x91, 0x3c, 0xd3, 0xa0, 0x2c, 0xce, 0x4b, 0x77, 0xc0, + 0xcd, 0x49, 0x14, 0xd4, 0x06, 0x61, 0x59, 0x3c, 0x45, 0x36, 0xfb, 0x24, 0xa2, 0xba, 0x6c, 0x9a, + 0x2a, 0xac, 0xeb, 0x86, 0x29, 0x9e, 0x9e, 0x36, 0xbd, 0xba, 0x81, 0x4c, 0x55, 0xae, 0x1b, 0xe2, + 0xc2, 0x34, 0x2a, 0xbd, 0x69, 0x54, 0xd4, 0x86, 0xa6, 0x8a, 0x67, 0xa6, 0x41, 0x27, 0xeb, 0x26, + 0x82, 0xa9, 0x93, 0x93, 0xeb, 0xdb, 0xe2, 0xd9, 0xe9, 0xb8, 0x95, 0xaa, 0xd6, 0x50, 0x99, 0x3d, + 0x7c, 0x09, 0x3c, 0xce, 0xa6, 0x43, 0x15, 0xcd, 0xac, 0xb6, 0xb6, 0xe8, 0x26, 0x22, 0x9b, 0xe7, + 0xbc, 0xb4, 0x01, 0xde, 0xca, 0xc1, 0xa6, 0x68, 0x50, 0xa9, 0xa9, 0x8a, 0x26, 0x2e, 0x12, 0x87, + 0x94, 0x4f, 0x4e, 0x4d, 0xde, 0x12, 0x2f, 0x90, 0x43, 0x2f, 0x07, 0xf9, 0x33, 0xb5, 0xb1, 0xa3, + 0x35, 0x0c, 0x51, 0xcc, 0x49, 0x2f, 0x37, 0x0c, 0x6d, 0xab, 0xa6, 0x8a, 0x17, 0xa7, 0xa9, 0x87, + 0x1c, 0x8f, 0x9a, 0xa2, 0x36, 0xf4, 0x17, 0xa2, 0x34, 0x6d, 0xc1, 0xe2, 0x4d, 0x75, 0x89, 0x1c, + 0x25, 0x13, 0x2d, 0x49, 0x36, 0xe5, 0xb2, 0x5e, 0x41, 0x5a, 0x43, 0xd1, 0xca, 0x6a, 0xc3, 0x44, + 0x75, 0xb9, 0x21, 0x57, 0xd4, 0xba, 0xda, 0x30, 0xc5, 0xcb, 0x24, 0x0e, 0xc8, 0x03, 0xfb, 0x05, + 0x09, 0xb8, 0xf2, 0xd1, 0x92, 0x28, 0x73, 0x89, 0x9c, 0x9f, 0x79, 0xc6, 0xa5, 0x11, 0x03, 0x0d, + 0xad, 0x72, 0x50, 0xd3, 0xc8, 0xaf, 0x46, 0x42, 0xf6, 0xa2, 0xf4, 0x18, 0xbc, 0x93, 0x83, 0x23, + 0x71, 0x5b, 0x5b, 0x5e, 0xfb, 0x18, 0x9c, 0xe6, 0x69, 0x08, 0xe2, 0x16, 0xb7, 0x55, 0xd9, 0x24, + 0xa1, 0xd4, 0xd8, 0x91, 0x12, 0x75, 0x8c, 0x3a, 0x59, 0x61, 0xed, 0xf7, 0x05, 0xb0, 0x32, 0xe5, + 0x47, 0x02, 0xc4, 0xc2, 0x22, 0x66, 0xa8, 0x2a, 0x7a, 0xbd, 0xae, 0x36, 0xca, 0x0c, 0x5e, 0xea, + 0xf1, 0xb5, 0x06, 0xee, 0x4f, 0x27, 0x6f, 0xe8, 0x26, 0xa3, 0x15, 0x88, 0xb5, 0x4c, 0xa7, 0x2d, + 0xeb, 0x0d, 0x55, 0x9c, 0xd9, 0xfa, 0xfa, 0xdf, 0xfc, 0xf8, 0x86, 0xf0, 0xb7, 0x3f, 0xbe, 0x21, + 0xfc, 0xe3, 0x8f, 0x6f, 0x08, 0x9f, 0xea, 0x07, 0x6e, 0xf8, 0xb2, 0xbf, 0xb7, 0x6e, 0x7b, 0x9d, + 0x8d, 0x03, 0xdf, 0x3a, 0x72, 0x59, 0x9a, 0xda, 0x6a, 0x6f, 0xc4, 0xff, 0xf2, 0x6b, 0xf5, 0xdc, + 0x8d, 0x03, 0xdc, 0xdd, 0xa0, 0x3f, 0xe8, 0xd8, 0x38, 0xf0, 0x46, 0xfe, 0xf6, 0xf7, 0xc3, 0xc4, + 0xd7, 0xa3, 0xc7, 0x7b, 0xa7, 0x28, 0xd9, 0x93, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x20, + 0x6f, 0x36, 0x26, 0x58, 0x00, 0x00, } func (m *UIBannerClickEvent) Marshal() (dAtA []byte, err error) { diff --git a/api/proto/teleport/usageevents/v1/usageevents.proto b/api/proto/teleport/usageevents/v1/usageevents.proto index a37045088eb8c..8962e740b9a71 100644 --- a/api/proto/teleport/usageevents/v1/usageevents.proto +++ b/api/proto/teleport/usageevents/v1/usageevents.proto @@ -242,6 +242,7 @@ enum CTA { CTA_EXTERNAL_AUDIT_STORAGE = 10; CTA_OKTA_USER_SYNC = 11; CTA_ENTRA_ID = 12; + CTA_OKTA_SCIM = 13; } // UIDiscoverDeployServiceEvent is emitted after the user installs a Teleport Agent. diff --git a/gen/proto/go/prehog/v1alpha/teleport.pb.go b/gen/proto/go/prehog/v1alpha/teleport.pb.go index afe507fd85c71..ec0f5d87bf9e2 100644 --- a/gen/proto/go/prehog/v1alpha/teleport.pb.go +++ b/gen/proto/go/prehog/v1alpha/teleport.pb.go @@ -431,6 +431,7 @@ const ( CTA_CTA_EXTERNAL_AUDIT_STORAGE CTA = 10 CTA_CTA_OKTA_USER_SYNC CTA = 11 CTA_CTA_ENTRA_ID CTA = 12 + CTA_CTA_OKTA_SCIM CTA = 13 ) // Enum value maps for CTA. @@ -449,6 +450,7 @@ var ( 10: "CTA_EXTERNAL_AUDIT_STORAGE", 11: "CTA_OKTA_USER_SYNC", 12: "CTA_ENTRA_ID", + 13: "CTA_OKTA_SCIM", } CTA_value = map[string]int32{ "CTA_UNSPECIFIED": 0, @@ -464,6 +466,7 @@ var ( "CTA_EXTERNAL_AUDIT_STORAGE": 10, "CTA_OKTA_USER_SYNC": 11, "CTA_ENTRA_ID": 12, + "CTA_OKTA_SCIM": 13, } ) @@ -496,10 +499,6 @@ func (CTA) EnumDescriptor() ([]byte, []int) { // IntegrationEnrollKind represents the types of integration that // can be enrolled. -// -// Note: IntegrationEnrollKind enum must be kept in sync with the values defined -// in api/proto/teleport/usageevents/v1/usageevents.proto. Values 18-25 have -// become out of sync and are manually mapped to each other. type IntegrationEnrollKind int32 const ( @@ -7322,6 +7321,84 @@ func (x *DatabaseUserPermissionsUpdateEvent) GetNumTablesPermissions() int32 { return 0 } +// SessionRecordingAccessEvent is emitted when the user accesses a session +// recording. +// +// PostHog event: tp.recording.access +type SessionRecordingAccessEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // session_type is type of the session, should be + // "ssh"/"k8s"/"db"/"app"/"desktop" (matching the values for + // api/types.SessionKind). + // + // PostHog property: tp.session_type + SessionType string `protobuf:"bytes,1,opt,name=session_type,json=sessionType,proto3" json:"session_type,omitempty"` + // user_name is the anonymized Teleport username, 32 bytes (HMAC-SHA-256) + // encoded in base64. + // + // PostHog property: tp.user_name + UserName string `protobuf:"bytes,2,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` + // format is the format the session recording was accessed. + // One of text/json/yaml/pty. pty being the interactive session player. + // + // PostHog property: tp.recording.format + Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"` +} + +func (x *SessionRecordingAccessEvent) Reset() { + *x = SessionRecordingAccessEvent{} + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[96] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SessionRecordingAccessEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SessionRecordingAccessEvent) ProtoMessage() {} + +func (x *SessionRecordingAccessEvent) ProtoReflect() protoreflect.Message { + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[96] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SessionRecordingAccessEvent.ProtoReflect.Descriptor instead. +func (*SessionRecordingAccessEvent) Descriptor() ([]byte, []int) { + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{96} +} + +func (x *SessionRecordingAccessEvent) GetSessionType() string { + if x != nil { + return x.SessionType + } + return "" +} + +func (x *SessionRecordingAccessEvent) GetUserName() string { + if x != nil { + return x.UserName + } + return "" +} + +func (x *SessionRecordingAccessEvent) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + // UserTaskStateEvent is emitted when a UserTask state changes. // This can happen when the Task is created, when it's manually // resolved by the user or when it changes back to being open @@ -7357,7 +7434,7 @@ type UserTaskStateEvent struct { func (x *UserTaskStateEvent) Reset() { *x = UserTaskStateEvent{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[96] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7369,7 +7446,7 @@ func (x *UserTaskStateEvent) String() string { func (*UserTaskStateEvent) ProtoMessage() {} func (x *UserTaskStateEvent) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[96] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7382,7 +7459,7 @@ func (x *UserTaskStateEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use UserTaskStateEvent.ProtoReflect.Descriptor instead. func (*UserTaskStateEvent) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{96} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{97} } func (x *UserTaskStateEvent) GetTaskType() string { @@ -7519,13 +7596,14 @@ type SubmitEventRequest struct { // *SubmitEventRequest_AccessGraphAccessPathChanged // *SubmitEventRequest_AccessGraphCrownJewelCreate // *SubmitEventRequest_UiAccessGraphCrownJewelDiffView + // *SubmitEventRequest_SessionRecordingAccess // *SubmitEventRequest_UserTaskState Event isSubmitEventRequest_Event `protobuf_oneof:"event"` } func (x *SubmitEventRequest) Reset() { *x = SubmitEventRequest{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[97] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7537,7 +7615,7 @@ func (x *SubmitEventRequest) String() string { func (*SubmitEventRequest) ProtoMessage() {} func (x *SubmitEventRequest) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[97] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7550,7 +7628,7 @@ func (x *SubmitEventRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitEventRequest.ProtoReflect.Descriptor instead. func (*SubmitEventRequest) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{97} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{98} } func (x *SubmitEventRequest) GetClusterName() string { @@ -8197,6 +8275,13 @@ func (x *SubmitEventRequest) GetUiAccessGraphCrownJewelDiffView() *UIAccessGraph return nil } +func (x *SubmitEventRequest) GetSessionRecordingAccess() *SessionRecordingAccessEvent { + if x, ok := x.GetEvent().(*SubmitEventRequest_SessionRecordingAccess); ok { + return x.SessionRecordingAccess + } + return nil +} + func (x *SubmitEventRequest) GetUserTaskState() *UserTaskStateEvent { if x, ok := x.GetEvent().(*SubmitEventRequest_UserTaskState); ok { return x.UserTaskState @@ -8569,6 +8654,10 @@ type SubmitEventRequest_UiAccessGraphCrownJewelDiffView struct { UiAccessGraphCrownJewelDiffView *UIAccessGraphCrownJewelDiffViewEvent `protobuf:"bytes,92,opt,name=ui_access_graph_crown_jewel_diff_view,json=uiAccessGraphCrownJewelDiffView,proto3,oneof"` } +type SubmitEventRequest_SessionRecordingAccess struct { + SessionRecordingAccess *SessionRecordingAccessEvent `protobuf:"bytes,93,opt,name=session_recording_access,json=sessionRecordingAccess,proto3,oneof"` +} + type SubmitEventRequest_UserTaskState struct { UserTaskState *UserTaskStateEvent `protobuf:"bytes,94,opt,name=user_task_state,json=userTaskState,proto3,oneof"` } @@ -8753,6 +8842,8 @@ func (*SubmitEventRequest_AccessGraphCrownJewelCreate) isSubmitEventRequest_Even func (*SubmitEventRequest_UiAccessGraphCrownJewelDiffView) isSubmitEventRequest_Event() {} +func (*SubmitEventRequest_SessionRecordingAccess) isSubmitEventRequest_Event() {} + func (*SubmitEventRequest_UserTaskState) isSubmitEventRequest_Event() {} type SubmitEventResponse struct { @@ -8763,7 +8854,7 @@ type SubmitEventResponse struct { func (x *SubmitEventResponse) Reset() { *x = SubmitEventResponse{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[98] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8775,7 +8866,7 @@ func (x *SubmitEventResponse) String() string { func (*SubmitEventResponse) ProtoMessage() {} func (x *SubmitEventResponse) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[98] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8788,7 +8879,7 @@ func (x *SubmitEventResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitEventResponse.ProtoReflect.Descriptor instead. func (*SubmitEventResponse) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{98} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{99} } type SubmitEventsRequest struct { @@ -8802,7 +8893,7 @@ type SubmitEventsRequest struct { func (x *SubmitEventsRequest) Reset() { *x = SubmitEventsRequest{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[99] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8814,7 +8905,7 @@ func (x *SubmitEventsRequest) String() string { func (*SubmitEventsRequest) ProtoMessage() {} func (x *SubmitEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[99] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8827,7 +8918,7 @@ func (x *SubmitEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitEventsRequest.ProtoReflect.Descriptor instead. func (*SubmitEventsRequest) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{99} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{100} } func (x *SubmitEventsRequest) GetEvents() []*SubmitEventRequest { @@ -8845,7 +8936,7 @@ type SubmitEventsResponse struct { func (x *SubmitEventsResponse) Reset() { *x = SubmitEventsResponse{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[100] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8857,7 +8948,7 @@ func (x *SubmitEventsResponse) String() string { func (*SubmitEventsResponse) ProtoMessage() {} func (x *SubmitEventsResponse) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[100] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8870,7 +8961,7 @@ func (x *SubmitEventsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitEventsResponse.ProtoReflect.Descriptor instead. func (*SubmitEventsResponse) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{100} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{101} } type HelloTeleportRequest struct { @@ -8881,7 +8972,7 @@ type HelloTeleportRequest struct { func (x *HelloTeleportRequest) Reset() { *x = HelloTeleportRequest{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[101] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8893,7 +8984,7 @@ func (x *HelloTeleportRequest) String() string { func (*HelloTeleportRequest) ProtoMessage() {} func (x *HelloTeleportRequest) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[101] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8906,7 +8997,7 @@ func (x *HelloTeleportRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HelloTeleportRequest.ProtoReflect.Descriptor instead. func (*HelloTeleportRequest) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{101} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{102} } type HelloTeleportResponse struct { @@ -8917,7 +9008,7 @@ type HelloTeleportResponse struct { func (x *HelloTeleportResponse) Reset() { *x = HelloTeleportResponse{} - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[102] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8929,7 +9020,7 @@ func (x *HelloTeleportResponse) String() string { func (*HelloTeleportResponse) ProtoMessage() {} func (x *HelloTeleportResponse) ProtoReflect() protoreflect.Message { - mi := &file_prehog_v1alpha_teleport_proto_msgTypes[102] + mi := &file_prehog_v1alpha_teleport_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8942,7 +9033,7 @@ func (x *HelloTeleportResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HelloTeleportResponse.ProtoReflect.Descriptor instead. func (*HelloTeleportResponse) Descriptor() ([]byte, []int) { - return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{102} + return file_prehog_v1alpha_teleport_proto_rawDescGZIP(), []int{103} } var File_prehog_v1alpha_teleport_proto protoreflect.FileDescriptor @@ -9958,634 +10049,648 @@ var file_prehog_v1alpha_teleport_proto_rawDesc = []byte{ 0x16, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x6e, 0x75, 0x6d, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x12, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, - 0x73, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, - 0x61, 0x73, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x9b, 0x4e, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, - 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x3f, 0x0a, 0x0a, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, - 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x3f, 0x0a, 0x0a, 0x73, 0x73, - 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, - 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x53, 0x53, 0x4f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x09, 0x73, 0x73, 0x6f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x4c, 0x0a, 0x0f, 0x75, 0x69, 0x5f, 0x62, 0x61, 0x6e, 0x6e, - 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x69, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x6c, - 0x69, 0x63, 0x6b, 0x12, 0x92, 0x01, 0x0a, 0x29, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x74, - 0x6f, 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6c, 0x69, 0x63, - 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6f, 0x54, 0x6f, 0x44, 0x61, - 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x23, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6f, 0x54, 0x6f, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, - 0x61, 0x72, 0x64, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x82, 0x01, 0x0a, 0x23, 0x75, 0x69, 0x5f, - 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x5f, 0x66, 0x69, 0x72, 0x73, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x41, 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x75, - 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x92, 0x01, - 0x0a, 0x29, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, 0x64, - 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x6c, 0x61, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x46, - 0x69, 0x72, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x61, 0x74, 0x65, - 0x72, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x23, 0x75, - 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, - 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x61, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x69, - 0x63, 0x6b, 0x12, 0x7b, 0x0a, 0x20, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, - 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, - 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x1c, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x65, 0x74, 0x43, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, - 0x87, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x72, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, - 0x65, 0x5f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, + 0x6f, 0x6e, 0x73, 0x22, 0x75, 0x0a, 0x1b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x8f, 0x01, 0x0a, 0x12, 0x55, + 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x61, 0x73, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, + 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x84, 0x4f, 0x0a, + 0x12, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x3f, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x12, 0x3f, 0x0a, 0x0a, 0x73, 0x73, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x53, 0x4f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x73, 0x73, 0x6f, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x4e, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, + 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x4c, 0x0a, 0x0f, + 0x75, 0x69, 0x5f, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, + 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x75, 0x69, 0x42, + 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x92, 0x01, 0x0a, 0x29, 0x75, + 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x5f, 0x67, 0x6f, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, + 0x72, 0x64, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, - 0x72, 0x64, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, - 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x7b, 0x0a, 0x20, 0x75, 0x69, 0x5f, - 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x5f, 0x63, - 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0e, 0x20, + 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x47, 0x6f, 0x54, 0x6f, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6c, + 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x23, 0x75, 0x69, 0x4f, 0x6e, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x6f, 0x54, + 0x6f, 0x44, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, + 0x82, 0x01, 0x0a, 0x23, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x61, + 0x64, 0x64, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, + 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, + 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, + 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, + 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x92, 0x01, 0x0a, 0x29, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x5f, 0x61, 0x64, 0x64, 0x5f, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x69, + 0x63, 0x6b, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x41, 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x4c, 0x61, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x23, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x41, + 0x64, 0x64, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, + 0x61, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x7b, 0x0a, 0x20, 0x75, 0x69, 0x5f, + 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x53, 0x65, + 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x53, 0x65, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x87, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, 0x6f, 0x6e, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x63, + 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, + 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, + 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x12, 0x7b, 0x0a, 0x20, 0x75, 0x69, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x5f, 0x63, + 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x52, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x69, + 0x6e, 0x75, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x1c, 0x75, 0x69, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, + 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x6f, 0x0a, + 0x1c, 0x75, 0x69, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, - 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x43, 0x6c, 0x69, 0x63, - 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x75, 0x69, 0x52, 0x65, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, - 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x6f, 0x0a, 0x1c, 0x75, 0x69, 0x5f, 0x72, 0x65, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x5f, 0x63, 0x6f, 0x70, 0x79, - 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, - 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x70, - 0x79, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, - 0x69, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, - 0x70, 0x79, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x72, 0x0a, 0x1d, 0x75, 0x69, 0x5f, 0x72, 0x65, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x69, - 0x6e, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, - 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x50, - 0x72, 0x69, 0x6e, 0x74, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x19, 0x75, 0x69, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, - 0x73, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x63, 0x0a, 0x19, 0x75, - 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x82, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x6f, 0x0a, 0x1d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, - 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, - 0x75, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, 0x75, 0x73, 0x65, 0x72, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x4d, 0x0a, 0x10, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, 0x32, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x56, 0x32, 0x12, 0x76, 0x0a, 0x20, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x1c, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, - 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x7f, 0x0a, - 0x23, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, 0x75, - 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x8f, - 0x01, 0x0a, 0x29, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, - 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, - 0x65, 0x5f, 0x6d, 0x74, 0x6c, 0x73, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x17, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x4d, - 0x54, 0x4c, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x24, 0x75, 0x69, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x4d, 0x74, 0x6c, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0xb8, 0x01, 0x0a, 0x38, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5f, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, - 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x31, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x34, - 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, 0x6b, - 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x70, 0x72, 0x65, + 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x70, 0x79, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, 0x69, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x73, 0x43, 0x6f, 0x70, 0x79, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x72, + 0x0a, 0x1d, 0x75, 0x69, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x43, 0x6c, 0x69, 0x63, 0x6b, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x19, 0x75, 0x69, 0x52, 0x65, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x79, 0x43, 0x6f, 0x64, 0x65, 0x73, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x43, 0x6c, 0x69, + 0x63, 0x6b, 0x12, 0x63, 0x0a, 0x19, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, + 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x16, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x82, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x6f, 0x0a, 0x1d, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x1a, 0x75, 0x73, 0x65, 0x72, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x4d, 0x0a, + 0x10, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x76, + 0x32, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x56, 0x32, 0x12, 0x76, 0x0a, 0x20, + 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x7f, 0x0a, 0x23, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x8f, 0x01, 0x0a, 0x29, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x6d, 0x74, 0x6c, 0x73, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x4d, 0x54, 0x4c, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x24, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x4d, 0x74, + 0x6c, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0xb8, 0x01, 0x0a, 0x38, 0x75, 0x69, 0x5f, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, + 0x5f, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x2e, 0x75, 0x69, - 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, - 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, - 0x2b, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x75, 0x74, - 0x6f, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x75, - 0x74, 0x6f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x26, 0x75, 0x69, - 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x75, 0x74, 0x6f, 0x44, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x12, 0x9f, 0x01, 0x0a, 0x2f, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, + 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x54, 0x6f, 0x6f, 0x6c, + 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x31, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x6b, 0x74, + 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0xae, 0x01, 0x0a, 0x34, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x5f, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, + 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x3e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, + 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x2e, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, + 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x95, 0x01, 0x0a, 0x2b, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, 0x75, 0x74, 0x6f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x26, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x41, + 0x75, 0x74, 0x6f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x9f, 0x01, 0x0a, 0x2f, + 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x69, + 0x61, 0x6d, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, + 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x65, 0x49, 0x41, 0x4d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x29, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x49, + 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x88, 0x01, + 0x0a, 0x26, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, + 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x49, 0x41, 0x4d, 0x50, 0x6f, - 0x6c, 0x69, 0x63, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x29, 0x75, 0x69, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x49, 0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, - 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x88, 0x01, 0x0a, 0x26, 0x75, 0x69, 0x5f, 0x64, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, - 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x22, 0x75, - 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, - 0x61, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x79, 0x0a, 0x21, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, - 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x75, - 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x69, 0x0a, 0x1b, - 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, - 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x0b, 0x72, 0x6f, 0x6c, 0x65, 0x5f, - 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x6f, - 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0a, 0x72, 0x6f, 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x63, 0x0a, 0x18, 0x75, - 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, - 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, - 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, - 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6c, - 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, 0x75, 0x69, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, - 0x12, 0x70, 0x0a, 0x1d, 0x75, 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x65, - 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x73, 0x61, 0x76, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, - 0x6b, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, + 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, + 0x70, 0x61, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x22, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x50, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x79, 0x0a, 0x21, 0x75, 0x69, 0x5f, 0x64, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x1d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x54, + 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x54, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x69, 0x0a, 0x1b, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x42, + 0x0a, 0x0b, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x1f, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x72, 0x6f, 0x6c, 0x65, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x63, 0x0a, 0x18, 0x75, 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, + 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x20, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, + 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x14, 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, + 0x6c, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x70, 0x0a, 0x1d, 0x75, 0x69, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x73, 0x61, + 0x76, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, + 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, + 0x55, 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x53, + 0x61, 0x76, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x18, 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, + 0x53, 0x61, 0x76, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x76, 0x0a, 0x1f, 0x75, 0x69, 0x5f, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, + 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x22, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, + 0x6f, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, + 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x63, + 0x6b, 0x12, 0x98, 0x01, 0x0a, 0x2b, 0x75, 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, + 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x6f, + 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x69, 0x63, + 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x43, 0x6c, 0x69, 0x63, - 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x61, 0x76, 0x65, 0x43, 0x6c, 0x69, - 0x63, 0x6b, 0x12, 0x76, 0x0a, 0x1f, 0x75, 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, - 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, - 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, - 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x43, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x98, 0x01, 0x0a, 0x2b, 0x75, - 0x69, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x72, 0x6f, 0x6c, - 0x65, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x3a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x55, 0x49, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, - 0x65, 0x56, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x25, - 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x56, - 0x69, 0x65, 0x77, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x45, 0x0a, 0x0c, 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4b, 0x75, 0x62, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0b, 0x6b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, - 0x73, 0x66, 0x74, 0x70, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x46, 0x54, 0x50, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x04, 0x73, 0x66, 0x74, 0x70, 0x12, 0x56, 0x0a, - 0x14, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x67, 0x65, - 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x12, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x57, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x5f, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x27, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x72, 0x74, - 0x62, 0x65, 0x61, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x9c, - 0x01, 0x0a, 0x2e, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x6f, - 0x69, 0x64, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x57, - 0x53, 0x4f, 0x49, 0x44, 0x43, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x28, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x77, 0x73, 0x4f, 0x69, 0x64, - 0x63, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x83, 0x01, - 0x0a, 0x25, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x64, 0x73, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, - 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, - 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, - 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x52, 0x44, 0x53, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x20, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, - 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x64, 0x73, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x6b, 0x0a, 0x1d, 0x75, 0x69, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x74, - 0x6f, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, 0x61, - 0x6c, 0x6c, 0x54, 0x6f, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, 0x69, 0x43, 0x61, 0x6c, 0x6c, 0x54, 0x6f, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x12, 0x54, 0x0a, 0x11, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, - 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x79, 0x0a, 0x21, 0x75, 0x69, 0x5f, 0x69, 0x6e, 0x74, - 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2c, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x55, 0x49, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x1d, 0x75, 0x69, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x82, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x55, 0x49, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, - 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x53, 0x0a, 0x13, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, - 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x62, - 0x6f, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x42, 0x6f, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x09, 0x62, 0x6f, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x7a, 0x0a, 0x1f, - 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x69, 0x6f, 0x6e, 0x6e, 0x61, 0x69, 0x72, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, - 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x61, 0x69, 0x72, 0x65, 0x53, 0x75, 0x62, - 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x75, 0x69, 0x4f, 0x6e, - 0x62, 0x6f, 0x61, 0x72, 0x64, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x61, 0x69, - 0x72, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x39, 0x0a, 0x08, 0x62, 0x6f, 0x74, 0x5f, - 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x31, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x42, 0x6f, 0x74, 0x4a, - 0x6f, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, 0x74, 0x4a, - 0x6f, 0x69, 0x6e, 0x12, 0x51, 0x0a, 0x10, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x5f, 0x65, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, - 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, - 0x73, 0x73, 0x69, 0x73, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x45, 0x78, 0x65, - 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x64, 0x0a, 0x17, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, - 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x4e, - 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, - 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x19, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x27, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x17, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x6e, 0x0a, 0x1c, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x72, - 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, - 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x5e, 0x0a, 0x15, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x36, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x13, - 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x0d, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x37, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, - 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x0c, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, - 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x65, - 0x76, 0x65, 0x6e, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x53, 0x0a, 0x13, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x39, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x55, 0x0a, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x3a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x55, - 0x0a, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x18, 0x3b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x55, 0x0a, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, - 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x3f, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x69, 0x0a, 0x1a, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, - 0x5f, 0x74, 0x6f, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x65, 0x4e, 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x63, 0x75, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x25, 0x75, 0x69, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, + 0x65, 0x77, 0x52, 0x6f, 0x6c, 0x65, 0x56, 0x69, 0x65, 0x77, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x45, 0x0a, 0x0c, + 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x24, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6b, 0x75, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x66, 0x74, 0x70, 0x18, 0x25, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x53, 0x46, 0x54, 0x50, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x04, + 0x73, 0x66, 0x74, 0x70, 0x12, 0x56, 0x0a, 0x14, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x26, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x57, 0x0a, 0x12, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x9c, 0x01, 0x0a, 0x2e, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, - 0x54, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x54, - 0x6f, 0x55, 0x73, 0x65, 0x72, 0x12, 0x81, 0x01, 0x0a, 0x22, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x63, 0x32, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x41, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, - 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x75, 0x69, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x63, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x62, 0x0a, 0x17, 0x75, 0x69, 0x5f, - 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x5f, - 0x65, 0x69, 0x63, 0x65, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, - 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x45, 0x49, 0x43, 0x45, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x45, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, - 0x17, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x43, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x43, 0x6f, 0x6e, 0x6e, + 0x65, 0x63, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x28, 0x75, 0x69, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x41, 0x77, 0x73, 0x4f, 0x69, 0x64, 0x63, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x83, 0x01, 0x0a, 0x25, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x64, + 0x73, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x29, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x44, 0x53, 0x45, 0x6e, 0x72, 0x6f, 0x6c, + 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x64, 0x73, 0x45, + 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x6b, 0x0a, 0x1d, 0x75, 0x69, + 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x74, 0x6f, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x63, 0x6c, 0x69, 0x63, 0x6b, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2a, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x55, 0x49, 0x43, 0x61, 0x6c, 0x6c, 0x54, 0x6f, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x75, + 0x69, 0x43, 0x61, 0x6c, 0x6c, 0x54, 0x6f, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6c, 0x69, + 0x63, 0x6b, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x54, 0x0a, 0x11, 0x61, 0x73, 0x73, 0x69, 0x73, + 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x2b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x73, 0x73, + 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x79, 0x0a, + 0x21, 0x75, 0x69, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x49, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x75, 0x69, 0x49, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x82, 0x01, 0x0a, 0x24, 0x75, 0x69, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x6e, 0x72, 0x6f, + 0x6c, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x49, 0x6e, 0x74, 0x65, 0x67, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x75, 0x69, 0x49, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x53, 0x0a, + 0x13, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x65, + 0x76, 0x65, 0x6e, 0x74, 0x18, 0x2e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x64, 0x69, 0x74, + 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x11, 0x65, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x12, 0x3f, 0x0a, 0x0a, 0x62, 0x6f, 0x74, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x18, 0x2f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x42, 0x6f, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x74, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x12, 0x7a, 0x0a, 0x1f, 0x75, 0x69, 0x5f, 0x6f, 0x6e, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x5f, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x61, 0x69, 0x72, 0x65, 0x5f, + 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x18, 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, + 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, + 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6e, + 0x61, 0x69, 0x72, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x1c, 0x75, 0x69, 0x4f, 0x6e, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x51, 0x75, 0x65, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x61, 0x69, 0x72, 0x65, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, + 0x39, 0x0a, 0x08, 0x62, 0x6f, 0x74, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x31, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x42, 0x6f, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x07, 0x62, 0x6f, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x51, 0x0a, 0x10, 0x61, 0x73, + 0x73, 0x69, 0x73, 0x74, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x32, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x45, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x61, 0x73, + 0x73, 0x69, 0x73, 0x74, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x64, 0x0a, + 0x17, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x6f, 0x6e, 0x76, + 0x65, 0x72, 0x73, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x33, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x4e, 0x6f, 0x64, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, 0x75, 0x69, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, - 0x65, 0x12, 0x64, 0x0a, 0x17, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x18, 0x44, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x44, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x15, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x65, 0x0a, 0x1a, 0x64, 0x65, 0x73, 0x6b, 0x74, - 0x6f, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x5f, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x45, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x73, - 0x6b, 0x74, 0x6f, 0x70, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x43, 0x6c, 0x69, - 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x52, - 0x0a, 0x11, 0x74, 0x61, 0x67, 0x5f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5f, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, - 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x54, 0x41, 0x47, 0x45, 0x78, - 0x65, 0x63, 0x75, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, - 0x00, 0x52, 0x0f, 0x74, 0x61, 0x67, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x12, 0x86, 0x01, 0x0a, 0x23, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, - 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x47, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x35, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x64, 0x69, 0x74, 0x53, + 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x61, 0x73, + 0x73, 0x69, 0x73, 0x74, 0x4e, 0x65, 0x77, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x65, 0x0a, 0x19, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x6e, 0x0a, 0x1c, 0x66, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, + 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x5e, 0x0a, 0x15, 0x61, 0x73, + 0x73, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, + 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x13, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x48, 0x0a, 0x0d, 0x61, 0x73, + 0x73, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x37, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x41, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x73, 0x73, 0x69, 0x73, 0x74, 0x41, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x53, 0x0a, 0x13, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, + 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x38, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, + 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x53, 0x0a, 0x13, 0x6c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, + 0x18, 0x39, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x11, 0x6c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x55, + 0x0a, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x55, 0x0a, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x3b, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x55, 0x0a, 0x12, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, + 0x00, 0x52, 0x10, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, + 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x68, 0x0a, + 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, + 0x62, 0x65, 0x72, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, + 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x69, 0x0a, 0x1a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x5f, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, + 0x40, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x54, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x54, 0x6f, 0x55, 0x73, 0x65, 0x72, 0x12, 0x81, 0x01, 0x0a, + 0x22, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x63, 0x32, + 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x43, 0x32, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x1e, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x45, 0x63, 0x32, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x62, 0x0a, 0x17, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, + 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x5f, 0x65, 0x69, 0x63, 0x65, 0x18, 0x42, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, + 0x6c, 0x6f, 0x79, 0x45, 0x49, 0x43, 0x45, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x14, + 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, + 0x45, 0x69, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x17, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, + 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x18, + 0x43, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x14, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x64, 0x0a, 0x17, 0x64, 0x65, 0x73, 0x6b, + 0x74, 0x6f, 0x70, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x73, 0x68, + 0x61, 0x72, 0x65, 0x18, 0x44, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x73, 0x6b, 0x74, + 0x6f, 0x70, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, + 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x65, + 0x0a, 0x1a, 0x64, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x5f, 0x63, 0x6c, 0x69, 0x70, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x45, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x44, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0x70, 0x43, 0x6c, 0x69, 0x70, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x18, 0x64, 0x65, 0x73, + 0x6b, 0x74, 0x6f, 0x70, 0x43, 0x6c, 0x69, 0x70, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x11, 0x74, 0x61, 0x67, 0x5f, 0x65, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x54, 0x41, 0x47, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x61, 0x67, 0x45, 0x78, 0x65, + 0x63, 0x75, 0x74, 0x65, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x86, 0x01, 0x0a, 0x23, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x18, 0x47, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x41, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x64, 0x69, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, - 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x6b, 0x0a, 0x1a, 0x73, - 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x67, - 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x17, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x4c, 0x0a, 0x0f, 0x61, 0x75, 0x64, 0x69, - 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x49, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x75, 0x6e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x59, 0x0a, 0x15, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, - 0x65, 0x72, 0x79, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, - 0x4a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, - 0x46, 0x65, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x13, 0x64, 0x69, + 0x74, 0x65, 0x12, 0x6b, 0x0a, 0x1a, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x17, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, + 0x4c, 0x0a, 0x0f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, + 0x75, 0x6e, 0x18, 0x49, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, + 0x61, 0x75, 0x64, 0x69, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x59, 0x0a, + 0x15, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, + 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x4a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, + 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x65, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, - 0x5f, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x4b, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x4c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, + 0x74, 0x48, 0x00, 0x52, 0x13, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x65, + 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x4b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, + 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x12, 0x68, 0x0a, 0x19, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, + 0x4c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x74, 0x0a, 0x1d, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x76, 0x69, + 0x65, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x4d, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, + 0x63, 0x65, 0x12, 0x62, 0x0a, 0x18, 0x6d, 0x66, 0x61, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x4e, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4d, 0x46, 0x41, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, + 0x6d, 0x66, 0x61, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x55, 0x0a, 0x12, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, + 0x5f, 0x73, 0x76, 0x69, 0x64, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x4f, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x53, 0x50, 0x49, 0x46, 0x46, 0x45, 0x53, 0x56, 0x49, 0x44, 0x49, 0x73, + 0x73, 0x75, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x73, 0x70, 0x69, + 0x66, 0x66, 0x65, 0x53, 0x76, 0x69, 0x64, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x12, 0x5c, 0x0a, + 0x15, 0x6f, 0x6b, 0x74, 0x61, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x50, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, + 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4f, 0x6b, + 0x74, 0x61, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x6f, 0x6b, 0x74, 0x61, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x12, 0x5e, 0x0a, 0x15, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x18, 0x51, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x13, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x7f, 0x0a, 0x21, 0x64, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x18, 0x52, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x84, 0x01, 0x0a, + 0x23, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x53, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x1f, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x12, 0x77, 0x0a, 0x21, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x5f, 0x6b, 0x75, 0x62, 0x65, 0x5f, 0x65, 0x6b, 0x73, 0x5f, 0x65, 0x6e, 0x72, 0x6f, + 0x6c, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x54, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x74, 0x0a, 0x1d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x4d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x70, - 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x1a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x62, 0x0a, 0x18, 0x6d, - 0x66, 0x61, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x4e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4d, - 0x46, 0x41, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x16, 0x6d, 0x66, 0x61, 0x41, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x55, 0x0a, 0x12, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x73, 0x76, 0x69, 0x64, 0x5f, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x4f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, - 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x50, 0x49, - 0x46, 0x46, 0x45, 0x53, 0x56, 0x49, 0x44, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x53, 0x76, 0x69, 0x64, - 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x12, 0x5c, 0x0a, 0x15, 0x6f, 0x6b, 0x74, 0x61, 0x5f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x18, - 0x50, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4f, 0x6b, 0x74, 0x61, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, - 0x52, 0x12, 0x6f, 0x6b, 0x74, 0x61, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, - 0x53, 0x79, 0x6e, 0x63, 0x12, 0x5e, 0x0a, 0x15, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x51, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x13, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x12, 0x7f, 0x0a, 0x21, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, - 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x52, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x32, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x55, - 0x73, 0x65, 0x72, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x84, 0x01, 0x0a, 0x23, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x53, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, 0x75, 0x69, 0x44, - 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x77, 0x0a, 0x21, - 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x75, 0x62, 0x65, - 0x5f, 0x65, 0x6b, 0x73, 0x5f, 0x65, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x18, 0x54, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x4b, 0x75, 0x62, 0x65, 0x45, 0x4b, 0x53, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x76, 0x65, 0x72, 0x4b, 0x75, 0x62, 0x65, 0x45, 0x6b, 0x73, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x7d, 0x0a, 0x23, 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, - 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x70, 0x70, 0x5f, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x55, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x12, 0x65, 0x0a, 0x18, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x5f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x5f, 0x73, 0x63, 0x61, 0x6e, - 0x18, 0x56, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x53, 0x63, 0x61, 0x6e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x94, 0x01, 0x0a, 0x29, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x73, 0x65, 0x63, - 0x72, 0x65, 0x74, 0x73, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x57, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x39, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x64, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x24, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, - 0x53, 0x63, 0x61, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, - 0x79, 0x73, 0x12, 0x95, 0x01, 0x0a, 0x2a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, + 0x55, 0x49, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x75, 0x62, 0x65, 0x45, 0x4b, + 0x53, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, + 0x75, 0x69, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4b, 0x75, 0x62, 0x65, 0x45, 0x6b, + 0x73, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x7d, 0x0a, 0x23, + 0x75, 0x69, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x18, 0x55, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x44, 0x69, 0x73, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1e, 0x75, 0x69, 0x44, + 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x70, 0x70, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x65, 0x0a, 0x18, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x67, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x18, 0x56, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, + 0x53, 0x63, 0x61, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x53, 0x63, + 0x61, 0x6e, 0x12, 0x94, 0x01, 0x0a, 0x29, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x5f, 0x73, 0x63, 0x61, 0x6e, - 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, - 0x73, 0x18, 0x58, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x53, - 0x53, 0x48, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x24, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x53, 0x73, 0x68, 0x50, - 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x5c, 0x0a, 0x15, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x73, - 0x63, 0x61, 0x6e, 0x18, 0x59, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x65, 0x68, - 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, 0x57, 0x53, 0x53, 0x63, 0x61, 0x6e, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x41, 0x77, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x7b, 0x0a, 0x20, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x5a, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, - 0x72, 0x61, 0x70, 0x68, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x78, 0x0a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x5f, 0x6a, 0x65, 0x77, 0x65, - 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, 0x5b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x73, + 0x18, 0x57, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x48, 0x00, 0x52, 0x24, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x95, 0x01, 0x0a, 0x2a, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x73, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x58, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x72, 0x6f, 0x77, 0x6e, - 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x1b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, - 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, - 0x86, 0x01, 0x0a, 0x25, 0x75, 0x69, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x5f, 0x63, 0x72, 0x6f, 0x77, 0x6e, 0x5f, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x5f, - 0x64, 0x69, 0x66, 0x66, 0x5f, 0x76, 0x69, 0x65, 0x77, 0x18, 0x5c, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x34, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x55, 0x49, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x72, - 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x56, 0x69, 0x65, 0x77, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, 0x75, 0x69, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x53, 0x53, 0x48, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x4b, 0x65, 0x79, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x24, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x53, + 0x63, 0x61, 0x6e, 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, + 0x73, 0x12, 0x5c, 0x0a, 0x15, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x5f, 0x61, 0x77, 0x73, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x18, 0x59, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x27, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, 0x57, 0x53, + 0x53, 0x63, 0x61, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, 0x77, 0x73, 0x53, 0x63, 0x61, 0x6e, 0x12, + 0x7b, 0x0a, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1c, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x78, 0x0a, 0x1f, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x72, 0x6f, + 0x77, 0x6e, 0x5f, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x18, + 0x5b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, + 0x70, 0x68, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, - 0x44, 0x69, 0x66, 0x66, 0x56, 0x69, 0x65, 0x77, 0x12, 0x4c, 0x0a, 0x0f, 0x75, 0x73, 0x65, 0x72, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x25, 0x75, 0x69, 0x5f, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x5f, 0x63, 0x72, 0x6f, 0x77, 0x6e, + 0x5f, 0x6a, 0x65, 0x77, 0x65, 0x6c, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x76, 0x69, 0x65, 0x77, + 0x18, 0x5c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x49, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x72, 0x6f, 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x44, + 0x69, 0x66, 0x66, 0x56, 0x69, 0x65, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x1f, + 0x75, 0x69, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x72, 0x6f, + 0x77, 0x6e, 0x4a, 0x65, 0x77, 0x65, 0x6c, 0x44, 0x69, 0x66, 0x66, 0x56, 0x69, 0x65, 0x77, 0x12, + 0x67, 0x0a, 0x18, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x5d, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x16, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x69, + 0x6e, 0x67, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x4c, 0x0a, 0x0f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x5e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x65, @@ -10760,7 +10865,7 @@ var file_prehog_v1alpha_teleport_proto_rawDesc = []byte{ 0x12, 0x19, 0x0a, 0x15, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x56, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, - 0x42, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0xc1, 0x02, 0x0a, 0x03, 0x43, 0x54, 0x41, + 0x42, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0xd4, 0x02, 0x0a, 0x03, 0x43, 0x54, 0x41, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x54, 0x41, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x54, 0x41, 0x5f, 0x41, 0x55, 0x54, 0x48, 0x5f, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x17, 0x0a, @@ -10780,142 +10885,143 @@ var file_prehog_v1alpha_teleport_proto_rawDesc = []byte{ 0x41, 0x4c, 0x5f, 0x41, 0x55, 0x44, 0x49, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x54, 0x41, 0x5f, 0x4f, 0x4b, 0x54, 0x41, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x54, - 0x41, 0x5f, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x2a, 0xe3, 0x08, 0x0a, - 0x15, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x72, 0x6f, - 0x6c, 0x6c, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x23, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, - 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, - 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x53, 0x4c, 0x41, 0x43, 0x4b, - 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41, 0x57, - 0x53, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, - 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x52, 0x44, 0x55, 0x54, 0x59, 0x10, 0x03, 0x12, - 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, - 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x45, 0x4d, 0x41, 0x49, 0x4c, - 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, - 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4a, 0x49, - 0x52, 0x41, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, - 0x44, 0x49, 0x53, 0x43, 0x4f, 0x52, 0x44, 0x10, 0x06, 0x12, 0x26, 0x0a, 0x22, 0x49, 0x4e, 0x54, + 0x41, 0x5f, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x12, 0x11, 0x0a, 0x0d, + 0x43, 0x54, 0x41, 0x5f, 0x4f, 0x4b, 0x54, 0x41, 0x5f, 0x53, 0x43, 0x49, 0x4d, 0x10, 0x0d, 0x2a, + 0xe3, 0x08, 0x0a, 0x15, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x27, 0x0a, 0x23, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, - 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x4d, 0x4f, 0x53, 0x54, 0x10, - 0x07, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x53, 0x5f, - 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x08, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, + 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x53, 0x4c, + 0x41, 0x43, 0x4b, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, + 0x5f, 0x41, 0x57, 0x53, 0x5f, 0x4f, 0x49, 0x44, 0x43, 0x10, 0x02, 0x12, 0x25, 0x0a, 0x21, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, + 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x52, 0x44, 0x55, 0x54, 0x59, + 0x10, 0x03, 0x12, 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x45, 0x4d, + 0x41, 0x49, 0x4c, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, + 0x5f, 0x4a, 0x49, 0x52, 0x41, 0x10, 0x05, 0x12, 0x23, 0x0a, 0x1f, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, - 0x4e, 0x44, 0x5f, 0x4f, 0x50, 0x53, 0x47, 0x45, 0x4e, 0x49, 0x45, 0x10, 0x09, 0x12, 0x20, 0x0a, - 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, - 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x4b, 0x54, 0x41, 0x10, 0x0a, 0x12, - 0x20, 0x0a, 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, - 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4a, 0x41, 0x4d, 0x46, 0x10, - 0x0b, 0x12, 0x26, 0x0a, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, - 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x12, 0x35, 0x0a, 0x31, 0x49, 0x4e, 0x54, - 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, - 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, - 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x53, 0x10, 0x0d, - 0x12, 0x2f, 0x0a, 0x2b, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, - 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, 0x45, 0x43, 0x49, 0x10, - 0x0e, 0x12, 0x2d, 0x0a, 0x29, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, - 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x47, 0x49, 0x54, 0x4c, 0x41, 0x42, 0x10, 0x0f, - 0x12, 0x2e, 0x0a, 0x2a, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, - 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, 0x53, 0x10, 0x10, - 0x12, 0x2e, 0x0a, 0x2a, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, - 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x41, 0x4e, 0x53, 0x49, 0x42, 0x4c, 0x45, 0x10, 0x11, - 0x12, 0x2a, 0x0a, 0x26, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, - 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, - 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x41, 0x57, 0x53, 0x10, 0x12, 0x12, 0x2a, 0x0a, 0x26, + 0x4e, 0x44, 0x5f, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x52, 0x44, 0x10, 0x06, 0x12, 0x26, 0x0a, 0x22, + 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, + 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x54, 0x54, 0x45, 0x52, 0x4d, 0x4f, + 0x53, 0x54, 0x10, 0x07, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, + 0x4d, 0x53, 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x08, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, + 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, + 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x50, 0x53, 0x47, 0x45, 0x4e, 0x49, 0x45, 0x10, 0x09, + 0x12, 0x20, 0x0a, 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x4b, 0x54, 0x41, + 0x10, 0x0a, 0x12, 0x20, 0x0a, 0x1c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4a, 0x41, + 0x4d, 0x46, 0x10, 0x0b, 0x12, 0x26, 0x0a, 0x22, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, + 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x10, 0x0c, 0x12, 0x35, 0x0a, 0x31, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, - 0x49, 0x44, 0x5f, 0x47, 0x43, 0x50, 0x10, 0x13, 0x12, 0x2c, 0x0a, 0x28, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, - 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x41, - 0x5a, 0x55, 0x52, 0x45, 0x10, 0x14, 0x12, 0x30, 0x0a, 0x2c, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, - 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x53, 0x50, 0x41, - 0x43, 0x45, 0x4c, 0x49, 0x46, 0x54, 0x10, 0x15, 0x12, 0x31, 0x0a, 0x2d, 0x49, 0x4e, 0x54, 0x45, - 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, - 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x4b, - 0x55, 0x42, 0x45, 0x52, 0x4e, 0x45, 0x54, 0x45, 0x53, 0x10, 0x16, 0x12, 0x24, 0x0a, 0x20, 0x49, + 0x49, 0x44, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x53, 0x10, 0x0d, 0x12, 0x2f, 0x0a, 0x2b, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, 0x45, + 0x43, 0x49, 0x10, 0x0e, 0x12, 0x2d, 0x0a, 0x29, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, + 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x47, 0x49, 0x54, 0x4c, 0x41, + 0x42, 0x10, 0x0f, 0x12, 0x2e, 0x0a, 0x2a, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, + 0x53, 0x10, 0x10, 0x12, 0x2e, 0x0a, 0x2a, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x41, 0x4e, 0x53, 0x49, 0x42, 0x4c, + 0x45, 0x10, 0x11, 0x12, 0x2a, 0x0a, 0x26, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x41, 0x57, 0x53, 0x10, 0x12, 0x12, + 0x2a, 0x0a, 0x26, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, + 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, + 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x47, 0x43, 0x50, 0x10, 0x13, 0x12, 0x2c, 0x0a, 0x28, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, - 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x5f, 0x49, 0x44, 0x10, - 0x17, 0x12, 0x37, 0x0a, 0x33, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x44, 0x41, 0x54, - 0x41, 0x44, 0x4f, 0x47, 0x5f, 0x49, 0x4e, 0x43, 0x49, 0x44, 0x45, 0x4e, 0x54, 0x5f, 0x4d, 0x41, - 0x4e, 0x41, 0x47, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x18, 0x12, 0x26, 0x0a, 0x22, 0x49, 0x4e, - 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, - 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, 0x4e, 0x4f, 0x57, - 0x10, 0x19, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x43, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x20, 0x45, 0x44, 0x49, + 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, + 0x44, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x10, 0x14, 0x12, 0x30, 0x0a, 0x2c, 0x49, 0x4e, 0x54, + 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, + 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, 0x44, 0x5f, + 0x53, 0x50, 0x41, 0x43, 0x45, 0x4c, 0x49, 0x46, 0x54, 0x10, 0x15, 0x12, 0x31, 0x0a, 0x2d, 0x49, + 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, + 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x49, + 0x44, 0x5f, 0x4b, 0x55, 0x42, 0x45, 0x52, 0x4e, 0x45, 0x54, 0x45, 0x53, 0x10, 0x16, 0x12, 0x24, + 0x0a, 0x20, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, + 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x45, 0x4e, 0x54, 0x52, 0x41, 0x5f, + 0x49, 0x44, 0x10, 0x17, 0x12, 0x37, 0x0a, 0x33, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, + 0x44, 0x41, 0x54, 0x41, 0x44, 0x4f, 0x47, 0x5f, 0x49, 0x4e, 0x43, 0x49, 0x44, 0x45, 0x4e, 0x54, + 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x18, 0x12, 0x26, 0x0a, + 0x22, 0x49, 0x4e, 0x54, 0x45, 0x47, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x4e, 0x52, + 0x4f, 0x4c, 0x4c, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x49, 0x43, 0x45, + 0x4e, 0x4f, 0x57, 0x10, 0x19, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x45, 0x64, 0x69, 0x74, 0x6f, 0x72, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x20, + 0x45, 0x44, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, + 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x25, 0x0a, 0x21, 0x45, 0x44, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, + 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, + 0x47, 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x25, 0x0a, 0x21, 0x45, 0x44, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, - 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x25, 0x0a, 0x21, 0x45, 0x44, 0x49, 0x54, 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, - 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x47, 0x52, 0x41, - 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x25, 0x0a, 0x21, 0x45, 0x44, 0x49, 0x54, 0x4f, 0x52, - 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x52, - 0x4f, 0x4c, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x3f, 0x0a, - 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x45, 0x41, 0x54, - 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x54, 0x52, 0x55, - 0x53, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x53, 0x10, 0x01, 0x2a, 0xa0, - 0x01, 0x0a, 0x1b, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, - 0x0a, 0x29, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, - 0x45, 0x4e, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x2a, 0x0a, - 0x26, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, - 0x4e, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4e, - 0x4f, 0x54, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x26, 0x0a, 0x22, 0x46, 0x45, 0x41, - 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x41, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x4f, 0x4e, 0x45, 0x10, - 0x02, 0x2a, 0x82, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x19, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x4c, 0x49, - 0x4d, 0x49, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x28, 0x0a, 0x24, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x4c, 0x49, 0x4d, - 0x49, 0x54, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x52, 0x55, 0x53, 0x54, 0x5f, - 0x54, 0x45, 0x41, 0x4d, 0x5f, 0x4a, 0x41, 0x4d, 0x46, 0x10, 0x01, 0x12, 0x29, 0x0a, 0x25, 0x4c, - 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x44, 0x45, 0x56, - 0x49, 0x43, 0x45, 0x5f, 0x54, 0x52, 0x55, 0x53, 0x54, 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x5f, 0x55, - 0x53, 0x41, 0x47, 0x45, 0x10, 0x02, 0x32, 0xb4, 0x02, 0x0a, 0x18, 0x54, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, - 0x12, 0x5b, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, + 0x53, 0x5f, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x02, + 0x2a, 0x3f, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x46, + 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, + 0x54, 0x52, 0x55, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x53, 0x10, + 0x01, 0x2a, 0xa0, 0x01, 0x0a, 0x1b, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x2d, 0x0a, 0x29, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, + 0x4f, 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x2a, 0x0a, 0x26, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x4f, + 0x4d, 0x4d, 0x45, 0x4e, 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, + 0x53, 0x5f, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x26, 0x0a, 0x22, + 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x45, 0x4e, + 0x44, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x44, 0x4f, + 0x4e, 0x45, 0x10, 0x02, 0x2a, 0x82, 0x01, 0x0a, 0x0c, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x19, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, + 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x28, 0x0a, 0x24, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, + 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x52, 0x55, + 0x53, 0x54, 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x5f, 0x4a, 0x41, 0x4d, 0x46, 0x10, 0x01, 0x12, 0x29, + 0x0a, 0x25, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, + 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x52, 0x55, 0x53, 0x54, 0x5f, 0x54, 0x45, 0x41, + 0x4d, 0x5f, 0x55, 0x53, 0x41, 0x47, 0x45, 0x10, 0x02, 0x32, 0xb4, 0x02, 0x0a, 0x18, 0x54, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x22, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, - 0x0d, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x24, - 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xc9, 0x01, - 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x42, 0x0d, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4b, 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, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x3b, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, 0x65, 0x68, 0x6f, - 0x67, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0xca, 0x02, 0x0e, 0x50, 0x72, 0x65, 0x68, - 0x6f, 0x67, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0xe2, 0x02, 0x1a, 0x50, 0x72, 0x65, - 0x68, 0x6f, 0x67, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x5c, 0x47, 0x50, 0x42, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x65, 0x68, 0x6f, 0x67, - 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, + 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, + 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x03, + 0x88, 0x02, 0x01, 0x12, 0x5b, 0x0a, 0x0c, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x23, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, + 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x5e, 0x0a, 0x0d, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x54, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x42, 0xc9, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x42, 0x0d, 0x54, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x4b, 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, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x2f, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, 0x70, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, + 0x65, 0x68, 0x6f, 0x67, 0x2e, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0xca, 0x02, 0x0e, 0x50, + 0x72, 0x65, 0x68, 0x6f, 0x67, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0xe2, 0x02, 0x1a, + 0x50, 0x72, 0x65, 0x68, 0x6f, 0x67, 0x5c, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x65, + 0x68, 0x6f, 0x67, 0x3a, 0x3a, 0x56, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -10931,7 +11037,7 @@ func file_prehog_v1alpha_teleport_proto_rawDescGZIP() []byte { } var file_prehog_v1alpha_teleport_proto_enumTypes = make([]protoimpl.EnumInfo, 13) -var file_prehog_v1alpha_teleport_proto_msgTypes = make([]protoimpl.MessageInfo, 103) +var file_prehog_v1alpha_teleport_proto_msgTypes = make([]protoimpl.MessageInfo, 104) var file_prehog_v1alpha_teleport_proto_goTypes = []any{ (ResourceKind)(0), // 0: prehog.v1alpha.ResourceKind (UserKind)(0), // 1: prehog.v1alpha.UserKind @@ -11042,15 +11148,16 @@ var file_prehog_v1alpha_teleport_proto_goTypes = []any{ (*OktaAccessListSyncEvent)(nil), // 106: prehog.v1alpha.OktaAccessListSyncEvent (*DatabaseUserCreatedEvent)(nil), // 107: prehog.v1alpha.DatabaseUserCreatedEvent (*DatabaseUserPermissionsUpdateEvent)(nil), // 108: prehog.v1alpha.DatabaseUserPermissionsUpdateEvent - (*UserTaskStateEvent)(nil), // 109: prehog.v1alpha.UserTaskStateEvent - (*SubmitEventRequest)(nil), // 110: prehog.v1alpha.SubmitEventRequest - (*SubmitEventResponse)(nil), // 111: prehog.v1alpha.SubmitEventResponse - (*SubmitEventsRequest)(nil), // 112: prehog.v1alpha.SubmitEventsRequest - (*SubmitEventsResponse)(nil), // 113: prehog.v1alpha.SubmitEventsResponse - (*HelloTeleportRequest)(nil), // 114: prehog.v1alpha.HelloTeleportRequest - (*HelloTeleportResponse)(nil), // 115: prehog.v1alpha.HelloTeleportResponse - (*durationpb.Duration)(nil), // 116: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 117: google.protobuf.Timestamp + (*SessionRecordingAccessEvent)(nil), // 109: prehog.v1alpha.SessionRecordingAccessEvent + (*UserTaskStateEvent)(nil), // 110: prehog.v1alpha.UserTaskStateEvent + (*SubmitEventRequest)(nil), // 111: prehog.v1alpha.SubmitEventRequest + (*SubmitEventResponse)(nil), // 112: prehog.v1alpha.SubmitEventResponse + (*SubmitEventsRequest)(nil), // 113: prehog.v1alpha.SubmitEventsRequest + (*SubmitEventsResponse)(nil), // 114: prehog.v1alpha.SubmitEventsResponse + (*HelloTeleportRequest)(nil), // 115: prehog.v1alpha.HelloTeleportRequest + (*HelloTeleportResponse)(nil), // 116: prehog.v1alpha.HelloTeleportResponse + (*durationpb.Duration)(nil), // 117: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 118: google.protobuf.Timestamp } var file_prehog_v1alpha_teleport_proto_depIdxs = []int32{ 17, // 0: prehog.v1alpha.ResourceCreateEvent.database:type_name -> prehog.v1alpha.DiscoveredDatabaseMetadata @@ -11058,7 +11165,7 @@ var file_prehog_v1alpha_teleport_proto_depIdxs = []int32{ 20, // 2: prehog.v1alpha.SessionStartEvent.database:type_name -> prehog.v1alpha.SessionStartDatabaseMetadata 21, // 3: prehog.v1alpha.SessionStartEvent.desktop:type_name -> prehog.v1alpha.SessionStartDesktopMetadata 1, // 4: prehog.v1alpha.SessionStartEvent.user_kind:type_name -> prehog.v1alpha.UserKind - 116, // 5: prehog.v1alpha.UserCertificateIssuedEvent.ttl:type_name -> google.protobuf.Duration + 117, // 5: prehog.v1alpha.UserCertificateIssuedEvent.ttl:type_name -> google.protobuf.Duration 1, // 6: prehog.v1alpha.SPIFFESVIDIssuedEvent.user_kind:type_name -> prehog.v1alpha.UserKind 2, // 7: prehog.v1alpha.DiscoverResourceMetadata.resource:type_name -> prehog.v1alpha.DiscoverResource 3, // 8: prehog.v1alpha.DiscoverStepStatus.status:type_name -> prehog.v1alpha.DiscoverStatus @@ -11144,7 +11251,7 @@ var file_prehog_v1alpha_teleport_proto_depIdxs = []int32{ 9, // 88: prehog.v1alpha.LicenseLimitEvent.license_limit:type_name -> prehog.v1alpha.LicenseLimit 20, // 89: prehog.v1alpha.DatabaseUserCreatedEvent.database:type_name -> prehog.v1alpha.SessionStartDatabaseMetadata 20, // 90: prehog.v1alpha.DatabaseUserPermissionsUpdateEvent.database:type_name -> prehog.v1alpha.SessionStartDatabaseMetadata - 117, // 91: prehog.v1alpha.SubmitEventRequest.timestamp:type_name -> google.protobuf.Timestamp + 118, // 91: prehog.v1alpha.SubmitEventRequest.timestamp:type_name -> google.protobuf.Timestamp 13, // 92: prehog.v1alpha.SubmitEventRequest.user_login:type_name -> prehog.v1alpha.UserLoginEvent 15, // 93: prehog.v1alpha.SubmitEventRequest.sso_create:type_name -> prehog.v1alpha.SSOCreateEvent 16, // 94: prehog.v1alpha.SubmitEventRequest.resource_create:type_name -> prehog.v1alpha.ResourceCreateEvent @@ -11234,19 +11341,20 @@ var file_prehog_v1alpha_teleport_proto_depIdxs = []int32{ 99, // 178: prehog.v1alpha.SubmitEventRequest.access_graph_access_path_changed:type_name -> prehog.v1alpha.AccessGraphAccessPathChangedEvent 101, // 179: prehog.v1alpha.SubmitEventRequest.access_graph_crown_jewel_create:type_name -> prehog.v1alpha.AccessGraphCrownJewelCreateEvent 100, // 180: prehog.v1alpha.SubmitEventRequest.ui_access_graph_crown_jewel_diff_view:type_name -> prehog.v1alpha.UIAccessGraphCrownJewelDiffViewEvent - 109, // 181: prehog.v1alpha.SubmitEventRequest.user_task_state:type_name -> prehog.v1alpha.UserTaskStateEvent - 110, // 182: prehog.v1alpha.SubmitEventsRequest.events:type_name -> prehog.v1alpha.SubmitEventRequest - 110, // 183: prehog.v1alpha.TeleportReportingService.SubmitEvent:input_type -> prehog.v1alpha.SubmitEventRequest - 112, // 184: prehog.v1alpha.TeleportReportingService.SubmitEvents:input_type -> prehog.v1alpha.SubmitEventsRequest - 114, // 185: prehog.v1alpha.TeleportReportingService.HelloTeleport:input_type -> prehog.v1alpha.HelloTeleportRequest - 111, // 186: prehog.v1alpha.TeleportReportingService.SubmitEvent:output_type -> prehog.v1alpha.SubmitEventResponse - 113, // 187: prehog.v1alpha.TeleportReportingService.SubmitEvents:output_type -> prehog.v1alpha.SubmitEventsResponse - 115, // 188: prehog.v1alpha.TeleportReportingService.HelloTeleport:output_type -> prehog.v1alpha.HelloTeleportResponse - 186, // [186:189] is the sub-list for method output_type - 183, // [183:186] is the sub-list for method input_type - 183, // [183:183] is the sub-list for extension type_name - 183, // [183:183] is the sub-list for extension extendee - 0, // [0:183] is the sub-list for field type_name + 109, // 181: prehog.v1alpha.SubmitEventRequest.session_recording_access:type_name -> prehog.v1alpha.SessionRecordingAccessEvent + 110, // 182: prehog.v1alpha.SubmitEventRequest.user_task_state:type_name -> prehog.v1alpha.UserTaskStateEvent + 111, // 183: prehog.v1alpha.SubmitEventsRequest.events:type_name -> prehog.v1alpha.SubmitEventRequest + 111, // 184: prehog.v1alpha.TeleportReportingService.SubmitEvent:input_type -> prehog.v1alpha.SubmitEventRequest + 113, // 185: prehog.v1alpha.TeleportReportingService.SubmitEvents:input_type -> prehog.v1alpha.SubmitEventsRequest + 115, // 186: prehog.v1alpha.TeleportReportingService.HelloTeleport:input_type -> prehog.v1alpha.HelloTeleportRequest + 112, // 187: prehog.v1alpha.TeleportReportingService.SubmitEvent:output_type -> prehog.v1alpha.SubmitEventResponse + 114, // 188: prehog.v1alpha.TeleportReportingService.SubmitEvents:output_type -> prehog.v1alpha.SubmitEventsResponse + 116, // 189: prehog.v1alpha.TeleportReportingService.HelloTeleport:output_type -> prehog.v1alpha.HelloTeleportResponse + 187, // [187:190] is the sub-list for method output_type + 184, // [184:187] is the sub-list for method input_type + 184, // [184:184] is the sub-list for extension type_name + 184, // [184:184] is the sub-list for extension extendee + 0, // [0:184] is the sub-list for field type_name } func init() { file_prehog_v1alpha_teleport_proto_init() } @@ -11254,7 +11362,7 @@ func file_prehog_v1alpha_teleport_proto_init() { if File_prehog_v1alpha_teleport_proto != nil { return } - file_prehog_v1alpha_teleport_proto_msgTypes[97].OneofWrappers = []any{ + file_prehog_v1alpha_teleport_proto_msgTypes[98].OneofWrappers = []any{ (*SubmitEventRequest_UserLogin)(nil), (*SubmitEventRequest_SsoCreate)(nil), (*SubmitEventRequest_ResourceCreate)(nil), @@ -11344,6 +11452,7 @@ func file_prehog_v1alpha_teleport_proto_init() { (*SubmitEventRequest_AccessGraphAccessPathChanged)(nil), (*SubmitEventRequest_AccessGraphCrownJewelCreate)(nil), (*SubmitEventRequest_UiAccessGraphCrownJewelDiffView)(nil), + (*SubmitEventRequest_SessionRecordingAccess)(nil), (*SubmitEventRequest_UserTaskState)(nil), } type x struct{} @@ -11352,7 +11461,7 @@ func file_prehog_v1alpha_teleport_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_prehog_v1alpha_teleport_proto_rawDesc, NumEnums: 13, - NumMessages: 103, + NumMessages: 104, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/proto/ts/prehog/v1alpha/teleport_pb.ts b/gen/proto/ts/prehog/v1alpha/teleport_pb.ts index fb7416a23cef0..5b089b63528df 100644 --- a/gen/proto/ts/prehog/v1alpha/teleport_pb.ts +++ b/gen/proto/ts/prehog/v1alpha/teleport_pb.ts @@ -2529,6 +2529,44 @@ export interface DatabaseUserPermissionsUpdateEvent { */ numTablesPermissions: number; } +/** + * SessionRecordingAccessEvent is emitted when the user accesses a session + * recording. + * + * PostHog event: tp.recording.access + * + * @generated from protobuf message prehog.v1alpha.SessionRecordingAccessEvent + */ +export interface SessionRecordingAccessEvent { + /** + * session_type is type of the session, should be + * "ssh"/"k8s"/"db"/"app"/"desktop" (matching the values for + * api/types.SessionKind). + * + * PostHog property: tp.session_type + * + * @generated from protobuf field: string session_type = 1; + */ + sessionType: string; + /** + * user_name is the anonymized Teleport username, 32 bytes (HMAC-SHA-256) + * encoded in base64. + * + * PostHog property: tp.user_name + * + * @generated from protobuf field: string user_name = 2; + */ + userName: string; + /** + * format is the format the session recording was accessed. + * One of text/json/yaml/pty. pty being the interactive session player. + * + * PostHog property: tp.recording.format + * + * @generated from protobuf field: string format = 3; + */ + format: string; +} /** * UserTaskStateEvent is emitted when a UserTask state changes. * This can happen when the Task is created, when it's manually @@ -3141,6 +3179,12 @@ export interface SubmitEventRequest { * @generated from protobuf field: prehog.v1alpha.UIAccessGraphCrownJewelDiffViewEvent ui_access_graph_crown_jewel_diff_view = 92; */ uiAccessGraphCrownJewelDiffView: UIAccessGraphCrownJewelDiffViewEvent; + } | { + oneofKind: "sessionRecordingAccess"; + /** + * @generated from protobuf field: prehog.v1alpha.SessionRecordingAccessEvent session_recording_access = 93; + */ + sessionRecordingAccess: SessionRecordingAccessEvent; } | { oneofKind: "userTaskState"; /** @@ -3554,16 +3598,16 @@ export enum CTA { /** * @generated from protobuf enum value: CTA_ENTRA_ID = 12; */ - CTA_ENTRA_ID = 12 + CTA_ENTRA_ID = 12, + /** + * @generated from protobuf enum value: CTA_OKTA_SCIM = 13; + */ + CTA_OKTA_SCIM = 13 } /** * IntegrationEnrollKind represents the types of integration that * can be enrolled. * - * Note: IntegrationEnrollKind enum must be kept in sync with the values defined - * in api/proto/teleport/usageevents/v1/usageevents.proto. Values 18-25 have - * become out of sync and are manually mapped to each other. - * * @generated from protobuf enum prehog.v1alpha.IntegrationEnrollKind */ export enum IntegrationEnrollKind { @@ -9688,6 +9732,69 @@ class DatabaseUserPermissionsUpdateEvent$Type extends MessageType { + constructor() { + super("prehog.v1alpha.SessionRecordingAccessEvent", [ + { no: 1, name: "session_type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "user_name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "format", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): SessionRecordingAccessEvent { + const message = globalThis.Object.create((this.messagePrototype!)); + message.sessionType = ""; + message.userName = ""; + message.format = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: SessionRecordingAccessEvent): SessionRecordingAccessEvent { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string session_type */ 1: + message.sessionType = reader.string(); + break; + case /* string user_name */ 2: + message.userName = reader.string(); + break; + case /* string format */ 3: + message.format = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: SessionRecordingAccessEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string session_type = 1; */ + if (message.sessionType !== "") + writer.tag(1, WireType.LengthDelimited).string(message.sessionType); + /* string user_name = 2; */ + if (message.userName !== "") + writer.tag(2, WireType.LengthDelimited).string(message.userName); + /* string format = 3; */ + if (message.format !== "") + writer.tag(3, WireType.LengthDelimited).string(message.format); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message prehog.v1alpha.SessionRecordingAccessEvent + */ +export const SessionRecordingAccessEvent = new SessionRecordingAccessEvent$Type(); +// @generated message type with reflection information, may provide speed optimized methods class UserTaskStateEvent$Type extends MessageType { constructor() { super("prehog.v1alpha.UserTaskStateEvent", [ @@ -9853,6 +9960,7 @@ class SubmitEventRequest$Type extends MessageType { { no: 90, name: "access_graph_access_path_changed", kind: "message", oneof: "event", T: () => AccessGraphAccessPathChangedEvent }, { no: 91, name: "access_graph_crown_jewel_create", kind: "message", oneof: "event", T: () => AccessGraphCrownJewelCreateEvent }, { no: 92, name: "ui_access_graph_crown_jewel_diff_view", kind: "message", oneof: "event", T: () => UIAccessGraphCrownJewelDiffViewEvent }, + { no: 93, name: "session_recording_access", kind: "message", oneof: "event", T: () => SessionRecordingAccessEvent }, { no: 94, name: "user_task_state", kind: "message", oneof: "event", T: () => UserTaskStateEvent } ]); } @@ -10409,6 +10517,12 @@ class SubmitEventRequest$Type extends MessageType { uiAccessGraphCrownJewelDiffView: UIAccessGraphCrownJewelDiffViewEvent.internalBinaryRead(reader, reader.uint32(), options, (message.event as any).uiAccessGraphCrownJewelDiffView) }; break; + case /* prehog.v1alpha.SessionRecordingAccessEvent session_recording_access */ 93: + message.event = { + oneofKind: "sessionRecordingAccess", + sessionRecordingAccess: SessionRecordingAccessEvent.internalBinaryRead(reader, reader.uint32(), options, (message.event as any).sessionRecordingAccess) + }; + break; case /* prehog.v1alpha.UserTaskStateEvent user_task_state */ 94: message.event = { oneofKind: "userTaskState", @@ -10700,6 +10814,9 @@ class SubmitEventRequest$Type extends MessageType { /* prehog.v1alpha.UIAccessGraphCrownJewelDiffViewEvent ui_access_graph_crown_jewel_diff_view = 92; */ if (message.event.oneofKind === "uiAccessGraphCrownJewelDiffView") UIAccessGraphCrownJewelDiffViewEvent.internalBinaryWrite(message.event.uiAccessGraphCrownJewelDiffView, writer.tag(92, WireType.LengthDelimited).fork(), options).join(); + /* prehog.v1alpha.SessionRecordingAccessEvent session_recording_access = 93; */ + if (message.event.oneofKind === "sessionRecordingAccess") + SessionRecordingAccessEvent.internalBinaryWrite(message.event.sessionRecordingAccess, writer.tag(93, WireType.LengthDelimited).fork(), options).join(); /* prehog.v1alpha.UserTaskStateEvent user_task_state = 94; */ if (message.event.oneofKind === "userTaskState") UserTaskStateEvent.internalBinaryWrite(message.event.userTaskState, writer.tag(94, WireType.LengthDelimited).fork(), options).join(); diff --git a/proto/prehog/v1alpha/teleport.proto b/proto/prehog/v1alpha/teleport.proto index 0e1e08833dad9..aee8d81b6cfc0 100644 --- a/proto/prehog/v1alpha/teleport.proto +++ b/proto/prehog/v1alpha/teleport.proto @@ -778,6 +778,7 @@ enum CTA { CTA_EXTERNAL_AUDIT_STORAGE = 10; CTA_OKTA_USER_SYNC = 11; CTA_ENTRA_ID = 12; + CTA_OKTA_SCIM = 13; } // a request forwarded to a kube cluster's API server (other than exec and @@ -1008,10 +1009,6 @@ message AccessListReviewComplianceEvent { // IntegrationEnrollKind represents the types of integration that // can be enrolled. -// -// Note: IntegrationEnrollKind enum must be kept in sync with the values defined -// in api/proto/teleport/usageevents/v1/usageevents.proto. Values 18-25 have -// become out of sync and are manually mapped to each other. enum IntegrationEnrollKind { INTEGRATION_ENROLL_KIND_UNSPECIFIED = 0; INTEGRATION_ENROLL_KIND_SLACK = 1; @@ -1403,6 +1400,31 @@ message DatabaseUserPermissionsUpdateEvent { int32 num_tables_permissions = 4; } +// SessionRecordingAccessEvent is emitted when the user accesses a session +// recording. +// +// PostHog event: tp.recording.access +message SessionRecordingAccessEvent { + // session_type is type of the session, should be + // "ssh"/"k8s"/"db"/"app"/"desktop" (matching the values for + // api/types.SessionKind). + // + // PostHog property: tp.session_type + string session_type = 1; + + // user_name is the anonymized Teleport username, 32 bytes (HMAC-SHA-256) + // encoded in base64. + // + // PostHog property: tp.user_name + string user_name = 2; + + // format is the format the session recording was accessed. + // One of text/json/yaml/pty. pty being the interactive session player. + // + // PostHog property: tp.recording.format + string format = 3; +} + // UserTaskStateEvent is emitted when a UserTask state changes. // This can happen when the Task is created, when it's manually // resolved by the user or when it changes back to being open @@ -1588,6 +1610,8 @@ message SubmitEventRequest { UIAccessGraphCrownJewelDiffViewEvent ui_access_graph_crown_jewel_diff_view = 92; + SessionRecordingAccessEvent session_recording_access = 93; + UserTaskStateEvent user_task_state = 94; } diff --git a/web/packages/teleport/src/services/userEvent/types.ts b/web/packages/teleport/src/services/userEvent/types.ts index abe0cfd317bd8..16e927986df65 100644 --- a/web/packages/teleport/src/services/userEvent/types.ts +++ b/web/packages/teleport/src/services/userEvent/types.ts @@ -260,6 +260,7 @@ export enum CtaEvent { CTA_EXTERNAL_AUDIT_STORAGE = 10, CTA_OKTA_USER_SYNC = 11, CTA_ENTRA_ID = 12, + CTA_OKTA_SCIM = 13, } export enum Feature { From 02354f880c65f8a948a512ec8a2f67b9bc093f89 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 28 Oct 2024 10:08:58 -0700 Subject: [PATCH 14/22] Allow passing an optional ARN when health checking an AWSOIDC integration (#46935) * AWS OIDC Ping: allow custom ARN This PR changes the Ping method to accept a custom ARN. This is meant to be used by WebUI to do a health check for the integration: - when creating - when editing - when selecting during Discover flows If the Ping method receives an ARN, it will use that value instead of using the one stored in the backend. * rename arn to roleArn * rename arn to role_arn --------- Co-authored-by: Marco Dinis --- .../integration/v1/awsoidc_service.pb.go | 199 ++++++++++-------- .../integration/v1/awsoidc_service.proto | 7 +- lib/auth/integration/integrationv1/awsoidc.go | 52 +++-- .../integration/integrationv1/awsoidc_test.go | 15 +- lib/integrations/awsoidc/clients.go | 7 - lib/integrations/awsoidc/clients_test.go | 21 +- .../awsoidc/deployservice_vcr_test.go | 9 +- lib/integrations/awsoidc/token_generator.go | 43 ++-- lib/reversetunnel/localsite.go | 7 +- lib/service/awsoidc.go | 7 +- lib/srv/forward/sshserver.go | 7 +- lib/web/integrations_awsoidc.go | 7 + lib/web/ui/integration.go | 8 + 13 files changed, 219 insertions(+), 170 deletions(-) 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 b884c584f70da..8bf7ce97a4bc1 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 @@ -2414,8 +2414,12 @@ type PingRequest struct { unknownFields protoimpl.UnknownFields // Integration is the AWS OIDC Integration name. - // Required. + // Required if ARN is empty. Integration string `protobuf:"bytes,1,opt,name=integration,proto3" json:"integration,omitempty"` + // The AWS Role ARN to be used when generating the token. + // This is used to test another ARN before saving the Integration. + // Required if integration is empty. + RoleArn string `protobuf:"bytes,2,opt,name=role_arn,json=roleArn,proto3" json:"role_arn,omitempty"` } func (x *PingRequest) Reset() { @@ -2455,6 +2459,13 @@ func (x *PingRequest) GetIntegration() string { return "" } +func (x *PingRequest) GetRoleArn() string { + if x != nil { + return x.RoleArn + } + return "" +} + // PingResponse contains the response for the Ping operation. type PingResponse struct { state protoimpl.MessageState @@ -2855,105 +2866,107 @@ var file_teleport_integration_v1_awsoidc_service_proto_rawDesc = []byte{ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2f, 0x0a, 0x0b, + 0x09, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x4a, 0x0a, 0x0b, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x58, 0x0a, - 0x0c, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, - 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, - 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x72, 0x6e, 0x12, 0x17, - 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x32, 0xb0, 0x0a, 0x0a, 0x0e, 0x41, 0x57, 0x53, 0x4f, - 0x49, 0x44, 0x43, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, - 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, - 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0a, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x7d, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, - 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x68, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, - 0x12, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, - 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, - 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x4c, - 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, + 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x41, 0x72, 0x6e, 0x22, 0x58, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x72, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x72, 0x6e, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x32, 0xb0, 0x0a, 0x0a, 0x0e, 0x41, 0x57, 0x53, 0x4f, 0x49, 0x44, 0x43, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, + 0x45, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, - 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, - 0x15, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, - 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x11, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, - 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, + 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x45, 0x49, 0x43, 0x45, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x45, 0x49, 0x43, 0x45, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x0a, + 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x2d, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, - 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x5c, 0x0a, 0x07, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x12, 0x27, 0x2e, 0x74, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7d, 0x0a, + 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x12, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, + 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x0b, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x12, 0x2b, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, + 0x43, 0x73, 0x12, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, + 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, + 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x50, 0x43, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x86, 0x01, 0x0a, 0x15, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6e, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, + 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, + 0x6f, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, + 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x7a, 0x0a, 0x11, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x31, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x74, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, - 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x2e, + 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x32, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x72, 0x6f, 0x6c, 0x6c, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x07, + 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x12, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x43, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, + 0x43, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x74, 0x0a, 0x0f, 0x4c, 0x69, + 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2f, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, - 0x6e, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5a, 0x5a, 0x58, 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, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, 0x43, + 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x4b, 0x53, + 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x53, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x24, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, + 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5a, 0x5a, 0x58, 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, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x76, 0x31, 0x3b, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x76, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/proto/teleport/integration/v1/awsoidc_service.proto b/api/proto/teleport/integration/v1/awsoidc_service.proto index 30b9033a7ae07..699b6721d86ab 100644 --- a/api/proto/teleport/integration/v1/awsoidc_service.proto +++ b/api/proto/teleport/integration/v1/awsoidc_service.proto @@ -529,8 +529,13 @@ message ListEKSClustersResponse { // PingRequest is a request for doing an health check against the configured integration. message PingRequest { // Integration is the AWS OIDC Integration name. - // Required. + // Required if ARN is empty. string integration = 1; + + // The AWS Role ARN to be used when generating the token. + // This is used to test another ARN before saving the Integration. + // Required if integration is empty. + string role_arn = 2; } // PingResponse contains the response for the Ping operation. diff --git a/lib/auth/integration/integrationv1/awsoidc.go b/lib/auth/integration/integrationv1/awsoidc.go index 47ae836ead17c..abc6446662182 100644 --- a/lib/auth/integration/integrationv1/awsoidc.go +++ b/lib/auth/integration/integrationv1/awsoidc.go @@ -157,35 +157,48 @@ func NewAWSOIDCService(cfg *AWSOIDCServiceConfig) (*AWSOIDCService, error) { var _ integrationpb.AWSOIDCServiceServer = (*AWSOIDCService)(nil) -func (s *AWSOIDCService) awsClientReq(ctx context.Context, integrationName, region string) (*awsoidc.AWSClientRequest, error) { +func (s *AWSOIDCService) roleARNForIntegration(ctx context.Context, integrationName string) (string, error) { integration, err := s.integrationService.GetIntegration(ctx, &integrationpb.GetIntegrationRequest{ Name: integrationName, }) if err != nil { - return nil, trace.Wrap(err) + return "", trace.Wrap(err) } if integration.GetSubKind() != types.IntegrationSubKindAWSOIDC { - return nil, trace.BadParameter("integration subkind (%s) mismatch", integration.GetSubKind()) + return "", trace.BadParameter("integration subkind (%s) mismatch", integration.GetSubKind()) } if integration.GetAWSOIDCIntegrationSpec() == nil { - return nil, trace.BadParameter("missing spec fields for %q (%q) integration", integration.GetName(), integration.GetSubKind()) + return "", trace.BadParameter("missing spec fields for %q (%q) integration", integration.GetName(), integration.GetSubKind()) } + return integration.GetAWSOIDCIntegrationSpec().RoleARN, nil +} + +func (s *AWSOIDCService) awsClientReqWithARN(ctx context.Context, integrationName, region, arn string) (*awsoidc.AWSClientRequest, error) { token, err := s.integrationService.generateAWSOIDCTokenWithoutAuthZ(ctx, integrationName) if err != nil { return nil, trace.Wrap(err) } return &awsoidc.AWSClientRequest{ - IntegrationName: integrationName, - Token: token.Token, - RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, - Region: region, + Token: token.Token, + RoleARN: arn, + Region: region, }, nil } +func (s *AWSOIDCService) awsClientReq(ctx context.Context, integrationName, region string) (*awsoidc.AWSClientRequest, error) { + roleARN, err := s.roleARNForIntegration(ctx, integrationName) + if err != nil { + return nil, trace.Wrap(err) + } + + return s.awsClientReqWithARN(ctx, integrationName, region, roleARN) + +} + // ListEICE returns a paginated list of EC2 Instance Connect Endpoints. func (s *AWSOIDCService) ListEICE(ctx context.Context, req *integrationpb.ListEICERequest) (*integrationpb.ListEICEResponse, error) { authCtx, err := s.authorizer.Authorize(ctx) @@ -788,15 +801,20 @@ func (s *AWSOIDCService) Ping(ctx context.Context, req *integrationpb.PingReques return nil, trace.Wrap(err) } - if req.Integration == "" { - return nil, trace.BadParameter("integration is required") - } - - // Instead of asking the user for a region (or storing a default region), we use the sentinel value for the global region. - // This improves the UX, because it is one less input we require from the user. - awsClientReq, err := s.awsClientReq(ctx, req.Integration, awsutils.AWSGlobalRegion) - if err != nil { - return nil, trace.Wrap(err) + var awsClientReq *awsoidc.AWSClientRequest + switch { + case req.GetRoleArn() != "": + awsClientReq, err = s.awsClientReqWithARN(ctx, req.Integration, awsutils.AWSGlobalRegion, req.GetRoleArn()) + if err != nil { + return nil, trace.Wrap(err) + } + case req.GetIntegration() != "": + awsClientReq, err = s.awsClientReq(ctx, req.GetIntegration(), awsutils.AWSGlobalRegion) + if err != nil { + return nil, trace.Wrap(err) + } + default: + return nil, trace.BadParameter("one of arn and integration is required") } awsClient, err := awsoidc.NewPingClient(ctx, awsClientReq) diff --git a/lib/auth/integration/integrationv1/awsoidc_test.go b/lib/auth/integration/integrationv1/awsoidc_test.go index eaa4c5c51fdba..b0ecdc525acd8 100644 --- a/lib/auth/integration/integrationv1/awsoidc_test.go +++ b/lib/auth/integration/integrationv1/awsoidc_test.go @@ -124,11 +124,6 @@ func TestGenerateAWSOIDCToken(t *testing.T) { }) require.NoError(t, err) - t.Run("without integration (v15 and lower clients) returns an error", func(t *testing.T) { - _, err := resourceSvc.GenerateAWSOIDCToken(ctx, &integrationv1.GenerateAWSOIDCTokenRequest{}) - require.Error(t, err) - }) - t.Run("with integration in rpc call but no issuer defined", func(t *testing.T) { resp, err := resourceSvc.GenerateAWSOIDCToken(ctx, &integrationv1.GenerateAWSOIDCTokenRequest{ Integration: integrationNameWithoutIssuer, @@ -323,6 +318,16 @@ func TestRBAC(t *testing.T) { return err }, }, + { + name: "Ping with arn", + fn: func() error { + _, err := awsoidService.Ping(userCtx, &integrationv1.PingRequest{ + Integration: integrationName, + RoleArn: "some-arn", + }) + return err + }, + }, } { t.Run(tt.name, func(t *testing.T) { err := tt.fn() diff --git a/lib/integrations/awsoidc/clients.go b/lib/integrations/awsoidc/clients.go index 82c84136ecb58..52be22b0dabe8 100644 --- a/lib/integrations/awsoidc/clients.go +++ b/lib/integrations/awsoidc/clients.go @@ -37,9 +37,6 @@ import ( // AWSClientRequest contains the required fields to set up an AWS service client. type AWSClientRequest struct { - // IntegrationName is the integration name that is going to issue an API Call. - IntegrationName string - // Token is the token used to issue the API Call. Token string @@ -55,10 +52,6 @@ type AWSClientRequest struct { // CheckAndSetDefaults checks if the required fields are present. func (req *AWSClientRequest) CheckAndSetDefaults() error { - if req.IntegrationName == "" { - return trace.BadParameter("integration name is required") - } - if req.Token == "" { return trace.BadParameter("token is required") } diff --git a/lib/integrations/awsoidc/clients_test.go b/lib/integrations/awsoidc/clients_test.go index ade39eeecdfc8..05e894b2edd7a 100644 --- a/lib/integrations/awsoidc/clients_test.go +++ b/lib/integrations/awsoidc/clients_test.go @@ -29,30 +29,27 @@ import ( func TestCheckAndSetDefaults(t *testing.T) { t.Run("invalid regions must return an error", func(t *testing.T) { err := (&AWSClientRequest{ - IntegrationName: "my-integration", - Token: "token", - RoleARN: "some-arn", - Region: "?", + Token: "token", + RoleARN: "some-arn", + Region: "?", }).CheckAndSetDefaults() require.True(t, trace.IsBadParameter(err)) }) t.Run("valid region", func(t *testing.T) { err := (&AWSClientRequest{ - IntegrationName: "my-integration", - Token: "token", - RoleARN: "some-arn", - Region: "us-east-1", + Token: "token", + RoleARN: "some-arn", + Region: "us-east-1", }).CheckAndSetDefaults() require.NoError(t, err) }) t.Run("empty region", func(t *testing.T) { err := (&AWSClientRequest{ - IntegrationName: "my-integration", - Token: "token", - RoleARN: "some-arn", - Region: "", + Token: "token", + RoleARN: "some-arn", + Region: "", }).CheckAndSetDefaults() require.NoError(t, err) }) diff --git a/lib/integrations/awsoidc/deployservice_vcr_test.go b/lib/integrations/awsoidc/deployservice_vcr_test.go index 24c60c4ccdfa1..48c49a835ff69 100644 --- a/lib/integrations/awsoidc/deployservice_vcr_test.go +++ b/lib/integrations/awsoidc/deployservice_vcr_test.go @@ -69,11 +69,10 @@ func TestDeployDBService(t *testing.T) { return &AWSClientRequest{ // To record new fixtures you will need a valid token. // You can get one by getting the generated token in a real cluster. - Token: awsOIDCToken, - RoleARN: awsOIDCRoleARN, - Region: awsRegion, - IntegrationName: integrationName, - httpClient: httpClient, + Token: awsOIDCToken, + RoleARN: awsOIDCRoleARN, + Region: awsRegion, + httpClient: httpClient, } } diff --git a/lib/integrations/awsoidc/token_generator.go b/lib/integrations/awsoidc/token_generator.go index afcd807325f9b..0cb4e8d122172 100644 --- a/lib/integrations/awsoidc/token_generator.go +++ b/lib/integrations/awsoidc/token_generator.go @@ -59,6 +59,8 @@ type KeyStoreManager interface { // GenerateAWSOIDCTokenRequest contains the required elements to generate an AWS OIDC Token (JWT). type GenerateAWSOIDCTokenRequest struct { // Integration is the AWS OIDC Integration name. + // This field is only used to obtain custom Issuers (those stored at S3 buckets). + // If empty, the default issuer for the cluster (its public endpoint URL) will be used. Integration string // Username is the JWT Username (on behalf of claim) Username string @@ -70,9 +72,6 @@ type GenerateAWSOIDCTokenRequest struct { // CheckAndSetDefaults checks the request params. func (g *GenerateAWSOIDCTokenRequest) CheckAndSetDefaults() error { - if g.Integration == "" { - return trace.BadParameter("integration missing") - } if g.Username == "" { return trace.BadParameter("username missing") } @@ -86,7 +85,28 @@ func (g *GenerateAWSOIDCTokenRequest) CheckAndSetDefaults() error { return nil } -func issuerForIntegration(ctx context.Context, integration types.Integration, cacheClt Cache) (string, error) { +// IssuerForIntegration returns the issuer for a given integration. +// Returns the default Issuer (oidc.IssuerForCluster) if integrationName is empty. +// All calls should be replaced with oidc.IssuerForCluster when IssuerS3URI is removed (it is currently deprecated). +func issuerForIntegration(ctx context.Context, cacheClt Cache, integrationName string) (string, error) { + if integrationName == "" { + issuer, err := oidc.IssuerForCluster(ctx, cacheClt, "") + return issuer, trace.Wrap(err) + } + + integration, err := cacheClt.GetIntegration(ctx, integrationName) + if err != nil { + return "", trace.Wrap(err) + } + + if integration.GetSubKind() != types.IntegrationSubKindAWSOIDC { + return "", trace.BadParameter("integration subkind (%s) mismatch", integration.GetSubKind()) + } + + if integration.GetAWSOIDCIntegrationSpec() == nil { + return "", trace.BadParameter("missing spec fields for %q (%q) integration", integration.GetName(), integration.GetSubKind()) + } + issuerS3URI := integration.GetAWSOIDCIntegrationSpec().IssuerS3URI if issuerS3URI == "" { issuer, err := oidc.IssuerForCluster(ctx, cacheClt, "") @@ -107,20 +127,7 @@ func GenerateAWSOIDCToken(ctx context.Context, cacheClt Cache, keyStoreManager K return "", trace.Wrap(err) } - integration, err := cacheClt.GetIntegration(ctx, req.Integration) - if err != nil { - return "", trace.Wrap(err) - } - - if integration.GetSubKind() != types.IntegrationSubKindAWSOIDC { - return "", trace.BadParameter("integration subkind (%s) mismatch", integration.GetSubKind()) - } - - if integration.GetAWSOIDCIntegrationSpec() == nil { - return "", trace.BadParameter("missing spec fields for %q (%q) integration", integration.GetName(), integration.GetSubKind()) - } - - issuer, err := issuerForIntegration(ctx, integration, cacheClt) + issuer, err := issuerForIntegration(ctx, cacheClt, req.Integration) if err != nil { return "", trace.Wrap(err) } diff --git a/lib/reversetunnel/localsite.go b/lib/reversetunnel/localsite.go index 54e9d5db3a680..0d992cf1f1463 100644 --- a/lib/reversetunnel/localsite.go +++ b/lib/reversetunnel/localsite.go @@ -540,10 +540,9 @@ func (s *localSite) setupTunnelForOpenSSHEICENode(ctx context.Context, targetSer } openTunnelClt, err := awsoidc.NewOpenTunnelEC2Client(ctx, &awsoidc.AWSClientRequest{ - IntegrationName: integration.GetName(), - Token: token, - RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, - Region: awsInfo.Region, + Token: token, + RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, + Region: awsInfo.Region, }) if err != nil { return nil, trace.BadParameter("failed to create the ec2 open tunnel client: %v", err) diff --git a/lib/service/awsoidc.go b/lib/service/awsoidc.go index 7dfedcf62eba7..47baedcac25dd 100644 --- a/lib/service/awsoidc.go +++ b/lib/service/awsoidc.go @@ -265,10 +265,9 @@ func (updater *AWSOIDCDeployServiceUpdater) updateAWSOIDCDeployService(ctx conte } req := &awsoidc.AWSClientRequest{ - IntegrationName: integration.GetName(), - Token: token, - RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, - Region: awsRegion, + Token: token, + RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, + Region: awsRegion, } // The deploy service client is initialized using AWS OIDC integration. diff --git a/lib/srv/forward/sshserver.go b/lib/srv/forward/sshserver.go index 7b2cf1b83fd3b..0e20e9d8434d6 100644 --- a/lib/srv/forward/sshserver.go +++ b/lib/srv/forward/sshserver.go @@ -690,10 +690,9 @@ func (s *Server) sendSSHPublicKeyToTarget(ctx context.Context) (ssh.Signer, erro } sendSSHClient, err := awsoidc.NewEICESendSSHPublicKeyClient(ctx, &awsoidc.AWSClientRequest{ - IntegrationName: integration.GetName(), - Token: token, - RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, - Region: awsInfo.Region, + Token: token, + RoleARN: integration.GetAWSOIDCIntegrationSpec().RoleARN, + Region: awsInfo.Region, }) if err != nil { return nil, trace.BadParameter("failed to create an aws client to send ssh public key: %v", err) diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index 8a28e2582e9c2..52d7d1710809b 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -1434,6 +1434,7 @@ func getServiceURLs(dbServices []types.DatabaseService, accountID, region, telep } // awsOIDCPing performs an health check for the integration. +// If ARN is present in the request body, that's the ARN that will be used instead of using the one stored in the integration. // Returns meta information: account id and assumed the ARN for the IAM Role. func (h *Handler) awsOIDCPing(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() @@ -1443,6 +1444,11 @@ func (h *Handler) awsOIDCPing(w http.ResponseWriter, r *http.Request, p httprout return nil, trace.BadParameter("an integration name is required") } + var req ui.AWSOIDCPingRequest + if err := httplib.ReadJSON(r, &req); err != nil { + return nil, trace.Wrap(err) + } + clt, err := sctx.GetUserClient(ctx, site) if err != nil { return nil, trace.Wrap(err) @@ -1450,6 +1456,7 @@ func (h *Handler) awsOIDCPing(w http.ResponseWriter, r *http.Request, p httprout pingResp, err := clt.IntegrationAWSOIDCClient().Ping(ctx, &integrationv1.PingRequest{ Integration: integrationName, + RoleArn: req.RoleARN, }) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/ui/integration.go b/lib/web/ui/integration.go index 2db7010c4f450..f1eaf46188164 100644 --- a/lib/web/ui/integration.go +++ b/lib/web/ui/integration.go @@ -525,3 +525,11 @@ type AWSOIDCPingResponse struct { // UserID is the unique identifier of the calling entity. UserID string `json:"userId"` } + +// AWSOIDCPingRequest contains ping request fields. +type AWSOIDCPingRequest struct { + // RoleARN is optional, and used for cases such as + // pinging to check validity before upserting an + // AWS OIDC integration. + RoleARN string `json:"roleArn,omitempty"` +} From 7d313a6ce83dad065ef88a4c452226d945337717 Mon Sep 17 00:00:00 2001 From: Brian Joerger Date: Mon, 28 Oct 2024 10:24:52 -0700 Subject: [PATCH 15/22] Allow Teleport Connect users to choose either WebAuthn or OTP in MFA prompts. (#47875) --- lib/client/mfa/prompt.go | 44 ------------------- lib/teleterm/clusters/storage.go | 11 ----- lib/teleterm/daemon/mfaprompt.go | 18 ++++---- .../modals/ReAuthenticate/ReAuthenticate.tsx | 8 ---- 4 files changed, 8 insertions(+), 73 deletions(-) diff --git a/lib/client/mfa/prompt.go b/lib/client/mfa/prompt.go index cfbb6e1c2d1a6..c96935c897f18 100644 --- a/lib/client/mfa/prompt.go +++ b/lib/client/mfa/prompt.go @@ -51,17 +51,8 @@ type PromptConfig struct { ProxyAddress string // WebauthnLoginFunc performs client-side Webauthn login. WebauthnLoginFunc WebauthnLoginFunc - // AllowStdinHijack allows stdin hijack during MFA prompts. - // Stdin hijack provides a better login UX, but it can be difficult to reason - // about and is often a source of bugs. - // Do not set this options unless you deeply understand what you are doing. - // If false then only the strongest auth method is prompted. - AllowStdinHijack bool // AuthenticatorAttachment specifies the desired authenticator attachment. AuthenticatorAttachment wancli.AuthenticatorAttachment - // PreferOTP favors OTP challenges, if applicable. - // Takes precedence over AuthenticatorAttachment settings. - PreferOTP bool // WebauthnSupported indicates whether Webauthn is supported. WebauthnSupported bool } @@ -81,41 +72,6 @@ func NewPromptConfig(proxyAddr string, opts ...mfa.PromptOpt) *PromptConfig { return cfg } -// RunOpts are mfa prompt run options. -type RunOpts struct { - PromptTOTP bool - PromptWebauthn bool -} - -// GetRunOptions gets mfa prompt run options by cross referencing the mfa challenge with prompt configuration. -func (c PromptConfig) GetRunOptions(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (RunOpts, error) { - promptTOTP := chal.TOTP != nil - promptWebauthn := chal.WebauthnChallenge != nil - - // Does the current platform support hardware MFA? Adjust accordingly. - switch { - case !promptTOTP && promptWebauthn && !c.WebauthnSupported: - return RunOpts{}, trace.BadParameter("hardware device MFA not supported by your platform, please register an OTP device") - case !c.WebauthnSupported: - // Do not prompt for hardware devices, it won't work. - promptWebauthn = false - } - - // Tweak enabled/disabled methods according to opts. - switch { - case promptTOTP && c.PreferOTP: - promptWebauthn = false - case promptWebauthn && c.AuthenticatorAttachment != wancli.AttachmentAuto: - // Prefer Webauthn if an specific attachment was requested. - promptTOTP = false - case promptWebauthn && !c.AllowStdinHijack: - // Use strongest auth if hijack is not allowed. - promptTOTP = false - } - - return RunOpts{promptTOTP, promptWebauthn}, nil -} - func (c PromptConfig) GetWebauthnOrigin() string { if !strings.HasPrefix(c.ProxyAddress, "https://") { return "https://" + c.ProxyAddress diff --git a/lib/teleterm/clusters/storage.go b/lib/teleterm/clusters/storage.go index 2be5817012fcf..79e6f63f57a0d 100644 --- a/lib/teleterm/clusters/storage.go +++ b/lib/teleterm/clusters/storage.go @@ -285,17 +285,6 @@ func (s *Storage) makeDefaultClientConfig(rootClusterURI uri.ResourceURI) *clien cfg.InsecureSkipVerify = s.InsecureSkipVerify cfg.AddKeysToAgent = s.AddKeysToAgent cfg.WebauthnLogin = s.WebauthnLogin - // Set AllowStdinHijack to true to enable daemon.mfaPrompt to ask for both TOTP and Webauthn at - // the same time if available. - // - // tsh sets AllowStdinHijack to true only during tsh login to avoid input swallowing bugs where - // calling a command would prompt for MFA and then expect some further data through stdin. tsh - // login does not ask for any further input after the MFA prompt. - // - // Since tsh daemon ran by Connect never expects data over stdin, it can always set this flag to - // true. - cfg.AllowStdinHijack = true - cfg.CustomHardwareKeyPrompt = s.HardwareKeyPromptConstructor(rootClusterURI) cfg.DTAuthnRunCeremony = dtauthn.NewCeremony().Run cfg.DTAutoEnroll = dtenroll.AutoEnroll diff --git a/lib/teleterm/daemon/mfaprompt.go b/lib/teleterm/daemon/mfaprompt.go index 81f53b9ab8004..a40d02130033b 100644 --- a/lib/teleterm/daemon/mfaprompt.go +++ b/lib/teleterm/daemon/mfaprompt.go @@ -73,13 +73,11 @@ func (s *Service) promptAppMFA(ctx context.Context, in *api.PromptMFARequest) (* // Run prompts the user to complete an MFA authentication challenge. func (p *mfaPrompt) Run(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) { - runOpts, err := p.cfg.GetRunOptions(ctx, chal) - if err != nil { - return nil, trace.Wrap(err) - } + promptOTP := chal.TOTP != nil + promptWebauthn := chal.WebauthnChallenge != nil && p.cfg.WebauthnSupported // No prompt to run, no-op. - if !runOpts.PromptTOTP && !runOpts.PromptWebauthn { + if !promptOTP && !promptWebauthn { return &proto.MFAAuthenticateResponse{}, nil } @@ -92,7 +90,7 @@ func (p *mfaPrompt) Run(ctx context.Context, chal *proto.MFAAuthenticateChalleng go func() { defer wg.Done() - resp, err := p.promptMFA(ctx, runOpts) + resp, err := p.promptMFA(ctx, promptOTP, promptWebauthn) respC <- libmfa.MFAGoroutineResponse{Resp: resp, Err: err} // If the user closes the modal in the Electron app, we need to be able to cancel the other @@ -103,7 +101,7 @@ func (p *mfaPrompt) Run(ctx context.Context, chal *proto.MFAAuthenticateChalleng }() // Fire Webauthn goroutine. - if runOpts.PromptWebauthn { + if promptWebauthn { wg.Add(1) go func() { defer wg.Done() @@ -128,12 +126,12 @@ func (p *mfaPrompt) promptWebauthn(ctx context.Context, chal *proto.MFAAuthentic return resp, nil } -func (p *mfaPrompt) promptMFA(ctx context.Context, runOpts libmfa.RunOpts) (*proto.MFAAuthenticateResponse, error) { +func (p *mfaPrompt) promptMFA(ctx context.Context, promptOTP, promptWebauthn bool) (*proto.MFAAuthenticateResponse, error) { resp, err := p.promptAppMFA(ctx, &api.PromptMFARequest{ ClusterUri: p.resourceURI.GetClusterURI().String(), Reason: p.cfg.PromptReason, - Totp: runOpts.PromptTOTP, - Webauthn: runOpts.PromptWebauthn, + Totp: promptOTP, + Webauthn: promptWebauthn, }) if err != nil { return nil, trail.FromGRPC(err) diff --git a/web/packages/teleterm/src/ui/ModalsHost/modals/ReAuthenticate/ReAuthenticate.tsx b/web/packages/teleterm/src/ui/ModalsHost/modals/ReAuthenticate/ReAuthenticate.tsx index aa8386031fed7..456b5a2bd494a 100644 --- a/web/packages/teleterm/src/ui/ModalsHost/modals/ReAuthenticate/ReAuthenticate.tsx +++ b/web/packages/teleterm/src/ui/ModalsHost/modals/ReAuthenticate/ReAuthenticate.tsx @@ -61,14 +61,6 @@ export const ReAuthenticate: FC<{ const logger = useLogger('ReAuthenticate'); const { promptMfaRequest: req } = props; - // TODO(ravicious): At the moment it doesn't seem like it's possible for both Webauthn and TOTP to - // be available at the same time (see lib/client/mfa.PromptConfig/GetRunOptions). Whenever both - // Webauthn and TOTP are supported, Webauthn is preferred. Well, unless AllowStdinHijack is - // specified, but lib/teleterm doesn't do this and AllowStdinHijack has a scary comment next to it - // telling you not to use it. - // - // Alas, the data structure certainly allows for this so the modal was designed with supporting - // such scenario in mind. const availableMfaTypes: MfaType[] = []; // Add Webauthn first to prioritize it if both Webauthn and TOTP are available. if (req.webauthn) { From ac2f8dcf11efddfc2f1a81edb07511c7854a7774 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 28 Oct 2024 10:45:45 -0700 Subject: [PATCH 16/22] Teleterm: add support for access requesting kube namespaces (#47347) --- .../RequestCheckout/KubeNamespaceSelector.tsx | 8 +- .../NewRequest/RequestCheckout/index.ts | 6 +- .../AccessRequests/NewRequest/index.ts | 2 + .../AccessRequestCheckout.tsx | 210 +++++++++--------- .../useAccessRequestCheckout.test.tsx | 120 ++++++++++ .../useAccessRequestCheckout.ts | 138 +++++++++--- .../NewRequest/useNewRequest.ts | 22 +- .../ui/DocumentCluster/UnifiedResources.tsx | 2 +- .../accessRequestsService.test.ts | 10 +- .../accessRequestsService.ts | 80 ++++++- 10 files changed, 458 insertions(+), 140 deletions(-) diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/KubeNamespaceSelector.tsx b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/KubeNamespaceSelector.tsx index 116ac3765b898..dc4221942bc63 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/KubeNamespaceSelector.tsx +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/KubeNamespaceSelector.tsx @@ -129,12 +129,16 @@ export function KubeNamespaceSelector({ }; async function handleLoadOptions(input: string) { - const options = await fetchKubeNamespaces({ + const namespaces = await fetchKubeNamespaces({ kubeCluster: kubeClusterItem.id, search: input, }); - return options; + return namespaces.map(namespace => ({ + kind: 'namespace', + value: namespace, + label: namespace, + })); } return ( diff --git a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/index.ts b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/index.ts index 95712e2755a15..9e727450cd3e1 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/index.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/RequestCheckout/index.ts @@ -17,7 +17,11 @@ */ export { RequestCheckoutWithSlider, RequestCheckout } from './RequestCheckout'; -export type { RequestCheckoutProps, PendingListItem } from './RequestCheckout'; +export type { + RequestCheckoutProps, + PendingListItem, + PendingKubeResourceItem, +} from './RequestCheckout'; export * from './utils'; export type { ReviewerOption } from './types'; diff --git a/web/packages/shared/components/AccessRequests/NewRequest/index.ts b/web/packages/shared/components/AccessRequests/NewRequest/index.ts index 44057733335fa..9074113221b16 100644 --- a/web/packages/shared/components/AccessRequests/NewRequest/index.ts +++ b/web/packages/shared/components/AccessRequests/NewRequest/index.ts @@ -20,3 +20,5 @@ export * from './RequestCheckout'; export * from './ResourceList'; export type { ResourceMap, RequestableResourceKind } from './resource'; export { getEmptyResourceState } from './resource'; +export type { KubeNamespaceRequest } from './kube'; +export { isKubeClusterWithNamespaces } from './kube'; diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx index 8e0904efbeee2..dbcc521911839 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/AccessRequestCheckout.tsx @@ -32,6 +32,7 @@ import * as Icon from 'design/Icon'; import { pluralize } from 'shared/utils/text'; import { RequestCheckoutWithSlider } from 'shared/components/AccessRequests/NewRequest'; +import { isKubeClusterWithNamespaces } from 'shared/components/AccessRequests/NewRequest/kube'; import useAccessRequestCheckout from './useAccessRequestCheckout'; import { AssumedRolesBar } from './AssumedRolesBar'; @@ -102,6 +103,8 @@ export function AccessRequestCheckout() { pendingRequestTtlOptions, startTime, onStartTimeChange, + fetchKubeNamespaces, + bulkToggleKubeResources, } = useAccessRequestCheckout(); const isRoleRequest = pendingAccessRequests[0]?.kind === 'role'; @@ -111,116 +114,126 @@ export function AccessRequestCheckout() { setShowCheckout(false); } + const pendingAccessRequestsWithoutParentResource = + pendingAccessRequests.filter( + d => !isKubeClusterWithNamespaces(d, pendingAccessRequests) + ); + + const numAddedResources = pendingAccessRequestsWithoutParentResource.length; + // We should rather detect how much space we have, // but for simplicity we only count items. const moreToShow = Math.max( - pendingAccessRequests.length - MAX_RESOURCES_IN_BAR_TO_SHOW, + pendingAccessRequestsWithoutParentResource.length - + MAX_RESOURCES_IN_BAR_TO_SHOW, 0 ); - const numPendingAccessRequests = pendingAccessRequests.length; - return ( <> - {pendingAccessRequests.length > 0 && !isCollapsed() && ( - props.theme.colors.spotBackground[1]}; - `} - > - 0 && + !isCollapsed() && ( + props.theme.space[1]}px; + border-top: 1px solid + ${props => props.theme.colors.spotBackground[1]}; `} > - - - {numPendingAccessRequests}{' '} - {pluralize( - numPendingAccessRequests, - isRoleRequest ? 'role' : 'resource' - )}{' '} - added to access request: - - - {pendingAccessRequests - .slice(0, MAX_RESOURCES_IN_BAR_TO_SHOW) - .map(c => { - let resource = { - name: c.name, - key: `${c.clusterName}-${c.kind}-${c.id}`, - Icon: undefined, - }; - switch (c.kind) { - case 'app': - case 'saml_idp_service_provider': - resource.Icon = Icon.Application; - break; - case 'node': - resource.Icon = Icon.Server; - break; - case 'db': - resource.Icon = Icon.Database; - break; - case 'kube_cluster': - resource.Icon = Icon.Kubernetes; - break; - case 'role': - break; - default: - c satisfies never; - } - return resource; - }) - .map(c => ( - - ))} - {!!moreToShow && ( - - )} + {c.Icon && } + + {c.name} + + + ))} + {!!moreToShow && ( + + )} + + + + setShowCheckout(!showCheckout)} + textTransform="none" + css={` + white-space: nowrap; + `} + > + Proceed to request + + + + - - setShowCheckout(!showCheckout)} - textTransform="none" - css={` - white-space: nowrap; - `} - > - Proceed to request - - - - - - - - )} + + )} {assumedRequests.map(request => ( ))} @@ -270,11 +283,8 @@ export function AccessRequestCheckout() { setPendingRequestTtl={setPendingRequestTtl} startTime={startTime} onStartTimeChange={onStartTimeChange} - // TODO: these are placeholders to satisy linters. - // There is a split PR that handles teleterm support - // that will be merged right after this one (once both are approved) - bulkToggleKubeResources={() => null} - fetchKubeNamespaces={() => null} + fetchKubeNamespaces={fetchKubeNamespaces} + bulkToggleKubeResources={bulkToggleKubeResources} /> )} diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx index 11e5c955f2fc8..a4dc881042005 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.test.tsx @@ -21,11 +21,14 @@ import { renderHook, waitFor } from '@testing-library/react'; import { makeRootCluster, makeServer, + makeKube, rootClusterUri, } from 'teleterm/services/tshd/testHelpers'; import { MockAppContext } from 'teleterm/ui/fixtures/mocks'; import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvider'; +import { mapRequestToKubeNamespaceUri } from '../services/workspacesService/accessRequestsService'; + import useAccessRequestCheckout from './useAccessRequestCheckout'; test('fetching requestable roles for servers uses UUID, not hostname', async () => { @@ -64,3 +67,120 @@ test('fetching requestable roles for servers uses UUID, not hostname', async () }) ); }); + +test('fetching requestable roles for a kube_cluster resource without specifying a namespace', async () => { + const kube = makeKube(); + const cluster = makeRootCluster(); + const appContext = new MockAppContext(); + appContext.clustersService.setState(draftState => { + draftState.clusters.set(rootClusterUri, cluster); + }); + await appContext.workspacesService.setActiveWorkspace(rootClusterUri); + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveResource({ + kind: 'kube', + resource: kube, + }); + + jest.spyOn(appContext.tshd, 'getRequestableRoles'); + + const wrapper = ({ children }) => ( + + {children} + + ); + + renderHook(useAccessRequestCheckout, { wrapper }); + + await waitFor(() => + expect(appContext.tshd.getRequestableRoles).toHaveBeenCalledWith({ + clusterUri: rootClusterUri, + resourceIds: [ + { + clusterName: 'teleport-local', + kind: 'kube_cluster', + name: kube.name, + subResourceName: '', + }, + ], + }) + ); +}); + +test(`fetching requestable roles for a kube cluster's namespaces only creates resource IDs for its namespaces`, async () => { + const kube1 = makeKube(); + const kube2 = makeKube({ + name: 'kube2', + uri: `${rootClusterUri}/kubes/kube2`, + }); + const cluster = makeRootCluster(); + const appContext = new MockAppContext(); + appContext.clustersService.setState(draftState => { + draftState.clusters.set(rootClusterUri, cluster); + }); + await appContext.workspacesService.setActiveWorkspace(rootClusterUri); + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveResource({ + kind: 'kube', + resource: kube1, + }); + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveResource({ + kind: 'kube', + resource: kube2, + }); + + await appContext.workspacesService + .getWorkspaceAccessRequestsService(rootClusterUri) + .addOrRemoveKubeNamespaces([ + mapRequestToKubeNamespaceUri({ + clusterUri: rootClusterUri, + id: kube1.name, + name: 'namespace1', + }), + mapRequestToKubeNamespaceUri({ + clusterUri: rootClusterUri, + id: kube1.name, + name: 'namespace2', + }), + ]); + + jest.spyOn(appContext.tshd, 'getRequestableRoles'); + + const wrapper = ({ children }) => ( + + {children} + + ); + + renderHook(useAccessRequestCheckout, { wrapper }); + + await waitFor(() => + expect(appContext.tshd.getRequestableRoles).toHaveBeenCalledWith({ + clusterUri: rootClusterUri, + resourceIds: [ + { + clusterName: 'teleport-local', + kind: 'namespace', + name: kube1.name, + subResourceName: 'namespace1', + }, + { + clusterName: 'teleport-local', + kind: 'namespace', + name: kube1.name, + subResourceName: 'namespace2', + }, + { + clusterName: 'teleport-local', + kind: 'kube_cluster', + name: kube2.name, + subResourceName: '', + }, + ], + }) + ); +}); diff --git a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts index 4ad261cf61b3c..7f8095a019828 100644 --- a/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts +++ b/web/packages/teleterm/src/ui/AccessRequestCheckout/useAccessRequestCheckout.ts @@ -24,6 +24,9 @@ import useAttempt from 'shared/hooks/useAttemptNext'; import { getDryRunMaxDuration, PendingListItem, + PendingKubeResourceItem, + isKubeClusterWithNamespaces, + KubeNamespaceRequest, } from 'shared/components/AccessRequests/NewRequest'; import { useSpecifiableFields } from 'shared/components/AccessRequests/NewRequest/useSpecifiableFields'; @@ -34,6 +37,8 @@ import { PendingAccessRequest, extractResourceRequestProperties, ResourceRequest, + mapRequestToKubeNamespaceUri, + mapKubeNamespaceUriToRequest, } from 'teleterm/ui/services/workspacesService/accessRequestsService'; import { retryWithRelogin } from 'teleterm/ui/utils'; import { @@ -87,9 +92,18 @@ export default function useAccessRequestCheckout() { const workspaceAccessRequest = ctx.workspacesService.getActiveWorkspaceAccessRequestsService(); const docService = ctx.workspacesService.getActiveWorkspaceDocumentService(); - const pendingAccessRequest = + const pendingAccessRequestRequest = workspaceAccessRequest?.getPendingAccessRequest(); + const pendingAccessRequests = getPendingAccessRequestsPerResource( + pendingAccessRequestRequest + ); + + const pendingAccessRequestsWithoutParentResource = + pendingAccessRequests.filter( + p => !isKubeClusterWithNamespaces(p, pendingAccessRequests) + ); + useEffect(() => { // Do a new dry run per changes to pending access requests // to get the latest time options and latest calculated @@ -99,20 +113,18 @@ export default function useAccessRequestCheckout() { if (showCheckout && requestedCount == 0) { performDryRun(); } - }, [showCheckout, pendingAccessRequest]); + }, [showCheckout, pendingAccessRequestRequest]); useEffect(() => { - if (!pendingAccessRequest || requestedCount > 0) { + if (!pendingAccessRequestRequest || requestedCount > 0) { return; } - const pendingAccessRequests = - getPendingAccessRequestsPerResource(pendingAccessRequest); runFetchResourceRoles(() => retryWithRelogin(ctx, clusterUri, async () => { const { response } = await ctx.tshd.getRequestableRoles({ clusterUri: rootClusterUri, - resourceIds: pendingAccessRequests + resourceIds: pendingAccessRequestsWithoutParentResource .filter(d => d.kind !== 'role') .map(d => ({ // We have to use id, not name. @@ -121,14 +133,14 @@ export default function useAccessRequestCheckout() { name: d.id, kind: d.kind, clusterName: d.clusterName, - subResourceName: '', + subResourceName: d.subResourceName || '', })), }); setResourceRequestRoles(response.applicableRoles); setSelectedResourceRequestRoles(response.applicableRoles); }) ); - }, [pendingAccessRequest]); + }, [pendingAccessRequestRequest]); useEffect(() => { clearCreateAttempt(); @@ -146,6 +158,9 @@ export default function useAccessRequestCheckout() { } }, [showCheckout, hasExited, createRequestAttempt.status]); + /** + * @param pendingRequest holds a list or map of resources to process + */ function getPendingAccessRequestsPerResource( pendingRequest: PendingAccessRequest ): PendingListItemWithOriginalItem[] { @@ -170,9 +185,34 @@ export default function useAccessRequestCheckout() { } case 'resource': { pendingRequest.resources.forEach(resourceRequest => { + // If this request is a kube cluster and has namespaces + // extract each as own request. + if ( + resourceRequest.kind === 'kube' && + resourceRequest.resource.namespaces?.size > 0 + ) { + // Process each namespace. + resourceRequest.resource.namespaces.forEach(namespaceRequestUri => { + const { kind, id, name } = + mapKubeNamespaceUriToRequest(namespaceRequestUri); + + const item = { + kind, + id, + name, + subResourceName: name, + originalItem: resourceRequest, + clusterName: + ctx.clustersService.findClusterByResource(namespaceRequestUri) + ?.name, + }; + pendingAccessRequests.push(item); + }); + } + const { kind, id, name } = extractResourceRequestProperties(resourceRequest); - pendingAccessRequests.push({ + const item: PendingListItemWithOriginalItem = { kind, id, name, @@ -180,7 +220,8 @@ export default function useAccessRequestCheckout() { clusterName: ctx.clustersService.findClusterByResource( resourceRequest.resource.uri )?.name, - }); + }; + pendingAccessRequests.push(item); }); } } @@ -207,6 +248,21 @@ export default function useAccessRequestCheckout() { ); } + async function bulkToggleKubeResources( + items: PendingKubeResourceItem[], + kubeCluster: PendingListKubeClusterWithOriginalItem + ) { + await workspaceAccessRequest.addOrRemoveKubeNamespaces( + items.map(item => + mapRequestToKubeNamespaceUri({ + id: item.id, + name: item.subResourceName, + clusterUri: kubeCluster.originalItem.resource.uri, + }) + ) + ); + } + function getAssumedRequests() { if (!clusterUri) { return []; @@ -222,22 +278,22 @@ export default function useAccessRequestCheckout() { * Shared logic used both during dry runs and regular access request creation. */ function prepareAndCreateRequest(req: CreateRequest) { - const pendingAccessRequests = - getPendingAccessRequestsPerResource(pendingAccessRequest); const params: CreateAccessRequestRequest = { rootClusterUri, reason: req.reason, suggestedReviewers: req.suggestedReviewers || [], dryRun: req.dryRun, - resourceIds: pendingAccessRequests + resourceIds: pendingAccessRequestsWithoutParentResource .filter(d => d.kind !== 'role') - .map(d => ({ - name: d.id, - clusterName: d.clusterName, - kind: d.kind, - subResourceName: '', - })), - roles: pendingAccessRequests + .map(d => { + return { + name: d.id, + clusterName: d.clusterName, + kind: d.kind, + subResourceName: d.subResourceName || '', + }; + }), + roles: pendingAccessRequestsWithoutParentResource .filter(d => d.kind === 'role') .map(d => d.name), assumeStartTime: req.start && Timestamp.fromDate(req.start), @@ -245,6 +301,11 @@ export default function useAccessRequestCheckout() { requestTtl: req.requestTTL && Timestamp.fromDate(req.requestTTL), }; + // Don't attempt creating anything if there are no resources selected. + if (!params.resourceIds.length && !params.roles.length) { + return; + } + // if we have a resource access request, we pass along the selected roles from the checkout if (params.resourceIds.length > 0) { params.roles = selectedResourceRequestRoles; @@ -256,7 +317,8 @@ export default function useAccessRequestCheckout() { ctx.clustersService.createAccessRequest(params).then(({ response }) => { return { accessRequest: response.request, - requestedCount: pendingAccessRequests.length, + requestedCount: + pendingAccessRequestsWithoutParentResource.filter.length, }; }) ).catch(e => { @@ -275,9 +337,9 @@ export default function useAccessRequestCheckout() { }); teletermAccessRequest = accessRequest; } catch { + setCreateRequestAttempt({ status: '' }); return; } - setCreateRequestAttempt({ status: '' }); const accessRequest = makeUiAccessRequest(teletermAccessRequest); @@ -333,9 +395,27 @@ export default function useAccessRequestCheckout() { } } + async function fetchKubeNamespaces({ + kubeCluster, + search, + }: KubeNamespaceRequest): Promise { + const { response } = await ctx.tshd.listKubernetesResources({ + searchKeywords: search, + limit: 50, + useSearchAsRoles: true, + nextKey: '', + resourceType: 'namespace', + clusterUri, + predicateExpression: '', + kubernetesCluster: kubeCluster, + kubernetesNamespace: '', + }); + return response.resources.map(i => i.name); + } + const shouldShowClusterNameColumn = - pendingAccessRequest?.kind === 'resource' && - Array.from(pendingAccessRequest.resources.values()).some(a => + pendingAccessRequestRequest?.kind === 'resource' && + Array.from(pendingAccessRequestRequest.resources.values()).some(a => routing.isLeafCluster(a.resource.uri) ); @@ -344,8 +424,7 @@ export default function useAccessRequestCheckout() { isCollapsed, assumedRequests: getAssumedRequests(), toggleResource, - pendingAccessRequests: - getPendingAccessRequestsPerResource(pendingAccessRequest), + pendingAccessRequests, shouldShowClusterNameColumn, createRequest, reset, @@ -373,6 +452,8 @@ export default function useAccessRequestCheckout() { pendingRequestTtlOptions, startTime, onStartTimeChange, + fetchKubeNamespaces, + bulkToggleKubeResources, }; } @@ -386,3 +467,8 @@ type PendingListItemWithOriginalItem = Omit & kind: 'role'; } ); + +type PendingListKubeClusterWithOriginalItem = Omit & { + kind: Extract; + originalItem: Extract; +}; diff --git a/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/useNewRequest.ts b/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/useNewRequest.ts index fefd237f739f0..bcc9d7b04f3e0 100644 --- a/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/useNewRequest.ts +++ b/web/packages/teleterm/src/ui/DocumentAccessRequests/NewRequest/useNewRequest.ts @@ -22,6 +22,7 @@ import { FetchStatus, SortType } from 'design/DataTable/types'; import useAttempt from 'shared/hooks/useAttemptNext'; import { makeAdvancedSearchQueryForLabel } from 'shared/utils/advancedSearchLabelQuery'; +import { RequestableResourceKind } from 'shared/components/AccessRequests/NewRequest/resource'; import { ShowResources, @@ -49,7 +50,6 @@ import type { ResourceLabel, ResourceFilter as WeakAgentFilter, ResourcesResponse, - ResourceIdKind, UnifiedResource, } from 'teleport/services/agents'; import type * as teleportApps from 'teleport/services/apps'; @@ -211,6 +211,17 @@ export default function useNewRequest(rootCluster: Cluster) { return; } + /** + * This should never happen but just a safeguard. + * This function is used in the "unified resources" view, + * where a user can click on a "request access" button. + * Selecting kube_cluster's namespace is not available in this view + * (instead it is rendered in the "request checkout" view). + */ + if (kind === 'namespace') { + return; + } + accessRequestsService.addOrRemoveResource( toResourceRequest({ kind, @@ -348,8 +359,13 @@ function getDefaultSort(kind: ResourceKind): SortType { export type ResourceKind = | Extract< - ResourceIdKind, - 'node' | 'app' | 'db' | 'kube_cluster' | 'saml_idp_service_provider' + RequestableResourceKind, + | 'node' + | 'app' + | 'db' + | 'kube_cluster' + | 'saml_idp_service_provider' + | 'namespace' > | 'role'; diff --git a/web/packages/teleterm/src/ui/DocumentCluster/UnifiedResources.tsx b/web/packages/teleterm/src/ui/DocumentCluster/UnifiedResources.tsx index 03da9da97f998..1d2f6e7613701 100644 --- a/web/packages/teleterm/src/ui/DocumentCluster/UnifiedResources.tsx +++ b/web/packages/teleterm/src/ui/DocumentCluster/UnifiedResources.tsx @@ -223,7 +223,7 @@ export function UnifiedResources(props: { const bulkAddResources = useCallback( (resources: UnifiedResourceResponse[]) => { - accessRequestsService.addOrRemoveResources(resources); + accessRequestsService.addAllOrRemoveAllResources(resources); }, [accessRequestsService] ); diff --git a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.test.ts b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.test.ts index 751cab9849052..c0b2f46f99217 100644 --- a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.test.ts +++ b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.test.ts @@ -124,7 +124,7 @@ test('getAddedItemsCount() returns added resource count for pending request', () expect(service.getAddedItemsCount()).toBe(0); }); -test('addOrRemoveResources() adds all resources to pending request', async () => { +test('addAllOrRemoveAllResources() adds all resources to pending request', async () => { const { accessRequestsService: service } = getTestSetup( getMockPendingResourceAccessRequest() ); @@ -138,7 +138,9 @@ test('addOrRemoveResources() adds all resources to pending request', async () => }); // add a single resource that isn't added should add to the request - await service.addOrRemoveResources([{ kind: 'server', resource: server }]); + await service.addAllOrRemoveAllResources([ + { kind: 'server', resource: server }, + ]); let pendingAccessRequest = service.getPendingAccessRequest(); expect( pendingAccessRequest.kind === 'resource' && @@ -149,7 +151,7 @@ test('addOrRemoveResources() adds all resources to pending request', async () => }); // padding an array that contains some resources already added and some that aren't should add them all - await service.addOrRemoveResources([ + await service.addAllOrRemoveAllResources([ { kind: 'server', resource: server }, { kind: 'server', resource: server2 }, ]); @@ -170,7 +172,7 @@ test('addOrRemoveResources() adds all resources to pending request', async () => }); // passing an array of resources that are all already added should remove all the passed resources - await service.addOrRemoveResources([ + await service.addAllOrRemoveAllResources([ { kind: 'server', resource: server }, { kind: 'server', resource: server2 }, ]); diff --git a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts index f8ff36b9c2491..e408e8244de68 100644 --- a/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts +++ b/web/packages/teleterm/src/ui/services/workspacesService/accessRequestsService.ts @@ -24,6 +24,7 @@ import { DatabaseUri, KubeUri, AppUri, + KubeResourceNamespaceUri, } from 'teleterm/ui/uri'; import { ModalsService } from 'teleterm/ui/services/modals'; @@ -98,7 +99,44 @@ export class AccessRequestsService { }); } - async addOrRemoveResources(requestedResources: ResourceRequest[]) { + async addOrRemoveKubeNamespaces(namespaceUris: KubeResourceNamespaceUri[]) { + this.setState(draftState => { + if (draftState.pending.kind !== 'resource') { + throw new Error('Cannot add a kube namespace to a role access request'); + } + + const { resources } = draftState.pending; + + namespaceUris.forEach(resourceUri => { + const requestedResource = resources.get( + routing.getKubeUri( + routing.parseKubeResourceNamespaceUri(resourceUri).params + ) + ); + if (!requestedResource || requestedResource.kind !== 'kube') { + throw new Error('Cannot add a kube namespace to a non-kube resource'); + } + const kubeResource = requestedResource.resource; + + if (!kubeResource.namespaces) { + kubeResource.namespaces = new Set(); + } + if (kubeResource.namespaces.has(resourceUri)) { + kubeResource.namespaces.delete(resourceUri); + } else { + kubeResource.namespaces.add(resourceUri); + } + }); + }); + } + + /** + * Removes all requested resources, if all the requested resources were already added + * or adds all requested resources, if not all requested resources were added. + * + * Typically used when user "selects all or deselects all" + */ + async addAllOrRemoveAllResources(requestedResources: ResourceRequest[]) { if (!(await this.canUpdateRequest('resource'))) { return; } @@ -258,6 +296,7 @@ export type ResourceRequest = kind: 'kube'; resource: { uri: KubeUri; + namespaces?: Set; }; } | { @@ -287,8 +326,7 @@ export function extractResourceRequestProperties({ kind: SharedResourceAccessRequestKind; id: string; /** - * Pretty name of the resource (can be the same as `id`). - * For example, for nodes, we want to show hostname instead of its id. + * Can refer to a pretty name of the resource (can be the same as `id`) */ name: string; } { @@ -317,6 +355,42 @@ export function extractResourceRequestProperties({ } } +export function mapRequestToKubeNamespaceUri({ + clusterUri, + id, + name, +}: { + clusterUri: ClusterUri; + /** kubeId */ + id: string; + /** kubeNamespaceId */ + name: string; +}) { + const { + params: { rootClusterId, leafClusterId }, + } = routing.parseClusterUri(clusterUri); + return routing.getKubeResourceNamespaceUri({ + rootClusterId, + leafClusterId, + kubeId: id, + kubeNamespaceId: name, + }); +} + +export function mapKubeNamespaceUriToRequest( + kubeNamespaceUri: KubeResourceNamespaceUri +): { + kind: 'namespace'; + /** kubeId */ + id: string; + /** kubeNamespaceId */ + name: string; +} { + const { kubeNamespaceId, kubeId } = + routing.parseKubeResourceNamespaceUri(kubeNamespaceUri).params; + return { kind: 'namespace', id: kubeId, name: kubeNamespaceId }; +} + /** * Maps the type used by the shared access requests to the type * required by the access requests service. From 24e8b68f3aa29074354e95b3cfec5938a81ea71e Mon Sep 17 00:00:00 2001 From: rosstimothy <39066650+rosstimothy@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:49:57 +0000 Subject: [PATCH 17/22] Generalize resource watchers (#47561) Consolidate resource watchers into a single watcher that leverages generics. While most of the resource watchers were similar, some resources have some one off functionality. These watchers have not been touched, however, all that could be refactored to use the generic watcher easily were. --- lib/kube/proxy/server.go | 13 +- lib/kube/proxy/utils_testing.go | 3 +- lib/kube/proxy/watcher.go | 6 +- lib/proxy/peer/client.go | 4 +- lib/proxy/router.go | 9 +- lib/proxy/router_test.go | 4 +- lib/reversetunnel/localsite.go | 23 +- lib/reversetunnel/localsite_test.go | 16 +- lib/reversetunnel/peer.go | 5 +- lib/reversetunnel/remotesite.go | 20 +- lib/reversetunnel/srv.go | 10 +- lib/reversetunnelclient/api.go | 3 +- lib/service/service.go | 1 + lib/services/readonly/readonly.go | 314 +++++ lib/services/watcher.go | 1738 ++++++++------------------- lib/services/watcher_test.go | 123 +- lib/srv/app/server.go | 3 +- lib/srv/app/watcher.go | 6 +- lib/srv/db/server.go | 3 +- lib/srv/db/watcher.go | 6 +- lib/srv/desktop/discovery.go | 5 +- lib/srv/discovery/discovery.go | 63 +- lib/srv/discovery/discovery_test.go | 7 +- lib/srv/regular/sshserver_test.go | 4 +- lib/utils/fncache.go | 2 + lib/web/apiserver.go | 10 +- lib/web/apiserver_test.go | 3 + 27 files changed, 1042 insertions(+), 1362 deletions(-) diff --git a/lib/kube/proxy/server.go b/lib/kube/proxy/server.go index 580abc957795b..8c770c16bbdb8 100644 --- a/lib/kube/proxy/server.go +++ b/lib/kube/proxy/server.go @@ -45,6 +45,7 @@ import ( "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/srv/ingress" ) @@ -98,7 +99,7 @@ type TLSServerConfig struct { // kubernetes cluster name. Proxy uses this map to route requests to the correct // kubernetes_service. The servers are kept in memory to avoid making unnecessary // unmarshal calls followed by filtering and to improve memory usage. - KubernetesServersWatcher *services.KubeServerWatcher + KubernetesServersWatcher *services.GenericWatcher[types.KubeServer, readonly.KubeServer] // PROXYProtocolMode controls behavior related to unsigned PROXY protocol headers. PROXYProtocolMode multiplexer.PROXYProtocolMode // InventoryHandle is used to send kube server heartbeats via the inventory control stream. @@ -170,7 +171,7 @@ type TLSServer struct { closeContext context.Context closeFunc context.CancelFunc // kubeClusterWatcher monitors changes to kube cluster resources. - kubeClusterWatcher *services.KubeClusterWatcher + kubeClusterWatcher *services.GenericWatcher[types.KubeCluster, readonly.KubeCluster] // reconciler reconciles proxied kube clusters with kube_clusters resources. reconciler *services.Reconciler[types.KubeCluster] // monitoredKubeClusters contains all kube clusters the proxied kube_clusters are @@ -620,7 +621,9 @@ func (t *TLSServer) getKubernetesServersForKubeClusterFunc() (getKubeServersByNa }, nil case ProxyService: return func(ctx context.Context, name string) ([]types.KubeServer, error) { - servers, err := t.KubernetesServersWatcher.GetKubeServersByClusterName(ctx, name) + servers, err := t.KubernetesServersWatcher.CurrentResourcesWithFilter(ctx, func(ks readonly.KubeServer) bool { + return ks.GetCluster().GetName() == name + }) return servers, trace.Wrap(err) }, nil case LegacyProxyService: @@ -630,7 +633,9 @@ func (t *TLSServer) getKubernetesServersForKubeClusterFunc() (getKubeServersByNa // and forward the request to the next proxy. kube, err := t.getKubeClusterWithServiceLabels(name) if err != nil { - servers, err := t.KubernetesServersWatcher.GetKubeServersByClusterName(ctx, name) + servers, err := t.KubernetesServersWatcher.CurrentResourcesWithFilter(ctx, func(ks readonly.KubeServer) bool { + return ks.GetCluster().GetName() == name + }) return servers, trace.Wrap(err) } srv, err := types.NewKubernetesServerV3FromCluster(kube, "", t.HostID) diff --git a/lib/kube/proxy/utils_testing.go b/lib/kube/proxy/utils_testing.go index 4621b7d51bec1..462638df203c4 100644 --- a/lib/kube/proxy/utils_testing.go +++ b/lib/kube/proxy/utils_testing.go @@ -294,6 +294,7 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo Component: teleport.ComponentKube, Client: client, }, + KubernetesServerGetter: client, }, ) require.NoError(t, err) @@ -387,7 +388,7 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo // Ensure watcher has the correct list of clusters. require.Eventually(t, func() bool { - kubeServers, err := kubeServersWatcher.GetKubernetesServers(ctx) + kubeServers, err := kubeServersWatcher.CurrentResources(ctx) return err == nil && len(kubeServers) == len(cfg.Clusters) }, 3*time.Second, time.Millisecond*100) diff --git a/lib/kube/proxy/watcher.go b/lib/kube/proxy/watcher.go index 047b0a4401f89..24e52e2d9c923 100644 --- a/lib/kube/proxy/watcher.go +++ b/lib/kube/proxy/watcher.go @@ -29,6 +29,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/utils" ) @@ -89,7 +90,7 @@ func (s *TLSServer) startReconciler(ctx context.Context) (err error) { // startKubeClusterResourceWatcher starts watching changes to Kube Clusters resources and // registers/unregisters the proxied Kube Cluster accordingly. -func (s *TLSServer) startKubeClusterResourceWatcher(ctx context.Context) (*services.KubeClusterWatcher, error) { +func (s *TLSServer) startKubeClusterResourceWatcher(ctx context.Context) (*services.GenericWatcher[types.KubeCluster, readonly.KubeCluster], error) { if len(s.ResourceMatchers) == 0 || s.KubeServiceType != KubeService { s.log.Debug("Not initializing Kube Cluster resource watcher.") return nil, nil @@ -102,6 +103,7 @@ func (s *TLSServer) startKubeClusterResourceWatcher(ctx context.Context) (*servi // Logger: s.log, Client: s.AccessPoint, }, + KubernetesClusterGetter: s.AccessPoint, }) if err != nil { return nil, trace.Wrap(err) @@ -110,7 +112,7 @@ func (s *TLSServer) startKubeClusterResourceWatcher(ctx context.Context) (*servi defer watcher.Close() for { select { - case clusters := <-watcher.KubeClustersC: + case clusters := <-watcher.ResourcesC: s.monitoredKubeClusters.setResources(clusters) select { case s.reconcileCh <- struct{}{}: diff --git a/lib/proxy/peer/client.go b/lib/proxy/peer/client.go index c00b67006875f..fe3659a92bf4a 100644 --- a/lib/proxy/peer/client.go +++ b/lib/proxy/peer/client.go @@ -51,6 +51,7 @@ import ( // AccessPoint is the subset of the auth cache consumed by the [Client]. type AccessPoint interface { types.Events + services.ProxyGetter } // ClientConfig configures a Client instance. @@ -416,6 +417,7 @@ func (c *Client) sync() { Client: c.config.AccessPoint, Logger: c.config.Log, }, + ProxyGetter: c.config.AccessPoint, ProxyDiffer: func(old, new types.Server) bool { return old.GetPeerAddr() != new.GetPeerAddr() }, @@ -434,7 +436,7 @@ func (c *Client) sync() { case <-proxyWatcher.Done(): c.config.Log.DebugContext(c.ctx, "stopping peer proxy sync: proxy watcher done") return - case proxies := <-proxyWatcher.ProxiesC: + case proxies := <-proxyWatcher.ResourcesC: if err := c.updateConnections(proxies); err != nil { c.config.Log.ErrorContext(c.ctx, "error syncing peer proxies", "error", err) } diff --git a/lib/proxy/router.go b/lib/proxy/router.go index 18e22adc798ee..f54f9718af604 100644 --- a/lib/proxy/router.go +++ b/lib/proxy/router.go @@ -44,6 +44,7 @@ import ( "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" ) @@ -383,7 +384,7 @@ func (r *Router) getRemoteCluster(ctx context.Context, clusterName string, check // site is the minimum interface needed to match servers // for a reversetunnelclient.RemoteSite. It makes testing easier. type site interface { - GetNodes(ctx context.Context, fn func(n services.Node) bool) ([]types.Server, error) + GetNodes(ctx context.Context, fn func(n readonly.Server) bool) ([]types.Server, error) GetClusterNetworkingConfig(ctx context.Context) (types.ClusterNetworkingConfig, error) } @@ -394,13 +395,13 @@ type remoteSite struct { } // GetNodes uses the wrapped sites NodeWatcher to filter nodes -func (r remoteSite) GetNodes(ctx context.Context, fn func(n services.Node) bool) ([]types.Server, error) { +func (r remoteSite) GetNodes(ctx context.Context, fn func(n readonly.Server) bool) ([]types.Server, error) { watcher, err := r.site.NodeWatcher() if err != nil { return nil, trace.Wrap(err) } - return watcher.GetNodes(ctx, fn), nil + return watcher.CurrentResourcesWithFilter(ctx, fn) } // GetClusterNetworkingConfig uses the wrapped sites cache to retrieve the ClusterNetworkingConfig @@ -450,7 +451,7 @@ func getServerWithResolver(ctx context.Context, host, port string, site site, re var maxScore int scores := make(map[string]int) - matches, err := site.GetNodes(ctx, func(server services.Node) bool { + matches, err := site.GetNodes(ctx, func(server readonly.Server) bool { score := routeMatcher.RouteToServerScore(server) if score < 1 { return false diff --git a/lib/proxy/router_test.go b/lib/proxy/router_test.go index 48268cf355961..177875fda2fd6 100644 --- a/lib/proxy/router_test.go +++ b/lib/proxy/router_test.go @@ -37,7 +37,7 @@ import ( "github.com/gravitational/teleport/lib/cryptosuites" "github.com/gravitational/teleport/lib/observability/tracing" "github.com/gravitational/teleport/lib/reversetunnelclient" - "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" ) @@ -51,7 +51,7 @@ func (t testSite) GetClusterNetworkingConfig(ctx context.Context) (types.Cluster return t.cfg, nil } -func (t testSite) GetNodes(ctx context.Context, fn func(n services.Node) bool) ([]types.Server, error) { +func (t testSite) GetNodes(ctx context.Context, fn func(n readonly.Server) bool) ([]types.Server, error) { var out []types.Server for _, s := range t.nodes { if fn(s) { diff --git a/lib/reversetunnel/localsite.go b/lib/reversetunnel/localsite.go index 0d992cf1f1463..7c89ea25273b0 100644 --- a/lib/reversetunnel/localsite.go +++ b/lib/reversetunnel/localsite.go @@ -44,6 +44,7 @@ import ( "github.com/gravitational/teleport/lib/reversetunnel/track" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv/forward" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" @@ -180,7 +181,7 @@ func (s *localSite) CachingAccessPoint() (authclient.RemoteProxyAccessPoint, err } // NodeWatcher returns a services.NodeWatcher for this cluster. -func (s *localSite) NodeWatcher() (*services.NodeWatcher, error) { +func (s *localSite) NodeWatcher() (*services.GenericWatcher[types.Server, readonly.Server], error) { return s.srv.NodeWatcher, nil } @@ -738,7 +739,11 @@ func (s *localSite) handleHeartbeat(rconn *remoteConn, ch ssh.Channel, reqC <-ch return case <-proxyResyncTicker.Chan(): var req discoveryRequest - req.SetProxies(s.srv.proxyWatcher.GetCurrent()) + proxies, err := s.srv.proxyWatcher.CurrentResources(s.srv.ctx) + if err != nil { + logger.WithError(err).Warn("Failed to get proxy set") + } + req.SetProxies(proxies) if err := rconn.sendDiscoveryRequest(req); err != nil { logger.WithError(err).Debug("Marking connection invalid on error") @@ -763,9 +768,12 @@ func (s *localSite) handleHeartbeat(rconn *remoteConn, ch ssh.Channel, reqC <-ch if firstHeartbeat { // as soon as the agent connects and sends a first heartbeat // send it the list of current proxies back - current := s.srv.proxyWatcher.GetCurrent() - if len(current) > 0 { - rconn.updateProxies(current) + proxies, err := s.srv.proxyWatcher.CurrentResources(s.srv.ctx) + if err != nil { + logger.WithError(err).Warn("Failed to get proxy set") + } + if len(proxies) > 0 { + rconn.updateProxies(proxies) } reverseSSHTunnels.WithLabelValues(rconn.tunnelType).Inc() firstHeartbeat = false @@ -934,7 +942,7 @@ func (s *localSite) periodicFunctions() { // sshTunnelStats reports SSH tunnel statistics for the cluster. func (s *localSite) sshTunnelStats() error { - missing := s.srv.NodeWatcher.GetNodes(s.srv.ctx, func(server services.Node) bool { + missing, err := s.srv.NodeWatcher.CurrentResourcesWithFilter(s.srv.ctx, func(server readonly.Server) bool { // Skip over any servers that have a TTL larger than announce TTL (10 // minutes) and are non-IoT SSH servers (they won't have tunnels). // @@ -966,6 +974,9 @@ func (s *localSite) sshTunnelStats() error { return err != nil }) + if err != nil { + return trace.Wrap(err) + } // Update Prometheus metrics and also log if any tunnels are missing. missingSSHTunnels.Set(float64(len(missing))) diff --git a/lib/reversetunnel/localsite_test.go b/lib/reversetunnel/localsite_test.go index 3397aed763683..195a1e76510c2 100644 --- a/lib/reversetunnel/localsite_test.go +++ b/lib/reversetunnel/localsite_test.go @@ -58,14 +58,16 @@ func TestRemoteConnCleanup(t *testing.T) { clock := clockwork.NewFakeClock() + clt := &mockLocalSiteClient{} watcher, err := services.NewProxyWatcher(ctx, services.ProxyWatcherConfig{ ResourceWatcherConfig: services.ResourceWatcherConfig{ Component: "test", Logger: utils.NewSlogLoggerForTests(), Clock: clock, - Client: &mockLocalSiteClient{}, + Client: clt, }, - ProxiesC: make(chan []types.Server, 2), + ProxyGetter: clt, + ProxiesC: make(chan []types.Server, 2), }) require.NoError(t, err) require.NoError(t, watcher.WaitInitialization()) @@ -249,17 +251,19 @@ func TestProxyResync(t *testing.T) { proxy2, err := types.NewServer(uuid.NewString(), types.KindProxy, types.ServerSpecV2{}) require.NoError(t, err) + clt := &mockLocalSiteClient{ + proxies: []types.Server{proxy1, proxy2}, + } // set up the watcher and wait for it to be initialized watcher, err := services.NewProxyWatcher(ctx, services.ProxyWatcherConfig{ ResourceWatcherConfig: services.ResourceWatcherConfig{ Component: "test", Logger: utils.NewSlogLoggerForTests(), Clock: clock, - Client: &mockLocalSiteClient{ - proxies: []types.Server{proxy1, proxy2}, - }, + Client: clt, }, - ProxiesC: make(chan []types.Server, 2), + ProxyGetter: clt, + ProxiesC: make(chan []types.Server, 2), }) require.NoError(t, err) require.NoError(t, watcher.WaitInitialization()) diff --git a/lib/reversetunnel/peer.go b/lib/reversetunnel/peer.go index fc16cbe11cefa..570be5edf4bbe 100644 --- a/lib/reversetunnel/peer.go +++ b/lib/reversetunnel/peer.go @@ -33,6 +33,7 @@ import ( "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" ) func newClusterPeers(clusterName string) *clusterPeers { @@ -90,7 +91,7 @@ func (p *clusterPeers) CachingAccessPoint() (authclient.RemoteProxyAccessPoint, return peer.CachingAccessPoint() } -func (p *clusterPeers) NodeWatcher() (*services.NodeWatcher, error) { +func (p *clusterPeers) NodeWatcher() (*services.GenericWatcher[types.Server, readonly.Server], error) { peer, err := p.pickPeer() if err != nil { return nil, trace.Wrap(err) @@ -202,7 +203,7 @@ func (s *clusterPeer) CachingAccessPoint() (authclient.RemoteProxyAccessPoint, e return nil, trace.ConnectionProblem(nil, "unable to fetch access point, this proxy %v has not been discovered yet, try again later", s) } -func (s *clusterPeer) NodeWatcher() (*services.NodeWatcher, error) { +func (s *clusterPeer) NodeWatcher() (*services.GenericWatcher[types.Server, readonly.Server], error) { return nil, trace.ConnectionProblem(nil, "unable to fetch node watcher, this proxy %v has not been discovered yet, try again later", s) } diff --git a/lib/reversetunnel/remotesite.go b/lib/reversetunnel/remotesite.go index 8e8b7e4c3fe79..f9617f33b87d5 100644 --- a/lib/reversetunnel/remotesite.go +++ b/lib/reversetunnel/remotesite.go @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv/forward" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" @@ -85,7 +86,7 @@ type remoteSite struct { remoteAccessPoint authclient.RemoteProxyAccessPoint // nodeWatcher provides access the node set for the remote site - nodeWatcher *services.NodeWatcher + nodeWatcher *services.GenericWatcher[types.Server, readonly.Server] // remoteCA is the last remote certificate authority recorded by the client. // It is used to detect CA rotation status changes. If the rotation @@ -164,7 +165,7 @@ func (s *remoteSite) CachingAccessPoint() (authclient.RemoteProxyAccessPoint, er } // NodeWatcher returns the services.NodeWatcher for the remote cluster. -func (s *remoteSite) NodeWatcher() (*services.NodeWatcher, error) { +func (s *remoteSite) NodeWatcher() (*services.GenericWatcher[types.Server, readonly.Server], error) { return s.nodeWatcher, nil } @@ -429,7 +430,11 @@ func (s *remoteSite) handleHeartbeat(conn *remoteConn, ch ssh.Channel, reqC <-ch return case <-proxyResyncTicker.Chan(): var req discoveryRequest - req.SetProxies(s.srv.proxyWatcher.GetCurrent()) + proxies, err := s.srv.proxyWatcher.CurrentResources(s.srv.ctx) + if err != nil { + logger.WithError(err).Warn("Failed to get proxy set") + } + req.SetProxies(proxies) if err := conn.sendDiscoveryRequest(req); err != nil { logger.WithError(err).Debug("Marking connection invalid on error") @@ -458,9 +463,12 @@ func (s *remoteSite) handleHeartbeat(conn *remoteConn, ch ssh.Channel, reqC <-ch if firstHeartbeat { // as soon as the agent connects and sends a first heartbeat // send it the list of current proxies back - current := s.srv.proxyWatcher.GetCurrent() - if len(current) > 0 { - conn.updateProxies(current) + proxies, err := s.srv.proxyWatcher.CurrentResources(s.srv.ctx) + if err != nil { + logger.WithError(err).Warn("Failed to get proxy set") + } + if len(proxies) > 0 { + conn.updateProxies(proxies) } firstHeartbeat = false } diff --git a/lib/reversetunnel/srv.go b/lib/reversetunnel/srv.go index 19dfd9e2d43ca..4cf45cf81a15f 100644 --- a/lib/reversetunnel/srv.go +++ b/lib/reversetunnel/srv.go @@ -49,6 +49,7 @@ import ( "github.com/gravitational/teleport/lib/proxy/peer" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv/ingress" "github.com/gravitational/teleport/lib/sshca" "github.com/gravitational/teleport/lib/sshutils" @@ -114,7 +115,7 @@ type server struct { // proxyWatcher monitors changes to the proxies // and broadcasts updates - proxyWatcher *services.ProxyWatcher + proxyWatcher *services.GenericWatcher[types.Server, readonly.Server] // offlineThreshold is how long to wait for a keep alive message before // marking a reverse tunnel connection as invalid. @@ -201,7 +202,7 @@ type Config struct { LockWatcher *services.LockWatcher // NodeWatcher is a node watcher. - NodeWatcher *services.NodeWatcher + NodeWatcher *services.GenericWatcher[types.Server, readonly.Server] // CertAuthorityWatcher is a cert authority watcher. CertAuthorityWatcher *services.CertAuthorityWatcher @@ -307,9 +308,6 @@ func NewServer(cfg Config) (reversetunnelclient.Server, error) { }, ProxiesC: make(chan []types.Server, 10), ProxyGetter: cfg.LocalAccessPoint, - ProxyDiffer: func(_, _ types.Server) bool { - return true // we always want to store the most recently heartbeated proxy - }, }) if err != nil { cancel() @@ -401,7 +399,7 @@ func (s *server) periodicFunctions() { s.log.Debugf("Closing.") return // Proxies have been updated, notify connected agents about the update. - case proxies := <-s.proxyWatcher.ProxiesC: + case proxies := <-s.proxyWatcher.ResourcesC: s.fanOutProxies(proxies) case <-ticker.C: if err := s.fetchClusterPeers(); err != nil { diff --git a/lib/reversetunnelclient/api.go b/lib/reversetunnelclient/api.go index f7e8dfb47ef63..e044bf4beb012 100644 --- a/lib/reversetunnelclient/api.go +++ b/lib/reversetunnelclient/api.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/proxy/peer" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/teleagent" ) @@ -123,7 +124,7 @@ type RemoteSite interface { // but is resilient to auth server crashes CachingAccessPoint() (authclient.RemoteProxyAccessPoint, error) // NodeWatcher returns the node watcher that maintains the node set for the site - NodeWatcher() (*services.NodeWatcher, error) + NodeWatcher() (*services.GenericWatcher[types.Server, readonly.Server], error) // GetTunnelsCount returns the amount of active inbound tunnels // from the remote cluster GetTunnelsCount() int diff --git a/lib/service/service.go b/lib/service/service.go index c171bb74ca301..215fdb0035f00 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -5026,6 +5026,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { Logger: process.logger.With(teleport.ComponentKey, teleport.Component(teleport.ComponentReverseTunnelServer, process.id)), Client: accessPoint, }, + KubernetesServerGetter: accessPoint, }) if err != nil { return trace.Wrap(err) diff --git a/lib/services/readonly/readonly.go b/lib/services/readonly/readonly.go index db65197a4338a..c4ed3185ace66 100644 --- a/lib/services/readonly/readonly.go +++ b/lib/services/readonly/readonly.go @@ -137,3 +137,317 @@ func (a sealedAccessGraphSettings) SecretsScanConfig() clusterconfigpb.AccessGra func (a sealedAccessGraphSettings) Clone() *clusterconfigpb.AccessGraphSettings { return protobuf.Clone(a.AccessGraphSettings).(*clusterconfigpb.AccessGraphSettings) } + +// Resource is a read only variant of [types.Resource]. +type Resource interface { + // GetKind returns resource kind + GetKind() string + // GetSubKind returns resource subkind + GetSubKind() string + // GetVersion returns resource version + GetVersion() string + // GetName returns the name of the resource + GetName() string + // Expiry returns object expiry setting + Expiry() time.Time + // GetMetadata returns object metadata + GetMetadata() types.Metadata + // GetRevision returns the revision + GetRevision() string +} + +// ResourceWithOrigin is a read only variant of [types.ResourceWithOrigin]. +type ResourceWithOrigin interface { + Resource + // Origin returns the origin value of the resource. + Origin() string +} + +// ResourceWithLabels is a read only variant of [types.ResourceWithLabels]. +type ResourceWithLabels interface { + ResourceWithOrigin + // GetLabel retrieves the label with the provided key. + GetLabel(key string) (value string, ok bool) + // GetAllLabels returns all resource's labels. + GetAllLabels() map[string]string + // GetStaticLabels returns the resource's static labels. + GetStaticLabels() map[string]string + // MatchSearch goes through select field values of a resource + // and tries to match against the list of search values. + MatchSearch(searchValues []string) bool +} + +// Application is a read only variant of [types.Application]. +type Application interface { + // ResourceWithLabels provides common resource methods. + ResourceWithLabels + // GetNamespace returns the app namespace. + GetNamespace() string + // GetStaticLabels returns the app static labels. + GetStaticLabels() map[string]string + // GetDynamicLabels returns the app dynamic labels. + GetDynamicLabels() map[string]types.CommandLabel + // String returns string representation of the app. + String() string + // GetDescription returns the app description. + GetDescription() string + // GetURI returns the app connection endpoint. + GetURI() string + // GetPublicAddr returns the app public address. + GetPublicAddr() string + // GetInsecureSkipVerify returns the app insecure setting. + GetInsecureSkipVerify() bool + // GetRewrite returns the app rewrite configuration. + GetRewrite() *types.Rewrite + // IsAWSConsole returns true if this app is AWS management console. + IsAWSConsole() bool + // IsAzureCloud returns true if this app represents Azure Cloud instance. + IsAzureCloud() bool + // IsGCP returns true if this app represents GCP instance. + IsGCP() bool + // IsTCP returns true if this app represents a TCP endpoint. + IsTCP() bool + // GetProtocol returns the application protocol. + GetProtocol() string + // GetAWSAccountID returns value of label containing AWS account ID on this app. + GetAWSAccountID() string + // GetAWSExternalID returns the AWS External ID configured for this app. + GetAWSExternalID() string + // GetUserGroups will get the list of user group IDs associated with the application. + GetUserGroups() []string + // Copy returns a copy of this app resource. + Copy() *types.AppV3 + // GetIntegration will return the Integration. + // If present, the Application must use the Integration's credentials instead of ambient credentials to access Cloud APIs. + GetIntegration() string + // GetRequiredAppNames will return a list of required apps names that should be authenticated during this apps authentication process. + GetRequiredAppNames() []string + // GetCORS returns the CORS configuration for the app. + GetCORS() *types.CORSPolicy +} + +// KubeServer is a read only variant of [types.KubeServer]. +type KubeServer interface { + // ResourceWithLabels provides common resource methods. + ResourceWithLabels + // GetNamespace returns server namespace. + GetNamespace() string + // GetTeleportVersion returns the teleport version the server is running on. + GetTeleportVersion() string + // GetHostname returns the server hostname. + GetHostname() string + // GetHostID returns ID of the host the server is running on. + GetHostID() string + // GetRotation gets the state of certificate authority rotation. + GetRotation() types.Rotation + // String returns string representation of the server. + String() string + // Copy returns a copy of this kube server object. + Copy() types.KubeServer + // CloneResource returns a copy of the KubeServer as a ResourceWithLabels + CloneResource() types.ResourceWithLabels + // GetCluster returns the Kubernetes Cluster this kube server proxies. + GetCluster() types.KubeCluster + // GetProxyIDs returns a list of proxy ids this service is connected to. + GetProxyIDs() []string +} + +// KubeCluster is a read only variant of [types.KubeCluster]. +type KubeCluster interface { + // ResourceWithLabels provides common resource methods. + ResourceWithLabels + // GetNamespace returns the kube cluster namespace. + GetNamespace() string + // GetStaticLabels returns the kube cluster static labels. + GetStaticLabels() map[string]string + // GetDynamicLabels returns the kube cluster dynamic labels. + GetDynamicLabels() map[string]types.CommandLabel + // GetKubeconfig returns the kubeconfig payload. + GetKubeconfig() []byte + // String returns string representation of the kube cluster. + String() string + // GetDescription returns the kube cluster description. + GetDescription() string + // GetAzureConfig gets the Azure config. + GetAzureConfig() types.KubeAzure + // GetAWSConfig gets the AWS config. + GetAWSConfig() types.KubeAWS + // GetGCPConfig gets the GCP config. + GetGCPConfig() types.KubeGCP + // IsAzure indentifies if the KubeCluster contains Azure details. + IsAzure() bool + // IsAWS indentifies if the KubeCluster contains AWS details. + IsAWS() bool + // IsGCP indentifies if the KubeCluster contains GCP details. + IsGCP() bool + // IsKubeconfig identifies if the KubeCluster contains kubeconfig data. + IsKubeconfig() bool + // Copy returns a copy of this kube cluster resource. + Copy() *types.KubernetesClusterV3 + // GetCloud gets the cloud this kube cluster is running on, or an empty string if it + // isn't running on a cloud provider. + GetCloud() string +} + +// Database is a read only variant of [types.Database]. +type Database interface { + // ResourceWithLabels provides common resource methods. + ResourceWithLabels + // GetNamespace returns the database namespace. + GetNamespace() string + // GetStaticLabels returns the database static labels. + GetStaticLabels() map[string]string + // GetDynamicLabels returns the database dynamic labels. + GetDynamicLabels() map[string]types.CommandLabel + // String returns string representation of the database. + String() string + // GetDescription returns the database description. + GetDescription() string + // GetProtocol returns the database protocol. + GetProtocol() string + // GetURI returns the database connection endpoint. + GetURI() string + // GetCA returns the database CA certificate. + GetCA() string + // GetTLS returns the database TLS configuration. + GetTLS() types.DatabaseTLS + // GetStatusCA gets the database CA certificate in the status field. + GetStatusCA() string + // GetMySQL returns the database options from spec. + GetMySQL() types.MySQLOptions + // GetOracle returns the database options from spec. + GetOracle() types.OracleOptions + // GetMySQLServerVersion returns the MySQL server version either from configuration or + // reported by the database. + GetMySQLServerVersion() string + // GetAWS returns the database AWS metadata. + GetAWS() types.AWS + // GetGCP returns GCP information for Cloud SQL databases. + GetGCP() types.GCPCloudSQL + // GetAzure returns Azure database server metadata. + GetAzure() types.Azure + // GetAD returns Active Directory database configuration. + GetAD() types.AD + // GetType returns the database authentication type: self-hosted, RDS, Redshift or Cloud SQL. + GetType() string + // GetSecretStore returns secret store configurations. + GetSecretStore() types.SecretStore + // GetManagedUsers returns a list of database users that are managed by Teleport. + GetManagedUsers() []string + // GetMongoAtlas returns Mongo Atlas database metadata. + GetMongoAtlas() types.MongoAtlas + // IsRDS returns true if this is an RDS/Aurora database. + IsRDS() bool + // IsRDSProxy returns true if this is an RDS Proxy database. + IsRDSProxy() bool + // IsRedshift returns true if this is a Redshift database. + IsRedshift() bool + // IsCloudSQL returns true if this is a Cloud SQL database. + IsCloudSQL() bool + // IsAzure returns true if this is an Azure database. + IsAzure() bool + // IsElastiCache returns true if this is an AWS ElastiCache database. + IsElastiCache() bool + // IsMemoryDB returns true if this is an AWS MemoryDB database. + IsMemoryDB() bool + // IsAWSHosted returns true if database is hosted by AWS. + IsAWSHosted() bool + // IsCloudHosted returns true if database is hosted in the cloud (AWS, Azure or Cloud SQL). + IsCloudHosted() bool + // RequireAWSIAMRolesAsUsers returns true for database types that require + // AWS IAM roles as database users. + RequireAWSIAMRolesAsUsers() bool + // SupportAWSIAMRoleARNAsUsers returns true for database types that support + // AWS IAM roles as database users. + SupportAWSIAMRoleARNAsUsers() bool + // Copy returns a copy of this database resource. + Copy() *types.DatabaseV3 + // GetAdminUser returns database privileged user information. + GetAdminUser() types.DatabaseAdminUser + // SupportsAutoUsers returns true if this database supports automatic + // user provisioning. + SupportsAutoUsers() bool + // GetEndpointType returns the endpoint type of the database, if available. + GetEndpointType() string + // GetCloud gets the cloud this database is running on, or an empty string if it + // isn't running on a cloud provider. + GetCloud() string + // IsUsernameCaseInsensitive returns true if the database username is case + // insensitive. + IsUsernameCaseInsensitive() bool +} + +// Server is a read only variant of [types.Server]. +type Server interface { + // ResourceWithLabels provides common resource headers + ResourceWithLabels + // GetTeleportVersion returns the teleport version the server is running on + GetTeleportVersion() string + // GetAddr return server address + GetAddr() string + // GetHostname returns server hostname + GetHostname() string + // GetNamespace returns server namespace + GetNamespace() string + // GetLabels returns server's static label key pairs + GetLabels() map[string]string + // GetCmdLabels gets command labels + GetCmdLabels() map[string]types.CommandLabel + // GetPublicAddr returns a public address where this server can be reached. + GetPublicAddr() string + // GetPublicAddrs returns a list of public addresses where this server can be reached. + GetPublicAddrs() []string + // GetRotation gets the state of certificate authority rotation. + GetRotation() types.Rotation + // GetUseTunnel gets if a reverse tunnel should be used to connect to this node. + GetUseTunnel() bool + // String returns string representation of the server + String() string + // GetPeerAddr returns the peer address of the server. + GetPeerAddr() string + // GetProxyIDs returns a list of proxy ids this service is connected to. + GetProxyIDs() []string + // DeepCopy creates a clone of this server value + DeepCopy() types.Server + + // CloneResource is used to return a clone of the Server and match the CloneAny interface + // This is helpful when interfacing with multiple types at the same time in unified resources + CloneResource() types.ResourceWithLabels + + // GetCloudMetadata gets the cloud metadata for the server. + GetCloudMetadata() *types.CloudMetadata + // GetAWSInfo returns the AWSInfo for the server. + GetAWSInfo() *types.AWSInfo + + // IsOpenSSHNode returns whether the connection to this Server must use OpenSSH. + // This returns true for SubKindOpenSSHNode and SubKindOpenSSHEICENode. + IsOpenSSHNode() bool + + // IsEICE returns whether the Node is an EICE instance. + // Must be `openssh-ec2-ice` subkind and have the AccountID and InstanceID information (AWS Metadata or Labels). + IsEICE() bool + + // GetAWSInstanceID returns the AWS Instance ID if this node comes from an EC2 instance. + GetAWSInstanceID() string + // GetAWSAccountID returns the AWS Account ID if this node comes from an EC2 instance. + GetAWSAccountID() string +} + +// DynamicWindowsDesktop represents a Windows desktop host that is automatically discovered by Windows Desktop Service. +type DynamicWindowsDesktop interface { + // ResourceWithLabels provides common resource methods. + ResourceWithLabels + // GetAddr returns the network address of this host. + GetAddr() string + // GetDomain returns the ActiveDirectory domain of this host. + GetDomain() string + // NonAD checks whether this is a standalone host that + // is not joined to an Active Directory domain. + NonAD() bool + // GetScreenSize returns the desired size of the screen to use for sessions + // to this host. Returns (0, 0) if no screen size is set, which means to + // use the size passed by the client over TDP. + GetScreenSize() (width, height uint32) + // Copy returns a copy of this dynamic Windows desktop + Copy() *types.DynamicWindowsDesktopV1 +} diff --git a/lib/services/watcher.go b/lib/services/watcher.go index 93daf0aee5cd6..7699f5459b070 100644 --- a/lib/services/watcher.go +++ b/lib/services/watcher.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/lib/defaults" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/utils" logutils "github.com/gravitational/teleport/lib/utils/log" ) @@ -87,21 +88,21 @@ func watchKindsString(kinds []types.WatchKind) string { // ResourceWatcherConfig configures resource watcher. type ResourceWatcherConfig struct { - // Component is a component used in logs. - Component string + // Clock is used to control time. + Clock clockwork.Clock + // Client is used to create new watchers + Client types.Events // Logger emits log messages. Logger *slog.Logger + // ResetC is a channel to notify of internal watcher reset (used in tests). + ResetC chan time.Duration + // Component is a component used in logs. + Component string // MaxRetryPeriod is the maximum retry period on failed watchers. MaxRetryPeriod time.Duration - // Clock is used to control time. - Clock clockwork.Clock - // Client is used to create new watchers. - Client types.Events // MaxStaleness is a maximum acceptable staleness for the locally maintained // resources, zero implies no staleness detection. MaxStaleness time.Duration - // ResetC is a channel to notify of internal watcher reset (used in tests). - ResetC chan time.Duration // QueueSize is an optional queue size QueueSize int } @@ -165,28 +166,23 @@ func newResourceWatcher(ctx context.Context, collector resourceCollector, cfg Re // resourceWatcher monitors additions, updates and deletions // to a set of resources. type resourceWatcher struct { - ResourceWatcherConfig - collector resourceCollector - - // ctx is a context controlling the lifetime of this resourceWatcher - // instance. - ctx context.Context - cancel context.CancelFunc - - // retry is used to manage backoff logic for watchers. - retry retryutils.Retry - // failureStartedAt records when the current sync failures were first // detected, zero if there are no failures present. failureStartedAt time.Time - + collector resourceCollector + // ctx is a context controlling the lifetime of this resourceWatcher + // instance. + ctx context.Context + // retry is used to manage backoff logic for watchers. + retry retryutils.Retry + cancel context.CancelFunc // LoopC is a channel to check whether the watch loop is running // (used in tests). LoopC chan struct{} - // StaleC is a channel that can trigger the condition of resource staleness // (used in tests). StaleC chan struct{} + ResourceWatcherConfig } // Done returns a channel that signals resource watcher closure. @@ -380,195 +376,523 @@ func (p *resourceWatcher) watch() error { // ProxyWatcherConfig is a ProxyWatcher configuration. type ProxyWatcherConfig struct { - ResourceWatcherConfig // ProxyGetter is used to directly fetch the list of active proxies. ProxyGetter // ProxyDiffer is used to decide whether a put operation on an existing proxy should // trigger a event. ProxyDiffer func(old, new types.Server) bool // ProxiesC is a channel used to report the current proxy set. It receives - // a fresh list at startup and subsequently a list of all known proxies + // a fresh list at startup and subsequently a list of all known proxy // whenever an addition or deletion is detected. ProxiesC chan []types.Server + ResourceWatcherConfig +} + +// NewProxyWatcher returns a new instance of GenericWatcher that is configured +// to watch for changes. +func NewProxyWatcher(ctx context.Context, cfg ProxyWatcherConfig) (*GenericWatcher[types.Server, readonly.Server], error) { + if cfg.ProxyGetter == nil { + return nil, trace.BadParameter("ProxyGetter must be provided") + } + + if cfg.ProxyDiffer == nil { + cfg.ProxyDiffer = func(old, new types.Server) bool { return true } + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.Server, readonly.Server]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindProxy, + ResourceKey: types.Server.GetName, + ResourceGetter: func(ctx context.Context) ([]types.Server, error) { + return cfg.ProxyGetter.GetProxies() + }, + ResourcesC: cfg.ProxiesC, + ResourceDiffer: cfg.ProxyDiffer, + RequireResourcesForInitialBroadcast: true, + CloneFunc: types.Server.DeepCopy, + }) + return w, trace.Wrap(err) +} + +// DatabaseWatcherConfig is a DatabaseWatcher configuration. +type DatabaseWatcherConfig struct { + // DatabaseGetter is responsible for fetching database resources. + DatabaseGetter + // DatabasesC receives up-to-date list of all database resources. + DatabasesC chan []types.Database + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig +} + +// NewDatabaseWatcher returns a new instance of DatabaseWatcher. +func NewDatabaseWatcher(ctx context.Context, cfg DatabaseWatcherConfig) (*GenericWatcher[types.Database, readonly.Database], error) { + if cfg.DatabaseGetter == nil { + return nil, trace.BadParameter("DatabaseGetter must be provided") + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.Database, readonly.Database]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindDatabase, + ResourceKey: types.Database.GetName, + ResourceGetter: func(ctx context.Context) ([]types.Database, error) { + return cfg.DatabaseGetter.GetDatabases(ctx) + }, + ResourcesC: cfg.DatabasesC, + CloneFunc: func(resource types.Database) types.Database { + return resource.Copy() + }, + }) + return w, trace.Wrap(err) +} + +// AppWatcherConfig is an AppWatcher configuration. +type AppWatcherConfig struct { + // AppGetter is responsible for fetching application resources. + AppGetter + // AppsC receives up-to-date list of all application resources. + AppsC chan []types.Application + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig +} + +// NewAppWatcher returns a new instance of AppWatcher. +func NewAppWatcher(ctx context.Context, cfg AppWatcherConfig) (*GenericWatcher[types.Application, readonly.Application], error) { + if cfg.AppGetter == nil { + return nil, trace.BadParameter("AppGetter must be provided") + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.Application, readonly.Application]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindApp, + ResourceKey: types.Application.GetName, + ResourceGetter: func(ctx context.Context) ([]types.Application, error) { + return cfg.AppGetter.GetApps(ctx) + }, + ResourcesC: cfg.AppsC, + CloneFunc: func(resource types.Application) types.Application { + return resource.Copy() + }, + }) + + return w, trace.Wrap(err) +} + +// KubeServerWatcherConfig is an KubeServerWatcher configuration. +type KubeServerWatcherConfig struct { + // KubernetesServerGetter is responsible for fetching kube_server resources. + KubernetesServerGetter + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig +} + +// NewKubeServerWatcher returns a new instance of KubeServerWatcher. +func NewKubeServerWatcher(ctx context.Context, cfg KubeServerWatcherConfig) (*GenericWatcher[types.KubeServer, readonly.KubeServer], error) { + if cfg.KubernetesServerGetter == nil { + return nil, trace.BadParameter("KubernetesServerGetter must be provided") + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.KubeServer, readonly.KubeServer]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindKubeServer, + ResourceGetter: func(ctx context.Context) ([]types.KubeServer, error) { + return cfg.KubernetesServerGetter.GetKubernetesServers(ctx) + }, + ResourceKey: func(resource types.KubeServer) string { + return resource.GetHostID() + resource.GetName() + }, + DisableUpdateBroadcast: true, + CloneFunc: types.KubeServer.Copy, + }) + return w, trace.Wrap(err) +} + +// KubeClusterWatcherConfig is an KubeClusterWatcher configuration. +type KubeClusterWatcherConfig struct { + // KubernetesGetter is responsible for fetching kube_cluster resources. + KubernetesClusterGetter + // KubeClustersC receives up-to-date list of all kube_cluster resources. + KubeClustersC chan []types.KubeCluster + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig +} + +// NewKubeClusterWatcher returns a new instance of KubeClusterWatcher. +func NewKubeClusterWatcher(ctx context.Context, cfg KubeClusterWatcherConfig) (*GenericWatcher[types.KubeCluster, readonly.KubeCluster], error) { + if cfg.KubernetesClusterGetter == nil { + return nil, trace.BadParameter("KubernetesClusterGetter must be provided") + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.KubeCluster, readonly.KubeCluster]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindKubernetesCluster, + ResourceGetter: func(ctx context.Context) ([]types.KubeCluster, error) { + return cfg.KubernetesClusterGetter.GetKubernetesClusters(ctx) + }, + ResourceKey: types.KubeCluster.GetName, + ResourcesC: cfg.KubeClustersC, + CloneFunc: func(resource types.KubeCluster) types.KubeCluster { + return resource.Copy() + }, + }) + return w, trace.Wrap(err) +} + +type DynamicWindowsDesktopGetter interface { + ListDynamicWindowsDesktops(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error) +} + +// DynamicWindowsDesktopWatcherConfig is a DynamicWindowsDesktopWatcher configuration. +type DynamicWindowsDesktopWatcherConfig struct { + // DynamicWindowsDesktopGetter is responsible for fetching DynamicWindowsDesktop resources. + DynamicWindowsDesktopGetter + // DynamicWindowsDesktopsC receives up-to-date list of all DynamicWindowsDesktop resources. + DynamicWindowsDesktopsC chan []types.DynamicWindowsDesktop + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig +} + +// NewDynamicWindowsDesktopWatcher returns a new instance of DynamicWindowsDesktopWatcher. +func NewDynamicWindowsDesktopWatcher(ctx context.Context, cfg DynamicWindowsDesktopWatcherConfig) (*GenericWatcher[types.DynamicWindowsDesktop, readonly.DynamicWindowsDesktop], error) { + if cfg.DynamicWindowsDesktopGetter == nil { + return nil, trace.BadParameter("KubernetesClusterGetter must be provided") + } + + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.DynamicWindowsDesktop, readonly.DynamicWindowsDesktop]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindDynamicWindowsDesktop, + ResourceGetter: func(ctx context.Context) ([]types.DynamicWindowsDesktop, error) { + var desktops []types.DynamicWindowsDesktop + next := "" + for { + d, token, err := cfg.DynamicWindowsDesktopGetter.ListDynamicWindowsDesktops(ctx, defaults.MaxIterationLimit, next) + if err != nil { + return nil, err + } + desktops = append(desktops, d...) + if token == "" { + break + } + next = token + } + return desktops, nil + }, + ResourceKey: types.DynamicWindowsDesktop.GetName, + ResourcesC: cfg.DynamicWindowsDesktopsC, + CloneFunc: func(resource types.DynamicWindowsDesktop) types.DynamicWindowsDesktop { + return resource.Copy() + }, + }) + return w, trace.Wrap(err) +} + +// GenericWatcherConfig is a generic resource watcher configuration. +type GenericWatcherConfig[T any, R any] struct { + // ResourceGetter is used to directly fetch the current set of resources. + ResourceGetter func(context.Context) ([]T, error) + // ResourceDiffer is used to decide whether a put operation on an existing ResourceGetter should + // trigger an event. + ResourceDiffer func(old, new T) bool + // ResourceKey defines how the resources should be keyed. + ResourceKey func(resource T) string + // ResourcesC is a channel used to report the current resourxe set. It receives + // a fresh list at startup and subsequently a list of all known resourxes + // whenever an addition or deletion is detected. + ResourcesC chan []T + // CloneFunc defines how a resource is cloned. All resources provided via + // the broadcast mechanism, or retrieved via [GenericWatcer.CurrentResources] + // or [GenericWatcher.CurrentResourcesWithFilter] will be cloned by this + // mechanism before being provided to callers. + CloneFunc func(resource T) T + ResourceWatcherConfig + // ResourceKind specifies the kind of resource the watcher is monitoring. + ResourceKind string + // RequireResourcesForInitialBroadcast indicates whether an update should be + // performed if the initial set of resources is empty. + RequireResourcesForInitialBroadcast bool + // DisableUpdateBroadcast turns off emitting updates on changes. When this + // mode is opted into, users must invoke [GenericWatcher.CurrentResources] or + // [GenericWatcher.CurrentResourcesWithFilter] manually to retrieve the active + // resource set. + DisableUpdateBroadcast bool } // CheckAndSetDefaults checks parameters and sets default values. -func (cfg *ProxyWatcherConfig) CheckAndSetDefaults() error { +func (cfg *GenericWatcherConfig[T, R]) CheckAndSetDefaults() error { if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if cfg.ProxyGetter == nil { - getter, ok := cfg.Client.(ProxyGetter) - if !ok { - return trace.BadParameter("missing parameter ProxyGetter and Client not usable as ProxyGetter") - } - cfg.ProxyGetter = getter + + if cfg.ResourceGetter == nil { + return trace.BadParameter("ResourceGetter not provided to generic resource watcher") + } + + if cfg.ResourceKind == "" { + return trace.BadParameter("ResourceKind not provided to generic resource watcher") + } + + if cfg.ResourceKey == nil { + return trace.BadParameter("ResourceKey not provided to generic resource watcher") + } + + if cfg.ResourceDiffer == nil { + cfg.ResourceDiffer = func(T, T) bool { return true } } - if cfg.ProxiesC == nil { - cfg.ProxiesC = make(chan []types.Server) + + if cfg.ResourcesC == nil { + cfg.ResourcesC = make(chan []T) } return nil } -// NewProxyWatcher returns a new instance of ProxyWatcher. -func NewProxyWatcher(ctx context.Context, cfg ProxyWatcherConfig) (*ProxyWatcher, error) { +// NewGenericResourceWatcher returns a new instance of resource watcher. +func NewGenericResourceWatcher[T any, R any](ctx context.Context, cfg GenericWatcherConfig[T, R]) (*GenericWatcher[T, R], error) { if err := cfg.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - collector := &proxyCollector{ - ProxyWatcherConfig: cfg, - initializationC: make(chan struct{}), + + cache, err := utils.NewFnCache(utils.FnCacheConfig{ + Context: ctx, + TTL: 3 * time.Second, + Clock: cfg.Clock, + }) + if err != nil { + return nil, trace.Wrap(err) + } + + collector := &genericCollector[T, R]{ + GenericWatcherConfig: cfg, + initializationC: make(chan struct{}), + cache: cache, } + collector.stale.Store(true) watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) if err != nil { return nil, trace.Wrap(err) } - return &ProxyWatcher{watcher, collector}, nil + return &GenericWatcher[T, R]{watcher, collector}, nil } -// ProxyWatcher is built on top of resourceWatcher to monitor additions -// and deletions to the set of proxies. -type ProxyWatcher struct { +// GenericWatcher is built on top of resourceWatcher to monitor additions +// and deletions to the set of resources. +type GenericWatcher[T any, R any] struct { *resourceWatcher - *proxyCollector + *genericCollector[T, R] +} + +// ResourceCount returns the current number of resources known to the watcher. +func (g *GenericWatcher[T, R]) ResourceCount() int { + g.rw.RLock() + defer g.rw.RUnlock() + return len(g.current) +} + +// CurrentResources returns a copy of the resources known to the watcher. +func (g *GenericWatcher[T, R]) CurrentResources(ctx context.Context) ([]T, error) { + if err := g.refreshStaleResources(ctx); err != nil { + return nil, trace.Wrap(err) + } + + g.rw.RLock() + defer g.rw.RUnlock() + + return resourcesToSlice(g.current, g.CloneFunc), nil +} + +// CurrentResourcesWithFilter returns a copy of the resources known to the watcher +// that match the provided filter. +func (g *GenericWatcher[T, R]) CurrentResourcesWithFilter(ctx context.Context, filter func(R) bool) ([]T, error) { + if err := g.refreshStaleResources(ctx); err != nil { + return nil, trace.Wrap(err) + } + + g.rw.RLock() + defer g.rw.RUnlock() + + r := func(a any) R { + return a.(R) + } + + var out []T + for _, resource := range g.current { + if filter(r(resource)) { + out = append(out, g.CloneFunc(resource)) + } + } + + return out, nil } -// proxyCollector accompanies resourceWatcher when monitoring proxies. -type proxyCollector struct { - ProxyWatcherConfig - // current holds a map of the currently known proxies (keyed by server name, +// genericCollector accompanies resourceWatcher when monitoring proxies. +type genericCollector[T any, R any] struct { + GenericWatcherConfig[T, R] + // current holds a map of the currently known resources (keyed by server name, // RWMutex protected). - current map[string]types.Server - rw sync.RWMutex + current map[string]T initializationC chan struct{} - once sync.Once + // cache is a helper for temporarily storing the results of CurrentResources. + // It's used to limit the number of calls to the backend. + cache *utils.FnCache + rw sync.RWMutex + once sync.Once + // stale is used to indicate that the watcher is stale and needs to be + // refreshed. + stale atomic.Bool } -// GetCurrent returns the currently stored proxies. -func (p *proxyCollector) GetCurrent() []types.Server { - p.rw.RLock() - defer p.rw.RUnlock() - return serverMapValues(p.current) +// resourceKinds specifies the resource kind to watch. +func (g *genericCollector[T, R]) resourceKinds() []types.WatchKind { + return []types.WatchKind{{Kind: g.ResourceKind}} } -// resourceKinds specifies the resource kind to watch. -func (p *proxyCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindProxy}} +// getResources gets the list of current resources. +func (g *genericCollector[T, R]) getResources(ctx context.Context) (map[string]T, error) { + resources, err := g.GenericWatcherConfig.ResourceGetter(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + current := make(map[string]T, len(resources)) + for _, resource := range resources { + current[g.GenericWatcherConfig.ResourceKey(resource)] = resource + } + return current, nil +} + +func (g *genericCollector[T, R]) refreshStaleResources(ctx context.Context) error { + if !g.stale.Load() { + return nil + } + + _, err := utils.FnCacheGet(ctx, g.cache, g.GenericWatcherConfig.ResourceKind, func(ctx context.Context) (any, error) { + current, err := g.getResources(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + // There is a chance that the watcher reinitialized while + // getting resources happened above. Check if we are still stale + if g.stale.CompareAndSwap(true, false) { + g.rw.Lock() + g.current = current + g.rw.Unlock() + } + + return nil, nil + }) + + return trace.Wrap(err) } // getResourcesAndUpdateCurrent is called when the resources should be // (re-)fetched directly. -func (p *proxyCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - proxies, err := p.ProxyGetter.GetProxies() +func (g *genericCollector[T, R]) getResourcesAndUpdateCurrent(ctx context.Context) error { + newCurrent, err := g.getResources(ctx) if err != nil { return trace.Wrap(err) } - newCurrent := make(map[string]types.Server, len(proxies)) - for _, proxy := range proxies { - newCurrent[proxy.GetName()] = proxy - } - p.rw.Lock() - defer p.rw.Unlock() - p.current = newCurrent - // only emit an empty proxy list if the collector has already been initialized - // to prevent an empty slice being sent out on creation of the watcher - if len(proxies) > 0 || (len(proxies) == 0 && p.isInitialized()) { - p.broadcastUpdate(ctx) + g.rw.Lock() + defer g.rw.Unlock() + g.current = newCurrent + g.stale.Store(false) + // Only emit an empty set of resources if the watcher is already initialized, + // or if explicitly opted into by for the watcher. + if len(newCurrent) > 0 || g.isInitialized() || + (!g.RequireResourcesForInitialBroadcast && len(newCurrent) == 0) { + g.broadcastUpdate(ctx) } - p.defineCollectorAsInitialized() + g.defineCollectorAsInitialized() return nil } -func (p *proxyCollector) defineCollectorAsInitialized() { - p.once.Do(func() { +func (g *genericCollector[T, R]) defineCollectorAsInitialized() { + g.once.Do(func() { // mark watcher as initialized. - close(p.initializationC) + close(g.initializationC) }) } // processEventsAndUpdateCurrent is called when a watcher event is received. -func (p *proxyCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - p.rw.Lock() - defer p.rw.Unlock() +func (g *genericCollector[T, R]) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { + g.rw.Lock() + defer g.rw.Unlock() var updated bool for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindProxy { - p.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) + if event.Resource == nil || event.Resource.GetKind() != g.ResourceKind { + g.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) continue } switch event.Type { case types.OpDelete: - delete(p.current, event.Resource.GetName()) - // Always broadcast when a proxy is deleted. + // On delete events, the server description is populated with the host ID. + delete(g.current, event.Resource.GetMetadata().Description+event.Resource.GetName()) + // Always broadcast when a resource is deleted. updated = true case types.OpPut: - server, ok := event.Resource.(types.Server) + resource, ok := event.Resource.(T) if !ok { - p.Logger.WarnContext(ctx, "Received unexpected type", "resource", event.Resource.GetKind()) + g.Logger.WarnContext(ctx, "Received unexpected type", "resource", event.Resource.GetKind()) continue } - current, exists := p.current[server.GetName()] - p.current[server.GetName()] = server - if !exists || (p.ProxyDiffer != nil && p.ProxyDiffer(current, server)) { - updated = true - } + + key := g.ResourceKey(resource) + current := g.current[key] + g.current[key] = resource + updated = g.ResourceDiffer(current, resource) default: - p.Logger.WarnContext(ctx, "Skipping unsupported event type", "event_type", event.Type) + g.Logger.WarnContext(ctx, "Skipping unsupported event type", "event_type", event.Type) } } if updated { - p.broadcastUpdate(ctx) + g.broadcastUpdate(ctx) } } -// broadcastUpdate broadcasts information about updating the proxy set. -func (p *proxyCollector) broadcastUpdate(ctx context.Context) { - names := make([]string, 0, len(p.current)) - for k := range p.current { +// broadcastUpdate broadcasts information about updating the resource set. +func (g *genericCollector[T, R]) broadcastUpdate(ctx context.Context) { + if g.DisableUpdateBroadcast { + return + } + + names := make([]string, 0, len(g.current)) + for k := range g.current { names = append(names, k) } - p.Logger.DebugContext(ctx, "List of known proxies updated", "proxies", names) + g.Logger.DebugContext(ctx, "List of known resources updated", "resources", names) select { - case p.ProxiesC <- serverMapValues(p.current): + case g.ResourcesC <- resourcesToSlice(g.current, g.CloneFunc): case <-ctx.Done(): } } // isInitialized is used to check that the cache has done its initial // sync -func (p *proxyCollector) initializationChan() <-chan struct{} { - return p.initializationC +func (g *genericCollector[T, R]) initializationChan() <-chan struct{} { + return g.initializationC } -func (p *proxyCollector) isInitialized() bool { +func (g *genericCollector[T, R]) isInitialized() bool { select { - case <-p.initializationC: + case <-g.initializationC: return true default: return false } } -func (p *proxyCollector) notifyStale() {} - -func serverMapValues(serverMap map[string]types.Server) []types.Server { - servers := make([]types.Server, 0, len(serverMap)) - for _, server := range serverMap { - servers = append(servers, server) - } - return servers +func (g *genericCollector[T, R]) notifyStale() { + g.stale.Store(true) } // LockWatcherConfig is a LockWatcher configuration. type LockWatcherConfig struct { - ResourceWatcherConfig LockGetter + ResourceWatcherConfig } // CheckAndSetDefaults checks parameters and sets default values. @@ -622,15 +946,15 @@ type lockCollector struct { LockWatcherConfig // current holds a map of the currently known locks (keyed by lock name). current map[string]types.Lock - // isStale indicates whether the local lock view (current) is stale. - isStale bool - // currentRW is a mutex protecting both current and isStale. - currentRW sync.RWMutex // fanout provides support for multiple subscribers to the lock updates. fanout *FanoutV2 // initializationC is used to check whether the initial sync has completed initializationC chan struct{} - once sync.Once + // currentRW is a mutex protecting both current and isStale. + currentRW sync.RWMutex + once sync.Once + // isStale indicates whether the local lock view (current) is stale. + isStale bool } // IsStale is used to check whether the lock watcher is stale. @@ -817,858 +1141,37 @@ func lockMapValues(lockMap map[string]types.Lock) []types.Lock { return locks } -// DatabaseWatcherConfig is a DatabaseWatcher configuration. -type DatabaseWatcherConfig struct { +func resourcesToSlice[T any](resources map[string]T, cloneFunc func(T) T) (slice []T) { + for _, resource := range resources { + slice = append(slice, cloneFunc(resource)) + } + return slice +} + +// CertAuthorityWatcherConfig is a CertAuthorityWatcher configuration. +type CertAuthorityWatcherConfig struct { // ResourceWatcherConfig is the resource watcher configuration. ResourceWatcherConfig - // DatabaseGetter is responsible for fetching database resources. - DatabaseGetter - // DatabasesC receives up-to-date list of all database resources. - DatabasesC chan types.Databases + // AuthorityGetter is responsible for fetching cert authority resources. + AuthorityGetter + // Types restricts which cert authority types are retrieved via the AuthorityGetter. + Types []types.CertAuthType } // CheckAndSetDefaults checks parameters and sets default values. -func (cfg *DatabaseWatcherConfig) CheckAndSetDefaults() error { +func (cfg *CertAuthorityWatcherConfig) CheckAndSetDefaults() error { if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { return trace.Wrap(err) } - if cfg.DatabaseGetter == nil { - getter, ok := cfg.Client.(DatabaseGetter) + if cfg.AuthorityGetter == nil { + getter, ok := cfg.Client.(AuthorityGetter) if !ok { - return trace.BadParameter("missing parameter DatabaseGetter and Client not usable as DatabaseGetter") + return trace.BadParameter("missing parameter AuthorityGetter and Client not usable as AuthorityGetter") } - cfg.DatabaseGetter = getter + cfg.AuthorityGetter = getter } - if cfg.DatabasesC == nil { - cfg.DatabasesC = make(chan types.Databases) - } - return nil -} - -// NewDatabaseWatcher returns a new instance of DatabaseWatcher. -func NewDatabaseWatcher(ctx context.Context, cfg DatabaseWatcherConfig) (*DatabaseWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - collector := &databaseCollector{ - DatabaseWatcherConfig: cfg, - initializationC: make(chan struct{}), - } - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - return &DatabaseWatcher{watcher, collector}, nil -} - -// DatabaseWatcher is built on top of resourceWatcher to monitor database resources. -type DatabaseWatcher struct { - *resourceWatcher - *databaseCollector -} - -// databaseCollector accompanies resourceWatcher when monitoring database resources. -type databaseCollector struct { - // DatabaseWatcherConfig is the watcher configuration. - DatabaseWatcherConfig - // current holds a map of the currently known database resources. - current map[string]types.Database - // lock protects the "current" map. - lock sync.RWMutex - // initializationC is used to check that the - initializationC chan struct{} - once sync.Once -} - -// resourceKinds specifies the resource kind to watch. -func (p *databaseCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindDatabase}} -} - -// isInitialized is used to check that the cache has done its initial -// sync -func (p *databaseCollector) initializationChan() <-chan struct{} { - return p.initializationC -} - -// getResourcesAndUpdateCurrent refreshes the list of current resources. -func (p *databaseCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - databases, err := p.DatabaseGetter.GetDatabases(ctx) - if err != nil { - return trace.Wrap(err) - } - newCurrent := make(map[string]types.Database, len(databases)) - for _, database := range databases { - newCurrent[database.GetName()] = database - } - p.lock.Lock() - defer p.lock.Unlock() - p.current = newCurrent - p.defineCollectorAsInitialized() - - select { - case <-ctx.Done(): - return trace.Wrap(ctx.Err()) - case p.DatabasesC <- databases: - } - - return nil -} - -func (p *databaseCollector) defineCollectorAsInitialized() { - p.once.Do(func() { - // mark watcher as initialized. - close(p.initializationC) - }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (p *databaseCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - p.lock.Lock() - defer p.lock.Unlock() - - var updated bool - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindDatabase { - p.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - switch event.Type { - case types.OpDelete: - delete(p.current, event.Resource.GetName()) - updated = true - case types.OpPut: - database, ok := event.Resource.(types.Database) - if !ok { - p.Logger.WarnContext(ctx, "Received unexpected resource type", "resource", event.Resource.GetKind()) - continue - } - p.current[database.GetName()] = database - updated = true - default: - p.Logger.WarnContext(ctx, "Received unsupported event type", "event_type", event.Type) - } - } - - if updated { - select { - case <-ctx.Done(): - case p.DatabasesC <- resourcesToSlice(p.current): - } - } -} - -func (*databaseCollector) notifyStale() {} - -type DynamicWindowsDesktopGetter interface { - ListDynamicWindowsDesktops(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error) -} - -// DynamicWindowsDesktopWatcherConfig is a DynamicWindowsDesktopWatcher configuration. -type DynamicWindowsDesktopWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig - // DynamicWindowsDesktopGetter is responsible for fetching DynamicWindowsDesktop resources. - DynamicWindowsDesktopGetter - // DynamicWindowsDesktopsC receives up-to-date list of all DynamicWindowsDesktop resources. - DynamicWindowsDesktopsC chan types.DynamicWindowsDesktops -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *DynamicWindowsDesktopWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.DynamicWindowsDesktopGetter == nil { - getter, ok := cfg.Client.(DynamicWindowsDesktopGetter) - if !ok { - return trace.BadParameter("missing parameter DynamicWindowsDesktopGetter and Client %T not usable as DynamicWindowsDesktopGetter", cfg.Client) - } - cfg.DynamicWindowsDesktopGetter = getter - } - if cfg.DynamicWindowsDesktopsC == nil { - cfg.DynamicWindowsDesktopsC = make(chan types.DynamicWindowsDesktops) - } - return nil -} - -// NewDynamicWindowsDesktopWatcher returns a new instance of DynamicWindowsDesktopWatcher. -func NewDynamicWindowsDesktopWatcher(ctx context.Context, cfg DynamicWindowsDesktopWatcherConfig) (*DynamicWindowsDesktopWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - collector := &dynamicWindowsDesktopCollector{ - DynamicWindowsDesktopWatcherConfig: cfg, - initializationC: make(chan struct{}), - } - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - return &DynamicWindowsDesktopWatcher{watcher, collector}, nil -} - -// DynamicWindowsDesktopWatcher is built on top of resourceWatcher to monitor DynamicWindowsDesktop resources. -type DynamicWindowsDesktopWatcher struct { - *resourceWatcher - *dynamicWindowsDesktopCollector -} - -// dynamicWindowsDesktopCollector accompanies resourceWatcher when monitoring DynamicWindowsDesktop resources. -type dynamicWindowsDesktopCollector struct { - // DynamicWindowsDesktopWatcherConfig is the watcher configuration. - DynamicWindowsDesktopWatcherConfig - // current holds a map of the currently known DynamicWindowsDesktop resources. - current map[string]types.DynamicWindowsDesktop - // lock protects the "current" map. - lock sync.RWMutex - // initializationC is used to check that the - initializationC chan struct{} - once sync.Once -} - -// resourceKinds specifies the resource kind to watch. -func (p *dynamicWindowsDesktopCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindDynamicWindowsDesktop}} -} - -// isInitialized is used to check that the cache has done its initial -// sync -func (p *dynamicWindowsDesktopCollector) initializationChan() <-chan struct{} { - return p.initializationC -} - -// getResourcesAndUpdateCurrent refreshes the list of current resources. -func (p *dynamicWindowsDesktopCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - var dynamicWindowsDesktops []types.DynamicWindowsDesktop - next := "" - for { - desktops, token, err := p.DynamicWindowsDesktopGetter.ListDynamicWindowsDesktops(ctx, defaults.MaxIterationLimit, next) - if err != nil { - return trace.Wrap(err) - } - dynamicWindowsDesktops = append(dynamicWindowsDesktops, desktops...) - if token == "" { - break - } - next = token - } - newCurrent := make(map[string]types.DynamicWindowsDesktop, len(dynamicWindowsDesktops)) - for _, dynamicWindowsDesktop := range dynamicWindowsDesktops { - newCurrent[dynamicWindowsDesktop.GetName()] = dynamicWindowsDesktop - } - p.lock.Lock() - defer p.lock.Unlock() - p.current = newCurrent - p.defineCollectorAsInitialized() - - select { - case <-ctx.Done(): - return trace.Wrap(ctx.Err()) - case p.DynamicWindowsDesktopsC <- dynamicWindowsDesktops: - } - - return nil -} - -func (p *dynamicWindowsDesktopCollector) defineCollectorAsInitialized() { - p.once.Do(func() { - // mark watcher as initialized. - close(p.initializationC) - }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (p *dynamicWindowsDesktopCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - p.lock.Lock() - defer p.lock.Unlock() - - var updated bool - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindDynamicWindowsDesktop { - p.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - switch event.Type { - case types.OpDelete: - delete(p.current, event.Resource.GetName()) - updated = true - case types.OpPut: - dynamicWindowsDesktop, ok := event.Resource.(types.DynamicWindowsDesktop) - if !ok { - p.Logger.WarnContext(ctx, "Received unexpected resource type", "resource", event.Resource.GetKind()) - continue - } - p.current[dynamicWindowsDesktop.GetName()] = dynamicWindowsDesktop - updated = true - default: - p.Logger.WarnContext(ctx, "Received unsupported event type", "event_type", event.Type) - } - } - - if updated { - select { - case <-ctx.Done(): - case p.DynamicWindowsDesktopsC <- resourcesToSlice(p.current): - } - } -} - -func (*dynamicWindowsDesktopCollector) notifyStale() {} - -// AppWatcherConfig is an AppWatcher configuration. -type AppWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig - // AppGetter is responsible for fetching application resources. - AppGetter - // AppsC receives up-to-date list of all application resources. - AppsC chan types.Apps -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *AppWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.AppGetter == nil { - getter, ok := cfg.Client.(AppGetter) - if !ok { - return trace.BadParameter("missing parameter AppGetter and Client not usable as AppGetter") - } - cfg.AppGetter = getter - } - if cfg.AppsC == nil { - cfg.AppsC = make(chan types.Apps) - } - return nil -} - -// NewAppWatcher returns a new instance of AppWatcher. -func NewAppWatcher(ctx context.Context, cfg AppWatcherConfig) (*AppWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - collector := &appCollector{ - AppWatcherConfig: cfg, - initializationC: make(chan struct{}), - } - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - return &AppWatcher{watcher, collector}, nil -} - -// AppWatcher is built on top of resourceWatcher to monitor application resources. -type AppWatcher struct { - *resourceWatcher - *appCollector -} - -// appCollector accompanies resourceWatcher when monitoring application resources. -type appCollector struct { - // AppWatcherConfig is the watcher configuration. - AppWatcherConfig - // current holds a map of the currently known application resources. - current map[string]types.Application - // lock protects the "current" map. - lock sync.RWMutex - // initializationC is used to check whether the initial sync has completed - initializationC chan struct{} - once sync.Once -} - -// resourceKinds specifies the resource kind to watch. -func (p *appCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindApp}} -} - -// isInitialized is used to check that the cache has done its initial -// sync -func (p *appCollector) initializationChan() <-chan struct{} { - return p.initializationC -} - -// getResourcesAndUpdateCurrent refreshes the list of current resources. -func (p *appCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - apps, err := p.AppGetter.GetApps(ctx) - if err != nil { - return trace.Wrap(err) - } - newCurrent := make(map[string]types.Application, len(apps)) - for _, app := range apps { - newCurrent[app.GetName()] = app - } - p.lock.Lock() - defer p.lock.Unlock() - p.current = newCurrent - p.defineCollectorAsInitialized() - select { - case <-ctx.Done(): - return trace.Wrap(ctx.Err()) - case p.AppsC <- apps: - } - return nil -} - -func (p *appCollector) defineCollectorAsInitialized() { - p.once.Do(func() { - // mark watcher as initialized. - close(p.initializationC) - }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (p *appCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - p.lock.Lock() - defer p.lock.Unlock() - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindApp { - p.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - switch event.Type { - case types.OpDelete: - delete(p.current, event.Resource.GetName()) - p.AppsC <- resourcesToSlice(p.current) - - select { - case <-ctx.Done(): - case p.AppsC <- resourcesToSlice(p.current): - } - - case types.OpPut: - app, ok := event.Resource.(types.Application) - if !ok { - p.Logger.WarnContext(ctx, "Received unexpected resource type", "resource", event.Resource.GetKind()) - continue - } - p.current[app.GetName()] = app - - select { - case <-ctx.Done(): - case p.AppsC <- resourcesToSlice(p.current): - } - default: - p.Logger.WarnContext(ctx, "Received unsupported event type", "event_type", event.Type) - } - } -} - -func (*appCollector) notifyStale() {} - -func resourcesToSlice[T any](resources map[string]T) (slice []T) { - for _, resource := range resources { - slice = append(slice, resource) - } - return slice -} - -// KubeClusterWatcherConfig is an KubeClusterWatcher configuration. -type KubeClusterWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig - // KubernetesGetter is responsible for fetching kube_cluster resources. - KubernetesClusterGetter - // KubeClustersC receives up-to-date list of all kube_cluster resources. - KubeClustersC chan types.KubeClusters -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *KubeClusterWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.KubernetesClusterGetter == nil { - getter, ok := cfg.Client.(KubernetesClusterGetter) - if !ok { - return trace.BadParameter("missing parameter KubernetesGetter and Client not usable as KubernetesGetter") - } - cfg.KubernetesClusterGetter = getter - } - if cfg.KubeClustersC == nil { - cfg.KubeClustersC = make(chan types.KubeClusters) - } - return nil -} - -// NewKubeClusterWatcher returns a new instance of KubeClusterWatcher. -func NewKubeClusterWatcher(ctx context.Context, cfg KubeClusterWatcherConfig) (*KubeClusterWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - collector := &kubeCollector{ - KubeClusterWatcherConfig: cfg, - initializationC: make(chan struct{}), - } - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - return &KubeClusterWatcher{watcher, collector}, nil -} - -// KubeClusterWatcher is built on top of resourceWatcher to monitor kube_cluster resources. -type KubeClusterWatcher struct { - *resourceWatcher - *kubeCollector -} - -// kubeCollector accompanies resourceWatcher when monitoring kube_cluster resources. -type kubeCollector struct { - // KubeClusterWatcherConfig is the watcher configuration. - KubeClusterWatcherConfig - // current holds a map of the currently known kube_cluster resources. - current map[string]types.KubeCluster - // lock protects the "current" map. - lock sync.RWMutex - // initializationC is used to check whether the initial sync has completed - initializationC chan struct{} - once sync.Once -} - -// isInitialized is used to check that the cache has done its initial -// sync -func (k *kubeCollector) initializationChan() <-chan struct{} { - return k.initializationC -} - -// resourceKinds specifies the resource kind to watch. -func (k *kubeCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindKubernetesCluster}} -} - -// getResourcesAndUpdateCurrent refreshes the list of current resources. -func (k *kubeCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - clusters, err := k.KubernetesClusterGetter.GetKubernetesClusters(ctx) - if err != nil { - return trace.Wrap(err) - } - newCurrent := make(map[string]types.KubeCluster, len(clusters)) - for _, cluster := range clusters { - newCurrent[cluster.GetName()] = cluster - } - k.lock.Lock() - defer k.lock.Unlock() - k.current = newCurrent - - select { - case <-ctx.Done(): - return trace.Wrap(ctx.Err()) - case k.KubeClustersC <- clusters: - } - - k.defineCollectorAsInitialized() - - return nil -} - -func (k *kubeCollector) defineCollectorAsInitialized() { - k.once.Do(func() { - // mark watcher as initialized. - close(k.initializationC) - }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (k *kubeCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - k.lock.Lock() - defer k.lock.Unlock() - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindKubernetesCluster { - k.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - switch event.Type { - case types.OpDelete: - delete(k.current, event.Resource.GetName()) - k.KubeClustersC <- resourcesToSlice(k.current) - - select { - case <-ctx.Done(): - case k.KubeClustersC <- resourcesToSlice(k.current): - } - - case types.OpPut: - cluster, ok := event.Resource.(types.KubeCluster) - if !ok { - k.Logger.WarnContext(ctx, "Received unexpected resource type", "resource", event.Resource.GetKind()) - continue - } - k.current[cluster.GetName()] = cluster - - select { - case <-ctx.Done(): - case k.KubeClustersC <- resourcesToSlice(k.current): - } - default: - k.Logger.WarnContext(ctx, "Received unsupported event type", "event_type", event.Type) - } - } -} - -func (*kubeCollector) notifyStale() {} - -// KubeServerWatcherConfig is an KubeServerWatcher configuration. -type KubeServerWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig - // KubernetesServerGetter is responsible for fetching kube_server resources. - KubernetesServerGetter -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *KubeServerWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.KubernetesServerGetter == nil { - getter, ok := cfg.Client.(KubernetesServerGetter) - if !ok { - return trace.BadParameter("missing parameter KubernetesServerGetter and Client not usable as KubernetesServerGetter") - } - cfg.KubernetesServerGetter = getter - } - return nil -} - -// NewKubeServerWatcher returns a new instance of KubeServerWatcher. -func NewKubeServerWatcher(ctx context.Context, cfg KubeServerWatcherConfig) (*KubeServerWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - cache, err := utils.NewFnCache(utils.FnCacheConfig{ - Context: ctx, - TTL: 3 * time.Second, - Clock: cfg.Clock, - }) - if err != nil { - return nil, trace.Wrap(err) - } - collector := &kubeServerCollector{ - KubeServerWatcherConfig: cfg, - initializationC: make(chan struct{}), - cache: cache, - } - // start the collector as staled. - collector.stale.Store(true) - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - return &KubeServerWatcher{watcher, collector}, nil -} - -// KubeServerWatcher is built on top of resourceWatcher to monitor kube_server resources. -type KubeServerWatcher struct { - *resourceWatcher - *kubeServerCollector -} - -// GetKubeServersByClusterName returns a list of kubernetes servers for the specified cluster. -func (k *KubeServerWatcher) GetKubeServersByClusterName(ctx context.Context, clusterName string) ([]types.KubeServer, error) { - k.refreshStaleKubeServers(ctx) - - k.lock.RLock() - defer k.lock.RUnlock() - var servers []types.KubeServer - for _, server := range k.current { - if server.GetCluster().GetName() == clusterName { - servers = append(servers, server.Copy()) - } - } - if len(servers) == 0 { - return nil, trace.NotFound("no kubernetes servers found for cluster %q", clusterName) - } - - return servers, nil -} - -// GetKubernetesServers returns a list of kubernetes servers for all clusters. -func (k *KubeServerWatcher) GetKubernetesServers(ctx context.Context) ([]types.KubeServer, error) { - k.refreshStaleKubeServers(ctx) - - k.lock.RLock() - defer k.lock.RUnlock() - servers := make([]types.KubeServer, 0, len(k.current)) - for _, server := range k.current { - servers = append(servers, server.Copy()) - } - return servers, nil -} - -// kubeServerCollector accompanies resourceWatcher when monitoring kube_server resources. -type kubeServerCollector struct { - // KubeServerWatcherConfig is the watcher configuration. - KubeServerWatcherConfig - // current holds a map of the currently known kube_server resources. - current map[kubeServersKey]types.KubeServer - // lock protects the "current" map. - lock sync.RWMutex - // initializationC is used to check whether the initial sync has completed - initializationC chan struct{} - once sync.Once - // stale is used to indicate that the watcher is stale and needs to be - // refreshed. - stale atomic.Bool - // cache is a helper for temporarily storing the results of GetKubernetesServers. - // It's used to limit the amount of calls to the backend. - cache *utils.FnCache -} - -// kubeServersKey is used to uniquely identify a kube_server resource. -type kubeServersKey struct { - hostID string - resourceName string -} - -// isInitialized is used to check that the cache has done its initial -// sync -func (k *kubeServerCollector) initializationChan() <-chan struct{} { - return k.initializationC -} - -// resourceKinds specifies the resource kind to watch. -func (k *kubeServerCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindKubeServer}} -} - -// getResourcesAndUpdateCurrent refreshes the list of current resources. -func (k *kubeServerCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - newCurrent, err := k.getResources(ctx) - if err != nil { - return trace.Wrap(err) - } - - k.lock.Lock() - k.current = newCurrent - k.lock.Unlock() - - k.stale.Store(false) - - k.defineCollectorAsInitialized() - return nil -} - -// getResourcesAndUpdateCurrent gets the list of current resources. -func (k *kubeServerCollector) getResources(ctx context.Context) (map[kubeServersKey]types.KubeServer, error) { - servers, err := k.KubernetesServerGetter.GetKubernetesServers(ctx) - if err != nil { - return nil, trace.Wrap(err) - } - current := make(map[kubeServersKey]types.KubeServer, len(servers)) - for _, server := range servers { - key := kubeServersKey{ - hostID: server.GetHostID(), - resourceName: server.GetName(), - } - current[key] = server - } - return current, nil -} - -func (k *kubeServerCollector) defineCollectorAsInitialized() { - k.once.Do(func() { - // mark watcher as initialized. - close(k.initializationC) - }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (k *kubeServerCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - k.lock.Lock() - defer k.lock.Unlock() - - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindKubeServer { - k.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - - switch event.Type { - case types.OpDelete: - key := kubeServersKey{ - // On delete events, the server description is populated with the host ID. - hostID: event.Resource.GetMetadata().Description, - resourceName: event.Resource.GetName(), - } - delete(k.current, key) - case types.OpPut: - server, ok := event.Resource.(types.KubeServer) - if !ok { - k.Logger.WarnContext(ctx, "Received unexpected resource type", "resource", event.Resource.GetKind()) - continue - } - - key := kubeServersKey{ - hostID: server.GetHostID(), - resourceName: server.GetName(), - } - k.current[key] = server - default: - k.Logger.WarnContext(ctx, "Received unsupported event type", "event_type", event.Type) - } - } -} - -func (k *kubeServerCollector) notifyStale() { - k.stale.Store(true) -} - -// refreshStaleKubeServers attempts to reload kube servers from the cache if -// the collector is stale. This ensures that no matter the health of -// the collector callers will be returned the most up to date node -// set as possible. -func (k *kubeServerCollector) refreshStaleKubeServers(ctx context.Context) error { - if !k.stale.Load() { - return nil - } - - _, err := utils.FnCacheGet(ctx, k.cache, "kube_servers", func(ctx context.Context) (any, error) { - current, err := k.getResources(ctx) - if err != nil { - return nil, trace.Wrap(err) - } - - // There is a chance that the watcher reinitialized while - // getting kube servers happened above. Check if we are still stale - if k.stale.CompareAndSwap(true, false) { - k.lock.Lock() - k.current = current - k.lock.Unlock() - } - - return nil, nil - }) - - return trace.Wrap(err) -} - -// CertAuthorityWatcherConfig is a CertAuthorityWatcher configuration. -type CertAuthorityWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig - // AuthorityGetter is responsible for fetching cert authority resources. - AuthorityGetter - // Types restricts which cert authority types are retrieved via the AuthorityGetter. - Types []types.CertAuthType -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *CertAuthorityWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.AuthorityGetter == nil { - getter, ok := cfg.Client.(AuthorityGetter) - if !ok { - return trace.BadParameter("missing parameter AuthorityGetter and Client not usable as AuthorityGetter") - } - cfg.AuthorityGetter = getter - } - if len(cfg.Types) == 0 { - return trace.BadParameter("missing parameter Types") + if len(cfg.Types) == 0 { + return trace.BadParameter("missing parameter Types") } return nil } @@ -1712,17 +1215,15 @@ type CertAuthorityWatcher struct { // caCollector accompanies resourceWatcher when monitoring cert authority resources. type caCollector struct { - CertAuthorityWatcherConfig fanout *FanoutV2 - - // lock protects concurrent access to cas - lock sync.RWMutex - // cas maps ca type -> cluster -> ca - cas map[types.CertAuthType]map[string]types.CertAuthority + cas map[types.CertAuthType]map[string]types.CertAuthority // initializationC is used to check whether the initial sync has completed initializationC chan struct{} - once sync.Once filter types.CertAuthorityFilter + CertAuthorityWatcherConfig + // lock protects concurrent access to cas + lock sync.RWMutex + once sync.Once } // Subscribe is used to subscribe to the lock updates. @@ -1859,285 +1360,40 @@ func (c *caCollector) notifyStale() {} // NodeWatcherConfig is a NodeWatcher configuration. type NodeWatcherConfig struct { - ResourceWatcherConfig // NodesGetter is used to directly fetch the list of active nodes. NodesGetter -} - -// CheckAndSetDefaults checks parameters and sets default values. -func (cfg *NodeWatcherConfig) CheckAndSetDefaults() error { - if err := cfg.ResourceWatcherConfig.CheckAndSetDefaults(); err != nil { - return trace.Wrap(err) - } - if cfg.NodesGetter == nil { - getter, ok := cfg.Client.(NodesGetter) - if !ok { - return trace.BadParameter("missing parameter NodesGetter and Client not usable as NodesGetter") - } - cfg.NodesGetter = getter - } - return nil + ResourceWatcherConfig } // NewNodeWatcher returns a new instance of NodeWatcher. -func NewNodeWatcher(ctx context.Context, cfg NodeWatcherConfig) (*NodeWatcher, error) { - if err := cfg.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - - cache, err := utils.NewFnCache(utils.FnCacheConfig{ - Context: ctx, - TTL: 3 * time.Second, - Clock: cfg.Clock, - }) - if err != nil { - return nil, trace.Wrap(err) - } - - collector := &nodeCollector{ - NodeWatcherConfig: cfg, - current: map[string]types.Server{}, - initializationC: make(chan struct{}), - cache: cache, - stale: true, - } - - watcher, err := newResourceWatcher(ctx, collector, cfg.ResourceWatcherConfig) - if err != nil { - return nil, trace.Wrap(err) - } - - return &NodeWatcher{resourceWatcher: watcher, nodeCollector: collector}, nil -} - -// NodeWatcher is built on top of resourceWatcher to monitor additions -// and deletions to the set of nodes. -type NodeWatcher struct { - *resourceWatcher - *nodeCollector -} - -// nodeCollector accompanies resourceWatcher when monitoring nodes. -type nodeCollector struct { - NodeWatcherConfig - - // initializationC is used to check whether the initial sync has completed - initializationC chan struct{} - once sync.Once - - cache *utils.FnCache - - rw sync.RWMutex - // current holds a map of the currently known nodes keyed by server name - current map[string]types.Server - stale bool -} - -// Node is a readonly subset of the types.Server interface which -// users may filter by in GetNodes. -type Node interface { - // ResourceWithLabels provides common resource headers - types.ResourceWithLabels - // GetTeleportVersion returns the teleport version the server is running on - GetTeleportVersion() string - // GetAddr return server address - GetAddr() string - // GetPublicAddrs returns all public addresses where this server can be reached. - GetPublicAddrs() []string - // GetHostname returns server hostname - GetHostname() string - // GetNamespace returns server namespace - GetNamespace() string - // GetCmdLabels gets command labels - GetCmdLabels() map[string]types.CommandLabel - // GetRotation gets the state of certificate authority rotation. - GetRotation() types.Rotation - // GetUseTunnel gets if a reverse tunnel should be used to connect to this node. - GetUseTunnel() bool - // GetProxyIDs returns a list of proxy ids this server is connected to. - GetProxyIDs() []string - // IsEICE returns whether the Node is an EICE instance. - // Must be `openssh-ec2-ice` subkind and have the AccountID and InstanceID information (AWS Metadata or Labels). - IsEICE() bool -} - -// GetNodes allows callers to retrieve a subset of nodes that match the filter provided. The -// returned servers are a copy and can be safely modified. It is intentionally hard to retrieve -// the full set of nodes to reduce the number of copies needed since the number of nodes can get -// quite large and doing so can be expensive. -func (n *nodeCollector) GetNodes(ctx context.Context, fn func(n Node) bool) []types.Server { - // Attempt to freshen our data first. - n.refreshStaleNodes(ctx) - - n.rw.RLock() - defer n.rw.RUnlock() - - var matched []types.Server - for _, server := range n.current { - if fn(server) { - matched = append(matched, server.DeepCopy()) - } - } - - return matched -} - -// GetNode allows callers to retrieve a node based on its name. The -// returned server are a copy and can be safely modified. -func (n *nodeCollector) GetNode(ctx context.Context, name string) (types.Server, error) { - // Attempt to freshen our data first. - n.refreshStaleNodes(ctx) - - n.rw.RLock() - defer n.rw.RUnlock() - - server, found := n.current[name] - if !found { - return nil, trace.NotFound("server does not exist") - } - return server.DeepCopy(), nil -} - -// refreshStaleNodes attempts to reload nodes from the NodeGetter if -// the collecter is stale. This ensures that no matter the health of -// the collecter callers will be returned the most up to date node -// set as possible. -func (n *nodeCollector) refreshStaleNodes(ctx context.Context) error { - n.rw.RLock() - if !n.stale { - n.rw.RUnlock() - return nil - } - n.rw.RUnlock() - - _, err := utils.FnCacheGet(ctx, n.cache, "nodes", func(ctx context.Context) (any, error) { - current, err := n.getNodes(ctx) - if err != nil { - return nil, trace.Wrap(err) - } - - n.rw.Lock() - defer n.rw.Unlock() - - // There is a chance that the watcher reinitialized while - // getting nodes happened above. Check if we are still stale - // now that the lock is held to ensure that the refresh is - // still necessary. - if !n.stale { - return nil, nil - } - - n.current = current - return nil, trace.Wrap(err) - }) - - return trace.Wrap(err) -} - -func (n *nodeCollector) NodeCount() int { - n.rw.RLock() - defer n.rw.RUnlock() - return len(n.current) -} - -// resourceKinds specifies the resource kind to watch. -func (n *nodeCollector) resourceKinds() []types.WatchKind { - return []types.WatchKind{{Kind: types.KindNode}} -} - -// getResourcesAndUpdateCurrent is called when the resources should be -// (re-)fetched directly. -func (n *nodeCollector) getResourcesAndUpdateCurrent(ctx context.Context) error { - newCurrent, err := n.getNodes(ctx) - if err != nil { - return trace.Wrap(err) - } - defer n.defineCollectorAsInitialized() - - if len(newCurrent) == 0 { - return nil - } - - n.rw.Lock() - defer n.rw.Unlock() - n.current = newCurrent - n.stale = false - return nil -} - -func (n *nodeCollector) getNodes(ctx context.Context) (map[string]types.Server, error) { - nodes, err := n.NodesGetter.GetNodes(ctx, apidefaults.Namespace) - if err != nil { - return nil, trace.Wrap(err) - } - - if len(nodes) == 0 { - return map[string]types.Server{}, nil - } - - current := make(map[string]types.Server, len(nodes)) - for _, node := range nodes { - current[node.GetName()] = node +func NewNodeWatcher(ctx context.Context, cfg NodeWatcherConfig) (*GenericWatcher[types.Server, readonly.Server], error) { + if cfg.NodesGetter == nil { + return nil, trace.BadParameter("NodesGetter must be provided") } - return current, nil -} - -func (n *nodeCollector) defineCollectorAsInitialized() { - n.once.Do(func() { - // mark watcher as initialized. - close(n.initializationC) + w, err := NewGenericResourceWatcher(ctx, GenericWatcherConfig[types.Server, readonly.Server]{ + ResourceWatcherConfig: cfg.ResourceWatcherConfig, + ResourceKind: types.KindNode, + ResourceGetter: func(ctx context.Context) ([]types.Server, error) { + return cfg.NodesGetter.GetNodes(ctx, apidefaults.Namespace) + }, + ResourceKey: types.Server.GetName, + DisableUpdateBroadcast: true, + CloneFunc: types.Server.DeepCopy, }) -} - -// processEventsAndUpdateCurrent is called when a watcher event is received. -func (n *nodeCollector) processEventsAndUpdateCurrent(ctx context.Context, events []types.Event) { - n.rw.Lock() - defer n.rw.Unlock() - - for _, event := range events { - if event.Resource == nil || event.Resource.GetKind() != types.KindNode { - n.Logger.WarnContext(ctx, "Received unexpected event", "event", logutils.StringerAttr(event)) - continue - } - - switch event.Type { - case types.OpDelete: - delete(n.current, event.Resource.GetName()) - case types.OpPut: - server, ok := event.Resource.(types.Server) - if !ok { - n.Logger.WarnContext(ctx, "Received unexpected type", "resource", event.Resource.GetKind()) - continue - } - - n.current[server.GetName()] = server - default: - n.Logger.WarnContext(ctx, "Skipping unsupported event type", "event_type", event.Type) - } - } -} - -func (n *nodeCollector) initializationChan() <-chan struct{} { - return n.initializationC -} - -func (n *nodeCollector) notifyStale() { - n.rw.Lock() - defer n.rw.Unlock() - n.stale = true + return w, trace.Wrap(err) } // AccessRequestWatcherConfig is a AccessRequestWatcher configuration. type AccessRequestWatcherConfig struct { - // ResourceWatcherConfig is the resource watcher configuration. - ResourceWatcherConfig // AccessRequestGetter is responsible for fetching access request resources. AccessRequestGetter - // Filter is the filter to use to monitor access requests. - Filter types.AccessRequestFilter // AccessRequestsC receives up-to-date list of all access request resources. AccessRequestsC chan types.AccessRequests + // ResourceWatcherConfig is the resource watcher configuration. + ResourceWatcherConfig + // Filter is the filter to use to monitor access requests. + Filter types.AccessRequestFilter } // CheckAndSetDefaults checks parameters and sets default values. @@ -2186,11 +1442,11 @@ type accessRequestCollector struct { AccessRequestWatcherConfig // current holds a map of the currently known access request resources. current map[string]types.AccessRequest - // lock protects the "current" map. - lock sync.RWMutex // initializationC is used to check that the watcher has been initialized properly. initializationC chan struct{} - once sync.Once + // lock protects the "current" map. + lock sync.RWMutex + once sync.Once } // resourceKinds specifies the resource kind to watch. @@ -2250,7 +1506,7 @@ func (p *accessRequestCollector) processEventsAndUpdateCurrent(ctx context.Conte delete(p.current, event.Resource.GetName()) select { case <-ctx.Done(): - case p.AccessRequestsC <- resourcesToSlice(p.current): + case p.AccessRequestsC <- resourcesToSlice(p.current, types.AccessRequest.Copy): } case types.OpPut: accessRequest, ok := event.Resource.(types.AccessRequest) @@ -2261,7 +1517,7 @@ func (p *accessRequestCollector) processEventsAndUpdateCurrent(ctx context.Conte p.current[accessRequest.GetName()] = accessRequest select { case <-ctx.Done(): - case p.AccessRequestsC <- resourcesToSlice(p.current): + case p.AccessRequestsC <- resourcesToSlice(p.current, types.AccessRequest.Copy): } default: @@ -2274,14 +1530,14 @@ func (*accessRequestCollector) notifyStale() {} // OktaAssignmentWatcherConfig is a OktaAssignmentWatcher configuration. type OktaAssignmentWatcherConfig struct { - // RWCfg is the resource watcher configuration. - RWCfg ResourceWatcherConfig // OktaAssignments is responsible for fetching Okta assignments. OktaAssignments OktaAssignmentsGetter - // PageSize is the number of Okta assignments to list at a time. - PageSize int // OktaAssignmentsC receives up-to-date list of all Okta assignment resources. OktaAssignmentsC chan types.OktaAssignments + // RWCfg is the resource watcher configuration. + RWCfg ResourceWatcherConfig + // PageSize is the number of Okta assignments to list at a time. + PageSize int } // CheckAndSetDefaults checks parameters and sets default values. @@ -2346,16 +1602,16 @@ func (o *OktaAssignmentWatcher) Done() <-chan struct{} { // oktaAssignmentCollector accompanies resourceWatcher when monitoring Okta assignment resources. type oktaAssignmentCollector struct { - logger *slog.Logger // OktaAssignmentWatcherConfig is the watcher configuration. - cfg OktaAssignmentWatcherConfig - // mu guards "current" - mu sync.RWMutex + cfg OktaAssignmentWatcherConfig + logger *slog.Logger // current holds a map of the currently known Okta assignment resources. current map[string]types.OktaAssignment // initializationC is used to check that the watcher has been initialized properly. initializationC chan struct{} - once sync.Once + // mu guards "current" + mu sync.RWMutex + once sync.Once } // resourceKinds specifies the resource kind to watch. @@ -2423,7 +1679,7 @@ func (c *oktaAssignmentCollector) processEventsAndUpdateCurrent(ctx context.Cont switch event.Type { case types.OpDelete: delete(c.current, event.Resource.GetName()) - resources := resourcesToSlice(c.current) + resources := resourcesToSlice(c.current, types.OktaAssignment.Copy) select { case <-ctx.Done(): case c.cfg.OktaAssignmentsC <- resources: @@ -2435,7 +1691,7 @@ func (c *oktaAssignmentCollector) processEventsAndUpdateCurrent(ctx context.Cont continue } c.current[oktaAssignment.GetName()] = oktaAssignment - resources := resourcesToSlice(c.current) + resources := resourcesToSlice(c.current, types.OktaAssignment.Copy) select { case <-ctx.Done(): diff --git a/lib/services/watcher_test.go b/lib/services/watcher_test.go index 3ffe202bb7087..730c7430696a4 100644 --- a/lib/services/watcher_test.go +++ b/lib/services/watcher_test.go @@ -45,6 +45,7 @@ import ( "github.com/gravitational/teleport/lib/fixtures" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/tlsca" ) @@ -131,7 +132,8 @@ func TestProxyWatcher(t *testing.T) { Events: local.NewEventsService(bk), }, }, - ProxiesC: make(chan []types.Server, 10), + ProxyGetter: presence, + ProxiesC: make(chan []types.Server, 10), }) require.NoError(t, err) t.Cleanup(w.Close) @@ -143,7 +145,7 @@ func TestProxyWatcher(t *testing.T) { // The first event is always the current list of proxies. select { - case changeset := <-w.ProxiesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], proxy)) case <-w.Done(): @@ -158,7 +160,7 @@ func TestProxyWatcher(t *testing.T) { // Watcher should detect the proxy list change. select { - case changeset := <-w.ProxiesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 2) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -171,7 +173,7 @@ func TestProxyWatcher(t *testing.T) { // Watcher should detect the proxy list change. select { - case changeset := <-w.ProxiesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], proxy2)) case <-w.Done(): @@ -185,7 +187,7 @@ func TestProxyWatcher(t *testing.T) { // Watcher should detect the proxy list change. select { - case changeset := <-w.ProxiesC: + case changeset := <-w.ResourcesC: require.Empty(t, changeset) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -562,14 +564,15 @@ func TestDatabaseWatcher(t *testing.T) { Events: local.NewEventsService(bk), }, }, - DatabasesC: make(chan types.Databases, 10), + DatabaseGetter: databasesService, + DatabasesC: make(chan []types.Database, 10), }) require.NoError(t, err) t.Cleanup(w.Close) // Initially there are no databases so watcher should send an empty list. select { - case changeset := <-w.DatabasesC: + case changeset := <-w.ResourcesC: require.Empty(t, changeset) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -583,7 +586,7 @@ func TestDatabaseWatcher(t *testing.T) { // The first event is always the current list of databases. select { - case changeset := <-w.DatabasesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], database1)) case <-w.Done(): @@ -598,7 +601,7 @@ func TestDatabaseWatcher(t *testing.T) { // Watcher should detect the database list change. select { - case changeset := <-w.DatabasesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 2) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -611,7 +614,7 @@ func TestDatabaseWatcher(t *testing.T) { // Watcher should detect the database list change. select { - case changeset := <-w.DatabasesC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], database2)) case <-w.Done(): @@ -661,14 +664,15 @@ func TestAppWatcher(t *testing.T) { Events: local.NewEventsService(bk), }, }, - AppsC: make(chan types.Apps, 10), + AppGetter: appService, + AppsC: make(chan []types.Application, 10), }) require.NoError(t, err) t.Cleanup(w.Close) // Initially there are no apps so watcher should send an empty list. select { - case changeset := <-w.AppsC: + case changeset := <-w.ResourcesC: require.Empty(t, changeset) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -682,7 +686,7 @@ func TestAppWatcher(t *testing.T) { // The first event is always the current list of apps. select { - case changeset := <-w.AppsC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], app1)) case <-w.Done(): @@ -697,7 +701,7 @@ func TestAppWatcher(t *testing.T) { // Watcher should detect the app list change. select { - case changeset := <-w.AppsC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 2) case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -710,7 +714,7 @@ func TestAppWatcher(t *testing.T) { // Watcher should detect the database list change. select { - case changeset := <-w.AppsC: + case changeset := <-w.ResourcesC: require.Len(t, changeset, 1) require.Empty(t, resourceDiff(changeset[0], app2)) case <-w.Done(): @@ -909,6 +913,7 @@ func TestNodeWatcherFallback(t *testing.T) { }, MaxStaleness: time.Minute, }, + NodesGetter: presence, }) require.NoError(t, err) t.Cleanup(w.Close) @@ -922,15 +927,14 @@ func TestNodeWatcherFallback(t *testing.T) { nodes = append(nodes, node) } - require.Empty(t, w.NodeCount()) + require.Empty(t, w.ResourceCount()) require.False(t, w.IsInitialized()) - got := w.GetNodes(ctx, func(n services.Node) bool { - return true - }) + got, err := w.CurrentResources(ctx) + require.NoError(t, err) require.Len(t, nodes, len(got)) - require.Len(t, nodes, w.NodeCount()) + require.Len(t, nodes, w.ResourceCount()) require.False(t, w.IsInitialized()) } @@ -961,6 +965,7 @@ func TestNodeWatcher(t *testing.T) { }, MaxStaleness: time.Minute, }, + NodesGetter: presence, }) require.NoError(t, err) t.Cleanup(w.Close) @@ -974,25 +979,27 @@ func TestNodeWatcher(t *testing.T) { nodes = append(nodes, node) } - require.Eventually(t, func() bool { - filtered := w.GetNodes(ctx, func(n services.Node) bool { - return true - }) - return len(filtered) == len(nodes) + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResources(ctx) + assert.NoError(t, err) + assert.Len(t, filtered, len(nodes)) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive nodes.") - require.Len(t, w.GetNodes(ctx, func(n services.Node) bool { return n.GetUseTunnel() }), 3) + filtered, err := w.CurrentResourcesWithFilter(ctx, func(n readonly.Server) bool { return n.GetUseTunnel() }) + require.NoError(t, err) + require.Len(t, filtered, 3) require.NoError(t, presence.DeleteNode(ctx, apidefaults.Namespace, nodes[0].GetName())) - require.Eventually(t, func() bool { - filtered := w.GetNodes(ctx, func(n services.Node) bool { - return true - }) - return len(filtered) == len(nodes)-1 + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResources(ctx) + assert.NoError(t, err) + assert.Len(t, filtered, len(nodes)-1) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive nodes.") - require.Empty(t, w.GetNodes(ctx, func(n services.Node) bool { return n.GetName() == nodes[0].GetName() })) + filtered, err = w.CurrentResourcesWithFilter(ctx, func(n readonly.Server) bool { return n.GetName() == nodes[0].GetName() }) + require.NoError(t, err) + require.Empty(t, filtered) } func newNodeServer(t *testing.T, name, hostname, addr string, tunnel bool) types.Server { @@ -1032,6 +1039,7 @@ func TestKubeServerWatcher(t *testing.T) { }, MaxStaleness: time.Minute, }, + KubernetesServerGetter: presence, }) require.NoError(t, err) t.Cleanup(w.Close) @@ -1057,55 +1065,66 @@ func TestKubeServerWatcher(t *testing.T) { kubeServers = append(kubeServers, kubeServer) } - require.Eventually(t, func() bool { - filtered, err := w.GetKubernetesServers(context.Background()) + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResources(context.Background()) assert.NoError(t, err) - return len(filtered) == len(kubeServers) + assert.Len(t, filtered, len(kubeServers)) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive kube servers.") // Test filtering by cluster name. - filtered, err := w.GetKubeServersByClusterName(context.Background(), kubeServers[0].GetName()) + filtered, err := w.CurrentResourcesWithFilter(context.Background(), func(ks readonly.KubeServer) bool { + return ks.GetName() == kubeServers[0].GetName() + }) require.NoError(t, err) require.Len(t, filtered, 1) // Test Deleting a kube server. require.NoError(t, presence.DeleteKubernetesServer(ctx, kubeServers[0].GetHostID(), kubeServers[0].GetName())) - require.Eventually(t, func() bool { - kube, err := w.GetKubernetesServers(context.Background()) + require.EventuallyWithT(t, func(t *assert.CollectT) { + kube, err := w.CurrentResources(context.Background()) assert.NoError(t, err) - return len(kube) == len(kubeServers)-1 + assert.Len(t, kube, len(kubeServers)-1) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive the delete event.") - filtered, err = w.GetKubeServersByClusterName(context.Background(), kubeServers[0].GetName()) - require.Error(t, err) + filtered, err = w.CurrentResourcesWithFilter(context.Background(), func(ks readonly.KubeServer) bool { + return ks.GetName() == kubeServers[0].GetName() + }) + require.NoError(t, err) require.Empty(t, filtered) // Test adding a kube server with the same name as an existing one. kubeServer := newKubeServer(t, kubeServers[1].GetName(), "addr", uuid.NewString()) _, err = presence.UpsertKubernetesServer(ctx, kubeServer) require.NoError(t, err) - require.Eventually(t, func() bool { - filtered, err := w.GetKubeServersByClusterName(context.Background(), kubeServers[1].GetName()) + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResourcesWithFilter(context.Background(), func(ks readonly.KubeServer) bool { + return ks.GetName() == kubeServers[1].GetName() + }) assert.NoError(t, err) - return len(filtered) == 2 - }, time.Second, time.Millisecond, "Timeout waiting for watcher to the new registered kube server.") + assert.Len(t, filtered, 2) + }, 1000*time.Second, time.Millisecond, "Timeout waiting for watcher to the new registered kube server.") // Test deleting all kube servers with the same name. - filtered, err = w.GetKubeServersByClusterName(context.Background(), kubeServers[1].GetName()) + filtered, err = w.CurrentResourcesWithFilter(context.Background(), func(ks readonly.KubeServer) bool { + return ks.GetName() == kubeServers[1].GetName() + }) assert.NoError(t, err) for _, server := range filtered { require.NoError(t, presence.DeleteKubernetesServer(ctx, server.GetHostID(), server.GetName())) } - require.Eventually(t, func() bool { - filtered, err := w.GetKubeServersByClusterName(context.Background(), kubeServers[1].GetName()) - return len(filtered) == 0 && err != nil + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResourcesWithFilter(context.Background(), func(ks readonly.KubeServer) bool { + return ks.GetName() == kubeServers[1].GetName() + }) + assert.NoError(t, err) + assert.Empty(t, filtered) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive the two delete events.") require.NoError(t, presence.DeleteAllKubernetesServers(ctx)) - require.Eventually(t, func() bool { - filtered, err := w.GetKubernetesServers(context.Background()) + require.EventuallyWithT(t, func(t *assert.CollectT) { + filtered, err := w.CurrentResources(context.Background()) assert.NoError(t, err) - return len(filtered) == 0 + assert.Empty(t, filtered) }, time.Second, time.Millisecond, "Timeout waiting for watcher to receive all delete events.") } diff --git a/lib/srv/app/server.go b/lib/srv/app/server.go index 83684289cdb3b..393086b69c1c2 100644 --- a/lib/srv/app/server.go +++ b/lib/srv/app/server.go @@ -40,6 +40,7 @@ import ( "github.com/gravitational/teleport/lib/labels" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/utils" ) @@ -153,7 +154,7 @@ type Server struct { reconcileCh chan struct{} // watcher monitors changes to application resources. - watcher *services.AppWatcher + watcher *services.GenericWatcher[types.Application, readonly.Application] } // monitoredApps is a collection of applications from different sources diff --git a/lib/srv/app/watcher.go b/lib/srv/app/watcher.go index ac355fd6b9fd2..c88e73dd7f5ab 100644 --- a/lib/srv/app/watcher.go +++ b/lib/srv/app/watcher.go @@ -28,6 +28,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/utils" ) @@ -67,7 +68,7 @@ func (s *Server) startReconciler(ctx context.Context) error { // startResourceWatcher starts watching changes to application resources and // registers/unregisters the proxied applications accordingly. -func (s *Server) startResourceWatcher(ctx context.Context) (*services.AppWatcher, error) { +func (s *Server) startResourceWatcher(ctx context.Context) (*services.GenericWatcher[types.Application, readonly.Application], error) { if len(s.c.ResourceMatchers) == 0 { s.log.DebugContext(ctx, "Not initializing application resource watcher.") return nil, nil @@ -80,6 +81,7 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.AppWatcher // Log: s.log, Client: s.c.AccessPoint, }, + AppGetter: s.c.AccessPoint, }) if err != nil { return nil, trace.Wrap(err) @@ -88,7 +90,7 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.AppWatcher defer watcher.Close() for { select { - case apps := <-watcher.AppsC: + case apps := <-watcher.ResourcesC: appsWithAddr := make(types.Apps, 0, len(apps)) for _, app := range apps { appsWithAddr = append(appsWithAddr, s.guessPublicAddr(app)) diff --git a/lib/srv/db/server.go b/lib/srv/db/server.go index 292615fe9f46e..10f54db7343f8 100644 --- a/lib/srv/db/server.go +++ b/lib/srv/db/server.go @@ -49,6 +49,7 @@ import ( "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/srv/db/cassandra" "github.com/gravitational/teleport/lib/srv/db/clickhouse" @@ -313,7 +314,7 @@ type Server struct { // heartbeats holds heartbeats for database servers. heartbeats map[string]srv.HeartbeatI // watcher monitors changes to database resources. - watcher *services.DatabaseWatcher + watcher *services.GenericWatcher[types.Database, readonly.Database] // proxiedDatabases contains databases this server currently is proxying. // Proxied databases are reconciled against monitoredDatabases below. proxiedDatabases map[string]types.Database diff --git a/lib/srv/db/watcher.go b/lib/srv/db/watcher.go index 58010eb6ad8d9..b65386a981247 100644 --- a/lib/srv/db/watcher.go +++ b/lib/srv/db/watcher.go @@ -27,6 +27,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" discovery "github.com/gravitational/teleport/lib/srv/discovery/common" dbfetchers "github.com/gravitational/teleport/lib/srv/discovery/fetchers/db" "github.com/gravitational/teleport/lib/utils" @@ -69,7 +70,7 @@ func (s *Server) startReconciler(ctx context.Context) error { // startResourceWatcher starts watching changes to database resources and // registers/unregisters the proxied databases accordingly. -func (s *Server) startResourceWatcher(ctx context.Context) (*services.DatabaseWatcher, error) { +func (s *Server) startResourceWatcher(ctx context.Context) (*services.GenericWatcher[types.Database, readonly.Database], error) { if len(s.cfg.ResourceMatchers) == 0 { s.log.DebugContext(ctx, "Not starting database resource watcher.") return nil, nil @@ -81,6 +82,7 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.DatabaseWa Logger: s.log, Client: s.cfg.AccessPoint, }, + DatabaseGetter: s.cfg.AccessPoint, }) if err != nil { return nil, trace.Wrap(err) @@ -90,7 +92,7 @@ func (s *Server) startResourceWatcher(ctx context.Context) (*services.DatabaseWa defer watcher.Close() for { select { - case databases := <-watcher.DatabasesC: + case databases := <-watcher.ResourcesC: s.monitoredDatabases.setResources(databases) select { case s.reconcileCh <- struct{}{}: diff --git a/lib/srv/desktop/discovery.go b/lib/srv/desktop/discovery.go index 6050309b35bbe..852468927e46c 100644 --- a/lib/srv/desktop/discovery.go +++ b/lib/srv/desktop/discovery.go @@ -39,6 +39,7 @@ import ( "github.com/gravitational/teleport/lib/auth/windows" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/utils" ) @@ -310,7 +311,7 @@ func (s *WindowsService) ldapEntryToWindowsDesktop( // startDynamicReconciler starts resource watcher and reconciler that registers/unregisters Windows desktops // according to the up-to-date list of dynamic Windows desktops resources. -func (s *WindowsService) startDynamicReconciler(ctx context.Context) (*services.DynamicWindowsDesktopWatcher, error) { +func (s *WindowsService) startDynamicReconciler(ctx context.Context) (*services.GenericWatcher[types.DynamicWindowsDesktop, readonly.DynamicWindowsDesktop], error) { if len(s.cfg.ResourceMatchers) == 0 { s.cfg.Logger.DebugContext(ctx, "Not starting dynamic desktop resource watcher.") return nil, nil @@ -353,7 +354,7 @@ func (s *WindowsService) startDynamicReconciler(ctx context.Context) (*services. defer watcher.Close() for { select { - case desktops := <-watcher.DynamicWindowsDesktopsC: + case desktops := <-watcher.ResourcesC: newResources = make(map[string]types.WindowsDesktop) for _, dynamicDesktop := range desktops { desktop, err := s.toWindowsDesktop(dynamicDesktop) diff --git a/lib/srv/discovery/discovery.go b/lib/srv/discovery/discovery.go index 6e93a8a8eddc6..095da62b6475f 100644 --- a/lib/srv/discovery/discovery.go +++ b/lib/srv/discovery/discovery.go @@ -55,6 +55,7 @@ import ( "github.com/gravitational/teleport/lib/cryptosuites" "github.com/gravitational/teleport/lib/integrations/awsoidc" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/srv/discovery/common" "github.com/gravitational/teleport/lib/srv/discovery/fetchers" aws_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/aws-sync" @@ -267,7 +268,7 @@ type Server struct { // cancelfn is used with ctx when stopping the discovery server cancelfn context.CancelFunc // nodeWatcher is a node watcher. - nodeWatcher *services.NodeWatcher + nodeWatcher *services.GenericWatcher[types.Server, readonly.Server] // ec2Watcher periodically retrieves EC2 instances. ec2Watcher *server.Watcher @@ -777,13 +778,16 @@ func (s *Server) initGCPWatchers(ctx context.Context, matchers []types.GCPMatche return nil } -func (s *Server) filterExistingEC2Nodes(instances *server.EC2Instances) { - nodes := s.nodeWatcher.GetNodes(s.ctx, func(n services.Node) bool { +func (s *Server) filterExistingEC2Nodes(instances *server.EC2Instances) error { + nodes, err := s.nodeWatcher.CurrentResourcesWithFilter(s.ctx, func(n readonly.Server) bool { labels := n.GetAllLabels() _, accountOK := labels[types.AWSAccountIDLabel] _, instanceOK := labels[types.AWSInstanceIDLabel] return accountOK && instanceOK }) + if err != nil { + return trace.Wrap(err) + } var filtered []server.EC2Instance outer: @@ -800,6 +804,7 @@ outer: filtered = append(filtered, inst) } instances.Instances = filtered + return nil } func genEC2InstancesLogStr(instances []server.EC2Instance) string { @@ -850,7 +855,9 @@ func (s *Server) handleEC2Instances(instances *server.EC2Instances) error { // EICE Nodes must never be filtered, so that we can extend their expiration and sync labels. totalInstancesFound := len(instances.Instances) if !instances.Rotation && instances.EnrollMode != types.InstallParamEnrollMode_INSTALL_PARAM_ENROLL_MODE_EICE { - s.filterExistingEC2Nodes(instances) + if err := s.filterExistingEC2Nodes(instances); err != nil { + return trace.Wrap(err) + } } instancesAlreadyEnrolled := totalInstancesFound - len(instances.Instances) @@ -904,12 +911,24 @@ func (s *Server) heartbeatEICEInstance(instances *server.EC2Instances) { continue } - existingNode, err := s.nodeWatcher.GetNode(s.ctx, eiceNode.GetName()) + existingNodes, err := s.nodeWatcher.CurrentResourcesWithFilter(s.ctx, func(s readonly.Server) bool { + return s.GetName() == eiceNode.GetName() + }) if err != nil && !trace.IsNotFound(err) { s.Log.Warnf("Error finding the existing node with name %q: %v", eiceNode.GetName(), err) continue } + var existingNode types.Server + switch len(existingNodes) { + case 0: + case 1: + existingNode = existingNodes[0] + default: + s.Log.Warnf("Found multiple matching nodes with name %q", eiceNode.GetName()) + continue + } + // EICE Node's Name are deterministic (based on the Account and Instance ID). // // To reduce load, nodes are skipped if @@ -1064,7 +1083,7 @@ func (s *Server) findUnrotatedEC2Nodes(ctx context.Context) ([]types.Server, err if err != nil { return nil, trace.Wrap(err) } - found := s.nodeWatcher.GetNodes(ctx, func(n services.Node) bool { + found, err := s.nodeWatcher.CurrentResourcesWithFilter(ctx, func(n readonly.Server) bool { if n.GetSubKind() != types.SubKindOpenSSHNode { return false } @@ -1077,6 +1096,9 @@ func (s *Server) findUnrotatedEC2Nodes(ctx context.Context) ([]types.Server, err return mostRecentCertRotation.After(n.GetRotation().LastRotated) }) + if err != nil { + return nil, trace.Wrap(err) + } if len(found) == 0 { return nil, trace.NotFound("no unrotated nodes found") @@ -1118,13 +1140,18 @@ func (s *Server) handleEC2Discovery() { } } -func (s *Server) filterExistingAzureNodes(instances *server.AzureInstances) { - nodes := s.nodeWatcher.GetNodes(s.ctx, func(n services.Node) bool { +func (s *Server) filterExistingAzureNodes(instances *server.AzureInstances) error { + nodes, err := s.nodeWatcher.CurrentResourcesWithFilter(s.ctx, func(n readonly.Server) bool { labels := n.GetAllLabels() _, subscriptionOK := labels[types.SubscriptionIDLabel] _, vmOK := labels[types.VMIDLabel] return subscriptionOK && vmOK }) + + if err != nil { + return trace.Wrap(err) + } + var filtered []*armcompute.VirtualMachine outer: for _, inst := range instances.Instances { @@ -1144,6 +1171,7 @@ outer: filtered = append(filtered, inst) } instances.Instances = filtered + return nil } func (s *Server) handleAzureInstances(instances *server.AzureInstances) error { @@ -1151,7 +1179,9 @@ func (s *Server) handleAzureInstances(instances *server.AzureInstances) error { if err != nil { return trace.Wrap(err) } - s.filterExistingAzureNodes(instances) + if err := s.filterExistingAzureNodes(instances); err != nil { + return trace.Wrap(err) + } if len(instances.Instances) == 0 { return trace.Wrap(errNoInstances) } @@ -1206,14 +1236,19 @@ func (s *Server) handleAzureDiscovery() { } } -func (s *Server) filterExistingGCPNodes(instances *server.GCPInstances) { - nodes := s.nodeWatcher.GetNodes(s.ctx, func(n services.Node) bool { +func (s *Server) filterExistingGCPNodes(instances *server.GCPInstances) error { + nodes, err := s.nodeWatcher.CurrentResourcesWithFilter(s.ctx, func(n readonly.Server) bool { labels := n.GetAllLabels() _, projectIDOK := labels[types.ProjectIDLabelDiscovery] _, zoneOK := labels[types.ZoneLabelDiscovery] _, nameOK := labels[types.NameLabelDiscovery] return projectIDOK && zoneOK && nameOK }) + + if err != nil { + return trace.Wrap(err) + } + var filtered []*gcpimds.Instance outer: for _, inst := range instances.Instances { @@ -1230,6 +1265,7 @@ outer: filtered = append(filtered, inst) } instances.Instances = filtered + return nil } func (s *Server) handleGCPInstances(instances *server.GCPInstances) error { @@ -1237,7 +1273,9 @@ func (s *Server) handleGCPInstances(instances *server.GCPInstances) error { if err != nil { return trace.Wrap(err) } - s.filterExistingGCPNodes(instances) + if err := s.filterExistingGCPNodes(instances); err != nil { + return trace.Wrap(err) + } if len(instances.Instances) == 0 { return trace.Wrap(errNoInstances) } @@ -1730,6 +1768,7 @@ func (s *Server) initTeleportNodeWatcher() (err error) { Client: s.AccessPoint, MaxStaleness: time.Minute, }, + NodesGetter: s.AccessPoint, }) return trace.Wrap(err) diff --git a/lib/srv/discovery/discovery_test.go b/lib/srv/discovery/discovery_test.go index 974dd1bfcdad1..ab384e65d74f5 100644 --- a/lib/srv/discovery/discovery_test.go +++ b/lib/srv/discovery/discovery_test.go @@ -852,11 +852,10 @@ func TestDiscoveryServerConcurrency(t *testing.T) { // We must get only one EC2 EICE Node. // Even when two servers are discovering the same EC2 Instance, they will use the same name when converting to EICE Node. - require.Eventually(t, func() bool { + require.EventuallyWithT(t, func(t *assert.CollectT) { allNodes, err := tlsServer.Auth().GetNodes(ctx, "default") - require.NoError(t, err) - - return len(allNodes) == 1 + assert.NoError(t, err) + assert.Len(t, allNodes, 1) }, 1*time.Second, 50*time.Millisecond) // We should never get a duplicate instance. diff --git a/lib/srv/regular/sshserver_test.go b/lib/srv/regular/sshserver_test.go index 42df4c9d4017c..8d6a64154ee9b 100644 --- a/lib/srv/regular/sshserver_test.go +++ b/lib/srv/regular/sshserver_test.go @@ -70,6 +70,7 @@ import ( "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" sess "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/sshutils" @@ -2865,12 +2866,13 @@ func newLockWatcher(ctx context.Context, t testing.TB, client types.Events) *ser return lockWatcher } -func newNodeWatcher(ctx context.Context, t *testing.T, client types.Events) *services.NodeWatcher { +func newNodeWatcher(ctx context.Context, t *testing.T, client *authclient.Client) *services.GenericWatcher[types.Server, readonly.Server] { nodeWatcher, err := services.NewNodeWatcher(ctx, services.NodeWatcherConfig{ ResourceWatcherConfig: services.ResourceWatcherConfig{ Component: "test", Client: client, }, + NodesGetter: client, }) require.NoError(t, err) t.Cleanup(nodeWatcher.Close) diff --git a/lib/utils/fncache.go b/lib/utils/fncache.go index e45a8b3a2d821..84f5be17478bb 100644 --- a/lib/utils/fncache.go +++ b/lib/utils/fncache.go @@ -245,6 +245,8 @@ func FnCacheGetWithTTL[T any](ctx context.Context, cache *FnCache, key any, ttl switch { case err != nil: return ret, err + case t == nil: + return ret, nil case !ok: return ret, trace.BadParameter("value retrieved was %T, expected %T", t, ret) } diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index faaffa2ff3e1e..d45effc964395 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -98,6 +98,7 @@ import ( "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/secret" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -164,7 +165,7 @@ type Handler struct { // nodeWatcher is a services.NodeWatcher used by Assist to lookup nodes from // the proxy's cache and get nodes in real time. - nodeWatcher *services.NodeWatcher + nodeWatcher *services.GenericWatcher[types.Server, readonly.Server] // tracer is used to create spans. tracer oteltrace.Tracer @@ -300,7 +301,7 @@ type Config struct { // NodeWatcher is a services.NodeWatcher used by Assist to lookup nodes from // the proxy's cache and get nodes in real time. - NodeWatcher *services.NodeWatcher + NodeWatcher *services.GenericWatcher[types.Server, readonly.Server] // PresenceChecker periodically runs the mfa ceremony for moderated // sessions. @@ -3544,9 +3545,12 @@ func (h *Handler) siteNodeConnect( WebsocketConn: ws, SSHDialTimeout: dialTimeout, HostNameResolver: func(serverID string) (string, error) { - matches := nw.GetNodes(r.Context(), func(n services.Node) bool { + matches, err := nw.CurrentResourcesWithFilter(r.Context(), func(n readonly.Server) bool { return n.GetName() == serverID }) + if err != nil { + return "", trace.Wrap(err) + } if len(matches) != 1 { return "", trace.NotFound("unable to resolve hostname for server %s", serverID) diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 5e3fea922d245..a585579f7ddda 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -381,6 +381,7 @@ func newWebSuiteWithConfig(t *testing.T, cfg webSuiteConfig) *WebSuite { Component: teleport.ComponentProxy, Client: s.proxyClient, }, + NodesGetter: s.proxyClient, }) require.NoError(t, err) @@ -8185,6 +8186,7 @@ func createProxy(ctx context.Context, t *testing.T, proxyID string, node *regula Component: teleport.ComponentProxy, Client: client, }, + NodesGetter: client, }) require.NoError(t, err) t.Cleanup(proxyNodeWatcher.Close) @@ -9075,6 +9077,7 @@ func startKubeWithoutCleanup(ctx context.Context, t *testing.T, cfg startKubeOpt Client: client, Clock: clock, }, + KubernetesServerGetter: client, }) require.NoError(t, err) From ae4ae8c70735521ea015dd87a5bdef4bf4311a34 Mon Sep 17 00:00:00 2001 From: Lisa Kim Date: Mon, 28 Oct 2024 11:54:50 -0700 Subject: [PATCH 18/22] Update e (#48026) --- e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e b/e index 84f36a00ae432..c8b2aed1f1c9d 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit 84f36a00ae432a6d8b08d6b84dd56a4970402bcf +Subproject commit c8b2aed1f1c9d059e8853163486214778dcb08b0 From acdda108e00e844ed1d1d51099f45d57b530551a Mon Sep 17 00:00:00 2001 From: Paul Gottschling Date: Mon, 28 Oct 2024 15:02:25 -0400 Subject: [PATCH 19/22] Add troubleshooting info to Usage and Billing page (#47969) Turn the section on validating usage data into the intro paragraph for a troubleshooting section. We don't actually need to compare the usage reporting system to audit events, and removing the comparison makes this information concise enough for an introductory paragraph. Add H2s for issues we have identified with usage reporting and billing on self-hosted clusters. --- docs/pages/usage-billing.mdx | 71 ++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/docs/pages/usage-billing.mdx b/docs/pages/usage-billing.mdx index f3a0f1a2ab4c9..3465c5a84bbc7 100644 --- a/docs/pages/usage-billing.mdx +++ b/docs/pages/usage-billing.mdx @@ -64,25 +64,6 @@ Set the `TELEPORT_REPORTING_HTTPS_PROXY` and `TELEPORT_REPORTING_HTTP_PROXY` environment variables to your proxy address. That will apply as the HTTP connect proxy setting overriding `HTTPS_PROXY` and `HTTP_PROXY` just for outbound usage reporting. -### Validating usage reports - -The system that Teleport uses for submitting usage reports is independent of the -system that Teleport uses for submitting audit events. - -Teleport processes submit audit events to the Teleport Auth Service, which -stores them on its audit event backend for retrieval by Teleport API clients. In -contrast, usage reports are aggregated on a submission service that runs either -on self-hosted Teleport infrastructure or Teleport Cloud, depending on the -user's plan. The submission service persists usage reports in the case of a -submission failure. After a successful submission, the submission service -deletes the reports. - -It is not possible for Teleport users to independently validate usage event -data, as there is no way to set up a third-party usage event destination or -retrieve usage events from a Teleport backend. Reach out to -support@goteleport.com if you have questions about usage reporting on your -Teleport account. - ## Billing metrics Teleport uses the anonymized usage data described in the previous section to @@ -144,6 +125,11 @@ to compute a daily TPR. Then we average the daily TPR over a monthly period, which starts on the subscription start date and ends on each monthly anniversary thereafter. +If you recreate a single resource more than once an hour, this will affect the +hourly average. For example, if were to create then delete 10 servers three +times in one hour, Teleport would display 10 servers at any given time. However, +for the entire hour, Teleport would report 30 protected servers. + ## Usage measurement for billing We aggregate all counts of the billing metrics on a monthly basis starting on @@ -155,3 +141,50 @@ Subscription, also known as a high water mark calculation. Reach out to sales@goteleport.com if you have questions about the commercial editions of Teleport. + +## Troubleshooting usage and billing + +Teleport aggregates usage reports on a submission service that runs either on +self-hosted Teleport infrastructure or Teleport Cloud, depending on the user's +plan. The submission service persists usage reports in the case of a submission +failure, and deletes the reports after a successful submission. It is not +possible to set up a third-party destination for usage events to independently +verify usage event data. + +If you are using Teleport Enterprise (Cloud), your usage data is accurate as +long as Teleport-managed reporting infrastructure works as expected (check the +[status page](https://status.teleport.sh/) for any incidents). On self-hosted +Teleport Enterprise clusters, some conditions can interfere with data reporting. +This section describes some scenarios that can lead to inaccurate data on +self-hosted clusters. + +If you suspect that any of these scenarios describe your Teleport cluster, or +your usage data appears inaccurate, reach out to support@goteleport.com. + +### Multiple Teleport clusters + +In versions older than v14.3.1, Teleport does not de-duplicate users as expected +across multiple Teleport clusters that belong to the same account. If you are +running multiple Teleport clusters with affected versions, the count of active +users may be higher than expected. + +### Unexpected license differences + +When distributing copies of your Teleport Enterprise (Self-Hosted) license +across Auth Service instances, you must not download a license multiple times +from your Teleport account. Instead, you must download a license once and copy +that license across Auth Service instances. Otherwise, the Teleport usage +reporting infrastructure will identify multiple licenses and misrepresent your +usage numbers. + +### SSO users + +In Teleport, single sign-on (SSO) users are +[ephemeral](reference/user-types.mdx#temporary-users). Teleport deletes an SSO user +when its session expires. To count the number of SSO users in your cluster, you +can examine Teleport audit events for unique SSO users that have authenticated +to Teleport during a given time period. The Teleport documentation includes +[how-to guides](./admin-guides/management/export-audit-events/export-audit-events.mdx) for +exporting audit events to common log management solutions so you can identify +users that have authenticated using an SSO provider. + From cc89f5743dbff5b37a38b1362bce516468eb5ce4 Mon Sep 17 00:00:00 2001 From: Hugo Shaka Date: Mon, 28 Oct 2024 15:46:21 -0400 Subject: [PATCH 20/22] cache /find endpoint (#48016) * cache /find endpoint * address feedback * typo in godoc --- lib/web/apiserver.go | 120 ++++++++++++++++++++------------- lib/web/apiserver_ping_test.go | 5 ++ 2 files changed, 79 insertions(+), 46 deletions(-) diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index d45effc964395..de4d085377c3c 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -131,6 +131,10 @@ const ( // DefaultFeatureWatchInterval is the default time in which the feature watcher // should ping the auth server to check for updated features DefaultFeatureWatchInterval = time.Minute * 5 + // findEndpointCacheTTL is the cache TTL for the find endpoint generic answer. + // This cache is here to protect against accidental or intentional DDoS, the TTL must be low to quickly reflect + // cluster configuration changes. + findEndpointCacheTTL = 10 * time.Second ) // healthCheckAppServerFunc defines a function used to perform a health check @@ -174,6 +178,11 @@ type Handler struct { // an authenticated websocket so unauthenticated sockets dont get left // open. wsIODeadline time.Duration + + // findEndpointCache is used to cache the find endpoint answer. As this endpoint is unprotected and has high + // rate-limits, each call must cause minimal work. The cached answer can be modulated after, for example if the + // caller specified its Automatic Updates UUID or group. + findEndpointCache *utils.FnCache } // HandlerOption is a functional argument - an option that can be passed @@ -478,6 +487,18 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*APIHandler, error) { } } + // We create the cache after applying the options to make sure we use the fake clock if it was passed. + findCache, err := utils.NewFnCache(utils.FnCacheConfig{ + TTL: findEndpointCacheTTL, + Clock: h.clock, + Context: cfg.Context, + ReloadOnErr: false, + }) + if err != nil { + return nil, trace.Wrap(err, "creating /find cache") + } + h.findEndpointCache = findCache + sessionLingeringThreshold := cachedSessionLingeringThreshold if cfg.CachedSessionLingeringThreshold != nil { sessionLingeringThreshold = *cfg.CachedSessionLingeringThreshold @@ -1522,56 +1543,63 @@ func (h *Handler) ping(w http.ResponseWriter, r *http.Request, p httprouter.Para } func (h *Handler) find(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { - // TODO(jent,espadolini): add a time-based cache to further reduce load on this endpoint - proxyConfig, err := h.cfg.ProxySettings.GetProxySettings(r.Context()) - if err != nil { - return nil, trace.Wrap(err) - } - authPref, err := h.cfg.AccessPoint.GetAuthPreference(r.Context()) - if err != nil { - return nil, trace.Wrap(err) - } - response := webclient.PingResponse{ - Auth: webclient.AuthenticationSettings{ - // Nodes need the signature algorithm suite when joining to generate - // keys with the correct algorithm. - SignatureAlgorithmSuite: authPref.GetSignatureAlgorithmSuite(), - }, - Proxy: *proxyConfig, - ServerVersion: teleport.Version, - MinClientVersion: teleport.MinClientVersion, - ClusterName: h.auth.clusterName, - } + // cache the generic answer to avoid doing work for each request + resp, err := utils.FnCacheGet[*webclient.PingResponse](r.Context(), h.findEndpointCache, "find", func(ctx context.Context) (*webclient.PingResponse, error) { + response := webclient.PingResponse{ + ServerVersion: teleport.Version, + MinClientVersion: teleport.MinClientVersion, + ClusterName: h.auth.clusterName, + } - autoUpdateConfig, err := h.cfg.AccessPoint.GetAutoUpdateConfig(r.Context()) - // TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions. - if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) { - h.logger.ErrorContext(r.Context(), "failed to receive AutoUpdateConfig", "error", err) - } - // If we can't get the AU config or tools AU are not configured, we default to "disabled". - // This ensures we fail open and don't accidentally update agents if something is going wrong. - // If we want to enable AUs by default, it would be better to create a default "autoupdate_config" resource - // than changing this logic. - if autoUpdateConfig.GetSpec().GetTools() == nil { - response.AutoUpdate.ToolsMode = autoupdate.ToolsUpdateModeDisabled - } else { - response.AutoUpdate.ToolsMode = autoUpdateConfig.GetSpec().GetTools().GetMode() - } + proxyConfig, err := h.cfg.ProxySettings.GetProxySettings(r.Context()) + if err != nil { + return nil, trace.Wrap(err) + } + response.Proxy = *proxyConfig - autoUpdateVersion, err := h.cfg.AccessPoint.GetAutoUpdateVersion(r.Context()) - // TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions. - if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) { - h.logger.ErrorContext(r.Context(), "failed to receive AutoUpdateVersion", "error", err) - } - // If we can't get the AU version or tools AU version is not specified, we default to the current proxy version. - // This ensures we always advertise a version compatible with the cluster. - if autoUpdateVersion.GetSpec().GetTools() == nil { - response.AutoUpdate.ToolsVersion = api.Version - } else { - response.AutoUpdate.ToolsVersion = autoUpdateVersion.GetSpec().GetTools().GetTargetVersion() + authPref, err := h.cfg.AccessPoint.GetAuthPreference(r.Context()) + if err != nil { + return nil, trace.Wrap(err) + } + response.Auth = webclient.AuthenticationSettings{SignatureAlgorithmSuite: authPref.GetSignatureAlgorithmSuite()} + + autoUpdateConfig, err := h.cfg.AccessPoint.GetAutoUpdateConfig(r.Context()) + // TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions. + if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) { + h.logger.ErrorContext(r.Context(), "failed to receive AutoUpdateConfig", "error", err) + } + // If we can't get the AU config or tools AU are not configured, we default to "disabled". + // This ensures we fail open and don't accidentally update agents if something is going wrong. + // If we want to enable AUs by default, it would be better to create a default "autoupdate_config" resource + // than changing this logic. + if autoUpdateConfig.GetSpec().GetTools() == nil { + response.AutoUpdate.ToolsMode = autoupdate.ToolsUpdateModeDisabled + } else { + response.AutoUpdate.ToolsMode = autoUpdateConfig.GetSpec().GetTools().GetMode() + } + + autoUpdateVersion, err := h.cfg.AccessPoint.GetAutoUpdateVersion(r.Context()) + // TODO(vapopov) DELETE IN v18.0.0 check of IsNotImplemented, must be backported to all latest supported versions. + if err != nil && !trace.IsNotFound(err) && !trace.IsNotImplemented(err) { + h.logger.ErrorContext(r.Context(), "failed to receive AutoUpdateVersion", "error", err) + } + // If we can't get the AU version or tools AU version is not specified, we default to the current proxy version. + // This ensures we always advertise a version compatible with the cluster. + if autoUpdateVersion.GetSpec().GetTools() == nil { + response.AutoUpdate.ToolsVersion = api.Version + } else { + response.AutoUpdate.ToolsVersion = autoUpdateVersion.GetSpec().GetTools().GetTargetVersion() + } + + return &response, nil + }) + if err != nil { + return nil, trace.Wrap(err) } - return response, nil + // If you need to modulate the response based on the request params (will need to do this for automatic updates) + // Do it here. + return resp, nil } func (h *Handler) pingWithConnector(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) { diff --git a/lib/web/apiserver_ping_test.go b/lib/web/apiserver_ping_test.go index 903a204fe2228..231c8625ffacd 100644 --- a/lib/web/apiserver_ping_test.go +++ b/lib/web/apiserver_ping_test.go @@ -395,6 +395,11 @@ func TestPing_autoUpdateResources(t *testing.T) { require.NoError(t, err) } + // expire the fn cache to force the next answer to be fresh + for _, proxy := range env.proxies { + proxy.clock.Advance(2 * findEndpointCacheTTL) + } + resp, err := client.NewInsecureWebClient().Do(req) require.NoError(t, err) From 916a557a7b5e49b812dae6e48449ff28a48b64bf Mon Sep 17 00:00:00 2001 From: "STeve (Xin) Huang" Date: Mon, 28 Oct 2024 16:54:07 -0400 Subject: [PATCH 21/22] update test plan for db access (#48039) --- .github/ISSUE_TEMPLATE/testplan.md | 54 +++++++++++++++++++----------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/testplan.md b/.github/ISSUE_TEMPLATE/testplan.md index 870e9592e8b31..7110906b6a0da 100644 --- a/.github/ISSUE_TEMPLATE/testplan.md +++ b/.github/ISSUE_TEMPLATE/testplan.md @@ -979,10 +979,14 @@ manualy testing. - [ ] Self-hosted MariaDB. - [ ] Self-hosted MongoDB. - [ ] Self-hosted CockroachDB. - - [ ] Self-hosted Redis. + - [ ] Self-hosted Redis/Valkey. - [ ] Self-hosted Redis Cluster. - [ ] Self-hosted MSSQL. - [ ] Self-hosted MSSQL with PKINIT authentication. + - [ ] Self-hosted Elasticsearch. + - [ ] Self-hosted Cassandra/ScyllaDB. + - [ ] Self-hosted Oracle. + - [ ] Self-hosted ClickHouse. - [ ] AWS Aurora Postgres. - [ ] AWS Aurora MySQL. - [ ] MySQL server version reported by Teleport is correct. @@ -992,32 +996,36 @@ manualy testing. - [ ] Verify connection to external AWS account works with `assume_role_arn: ""` and `external_id: ""` - [ ] AWS ElastiCache. - [ ] AWS MemoryDB. + - [ ] AWS OpenSearch. + - [ ] AWS Dynamodb. + - [ ] Verify connection to external AWS account works with `assume_role_arn: ""` and `external_id: ""` + - [ ] AWS DocumentDB + - [ ] AWS Keyspaces + - [ ] Verify connection to external AWS account works with `assume_role_arn: ""` and `external_id: ""` - [ ] GCP Cloud SQL Postgres. - [ ] GCP Cloud SQL MySQL. - [ ] GCP Cloud Spanner. - - [ ] Snowflake. - [ ] Azure Cache for Redis. - [x] Azure single-server MySQL and Postgres (EOL Sep 2024 and Mar 2025, skip) - - [ ] Azure flexible-server MySQL and Postgres - - [ ] Elasticsearch. - - [ ] OpenSearch. - - [ ] Cassandra/ScyllaDB. - - [ ] Verify connection to external AWS account works with `assume_role_arn: ""` and `external_id: ""` - - [ ] Dynamodb. - - [ ] Verify connection to external AWS account works with `assume_role_arn: ""` and `external_id: ""` + - [ ] Azure flexible-server MySQL + - [ ] Azure flexible-server Postgres - [ ] Azure SQL Server. - - [ ] Oracle. - - [ ] ClickHouse. + - [ ] Snowflake. + - [ ] MongoDB Atlas. - [ ] Connect to a database within a remote cluster via a trusted cluster. - [ ] Self-hosted Postgres. - [ ] Self-hosted MySQL. - [ ] Self-hosted MariaDB. - [ ] Self-hosted MongoDB. - [ ] Self-hosted CockroachDB. - - [ ] Self-hosted Redis. + - [ ] Self-hosted Redis/Valkey. - [ ] Self-hosted Redis Cluster. - [ ] Self-hosted MSSQL. - [ ] Self-hosted MSSQL with PKINIT authentication. + - [ ] Self-hosted Elasticsearch. + - [ ] Self-hosted Cassandra/ScyllaDB. + - [ ] Self-hosted Oracle. + - [ ] Self-hosted ClickHouse. - [ ] AWS Aurora Postgres. - [ ] AWS Aurora MySQL. - [ ] AWS RDS Proxy (MySQL, Postgres, MariaDB, or SQL Server) @@ -1025,20 +1033,20 @@ manualy testing. - [ ] AWS Redshift Serverless. - [ ] AWS ElastiCache. - [ ] AWS MemoryDB. + - [ ] AWS OpenSearch. + - [ ] AWS Dynamodb. + - [ ] AWS DocumentDB + - [ ] AWS Keyspaces - [ ] GCP Cloud SQL Postgres. - [ ] GCP Cloud SQL MySQL. - [ ] GCP Cloud Spanner. - - [ ] Snowflake. - [ ] Azure Cache for Redis. - [x] Azure single-server MySQL and Postgres (EOL Sep 2024 and Mar 2025, skip) - - [ ] Azure flexible-server MySQL and Postgres - - [ ] Elasticsearch. - - [ ] OpenSearch. - - [ ] Cassandra/ScyllaDB. - - [ ] Dynamodb. + - [ ] Azure flexible-server MySQL + - [ ] Azure flexible-server Postgres - [ ] Azure SQL Server. - - [ ] Oracle. - - [ ] ClickHouse. + - [ ] Snowflake. + - [ ] MongoDB Atlas. - [ ] Verify auto user provisioning. Verify all supported modes: `keep`, `best_effort_drop` - [ ] Self-hosted Postgres. @@ -1084,6 +1092,7 @@ manualy testing. - [ ] Can detect and register ElastiCache Redis clusters. - [ ] Can detect and register MemoryDB clusters. - [ ] Can detect and register OpenSearch domains. + - [ ] Can detect and register DocumentDB clusters. - [ ] Azure - [ ] Can detect and register MySQL and Postgres single-server instances. - [ ] Can detect and register MySQL and Postgres flexible-server instances. @@ -1098,6 +1107,11 @@ manualy testing. - [ ] Verify searching for all columns in the search bar works - [ ] Verify you can sort by all columns except `labels` - [ ] `tsh bench` load tests (instructions on Notion -> Database Access -> Load test) +- [ ] Verify database session player + - [ ] Web UI + - [ ] Postgres + - [ ] `tsh play` + - [ ] Postgres ## TLS Routing From 872b97ac5e1867b4b0562ca47b5cda9bbc0533f5 Mon Sep 17 00:00:00 2001 From: Zac Bergquist Date: Mon, 28 Oct 2024 16:00:55 -0600 Subject: [PATCH 22/22] Fix some LDAP connection bugs (#48041) In #36281 we made some improvements to the LDAP reconnect behavior. These changes considered the case where we had a connection to the LDAP server but then got disconnected. They did not consider the case where we never succesfully established a connection at all. --- lib/srv/desktop/discovery.go | 10 ++++++++++ lib/srv/desktop/windows_server.go | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/srv/desktop/discovery.go b/lib/srv/desktop/discovery.go index 852468927e46c..0e22d2487a802 100644 --- a/lib/srv/desktop/discovery.go +++ b/lib/srv/desktop/discovery.go @@ -100,6 +100,16 @@ func (s *WindowsService) ldapSearchFilter() string { // getDesktopsFromLDAP discovers Windows hosts via LDAP func (s *WindowsService) getDesktopsFromLDAP() map[string]types.WindowsDesktop { + // Check whether we've ever successfully initialized our LDAP client. + s.mu.Lock() + if !s.ldapInitialized { + s.cfg.Logger.DebugContext(context.Background(), "LDAP not ready, skipping discovery and attempting to reconnect") + s.mu.Unlock() + s.initializeLDAP() + return nil + } + s.mu.Unlock() + filter := s.ldapSearchFilter() s.cfg.Logger.DebugContext(context.Background(), "searching for desktops", "filter", filter) diff --git a/lib/srv/desktop/windows_server.go b/lib/srv/desktop/windows_server.go index 77b272acd0696..fd75cbc89bd04 100644 --- a/lib/srv/desktop/windows_server.go +++ b/lib/srv/desktop/windows_server.go @@ -450,7 +450,20 @@ func (s *WindowsService) startLDAPConnectionCheck(ctx context.Context) { for { select { case <-t.Chan(): - // attempt to read CAs in the NTAuth store (we know we have permissions to do so) + // First check if we have successfully initialized the LDAP client. + // If not, then do that now and return. + // (This mimics the check that is performed when LDAP discovery is enabled.) + s.mu.Lock() + if !s.ldapInitialized { + s.cfg.Logger.DebugContext(context.Background(), "LDAP not ready, attempting to reconnect") + s.mu.Unlock() + s.initializeLDAP() + return + } + s.mu.Unlock() + + // If we have initizlied the LDAP client, then try to use it to make sure we're still connected + // by attempting to read CAs in the NTAuth store (we know we have permissions to do so). ntAuthDN := "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration," + s.cfg.LDAPConfig.DomainDN() _, err := s.lc.Read(ntAuthDN, "certificationAuthority", []string{"cACertificate"}) if trace.IsConnectionProblem(err) {
+ + + + + {getPrettyResourceKind(item.kind)} + {item.name} - )} - {userGroupFetchAttempt?.status === 'failed' && ( - {userGroupFetchAttempt.statusText} - )} - {userGroupFetchAttempt?.status === 'success' && - appsGrantedByUserGroup.length > 0 && ( - - )} - {isResourceRequest && ( - - )} - - r.name) ?? []} - selectedReviewers={selectedReviewers} - setSelectedReviewers={setSelectedReviewers} + + + + +