diff --git a/.github/workflows/doc-tests.yaml b/.github/workflows/doc-tests.yaml index e4463ddba2530..54df4b0743ef2 100644 --- a/.github/workflows/doc-tests.yaml +++ b/.github/workflows/doc-tests.yaml @@ -50,7 +50,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - repository: 'gravitational/docs' + repository: 'gravitational/docs-website' path: 'docs' # Cache node_modules. Unlike the example in the actions/cache repo, this @@ -80,30 +80,35 @@ jobs: # use for the live docs site in that we only test a single version of # the content. # - # To do this, we replace the three submodules we use for building the - # live docs site with a single submodule, pointing to the - # gravitational/teleport branch we are linting. - # + # To do this, we delete the three submodules we use for building the + # live docs site and copy a gravitational/teleport clone into the + # content directory. + # # The docs engine expects a config.json file at the root of the # gravitational/docs clone that associates directories with git # submodules. By default, these directories represent versioned branches # of gravitational/teleport. We override this in order to build only a # single version of the docs. + # + # We also replace data fetched from Sanity CMS with hardcoded JSON + # objects to remove the need to authenticate with Sanity. Each includes + # the minimal set of data required for docs builds to succeed. run: | echo "" > .gitmodules rm -rf content/* - cd content # Rather than using a submodule, copy the teleport source into the # content directory. - cp -r $GITHUB_WORKSPACE/teleport $GITHUB_WORKSPACE/docs/content - cd $GITHUB_WORKSPACE/docs - echo "{\"versions\": [{\"name\": \"teleport\", \"branch\": \"teleport\", \"deprecated\": false}]}" > $GITHUB_WORKSPACE/docs/config.json - cat <<< "$(jq '.scripts."git-update" = "echo Skipping submodule update"' package.json)" > package.json - yarn build-node + cp -r "$GITHUB_WORKSPACE/teleport" "$GITHUB_WORKSPACE/docs/content/current" + jq -nr --arg version "current" '{"versions": [{"name": $version,"branch": $version,"deprecated": false,"isDefault": true}]}' > config.json + NEW_PACKAGE_JSON=$(jq '.scripts."git-update" = "echo Skipping submodule update"' package.json); + NEW_PACKAGE_JSON=$(jq '.scripts."prepare-sanity-data" = "echo Using pre-populated Sanity data"' <<< "$NEW_PACKAGE_JSON"); + echo "$NEW_PACKAGE_JSON" > package.json; + echo "{}" > data/events.json + echo '{"bannerButtons":{"second":{"title":"LOG IN","url":"https://teleport.sh"},"first":{"title":"Support","url":"https://goteleport.com/support/"}},"navbarData":{"rightSide":{},"logo":"/favicon.svg","menu":[]}}' > data/navbar.json - name: Check spelling working-directory: 'docs' - run: yarn spellcheck content/teleport + run: yarn spellcheck content/current - name: Lint docs formatting working-directory: 'docs' diff --git a/.github/workflows/docs-amplify.yaml b/.github/workflows/docs-amplify.yaml new file mode 100644 index 0000000000000..3ca12933b50c1 --- /dev/null +++ b/.github/workflows/docs-amplify.yaml @@ -0,0 +1,42 @@ +name: Docs Preview +on: + pull_request: + paths: + - 'docs/**' + - .github/workflows/docs-amplify.yaml + workflow_dispatch: + +permissions: + pull-requests: write + id-token: write + +jobs: + amplify-preview: + name: Prepare Amplify preview URL + runs-on: ubuntu-22.04-2core-arm64 + environment: docs-amplify + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4 + with: + aws-region: us-west-2 + role-to-assume: ${{ vars.IAM_ROLE }} + + - name: Create Amplify preview environment + uses: gravitational/shared-workflows/tools/amplify-preview@tools/amplify-preview/v0.0.1 + continue-on-error: true + with: + app_ids: ${{ vars.AMPLIFY_APP_IDS }} + create_branches: "true" + github_token: ${{ secrets.GITHUB_TOKEN }} + wait: "true" + + - name: Print failure message + if: failure() + env: + ERR_TITLE: Teleport Docs preview build failed + ERR_MESSAGE: >- + Please refer to the following documentation for help: https://www.notion.so/goteleport/How-to-Amplify-deployments-162fdd3830be8096ba72efa1a49ee7bc?pvs=4 + run: | + echo ::error title=$ERR_TITLE::$ERR_MESSAGE + exit 1 diff --git a/.github/workflows/update-docs-webhook.yaml b/.github/workflows/update-docs-webhook.yaml index 7f46fb51996ac..4c59c66039cbd 100644 --- a/.github/workflows/update-docs-webhook.yaml +++ b/.github/workflows/update-docs-webhook.yaml @@ -15,18 +15,11 @@ jobs: environment: update-docs strategy: fail-fast: false - matrix: - webhooks: - - url_secret_name: DOCS_DEPLOY_HOOK - http_method: GET - - url_secret_name: AMPLIFY_DOCS_DEPLOY_HOOK - http_method: POST steps: - name: Call deployment webhook env: - WEBHOOK_URL: ${{ secrets[matrix.webhooks.url_secret_name] }} - HTTP_METHOD: ${{ matrix.webhooks.http_method }} + WEBHOOK_URL: ${{ secrets[AMPLIFY_DOCS_DEPLOY_HOOK] }} run: | - if curl -X "$HTTP_METHOD" --silent --fail --show-error "$WEBHOOK_URL" > /dev/null; then + if curl -X POST --silent --fail --show-error "$WEBHOOK_URL" > /dev/null; then echo "Triggered successfully" fi diff --git a/.github/workflows/vercel-preview.yaml b/.github/workflows/vercel-preview.yaml deleted file mode 100644 index f74b3086138c0..0000000000000 --- a/.github/workflows/vercel-preview.yaml +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: Deploy Vercel Preview -permissions: - # Required in order to comment on PRs with a deployment link - pull-requests: write -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} - -on: - pull_request: - paths: - - 'docs/**' - - .github/workflows/vercel-preview.yaml - types: [opened, reopened, synchronize] - workflow_dispatch: - -jobs: - deploy-vercel-preview: - name: Deploy Vercel preview - runs-on: ubuntu-latest - environment: vercel - - steps: - - name: Extract branch name - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT - id: extract_branch - - uses: actions/checkout@v4 - with: - repository: 'gravitational/docs' - - name: Configure Submodules - env: - BRANCH: ${{ steps.extract_branch.outputs.branch }} - # Edit config.json and .gitmodules so there is a single submodule - # pointing to the version of the docs to deploy to the preview site. - run: | - git rm content/* - git submodule add --force -b "${BRANCH}" https://github.com/gravitational/teleport content/preview - echo "{\"versions\": [{\"name\": \"preview\", \"branch\": \"preview\", \"deprecated\": false, \"latest\": true}]}" > config.json - git submodule update --init --remote --progress - - name: Install Vercel CLI - run: yarn global add vercel@latest - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - name: Deploy Project Artifacts to Vercel - id: deploy - run: | - vercel deploy --archive=tgz --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt - preview_url="$(cat deployment-url.txt)" - echo "PREVIEW_URL=$preview_url" >> $GITHUB_OUTPUT - - uses: actions/github-script@v7 - env: - PREVIEW_URL: ${{ steps.deploy.outputs.PREVIEW_URL }} - with: - script: | - const previewUrl = process.env.PREVIEW_URL - - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `🤖 Vercel preview here: ${previewUrl}/docs` - }) diff --git a/.golangci.yml b/.golangci.yml index a28fd012d52c2..01e8fe99ef061 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -56,6 +56,7 @@ issues: linters: [staticcheck] text: 'grpc.WithReturnConnectionError is deprecated' - linters: [govet] + path-except: ^e/ text: 'non-constant format string in call to github.com/gravitational/trace.' exclude-use-default: true max-same-issues: 0 diff --git a/api/client/client.go b/api/client/client.go index e3e1184250572..edffe12d00ff2 100644 --- a/api/client/client.go +++ b/api/client/client.go @@ -2286,12 +2286,56 @@ func (c *Client) GetTrustedClusters(ctx context.Context) ([]types.TrustedCluster } // UpsertTrustedCluster creates or updates a Trusted Cluster. -func (c *Client) UpsertTrustedCluster(ctx context.Context, trusedCluster types.TrustedCluster) (types.TrustedCluster, error) { - trustedCluster, ok := trusedCluster.(*types.TrustedClusterV2) +// +// Deprecated: Use [Client.UpsertTrustedClusterV2] instead. +func (c *Client) UpsertTrustedCluster(ctx context.Context, trustedCluster types.TrustedCluster) (types.TrustedCluster, error) { + trustedClusterV2, ok := trustedCluster.(*types.TrustedClusterV2) if !ok { - return nil, trace.BadParameter("invalid type %T", trusedCluster) + return nil, trace.BadParameter("invalid type %T", trustedCluster) } - resp, err := c.grpc.UpsertTrustedCluster(ctx, trustedCluster) + resp, err := c.grpc.UpsertTrustedCluster(ctx, trustedClusterV2) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + +// UpsertTrustedClusterV2 creates or updates a Trusted Cluster. +func (c *Client) UpsertTrustedClusterV2(ctx context.Context, trustedCluster types.TrustedCluster) (types.TrustedCluster, error) { + trustedClusterV2, ok := trustedCluster.(*types.TrustedClusterV2) + if !ok { + return nil, trace.BadParameter("invalid type %T", trustedCluster) + } + req := &trustpb.UpsertTrustedClusterRequest{TrustedCluster: trustedClusterV2} + resp, err := c.TrustClient().UpsertTrustedCluster(ctx, req) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + +// CreateTrustedCluster creates a Trusted Cluster. +func (c *Client) CreateTrustedCluster(ctx context.Context, trustedCluster types.TrustedCluster) (types.TrustedCluster, error) { + trustedClusterV2, ok := trustedCluster.(*types.TrustedClusterV2) + if !ok { + return nil, trace.BadParameter("invalid type %T", trustedCluster) + } + req := &trustpb.CreateTrustedClusterRequest{TrustedCluster: trustedClusterV2} + resp, err := c.TrustClient().CreateTrustedCluster(ctx, req) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + +// UpdateTrustedCluster updates a Trusted Cluster. +func (c *Client) UpdateTrustedCluster(ctx context.Context, trustedCluster types.TrustedCluster) (types.TrustedCluster, error) { + trustedClusterV2, ok := trustedCluster.(*types.TrustedClusterV2) + if !ok { + return nil, trace.BadParameter("invalid type %T", trustedCluster) + } + req := &trustpb.UpdateTrustedClusterRequest{TrustedCluster: trustedClusterV2} + resp, err := c.TrustClient().UpdateTrustedCluster(ctx, req) if err != nil { return nil, trace.Wrap(err) } @@ -4262,6 +4306,12 @@ func (c *Client) GetSSHTargets(ctx context.Context, req *proto.GetSSHTargetsRequ return rsp, trace.Wrap(err) } +// ResolveSSHTarget gets a server that would match an equivalent ssh dial request. +func (c *Client) ResolveSSHTarget(ctx context.Context, req *proto.ResolveSSHTargetRequest) (*proto.ResolveSSHTargetResponse, error) { + rsp, err := c.grpc.ResolveSSHTarget(ctx, req) + return rsp, trace.Wrap(err) +} + // CreateSessionTracker creates a tracker resource for an active session. func (c *Client) CreateSessionTracker(ctx context.Context, st types.SessionTracker) (types.SessionTracker, error) { v1, ok := st.(*types.SessionTrackerV1) @@ -5091,6 +5141,52 @@ func (c *Client) UpsertUserLastSeenNotification(ctx context.Context, req *notifi return rsp, trace.Wrap(err) } +// GetWorkloadIdentity returns a workload identity by name. +func (c *Client) GetWorkloadIdentity(ctx context.Context, name string) (*workloadidentityv1pb.WorkloadIdentity, error) { + resp, err := c.WorkloadIdentityResourceServiceClient().GetWorkloadIdentity(ctx, &workloadidentityv1pb.GetWorkloadIdentityRequest{ + Name: name, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + +// DeleteWorkloadIdentity deletes a workload identity by name. It will throw an +// error if the workload identity does not exist. +func (c *Client) DeleteWorkloadIdentity(ctx context.Context, name string) error { + _, err := c.WorkloadIdentityResourceServiceClient().DeleteWorkloadIdentity(ctx, &workloadidentityv1pb.DeleteWorkloadIdentityRequest{ + Name: name, + }) + if err != nil { + return trace.Wrap(err) + } + return nil +} + +// CreateWorkloadIdentity creates a new workload identity, it will not overwrite +// an existing workload identity with the same name. +func (c *Client) CreateWorkloadIdentity(ctx context.Context, r *workloadidentityv1pb.WorkloadIdentity) (*workloadidentityv1pb.WorkloadIdentity, error) { + resp, err := c.WorkloadIdentityResourceServiceClient().CreateWorkloadIdentity(ctx, &workloadidentityv1pb.CreateWorkloadIdentityRequest{ + WorkloadIdentity: r, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + +// UpsertWorkloadIdentity creates or updates a workload identity. +func (c *Client) UpsertWorkloadIdentity(ctx context.Context, r *workloadidentityv1pb.WorkloadIdentity) (*workloadidentityv1pb.WorkloadIdentity, error) { + resp, err := c.WorkloadIdentityResourceServiceClient().UpsertWorkloadIdentity(ctx, &workloadidentityv1pb.UpsertWorkloadIdentityRequest{ + WorkloadIdentity: r, + }) + if err != nil { + return nil, trace.Wrap(err) + } + return resp, nil +} + // ResourceUsageClient returns an unadorned Resource Usage service client, // using the underlying Auth gRPC connection. // Clients connecting to non-Enterprise clusters, or older Teleport versions, diff --git a/api/client/proto/authservice.pb.go b/api/client/proto/authservice.pb.go index dd1161bbfcac2..f9099550a91f1 100644 --- a/api/client/proto/authservice.pb.go +++ b/api/client/proto/authservice.pb.go @@ -11522,6 +11522,150 @@ func (m *ListResourcesRequest) GetIncludeLogins() bool { return false } +// ResolveSSHTargetRequest provides details about a server to be resolved in +// an equivalent manner to a ssh dial request. +// +// Resolution can happen in two modes: +// 1. searching for hosts based on labels, a predicate expression, or keywords +// 2. searching based on hostname +// +// If a Host is provided, resolution will only operate in the second mode and +// will not perform any resolution based on labels. In order to resolve via +// labels the Host must not be populated. +type ResolveSSHTargetRequest struct { + // The target host as would be sent to the proxy during a dial request. + Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` + // The ssh port. This value is optional, and both empty string and "0" are typically + // treated as meaning that any port should match. + Port string `protobuf:"bytes,2,opt,name=port,proto3" json:"port,omitempty"` + // If not empty, a label-based matcher. + Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Boolean conditions that will be matched against the resource. + PredicateExpression string `protobuf:"bytes,4,opt,name=predicate_expression,json=predicateExpression,proto3" json:"predicate_expression,omitempty"` + // A list of search keywords to match against resource field values. + SearchKeywords []string `protobuf:"bytes,5,rep,name=search_keywords,json=searchKeywords,proto3" json:"search_keywords,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResolveSSHTargetRequest) Reset() { *m = ResolveSSHTargetRequest{} } +func (m *ResolveSSHTargetRequest) String() string { return proto.CompactTextString(m) } +func (*ResolveSSHTargetRequest) ProtoMessage() {} +func (*ResolveSSHTargetRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_0ffcffcda38ae159, []int{163} +} +func (m *ResolveSSHTargetRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResolveSSHTargetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResolveSSHTargetRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResolveSSHTargetRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveSSHTargetRequest.Merge(m, src) +} +func (m *ResolveSSHTargetRequest) XXX_Size() int { + return m.Size() +} +func (m *ResolveSSHTargetRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveSSHTargetRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ResolveSSHTargetRequest proto.InternalMessageInfo + +func (m *ResolveSSHTargetRequest) GetHost() string { + if m != nil { + return m.Host + } + return "" +} + +func (m *ResolveSSHTargetRequest) GetPort() string { + if m != nil { + return m.Port + } + return "" +} + +func (m *ResolveSSHTargetRequest) GetLabels() map[string]string { + if m != nil { + return m.Labels + } + return nil +} + +func (m *ResolveSSHTargetRequest) GetPredicateExpression() string { + if m != nil { + return m.PredicateExpression + } + return "" +} + +func (m *ResolveSSHTargetRequest) GetSearchKeywords() []string { + if m != nil { + return m.SearchKeywords + } + return nil +} + +// GetSSHTargetsResponse holds ssh servers that match an ssh targets request. +type ResolveSSHTargetResponse struct { + // The target matching the supplied request. + Server *types.ServerV2 `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResolveSSHTargetResponse) Reset() { *m = ResolveSSHTargetResponse{} } +func (m *ResolveSSHTargetResponse) String() string { return proto.CompactTextString(m) } +func (*ResolveSSHTargetResponse) ProtoMessage() {} +func (*ResolveSSHTargetResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_0ffcffcda38ae159, []int{164} +} +func (m *ResolveSSHTargetResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResolveSSHTargetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResolveSSHTargetResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResolveSSHTargetResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResolveSSHTargetResponse.Merge(m, src) +} +func (m *ResolveSSHTargetResponse) XXX_Size() int { + return m.Size() +} +func (m *ResolveSSHTargetResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ResolveSSHTargetResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ResolveSSHTargetResponse proto.InternalMessageInfo + +func (m *ResolveSSHTargetResponse) GetServer() *types.ServerV2 { + if m != nil { + return m.Server + } + return nil +} + // GetSSHTargetsRequest gets all servers that might match an equivalent ssh dial request. type GetSSHTargetsRequest struct { // Host is the target host as would be sent to the proxy during a dial request. @@ -11538,7 +11682,7 @@ func (m *GetSSHTargetsRequest) Reset() { *m = GetSSHTargetsRequest{} } func (m *GetSSHTargetsRequest) String() string { return proto.CompactTextString(m) } func (*GetSSHTargetsRequest) ProtoMessage() {} func (*GetSSHTargetsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{163} + return fileDescriptor_0ffcffcda38ae159, []int{165} } func (m *GetSSHTargetsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11594,7 +11738,7 @@ func (m *GetSSHTargetsResponse) Reset() { *m = GetSSHTargetsResponse{} } func (m *GetSSHTargetsResponse) String() string { return proto.CompactTextString(m) } func (*GetSSHTargetsResponse) ProtoMessage() {} func (*GetSSHTargetsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{164} + return fileDescriptor_0ffcffcda38ae159, []int{166} } func (m *GetSSHTargetsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11649,7 +11793,7 @@ func (m *ListResourcesResponse) Reset() { *m = ListResourcesResponse{} } func (m *ListResourcesResponse) String() string { return proto.CompactTextString(m) } func (*ListResourcesResponse) ProtoMessage() {} func (*ListResourcesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{165} + return fileDescriptor_0ffcffcda38ae159, []int{167} } func (m *ListResourcesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11714,7 +11858,7 @@ func (m *CreateSessionTrackerRequest) Reset() { *m = CreateSessionTracke func (m *CreateSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*CreateSessionTrackerRequest) ProtoMessage() {} func (*CreateSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{166} + return fileDescriptor_0ffcffcda38ae159, []int{168} } func (m *CreateSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11763,7 +11907,7 @@ func (m *GetSessionTrackerRequest) Reset() { *m = GetSessionTrackerReque func (m *GetSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*GetSessionTrackerRequest) ProtoMessage() {} func (*GetSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{167} + return fileDescriptor_0ffcffcda38ae159, []int{169} } func (m *GetSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11812,7 +11956,7 @@ func (m *RemoveSessionTrackerRequest) Reset() { *m = RemoveSessionTracke func (m *RemoveSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*RemoveSessionTrackerRequest) ProtoMessage() {} func (*RemoveSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{168} + return fileDescriptor_0ffcffcda38ae159, []int{170} } func (m *RemoveSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11860,7 +12004,7 @@ func (m *SessionTrackerUpdateState) Reset() { *m = SessionTrackerUpdateS func (m *SessionTrackerUpdateState) String() string { return proto.CompactTextString(m) } func (*SessionTrackerUpdateState) ProtoMessage() {} func (*SessionTrackerUpdateState) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{169} + return fileDescriptor_0ffcffcda38ae159, []int{171} } func (m *SessionTrackerUpdateState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11908,7 +12052,7 @@ func (m *SessionTrackerAddParticipant) Reset() { *m = SessionTrackerAddP func (m *SessionTrackerAddParticipant) String() string { return proto.CompactTextString(m) } func (*SessionTrackerAddParticipant) ProtoMessage() {} func (*SessionTrackerAddParticipant) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{170} + return fileDescriptor_0ffcffcda38ae159, []int{172} } func (m *SessionTrackerAddParticipant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11956,7 +12100,7 @@ func (m *SessionTrackerRemoveParticipant) Reset() { *m = SessionTrackerR func (m *SessionTrackerRemoveParticipant) String() string { return proto.CompactTextString(m) } func (*SessionTrackerRemoveParticipant) ProtoMessage() {} func (*SessionTrackerRemoveParticipant) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{171} + return fileDescriptor_0ffcffcda38ae159, []int{173} } func (m *SessionTrackerRemoveParticipant) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12005,7 +12149,7 @@ func (m *SessionTrackerUpdateExpiry) Reset() { *m = SessionTrackerUpdate func (m *SessionTrackerUpdateExpiry) String() string { return proto.CompactTextString(m) } func (*SessionTrackerUpdateExpiry) ProtoMessage() {} func (*SessionTrackerUpdateExpiry) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{172} + return fileDescriptor_0ffcffcda38ae159, []int{174} } func (m *SessionTrackerUpdateExpiry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12060,7 +12204,7 @@ func (m *UpdateSessionTrackerRequest) Reset() { *m = UpdateSessionTracke func (m *UpdateSessionTrackerRequest) String() string { return proto.CompactTextString(m) } func (*UpdateSessionTrackerRequest) ProtoMessage() {} func (*UpdateSessionTrackerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{173} + return fileDescriptor_0ffcffcda38ae159, []int{175} } func (m *UpdateSessionTrackerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12181,7 +12325,7 @@ func (m *PresenceMFAChallengeRequest) Reset() { *m = PresenceMFAChalleng func (m *PresenceMFAChallengeRequest) String() string { return proto.CompactTextString(m) } func (*PresenceMFAChallengeRequest) ProtoMessage() {} func (*PresenceMFAChallengeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{174} + return fileDescriptor_0ffcffcda38ae159, []int{176} } func (m *PresenceMFAChallengeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12239,7 +12383,7 @@ func (m *PresenceMFAChallengeSend) Reset() { *m = PresenceMFAChallengeSe func (m *PresenceMFAChallengeSend) String() string { return proto.CompactTextString(m) } func (*PresenceMFAChallengeSend) ProtoMessage() {} func (*PresenceMFAChallengeSend) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{175} + return fileDescriptor_0ffcffcda38ae159, []int{177} } func (m *PresenceMFAChallengeSend) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12326,7 +12470,7 @@ func (m *GetDomainNameResponse) Reset() { *m = GetDomainNameResponse{} } func (m *GetDomainNameResponse) String() string { return proto.CompactTextString(m) } func (*GetDomainNameResponse) ProtoMessage() {} func (*GetDomainNameResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{176} + return fileDescriptor_0ffcffcda38ae159, []int{178} } func (m *GetDomainNameResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12375,7 +12519,7 @@ func (m *GetClusterCACertResponse) Reset() { *m = GetClusterCACertRespon func (m *GetClusterCACertResponse) String() string { return proto.CompactTextString(m) } func (*GetClusterCACertResponse) ProtoMessage() {} func (*GetClusterCACertResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{177} + return fileDescriptor_0ffcffcda38ae159, []int{179} } func (m *GetClusterCACertResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12423,7 +12567,7 @@ func (m *GetLicenseResponse) Reset() { *m = GetLicenseResponse{} } func (m *GetLicenseResponse) String() string { return proto.CompactTextString(m) } func (*GetLicenseResponse) ProtoMessage() {} func (*GetLicenseResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{178} + return fileDescriptor_0ffcffcda38ae159, []int{180} } func (m *GetLicenseResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12471,7 +12615,7 @@ func (m *ListReleasesResponse) Reset() { *m = ListReleasesResponse{} } func (m *ListReleasesResponse) String() string { return proto.CompactTextString(m) } func (*ListReleasesResponse) ProtoMessage() {} func (*ListReleasesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{179} + return fileDescriptor_0ffcffcda38ae159, []int{181} } func (m *ListReleasesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12520,7 +12664,7 @@ func (m *GetOIDCAuthRequestRequest) Reset() { *m = GetOIDCAuthRequestReq func (m *GetOIDCAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetOIDCAuthRequestRequest) ProtoMessage() {} func (*GetOIDCAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{180} + return fileDescriptor_0ffcffcda38ae159, []int{182} } func (m *GetOIDCAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12569,7 +12713,7 @@ func (m *GetSAMLAuthRequestRequest) Reset() { *m = GetSAMLAuthRequestReq func (m *GetSAMLAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetSAMLAuthRequestRequest) ProtoMessage() {} func (*GetSAMLAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{181} + return fileDescriptor_0ffcffcda38ae159, []int{183} } func (m *GetSAMLAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12618,7 +12762,7 @@ func (m *GetGithubAuthRequestRequest) Reset() { *m = GetGithubAuthReques func (m *GetGithubAuthRequestRequest) String() string { return proto.CompactTextString(m) } func (*GetGithubAuthRequestRequest) ProtoMessage() {} func (*GetGithubAuthRequestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{182} + return fileDescriptor_0ffcffcda38ae159, []int{184} } func (m *GetGithubAuthRequestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12667,7 +12811,7 @@ func (m *CreateOIDCConnectorRequest) Reset() { *m = CreateOIDCConnectorR func (m *CreateOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateOIDCConnectorRequest) ProtoMessage() {} func (*CreateOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{183} + return fileDescriptor_0ffcffcda38ae159, []int{185} } func (m *CreateOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12716,7 +12860,7 @@ func (m *UpdateOIDCConnectorRequest) Reset() { *m = UpdateOIDCConnectorR func (m *UpdateOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateOIDCConnectorRequest) ProtoMessage() {} func (*UpdateOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{184} + return fileDescriptor_0ffcffcda38ae159, []int{186} } func (m *UpdateOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12765,7 +12909,7 @@ func (m *UpsertOIDCConnectorRequest) Reset() { *m = UpsertOIDCConnectorR func (m *UpsertOIDCConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertOIDCConnectorRequest) ProtoMessage() {} func (*UpsertOIDCConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{185} + return fileDescriptor_0ffcffcda38ae159, []int{187} } func (m *UpsertOIDCConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12814,7 +12958,7 @@ func (m *CreateSAMLConnectorRequest) Reset() { *m = CreateSAMLConnectorR func (m *CreateSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateSAMLConnectorRequest) ProtoMessage() {} func (*CreateSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{186} + return fileDescriptor_0ffcffcda38ae159, []int{188} } func (m *CreateSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12863,7 +13007,7 @@ func (m *UpdateSAMLConnectorRequest) Reset() { *m = UpdateSAMLConnectorR func (m *UpdateSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateSAMLConnectorRequest) ProtoMessage() {} func (*UpdateSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{187} + return fileDescriptor_0ffcffcda38ae159, []int{189} } func (m *UpdateSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12912,7 +13056,7 @@ func (m *UpsertSAMLConnectorRequest) Reset() { *m = UpsertSAMLConnectorR func (m *UpsertSAMLConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertSAMLConnectorRequest) ProtoMessage() {} func (*UpsertSAMLConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{188} + return fileDescriptor_0ffcffcda38ae159, []int{190} } func (m *UpsertSAMLConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12961,7 +13105,7 @@ func (m *CreateGithubConnectorRequest) Reset() { *m = CreateGithubConnec func (m *CreateGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*CreateGithubConnectorRequest) ProtoMessage() {} func (*CreateGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{189} + return fileDescriptor_0ffcffcda38ae159, []int{191} } func (m *CreateGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13010,7 +13154,7 @@ func (m *UpdateGithubConnectorRequest) Reset() { *m = UpdateGithubConnec func (m *UpdateGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpdateGithubConnectorRequest) ProtoMessage() {} func (*UpdateGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{190} + return fileDescriptor_0ffcffcda38ae159, []int{192} } func (m *UpdateGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13059,7 +13203,7 @@ func (m *UpsertGithubConnectorRequest) Reset() { *m = UpsertGithubConnec func (m *UpsertGithubConnectorRequest) String() string { return proto.CompactTextString(m) } func (*UpsertGithubConnectorRequest) ProtoMessage() {} func (*UpsertGithubConnectorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{191} + return fileDescriptor_0ffcffcda38ae159, []int{193} } func (m *UpsertGithubConnectorRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13110,7 +13254,7 @@ func (m *GetSSODiagnosticInfoRequest) Reset() { *m = GetSSODiagnosticInf func (m *GetSSODiagnosticInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetSSODiagnosticInfoRequest) ProtoMessage() {} func (*GetSSODiagnosticInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{192} + return fileDescriptor_0ffcffcda38ae159, []int{194} } func (m *GetSSODiagnosticInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13176,7 +13320,7 @@ func (m *SystemRoleAssertion) Reset() { *m = SystemRoleAssertion{} } func (m *SystemRoleAssertion) String() string { return proto.CompactTextString(m) } func (*SystemRoleAssertion) ProtoMessage() {} func (*SystemRoleAssertion) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{193} + return fileDescriptor_0ffcffcda38ae159, []int{195} } func (m *SystemRoleAssertion) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13246,7 +13390,7 @@ func (m *SystemRoleAssertionSet) Reset() { *m = SystemRoleAssertionSet{} func (m *SystemRoleAssertionSet) String() string { return proto.CompactTextString(m) } func (*SystemRoleAssertionSet) ProtoMessage() {} func (*SystemRoleAssertionSet) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{194} + return fileDescriptor_0ffcffcda38ae159, []int{196} } func (m *SystemRoleAssertionSet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13315,7 +13459,7 @@ func (m *UpstreamInventoryOneOf) Reset() { *m = UpstreamInventoryOneOf{} func (m *UpstreamInventoryOneOf) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryOneOf) ProtoMessage() {} func (*UpstreamInventoryOneOf) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{195} + return fileDescriptor_0ffcffcda38ae159, []int{197} } func (m *UpstreamInventoryOneOf) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13442,7 +13586,7 @@ func (m *DownstreamInventoryOneOf) Reset() { *m = DownstreamInventoryOne func (m *DownstreamInventoryOneOf) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryOneOf) ProtoMessage() {} func (*DownstreamInventoryOneOf) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{196} + return fileDescriptor_0ffcffcda38ae159, []int{198} } func (m *DownstreamInventoryOneOf) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13540,7 +13684,7 @@ func (m *DownstreamInventoryPing) Reset() { *m = DownstreamInventoryPing func (m *DownstreamInventoryPing) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryPing) ProtoMessage() {} func (*DownstreamInventoryPing) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{197} + return fileDescriptor_0ffcffcda38ae159, []int{199} } func (m *DownstreamInventoryPing) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13591,7 +13735,7 @@ func (m *UpstreamInventoryPong) Reset() { *m = UpstreamInventoryPong{} } func (m *UpstreamInventoryPong) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryPong) ProtoMessage() {} func (*UpstreamInventoryPong) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{198} + return fileDescriptor_0ffcffcda38ae159, []int{200} } func (m *UpstreamInventoryPong) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13665,7 +13809,7 @@ func (m *UpstreamInventoryHello) Reset() { *m = UpstreamInventoryHello{} func (m *UpstreamInventoryHello) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryHello) ProtoMessage() {} func (*UpstreamInventoryHello) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{199} + return fileDescriptor_0ffcffcda38ae159, []int{201} } func (m *UpstreamInventoryHello) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13765,7 +13909,7 @@ func (m *UpstreamInventoryAgentMetadata) Reset() { *m = UpstreamInventor func (m *UpstreamInventoryAgentMetadata) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryAgentMetadata) ProtoMessage() {} func (*UpstreamInventoryAgentMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{200} + return fileDescriptor_0ffcffcda38ae159, []int{202} } func (m *UpstreamInventoryAgentMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13867,7 +14011,7 @@ func (m *DownstreamInventoryHello) Reset() { *m = DownstreamInventoryHel func (m *DownstreamInventoryHello) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryHello) ProtoMessage() {} func (*DownstreamInventoryHello) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{201} + return fileDescriptor_0ffcffcda38ae159, []int{203} } func (m *DownstreamInventoryHello) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13970,7 +14114,7 @@ func (m *DownstreamInventoryHello_SupportedCapabilities) String() string { } func (*DownstreamInventoryHello_SupportedCapabilities) ProtoMessage() {} func (*DownstreamInventoryHello_SupportedCapabilities) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{201, 0} + return fileDescriptor_0ffcffcda38ae159, []int{203, 0} } func (m *DownstreamInventoryHello_SupportedCapabilities) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14143,7 +14287,7 @@ func (m *InventoryUpdateLabelsRequest) Reset() { *m = InventoryUpdateLab func (m *InventoryUpdateLabelsRequest) String() string { return proto.CompactTextString(m) } func (*InventoryUpdateLabelsRequest) ProtoMessage() {} func (*InventoryUpdateLabelsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{202} + return fileDescriptor_0ffcffcda38ae159, []int{204} } func (m *InventoryUpdateLabelsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14209,7 +14353,7 @@ func (m *DownstreamInventoryUpdateLabels) Reset() { *m = DownstreamInven func (m *DownstreamInventoryUpdateLabels) String() string { return proto.CompactTextString(m) } func (*DownstreamInventoryUpdateLabels) ProtoMessage() {} func (*DownstreamInventoryUpdateLabels) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{203} + return fileDescriptor_0ffcffcda38ae159, []int{205} } func (m *DownstreamInventoryUpdateLabels) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14274,7 +14418,7 @@ func (m *InventoryHeartbeat) Reset() { *m = InventoryHeartbeat{} } func (m *InventoryHeartbeat) String() string { return proto.CompactTextString(m) } func (*InventoryHeartbeat) ProtoMessage() {} func (*InventoryHeartbeat) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{204} + return fileDescriptor_0ffcffcda38ae159, []int{206} } func (m *InventoryHeartbeat) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14346,7 +14490,7 @@ func (m *UpstreamInventoryGoodbye) Reset() { *m = UpstreamInventoryGoodb func (m *UpstreamInventoryGoodbye) String() string { return proto.CompactTextString(m) } func (*UpstreamInventoryGoodbye) ProtoMessage() {} func (*UpstreamInventoryGoodbye) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{205} + return fileDescriptor_0ffcffcda38ae159, []int{207} } func (m *UpstreamInventoryGoodbye) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14396,7 +14540,7 @@ func (m *InventoryStatusRequest) Reset() { *m = InventoryStatusRequest{} func (m *InventoryStatusRequest) String() string { return proto.CompactTextString(m) } func (*InventoryStatusRequest) ProtoMessage() {} func (*InventoryStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{206} + return fileDescriptor_0ffcffcda38ae159, []int{208} } func (m *InventoryStatusRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14454,7 +14598,7 @@ func (m *InventoryStatusSummary) Reset() { *m = InventoryStatusSummary{} func (m *InventoryStatusSummary) String() string { return proto.CompactTextString(m) } func (*InventoryStatusSummary) ProtoMessage() {} func (*InventoryStatusSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{207} + return fileDescriptor_0ffcffcda38ae159, []int{209} } func (m *InventoryStatusSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14531,7 +14675,7 @@ func (m *InventoryConnectedServiceCountsRequest) Reset() { func (m *InventoryConnectedServiceCountsRequest) String() string { return proto.CompactTextString(m) } func (*InventoryConnectedServiceCountsRequest) ProtoMessage() {} func (*InventoryConnectedServiceCountsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{208} + return fileDescriptor_0ffcffcda38ae159, []int{210} } func (m *InventoryConnectedServiceCountsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14573,7 +14717,7 @@ func (m *InventoryConnectedServiceCounts) Reset() { *m = InventoryConnec func (m *InventoryConnectedServiceCounts) String() string { return proto.CompactTextString(m) } func (*InventoryConnectedServiceCounts) ProtoMessage() {} func (*InventoryConnectedServiceCounts) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{209} + return fileDescriptor_0ffcffcda38ae159, []int{211} } func (m *InventoryConnectedServiceCounts) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14627,7 +14771,7 @@ func (m *InventoryPingRequest) Reset() { *m = InventoryPingRequest{} } func (m *InventoryPingRequest) String() string { return proto.CompactTextString(m) } func (*InventoryPingRequest) ProtoMessage() {} func (*InventoryPingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{210} + return fileDescriptor_0ffcffcda38ae159, []int{212} } func (m *InventoryPingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14684,7 +14828,7 @@ func (m *InventoryPingResponse) Reset() { *m = InventoryPingResponse{} } func (m *InventoryPingResponse) String() string { return proto.CompactTextString(m) } func (*InventoryPingResponse) ProtoMessage() {} func (*InventoryPingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{211} + return fileDescriptor_0ffcffcda38ae159, []int{213} } func (m *InventoryPingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14733,7 +14877,7 @@ func (m *GetClusterAlertsResponse) Reset() { *m = GetClusterAlertsRespon func (m *GetClusterAlertsResponse) String() string { return proto.CompactTextString(m) } func (*GetClusterAlertsResponse) ProtoMessage() {} func (*GetClusterAlertsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{212} + return fileDescriptor_0ffcffcda38ae159, []int{214} } func (m *GetClusterAlertsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14780,7 +14924,7 @@ func (m *GetAlertAcksRequest) Reset() { *m = GetAlertAcksRequest{} } func (m *GetAlertAcksRequest) String() string { return proto.CompactTextString(m) } func (*GetAlertAcksRequest) ProtoMessage() {} func (*GetAlertAcksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{213} + return fileDescriptor_0ffcffcda38ae159, []int{215} } func (m *GetAlertAcksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14822,7 +14966,7 @@ func (m *GetAlertAcksResponse) Reset() { *m = GetAlertAcksResponse{} } func (m *GetAlertAcksResponse) String() string { return proto.CompactTextString(m) } func (*GetAlertAcksResponse) ProtoMessage() {} func (*GetAlertAcksResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{214} + return fileDescriptor_0ffcffcda38ae159, []int{216} } func (m *GetAlertAcksResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14872,7 +15016,7 @@ func (m *ClearAlertAcksRequest) Reset() { *m = ClearAlertAcksRequest{} } func (m *ClearAlertAcksRequest) String() string { return proto.CompactTextString(m) } func (*ClearAlertAcksRequest) ProtoMessage() {} func (*ClearAlertAcksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{215} + return fileDescriptor_0ffcffcda38ae159, []int{217} } func (m *ClearAlertAcksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14921,7 +15065,7 @@ func (m *UpsertClusterAlertRequest) Reset() { *m = UpsertClusterAlertReq func (m *UpsertClusterAlertRequest) String() string { return proto.CompactTextString(m) } func (*UpsertClusterAlertRequest) ProtoMessage() {} func (*UpsertClusterAlertRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{216} + return fileDescriptor_0ffcffcda38ae159, []int{218} } func (m *UpsertClusterAlertRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -14970,7 +15114,7 @@ func (m *GetConnectionDiagnosticRequest) Reset() { *m = GetConnectionDia func (m *GetConnectionDiagnosticRequest) String() string { return proto.CompactTextString(m) } func (*GetConnectionDiagnosticRequest) ProtoMessage() {} func (*GetConnectionDiagnosticRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{217} + return fileDescriptor_0ffcffcda38ae159, []int{219} } func (m *GetConnectionDiagnosticRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15021,7 +15165,7 @@ func (m *AppendDiagnosticTraceRequest) Reset() { *m = AppendDiagnosticTr func (m *AppendDiagnosticTraceRequest) String() string { return proto.CompactTextString(m) } func (*AppendDiagnosticTraceRequest) ProtoMessage() {} func (*AppendDiagnosticTraceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{218} + return fileDescriptor_0ffcffcda38ae159, []int{220} } func (m *AppendDiagnosticTraceRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15076,7 +15220,7 @@ func (m *SubmitUsageEventRequest) Reset() { *m = SubmitUsageEventRequest func (m *SubmitUsageEventRequest) String() string { return proto.CompactTextString(m) } func (*SubmitUsageEventRequest) ProtoMessage() {} func (*SubmitUsageEventRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{219} + return fileDescriptor_0ffcffcda38ae159, []int{221} } func (m *SubmitUsageEventRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15123,7 +15267,7 @@ func (m *GetLicenseRequest) Reset() { *m = GetLicenseRequest{} } func (m *GetLicenseRequest) String() string { return proto.CompactTextString(m) } func (*GetLicenseRequest) ProtoMessage() {} func (*GetLicenseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{220} + return fileDescriptor_0ffcffcda38ae159, []int{222} } func (m *GetLicenseRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15163,7 +15307,7 @@ func (m *ListReleasesRequest) Reset() { *m = ListReleasesRequest{} } func (m *ListReleasesRequest) String() string { return proto.CompactTextString(m) } func (*ListReleasesRequest) ProtoMessage() {} func (*ListReleasesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{221} + return fileDescriptor_0ffcffcda38ae159, []int{223} } func (m *ListReleasesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15207,7 +15351,7 @@ func (m *CreateTokenV2Request) Reset() { *m = CreateTokenV2Request{} } func (m *CreateTokenV2Request) String() string { return proto.CompactTextString(m) } func (*CreateTokenV2Request) ProtoMessage() {} func (*CreateTokenV2Request) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{222} + return fileDescriptor_0ffcffcda38ae159, []int{224} } func (m *CreateTokenV2Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15284,7 +15428,7 @@ func (m *UpsertTokenV2Request) Reset() { *m = UpsertTokenV2Request{} } func (m *UpsertTokenV2Request) String() string { return proto.CompactTextString(m) } func (*UpsertTokenV2Request) ProtoMessage() {} func (*UpsertTokenV2Request) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{223} + return fileDescriptor_0ffcffcda38ae159, []int{225} } func (m *UpsertTokenV2Request) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15359,7 +15503,7 @@ func (m *GetHeadlessAuthenticationRequest) Reset() { *m = GetHeadlessAut func (m *GetHeadlessAuthenticationRequest) String() string { return proto.CompactTextString(m) } func (*GetHeadlessAuthenticationRequest) ProtoMessage() {} func (*GetHeadlessAuthenticationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{224} + return fileDescriptor_0ffcffcda38ae159, []int{226} } func (m *GetHeadlessAuthenticationRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15417,7 +15561,7 @@ func (m *UpdateHeadlessAuthenticationStateRequest) Reset() { func (m *UpdateHeadlessAuthenticationStateRequest) String() string { return proto.CompactTextString(m) } func (*UpdateHeadlessAuthenticationStateRequest) ProtoMessage() {} func (*UpdateHeadlessAuthenticationStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{225} + return fileDescriptor_0ffcffcda38ae159, []int{227} } func (m *UpdateHeadlessAuthenticationStateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15483,7 +15627,7 @@ func (m *ExportUpgradeWindowsRequest) Reset() { *m = ExportUpgradeWindow func (m *ExportUpgradeWindowsRequest) String() string { return proto.CompactTextString(m) } func (*ExportUpgradeWindowsRequest) ProtoMessage() {} func (*ExportUpgradeWindowsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{226} + return fileDescriptor_0ffcffcda38ae159, []int{228} } func (m *ExportUpgradeWindowsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15549,7 +15693,7 @@ func (m *ExportUpgradeWindowsResponse) Reset() { *m = ExportUpgradeWindo func (m *ExportUpgradeWindowsResponse) String() string { return proto.CompactTextString(m) } func (*ExportUpgradeWindowsResponse) ProtoMessage() {} func (*ExportUpgradeWindowsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{227} + return fileDescriptor_0ffcffcda38ae159, []int{229} } func (m *ExportUpgradeWindowsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15624,7 +15768,7 @@ func (m *ListAccessRequestsRequest) Reset() { *m = ListAccessRequestsReq func (m *ListAccessRequestsRequest) String() string { return proto.CompactTextString(m) } func (*ListAccessRequestsRequest) ProtoMessage() {} func (*ListAccessRequestsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{228} + return fileDescriptor_0ffcffcda38ae159, []int{230} } func (m *ListAccessRequestsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15703,7 +15847,7 @@ func (m *ListAccessRequestsResponse) Reset() { *m = ListAccessRequestsRe func (m *ListAccessRequestsResponse) String() string { return proto.CompactTextString(m) } func (*ListAccessRequestsResponse) ProtoMessage() {} func (*ListAccessRequestsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{229} + return fileDescriptor_0ffcffcda38ae159, []int{231} } func (m *ListAccessRequestsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15759,7 +15903,7 @@ func (m *AccessRequestAllowedPromotionRequest) Reset() { *m = AccessRequ func (m *AccessRequestAllowedPromotionRequest) String() string { return proto.CompactTextString(m) } func (*AccessRequestAllowedPromotionRequest) ProtoMessage() {} func (*AccessRequestAllowedPromotionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{230} + return fileDescriptor_0ffcffcda38ae159, []int{232} } func (m *AccessRequestAllowedPromotionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -15808,7 +15952,7 @@ func (m *AccessRequestAllowedPromotionResponse) Reset() { *m = AccessReq func (m *AccessRequestAllowedPromotionResponse) String() string { return proto.CompactTextString(m) } func (*AccessRequestAllowedPromotionResponse) ProtoMessage() {} func (*AccessRequestAllowedPromotionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_0ffcffcda38ae159, []int{231} + return fileDescriptor_0ffcffcda38ae159, []int{233} } func (m *AccessRequestAllowedPromotionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -16025,6 +16169,9 @@ func init() { proto.RegisterType((*ListUnifiedResourcesResponse)(nil), "proto.ListUnifiedResourcesResponse") proto.RegisterType((*ListResourcesRequest)(nil), "proto.ListResourcesRequest") proto.RegisterMapType((map[string]string)(nil), "proto.ListResourcesRequest.LabelsEntry") + proto.RegisterType((*ResolveSSHTargetRequest)(nil), "proto.ResolveSSHTargetRequest") + proto.RegisterMapType((map[string]string)(nil), "proto.ResolveSSHTargetRequest.LabelsEntry") + proto.RegisterType((*ResolveSSHTargetResponse)(nil), "proto.ResolveSSHTargetResponse") proto.RegisterType((*GetSSHTargetsRequest)(nil), "proto.GetSSHTargetsRequest") proto.RegisterType((*GetSSHTargetsResponse)(nil), "proto.GetSSHTargetsResponse") proto.RegisterType((*ListResourcesResponse)(nil), "proto.ListResourcesResponse") @@ -16108,971 +16255,979 @@ func init() { } var fileDescriptor_0ffcffcda38ae159 = []byte{ - // 15418 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x59, 0x6c, 0x5c, 0xc9, - 0x7a, 0x18, 0xac, 0xe6, 0xce, 0x8f, 0x8b, 0x5a, 0x45, 0x52, 0x6c, 0x51, 0x4b, 0x4b, 0x47, 0xa3, - 0x19, 0x8d, 0xee, 0x5c, 0x2d, 0x9c, 0xe5, 0xce, 0x3e, 0xd3, 0x4d, 0x52, 0x22, 0x25, 0x6e, 0x73, - 0x9a, 0xa4, 0x66, 0xf3, 0xed, 0x7b, 0xd8, 0x5d, 0x22, 0x8f, 0xd5, 0x3c, 0xa7, 0xef, 0x39, 0xa7, - 0xa5, 0xd1, 0xf5, 0x7f, 0xfd, 0xc3, 0x76, 0x16, 0x07, 0x41, 0x12, 0x1b, 0x88, 0x03, 0x27, 0x79, - 0x70, 0x02, 0x38, 0x40, 0x10, 0x20, 0x80, 0x5f, 0x02, 0x3f, 0x19, 0x41, 0x9e, 0x72, 0x63, 0x20, - 0x48, 0x0c, 0xdb, 0x2f, 0x01, 0x42, 0x27, 0x17, 0xf0, 0x0b, 0x91, 0x3c, 0x18, 0x41, 0x02, 0xe4, - 0x06, 0x06, 0x82, 0xfa, 0x6a, 0x39, 0x55, 0x67, 0xe9, 0x26, 0x25, 0xcd, 0x75, 0x5e, 0x24, 0xf6, - 0xb7, 0x55, 0xd5, 0x57, 0x75, 0xaa, 0xea, 0xfb, 0xea, 0xab, 0xaf, 0xe0, 0x66, 0x44, 0x5b, 0xb4, - 0xed, 0x07, 0xd1, 0xad, 0x16, 0xdd, 0x73, 0x1a, 0xcf, 0x6e, 0x35, 0x5a, 0x2e, 0xf5, 0xa2, 0x5b, - 0xed, 0xc0, 0x8f, 0xfc, 0x5b, 0x4e, 0x27, 0xda, 0x0f, 0x69, 0xf0, 0xc4, 0x6d, 0xd0, 0x9b, 0x08, - 0x21, 0x83, 0xf8, 0xdf, 0xdc, 0xf4, 0x9e, 0xbf, 0xe7, 0x73, 0x1a, 0xf6, 0x17, 0x47, 0xce, 0x9d, - 0xdf, 0xf3, 0xfd, 0xbd, 0x16, 0xe5, 0xcc, 0xbb, 0x9d, 0x47, 0xb7, 0xe8, 0x41, 0x3b, 0x7a, 0x26, - 0x90, 0xe5, 0x24, 0x32, 0x72, 0x0f, 0x68, 0x18, 0x39, 0x07, 0x6d, 0x41, 0xf0, 0xba, 0xaa, 0x8a, - 0x13, 0x45, 0x0c, 0x13, 0xb9, 0xbe, 0x77, 0xeb, 0xc9, 0x1d, 0xfd, 0xa7, 0x20, 0xbd, 0xde, 0xb5, - 0xd6, 0x0d, 0x1a, 0x44, 0xe1, 0xb1, 0x28, 0xe9, 0x13, 0xea, 0x45, 0xa9, 0xe2, 0x05, 0x65, 0xf4, - 0xac, 0x4d, 0x43, 0x4e, 0x22, 0xff, 0x13, 0xa4, 0x57, 0xb2, 0x49, 0xf1, 0x5f, 0x41, 0xf2, 0xdd, - 0x6c, 0x92, 0xa7, 0x74, 0x97, 0xe9, 0xd4, 0x53, 0x7f, 0xf4, 0x20, 0x0f, 0x9c, 0x76, 0x9b, 0x06, - 0xf1, 0x1f, 0x82, 0xfc, 0x9c, 0x22, 0x3f, 0x78, 0xe4, 0x30, 0x15, 0x1d, 0x3c, 0x72, 0x52, 0xcd, - 0xe8, 0x84, 0xce, 0x1e, 0x15, 0xd5, 0x7f, 0x72, 0x47, 0xff, 0xc9, 0x49, 0xad, 0xdf, 0x29, 0xc0, - 0xe0, 0x43, 0x27, 0x6a, 0xec, 0x93, 0x4f, 0x60, 0xf0, 0x81, 0xeb, 0x35, 0xc3, 0x52, 0xe1, 0x72, - 0xff, 0xf5, 0xb1, 0xf9, 0xe2, 0x4d, 0xde, 0x14, 0x44, 0x32, 0x44, 0x75, 0xf6, 0x27, 0x87, 0xe5, - 0x53, 0x47, 0x87, 0xe5, 0xd3, 0x8f, 0x19, 0xd9, 0x1b, 0xfe, 0x81, 0x1b, 0x61, 0xdf, 0xda, 0x9c, - 0x8f, 0x6c, 0xc3, 0x54, 0xa5, 0xd5, 0xf2, 0x9f, 0x6e, 0x3a, 0x41, 0xe4, 0x3a, 0xad, 0x5a, 0xa7, - 0xd1, 0xa0, 0x61, 0x58, 0xea, 0xbb, 0x5c, 0xb8, 0x3e, 0x52, 0xbd, 0x7a, 0x74, 0x58, 0x2e, 0x3b, - 0x0c, 0x5d, 0x6f, 0x73, 0x7c, 0x3d, 0xe4, 0x04, 0x9a, 0xa0, 0x2c, 0x7e, 0xeb, 0x0f, 0x87, 0xa0, - 0xb8, 0xec, 0x87, 0xd1, 0x02, 0xeb, 0x51, 0x9b, 0xfe, 0xb0, 0x43, 0xc3, 0x88, 0x5c, 0x85, 0x21, - 0x06, 0x5b, 0x59, 0x2c, 0x15, 0x2e, 0x17, 0xae, 0x8f, 0x56, 0xc7, 0x8e, 0x0e, 0xcb, 0xc3, 0xfb, - 0x7e, 0x18, 0xd5, 0xdd, 0xa6, 0x2d, 0x50, 0xe4, 0x75, 0x18, 0x59, 0xf7, 0x9b, 0x74, 0xdd, 0x39, - 0xa0, 0x58, 0x8b, 0xd1, 0xea, 0xc4, 0xd1, 0x61, 0x79, 0xd4, 0xf3, 0x9b, 0xb4, 0xee, 0x39, 0x07, - 0xd4, 0x56, 0x68, 0xb2, 0x03, 0x03, 0xb6, 0xdf, 0xa2, 0xa5, 0x7e, 0x24, 0xab, 0x1e, 0x1d, 0x96, - 0x07, 0x02, 0xbf, 0x45, 0x7f, 0x76, 0x58, 0x7e, 0x67, 0xcf, 0x8d, 0xf6, 0x3b, 0xbb, 0x37, 0x1b, - 0xfe, 0xc1, 0xad, 0xbd, 0xc0, 0x79, 0xe2, 0xf2, 0x41, 0xe8, 0xb4, 0x6e, 0xc5, 0x43, 0xb5, 0xed, - 0x8a, 0x7e, 0xaf, 0x3d, 0x0b, 0x23, 0x7a, 0xc0, 0x24, 0xd9, 0x28, 0x8f, 0x3c, 0x84, 0xe9, 0x4a, - 0xb3, 0xe9, 0x72, 0x8e, 0xcd, 0xc0, 0xf5, 0x1a, 0x6e, 0xdb, 0x69, 0x85, 0xa5, 0x81, 0xcb, 0xfd, - 0xd7, 0x47, 0x85, 0x52, 0x14, 0xbe, 0xde, 0x56, 0x04, 0x9a, 0x52, 0x32, 0x05, 0x90, 0x37, 0x61, - 0x64, 0x71, 0xbd, 0xc6, 0xea, 0x1e, 0x96, 0x06, 0x51, 0xd8, 0xec, 0xd1, 0x61, 0x79, 0xaa, 0xe9, - 0x85, 0xd8, 0x34, 0x5d, 0x80, 0x22, 0x24, 0xef, 0xc0, 0xf8, 0x66, 0x67, 0xb7, 0xe5, 0x36, 0xb6, - 0x56, 0x6b, 0x0f, 0xe8, 0xb3, 0xd2, 0xd0, 0xe5, 0xc2, 0xf5, 0xf1, 0x2a, 0x39, 0x3a, 0x2c, 0x4f, - 0xb6, 0x11, 0x5e, 0x8f, 0x5a, 0x61, 0xfd, 0x31, 0x7d, 0x66, 0x1b, 0x74, 0x31, 0x5f, 0xad, 0xb6, - 0xcc, 0xf8, 0x86, 0x53, 0x7c, 0x61, 0xb8, 0xaf, 0xf3, 0x71, 0x3a, 0x72, 0x0b, 0xc0, 0xa6, 0x07, - 0x7e, 0x44, 0x2b, 0xcd, 0x66, 0x50, 0x1a, 0x41, 0xdd, 0x9e, 0x3e, 0x3a, 0x2c, 0x8f, 0x05, 0x08, - 0xad, 0x3b, 0xcd, 0x66, 0x60, 0x6b, 0x24, 0x64, 0x01, 0x46, 0x6c, 0x9f, 0x2b, 0xb8, 0x34, 0x7a, - 0xb9, 0x70, 0x7d, 0x6c, 0xfe, 0xb4, 0x18, 0x86, 0x12, 0x5c, 0x3d, 0x7b, 0x74, 0x58, 0x26, 0x81, - 0xf8, 0xa5, 0xb7, 0x52, 0x52, 0x90, 0x32, 0x0c, 0xaf, 0xfb, 0x0b, 0x4e, 0x63, 0x9f, 0x96, 0x00, - 0xc7, 0xde, 0xe0, 0xd1, 0x61, 0xb9, 0xf0, 0x5d, 0x5b, 0x42, 0xc9, 0x13, 0x18, 0x8b, 0x3b, 0x2a, - 0x2c, 0x8d, 0xa1, 0xfa, 0xb6, 0x8e, 0x0e, 0xcb, 0x67, 0x43, 0x04, 0xd7, 0x59, 0xd7, 0x6b, 0x1a, - 0x7c, 0x81, 0x51, 0xa0, 0x17, 0x44, 0xbe, 0x86, 0x99, 0xf8, 0x67, 0x25, 0x0c, 0x69, 0xc0, 0x64, - 0xac, 0x2c, 0x96, 0x26, 0x50, 0x33, 0xaf, 0x1e, 0x1d, 0x96, 0x2d, 0xad, 0x06, 0x75, 0x47, 0x92, - 0xd4, 0xdd, 0xa6, 0xd6, 0xd2, 0x6c, 0x21, 0xf7, 0x07, 0x46, 0xc6, 0x8b, 0x13, 0xf6, 0xc5, 0x6d, - 0x2f, 0x8c, 0x9c, 0xdd, 0x16, 0xcd, 0x24, 0xb2, 0xfe, 0xb2, 0x00, 0x64, 0xa3, 0x4d, 0xbd, 0x5a, - 0x6d, 0x99, 0x7d, 0x4f, 0xf2, 0x73, 0x7a, 0x03, 0x46, 0x79, 0xc7, 0xb1, 0xde, 0xed, 0xc3, 0xde, - 0x9d, 0x3c, 0x3a, 0x2c, 0x83, 0xe8, 0x5d, 0xd6, 0xb3, 0x31, 0x01, 0xb9, 0x06, 0xfd, 0x5b, 0x5b, - 0xab, 0xf8, 0xad, 0xf4, 0x57, 0xa7, 0x8e, 0x0e, 0xcb, 0xfd, 0x51, 0xd4, 0xfa, 0xd9, 0x61, 0x79, - 0x64, 0xb1, 0x13, 0xa0, 0x5a, 0x6c, 0x86, 0x27, 0xd7, 0x60, 0x78, 0xa1, 0xd5, 0x09, 0x23, 0x1a, - 0x94, 0x06, 0xe2, 0x8f, 0xb4, 0xc1, 0x41, 0xb6, 0xc4, 0x91, 0xef, 0xc0, 0xc0, 0x76, 0x48, 0x83, - 0xd2, 0x20, 0xf6, 0xf7, 0x84, 0xe8, 0x6f, 0x06, 0xda, 0x99, 0xaf, 0x8e, 0xb0, 0x2f, 0xb1, 0x13, - 0xd2, 0xc0, 0x46, 0x22, 0x72, 0x13, 0x06, 0x79, 0xa7, 0x0d, 0xe1, 0x24, 0x35, 0xa1, 0x46, 0x47, - 0x8b, 0xee, 0xbc, 0x53, 0x1d, 0x3d, 0x3a, 0x2c, 0x0f, 0x62, 0xe7, 0xd9, 0x9c, 0xec, 0xfe, 0xc0, - 0x48, 0xa1, 0xd8, 0x67, 0x8f, 0x30, 0x5e, 0xf6, 0x59, 0x58, 0xdf, 0x81, 0x31, 0xad, 0xf9, 0xe4, - 0x02, 0x0c, 0xb0, 0xff, 0x71, 0x12, 0x19, 0xe7, 0x85, 0xb1, 0x85, 0xc3, 0x46, 0xa8, 0xf5, 0x4f, - 0xa6, 0xa0, 0xc8, 0x38, 0x8d, 0x99, 0xe7, 0xa6, 0xae, 0x2a, 0xce, 0x57, 0x34, 0x55, 0x55, 0x2a, - 0xe8, 0xca, 0xba, 0x0e, 0xaa, 0x74, 0x31, 0x09, 0x8d, 0x1f, 0x1d, 0x96, 0x47, 0x3a, 0x02, 0x16, - 0xd7, 0x8d, 0xd4, 0x60, 0x78, 0xe9, 0x9b, 0xb6, 0x1b, 0xd0, 0x10, 0x55, 0x3b, 0x36, 0x3f, 0x77, - 0x93, 0x2f, 0x97, 0x37, 0xe5, 0x72, 0x79, 0x73, 0x4b, 0x2e, 0x97, 0xd5, 0x8b, 0x62, 0x32, 0x3e, - 0x43, 0x39, 0x4b, 0x3c, 0x3e, 0x7e, 0xe3, 0xcf, 0xca, 0x05, 0x5b, 0x4a, 0x22, 0x6f, 0xc0, 0xd0, - 0x5d, 0x3f, 0x38, 0x70, 0x22, 0xd1, 0x07, 0xd3, 0x47, 0x87, 0xe5, 0xe2, 0x23, 0x84, 0x68, 0x43, - 0x4a, 0xd0, 0x90, 0xbb, 0x30, 0x69, 0xfb, 0x9d, 0x88, 0x6e, 0xf9, 0xb2, 0xe7, 0x06, 0x91, 0xeb, - 0xd2, 0xd1, 0x61, 0x79, 0x2e, 0x60, 0x98, 0x7a, 0xe4, 0xd7, 0x45, 0x17, 0x6a, 0xfc, 0x09, 0x2e, - 0xb2, 0x04, 0x93, 0x15, 0x9c, 0xbd, 0x85, 0xd6, 0x78, 0x7f, 0x8d, 0x56, 0x2f, 0x1e, 0x1d, 0x96, - 0xcf, 0x39, 0x88, 0xa9, 0x07, 0x02, 0xa5, 0x8b, 0x31, 0x99, 0xc8, 0x3a, 0x9c, 0x79, 0xd0, 0xd9, - 0xa5, 0x81, 0x47, 0x23, 0x1a, 0xca, 0x1a, 0x0d, 0x63, 0x8d, 0x2e, 0x1f, 0x1d, 0x96, 0x2f, 0x3c, - 0x56, 0xc8, 0x8c, 0x3a, 0xa5, 0x59, 0x09, 0x85, 0xd3, 0xa2, 0xa2, 0x8b, 0x4e, 0xe4, 0xec, 0x3a, - 0x21, 0xc5, 0x49, 0x69, 0x6c, 0xfe, 0x2c, 0x57, 0xf1, 0xcd, 0x04, 0xb6, 0x7a, 0x55, 0x68, 0xf9, - 0xbc, 0x6a, 0x7b, 0x53, 0xa0, 0xb4, 0x82, 0x92, 0x32, 0xd9, 0xdc, 0xac, 0xd6, 0x9d, 0x51, 0xac, - 0x2d, 0xce, 0xcd, 0x6a, 0xdd, 0xd1, 0x67, 0x2d, 0xb5, 0x02, 0xad, 0xc2, 0xe0, 0x36, 0x5b, 0x9d, - 0x71, 0xce, 0x9a, 0x9c, 0xbf, 0x22, 0x6a, 0x94, 0x1c, 0x7f, 0x37, 0xd9, 0x0f, 0x24, 0xc4, 0x2f, - 0xef, 0x34, 0xae, 0xe8, 0xfa, 0x5a, 0x8c, 0x38, 0xf2, 0x19, 0x80, 0xa8, 0x55, 0xa5, 0xdd, 0x2e, - 0x8d, 0x61, 0x23, 0xcf, 0x98, 0x8d, 0xac, 0xb4, 0xdb, 0xd5, 0x4b, 0xa2, 0x7d, 0x67, 0x55, 0xfb, - 0x9c, 0x76, 0x5b, 0x93, 0xa6, 0x09, 0x21, 0x9f, 0xc0, 0x38, 0x4e, 0x69, 0xb2, 0x47, 0xc7, 0xb1, - 0x47, 0xcf, 0x1f, 0x1d, 0x96, 0x67, 0x71, 0xb6, 0xca, 0xe8, 0x4f, 0x83, 0x81, 0xfc, 0x32, 0xcc, - 0x08, 0x71, 0x0f, 0x5d, 0xaf, 0xe9, 0x3f, 0x0d, 0x17, 0x69, 0xf8, 0x38, 0xf2, 0xdb, 0x38, 0xfd, - 0x8d, 0xcd, 0x5f, 0x30, 0xab, 0x67, 0xd2, 0x54, 0x6f, 0x88, 0x9a, 0x5a, 0xaa, 0xa6, 0x4f, 0x39, - 0x41, 0xbd, 0xc9, 0x29, 0xf4, 0x09, 0x32, 0x53, 0x04, 0x59, 0x81, 0xd3, 0xdb, 0x21, 0x35, 0xda, - 0x30, 0x89, 0xeb, 0x43, 0x99, 0xf5, 0x70, 0x27, 0xa4, 0xf5, 0xbc, 0x76, 0x24, 0xf9, 0x88, 0x0d, - 0x64, 0x31, 0xf0, 0xdb, 0x89, 0x31, 0x7e, 0x1a, 0x35, 0x62, 0x1d, 0x1d, 0x96, 0x2f, 0x35, 0x03, - 0xbf, 0x5d, 0xcf, 0x1f, 0xe8, 0x19, 0xdc, 0xe4, 0xfb, 0x70, 0x76, 0xc1, 0xf7, 0x3c, 0xda, 0x60, - 0x33, 0xe8, 0xa2, 0xeb, 0xec, 0x79, 0x7e, 0x18, 0xb9, 0x8d, 0x95, 0xc5, 0x52, 0x31, 0x5e, 0x1e, - 0x1a, 0x8a, 0xa2, 0xde, 0x54, 0x24, 0xe6, 0xf2, 0x90, 0x23, 0x85, 0x7c, 0x05, 0x13, 0xa2, 0x2c, - 0x1a, 0xe0, 0xd0, 0x3c, 0xd3, 0x7d, 0xa0, 0x29, 0x62, 0xbe, 0xd0, 0x07, 0xf2, 0x27, 0xdf, 0x3a, - 0x99, 0xb2, 0xc8, 0xd7, 0x30, 0xb6, 0x76, 0xb7, 0x62, 0xd3, 0xb0, 0xed, 0x7b, 0x21, 0x2d, 0x11, - 0xec, 0xd1, 0x4b, 0x42, 0xf4, 0xda, 0xdd, 0x4a, 0xa5, 0x13, 0xed, 0x53, 0x2f, 0x72, 0x1b, 0x4e, - 0x44, 0x25, 0x55, 0x75, 0x8e, 0x8d, 0xbc, 0x83, 0x47, 0x4e, 0x3d, 0x10, 0x10, 0xad, 0x15, 0xba, - 0x38, 0x32, 0x07, 0x23, 0xb5, 0xda, 0xf2, 0xaa, 0xbf, 0xe7, 0x7a, 0xa5, 0x29, 0xa6, 0x0c, 0x5b, - 0xfd, 0x26, 0x8f, 0x60, 0x46, 0xb3, 0x0d, 0xea, 0xec, 0x7f, 0x7a, 0x40, 0xbd, 0xa8, 0x34, 0x8d, - 0x75, 0xf8, 0xae, 0x32, 0x6e, 0x6e, 0xea, 0x26, 0xc4, 0x93, 0x3b, 0x37, 0x2b, 0xf1, 0xcf, 0x9a, - 0x64, 0xaa, 0xf6, 0x95, 0x0a, 0xf6, 0xb4, 0x93, 0x81, 0x21, 0x5b, 0x30, 0xbc, 0xd9, 0x09, 0xda, - 0x7e, 0x48, 0x4b, 0x33, 0xa8, 0xb8, 0xab, 0xdd, 0xbe, 0x50, 0x41, 0x5a, 0x9d, 0x61, 0x53, 0x74, - 0x9b, 0xff, 0xd0, 0x5a, 0x27, 0x45, 0x91, 0x4f, 0x61, 0xbc, 0x56, 0x5b, 0x8e, 0x17, 0x94, 0xb3, - 0xb8, 0xa0, 0x5c, 0x38, 0x3a, 0x2c, 0x97, 0xd8, 0x96, 0x2a, 0x5e, 0x54, 0xf4, 0xaf, 0x4a, 0xe7, - 0x60, 0x12, 0xb6, 0x56, 0x6b, 0xb1, 0x84, 0xd9, 0x58, 0x02, 0xdb, 0xcc, 0x65, 0x4b, 0xd0, 0x39, - 0xc8, 0xbf, 0x2c, 0xc0, 0x65, 0x5d, 0x64, 0x96, 0x62, 0x4a, 0xe7, 0x9e, 0x47, 0x9b, 0xf3, 0x47, - 0x87, 0xe5, 0x9b, 0x66, 0x3b, 0xea, 0x99, 0x9d, 0xa5, 0xd5, 0xad, 0x67, 0x55, 0xb0, 0xbe, 0x7a, - 0x03, 0x32, 0xeb, 0x3b, 0xf7, 0xdc, 0xf5, 0x35, 0xb5, 0xd6, 0xbb, 0xbe, 0xbd, 0xaa, 0x62, 0x7d, - 0x0e, 0xa3, 0x6a, 0xd2, 0x26, 0xc3, 0xd0, 0x5f, 0x69, 0xb5, 0x8a, 0xa7, 0xd8, 0x1f, 0xb5, 0xda, - 0x72, 0xb1, 0x40, 0x26, 0x01, 0xe2, 0x95, 0xaa, 0xd8, 0x47, 0xc6, 0x61, 0x44, 0xae, 0x24, 0xc5, - 0x7e, 0xa4, 0x6f, 0xb7, 0x8b, 0x03, 0x84, 0xc0, 0xa4, 0x39, 0x9f, 0x15, 0x07, 0xad, 0xdf, 0x2c, - 0xc0, 0xa8, 0xfa, 0x0e, 0xc9, 0x69, 0x18, 0xdb, 0x5e, 0xaf, 0x6d, 0x2e, 0x2d, 0xac, 0xdc, 0x5d, - 0x59, 0x5a, 0x2c, 0x9e, 0x22, 0x17, 0xe1, 0xdc, 0x56, 0x6d, 0xb9, 0xbe, 0x58, 0xad, 0xaf, 0x6e, - 0x2c, 0x54, 0x56, 0xeb, 0x9b, 0xf6, 0xc6, 0xe7, 0x5f, 0xd4, 0xb7, 0xb6, 0xd7, 0xd7, 0x97, 0x56, - 0x8b, 0x05, 0x52, 0x82, 0x69, 0x86, 0x7e, 0xb0, 0x5d, 0x5d, 0xd2, 0x09, 0x8a, 0x7d, 0xe4, 0x0a, - 0x5c, 0xcc, 0xc2, 0xd4, 0x97, 0x97, 0x2a, 0x8b, 0xab, 0x4b, 0xb5, 0x5a, 0xb1, 0x9f, 0xcc, 0xc2, - 0x14, 0x23, 0xa9, 0x6c, 0x6e, 0x1a, 0xbc, 0x03, 0x56, 0x0b, 0xc6, 0xb4, 0x0f, 0x80, 0x5c, 0x80, - 0xd2, 0xc2, 0x92, 0xbd, 0x55, 0xdf, 0xdc, 0xb6, 0x37, 0x37, 0x6a, 0x4b, 0x75, 0xb3, 0x86, 0x49, - 0xec, 0xea, 0xc6, 0xbd, 0x95, 0xf5, 0x3a, 0x03, 0xd5, 0x8a, 0x05, 0x56, 0x0d, 0x03, 0x5b, 0x5b, - 0x59, 0xbf, 0xb7, 0xba, 0x54, 0xdf, 0xae, 0x2d, 0x09, 0x92, 0x3e, 0xeb, 0x57, 0xfb, 0x52, 0x4b, - 0x3a, 0x99, 0x87, 0xb1, 0x1a, 0xf7, 0x57, 0xe0, 0x34, 0xc7, 0x0d, 0x44, 0xb6, 0x47, 0x1b, 0x17, - 0x6e, 0x0c, 0x3e, 0x83, 0xe9, 0x44, 0x6c, 0x97, 0xb6, 0xc9, 0xbe, 0xe6, 0x86, 0xdf, 0xd2, 0x77, - 0x69, 0x6d, 0x01, 0xb3, 0x15, 0x96, 0xcc, 0x6b, 0xfb, 0x39, 0x6e, 0x2d, 0xa2, 0x45, 0x22, 0xf7, - 0x73, 0xfa, 0xda, 0xae, 0x76, 0x76, 0xf3, 0x71, 0x97, 0x8a, 0x6d, 0x18, 0xf2, 0x64, 0xec, 0x25, - 0x14, 0x1d, 0x79, 0x5d, 0xee, 0x74, 0xb9, 0x75, 0x87, 0x8b, 0x7d, 0xc2, 0x2e, 0x11, 0x9b, 0x5c, - 0xab, 0x93, 0xb3, 0xb0, 0x92, 0x0f, 0x92, 0x63, 0x46, 0x28, 0x03, 0x85, 0x25, 0xd6, 0x4f, 0x3b, - 0x41, 0x4a, 0xca, 0x30, 0xc8, 0x67, 0x5c, 0xae, 0x0f, 0xdc, 0x5b, 0xb7, 0x18, 0xc0, 0xe6, 0x70, - 0xeb, 0x8f, 0xfa, 0xf5, 0x4d, 0x06, 0xdb, 0x4b, 0x6b, 0xfa, 0xc6, 0xbd, 0x34, 0xea, 0x19, 0xa1, - 0xcc, 0x14, 0xe4, 0x5f, 0x09, 0x9a, 0x82, 0xfd, 0xb1, 0x29, 0x28, 0x3e, 0x35, 0x6e, 0x0a, 0xc6, - 0x24, 0xac, 0x17, 0xc5, 0xb6, 0x0d, 0xa5, 0x0e, 0xc4, 0xbd, 0x28, 0xb6, 0x7a, 0xa2, 0x17, 0x35, - 0x22, 0xf2, 0x3e, 0x40, 0xe5, 0x61, 0x0d, 0x6d, 0x1e, 0x7b, 0x5d, 0x6c, 0x5d, 0x71, 0x91, 0x71, - 0x9e, 0x86, 0xc2, 0xa4, 0x0a, 0x74, 0x9b, 0x51, 0xa3, 0x26, 0x55, 0x98, 0xa8, 0xfc, 0xa8, 0x13, - 0xd0, 0x95, 0x26, 0x5b, 0xa7, 0x22, 0x6e, 0x1c, 0x8f, 0xf2, 0x89, 0xd4, 0x61, 0x88, 0xba, 0x2b, - 0x30, 0x9a, 0x00, 0x93, 0x85, 0x6c, 0xc0, 0x99, 0x7b, 0x0b, 0x9b, 0x62, 0x5c, 0x55, 0x1a, 0x0d, - 0xbf, 0xe3, 0x45, 0x62, 0xbf, 0x7a, 0xe5, 0xe8, 0xb0, 0x7c, 0x71, 0xaf, 0xd1, 0xae, 0xcb, 0x31, - 0xe8, 0x70, 0xb4, 0xbe, 0x61, 0x4d, 0xf1, 0x92, 0xab, 0xd0, 0xbf, 0x6d, 0xaf, 0x08, 0xcb, 0xf9, - 0xcc, 0xd1, 0x61, 0x79, 0xa2, 0x13, 0xb8, 0x1a, 0x0b, 0xc3, 0x92, 0xf7, 0x00, 0xb6, 0x9c, 0x60, - 0x8f, 0x46, 0x9b, 0x7e, 0x10, 0xe1, 0x86, 0x73, 0xa2, 0x7a, 0xee, 0xe8, 0xb0, 0x3c, 0x13, 0x21, - 0xb4, 0xce, 0xa6, 0x3f, 0xbd, 0xd1, 0x31, 0xf1, 0xfd, 0x81, 0x91, 0xbe, 0x62, 0xbf, 0x3d, 0x5a, - 0xa3, 0x61, 0xc8, 0xed, 0xc3, 0x16, 0x4c, 0xde, 0xa3, 0x11, 0x1b, 0xb8, 0xd2, 0xde, 0xe9, 0xde, - 0xad, 0x1f, 0xc2, 0xd8, 0x43, 0x37, 0xda, 0xaf, 0xd1, 0x46, 0x40, 0x23, 0xe9, 0xeb, 0x41, 0x95, - 0x3f, 0x75, 0xa3, 0xfd, 0x7a, 0xc8, 0xe1, 0xfa, 0xba, 0xae, 0x91, 0x5b, 0x4b, 0x70, 0x5a, 0x94, - 0xa6, 0xcc, 0xab, 0x79, 0x53, 0x60, 0x01, 0x05, 0x62, 0xb7, 0xeb, 0x02, 0x4d, 0x31, 0xff, 0xaa, - 0x0f, 0x66, 0x16, 0xf6, 0x1d, 0x6f, 0x8f, 0x6e, 0x3a, 0x61, 0xf8, 0xd4, 0x0f, 0x9a, 0x5a, 0xe5, - 0xd1, 0xb6, 0x4c, 0x55, 0x1e, 0x8d, 0xc9, 0x79, 0x18, 0xdb, 0x68, 0x35, 0x25, 0x8f, 0xb0, 0x7b, - 0xb1, 0x2c, 0xbf, 0xd5, 0xac, 0xb7, 0xa5, 0x2c, 0x9d, 0x88, 0xf1, 0xac, 0xd3, 0xa7, 0x8a, 0xa7, - 0x3f, 0xe6, 0xf1, 0xe8, 0x53, 0x8d, 0x47, 0x23, 0x22, 0x4b, 0x70, 0xa6, 0x46, 0x1b, 0xbe, 0xd7, - 0xbc, 0xeb, 0x34, 0x22, 0x3f, 0xd8, 0xf2, 0x1f, 0x53, 0x4f, 0x0c, 0x68, 0x34, 0x0c, 0x42, 0x44, - 0xd6, 0x1f, 0x21, 0xb6, 0x1e, 0x31, 0xb4, 0x9d, 0xe6, 0x20, 0x1b, 0x30, 0xf2, 0x50, 0x78, 0x0c, - 0x85, 0xb1, 0x7c, 0xed, 0xa6, 0x72, 0x21, 0x2e, 0x04, 0x14, 0x47, 0xa1, 0xd3, 0x52, 0xe6, 0xbe, - 0xda, 0x67, 0xe1, 0x54, 0x26, 0x29, 0x6d, 0x25, 0xc4, 0xda, 0x86, 0x89, 0xcd, 0x56, 0x67, 0xcf, - 0xf5, 0xd8, 0xa4, 0x53, 0xa3, 0x3f, 0x24, 0x8b, 0x00, 0x31, 0x40, 0xf8, 0x01, 0xa7, 0x84, 0x89, - 0x1d, 0x23, 0x76, 0xde, 0x14, 0x5f, 0x2e, 0x42, 0xd0, 0x22, 0xb2, 0x35, 0x3e, 0xeb, 0x7f, 0xf7, - 0x03, 0x11, 0x1d, 0x80, 0x8b, 0x60, 0x8d, 0x46, 0x6c, 0x79, 0x3a, 0x0b, 0x7d, 0xca, 0x5d, 0x37, - 0x74, 0x74, 0x58, 0xee, 0x73, 0x9b, 0x76, 0xdf, 0xca, 0x22, 0x79, 0x0b, 0x06, 0x91, 0x0c, 0xf5, - 0x3f, 0xa9, 0xca, 0xd3, 0x25, 0xf0, 0xc9, 0x07, 0x57, 0x5f, 0x9b, 0x13, 0x93, 0xb7, 0x61, 0x74, - 0x91, 0xb6, 0xe8, 0x9e, 0x13, 0xf9, 0x72, 0x3a, 0xe1, 0x0e, 0x30, 0x09, 0xd4, 0xc6, 0x5c, 0x4c, - 0xc9, 0xcc, 0x61, 0x9b, 0x3a, 0xa1, 0xef, 0xe9, 0xe6, 0x70, 0x80, 0x10, 0xdd, 0x1c, 0xe6, 0x34, - 0xe4, 0xb7, 0x0a, 0x30, 0x56, 0xf1, 0x3c, 0xe1, 0x58, 0x0a, 0x85, 0xd6, 0x67, 0x6e, 0x2a, 0x4f, - 0xec, 0xaa, 0xb3, 0x4b, 0x5b, 0x3b, 0x4e, 0xab, 0x43, 0xc3, 0xea, 0xd7, 0xcc, 0x42, 0xf9, 0x4f, - 0x87, 0xe5, 0x0f, 0x4e, 0xe0, 0x2a, 0x8a, 0x7d, 0xba, 0x5b, 0x81, 0xe3, 0x46, 0x21, 0xfb, 0x6a, - 0x9d, 0xb8, 0x40, 0xfd, 0xbb, 0xd1, 0xea, 0x11, 0xaf, 0x0d, 0x43, 0xbd, 0xd6, 0x06, 0x72, 0x00, - 0xa7, 0x2b, 0x61, 0xd8, 0x39, 0xa0, 0xb5, 0xc8, 0x09, 0xa2, 0x2d, 0xf7, 0x80, 0xe2, 0x84, 0xd4, - 0xdd, 0xb9, 0xf0, 0xda, 0x4f, 0x0e, 0xcb, 0x05, 0x66, 0x14, 0x39, 0xc8, 0xca, 0xf6, 0x3d, 0x41, - 0x54, 0x8f, 0x5c, 0x7d, 0x79, 0x43, 0x37, 0x43, 0x52, 0xb6, 0x75, 0x55, 0x6d, 0x48, 0x56, 0x16, - 0xf3, 0x7a, 0xdc, 0x5a, 0x80, 0x0b, 0xf7, 0x68, 0x64, 0xd3, 0x90, 0x46, 0xf2, 0x1b, 0xc1, 0x11, - 0x1e, 0x3b, 0x77, 0x87, 0xf1, 0xb7, 0x62, 0xc6, 0xee, 0xe7, 0xdf, 0x85, 0xc4, 0x58, 0x7f, 0xad, - 0x00, 0xe5, 0x85, 0x80, 0x72, 0x7b, 0x22, 0x47, 0x50, 0xf7, 0xb9, 0xeb, 0x02, 0x0c, 0x6c, 0x3d, - 0x6b, 0x4b, 0xaf, 0x0c, 0x62, 0x59, 0xa7, 0xd8, 0x08, 0x3d, 0xa6, 0x93, 0xcb, 0x7a, 0x04, 0x33, - 0x36, 0xf5, 0xe8, 0x53, 0x67, 0xb7, 0x45, 0x0d, 0x3f, 0x51, 0x19, 0x06, 0xf9, 0x87, 0x9e, 0x6a, - 0x02, 0x87, 0x9f, 0xcc, 0xe7, 0x66, 0x4d, 0xc0, 0xd8, 0xa6, 0xeb, 0xed, 0x09, 0xe9, 0xd6, 0x9f, - 0x0f, 0xc0, 0x38, 0xff, 0x2d, 0x4c, 0xa4, 0xc4, 0x72, 0x59, 0x38, 0xce, 0x72, 0xf9, 0x2e, 0x4c, - 0xb0, 0xf5, 0x86, 0x06, 0x3b, 0x34, 0x60, 0xf3, 0xbf, 0xd0, 0x04, 0x9a, 0x7b, 0x21, 0x22, 0xea, - 0x4f, 0x38, 0xc6, 0x36, 0x09, 0xc9, 0x2a, 0x4c, 0x72, 0xc0, 0x5d, 0xea, 0x44, 0x9d, 0xd8, 0x63, - 0x75, 0x5a, 0xd8, 0x44, 0x12, 0xcc, 0x87, 0xa6, 0x90, 0xf5, 0x48, 0x00, 0xed, 0x04, 0x2f, 0xf9, - 0x04, 0x4e, 0x6f, 0x06, 0xfe, 0x37, 0xcf, 0xb4, 0x0d, 0x02, 0xff, 0x3a, 0xb9, 0xf5, 0xc4, 0x50, - 0x75, 0x7d, 0x9b, 0x90, 0xa4, 0x26, 0xaf, 0xc3, 0xc8, 0x4a, 0x58, 0xf5, 0x03, 0xd7, 0xdb, 0xc3, - 0x6f, 0x74, 0x84, 0x3b, 0xfa, 0xdd, 0xb0, 0xbe, 0x8b, 0x40, 0x5b, 0xa1, 0x13, 0x2e, 0xe9, 0xe1, - 0xde, 0x2e, 0xe9, 0xdb, 0x00, 0xab, 0xbe, 0xd3, 0xac, 0xb4, 0x5a, 0x0b, 0x95, 0x10, 0x57, 0x62, - 0xb1, 0x1e, 0xb5, 0x7c, 0xa7, 0x59, 0x77, 0x5a, 0xad, 0x7a, 0xc3, 0x09, 0x6d, 0x8d, 0x86, 0x7c, - 0x09, 0xe7, 0x42, 0x77, 0xcf, 0xc3, 0xc6, 0xd5, 0x9d, 0xd6, 0x9e, 0x1f, 0xb8, 0xd1, 0xfe, 0x41, - 0x3d, 0xec, 0xb8, 0x11, 0xf7, 0x07, 0x4d, 0xce, 0x5f, 0x12, 0x93, 0x5c, 0x4d, 0xd2, 0x55, 0x24, - 0x59, 0x8d, 0x51, 0xd9, 0xb3, 0x61, 0x36, 0x82, 0x3c, 0x84, 0x89, 0x55, 0xb7, 0x41, 0xbd, 0x90, - 0xa2, 0x83, 0xef, 0x19, 0x7a, 0x8b, 0xba, 0x7f, 0xcc, 0x4c, 0x89, 0x13, 0x2d, 0x9d, 0x09, 0x3f, - 0x5d, 0x53, 0xce, 0xfd, 0x81, 0x91, 0xa1, 0xe2, 0xb0, 0x7d, 0x5a, 0x00, 0x1f, 0x3a, 0x81, 0xe7, - 0x7a, 0x7b, 0xa1, 0xf5, 0xb7, 0x09, 0x8c, 0xa8, 0x7e, 0xba, 0xa9, 0x5b, 0x2a, 0x62, 0x69, 0xc6, - 0x21, 0x1b, 0xfb, 0xe1, 0x6c, 0x8d, 0x82, 0x9c, 0x43, 0xdb, 0x45, 0x6c, 0x0a, 0x86, 0xd9, 0x27, - 0xe4, 0xb4, 0xdb, 0x36, 0x83, 0xb1, 0xa9, 0x61, 0xb1, 0x8a, 0x83, 0x66, 0x84, 0x4f, 0x0d, 0xcd, - 0x5d, 0xbb, 0x6f, 0xb1, 0xca, 0xbe, 0xc9, 0x8d, 0x95, 0xc5, 0x05, 0xec, 0xff, 0x11, 0xfe, 0x4d, - 0xfa, 0x6e, 0xb3, 0x61, 0x23, 0x94, 0x61, 0x6b, 0x95, 0xb5, 0x55, 0xd1, 0xc7, 0x88, 0x0d, 0x9d, - 0x83, 0x96, 0x8d, 0x50, 0xb6, 0xdb, 0xe5, 0x2e, 0x95, 0x05, 0xdf, 0x8b, 0x02, 0xbf, 0x15, 0xe2, - 0x16, 0x6e, 0x84, 0x8f, 0x41, 0xe1, 0x8b, 0x69, 0x08, 0x94, 0x9d, 0x20, 0x25, 0x0f, 0x61, 0xb6, - 0xd2, 0x7c, 0xe2, 0x78, 0x0d, 0xda, 0xe4, 0x98, 0x87, 0x7e, 0xf0, 0xf8, 0x51, 0xcb, 0x7f, 0x1a, - 0xe2, 0x20, 0x19, 0x11, 0xae, 0x4b, 0x41, 0x22, 0x5d, 0x3b, 0x4f, 0x25, 0x91, 0x9d, 0xc7, 0xcd, - 0xe6, 0x81, 0x85, 0x96, 0xdf, 0x69, 0x8a, 0xa1, 0x83, 0xf3, 0x40, 0x83, 0x01, 0x6c, 0x0e, 0x67, - 0x5a, 0x5a, 0xae, 0xad, 0xe1, 0xc0, 0x10, 0x5a, 0xda, 0x0f, 0x0f, 0x6c, 0x06, 0x23, 0xd7, 0x60, - 0x58, 0x6e, 0xdc, 0xf9, 0x49, 0x06, 0x7a, 0xd0, 0xe5, 0x86, 0x5d, 0xe2, 0xd8, 0x77, 0x6c, 0xd3, - 0x86, 0xff, 0x84, 0x06, 0xcf, 0x16, 0xfc, 0x26, 0x95, 0x6e, 0x2d, 0xe1, 0xb6, 0xe1, 0x88, 0x7a, - 0x83, 0x61, 0x6c, 0x93, 0x90, 0x15, 0xc0, 0x17, 0xee, 0xb0, 0x74, 0x3a, 0x2e, 0x80, 0x2f, 0xec, - 0xa1, 0x2d, 0x71, 0x64, 0x11, 0xce, 0x54, 0x3a, 0x91, 0x7f, 0xe0, 0x44, 0x6e, 0x63, 0xbb, 0xbd, - 0x17, 0x38, 0xac, 0x90, 0x22, 0x32, 0xa0, 0x21, 0xe3, 0x48, 0x64, 0xbd, 0x23, 0xb0, 0x76, 0x9a, - 0x81, 0xbc, 0x03, 0xe3, 0x2b, 0x21, 0x77, 0x5d, 0x3a, 0x21, 0x6d, 0xa2, 0xff, 0x49, 0xd4, 0xd2, - 0x0d, 0xeb, 0xe8, 0xc8, 0xac, 0x33, 0xd3, 0xa7, 0x69, 0x1b, 0x74, 0xc4, 0x82, 0xa1, 0x4a, 0x18, - 0xba, 0x61, 0x84, 0x6e, 0xa5, 0x91, 0x2a, 0x1c, 0x1d, 0x96, 0x87, 0x1c, 0x84, 0xd8, 0x02, 0x43, - 0x1e, 0xc2, 0xd8, 0x22, 0x65, 0x3b, 0xe7, 0xad, 0xa0, 0x13, 0x46, 0xe8, 0x24, 0x1a, 0x9b, 0x3f, - 0x27, 0x66, 0x23, 0x0d, 0x23, 0xc6, 0x32, 0xdf, 0xa2, 0x36, 0x11, 0x5e, 0x8f, 0x18, 0x42, 0x5f, - 0x6a, 0x35, 0x7a, 0x66, 0x16, 0x08, 0x9e, 0x65, 0xb7, 0xc9, 0xe6, 0x97, 0x69, 0xac, 0x03, 0x9a, - 0x05, 0x62, 0x42, 0xab, 0xef, 0x23, 0x46, 0x37, 0x0b, 0x0c, 0x16, 0xd2, 0x48, 0x79, 0xc3, 0x67, - 0x0c, 0x8f, 0xa7, 0x89, 0x94, 0x55, 0x3c, 0xa1, 0xaf, 0xfc, 0x43, 0x18, 0x5b, 0xe8, 0x84, 0x91, - 0x7f, 0xb0, 0xb5, 0x4f, 0x0f, 0x28, 0x3a, 0x92, 0x84, 0xf1, 0xd3, 0x40, 0x70, 0x3d, 0x62, 0x70, - 0xbd, 0x99, 0x1a, 0x39, 0xf9, 0x0c, 0x88, 0xb4, 0x62, 0xee, 0xb1, 0xf1, 0xe1, 0xb1, 0xb1, 0x8c, - 0xbe, 0xa4, 0x11, 0x6e, 0xba, 0x48, 0xe3, 0xa7, 0xbe, 0xa7, 0xd0, 0xba, 0x3f, 0x33, 0xcd, 0xcc, - 0x2a, 0xc4, 0xab, 0x78, 0x2f, 0x70, 0xda, 0xfb, 0xa5, 0x52, 0x6c, 0x1a, 0x88, 0x46, 0xed, 0x31, - 0xb8, 0xb1, 0xc5, 0x89, 0xc9, 0x49, 0x0d, 0x80, 0xff, 0x5c, 0x65, 0x1d, 0xcf, 0xbd, 0x4f, 0x25, - 0x43, 0x5f, 0x0c, 0x21, 0x75, 0x85, 0xe6, 0x8e, 0x10, 0xdb, 0x72, 0x8d, 0xde, 0xd4, 0xc4, 0x90, - 0xc7, 0x50, 0xe4, 0xbf, 0xd6, 0x7c, 0xcf, 0x8d, 0xf8, 0x7a, 0x31, 0x67, 0xb8, 0x2a, 0x93, 0x68, - 0x59, 0x00, 0xba, 0x88, 0x45, 0x01, 0x07, 0x0a, 0xab, 0x15, 0x93, 0x12, 0x4c, 0x36, 0x61, 0x6c, - 0x33, 0xf0, 0x9b, 0x9d, 0x46, 0x84, 0xbb, 0x8c, 0xf3, 0x38, 0xf1, 0x13, 0x51, 0x8e, 0x86, 0xe1, - 0x3a, 0x69, 0x73, 0x40, 0x9d, 0xad, 0x0b, 0xba, 0x4e, 0x34, 0x42, 0x52, 0x85, 0xa1, 0x4d, 0xbf, - 0xe5, 0x36, 0x9e, 0x95, 0x2e, 0x60, 0xa5, 0xa7, 0xa5, 0x30, 0x04, 0xca, 0xaa, 0xe2, 0x96, 0xb6, - 0x8d, 0x20, 0x7d, 0x4b, 0xcb, 0x89, 0x48, 0x05, 0x26, 0x3e, 0x63, 0x03, 0xc6, 0xf5, 0x3d, 0xcf, - 0x71, 0x03, 0x5a, 0xba, 0x88, 0xfd, 0x82, 0x6e, 0xfc, 0x1f, 0xea, 0x08, 0x7d, 0x38, 0x1b, 0x1c, - 0x64, 0x05, 0x4e, 0xaf, 0x84, 0xb5, 0x28, 0x70, 0xdb, 0x74, 0xcd, 0xf1, 0x9c, 0x3d, 0xda, 0x2c, - 0x5d, 0x8a, 0xfd, 0xe8, 0x6e, 0x58, 0x0f, 0x11, 0x57, 0x3f, 0xe0, 0x48, 0xdd, 0x8f, 0x9e, 0xe0, - 0x23, 0x9f, 0xc3, 0xf4, 0xd2, 0x37, 0x11, 0x1b, 0x31, 0xad, 0x4a, 0xa7, 0xe9, 0x46, 0xb5, 0xc8, - 0x0f, 0x9c, 0x3d, 0x5a, 0x2a, 0xa3, 0xbc, 0x57, 0x8e, 0x0e, 0xcb, 0x97, 0xa9, 0xc0, 0xd7, 0x1d, - 0x46, 0x50, 0x0f, 0x39, 0x85, 0x7e, 0x3e, 0x9e, 0x25, 0x81, 0x69, 0xbf, 0xd6, 0x69, 0xb3, 0xdd, - 0x36, 0x6a, 0xff, 0xb2, 0xa1, 0x7d, 0x0d, 0xc3, 0xb5, 0x1f, 0x72, 0x40, 0x4a, 0xfb, 0x1a, 0x21, - 0xb1, 0x81, 0xdc, 0xf7, 0x5d, 0xaf, 0xd2, 0x88, 0xdc, 0x27, 0x54, 0x58, 0xcc, 0x61, 0xe9, 0x0a, - 0xd6, 0x14, 0x7d, 0xfe, 0xbf, 0xe8, 0xbb, 0x5e, 0xdd, 0x41, 0x74, 0x3d, 0x14, 0x78, 0xfd, 0x1b, - 0x49, 0x73, 0x93, 0xef, 0xc3, 0xd9, 0x35, 0x7f, 0xd7, 0x6d, 0x51, 0x3e, 0xe5, 0x70, 0xb5, 0xa0, - 0xff, 0xd2, 0x42, 0xb9, 0xe8, 0xf3, 0x3f, 0x40, 0x8a, 0xba, 0x98, 0xad, 0x0e, 0x14, 0x8d, 0xee, - 0xf3, 0xcf, 0x96, 0x42, 0x96, 0x60, 0x1c, 0xbf, 0xcb, 0x16, 0xfe, 0x0c, 0x4b, 0x57, 0xd1, 0xa4, - 0xbb, 0x92, 0xd8, 0xa5, 0xdd, 0x5c, 0xd2, 0x68, 0x96, 0xbc, 0x28, 0x78, 0x66, 0x1b, 0x6c, 0xe4, - 0x63, 0x98, 0x4b, 0x0e, 0xef, 0x05, 0xdf, 0x7b, 0xe4, 0xee, 0x75, 0x02, 0xda, 0x2c, 0xbd, 0xc2, - 0xaa, 0x6a, 0x77, 0xa1, 0x20, 0x5f, 0xc1, 0x0c, 0xae, 0x75, 0x15, 0xcf, 0xf7, 0x9e, 0x1d, 0xb8, - 0x3f, 0xc2, 0xfd, 0x33, 0xdb, 0xf6, 0x5e, 0xc3, 0x6d, 0xef, 0xb5, 0xa3, 0xc3, 0xf2, 0x15, 0x5c, - 0x13, 0xeb, 0x8e, 0x4e, 0x91, 0xf0, 0x5a, 0x67, 0xcb, 0x98, 0x7b, 0x08, 0x67, 0x52, 0xf5, 0x27, - 0x45, 0xe8, 0x7f, 0x2c, 0xce, 0x67, 0x47, 0x6d, 0xf6, 0x27, 0x79, 0x03, 0x06, 0x9f, 0x30, 0x43, - 0x0d, 0xb7, 0x23, 0xf1, 0x89, 0x9f, 0xc6, 0xba, 0xe2, 0x3d, 0xf2, 0x6d, 0x4e, 0xf4, 0x7e, 0xdf, - 0xbb, 0x85, 0xfb, 0x03, 0x23, 0x63, 0xc5, 0x71, 0x7e, 0xac, 0x7e, 0x7f, 0x60, 0x64, 0xa2, 0x38, - 0x69, 0x55, 0xe0, 0x74, 0x82, 0x9e, 0x94, 0x60, 0x98, 0x7a, 0x6c, 0xf3, 0xdf, 0xe4, 0x1b, 0x22, - 0x5b, 0xfe, 0x24, 0xd3, 0x30, 0xd8, 0x72, 0x0f, 0xdc, 0x08, 0x0b, 0x1c, 0xb4, 0xf9, 0x0f, 0xeb, - 0xb7, 0x0b, 0x40, 0xd2, 0xeb, 0x11, 0xb9, 0x95, 0x10, 0xc3, 0xb7, 0xbe, 0x02, 0xa4, 0x1f, 0x1c, - 0x48, 0xe9, 0x9f, 0xc1, 0x14, 0x1f, 0x10, 0x72, 0xe5, 0xd4, 0xca, 0xe2, 0x33, 0x76, 0x06, 0x5a, - 0x77, 0x36, 0x09, 0x34, 0xae, 0xb3, 0xab, 0x58, 0xb5, 0x0e, 0xcc, 0x64, 0xae, 0x44, 0x64, 0x0d, - 0x66, 0x0e, 0x7c, 0x2f, 0xda, 0x6f, 0x3d, 0x93, 0x0b, 0x91, 0x28, 0xad, 0x80, 0xa5, 0xe1, 0xe4, - 0x9b, 0x49, 0x60, 0x4f, 0x09, 0xb0, 0x90, 0x88, 0xe5, 0x08, 0xa7, 0x93, 0x6c, 0x89, 0x65, 0xc3, - 0x99, 0xd4, 0x84, 0x4e, 0x3e, 0x82, 0xf1, 0x06, 0x1a, 0x77, 0x46, 0x49, 0x7c, 0x39, 0xd3, 0xe0, - 0xfa, 0xb7, 0xca, 0xe1, 0xbc, 0x29, 0xff, 0xac, 0x00, 0xb3, 0x39, 0x53, 0xf9, 0xc9, 0x55, 0xfd, - 0x05, 0x9c, 0x3d, 0x70, 0xbe, 0xa9, 0x07, 0x68, 0xbb, 0xd7, 0x03, 0xc7, 0x4b, 0x68, 0x1b, 0xa7, - 0xa9, 0x6c, 0x0a, 0x3d, 0xb6, 0xe9, 0xc0, 0xf9, 0xc6, 0x46, 0x02, 0x9b, 0xe1, 0x79, 0x3d, 0x3f, - 0x85, 0x09, 0x63, 0xf2, 0x3e, 0x71, 0xe5, 0xac, 0x3b, 0x70, 0x66, 0x91, 0xb6, 0x68, 0x44, 0x8f, - 0xed, 0xb3, 0xb3, 0x36, 0x01, 0x6a, 0xf4, 0xc0, 0x69, 0xef, 0xfb, 0x6c, 0x53, 0x5f, 0xd5, 0x7f, - 0x09, 0x9f, 0x0f, 0x91, 0xe6, 0x89, 0x44, 0xec, 0xbc, 0xc9, 0x37, 0xfa, 0xa1, 0xa2, 0xb4, 0x35, - 0x2e, 0xeb, 0xdf, 0xf7, 0x01, 0x11, 0xb3, 0x6f, 0x40, 0x9d, 0x03, 0x59, 0x8d, 0xf7, 0x60, 0x9c, - 0x5b, 0xe8, 0x1c, 0x8c, 0xd5, 0x19, 0x9b, 0x9f, 0x12, 0x5f, 0x9e, 0x8e, 0x5a, 0x3e, 0x65, 0x1b, - 0xa4, 0x8c, 0xd5, 0xa6, 0xdc, 0xb5, 0x80, 0xac, 0x7d, 0x06, 0xab, 0x8e, 0x62, 0xac, 0xfa, 0x6f, - 0xf2, 0x09, 0x4c, 0x2e, 0xf8, 0x07, 0x6d, 0xa6, 0x13, 0xc1, 0xdc, 0x2f, 0xdc, 0x36, 0xa2, 0x5c, - 0x03, 0xb9, 0x7c, 0xca, 0x4e, 0x90, 0x93, 0x75, 0x98, 0xba, 0xdb, 0xea, 0x84, 0xfb, 0x15, 0xaf, - 0xb9, 0xd0, 0xf2, 0x43, 0x29, 0x65, 0x40, 0x58, 0x5a, 0x62, 0xee, 0x4c, 0x53, 0x2c, 0x9f, 0xb2, - 0xb3, 0x18, 0xc9, 0x35, 0x18, 0x5c, 0x7a, 0xc2, 0xe6, 0x74, 0x19, 0xe1, 0x22, 0x02, 0xf0, 0x36, - 0x3c, 0xba, 0xf1, 0x68, 0xf9, 0x94, 0xcd, 0xb1, 0xd5, 0x51, 0x18, 0x96, 0xd6, 0xfd, 0x2d, 0xb6, - 0xdf, 0x56, 0xea, 0xac, 0x45, 0x4e, 0xd4, 0x09, 0xc9, 0x1c, 0x8c, 0x6c, 0xb7, 0x99, 0xd1, 0x29, - 0xdd, 0x22, 0xb6, 0xfa, 0x6d, 0xbd, 0x61, 0x6a, 0x9a, 0x5c, 0x80, 0xd8, 0xa7, 0x2b, 0x88, 0x35, - 0x27, 0xef, 0xb2, 0xa9, 0xdc, 0xee, 0xd4, 0x46, 0xb9, 0x7d, 0x89, 0x72, 0x8b, 0x49, 0x5d, 0x5b, - 0x33, 0x99, 0xca, 0xb3, 0x3e, 0x87, 0x4b, 0xdb, 0xed, 0x90, 0x06, 0x51, 0xa5, 0xdd, 0x6e, 0xb9, - 0x0d, 0x7e, 0x42, 0x86, 0x5e, 0x00, 0x39, 0x58, 0xde, 0x81, 0x21, 0x0e, 0x10, 0xc3, 0x44, 0x8e, - 0xc1, 0x4a, 0xbb, 0x2d, 0x7c, 0x0f, 0x6f, 0xf2, 0x9d, 0x3f, 0xf7, 0x26, 0xd8, 0x82, 0xda, 0xfa, - 0x8d, 0x02, 0x5c, 0xe2, 0x5f, 0x40, 0xae, 0xe8, 0xef, 0xc0, 0x28, 0xc6, 0xbf, 0xb5, 0x9d, 0x86, - 0xfc, 0x26, 0x78, 0x20, 0xa0, 0x04, 0xda, 0x31, 0x5e, 0x8b, 0x2c, 0xec, 0xcb, 0x8f, 0x2c, 0x94, - 0x1f, 0x58, 0x7f, 0xe6, 0x07, 0xf6, 0x19, 0x58, 0xa2, 0x46, 0xad, 0x56, 0xaa, 0x52, 0xe1, 0xf3, - 0xd4, 0xca, 0xfa, 0xef, 0x7d, 0x30, 0x7b, 0x8f, 0x7a, 0x34, 0x70, 0xb0, 0x9d, 0x86, 0x97, 0x4b, - 0x8f, 0x30, 0x2a, 0x74, 0x8d, 0x30, 0x2a, 0x4b, 0xbf, 0x61, 0x1f, 0xfa, 0x0d, 0x53, 0xe1, 0x52, - 0xcc, 0x16, 0xdd, 0xb6, 0x57, 0x44, 0xb3, 0xd0, 0x16, 0xed, 0x04, 0x2e, 0x3f, 0x65, 0x58, 0x89, - 0xa3, 0x93, 0x06, 0x7a, 0xfa, 0x1c, 0xa6, 0x44, 0xb4, 0xc6, 0xb0, 0x88, 0x4e, 0x32, 0x63, 0x92, - 0xd6, 0x61, 0x88, 0xbb, 0x3b, 0xf1, 0x6c, 0x6b, 0x6c, 0xfe, 0x86, 0xf8, 0xa6, 0x72, 0x1a, 0x28, - 0x7c, 0xa3, 0xb8, 0xb0, 0xf3, 0x21, 0x10, 0x21, 0xc0, 0x16, 0x52, 0xe6, 0x3e, 0x83, 0x31, 0x8d, - 0xe4, 0x38, 0x6b, 0xbf, 0x72, 0xbb, 0xb2, 0xed, 0xa8, 0xb7, 0xc7, 0x3d, 0xb8, 0xda, 0xda, 0x6f, - 0x7d, 0x00, 0xa5, 0x74, 0x6d, 0x84, 0xab, 0xad, 0x97, 0x67, 0xcf, 0x5a, 0x84, 0xe9, 0x7b, 0x34, - 0xc2, 0x81, 0x8b, 0x1f, 0x91, 0x16, 0x65, 0x97, 0xf8, 0xce, 0xe4, 0xac, 0x8a, 0x40, 0x36, 0xc0, - 0xb4, 0xaf, 0xb4, 0x06, 0x33, 0x09, 0x29, 0xa2, 0xfc, 0xf7, 0x61, 0x58, 0x80, 0xd4, 0x8c, 0x2a, - 0x42, 0x75, 0xe9, 0xae, 0x40, 0xec, 0xcc, 0xf3, 0x71, 0x2b, 0x24, 0xdb, 0x92, 0xc1, 0xda, 0x87, - 0xb3, 0x6c, 0x99, 0x8d, 0xa5, 0xaa, 0xe1, 0x78, 0x1e, 0x46, 0xdb, 0x6c, 0xa3, 0x10, 0xba, 0x3f, - 0xe2, 0xc3, 0x68, 0xd0, 0x1e, 0x61, 0x80, 0x9a, 0xfb, 0x23, 0x4a, 0x2e, 0x02, 0x20, 0x12, 0x9b, - 0x29, 0x66, 0x01, 0x24, 0xe7, 0xae, 0x4c, 0x02, 0x18, 0xa3, 0xc7, 0xc7, 0x8d, 0x8d, 0x7f, 0x5b, - 0x01, 0xcc, 0xa6, 0x4a, 0x12, 0x0d, 0xb8, 0x05, 0x23, 0x72, 0x7f, 0x9c, 0x38, 0x64, 0xd0, 0x5b, - 0x60, 0x2b, 0x22, 0xf2, 0x2a, 0x9c, 0xf6, 0xe8, 0x37, 0x51, 0x3d, 0x55, 0x87, 0x09, 0x06, 0xde, - 0x94, 0xf5, 0xb0, 0x7e, 0x01, 0x1d, 0xcb, 0x35, 0xcf, 0x7f, 0xfa, 0xa8, 0xe5, 0x3c, 0xa6, 0xa9, - 0x82, 0x3f, 0x82, 0x91, 0x5a, 0xef, 0x82, 0xf9, 0xe7, 0x23, 0x0b, 0xb7, 0x15, 0x8b, 0xd5, 0x82, - 0x39, 0xd6, 0xa4, 0x5a, 0x65, 0x6d, 0x75, 0xa5, 0xb9, 0xf9, 0x6d, 0x2b, 0xf0, 0x09, 0x9c, 0xcf, - 0x2c, 0xed, 0xdb, 0x56, 0xe2, 0x1f, 0x0c, 0xc0, 0x2c, 0x5f, 0x4c, 0xd2, 0x23, 0xf8, 0xf8, 0x53, - 0xcd, 0xcf, 0xe5, 0xbc, 0xf7, 0x76, 0xc6, 0x79, 0x2f, 0xb2, 0xe8, 0xe7, 0xbd, 0xc6, 0x29, 0xef, - 0xbb, 0xd9, 0xa7, 0xbc, 0xe8, 0x84, 0x32, 0x4f, 0x79, 0x93, 0x67, 0xbb, 0x4b, 0xf9, 0x67, 0xbb, - 0x78, 0xf0, 0x94, 0x71, 0xb6, 0x9b, 0x75, 0xa2, 0x9b, 0x08, 0x94, 0x1a, 0x79, 0xb9, 0x81, 0x52, - 0xaf, 0xc2, 0x70, 0xa5, 0xdd, 0xd6, 0x02, 0x0f, 0xb1, 0x7b, 0x9c, 0x76, 0x9b, 0x2b, 0x4f, 0x22, - 0xe5, 0x3c, 0x0f, 0x19, 0xf3, 0xfc, 0x7b, 0x00, 0x0b, 0x78, 0x3d, 0x02, 0x3b, 0x6e, 0x0c, 0x29, - 0x70, 0x87, 0xcf, 0x2f, 0x4d, 0x60, 0xc7, 0xe9, 0xee, 0x95, 0x98, 0x98, 0x6f, 0xec, 0xad, 0x1d, - 0x28, 0xa5, 0x87, 0xcf, 0x4b, 0x98, 0xba, 0x7e, 0xbf, 0x00, 0x17, 0xc5, 0x26, 0x27, 0xf1, 0x81, - 0x9f, 0x7c, 0x74, 0xbe, 0x0d, 0xe3, 0x82, 0x77, 0x2b, 0xfe, 0x10, 0xf8, 0x01, 0xbb, 0x9c, 0x8c, - 0xf9, 0x8c, 0x6e, 0x90, 0x91, 0xb7, 0x61, 0x04, 0xff, 0x88, 0x0f, 0x86, 0x98, 0x66, 0x46, 0x91, - 0xb4, 0x9e, 0x3c, 0x1e, 0x52, 0xa4, 0xd6, 0xd7, 0x70, 0x29, 0xaf, 0xe2, 0x2f, 0x41, 0x2f, 0xff, - 0xa6, 0x00, 0xe7, 0x85, 0x78, 0x63, 0xaa, 0x78, 0xae, 0x55, 0xe7, 0x04, 0xe1, 0xca, 0xf7, 0x61, - 0x8c, 0x15, 0x28, 0xeb, 0xdd, 0x2f, 0x96, 0x56, 0x61, 0x39, 0xc4, 0x98, 0x45, 0x27, 0x72, 0x44, - 0xf8, 0x8d, 0x73, 0xd0, 0x92, 0x9e, 0x11, 0x5b, 0x67, 0xb6, 0xbe, 0x84, 0x0b, 0xd9, 0x4d, 0x78, - 0x09, 0xfa, 0xb9, 0x0f, 0x73, 0x19, 0x8b, 0xc2, 0xf3, 0xad, 0xc9, 0x5f, 0xc0, 0xf9, 0x4c, 0x59, - 0x2f, 0xa1, 0x9a, 0xcb, 0x6c, 0xc7, 0x11, 0xbd, 0x84, 0x2e, 0xb4, 0x1e, 0xc2, 0xb9, 0x0c, 0x49, - 0x2f, 0xa1, 0x8a, 0xf7, 0x60, 0x56, 0xed, 0xb4, 0x5f, 0xa8, 0x86, 0x6b, 0x70, 0x91, 0x0b, 0x7a, - 0x39, 0xbd, 0xf2, 0x00, 0xce, 0x0b, 0x71, 0x2f, 0x41, 0x7b, 0xcb, 0x70, 0x21, 0x36, 0xa8, 0x33, - 0xf6, 0x49, 0xc7, 0x9e, 0x64, 0xac, 0x55, 0xb8, 0x1c, 0x4b, 0xca, 0xd9, 0x34, 0x1c, 0x5f, 0x1a, - 0xdf, 0x0e, 0xc6, 0xbd, 0xf4, 0x52, 0x7a, 0xf4, 0x21, 0x9c, 0x35, 0x84, 0xbe, 0xb4, 0xad, 0xd2, - 0x0a, 0x4c, 0x71, 0xc1, 0xe6, 0xd6, 0x79, 0x5e, 0xdf, 0x3a, 0x8f, 0xcd, 0x9f, 0x89, 0x45, 0x22, - 0x78, 0xe7, 0xcd, 0x8c, 0xdd, 0xf4, 0x1a, 0xee, 0xa6, 0x25, 0x49, 0x5c, 0xc3, 0xb7, 0x61, 0x88, - 0x43, 0x44, 0xfd, 0x32, 0x84, 0x71, 0x63, 0x81, 0xb3, 0x09, 0x62, 0xeb, 0xfb, 0x70, 0x91, 0x5b, - 0xa2, 0xf1, 0x41, 0xa5, 0x69, 0x2d, 0x7e, 0x94, 0x30, 0x44, 0xcf, 0x09, 0xb9, 0x49, 0xfa, 0x1c, - 0x7b, 0x74, 0x57, 0x8e, 0xed, 0x3c, 0xf9, 0xc7, 0xba, 0xba, 0x26, 0x0d, 0xcc, 0xbe, 0x4c, 0x03, - 0xf3, 0x2a, 0x5c, 0x51, 0x06, 0x66, 0xb2, 0x18, 0x39, 0xb4, 0xac, 0x2f, 0xe1, 0x3c, 0x6f, 0xa8, - 0x0c, 0x29, 0x34, 0xab, 0xf1, 0x41, 0xa2, 0x99, 0xb3, 0xa2, 0x99, 0x26, 0x75, 0x4e, 0x23, 0xff, - 0x4e, 0x41, 0x7e, 0x72, 0xd9, 0xc2, 0x7f, 0xde, 0x16, 0xf7, 0x3a, 0x94, 0x95, 0x42, 0xcc, 0x1a, - 0x3d, 0x9f, 0xb9, 0xbd, 0x06, 0x33, 0xba, 0x18, 0xb7, 0x41, 0x77, 0xee, 0xe0, 0x09, 0xd2, 0x5b, - 0xec, 0xb3, 0x40, 0x80, 0x1c, 0x76, 0xa5, 0x0c, 0xbd, 0x21, 0xbd, 0xad, 0x28, 0xad, 0x3a, 0x5c, - 0x48, 0x77, 0x85, 0xdb, 0x90, 0xf7, 0x09, 0xc8, 0x27, 0xec, 0x13, 0x46, 0x88, 0xe8, 0x8c, 0x5c, - 0xa1, 0xf2, 0x3b, 0xe6, 0xec, 0x92, 0xcb, 0xb2, 0xe4, 0x54, 0x93, 0x68, 0x3f, 0x2b, 0x5d, 0x8e, - 0x87, 0x1f, 0x03, 0x91, 0xa8, 0x85, 0x9a, 0x2d, 0x8b, 0x3e, 0x07, 0xfd, 0x0b, 0x35, 0x5b, 0x5c, - 0x64, 0xc2, 0x9d, 0x60, 0x23, 0x0c, 0x6c, 0x06, 0x4b, 0xee, 0xc8, 0xfb, 0x8e, 0xb1, 0x23, 0xbf, - 0x3f, 0x30, 0xd2, 0x5f, 0x1c, 0xb0, 0x49, 0xcd, 0xdd, 0xf3, 0x1e, 0xba, 0xd1, 0xbe, 0x2a, 0xb0, - 0x62, 0x7d, 0x05, 0x53, 0x46, 0xf1, 0xe2, 0x2b, 0xee, 0x7a, 0x03, 0x8b, 0xed, 0x67, 0x17, 0x2a, - 0x18, 0x56, 0x83, 0x2e, 0x8b, 0x71, 0x3e, 0xdf, 0x34, 0x9c, 0x3a, 0x5e, 0xef, 0xb5, 0x25, 0xd2, - 0xfa, 0xdd, 0x01, 0x4d, 0xba, 0x76, 0xaf, 0xad, 0x4b, 0xeb, 0xee, 0x00, 0xf0, 0x11, 0xa2, 0x35, - 0x8e, 0x6d, 0x00, 0xc7, 0x44, 0xb4, 0x0a, 0x9f, 0x92, 0x6d, 0x8d, 0xe8, 0xb8, 0xf7, 0xde, 0x44, - 0xfc, 0x31, 0x67, 0x92, 0x57, 0x3d, 0x55, 0xfc, 0xb1, 0x10, 0x1d, 0xda, 0x3a, 0x11, 0xf9, 0x7e, - 0xf2, 0x72, 0xc6, 0x20, 0x1e, 0x58, 0xbd, 0x22, 0x4f, 0xb0, 0xd3, 0x6d, 0x3b, 0xd9, 0xfd, 0x8c, - 0xa7, 0x30, 0xc3, 0x78, 0xdd, 0x47, 0x68, 0x58, 0x2c, 0x7d, 0x13, 0x51, 0x8f, 0xcf, 0xed, 0x43, - 0x58, 0xce, 0xb5, 0x2e, 0xe5, 0xc4, 0xc4, 0xc2, 0xff, 0x1e, 0xcb, 0xa9, 0x53, 0x85, 0xb3, 0xb3, - 0xe5, 0xe3, 0x20, 0xb2, 0x57, 0x97, 0xbc, 0x66, 0xdb, 0x77, 0x95, 0xc1, 0xc4, 0x07, 0x51, 0xd0, - 0xaa, 0x53, 0x01, 0xb7, 0x75, 0x22, 0xeb, 0xd5, 0xae, 0x51, 0xed, 0x23, 0x30, 0xb0, 0xb5, 0xb0, - 0xb5, 0x5a, 0x2c, 0x58, 0xb7, 0x00, 0xb4, 0x92, 0x00, 0x86, 0xd6, 0x37, 0xec, 0xb5, 0xca, 0x6a, - 0xf1, 0x14, 0x99, 0x81, 0x33, 0x0f, 0x57, 0xd6, 0x17, 0x37, 0x1e, 0xd6, 0xea, 0xb5, 0xb5, 0x8a, - 0xbd, 0xb5, 0x50, 0xb1, 0x17, 0x8b, 0x05, 0xeb, 0x6b, 0x98, 0x36, 0x5b, 0xf8, 0x52, 0x07, 0x61, - 0x04, 0x53, 0x6a, 0x3f, 0x73, 0xff, 0xe1, 0x96, 0x16, 0xd1, 0x2a, 0x8c, 0xbf, 0x64, 0x64, 0x96, - 0x30, 0x13, 0xc5, 0x67, 0xa4, 0x11, 0x91, 0xd7, 0xf9, 0xb6, 0x20, 0x79, 0x73, 0x99, 0x6d, 0x0b, - 0xea, 0xf1, 0xbe, 0x00, 0xa7, 0xbe, 0xef, 0xc1, 0xb4, 0x59, 0xea, 0x71, 0xbd, 0x54, 0xaf, 0x60, - 0xa8, 0xaf, 0x76, 0xad, 0x89, 0x10, 0xfd, 0xd8, 0x40, 0xcc, 0xac, 0xdf, 0x83, 0xa2, 0xa0, 0x8a, - 0x57, 0xde, 0xab, 0xd2, 0x8d, 0x58, 0xc8, 0xb8, 0x84, 0x29, 0x83, 0xd2, 0x7d, 0x28, 0xb2, 0x19, - 0x53, 0x70, 0xf2, 0x02, 0xa6, 0x61, 0x70, 0x35, 0x3e, 0xce, 0xb1, 0xf9, 0x0f, 0xbc, 0xdd, 0x13, - 0x39, 0x41, 0x24, 0xe3, 0xe0, 0x46, 0x6d, 0xf5, 0x9b, 0xbc, 0x0e, 0x43, 0x77, 0xdd, 0x56, 0x24, - 0x5c, 0x23, 0xf1, 0x22, 0xcf, 0xc4, 0x72, 0x84, 0x2d, 0x08, 0x2c, 0x1b, 0xce, 0x68, 0x05, 0x9e, - 0xa0, 0xaa, 0xa4, 0x04, 0xc3, 0xeb, 0xf4, 0x1b, 0xad, 0x7c, 0xf9, 0xd3, 0x7a, 0x07, 0xce, 0x88, - 0x18, 0x43, 0x4d, 0x4d, 0x57, 0xc4, 0x5d, 0xf1, 0x82, 0x71, 0x61, 0x55, 0x88, 0x44, 0x14, 0xe3, - 0xdb, 0x6e, 0x37, 0x9f, 0x93, 0x8f, 0x2d, 0x14, 0x27, 0xe4, 0x7b, 0x4d, 0x9e, 0x02, 0xf5, 0xea, - 0xce, 0xbf, 0xd1, 0x07, 0xa5, 0x84, 0x97, 0x61, 0x61, 0xdf, 0x69, 0xb5, 0xa8, 0xb7, 0x47, 0xc9, - 0x75, 0x18, 0xd8, 0xda, 0xd8, 0xda, 0x14, 0x5e, 0x52, 0x19, 0x5d, 0xc0, 0x40, 0x8a, 0xc6, 0x46, - 0x0a, 0xf2, 0x00, 0xce, 0xc8, 0x28, 0x62, 0x85, 0x12, 0x3d, 0x74, 0xb1, 0x7b, 0x4c, 0x72, 0x9a, - 0x8f, 0xbc, 0x25, 0x5c, 0x22, 0x3f, 0xec, 0xb8, 0x01, 0x6d, 0xa2, 0xe7, 0x27, 0x3e, 0xaa, 0xd7, - 0x30, 0xb6, 0x4e, 0x46, 0xbe, 0x07, 0xe3, 0xb5, 0xda, 0x46, 0x5c, 0xfa, 0xa0, 0x71, 0x42, 0xa4, - 0xa3, 0x6c, 0x83, 0x90, 0x5f, 0x09, 0xb6, 0xfe, 0xa0, 0x00, 0xb3, 0x39, 0xee, 0x16, 0xf2, 0xba, - 0xa1, 0x87, 0x29, 0x4d, 0x0f, 0x92, 0x64, 0xf9, 0x94, 0x50, 0xc4, 0x82, 0x16, 0x93, 0xdd, 0x7f, - 0x82, 0x98, 0xec, 0xe5, 0x53, 0x71, 0x1c, 0x36, 0x79, 0x15, 0xfa, 0x6b, 0xb5, 0x0d, 0xe1, 0x56, - 0x27, 0x71, 0x0b, 0x34, 0x62, 0x46, 0x50, 0x05, 0x18, 0x91, 0x20, 0xeb, 0x34, 0x4c, 0x18, 0x1d, - 0x63, 0x59, 0x30, 0xae, 0xd7, 0x90, 0xf5, 0xfe, 0x82, 0xdf, 0x54, 0xbd, 0xcf, 0xfe, 0xb6, 0x7e, - 0x6c, 0xea, 0x8c, 0x5c, 0x04, 0x90, 0xe7, 0xb5, 0x6e, 0x53, 0x9e, 0xfc, 0x08, 0xc8, 0x4a, 0x93, - 0x5c, 0x81, 0xf1, 0x80, 0x36, 0xdd, 0x80, 0x36, 0xa2, 0x7a, 0x27, 0x10, 0x17, 0x63, 0xec, 0x31, - 0x09, 0xdb, 0x0e, 0x5a, 0xe4, 0x3b, 0x30, 0xc4, 0x0f, 0x92, 0x45, 0xeb, 0xa5, 0x91, 0x50, 0xab, - 0x6d, 0xac, 0xdd, 0xad, 0xf0, 0x83, 0x6e, 0x5b, 0x90, 0x58, 0x55, 0x18, 0xd3, 0x5a, 0xd5, 0xab, - 0xf4, 0x69, 0x18, 0xd4, 0xbd, 0x94, 0xfc, 0x87, 0xf5, 0x9b, 0x05, 0x98, 0xc6, 0x61, 0xb0, 0xe7, - 0xb2, 0xe5, 0x21, 0x6e, 0xcb, 0xbc, 0xd1, 0x69, 0x17, 0x8c, 0x4e, 0x4b, 0xd0, 0xaa, 0xde, 0x7b, - 0x3f, 0xd5, 0x7b, 0x17, 0xb2, 0x7a, 0x0f, 0xa7, 0x00, 0xd7, 0xf7, 0xf4, 0x4e, 0xd3, 0x8f, 0xeb, - 0x7e, 0xbb, 0x00, 0x53, 0x5a, 0x9d, 0x54, 0x03, 0xef, 0x18, 0x55, 0x3a, 0x9f, 0x51, 0xa5, 0xd4, - 0x78, 0xaa, 0xa6, 0x6a, 0xf4, 0x4a, 0xb7, 0x1a, 0x65, 0x0d, 0x27, 0x63, 0x98, 0xfc, 0x79, 0x01, - 0x66, 0x32, 0x75, 0x40, 0xce, 0xb2, 0xfd, 0x7f, 0x23, 0xa0, 0x91, 0xd0, 0xbc, 0xf8, 0xc5, 0xe0, - 0x2b, 0x61, 0xd8, 0xa1, 0x81, 0xd0, 0xbb, 0xf8, 0x45, 0x5e, 0x81, 0x89, 0x4d, 0x1a, 0xb8, 0x7e, - 0x93, 0x5f, 0x4c, 0xe0, 0x11, 0xbf, 0x13, 0xb6, 0x09, 0x24, 0x17, 0x60, 0x54, 0x45, 0xac, 0x72, - 0x1f, 0xae, 0x1d, 0x03, 0x98, 0xec, 0x45, 0x77, 0x8f, 0x1f, 0xfc, 0x30, 0x66, 0xf1, 0x8b, 0x4d, - 0xc0, 0xd2, 0xa3, 0x3a, 0xc4, 0x27, 0x60, 0xe9, 0x2e, 0x3d, 0x0b, 0x43, 0x9f, 0xd9, 0x38, 0x8e, - 0x31, 0xe7, 0x84, 0x2d, 0x7e, 0x91, 0x49, 0x0c, 0x2d, 0xc7, 0x7b, 0x31, 0x18, 0x52, 0xfe, 0x3e, - 0x4c, 0x67, 0xe9, 0x35, 0xeb, 0x2b, 0x10, 0xbc, 0x7d, 0x8a, 0xf7, 0x4b, 0x98, 0xaa, 0x34, 0x9b, - 0xf1, 0x70, 0xe5, 0xbd, 0xca, 0xe7, 0x09, 0xee, 0xd3, 0x14, 0xdb, 0xda, 0x81, 0x15, 0xcf, 0x8d, - 0xec, 0xa9, 0xa5, 0x6f, 0xdc, 0x30, 0x72, 0xbd, 0x3d, 0xcd, 0xf1, 0x6a, 0x9f, 0x5d, 0xa7, 0x4f, - 0x33, 0x86, 0x00, 0xdb, 0x71, 0x98, 0xb2, 0x39, 0x3c, 0x43, 0xf8, 0xb4, 0x26, 0x36, 0x9e, 0xba, - 0x66, 0x4d, 0xb9, 0x31, 0xa2, 0xbf, 0xd2, 0x78, 0x6c, 0x7d, 0x0f, 0xce, 0xf2, 0x69, 0xbf, 0x5b, - 0xe5, 0x45, 0xb5, 0x75, 0x3f, 0xb1, 0xf5, 0xae, 0xf4, 0xe4, 0x74, 0xad, 0x99, 0x3d, 0x6e, 0xd4, - 0x05, 0x8b, 0xfc, 0x6f, 0x05, 0x98, 0x4b, 0xb0, 0xd6, 0x9e, 0x79, 0x0d, 0xb9, 0xe6, 0xbc, 0x9a, - 0x0c, 0xdd, 0xc7, 0xbd, 0x12, 0x77, 0x90, 0xba, 0x4d, 0x15, 0xbd, 0x4f, 0x6e, 0x01, 0x70, 0x66, - 0x6d, 0x8b, 0x83, 0xc7, 0x03, 0x22, 0xca, 0x09, 0x37, 0x39, 0x1a, 0x09, 0xe9, 0x40, 0x96, 0xde, - 0xc5, 0x37, 0xd2, 0xcb, 0x7f, 0x8e, 0x79, 0x56, 0xa8, 0x60, 0xaf, 0xe7, 0x38, 0xd2, 0xb3, 0xe4, - 0x5b, 0x7f, 0xb7, 0x1f, 0x66, 0xf5, 0x0e, 0x7c, 0x9e, 0xb6, 0x6e, 0xc2, 0xd8, 0x82, 0xef, 0x45, - 0xf4, 0x9b, 0x48, 0xcb, 0x73, 0x41, 0x54, 0x34, 0x82, 0xc2, 0x88, 0xed, 0x35, 0x07, 0xd4, 0xd9, - 0x5e, 0xcf, 0x88, 0xd6, 0x8c, 0x09, 0xc9, 0x02, 0x4c, 0xac, 0xd3, 0xa7, 0x29, 0x05, 0x62, 0xc4, - 0xa8, 0x47, 0x9f, 0xd6, 0x35, 0x25, 0xea, 0x61, 0x7c, 0x06, 0x0f, 0xd9, 0x85, 0x49, 0x39, 0xb8, - 0x0c, 0x65, 0xce, 0xe9, 0x2b, 0xaf, 0x39, 0x9c, 0x79, 0x1e, 0x08, 0x56, 0x42, 0x8e, 0x0e, 0x13, - 0x12, 0x59, 0xd3, 0x79, 0x89, 0x3c, 0xb5, 0x81, 0xb9, 0xb4, 0x6b, 0x18, 0x23, 0x1e, 0x37, 0x99, - 0xd2, 0x40, 0x17, 0x61, 0x6d, 0x42, 0x29, 0xdd, 0x1f, 0xa2, 0xb4, 0xb7, 0x60, 0x88, 0x43, 0xc5, - 0x56, 0x49, 0xa6, 0x30, 0x52, 0xd4, 0xdc, 0x97, 0xd1, 0x14, 0xab, 0x12, 0x87, 0x59, 0xcb, 0xe8, - 0x5f, 0x52, 0x34, 0x6a, 0xb3, 0x7a, 0x3b, 0xd9, 0xbd, 0x18, 0xea, 0x2c, 0xbb, 0x57, 0x8f, 0xc5, - 0x91, 0x57, 0x52, 0x16, 0xd0, 0x45, 0xa7, 0x4b, 0x12, 0x15, 0xbb, 0x01, 0xc3, 0x02, 0x94, 0x48, - 0xae, 0x14, 0x7f, 0x7e, 0x92, 0xc0, 0x7a, 0x1f, 0xce, 0xa1, 0xbf, 0xd0, 0xf5, 0xf6, 0x5a, 0x74, - 0x3b, 0x34, 0x2e, 0x95, 0xf4, 0xfa, 0xac, 0x3f, 0x84, 0xb9, 0x2c, 0xde, 0x9e, 0x5f, 0x36, 0x4f, - 0x77, 0xf2, 0xa7, 0x7d, 0x30, 0xbd, 0x12, 0xea, 0x1b, 0x2e, 0x95, 0xf2, 0x24, 0x23, 0x0d, 0x07, - 0xea, 0x64, 0xf9, 0x54, 0x56, 0x9a, 0x8d, 0xb7, 0xb4, 0xeb, 0xae, 0x7d, 0xdd, 0xf2, 0x6b, 0xb0, - 0x65, 0x4b, 0x5d, 0x78, 0x7d, 0x15, 0x06, 0xd6, 0xd9, 0x54, 0xdd, 0x2f, 0xfa, 0x8e, 0x73, 0x30, - 0x10, 0x5e, 0x37, 0x65, 0x4b, 0x24, 0xfb, 0x41, 0xee, 0xa6, 0x2e, 0xb5, 0x0e, 0xf4, 0xce, 0x1f, - 0xb1, 0x7c, 0x2a, 0x75, 0xbf, 0xf5, 0x1d, 0x18, 0xab, 0x34, 0x0f, 0x78, 0x48, 0xa6, 0xef, 0x25, - 0x3e, 0x4b, 0x0d, 0xb3, 0x7c, 0xca, 0xd6, 0x09, 0xc9, 0x35, 0x7e, 0xab, 0x61, 0x28, 0x27, 0xa7, - 0x06, 0xdb, 0xac, 0x55, 0xda, 0xed, 0xea, 0x08, 0x0c, 0xf1, 0x8b, 0x96, 0xd6, 0x97, 0x30, 0x27, - 0x02, 0x79, 0xb8, 0x77, 0x14, 0xc3, 0x7d, 0xc2, 0x38, 0x56, 0xab, 0x5b, 0xf0, 0xcd, 0x25, 0x00, - 0xb4, 0x85, 0x56, 0xbc, 0x26, 0xfd, 0x46, 0x44, 0x12, 0x6a, 0x10, 0xeb, 0x6d, 0x18, 0x55, 0x1a, - 0xc2, 0x0d, 0xbf, 0xb6, 0xd8, 0xa1, 0xb6, 0xa6, 0x8d, 0x5b, 0xbc, 0xf2, 0xea, 0xee, 0x39, 0xa3, - 0xed, 0x22, 0x4b, 0x0e, 0xb7, 0x10, 0x5c, 0x98, 0x49, 0x0c, 0x82, 0x38, 0x09, 0x83, 0xda, 0xa3, - 0xf3, 0x50, 0x47, 0xf5, 0x3b, 0xb9, 0x85, 0xef, 0x3b, 0xd6, 0x16, 0xde, 0xfa, 0x17, 0x7d, 0x68, - 0x5c, 0xa6, 0xf4, 0x91, 0xf0, 0xd3, 0xe9, 0xbe, 0xc2, 0x2a, 0x8c, 0x62, 0xeb, 0x17, 0xe5, 0x85, - 0xc1, 0xee, 0x71, 0x28, 0x23, 0x3f, 0x39, 0x2c, 0x9f, 0xc2, 0xe0, 0x93, 0x98, 0x8d, 0x7c, 0x0c, - 0xc3, 0x4b, 0x5e, 0x13, 0x25, 0xf4, 0x9f, 0x40, 0x82, 0x64, 0x62, 0x7d, 0x82, 0x55, 0xde, 0x62, - 0x9f, 0x30, 0x77, 0xef, 0xd8, 0x1a, 0x24, 0xb6, 0x72, 0x07, 0xf3, 0xac, 0xdc, 0xa1, 0x84, 0x95, - 0x6b, 0xc1, 0xe0, 0x46, 0xd0, 0x14, 0xb9, 0x6d, 0x26, 0xe7, 0xc7, 0x85, 0xe2, 0x10, 0x66, 0x73, - 0x94, 0xf5, 0x3f, 0x0a, 0x30, 0x7b, 0x8f, 0x46, 0x99, 0x63, 0xc8, 0xd0, 0x4a, 0xe1, 0x85, 0xb5, - 0xd2, 0xf7, 0x3c, 0x5a, 0x51, 0xad, 0xee, 0xcf, 0x6b, 0xf5, 0x40, 0x5e, 0xab, 0x07, 0xf3, 0x5b, - 0x7d, 0x0f, 0x86, 0x78, 0x53, 0x99, 0x25, 0xbf, 0x12, 0xd1, 0x83, 0xd8, 0x92, 0xd7, 0xa3, 0xe8, - 0x6c, 0x8e, 0x63, 0x1b, 0xc9, 0x55, 0x27, 0xd4, 0x2d, 0x79, 0xf1, 0xd3, 0xfa, 0x01, 0x5e, 0x35, - 0x5e, 0xf5, 0x1b, 0x8f, 0x35, 0x8f, 0xf0, 0x30, 0xff, 0x42, 0x93, 0x27, 0x08, 0x8c, 0x8a, 0x63, - 0x6c, 0x49, 0x41, 0x2e, 0xc3, 0xd8, 0x8a, 0x77, 0xd7, 0x0f, 0x1a, 0x74, 0xc3, 0x6b, 0x71, 0xe9, - 0x23, 0xb6, 0x0e, 0x12, 0x9e, 0x12, 0x51, 0x42, 0xec, 0x7e, 0x40, 0x40, 0xc2, 0xfd, 0xc0, 0x60, - 0x3b, 0xf3, 0x36, 0xc7, 0x09, 0x47, 0x0c, 0xfb, 0xbb, 0x9b, 0xe5, 0xae, 0x4c, 0xfc, 0x5e, 0x84, - 0xbb, 0x70, 0xce, 0xa6, 0xed, 0x96, 0xc3, 0xf6, 0x74, 0x07, 0x3e, 0xa7, 0x57, 0x6d, 0xbe, 0x9c, - 0x71, 0x4d, 0xd0, 0x8c, 0xa9, 0x50, 0x55, 0xee, 0xeb, 0x52, 0xe5, 0x03, 0xb8, 0x72, 0x8f, 0x46, - 0xe6, 0x84, 0x1a, 0xfb, 0x9b, 0x45, 0xe3, 0x97, 0x61, 0x24, 0x34, 0x7d, 0xe5, 0xf2, 0xda, 0x5b, - 0x26, 0xe3, 0xce, 0x9b, 0xf2, 0x34, 0x49, 0xc8, 0x51, 0x7f, 0x59, 0x9f, 0x40, 0x39, 0xaf, 0xb8, - 0xe3, 0x85, 0xbc, 0xba, 0x70, 0x39, 0x5f, 0x80, 0xa8, 0xee, 0x12, 0x48, 0xbf, 0xba, 0xf8, 0x84, - 0x7a, 0xd5, 0xd6, 0x74, 0xc5, 0x8b, 0x3f, 0xac, 0xaa, 0x0c, 0xfe, 0x7b, 0x81, 0xea, 0xd6, 0xf1, - 0xc8, 0xda, 0x14, 0x10, 0xeb, 0xb5, 0x02, 0x23, 0x12, 0x26, 0xf4, 0x3a, 0x9b, 0x59, 0x53, 0xa9, - 0xd0, 0xa6, 0x14, 0xa0, 0xd8, 0xac, 0x1f, 0xc8, 0xe3, 0x1b, 0x93, 0xe3, 0x78, 0xf7, 0x66, 0x8f, - 0x73, 0x5e, 0x63, 0xf9, 0x70, 0xce, 0x94, 0xad, 0xbb, 0xe5, 0x8b, 0x9a, 0x5b, 0x9e, 0x7b, 0xe3, - 0x2f, 0x9b, 0x6e, 0x62, 0xe1, 0x69, 0xd0, 0x40, 0xe4, 0x92, 0xee, 0x7c, 0x1f, 0x4f, 0x5f, 0xc4, - 0xbd, 0x0d, 0x73, 0x59, 0x05, 0x6a, 0x76, 0xa0, 0xf2, 0xf0, 0x8a, 0xfd, 0xce, 0x22, 0x5c, 0x92, - 0xd9, 0xa5, 0x7c, 0x3f, 0x0a, 0xa3, 0xc0, 0x69, 0xd7, 0x1a, 0x81, 0xdb, 0x8e, 0xb9, 0x2c, 0x18, - 0xe2, 0x10, 0xa1, 0x09, 0x7e, 0x14, 0xc6, 0x69, 0x04, 0xc6, 0xfa, 0x95, 0x02, 0x58, 0x46, 0x9c, - 0x16, 0xf6, 0xf3, 0x66, 0xe0, 0x3f, 0x71, 0x9b, 0xda, 0xf1, 0xd3, 0xeb, 0x86, 0xeb, 0x93, 0xdf, - 0x49, 0x4c, 0x86, 0x88, 0x8b, 0x39, 0xf3, 0x76, 0xc2, 0x1d, 0xc9, 0x37, 0x9e, 0x18, 0xbb, 0x65, - 0x5e, 0x88, 0x50, 0x6e, 0xca, 0xff, 0x55, 0x80, 0xab, 0x5d, 0xeb, 0x20, 0xda, 0xb3, 0x0b, 0xc5, - 0x24, 0x4e, 0x8c, 0xa0, 0xb2, 0x16, 0xb7, 0x91, 0x96, 0xb0, 0x73, 0x87, 0xc7, 0xa1, 0xcb, 0xf8, - 0xa6, 0xb6, 0x92, 0x9c, 0x92, 0x77, 0xf2, 0xda, 0x63, 0xfe, 0x0a, 0x3f, 0x72, 0x5a, 0x0b, 0xe8, - 0x00, 0xe8, 0x8f, 0xef, 0x14, 0x44, 0x0c, 0x5a, 0x4f, 0xa6, 0xc9, 0xd0, 0x88, 0xad, 0x4f, 0xf1, - 0xbb, 0xce, 0xae, 0xf4, 0xf1, 0x3e, 0xb5, 0x05, 0xb8, 0x9a, 0x88, 0x1d, 0x78, 0x0e, 0x21, 0x11, - 0xcc, 0x30, 0xf5, 0xb3, 0xbd, 0xf7, 0xbd, 0xc0, 0xef, 0xb4, 0x7f, 0x3e, 0xbd, 0xfe, 0x87, 0x05, - 0x1e, 0xcc, 0xa9, 0x17, 0x2b, 0x3a, 0x7a, 0x01, 0x20, 0x86, 0x26, 0x82, 0xfa, 0x15, 0x62, 0xe7, - 0x0e, 0x37, 0xb9, 0xf1, 0x54, 0x61, 0x8f, 0x0b, 0xd0, 0xd8, 0x7e, 0xbe, 0x3d, 0xf9, 0x26, 0x06, - 0x0c, 0xa8, 0xd2, 0x8f, 0xa7, 0xf7, 0x77, 0xa4, 0xff, 0xe3, 0x84, 0x7c, 0xfb, 0x30, 0xcd, 0x66, - 0x80, 0x4a, 0x27, 0xda, 0xf7, 0x03, 0x37, 0x92, 0xd7, 0x53, 0xc8, 0xa6, 0xc8, 0x08, 0xc0, 0xb9, - 0x3e, 0xfc, 0xd9, 0x61, 0xf9, 0xdd, 0x93, 0xe4, 0xfd, 0x94, 0x32, 0xb7, 0x54, 0x16, 0x01, 0x6b, - 0x16, 0xfa, 0x17, 0xec, 0x55, 0x9c, 0xf0, 0xec, 0x55, 0x35, 0xe1, 0xd9, 0xab, 0xd6, 0x5f, 0xf4, - 0x41, 0x99, 0xe7, 0x2c, 0xc1, 0x38, 0x93, 0xd8, 0x6b, 0xa1, 0x05, 0xae, 0x1c, 0xd7, 0xc1, 0x90, - 0xc8, 0x49, 0xd2, 0x77, 0x9c, 0x9c, 0x24, 0xbf, 0x04, 0x39, 0x2e, 0xab, 0x63, 0x78, 0x01, 0x5e, - 0x3b, 0x3a, 0x2c, 0x5f, 0x8d, 0xbd, 0x00, 0x1c, 0x9b, 0xe5, 0x0e, 0xc8, 0x29, 0x22, 0xed, 0xbf, - 0x18, 0x78, 0x0e, 0xff, 0xc5, 0x6d, 0x18, 0x46, 0x63, 0x66, 0x65, 0x53, 0x44, 0x7e, 0xe2, 0xf0, - 0xc4, 0x0c, 0x45, 0x75, 0x57, 0x4f, 0x07, 0x28, 0xc9, 0xac, 0x7f, 0xd0, 0x07, 0x97, 0xf3, 0x75, - 0x2e, 0xea, 0xb6, 0x08, 0x10, 0x47, 0xb8, 0x74, 0x8b, 0xa8, 0xc1, 0x6f, 0xe7, 0x29, 0xdd, 0x55, - 0x11, 0x6d, 0x1a, 0x1f, 0xdb, 0xfb, 0xc8, 0x9b, 0xd6, 0x89, 0xe3, 0x14, 0xe3, 0x02, 0xb6, 0xc8, - 0x66, 0x2b, 0x40, 0x46, 0x36, 0x5b, 0x01, 0x23, 0xbb, 0x30, 0xbb, 0x19, 0xb8, 0x4f, 0x9c, 0x88, - 0x3e, 0xa0, 0xcf, 0xf8, 0x65, 0xa1, 0x25, 0x71, 0x43, 0x88, 0x5f, 0x9f, 0xbf, 0x7e, 0x74, 0x58, - 0x7e, 0xa5, 0xcd, 0x49, 0x30, 0x63, 0x19, 0xbf, 0xfb, 0x59, 0x4f, 0x5f, 0x1a, 0xca, 0x13, 0x64, - 0xfd, 0xbb, 0x02, 0x9c, 0xc7, 0x6d, 0xb9, 0x70, 0xbb, 0xca, 0xc2, 0x9f, 0x2b, 0xb0, 0x52, 0x6f, - 0xa0, 0x18, 0x8b, 0x18, 0x58, 0x69, 0xdc, 0x44, 0xb7, 0x0d, 0x32, 0xb2, 0x02, 0x63, 0xe2, 0x37, - 0x7e, 0x7f, 0xfd, 0x68, 0x10, 0xcc, 0x68, 0x13, 0x16, 0x0e, 0x75, 0xee, 0x2a, 0xc2, 0x81, 0x2d, - 0x84, 0xe1, 0x85, 0x4d, 0x5b, 0xe7, 0xb5, 0x7e, 0xda, 0x07, 0x17, 0x76, 0x68, 0xe0, 0x3e, 0x7a, - 0x96, 0xd3, 0x98, 0x0d, 0x98, 0x96, 0x20, 0x9e, 0xb7, 0xc4, 0xf8, 0xc4, 0x78, 0x3e, 0x4b, 0x59, - 0x55, 0x91, 0xf8, 0x44, 0x7e, 0x71, 0x99, 0x8c, 0x27, 0x08, 0x99, 0x7c, 0x0b, 0x46, 0x12, 0x99, - 0x83, 0xb0, 0xff, 0xe5, 0x17, 0x1a, 0x77, 0xd5, 0xf2, 0x29, 0x5b, 0x51, 0x92, 0x5f, 0xcb, 0x3f, - 0xaa, 0x12, 0xae, 0x8f, 0x5e, 0xfe, 0x4f, 0xfc, 0x60, 0xd9, 0xc7, 0xea, 0x68, 0xd8, 0x8c, 0x0f, - 0x76, 0xf9, 0x94, 0x9d, 0x57, 0x52, 0x75, 0x0c, 0x46, 0x2b, 0x78, 0x6e, 0xc7, 0x2c, 0xf7, 0xff, - 0xd9, 0x07, 0x97, 0xe4, 0xc5, 0x9f, 0x1c, 0x35, 0x7f, 0x0e, 0xb3, 0x12, 0x54, 0x69, 0xb3, 0x0d, - 0x03, 0x6d, 0x9a, 0x9a, 0xe6, 0x39, 0x65, 0xa5, 0xa6, 0x1d, 0x41, 0x13, 0x2b, 0x3b, 0x8f, 0xfd, - 0xe5, 0x78, 0x3f, 0x3f, 0xce, 0xca, 0xe3, 0x84, 0x5e, 0x48, 0x7d, 0xce, 0x34, 0x54, 0x63, 0xcc, - 0x9f, 0xcd, 0x94, 0xf7, 0x74, 0xe0, 0x45, 0xbd, 0xa7, 0xcb, 0xa7, 0x92, 0xfe, 0xd3, 0xea, 0x24, - 0x8c, 0xaf, 0xd3, 0xa7, 0xb1, 0xde, 0xff, 0x7a, 0x21, 0x91, 0xea, 0x81, 0xed, 0x30, 0x78, 0xce, - 0x87, 0x42, 0x9c, 0x0a, 0x08, 0x53, 0x3d, 0xe8, 0x3b, 0x0c, 0x4e, 0xba, 0x02, 0xc3, 0xfc, 0x30, - 0xbb, 0x79, 0x0c, 0x0b, 0x5f, 0xdd, 0xe0, 0xe1, 0xd7, 0x2a, 0x9b, 0xdc, 0xd8, 0x17, 0xfc, 0xd6, - 0x03, 0xb8, 0x22, 0x62, 0xbc, 0xcd, 0xce, 0xc7, 0x82, 0x4e, 0xb8, 0x7c, 0x59, 0x0e, 0x5c, 0xba, - 0x47, 0x93, 0x53, 0x8f, 0x71, 0xc3, 0xe9, 0x13, 0x38, 0x6d, 0xc0, 0x95, 0x44, 0xdc, 0x95, 0xaa, - 0x31, 0xa4, 0x44, 0x27, 0xa9, 0xad, 0xcb, 0x59, 0x45, 0xe8, 0x95, 0xb5, 0x28, 0x26, 0x87, 0x0d, - 0xe2, 0x23, 0xb6, 0xf0, 0x04, 0xb3, 0xde, 0x75, 0xed, 0xbb, 0xe6, 0x33, 0x1e, 0xcf, 0x1e, 0x28, - 0x57, 0x5e, 0x85, 0xb5, 0x26, 0x8c, 0xb3, 0x00, 0x6b, 0x12, 0xc6, 0x25, 0xaa, 0x45, 0xc3, 0xd0, - 0xfa, 0xcf, 0x83, 0x60, 0x09, 0xc5, 0x66, 0x9d, 0xd0, 0x4b, 0x7d, 0xec, 0xa6, 0x2a, 0x2b, 0x16, - 0xaa, 0xb3, 0x7a, 0x4e, 0xd2, 0x18, 0xcb, 0x47, 0x1e, 0xee, 0xf3, 0x1a, 0x31, 0xd4, 0x18, 0x79, - 0xa9, 0xd6, 0x7f, 0x95, 0x33, 0x4d, 0xf2, 0x8f, 0x0d, 0xaf, 0x6c, 0xe7, 0x4c, 0x93, 0x86, 0xdc, - 0xec, 0x29, 0xd3, 0x36, 0x8f, 0x44, 0xfa, 0x9f, 0xe7, 0x48, 0x84, 0x7d, 0x91, 0xfa, 0xa1, 0xc8, - 0xb6, 0xa9, 0x4b, 0xf1, 0x3d, 0xca, 0xd3, 0x7b, 0x1d, 0x25, 0x32, 0x2e, 0x68, 0x10, 0x43, 0xaa, - 0x21, 0x86, 0xb8, 0x50, 0xd4, 0x7c, 0x96, 0x0b, 0xfb, 0xb4, 0xf1, 0x58, 0xf8, 0x8a, 0xe5, 0x81, - 0x6e, 0x96, 0xcf, 0x9c, 0xe7, 0xa7, 0xe6, 0xdf, 0x39, 0x47, 0xd4, 0x1b, 0x8c, 0x55, 0xcf, 0x18, - 0x91, 0x14, 0x4b, 0x7e, 0x04, 0x53, 0xaa, 0xab, 0x13, 0x21, 0x5a, 0x63, 0xf3, 0xaf, 0xc4, 0xa9, - 0x4c, 0x0f, 0x1e, 0x39, 0x37, 0x9f, 0xdc, 0xb9, 0x99, 0x41, 0xcb, 0x13, 0x11, 0x34, 0x24, 0x42, - 0x8b, 0xcf, 0xd2, 0x0f, 0xba, 0x32, 0x18, 0xc9, 0x17, 0x30, 0x5d, 0xab, 0x6d, 0xf0, 0xcb, 0x1c, - 0xb6, 0x3c, 0xe0, 0xb7, 0x57, 0x45, 0xc0, 0x16, 0x76, 0x77, 0x18, 0xfa, 0x75, 0x71, 0x09, 0x44, - 0x0f, 0x0b, 0xd0, 0x53, 0x31, 0x64, 0x89, 0xd0, 0x4f, 0xca, 0xff, 0xbe, 0xba, 0xab, 0xc0, 0xb6, - 0x22, 0x6e, 0x8b, 0x8a, 0x4b, 0x47, 0x72, 0x60, 0xe7, 0x9c, 0xf2, 0x15, 0xbe, 0xe5, 0x53, 0xbe, - 0xdf, 0xeb, 0x93, 0x37, 0x34, 0xd2, 0x07, 0xad, 0x27, 0x3e, 0xec, 0xcb, 0x6c, 0xc1, 0xb1, 0xd6, - 0xe9, 0xcc, 0xca, 0x91, 0xaa, 0x3c, 0x2a, 0x55, 0xc9, 0xca, 0x26, 0xd5, 0xb1, 0x43, 0x8c, 0x30, - 0x4e, 0x4f, 0x71, 0x57, 0xa4, 0x71, 0x25, 0xcf, 0xe1, 0xfa, 0x5f, 0xfc, 0x1c, 0xee, 0xc7, 0x30, - 0x23, 0xaf, 0x46, 0x2d, 0x50, 0x2f, 0xa2, 0x81, 0x3c, 0xb1, 0x9f, 0x8c, 0x93, 0xbe, 0x61, 0x7a, - 0xbf, 0x22, 0xf4, 0x57, 0xec, 0x75, 0xe1, 0xd1, 0x61, 0x7f, 0x92, 0xcb, 0x66, 0x40, 0x1c, 0xbf, - 0xf3, 0x66, 0x84, 0xbf, 0x5d, 0x66, 0xd5, 0xe5, 0x7e, 0x16, 0x57, 0xa6, 0xea, 0xb3, 0x75, 0x90, - 0xb5, 0x00, 0xe7, 0xcd, 0xe2, 0x37, 0x69, 0x70, 0xe0, 0xe2, 0xde, 0xbb, 0x46, 0x23, 0x59, 0x68, - 0x21, 0x2e, 0x94, 0xe8, 0x01, 0xd5, 0xc2, 0x0c, 0xfc, 0x3f, 0x7d, 0x50, 0xce, 0x6c, 0x44, 0x25, - 0x0c, 0xdd, 0x3d, 0x0f, 0x33, 0x68, 0x5c, 0x80, 0x81, 0x07, 0xae, 0xd7, 0xd4, 0x0d, 0xc9, 0xc7, - 0xae, 0xd7, 0xb4, 0x11, 0xca, 0x6c, 0x90, 0x5a, 0x67, 0x17, 0x09, 0x34, 0x13, 0x39, 0xec, 0xec, - 0xd6, 0x19, 0x91, 0x6e, 0x83, 0x08, 0x32, 0x72, 0x0d, 0x86, 0x65, 0xb6, 0xb5, 0xfe, 0xd8, 0x7b, - 0x26, 0xd3, 0xac, 0x49, 0x1c, 0xf9, 0x08, 0x46, 0xd6, 0x68, 0xe4, 0x34, 0x9d, 0xc8, 0x11, 0x63, - 0x47, 0x3e, 0x84, 0x21, 0xc1, 0xd5, 0xa2, 0x58, 0xa1, 0x47, 0x0e, 0x04, 0xc4, 0x56, 0x2c, 0xa8, - 0x40, 0x37, 0x6c, 0xb7, 0x9c, 0x67, 0x2a, 0x98, 0x94, 0x29, 0x30, 0x06, 0x91, 0x77, 0xcc, 0x90, - 0x8b, 0xf8, 0xf8, 0x2c, 0x53, 0x21, 0x71, 0x40, 0xc6, 0x32, 0x86, 0x81, 0xc4, 0xaa, 0x16, 0xd9, - 0x04, 0xad, 0x4c, 0x6e, 0x83, 0xd2, 0x36, 0x19, 0xad, 0xdf, 0x1a, 0x83, 0x33, 0x9b, 0xce, 0x9e, - 0xeb, 0xb1, 0x1d, 0x85, 0x4d, 0x43, 0xbf, 0x13, 0x34, 0x28, 0xa9, 0xc0, 0xa4, 0x19, 0xc0, 0xdd, - 0x23, 0x3c, 0x9d, 0x6d, 0x9a, 0x4c, 0x18, 0x99, 0x87, 0x51, 0x75, 0x69, 0x5c, 0xec, 0x74, 0x32, - 0x2e, 0x93, 0x2f, 0x9f, 0xb2, 0x63, 0x32, 0xf2, 0x9e, 0x71, 0xf8, 0x78, 0x5a, 0xe5, 0x3f, 0x40, - 0xda, 0x79, 0x1e, 0x61, 0xeb, 0xf9, 0x4d, 0x73, 0xb7, 0xc6, 0x4f, 0xd8, 0x7e, 0x90, 0x3a, 0x8f, - 0x1c, 0x34, 0x6a, 0x9c, 0x72, 0xca, 0xe2, 0x46, 0x35, 0x37, 0x7b, 0x7d, 0xc6, 0x49, 0xe5, 0x97, - 0x30, 0xf6, 0xa0, 0xb3, 0x4b, 0xe5, 0xc9, 0xeb, 0x90, 0xd8, 0xbc, 0x25, 0xaf, 0x25, 0x08, 0xfc, - 0xce, 0x9b, 0xfc, 0x2b, 0x7e, 0xdc, 0xd9, 0xa5, 0xe9, 0x67, 0x11, 0xd8, 0xaa, 0xa9, 0x09, 0x23, - 0xfb, 0x50, 0x4c, 0xde, 0x20, 0x10, 0x5d, 0xda, 0xe5, 0xde, 0x03, 0x26, 0xfa, 0xd1, 0x1e, 0x5f, - 0xe0, 0x71, 0xcd, 0x46, 0x21, 0x29, 0xa9, 0xe4, 0xc7, 0x30, 0x93, 0xe9, 0x12, 0x57, 0x77, 0x20, - 0xbb, 0x7b, 0xdb, 0x71, 0x09, 0x4a, 0x68, 0x4d, 0x5e, 0xb8, 0x34, 0x4a, 0xce, 0x2e, 0x85, 0x34, - 0xe1, 0x74, 0x22, 0x32, 0x5e, 0xbc, 0x30, 0x93, 0x1f, 0x6b, 0x8f, 0xbb, 0x26, 0x99, 0xa4, 0x39, - 0xb3, 0xac, 0xa4, 0x48, 0xb2, 0x0a, 0xa3, 0xca, 0x17, 0x25, 0x72, 0xf3, 0x65, 0xf9, 0xdd, 0x4a, - 0x47, 0x87, 0xe5, 0xe9, 0xd8, 0xef, 0x66, 0xc8, 0x8c, 0x05, 0x90, 0x5f, 0x86, 0x2b, 0x6a, 0x88, - 0x6e, 0x04, 0xd9, 0x1e, 0x4a, 0xf1, 0xb8, 0xc3, 0x8d, 0xe4, 0x08, 0xcf, 0xa3, 0xdf, 0xb9, 0x53, - 0xed, 0x2b, 0x15, 0x96, 0x4f, 0xd9, 0xbd, 0x45, 0x93, 0x5f, 0x2d, 0xc0, 0xd9, 0x9c, 0x52, 0xc7, - 0xb1, 0xd4, 0x9e, 0x6e, 0x63, 0xb4, 0x3c, 0xf1, 0xde, 0x9f, 0xdb, 0x8c, 0xef, 0xc7, 0x4a, 0xff, - 0xb1, 0xd1, 0xee, 0x9c, 0x92, 0xc8, 0x6d, 0x80, 0x3d, 0x37, 0x12, 0x63, 0x0c, 0xd3, 0xd4, 0xa5, - 0x3f, 0x50, 0xa6, 0xb6, 0x3d, 0x37, 0x12, 0x23, 0xed, 0x77, 0x0b, 0x3d, 0xe7, 0x75, 0xcc, 0x5e, - 0x37, 0x36, 0xff, 0x6a, 0xb7, 0x49, 0x2f, 0xa6, 0xae, 0xde, 0x3e, 0x3a, 0x2c, 0xbf, 0xa1, 0x52, - 0xa0, 0x35, 0x90, 0x4a, 0xde, 0xf2, 0xad, 0x3b, 0x8a, 0xce, 0x68, 0x4f, 0xcf, 0xa5, 0xe5, 0x0d, - 0x18, 0x42, 0xcf, 0x54, 0x58, 0x9a, 0x40, 0xdb, 0x0d, 0x13, 0x77, 0xa1, 0xff, 0x4a, 0xdf, 0xad, - 0x09, 0x1a, 0xb2, 0xcc, 0x6c, 0x20, 0xdc, 0x2d, 0x4a, 0x9b, 0x45, 0xa4, 0xf9, 0x13, 0x76, 0x34, - 0x47, 0xc9, 0xfc, 0x3b, 0xc6, 0xf3, 0x24, 0x26, 0x5b, 0x15, 0x60, 0x24, 0x10, 0xd3, 0xed, 0xfd, - 0x81, 0x91, 0x81, 0xe2, 0x20, 0x9f, 0x11, 0xe4, 0x5d, 0x92, 0x5f, 0x1f, 0xe1, 0x17, 0xcf, 0xb7, - 0x3d, 0xf7, 0x91, 0x1b, 0xcf, 0xcc, 0xba, 0x4f, 0x3b, 0x7e, 0x27, 0x4c, 0x58, 0x9c, 0x39, 0x2f, - 0x82, 0x29, 0xf7, 0x77, 0x5f, 0x4f, 0xf7, 0xf7, 0x9b, 0xda, 0x41, 0xb1, 0x96, 0xce, 0x97, 0x5b, - 0x16, 0xa6, 0xbb, 0x39, 0x3e, 0x41, 0xfe, 0x1a, 0x86, 0x30, 0x03, 0x2f, 0x3f, 0x85, 0x1f, 0x9b, - 0xbf, 0x29, 0xba, 0xb3, 0x4b, 0xf5, 0x79, 0xca, 0x5e, 0x91, 0x4c, 0x82, 0x6b, 0x1c, 0x01, 0x86, - 0xc6, 0x11, 0x42, 0xb6, 0x60, 0x6a, 0x93, 0x6d, 0x74, 0xf9, 0x8d, 0x86, 0x76, 0x20, 0x5c, 0x82, - 0xdc, 0xd9, 0x88, 0x1b, 0xed, 0xb6, 0x44, 0xd7, 0xa9, 0xc2, 0xeb, 0x7b, 0xcd, 0x0c, 0x76, 0xb2, - 0x04, 0x93, 0x35, 0xea, 0x04, 0x8d, 0xfd, 0x07, 0xf4, 0x19, 0x33, 0x32, 0x8c, 0xa7, 0x71, 0x42, - 0xc4, 0xb0, 0xf6, 0x22, 0x4a, 0x8f, 0xac, 0x32, 0x99, 0xc8, 0xa7, 0x30, 0x54, 0xf3, 0x83, 0xa8, - 0xfa, 0x4c, 0xcc, 0xd6, 0xf2, 0x9c, 0x96, 0x03, 0xab, 0xe7, 0xe4, 0xf3, 0x40, 0xa1, 0x1f, 0x44, - 0xf5, 0x5d, 0x23, 0x13, 0x1c, 0x27, 0x21, 0xcf, 0x60, 0xda, 0x9c, 0x29, 0x45, 0xa0, 0xfd, 0x88, - 0x30, 0x6e, 0xb2, 0xa6, 0x63, 0x4e, 0x52, 0xbd, 0x2e, 0xa4, 0x5f, 0x4e, 0xce, 0xc7, 0x8f, 0x10, - 0xaf, 0x5b, 0x04, 0x59, 0xfc, 0x64, 0x0d, 0xdf, 0x55, 0xe2, 0x2d, 0xaa, 0x84, 0x3c, 0x40, 0x7f, - 0x34, 0xce, 0x35, 0xd8, 0xc1, 0xd9, 0x16, 0x35, 0xe1, 0x84, 0xc9, 0xc7, 0xb8, 0xec, 0x14, 0x2b, - 0xd9, 0x84, 0x33, 0xdb, 0x21, 0xdd, 0x0c, 0xe8, 0x13, 0x97, 0x3e, 0x95, 0xf2, 0x20, 0x4e, 0xcc, - 0xc6, 0xe4, 0xb5, 0x39, 0x36, 0x4b, 0x60, 0x9a, 0x99, 0xbc, 0x07, 0xb0, 0xe9, 0x7a, 0x1e, 0x6d, - 0xe2, 0x61, 0xff, 0x18, 0x8a, 0xc2, 0x83, 0x8c, 0x36, 0x42, 0xeb, 0xbe, 0xd7, 0xd2, 0x55, 0xaa, - 0x11, 0x93, 0x2a, 0x4c, 0xac, 0x78, 0x8d, 0x56, 0x47, 0x04, 0xe5, 0x84, 0x38, 0x53, 0x8a, 0x84, - 0x91, 0x2e, 0x47, 0xd4, 0x53, 0x1f, 0xb9, 0xc9, 0x42, 0x1e, 0x00, 0x11, 0x00, 0x31, 0x6a, 0x9d, - 0xdd, 0x16, 0x15, 0x9f, 0x3b, 0x3a, 0x28, 0xa5, 0x20, 0x1c, 0xee, 0x46, 0x1e, 0xc6, 0x14, 0xdb, - 0xdc, 0x7b, 0x30, 0xa6, 0x8d, 0xf9, 0x8c, 0xec, 0x28, 0xd3, 0x7a, 0x76, 0x94, 0x51, 0x3d, 0x0b, - 0xca, 0x3f, 0x2d, 0xc0, 0x85, 0xec, 0x6f, 0x49, 0xd8, 0x26, 0x1b, 0x30, 0xaa, 0x80, 0xea, 0x3e, - 0x9c, 0x34, 0xb8, 0x13, 0x5b, 0x3b, 0xfe, 0x41, 0xcb, 0x99, 0x47, 0x6f, 0x7d, 0x2c, 0xe3, 0x39, - 0x4e, 0xc1, 0xfe, 0xe6, 0x08, 0x4c, 0xe3, 0xbd, 0x8f, 0xe4, 0x3c, 0xf5, 0x09, 0x66, 0x39, 0x42, - 0x98, 0x76, 0xa8, 0x23, 0xfc, 0xbb, 0x1c, 0x9e, 0xcc, 0xf7, 0x67, 0x30, 0x90, 0xb7, 0xf5, 0x48, - 0xa4, 0x3e, 0xed, 0x1d, 0x27, 0x09, 0xd4, 0x9b, 0x10, 0x87, 0x28, 0xbd, 0x6e, 0x04, 0xc2, 0x1c, - 0x7b, 0xd2, 0x1b, 0x38, 0xee, 0xa4, 0xb7, 0xad, 0x26, 0x3d, 0x9e, 0x3d, 0xe7, 0x35, 0x6d, 0xd2, - 0x7b, 0xf9, 0xb3, 0xdd, 0xd0, 0xcb, 0x9e, 0xed, 0x86, 0x5f, 0x6c, 0xb6, 0x1b, 0x79, 0xce, 0xd9, - 0xee, 0x2e, 0x4c, 0xae, 0x53, 0xda, 0xd4, 0x8e, 0x27, 0x47, 0xe3, 0xd5, 0xd3, 0xa3, 0xe8, 0x78, - 0xce, 0x3a, 0xa3, 0x4c, 0x70, 0xe5, 0xce, 0x9a, 0xf0, 0x57, 0x33, 0x6b, 0x8e, 0xbd, 0xe4, 0x59, - 0x73, 0xfc, 0x45, 0x66, 0xcd, 0xd4, 0xd4, 0x37, 0x71, 0xe2, 0xa9, 0xef, 0x45, 0x66, 0xab, 0x8f, - 0x31, 0x90, 0xb7, 0x56, 0x5b, 0x16, 0x31, 0x5b, 0x5a, 0x90, 0xd4, 0xb2, 0x1f, 0xca, 0x7b, 0x0e, - 0xf8, 0x37, 0x83, 0xe1, 0x6b, 0x19, 0xc2, 0x1d, 0xc0, 0xfe, 0xb6, 0xaa, 0x18, 0xbe, 0xab, 0xf3, - 0xab, 0xfb, 0x40, 0xc3, 0xe2, 0x32, 0xb1, 0x98, 0xe3, 0x92, 0xdb, 0x4f, 0x5b, 0xe2, 0xad, 0x3f, - 0x2d, 0xf0, 0x50, 0x80, 0xff, 0x17, 0xa7, 0xca, 0x17, 0x39, 0x9e, 0xff, 0xb5, 0x38, 0xc9, 0x88, - 0x48, 0x88, 0x12, 0x38, 0x8d, 0xc7, 0x71, 0x7c, 0xc4, 0xf7, 0xd9, 0x77, 0xae, 0x23, 0xc4, 0x46, - 0x7d, 0x56, 0x69, 0x4a, 0x47, 0xee, 0xdc, 0x91, 0x13, 0x80, 0xc8, 0xb5, 0xc2, 0xc1, 0xe6, 0x04, - 0xa0, 0x33, 0x60, 0x84, 0xea, 0x69, 0xcb, 0xe6, 0x39, 0x32, 0x32, 0x6b, 0xf0, 0x4e, 0x3a, 0xcb, - 0x03, 0x5a, 0x59, 0x71, 0x96, 0x07, 0x5d, 0x8d, 0x71, 0xbe, 0x87, 0x6d, 0x38, 0x6f, 0xd3, 0x03, - 0xff, 0x09, 0x7d, 0xb9, 0x62, 0xbf, 0x82, 0x73, 0xa6, 0x40, 0x7e, 0x1f, 0x90, 0x3f, 0x5e, 0xf1, - 0x71, 0xf6, 0x93, 0x17, 0x82, 0x81, 0x3f, 0x79, 0xc1, 0x33, 0xe7, 0xb3, 0x3f, 0xf5, 0x75, 0x03, - 0x71, 0x96, 0x0f, 0x17, 0x4c, 0xe1, 0x95, 0x66, 0x13, 0x5f, 0xcd, 0x6d, 0xb8, 0x6d, 0xc7, 0x8b, - 0xc8, 0x06, 0x8c, 0x69, 0x3f, 0x13, 0x3e, 0x10, 0x0d, 0x23, 0xf6, 0x34, 0x31, 0xc0, 0xc8, 0x3c, - 0x1c, 0x83, 0x2d, 0x0a, 0xe5, 0xa4, 0x7a, 0x98, 0xca, 0xf4, 0x32, 0xab, 0x30, 0xa1, 0xfd, 0x54, - 0x07, 0x05, 0xf8, 0xf1, 0x6b, 0x25, 0x98, 0x0a, 0x33, 0x59, 0xac, 0x06, 0xcc, 0x65, 0x29, 0x8d, - 0xa7, 0xa8, 0x27, 0x4b, 0x71, 0x06, 0xba, 0xde, 0x31, 0xae, 0xa7, 0xf3, 0xb2, 0xcf, 0x59, 0x7f, - 0x6f, 0x00, 0xce, 0x8b, 0xce, 0x78, 0x99, 0x3d, 0x4e, 0x7e, 0x00, 0x63, 0x5a, 0x1f, 0x0b, 0xa5, - 0x5f, 0x96, 0xb7, 0xf9, 0xf2, 0xc6, 0x02, 0xf7, 0xd5, 0x74, 0x10, 0x50, 0x4f, 0x74, 0xf7, 0xf2, - 0x29, 0x5b, 0x17, 0x49, 0x5a, 0x30, 0x69, 0x76, 0xb4, 0x70, 0x57, 0x5d, 0xcd, 0x2c, 0xc4, 0x24, - 0x95, 0xf9, 0xeb, 0x9b, 0xf5, 0xcc, 0xee, 0x5e, 0x3e, 0x65, 0x27, 0x64, 0x93, 0x6f, 0xe0, 0x4c, - 0xaa, 0x97, 0x85, 0x2f, 0xf2, 0xd5, 0xcc, 0x02, 0x53, 0xd4, 0xfc, 0x10, 0x24, 0x40, 0x70, 0x6e, - 0xb1, 0xe9, 0x42, 0x48, 0x13, 0xc6, 0xf5, 0x8e, 0x17, 0xfe, 0xb4, 0x2b, 0x5d, 0x54, 0xc9, 0x09, - 0xf9, 0xe6, 0x4e, 0xe8, 0x12, 0xfb, 0xfe, 0x99, 0x79, 0xb0, 0x63, 0x10, 0x8f, 0xc0, 0x10, 0xff, - 0x6d, 0xfd, 0x5e, 0x01, 0xce, 0x6f, 0x06, 0x34, 0xa4, 0x5e, 0x83, 0x1a, 0xf7, 0x22, 0x5e, 0x70, - 0x44, 0xe4, 0x9d, 0xa9, 0xf4, 0xbd, 0xf0, 0x99, 0x8a, 0xf5, 0x6f, 0x0b, 0x50, 0xca, 0xaa, 0x72, - 0x8d, 0x7a, 0x4d, 0xb2, 0x09, 0xc5, 0x64, 0x1b, 0xc4, 0x17, 0x63, 0xa9, 0xf4, 0xe3, 0xb9, 0xad, - 0x5d, 0x3e, 0x65, 0xa7, 0xb8, 0xc9, 0x3a, 0x9c, 0xd1, 0x60, 0xe2, 0x4c, 0xa3, 0xef, 0x38, 0x67, - 0x1a, 0xac, 0x87, 0x53, 0xac, 0xfa, 0x91, 0xd0, 0x32, 0xae, 0xba, 0x8b, 0xfe, 0x81, 0xe3, 0x7a, - 0x6c, 0x13, 0xad, 0x25, 0xb8, 0x83, 0x18, 0x2a, 0xd4, 0xce, 0x0f, 0x39, 0x10, 0x2a, 0xaf, 0x88, - 0x29, 0x12, 0xeb, 0x43, 0x5c, 0x1d, 0x84, 0x63, 0x93, 0x5f, 0xca, 0x57, 0xc2, 0x2e, 0xc3, 0xe0, - 0xd6, 0x6a, 0x6d, 0xa1, 0x22, 0xae, 0xf8, 0xf3, 0xc4, 0x30, 0xad, 0xb0, 0xde, 0x70, 0x6c, 0x8e, - 0xb0, 0x3e, 0x00, 0x72, 0x8f, 0x46, 0xe2, 0xfd, 0x0b, 0xc5, 0x77, 0x0d, 0x86, 0x05, 0x48, 0x70, - 0xa2, 0xbb, 0x5e, 0xbc, 0xa6, 0x61, 0x4b, 0x9c, 0xb5, 0x29, 0x6d, 0x90, 0x16, 0x75, 0x42, 0x6d, - 0xd1, 0x7f, 0x17, 0x46, 0x02, 0x01, 0x13, 0x6b, 0xfe, 0xa4, 0x7a, 0xde, 0x08, 0xc1, 0xfc, 0x18, - 0x49, 0xd2, 0xd8, 0xea, 0x2f, 0x6b, 0x15, 0x93, 0x38, 0x6d, 0xac, 0x2c, 0x2e, 0x30, 0xad, 0x0a, - 0x65, 0xc9, 0xee, 0xb8, 0x85, 0xb7, 0x42, 0x22, 0xaa, 0x5f, 0xf0, 0x47, 0xd5, 0xe0, 0x04, 0x22, - 0x52, 0x97, 0x69, 0x24, 0xd6, 0x9b, 0x2a, 0x25, 0x54, 0x86, 0xb4, 0xbc, 0x67, 0x7a, 0xd6, 0x31, - 0xd9, 0xd5, 0x3d, 0x0c, 0x80, 0x7b, 0x19, 0x95, 0x70, 0x60, 0x8e, 0x6f, 0x21, 0x58, 0xab, 0xc4, - 0x23, 0xa5, 0xbe, 0x9a, 0x76, 0x17, 0x60, 0x54, 0xc1, 0xd4, 0x69, 0x36, 0xd7, 0x95, 0x41, 0xbf, - 0xf3, 0x26, 0xcf, 0x85, 0xd0, 0x50, 0x02, 0x62, 0x3e, 0x56, 0x04, 0xff, 0xa6, 0xbf, 0xe5, 0x22, - 0x42, 0x1a, 0x44, 0xdf, 0x6a, 0x11, 0x71, 0x36, 0xb4, 0x93, 0x14, 0x61, 0xd0, 0xef, 0xcc, 0x1f, - 0x47, 0x51, 0xdf, 0x72, 0x11, 0x4c, 0x51, 0xdf, 0x5e, 0x11, 0x54, 0xa6, 0x8d, 0xe3, 0x83, 0x34, - 0x55, 0xc8, 0x52, 0xba, 0x10, 0xe9, 0xed, 0x4f, 0x70, 0x74, 0xed, 0x0f, 0x0a, 0x17, 0xb8, 0xb2, - 0x7e, 0x0e, 0xc5, 0x30, 0x85, 0x7d, 0xbb, 0xc5, 0xfc, 0xc3, 0x02, 0x4f, 0x62, 0x57, 0xdb, 0xd0, - 0x9e, 0x07, 0xf6, 0x1e, 0xf9, 0x5a, 0xb0, 0x8d, 0xf6, 0xb5, 0x6b, 0x87, 0x9f, 0x18, 0x6c, 0xe3, - 0x74, 0xa2, 0x7d, 0x95, 0xe4, 0x1d, 0x4f, 0x42, 0x93, 0xd4, 0xe4, 0x3d, 0x98, 0xd0, 0x40, 0x6a, - 0x27, 0xc8, 0x9f, 0xe1, 0xd1, 0xd9, 0xdd, 0xa6, 0x6d, 0x52, 0x5a, 0x7f, 0x59, 0x80, 0xa9, 0x8c, - 0x87, 0xeb, 0xd1, 0x51, 0x82, 0x16, 0x96, 0x9a, 0xa8, 0xc4, 0xc3, 0x79, 0x98, 0x4f, 0xc7, 0x58, - 0x7f, 0x15, 0x21, 0x3e, 0x40, 0xa2, 0x3d, 0xb2, 0xdf, 0xa7, 0x3d, 0x07, 0x99, 0xfd, 0xb0, 0xbe, - 0x4e, 0x4e, 0x42, 0x80, 0xb8, 0x26, 0xc2, 0x25, 0x5d, 0x63, 0xdb, 0x65, 0xed, 0x85, 0xfe, 0x98, - 0xf7, 0x67, 0x87, 0xe5, 0x77, 0x4e, 0x12, 0x2a, 0x1c, 0x8b, 0xb6, 0xb5, 0x62, 0xac, 0x5f, 0xeb, - 0x83, 0xb3, 0x19, 0xed, 0xaf, 0xd1, 0xe8, 0xaf, 0x42, 0x05, 0x4f, 0x60, 0x2c, 0xae, 0x4c, 0x58, - 0xea, 0x47, 0xcf, 0xcd, 0x16, 0xbe, 0x97, 0x11, 0xeb, 0x20, 0x7c, 0x29, 0x4a, 0xd0, 0x0b, 0xb2, - 0xfe, 0xa8, 0x0f, 0xce, 0x6e, 0xb7, 0x43, 0xbc, 0x33, 0xb9, 0xe2, 0x3d, 0xa1, 0x5e, 0xe4, 0x07, - 0xcf, 0xf0, 0x9e, 0x17, 0x79, 0x1b, 0x06, 0x97, 0x69, 0xab, 0xe5, 0x8b, 0xf1, 0x7f, 0x51, 0xc6, - 0x3b, 0x25, 0xa9, 0x91, 0x68, 0xf9, 0x94, 0xcd, 0xa9, 0xc9, 0x7b, 0x30, 0xba, 0x4c, 0x9d, 0x20, - 0xda, 0xa5, 0x8e, 0x34, 0x87, 0xe4, 0xe3, 0x40, 0x1a, 0x8b, 0x20, 0x58, 0x3e, 0x65, 0xc7, 0xd4, - 0x64, 0x1e, 0x06, 0x36, 0x7d, 0x6f, 0x4f, 0xe5, 0x87, 0xc8, 0x29, 0x90, 0xd1, 0x2c, 0x9f, 0xb2, - 0x91, 0x96, 0xac, 0xc1, 0x44, 0x65, 0x8f, 0x7a, 0x51, 0xe2, 0x08, 0xff, 0x5a, 0x1e, 0xb3, 0x41, - 0xbc, 0x7c, 0xca, 0x36, 0xb9, 0xc9, 0x07, 0x30, 0x7c, 0xcf, 0xf7, 0x9b, 0xbb, 0xcf, 0x64, 0x96, - 0x93, 0x72, 0x9e, 0x20, 0x41, 0xb6, 0x7c, 0xca, 0x96, 0x1c, 0xd5, 0x41, 0xe8, 0x5f, 0x0b, 0xf7, - 0xac, 0xc3, 0x02, 0x94, 0x16, 0xfd, 0xa7, 0x5e, 0xa6, 0x56, 0xbf, 0x67, 0x6a, 0x55, 0x8a, 0xcf, - 0xa0, 0x4f, 0xe8, 0xf5, 0x2d, 0x18, 0xd8, 0x74, 0xbd, 0xbd, 0xc4, 0x56, 0x30, 0x83, 0x8f, 0x51, - 0xa1, 0x7a, 0x5c, 0x6f, 0x8f, 0xac, 0xca, 0xfd, 0xbd, 0xf0, 0x63, 0xf6, 0x1b, 0x46, 0x45, 0x06, - 0xb7, 0x4e, 0x1d, 0xef, 0xe3, 0xf9, 0x6f, 0xd9, 0xc0, 0xd7, 0x61, 0x36, 0xa7, 0x5c, 0x2d, 0x24, - 0x65, 0x00, 0x37, 0x36, 0x7f, 0xab, 0x00, 0x33, 0x99, 0x1d, 0x98, 0xa4, 0x64, 0x36, 0x1d, 0x1f, - 0x98, 0x0b, 0x2d, 0xbf, 0xf1, 0xf8, 0x18, 0x61, 0x93, 0x96, 0x7c, 0x50, 0x5f, 0x7c, 0x21, 0x0d, - 0xc6, 0x97, 0x78, 0x34, 0x51, 0x17, 0x69, 0xfd, 0xf3, 0xac, 0xb1, 0xce, 0x95, 0x5b, 0x8a, 0x43, - 0x45, 0xb8, 0xeb, 0x4a, 0x45, 0x87, 0xcc, 0x69, 0x73, 0x81, 0xcc, 0x98, 0x24, 0x3f, 0xf9, 0x1d, - 0x2d, 0x43, 0x1d, 0xff, 0x62, 0xdf, 0x7f, 0x81, 0xef, 0x52, 0xc9, 0x62, 0x65, 0x2e, 0xfb, 0x61, - 0xe4, 0xa9, 0x70, 0x7d, 0x5b, 0xfd, 0x26, 0x37, 0xa0, 0x28, 0x1f, 0xe1, 0x11, 0xaf, 0x7d, 0x05, - 0x22, 0xe6, 0x24, 0x05, 0x27, 0xef, 0xc2, 0x6c, 0x12, 0x26, 0x5b, 0xc9, 0xaf, 0xc5, 0xe6, 0xa1, - 0xad, 0x3f, 0xe9, 0xc3, 0x47, 0x04, 0xba, 0x7c, 0x3a, 0xac, 0xff, 0x36, 0x6a, 0x32, 0xf8, 0x68, - 0xa3, 0x46, 0x2e, 0xc0, 0xe8, 0x46, 0xcd, 0x78, 0xdd, 0xd0, 0x8e, 0x01, 0xac, 0xda, 0xac, 0x09, - 0x95, 0xa0, 0xb1, 0xef, 0x46, 0xb4, 0x11, 0x75, 0x02, 0x19, 0x8d, 0x94, 0x82, 0x13, 0x0b, 0xc6, - 0xef, 0xb5, 0xdc, 0xdd, 0x86, 0x14, 0xc6, 0x55, 0x60, 0xc0, 0xc8, 0xab, 0x30, 0xb9, 0xe2, 0x85, - 0x91, 0xd3, 0x6a, 0xad, 0xd1, 0x68, 0xdf, 0x6f, 0x8a, 0xb7, 0x9b, 0xed, 0x04, 0x94, 0x95, 0xbb, - 0xe0, 0x7b, 0x91, 0xe3, 0x7a, 0x34, 0xb0, 0x3b, 0x5e, 0xe4, 0x1e, 0x50, 0xd1, 0xf6, 0x14, 0x9c, - 0xbc, 0x05, 0x33, 0x0a, 0xb6, 0x11, 0x34, 0xf6, 0x69, 0x18, 0x05, 0xf8, 0xe6, 0x29, 0x06, 0xe6, - 0xd9, 0xd9, 0x48, 0x2c, 0xa1, 0xe5, 0x77, 0x9a, 0x4b, 0xde, 0x13, 0x37, 0xf0, 0xf9, 0x89, 0xf7, - 0x88, 0x28, 0x21, 0x01, 0xb7, 0x7e, 0x67, 0x24, 0x73, 0x66, 0x78, 0x91, 0x31, 0xf8, 0x05, 0x8c, - 0x2f, 0x38, 0x6d, 0x67, 0xd7, 0x6d, 0xb9, 0x91, 0xab, 0x1e, 0x87, 0x7c, 0xbb, 0xc7, 0xb4, 0x22, - 0x9f, 0x65, 0xa2, 0x4d, 0x9d, 0xd9, 0x36, 0x44, 0xcd, 0xfd, 0xc5, 0x10, 0xcc, 0x64, 0xd2, 0x91, - 0xeb, 0xe2, 0x15, 0x49, 0x35, 0x75, 0x8b, 0x27, 0x0a, 0xed, 0x24, 0x98, 0xf5, 0x25, 0x82, 0x16, - 0x5a, 0xd4, 0xf1, 0x3a, 0xe2, 0x81, 0x42, 0xdb, 0x80, 0xb1, 0xbe, 0x64, 0x5b, 0x13, 0x4d, 0x18, - 0xde, 0xb6, 0xb0, 0x13, 0x50, 0x0c, 0x66, 0xeb, 0x44, 0xfb, 0x52, 0xd4, 0x00, 0xbf, 0x17, 0xac, - 0x81, 0x98, 0xa4, 0x75, 0xbf, 0x49, 0x35, 0x49, 0x83, 0x5c, 0x92, 0x09, 0x65, 0x92, 0x18, 0x44, - 0x4a, 0x1a, 0xe2, 0x92, 0x34, 0x10, 0x79, 0x05, 0x26, 0x2a, 0xed, 0xb6, 0x26, 0x08, 0x5f, 0x26, - 0xb4, 0x4d, 0x20, 0xb9, 0x04, 0x50, 0x69, 0xb7, 0xa5, 0x18, 0x7c, 0x75, 0xd0, 0xd6, 0x20, 0xe4, - 0x66, 0x9c, 0x07, 0x52, 0x13, 0x85, 0xa7, 0x21, 0x76, 0x06, 0x86, 0xe9, 0x55, 0x25, 0xcd, 0x13, - 0x42, 0x81, 0xeb, 0x35, 0x01, 0x26, 0x1f, 0xc2, 0xb9, 0x44, 0x3c, 0x8c, 0x56, 0x00, 0x9e, 0x54, - 0xd8, 0xf9, 0x04, 0xe4, 0x1d, 0x38, 0x9b, 0x40, 0xca, 0xe2, 0xf0, 0x50, 0xc2, 0xce, 0xc1, 0x92, - 0xf7, 0xa1, 0x94, 0xc8, 0xf5, 0x10, 0x17, 0x8a, 0x07, 0x10, 0x76, 0x2e, 0x9e, 0x7d, 0x5d, 0x89, - 0x4b, 0xa3, 0xa2, 0x48, 0x3c, 0x6b, 0xb5, 0xb3, 0x91, 0x64, 0x19, 0xca, 0x99, 0x31, 0x46, 0x5a, - 0xc1, 0xf8, 0x9a, 0xa2, 0xdd, 0x8b, 0x8c, 0x54, 0xe1, 0x42, 0x26, 0x89, 0xac, 0x06, 0xbe, 0xb1, - 0x68, 0x77, 0xa5, 0x21, 0xf3, 0x30, 0x1d, 0xc7, 0x5a, 0x69, 0x55, 0xc0, 0xe7, 0x15, 0xed, 0x4c, - 0x1c, 0x79, 0xc3, 0xcc, 0xe8, 0xc1, 0x0b, 0xc3, 0xd7, 0x15, 0xed, 0x34, 0xc2, 0x3a, 0x2a, 0xc0, - 0x85, 0xcc, 0xb5, 0x58, 0x9a, 0x0c, 0x73, 0xc9, 0xbd, 0xa9, 0x36, 0x17, 0xdc, 0x10, 0x01, 0x94, - 0xdc, 0xd5, 0x2d, 0x03, 0xd4, 0x91, 0x9f, 0x8b, 0x7a, 0x10, 0x87, 0x53, 0xde, 0x53, 0x47, 0x9b, - 0xfd, 0xe8, 0x2c, 0xb9, 0x95, 0xdc, 0xa3, 0x65, 0x14, 0xae, 0x1f, 0x71, 0xca, 0xc3, 0xcc, 0x17, - 0x39, 0x45, 0xfa, 0x93, 0x02, 0x94, 0x7b, 0x6c, 0x41, 0x54, 0x9b, 0x0a, 0xc7, 0x68, 0xd3, 0x7d, - 0xd5, 0x26, 0x7e, 0xa1, 0x7e, 0xfe, 0x78, 0xdb, 0x9c, 0x97, 0xdd, 0xac, 0xbf, 0x2c, 0x00, 0x49, - 0x6f, 0x75, 0xc9, 0x77, 0x61, 0xb4, 0x56, 0x5b, 0x36, 0x22, 0x2d, 0x53, 0x87, 0x5b, 0x31, 0x05, - 0xb9, 0x7d, 0xac, 0xd0, 0x4a, 0x3d, 0xb0, 0xf2, 0x93, 0x54, 0x3c, 0x67, 0x7f, 0xd7, 0x78, 0xce, - 0x54, 0x34, 0xe7, 0x52, 0x46, 0x80, 0xe2, 0x40, 0x8f, 0x00, 0xc5, 0x74, 0xf4, 0xa1, 0xb5, 0x08, - 0xa5, 0xbc, 0xdd, 0x32, 0xce, 0x70, 0x3c, 0x7b, 0xa2, 0x76, 0x40, 0xc7, 0x67, 0x38, 0x13, 0x6c, - 0xbd, 0x03, 0x67, 0x15, 0x37, 0x7f, 0x96, 0x49, 0x4b, 0x5b, 0x22, 0x4c, 0x6c, 0x95, 0x1e, 0x25, - 0x06, 0x58, 0x7f, 0x3c, 0x90, 0x62, 0xac, 0x75, 0x0e, 0x0e, 0x9c, 0xe0, 0x19, 0xa9, 0x98, 0x8c, - 0xfd, 0x3d, 0xad, 0x9a, 0xea, 0x00, 0xdb, 0x63, 0x6a, 0xd2, 0xd9, 0xba, 0x80, 0x3b, 0x0c, 0xaf, - 0x41, 0xf9, 0xd1, 0x5e, 0x1f, 0x4f, 0xcd, 0x66, 0x00, 0xc9, 0x0e, 0x4c, 0x88, 0xb5, 0x1b, 0x7f, - 0xcb, 0x6f, 0xec, 0x76, 0xf2, 0x1b, 0x33, 0xaa, 0x77, 0xd3, 0x60, 0xe1, 0xa3, 0xd1, 0x14, 0x43, - 0xbe, 0x80, 0x49, 0xb9, 0x53, 0x13, 0x82, 0x79, 0x30, 0xd6, 0x9d, 0xee, 0x82, 0x4d, 0x1e, 0x2e, - 0x39, 0x21, 0x88, 0x55, 0x59, 0x4e, 0x76, 0x5c, 0xf2, 0xe0, 0x71, 0xaa, 0x6c, 0xb0, 0x88, 0x2a, - 0x1b, 0xb0, 0xb9, 0x4f, 0x81, 0xa4, 0xdb, 0xd5, 0xeb, 0x73, 0x9a, 0xd0, 0x3e, 0xa7, 0xb9, 0x0a, - 0x4c, 0x65, 0x34, 0xe0, 0x44, 0x22, 0x3e, 0x05, 0x92, 0xae, 0xe9, 0x49, 0x24, 0x58, 0xd7, 0xe1, - 0x55, 0xa5, 0x02, 0x35, 0x1a, 0x0c, 0x99, 0xd2, 0xc9, 0xfe, 0x2b, 0x7d, 0x50, 0xee, 0x41, 0x4a, - 0xfe, 0x71, 0x21, 0xa9, 0x6d, 0x3e, 0x1a, 0xdf, 0x4b, 0x6a, 0x3b, 0x9b, 0x3f, 0x43, 0xed, 0xd5, - 0xf7, 0x7f, 0xf5, 0xcf, 0x9e, 0xdb, 0xf2, 0x48, 0x77, 0xd9, 0xc9, 0xb5, 0x35, 0xa0, 0x6b, 0x6b, - 0x07, 0xa6, 0x0d, 0xb3, 0xf0, 0x38, 0x8b, 0x97, 0x05, 0x20, 0x5e, 0x88, 0x5e, 0xf5, 0xf7, 0xc4, - 0x43, 0xd6, 0x7d, 0xa5, 0x82, 0xad, 0x41, 0xad, 0xbb, 0x30, 0x93, 0x90, 0x2b, 0x9c, 0xff, 0xdf, - 0x05, 0x95, 0xa2, 0x02, 0x05, 0xf7, 0x57, 0xcf, 0xfc, 0xec, 0xb0, 0x3c, 0xc1, 0xb6, 0xf5, 0x37, - 0xe3, 0x57, 0x42, 0xe4, 0x5f, 0xd6, 0x9a, 0x7e, 0x7c, 0x51, 0x69, 0xe9, 0xa9, 0xbb, 0xc8, 0x1d, - 0x18, 0xe2, 0x90, 0x44, 0x2e, 0x7e, 0x9d, 0x5a, 0xcc, 0x0b, 0x82, 0xd0, 0x9a, 0xc1, 0x0b, 0xf5, - 0xf8, 0xa3, 0x12, 0x27, 0x80, 0xb1, 0xb6, 0xf9, 0xdb, 0x54, 0x31, 0x58, 0xe5, 0xfb, 0x1f, 0xa8, - 0xc4, 0x89, 0x6a, 0x64, 0x1c, 0x8b, 0xa4, 0xf3, 0xfc, 0xa7, 0x2d, 0xda, 0xe4, 0x8f, 0x8a, 0x56, - 0xc7, 0x85, 0x8d, 0x3b, 0xe0, 0x30, 0x01, 0xc8, 0x66, 0x7d, 0x02, 0x33, 0x6c, 0xb7, 0x10, 0x24, - 0xcb, 0xc3, 0x17, 0x69, 0x18, 0xcc, 0xbc, 0x37, 0xe3, 0x30, 0x10, 0xde, 0x9b, 0x11, 0x48, 0x6b, - 0x15, 0xce, 0x71, 0xe7, 0xa7, 0xde, 0xa4, 0xf8, 0xa8, 0x61, 0x10, 0x7f, 0x27, 0xae, 0x63, 0x67, - 0xb4, 0x9e, 0xd3, 0x59, 0x1f, 0xe3, 0x7d, 0x3f, 0x31, 0x50, 0x5d, 0xdf, 0x8b, 0x3d, 0x9d, 0xc7, - 0x4b, 0x10, 0xf0, 0xff, 0xc3, 0x85, 0x4a, 0xbb, 0x4d, 0xbd, 0x66, 0xcc, 0xb8, 0x15, 0x38, 0xc7, - 0x4c, 0xdf, 0x42, 0x2a, 0x30, 0x88, 0xd4, 0xea, 0x0c, 0x58, 0x54, 0x37, 0xa3, 0x3a, 0x48, 0x27, - 0x92, 0x33, 0x63, 0x01, 0x9c, 0xd3, 0x6a, 0xc2, 0x6c, 0xad, 0xb3, 0x7b, 0xe0, 0x46, 0x78, 0xdb, - 0x06, 0x53, 0x20, 0xc9, 0xb2, 0x57, 0xe4, 0x73, 0x82, 0x5c, 0x19, 0xd7, 0xe3, 0x7b, 0x61, 0x78, - 0x61, 0x47, 0xa4, 0x45, 0x7a, 0x72, 0xe7, 0x66, 0xcc, 0x8a, 0x5e, 0x1e, 0x5e, 0x0a, 0xa2, 0xc5, - 0x93, 0x83, 0xd6, 0x14, 0x9c, 0xd1, 0xcf, 0xbc, 0xf8, 0x08, 0x99, 0x81, 0x29, 0xf3, 0x2c, 0x8b, - 0x83, 0xbf, 0x86, 0x69, 0xee, 0x6b, 0xe7, 0x8f, 0x2b, 0xcc, 0xc7, 0xef, 0x08, 0xf4, 0xed, 0xcc, - 0x27, 0x2e, 0x69, 0x60, 0xec, 0xb6, 0x7a, 0x36, 0x67, 0x67, 0x9e, 0xdf, 0xd9, 0x7e, 0x32, 0x6f, - 0x9c, 0xc6, 0xf6, 0xed, 0xcc, 0x57, 0x87, 0x45, 0x92, 0x6a, 0x26, 0x9d, 0x77, 0xff, 0xb7, 0x22, - 0x7d, 0x1e, 0xd3, 0x84, 0x2c, 0x53, 0x07, 0xaf, 0xf4, 0x65, 0x27, 0x5b, 0x98, 0x84, 0x3e, 0x95, - 0x85, 0xb6, 0xcf, 0x6d, 0x5a, 0xbf, 0x5f, 0x80, 0xeb, 0x7c, 0x43, 0x96, 0xcd, 0x87, 0x07, 0x5b, - 0x39, 0xcc, 0xe4, 0x5d, 0x18, 0x0c, 0xb5, 0x00, 0x0f, 0x4b, 0xd4, 0xbc, 0x9b, 0x24, 0xce, 0x40, - 0x2a, 0x30, 0xae, 0xdf, 0x5c, 0x3b, 0x5e, 0x82, 0x4b, 0x7b, 0xec, 0xe0, 0x91, 0xa3, 0x6e, 0xb3, - 0x3d, 0x86, 0xf3, 0x4b, 0xdf, 0xb0, 0x01, 0x21, 0x56, 0x28, 0x61, 0x3d, 0xc4, 0x97, 0xf9, 0x4f, - 0x6f, 0x89, 0x11, 0x63, 0x9a, 0xf6, 0x49, 0x30, 0xb3, 0x93, 0xe5, 0x22, 0x17, 0x5f, 0x71, 0xb2, - 0x0d, 0x98, 0xf5, 0xc7, 0x05, 0xb8, 0x90, 0x5d, 0x9a, 0x98, 0x58, 0x56, 0xe0, 0xcc, 0x82, 0xe3, - 0xf9, 0x9e, 0xdb, 0x70, 0x5a, 0xb5, 0xc6, 0x3e, 0x6d, 0x76, 0x54, 0x2a, 0x6b, 0x35, 0xcb, 0xec, - 0x51, 0x4f, 0xb2, 0x4b, 0x12, 0x3b, 0xcd, 0xc5, 0x2c, 0x44, 0xbc, 0xba, 0xc2, 0xe7, 0xde, 0x16, - 0x0d, 0x94, 0x3c, 0x5e, 0xb3, 0x1c, 0x2c, 0xb9, 0x2d, 0x0f, 0x15, 0x9a, 0xdb, 0x9e, 0x1b, 0x29, - 0x26, 0xee, 0xea, 0xc9, 0x42, 0x59, 0xff, 0xa1, 0x00, 0xe7, 0xf0, 0xf5, 0x3a, 0xe3, 0x3d, 0xdc, - 0x38, 0xa3, 0xbb, 0x4c, 0x4a, 0x5e, 0x30, 0xae, 0xe2, 0x18, 0xd4, 0x66, 0x76, 0x72, 0xf2, 0x06, - 0x0c, 0xd4, 0x64, 0xc0, 0xd9, 0x64, 0xe2, 0x25, 0x73, 0xc1, 0xc1, 0xf0, 0x36, 0x52, 0x31, 0x1b, - 0x7e, 0x91, 0x86, 0x0d, 0xea, 0xe1, 0x93, 0xf3, 0xdc, 0xf3, 0xa0, 0x41, 0xe2, 0x64, 0x6b, 0x03, - 0x79, 0xc9, 0xd6, 0x06, 0xcd, 0x64, 0x6b, 0xd6, 0x13, 0xfe, 0x76, 0x5d, 0xb2, 0x41, 0xa2, 0x93, - 0x3e, 0x4e, 0xbd, 0x50, 0xcf, 0xd7, 0x81, 0xb3, 0x59, 0x2d, 0x63, 0x9b, 0xf4, 0xc4, 0xe3, 0xf3, - 0xf9, 0x19, 0xd4, 0x37, 0xe1, 0x15, 0x83, 0xb6, 0xd2, 0x6a, 0xf9, 0x4f, 0x69, 0x73, 0x33, 0xf0, - 0x0f, 0xfc, 0xc8, 0x78, 0xbb, 0xeb, 0xb4, 0xa3, 0xd3, 0xa9, 0xc5, 0x38, 0x09, 0xb6, 0xfe, 0x3f, - 0xb8, 0xd6, 0x43, 0xa2, 0x68, 0x54, 0x0d, 0xce, 0x38, 0x09, 0x9c, 0x8c, 0x1c, 0xba, 0x96, 0xd5, - 0xae, 0xa4, 0xa0, 0xd0, 0x4e, 0xf3, 0xdf, 0xd8, 0x32, 0x5e, 0x75, 0x27, 0x25, 0x98, 0xde, 0xb4, - 0x37, 0x16, 0xb7, 0x17, 0xb6, 0xea, 0x5b, 0x5f, 0x6c, 0x2e, 0xd5, 0xb7, 0xd7, 0x1f, 0xac, 0x6f, - 0x3c, 0x5c, 0xe7, 0x4f, 0x10, 0x18, 0x98, 0xad, 0xa5, 0xca, 0x5a, 0xb1, 0x40, 0xa6, 0xa1, 0x68, - 0x80, 0x97, 0xb6, 0xab, 0xc5, 0xbe, 0x1b, 0x5f, 0x1b, 0xaf, 0x95, 0x93, 0x0b, 0x50, 0xaa, 0x6d, - 0x6f, 0x6e, 0x6e, 0xd8, 0x4a, 0xaa, 0xfe, 0x00, 0xc2, 0x0c, 0x9c, 0x31, 0xb0, 0x77, 0xed, 0xa5, - 0xa5, 0x62, 0x81, 0x55, 0xc5, 0x00, 0x6f, 0xda, 0x4b, 0x6b, 0x2b, 0xdb, 0x6b, 0xc5, 0xbe, 0x1b, - 0x75, 0xfd, 0x06, 0x29, 0x39, 0x0f, 0xb3, 0x8b, 0x4b, 0x3b, 0x2b, 0x0b, 0x4b, 0x59, 0xb2, 0xa7, - 0xa1, 0xa8, 0x23, 0xb7, 0x36, 0xb6, 0x36, 0xb9, 0x68, 0x1d, 0xfa, 0x70, 0xa9, 0x5a, 0xd9, 0xde, - 0x5a, 0x5e, 0x2f, 0xf6, 0x5b, 0x03, 0x23, 0x7d, 0xc5, 0xbe, 0x1b, 0x3f, 0x30, 0xae, 0x97, 0xb2, - 0xea, 0x0b, 0xf2, 0xed, 0x5a, 0xe5, 0x5e, 0x7e, 0x11, 0x1c, 0xbb, 0x76, 0xb7, 0x52, 0x2c, 0x90, - 0x8b, 0x70, 0xce, 0x80, 0x6e, 0x56, 0x6a, 0xb5, 0x87, 0x1b, 0xf6, 0xe2, 0xea, 0x52, 0xad, 0x56, - 0xec, 0xbb, 0xb1, 0x63, 0x24, 0x98, 0x64, 0x25, 0xac, 0xdd, 0xad, 0xd4, 0xed, 0xa5, 0xcf, 0xb6, - 0x57, 0xec, 0xa5, 0xc5, 0x74, 0x09, 0x06, 0xf6, 0x8b, 0xa5, 0x5a, 0xb1, 0x40, 0xa6, 0xe0, 0xb4, - 0x01, 0x5d, 0xdf, 0x28, 0xf6, 0xdd, 0x78, 0x55, 0xe4, 0x20, 0x24, 0x93, 0x00, 0x8b, 0x4b, 0xb5, - 0x85, 0xa5, 0xf5, 0xc5, 0x95, 0xf5, 0x7b, 0xc5, 0x53, 0x64, 0x02, 0x46, 0x2b, 0xea, 0x67, 0xe1, - 0xc6, 0xfb, 0x70, 0x3a, 0x61, 0xde, 0x33, 0x0a, 0x65, 0x18, 0x17, 0x4f, 0xa1, 0xfa, 0xe5, 0x4f, - 0xf4, 0xb1, 0x72, 0x4b, 0xbd, 0x58, 0xb8, 0x51, 0x95, 0x0f, 0x5c, 0x6b, 0xdf, 0x39, 0x19, 0x83, - 0xe1, 0xc5, 0xa5, 0xbb, 0x95, 0xed, 0xd5, 0xad, 0xe2, 0x29, 0xf6, 0x63, 0xc1, 0x5e, 0xaa, 0x6c, - 0x2d, 0x2d, 0x16, 0x0b, 0x64, 0x14, 0x06, 0x6b, 0x5b, 0x95, 0xad, 0xa5, 0x62, 0x1f, 0x19, 0x81, - 0x81, 0xed, 0xda, 0x92, 0x5d, 0xec, 0x9f, 0xff, 0xd7, 0xff, 0xa8, 0xc0, 0x1d, 0x8d, 0xf2, 0xa2, - 0xd9, 0xd7, 0x9a, 0x41, 0x29, 0xa6, 0x3c, 0xf1, 0x9a, 0x6f, 0xae, 0xf5, 0x88, 0xbb, 0x80, 0xb9, - 0x2e, 0x87, 0x3b, 0x48, 0x70, 0xbd, 0x70, 0xbb, 0x40, 0x6c, 0x0c, 0x86, 0x49, 0xd8, 0x57, 0x4a, - 0x72, 0xb6, 0x09, 0x3c, 0x77, 0xb1, 0xab, 0x59, 0x46, 0x7e, 0x09, 0x2c, 0x5d, 0x66, 0x8e, 0x15, - 0xf2, 0xdd, 0xe3, 0x59, 0x1b, 0xb2, 0xcc, 0x57, 0x8f, 0x47, 0x4e, 0xee, 0xc3, 0x04, 0xdb, 0x9b, - 0x2b, 0x32, 0x72, 0x3e, 0xc9, 0xa8, 0x99, 0x04, 0x73, 0x17, 0xb2, 0x91, 0xea, 0xc1, 0xad, 0x71, - 0x6c, 0x08, 0x37, 0xae, 0x43, 0x22, 0xf3, 0xd4, 0x48, 0x08, 0x9f, 0xf1, 0xe7, 0xce, 0x24, 0xc0, - 0x3b, 0x77, 0x6e, 0x17, 0x48, 0x0d, 0x93, 0x44, 0x1a, 0x9b, 0x7c, 0x22, 0x6f, 0x3e, 0xa6, 0x77, - 0xff, 0xbc, 0x36, 0x65, 0xf5, 0x3c, 0x6e, 0x8e, 0x75, 0xb0, 0x0e, 0x24, 0xbd, 0x77, 0x26, 0x97, - 0xe3, 0x71, 0x90, 0xbd, 0xad, 0x9e, 0x3b, 0x9b, 0x3a, 0xc8, 0x5a, 0x62, 0xbb, 0x27, 0xb2, 0x04, - 0x93, 0x22, 0x09, 0x85, 0xd8, 0xcd, 0x93, 0x6e, 0xf6, 0x40, 0xae, 0x98, 0x7b, 0xa8, 0x27, 0x65, - 0x11, 0x90, 0xb9, 0xb8, 0x1d, 0x49, 0x33, 0x61, 0xee, 0x7c, 0x26, 0x4e, 0xb4, 0xef, 0x2e, 0x4c, - 0x9a, 0xc6, 0x05, 0x91, 0x1d, 0x94, 0x69, 0x73, 0xe4, 0x56, 0xa8, 0x0e, 0xb3, 0x6b, 0x8e, 0x8b, - 0xe7, 0x25, 0x22, 0x48, 0x4f, 0xc6, 0xc1, 0x91, 0x72, 0x97, 0xc0, 0xb8, 0x1a, 0xf5, 0x9a, 0xaa, - 0x13, 0xf2, 0x1e, 0xcf, 0xc0, 0xcf, 0xa6, 0x26, 0xf7, 0xc8, 0x66, 0x8c, 0x22, 0xb1, 0xcc, 0x27, - 0xcf, 0xb3, 0xc2, 0x4e, 0xe7, 0xf2, 0x22, 0xa5, 0xc9, 0x1a, 0x6e, 0xd2, 0x13, 0x12, 0xb5, 0x31, - 0x71, 0x62, 0x71, 0x25, 0x4c, 0x85, 0x12, 0xb9, 0xc9, 0x90, 0xe7, 0x90, 0xe4, 0x28, 0x2e, 0x57, - 0xd8, 0xed, 0x02, 0xf9, 0x1a, 0xbf, 0xea, 0x4c, 0x71, 0x0f, 0xdd, 0x68, 0x5f, 0xec, 0x7e, 0xce, - 0x67, 0x0a, 0x10, 0x1f, 0x4a, 0x17, 0xe9, 0x36, 0x4c, 0x67, 0x05, 0x67, 0x2b, 0x85, 0x76, 0x89, - 0xdc, 0xce, 0x1d, 0x05, 0x36, 0x33, 0x35, 0x9a, 0xf9, 0x9d, 0xd4, 0x25, 0x36, 0x38, 0x57, 0xe6, - 0x87, 0x30, 0xc9, 0x46, 0xc9, 0x03, 0x4a, 0xdb, 0x95, 0x96, 0xfb, 0x84, 0x86, 0x44, 0x66, 0xf8, - 0x56, 0xa0, 0x3c, 0xde, 0xeb, 0x05, 0xf2, 0x1d, 0x18, 0x7b, 0xe8, 0x44, 0x8d, 0x7d, 0x91, 0xe9, - 0x56, 0x26, 0xc2, 0x45, 0xd8, 0x9c, 0xfc, 0x85, 0xc8, 0xdb, 0x05, 0xf2, 0x11, 0x0c, 0xdf, 0xa3, - 0x11, 0xde, 0x3c, 0xbf, 0xa2, 0x62, 0x09, 0xb9, 0x7f, 0x72, 0xc5, 0x53, 0xb7, 0x90, 0x64, 0x85, - 0x93, 0xce, 0x5c, 0x72, 0x0b, 0x80, 0x4f, 0x08, 0x28, 0x21, 0x89, 0x9e, 0x4b, 0x55, 0x9b, 0xdc, - 0x63, 0x9b, 0x87, 0x16, 0x8d, 0xe8, 0x71, 0x8b, 0xcc, 0xd3, 0xd1, 0x2a, 0x4c, 0xaa, 0x37, 0xca, - 0xd6, 0x31, 0x21, 0x91, 0x95, 0x10, 0x16, 0x9e, 0x40, 0xda, 0xfb, 0xec, 0xab, 0xe0, 0x0f, 0x74, - 0x63, 0xe6, 0x1a, 0x9c, 0x49, 0x67, 0xf5, 0xf4, 0x37, 0xfa, 0x14, 0x2a, 0x95, 0xc8, 0xc9, 0x34, - 0xde, 0x65, 0x3f, 0x8c, 0x4c, 0x5e, 0x05, 0xc9, 0xe6, 0xfd, 0x45, 0x98, 0xd3, 0xcb, 0x35, 0x53, - 0xad, 0xc7, 0x73, 0x6e, 0x5e, 0x06, 0xf7, 0xb9, 0x2b, 0x5d, 0x28, 0x84, 0xfd, 0xd6, 0xff, 0xeb, - 0x7d, 0x05, 0x9c, 0x4e, 0x16, 0x61, 0x4a, 0x96, 0xb5, 0xd1, 0xa6, 0x5e, 0xad, 0xb6, 0x8c, 0xef, - 0x51, 0xc9, 0xc8, 0x15, 0x0d, 0x26, 0xa5, 0x93, 0x34, 0x8a, 0x2d, 0x7d, 0x46, 0x86, 0x1a, 0xd2, - 0x2d, 0x6f, 0x4d, 0xbc, 0xf4, 0x65, 0xe6, 0x00, 0x7f, 0xc0, 0x9d, 0x4a, 0xc6, 0xe6, 0x7f, 0x67, - 0x9e, 0x74, 0x31, 0x80, 0xe6, 0x72, 0x4c, 0x88, 0xdb, 0x05, 0xf2, 0x05, 0x90, 0xb4, 0x49, 0xa2, - 0x54, 0x98, 0x6b, 0x7e, 0x29, 0x15, 0x76, 0xb1, 0x67, 0xee, 0xc1, 0x8c, 0xca, 0x4f, 0xa5, 0x95, - 0x3a, 0x4f, 0x72, 0x6a, 0x93, 0x57, 0x4b, 0xf2, 0x09, 0x4c, 0x89, 0x41, 0xab, 0x23, 0x48, 0x51, - 0xcd, 0x3f, 0xc2, 0x2a, 0xc9, 0x1d, 0xa7, 0xf7, 0x61, 0xa6, 0x96, 0xd0, 0x18, 0x0f, 0xe6, 0x3f, - 0x67, 0x8a, 0x40, 0x60, 0x8d, 0x46, 0x5c, 0x65, 0xd9, 0xb2, 0x1e, 0x00, 0xe1, 0x4e, 0x21, 0x29, - 0xee, 0x89, 0x4b, 0x9f, 0x92, 0x8b, 0x89, 0xaa, 0x33, 0x20, 0x92, 0xe1, 0x04, 0x96, 0xdb, 0xb2, - 0x2d, 0xfe, 0xbc, 0x3c, 0x42, 0x8d, 0x73, 0xf4, 0xcb, 0x06, 0x83, 0x71, 0x14, 0x2f, 0x3a, 0xe0, - 0x5c, 0x2e, 0x05, 0xf9, 0x65, 0x4c, 0x0c, 0xdd, 0xdd, 0xac, 0x22, 0xdf, 0xc9, 0xb2, 0x7e, 0x73, - 0x0c, 0xc3, 0xb9, 0x37, 0x8e, 0x47, 0xac, 0x0c, 0xd9, 0x89, 0x7b, 0x34, 0xda, 0x6c, 0x75, 0xf6, - 0x5c, 0x7c, 0x78, 0x98, 0x28, 0xa7, 0x91, 0x02, 0x89, 0x71, 0x29, 0xf3, 0x31, 0xc6, 0x88, 0x1a, - 0xfd, 0x21, 0x59, 0x81, 0x22, 0x9f, 0xff, 0x35, 0x11, 0x17, 0x53, 0x22, 0x04, 0x89, 0x13, 0x38, - 0x07, 0x61, 0x6e, 0x6f, 0xdd, 0xe2, 0xb1, 0x51, 0x44, 0x7e, 0x93, 0xfa, 0x06, 0x73, 0xca, 0x80, - 0xa9, 0xc7, 0x32, 0x58, 0x8f, 0xd8, 0x34, 0xa4, 0x91, 0xcc, 0x40, 0xc5, 0x9f, 0x9d, 0xbe, 0x1a, - 0x2f, 0xf6, 0x69, 0x6c, 0xfc, 0xe9, 0x27, 0xb2, 0x25, 0xee, 0xbc, 0x49, 0xd4, 0x53, 0xdc, 0x19, - 0x42, 0x5f, 0x35, 0xf6, 0x24, 0x27, 0x93, 0xfb, 0x16, 0xae, 0x41, 0x98, 0x75, 0x6b, 0x26, 0xae, - 0x1b, 0xfb, 0x2d, 0xb9, 0x26, 0x34, 0xae, 0x9d, 0x79, 0x9c, 0xd2, 0xd8, 0x22, 0xc9, 0xb6, 0xb0, - 0x9d, 0x20, 0xa0, 0x1e, 0x67, 0xce, 0xdb, 0x6f, 0x64, 0x71, 0x7f, 0x8c, 0x53, 0x8f, 0xc6, 0xcd, - 0xef, 0x1c, 0xf6, 0x12, 0xc1, 0x9f, 0x49, 0xbb, 0x5d, 0x20, 0xef, 0xc2, 0x88, 0xa8, 0x23, 0x63, - 0x32, 0x2a, 0x1d, 0x76, 0xa9, 0x35, 0x72, 0x02, 0x57, 0x12, 0xd6, 0xd9, 0xa4, 0xc9, 0xeb, 0x7d, - 0x5e, 0xe7, 0x77, 0xd9, 0x62, 0xdb, 0x7c, 0x1e, 0xce, 0x05, 0xb9, 0xea, 0x22, 0x67, 0x49, 0x65, - 0x6a, 0x92, 0xa0, 0x1e, 0xcb, 0x23, 0x17, 0xc2, 0xf6, 0xcd, 0x98, 0xee, 0x54, 0x65, 0x2d, 0x54, - 0xfb, 0x66, 0x03, 0xdc, 0x6b, 0xad, 0x5d, 0x81, 0x62, 0xa5, 0x81, 0x2b, 0x41, 0x8d, 0x1e, 0x38, - 0xed, 0x7d, 0x3f, 0xa0, 0xca, 0x68, 0x49, 0x22, 0xa4, 0xac, 0x19, 0xb5, 0xb3, 0x10, 0x88, 0x55, - 0xea, 0x60, 0x4e, 0xf8, 0x59, 0xb5, 0xb5, 0x48, 0xa0, 0xb2, 0x39, 0xba, 0x18, 0x29, 0xd3, 0x0b, - 0xcc, 0xac, 0x6a, 0xbd, 0x98, 0x98, 0xf7, 0x71, 0xc2, 0x50, 0xc4, 0xa1, 0x5a, 0x21, 0x14, 0x48, - 0x99, 0x73, 0xf2, 0xfa, 0x91, 0x22, 0xad, 0xc8, 0x73, 0xe3, 0x58, 0x2d, 0x79, 0xdc, 0x79, 0xc5, - 0x7f, 0x0f, 0x26, 0x97, 0xd8, 0x84, 0xde, 0x69, 0xba, 0xfc, 0x1d, 0x0c, 0x62, 0x3e, 0x6c, 0x90, - 0xcb, 0xb8, 0x2c, 0x5f, 0x26, 0x44, 0x56, 0x61, 0xfa, 0xcb, 0x35, 0x45, 0x83, 0xc9, 0xfe, 0x98, - 0x96, 0x62, 0xc5, 0x53, 0x24, 0x68, 0x9a, 0x0b, 0x5b, 0x7f, 0x96, 0xef, 0x08, 0x2b, 0xed, 0x76, - 0x4b, 0xba, 0xa4, 0xf9, 0xd9, 0xfb, 0x35, 0xc3, 0x84, 0x4c, 0xe1, 0xa5, 0xec, 0xf4, 0xa6, 0xf1, - 0x73, 0xed, 0xa5, 0xf0, 0x1c, 0x99, 0x39, 0xf8, 0x5e, 0x63, 0x51, 0x65, 0xae, 0xaf, 0xb4, 0x5a, - 0x29, 0xe6, 0x90, 0xbc, 0x6e, 0x4a, 0xcf, 0xa2, 0xe9, 0x55, 0x02, 0x9a, 0xe8, 0x7c, 0xd7, 0x55, - 0x69, 0xb7, 0xf9, 0x64, 0x79, 0x49, 0x4d, 0x18, 0x26, 0x22, 0x6d, 0xa2, 0x27, 0xf1, 0x62, 0x6e, - 0xbf, 0x8f, 0xc3, 0x2c, 0x7e, 0x4e, 0x9c, 0xe8, 0x06, 0x6f, 0xf2, 0x35, 0x75, 0xb5, 0x09, 0x4b, - 0x20, 0xd5, 0x3a, 0x71, 0x1a, 0xb7, 0x3e, 0xf1, 0xdb, 0xe4, 0xca, 0x33, 0x93, 0x80, 0x4b, 0x79, - 0x97, 0xf2, 0xd0, 0xca, 0x53, 0x5a, 0x14, 0x83, 0x29, 0xae, 0xe0, 0x25, 0x63, 0x7d, 0x48, 0xd7, - 0xb1, 0x9c, 0x8b, 0x57, 0x4d, 0x2e, 0x26, 0x5f, 0x8b, 0x57, 0x42, 0x73, 0x9e, 0x91, 0xcf, 0xed, - 0x93, 0xbb, 0x30, 0xad, 0xf7, 0xa8, 0x6a, 0x77, 0xde, 0xec, 0x9f, 0x27, 0x67, 0x0b, 0x66, 0x32, - 0x1f, 0x77, 0x57, 0x4b, 0x6c, 0xb7, 0xa7, 0xdf, 0x73, 0xa5, 0x52, 0x38, 0x2b, 0x2c, 0xfb, 0xc4, - 0x73, 0xf6, 0xe4, 0x15, 0xd3, 0xf0, 0xcf, 0x7e, 0xed, 0x7e, 0xee, 0x5a, 0x0f, 0x2a, 0xa1, 0xd0, - 0xaf, 0x71, 0x05, 0x4c, 0x95, 0x71, 0x45, 0x73, 0x05, 0xe4, 0x14, 0x60, 0x75, 0x23, 0x51, 0x63, - 0x60, 0x3a, 0x03, 0x9d, 0xaf, 0xe2, 0xab, 0xf9, 0x32, 0xe3, 0x81, 0xb5, 0x23, 0x13, 0xb4, 0xe7, - 0x6a, 0x26, 0x1b, 0xdd, 0xdb, 0x96, 0x9c, 0x53, 0xe3, 0xe1, 0xf8, 0x55, 0xce, 0x93, 0xd6, 0x54, - 0x6e, 0x1b, 0xe3, 0x91, 0xfe, 0xa4, 0xdb, 0xc6, 0x40, 0xca, 0x1a, 0x5e, 0xed, 0x4a, 0xa3, 0x59, - 0x74, 0xe4, 0x2b, 0xee, 0xc7, 0x31, 0x8b, 0xd0, 0xfd, 0x38, 0x99, 0xf2, 0x2f, 0xe7, 0x13, 0xe8, - 0xc2, 0x1d, 0x7e, 0x68, 0x6b, 0x92, 0x84, 0x44, 0x37, 0x95, 0x12, 0xb8, 0xe4, 0xd8, 0xc8, 0x24, - 0xd1, 0x8b, 0x78, 0x28, 0xbf, 0xc1, 0x1c, 0x2d, 0x65, 0x21, 0x8f, 0xb5, 0x4d, 0xd9, 0x80, 0x52, - 0xdc, 0x99, 0x89, 0x06, 0x9c, 0xb0, 0x2b, 0xa5, 0x32, 0xce, 0xc5, 0xdf, 0x71, 0x52, 0xe2, 0x6b, - 0xa9, 0x2f, 0x3d, 0x47, 0x31, 0x5d, 0x8b, 0xe0, 0xf3, 0xb9, 0x96, 0xf0, 0xfd, 0x7c, 0xec, 0xc4, - 0x8d, 0xa1, 0x19, 0xf3, 0xb9, 0x8e, 0x54, 0xc6, 0xea, 0xa4, 0x81, 0xc8, 0x6f, 0xf5, 0xc5, 0x2c, - 0x39, 0x61, 0x7a, 0xc6, 0xd5, 0xea, 0x25, 0xf7, 0x69, 0x49, 0xc4, 0x49, 0x66, 0xdc, 0xe3, 0x54, - 0x2d, 0x4f, 0xce, 0x22, 0x8c, 0xf1, 0xda, 0xf2, 0x85, 0xf4, 0x9c, 0xa1, 0x26, 0x63, 0x0d, 0x9d, - 0x33, 0x1a, 0x67, 0x2e, 0x9f, 0x0b, 0xe8, 0x4a, 0x96, 0xe0, 0xfc, 0x5a, 0x9c, 0x4f, 0xcb, 0x30, - 0xdc, 0xc8, 0x4a, 0x0b, 0xbc, 0x36, 0x17, 0x92, 0xca, 0x31, 0x2a, 0x94, 0xdf, 0x24, 0xa2, 0xab, - 0xa6, 0x47, 0x95, 0xf2, 0xf7, 0xaf, 0x53, 0xe2, 0x89, 0x68, 0x7c, 0xa5, 0x49, 0xe6, 0x63, 0x3c, - 0xab, 0x7c, 0x62, 0x1a, 0x14, 0x1d, 0x14, 0xd9, 0x62, 0x36, 0xf1, 0xfa, 0x08, 0x0d, 0xa2, 0x54, - 0xbe, 0xc5, 0x57, 0x8c, 0xcd, 0x5b, 0x12, 0x9d, 0xbf, 0x77, 0x53, 0x73, 0x76, 0xae, 0xc4, 0x6c, - 0x74, 0x2f, 0xb5, 0x7d, 0x5f, 0x9b, 0xb3, 0x93, 0xbc, 0x21, 0xb9, 0x9e, 0xdc, 0xb8, 0xa5, 0x48, - 0x7a, 0xaf, 0x09, 0x22, 0x84, 0x24, 0x11, 0x40, 0x6a, 0x19, 0x7a, 0x30, 0x91, 0xf9, 0x5a, 0xb0, - 0xe5, 0xf8, 0xcf, 0x91, 0x96, 0x85, 0xec, 0x55, 0xc3, 0x2f, 0xb5, 0x89, 0xce, 0xe4, 0x0c, 0x95, - 0x39, 0x9e, 0x47, 0xd0, 0x4b, 0xf6, 0x3a, 0x5e, 0x69, 0x4a, 0x34, 0xd0, 0x6d, 0x50, 0xb5, 0xb3, - 0xc9, 0xc4, 0xe6, 0xb7, 0xff, 0x9e, 0xdc, 0x29, 0x25, 0xe5, 0x9d, 0x4d, 0x38, 0x6d, 0x7b, 0x55, - 0xec, 0x6b, 0x39, 0x19, 0x27, 0xda, 0x84, 0x97, 0x8a, 0x5e, 0xeb, 0xd6, 0x6a, 0xed, 0x31, 0xce, - 0x2e, 0x66, 0xd0, 0xe9, 0x9a, 0xbb, 0xe7, 0xa9, 0x9b, 0x08, 0x35, 0x5b, 0x19, 0x41, 0x1a, 0x2c, - 0x39, 0xc5, 0x18, 0x28, 0x95, 0x9f, 0x67, 0x5a, 0xee, 0xde, 0x15, 0x9a, 0x06, 0x11, 0x49, 0xf1, - 0x68, 0xee, 0xd6, 0xf3, 0x99, 0xb8, 0xb4, 0x40, 0xfd, 0x81, 0x7e, 0x25, 0xd0, 0x7c, 0xb5, 0xdf, - 0x14, 0x98, 0xf9, 0xa2, 0xff, 0x2d, 0xf4, 0xba, 0xd8, 0x7e, 0x8b, 0xea, 0x5e, 0x17, 0xed, 0xc5, - 0xf7, 0x84, 0xd3, 0x83, 0x7c, 0x0c, 0xa3, 0xea, 0x45, 0x7c, 0xe5, 0xdf, 0x4e, 0x3e, 0xca, 0x3f, - 0x57, 0x4a, 0x23, 0x44, 0x81, 0x6f, 0x4b, 0xc7, 0x07, 0x96, 0x59, 0x32, 0x1d, 0x46, 0xf9, 0xc5, - 0xbe, 0x2d, 0xbd, 0x1e, 0x06, 0x5b, 0xea, 0x3d, 0xfc, 0x24, 0xdb, 0xf7, 0x60, 0x3c, 0x7e, 0xfb, - 0x7e, 0x67, 0x5e, 0x63, 0x4c, 0x3c, 0x88, 0x9f, 0x64, 0x7c, 0x57, 0x1e, 0x69, 0x60, 0x79, 0x26, - 0xb2, 0xfb, 0x2a, 0xfe, 0xb1, 0xf4, 0xb2, 0x18, 0x35, 0x4d, 0xbd, 0xa4, 0xdf, 0x65, 0xf2, 0x1d, - 0xd7, 0x1f, 0xa3, 0x55, 0x5d, 0x9b, 0xf1, 0x9c, 0xb4, 0xea, 0xda, 0xac, 0xe7, 0xa0, 0x63, 0x97, - 0xff, 0x17, 0xd2, 0xa5, 0x10, 0x0b, 0xbd, 0x68, 0x54, 0x2b, 0x25, 0xf7, 0x52, 0x1e, 0x3a, 0x29, - 0xba, 0x06, 0xc5, 0xe4, 0xcb, 0xb9, 0xca, 0x1e, 0xcb, 0x79, 0xe2, 0x58, 0x19, 0x79, 0xb9, 0x4f, - 0xee, 0x6e, 0x4a, 0xff, 0xb8, 0x29, 0xf7, 0x4a, 0x76, 0xa5, 0x74, 0xd1, 0xf9, 0x0e, 0xf3, 0x09, - 0xe3, 0x11, 0x5d, 0xdd, 0x52, 0x4e, 0x3d, 0xd2, 0xab, 0xef, 0xac, 0x32, 0xde, 0xdd, 0x75, 0x65, - 0xd2, 0xaa, 0xcc, 0x23, 0x5b, 0xe5, 0x2c, 0xe8, 0xfd, 0xe2, 0x42, 0xcf, 0xe3, 0x5f, 0xf2, 0x0b, - 0x30, 0x9b, 0x93, 0x41, 0x9e, 0x5c, 0x4b, 0x78, 0x5a, 0xb3, 0x33, 0xcc, 0xab, 0x01, 0x92, 0xf9, - 0xba, 0xfd, 0x1a, 0xc6, 0x0d, 0x18, 0x29, 0x24, 0x52, 0x67, 0x71, 0x0f, 0xdd, 0x68, 0x9f, 0x3f, - 0xe2, 0xae, 0x4d, 0x9b, 0x99, 0xb9, 0x27, 0x48, 0x0d, 0x6d, 0x11, 0x03, 0x9a, 0x71, 0x1c, 0x97, - 0x21, 0x70, 0x2e, 0x5b, 0x20, 0x9b, 0x3b, 0xd8, 0x58, 0xc8, 0xc8, 0xef, 0xa1, 0xc6, 0x42, 0x7e, - 0xee, 0x8f, 0xdc, 0x6a, 0x6e, 0xca, 0x3d, 0x52, 0xb6, 0xc4, 0xfc, 0x54, 0x1f, 0xb9, 0x12, 0xef, - 0x33, 0x89, 0xa9, 0xec, 0x1d, 0x24, 0x87, 0xbc, 0xfb, 0xec, 0x61, 0xcb, 0x25, 0xd7, 0xe4, 0x9a, - 0xd7, 0xea, 0x97, 0x97, 0x27, 0x24, 0xb7, 0x7e, 0x4b, 0xf2, 0x7b, 0xca, 0xae, 0xdf, 0x71, 0x17, - 0x5d, 0x75, 0xfe, 0x95, 0x48, 0x20, 0x63, 0x34, 0x54, 0x83, 0xcf, 0xe5, 0xc0, 0xc9, 0x3a, 0x06, - 0x02, 0x25, 0xa1, 0x9a, 0x51, 0x9a, 0x9d, 0xa1, 0x26, 0x57, 0x1e, 0x1f, 0xc7, 0x46, 0x86, 0x8f, - 0x93, 0x8c, 0xe3, 0x44, 0x6a, 0x10, 0x31, 0x8e, 0x0d, 0xe8, 0xc9, 0xc6, 0x71, 0x42, 0xa0, 0x39, - 0x8e, 0x93, 0xd5, 0x4c, 0x5a, 0xfa, 0xb9, 0xbd, 0x9a, 0xac, 0xa6, 0x1a, 0xc7, 0xd9, 0x12, 0xf3, - 0x33, 0xb1, 0xe4, 0x4a, 0x54, 0xe3, 0xd8, 0x94, 0x98, 0x43, 0x7e, 0xcc, 0x71, 0x9c, 0x2c, 0xc4, - 0x1c, 0xc7, 0x27, 0xaa, 0x9f, 0x1a, 0xc7, 0xd9, 0xf5, 0x3b, 0xf1, 0x38, 0x4e, 0xa4, 0x2e, 0x32, - 0x1a, 0x9a, 0x35, 0x8e, 0x93, 0xf4, 0x7c, 0x1c, 0x27, 0xa1, 0x09, 0xe7, 0x4a, 0x97, 0x71, 0x9c, - 0xe4, 0xfc, 0x0c, 0xe5, 0x25, 0xd2, 0xae, 0x1c, 0x67, 0x24, 0xe7, 0x66, 0x6c, 0x21, 0x0f, 0xd1, - 0xbd, 0x97, 0x80, 0x1f, 0x6f, 0x34, 0x5f, 0xc8, 0x13, 0x8a, 0xe3, 0x79, 0x47, 0x2a, 0x31, 0x59, - 0x5d, 0xd3, 0x77, 0x95, 0x9d, 0x75, 0xa6, 0x4b, 0x85, 0x77, 0xd8, 0xb8, 0x69, 0x76, 0x91, 0xdb, - 0x2d, 0x69, 0x4e, 0x17, 0xb9, 0xca, 0x94, 0x49, 0xca, 0xcd, 0x65, 0xe9, 0x3e, 0xbe, 0x3f, 0x97, - 0x07, 0x1c, 0x49, 0xbe, 0xf9, 0x84, 0x71, 0x74, 0xe2, 0x9a, 0x2a, 0x23, 0x29, 0x59, 0xd3, 0x93, - 0x8e, 0xf3, 0x35, 0xb9, 0x7b, 0x48, 0x65, 0xdb, 0x4a, 0x34, 0x5a, 0x1f, 0xeb, 0xb9, 0x18, 0xb2, - 0x85, 0xbe, 0xdc, 0x34, 0x5c, 0xf3, 0x03, 0xe7, 0xa5, 0xf5, 0xea, 0x29, 0x35, 0x95, 0x37, 0x48, - 0x97, 0x9a, 0x97, 0x54, 0x48, 0x49, 0x4d, 0x73, 0x7f, 0x82, 0xde, 0x2f, 0x71, 0xe3, 0xca, 0x7b, - 0xe4, 0xe7, 0x7b, 0x52, 0xa6, 0x8c, 0x60, 0x25, 0x46, 0x8b, 0x31, 0x62, 0x1f, 0x8a, 0x13, 0x3c, - 0x09, 0xcc, 0x55, 0x7e, 0x16, 0x3f, 0xf9, 0x04, 0x8a, 0x62, 0x7a, 0x8b, 0x05, 0x64, 0x11, 0xe6, - 0x76, 0x5d, 0x55, 0x3a, 0xdd, 0x8e, 0x51, 0x83, 0xe3, 0x38, 0xdb, 0x8e, 0xa3, 0x89, 0x7c, 0xcf, - 0x14, 0x5b, 0x0e, 0xb7, 0x82, 0x4e, 0x18, 0xd1, 0x66, 0xda, 0xa3, 0x64, 0x56, 0x46, 0x46, 0x46, - 0x98, 0xe4, 0x3b, 0xf3, 0x64, 0x05, 0xe7, 0x36, 0x13, 0xdc, 0xcd, 0xe5, 0x96, 0x2d, 0x06, 0xa7, - 0x9e, 0x65, 0x75, 0xad, 0xc7, 0xac, 0x53, 0x5e, 0xd9, 0xf9, 0x95, 0x52, 0x2a, 0x3a, 0x66, 0xeb, - 0xf2, 0x54, 0xf4, 0x01, 0x86, 0x01, 0x70, 0xf7, 0x5f, 0x2f, 0xcd, 0x24, 0x2f, 0x1a, 0x91, 0x4f, - 0x61, 0x54, 0x32, 0xf7, 0x56, 0x48, 0x92, 0x1b, 0x15, 0xb2, 0x08, 0x13, 0xc6, 0x2d, 0x2a, 0x65, - 0xdd, 0x64, 0xdd, 0xad, 0xea, 0xd2, 0xcf, 0x13, 0xc6, 0x6d, 0x29, 0x25, 0x25, 0xeb, 0x0e, 0x55, - 0xae, 0x94, 0x8f, 0x60, 0x4c, 0xa8, 0xb4, 0xab, 0x36, 0xf2, 0xfd, 0x6d, 0x33, 0x5a, 0x44, 0x72, - 0xa7, 0xe9, 0x46, 0x0b, 0xbe, 0xf7, 0xc8, 0xdd, 0xeb, 0xa9, 0x98, 0x34, 0xcb, 0xce, 0x3c, 0xf9, - 0x0a, 0x9f, 0x3c, 0x97, 0x0f, 0xd1, 0xd3, 0xe8, 0xa9, 0x1f, 0x3c, 0x76, 0xbd, 0xbd, 0x1e, 0x22, - 0x2f, 0x9b, 0x22, 0x93, 0x7c, 0x32, 0x76, 0xe4, 0x2b, 0x98, 0xab, 0xe5, 0x0b, 0xef, 0x29, 0xa4, - 0xfb, 0xf2, 0x52, 0x83, 0x0b, 0x18, 0x3d, 0x73, 0xd2, 0xba, 0x77, 0x15, 0xfa, 0x05, 0x4f, 0xd8, - 0x28, 0x7d, 0xf5, 0x0d, 0x3f, 0x68, 0xf6, 0x96, 0x58, 0x36, 0x03, 0x69, 0x13, 0x6c, 0x52, 0x19, - 0x5f, 0xc0, 0xb9, 0x5a, 0xae, 0xe8, 0x5e, 0x22, 0x7a, 0xed, 0x24, 0xcf, 0xa3, 0x2a, 0x4e, 0x58, - 0xef, 0xae, 0x32, 0x57, 0x70, 0x4e, 0x63, 0xeb, 0xd0, 0x66, 0x40, 0x1f, 0xd1, 0x00, 0xc3, 0xb5, - 0x7b, 0x05, 0x2a, 0x9b, 0xe4, 0xb2, 0xe5, 0x2b, 0x70, 0xa6, 0x96, 0x12, 0x95, 0xc7, 0xd2, 0xeb, - 0xfc, 0x67, 0x0a, 0x5b, 0x7a, 0xcc, 0x7a, 0xf5, 0x88, 0x12, 0x1a, 0xbb, 0x47, 0xa3, 0xed, 0x95, - 0x1e, 0x5a, 0x92, 0xf7, 0x09, 0x24, 0xe1, 0xce, 0x1d, 0xc6, 0x59, 0xd3, 0x38, 0xd3, 0x14, 0xb9, - 0x1f, 0xef, 0xa7, 0xf2, 0x2c, 0xa4, 0x67, 0xb1, 0x79, 0x12, 0xde, 0xc4, 0xb9, 0x50, 0x84, 0x2c, - 0xcf, 0xc6, 0x5b, 0x00, 0x0e, 0x89, 0x5d, 0x75, 0x5a, 0xf4, 0x72, 0x48, 0x2a, 0xdc, 0xfc, 0xe3, - 0xc3, 0x43, 0xc0, 0x2e, 0xa5, 0x42, 0xd9, 0xbb, 0x8a, 0xe0, 0x5e, 0xd0, 0x55, 0xbf, 0xf1, 0x58, - 0xf7, 0x82, 0xb2, 0xdf, 0x49, 0xf7, 0x20, 0x83, 0xed, 0xcc, 0x8b, 0x19, 0x9f, 0xfd, 0x30, 0x02, - 0xbf, 0x10, 0x10, 0xcf, 0xf8, 0x49, 0xb8, 0xf0, 0x20, 0xbd, 0x29, 0x7d, 0x8b, 0x58, 0xa0, 0x29, - 0x39, 0x57, 0x35, 0xca, 0xad, 0x88, 0x4c, 0xa6, 0x5b, 0x51, 0xaf, 0x68, 0xbe, 0x2f, 0x9f, 0xd8, - 0xb4, 0xdd, 0xc2, 0x28, 0xe8, 0x03, 0x9f, 0xf3, 0xc4, 0x81, 0xb1, 0x69, 0x54, 0xef, 0xf8, 0xad, - 0x29, 0x11, 0xf5, 0x63, 0x28, 0x5e, 0x25, 0x54, 0x4e, 0xe3, 0x62, 0x55, 0xea, 0xc1, 0x48, 0xb7, - 0x0b, 0x64, 0x1d, 0xce, 0xde, 0xa3, 0x91, 0x98, 0xe3, 0x6c, 0x1a, 0x46, 0x81, 0xdb, 0x88, 0xba, - 0x1e, 0x0c, 0x4a, 0xdb, 0x24, 0x83, 0x67, 0xe7, 0x2d, 0x26, 0xaf, 0x96, 0x2d, 0xaf, 0x2b, 0x5f, - 0x97, 0x10, 0x59, 0x71, 0xda, 0x70, 0x92, 0x2a, 0xe6, 0x0f, 0xf1, 0x61, 0x1e, 0x81, 0x93, 0xcf, - 0x5a, 0x8c, 0xb3, 0x9f, 0x08, 0x6b, 0xeb, 0x26, 0x0c, 0x71, 0xa6, 0xdc, 0x05, 0x75, 0x5c, 0xe7, - 0x21, 0x77, 0x60, 0x54, 0x85, 0xd0, 0x10, 0x03, 0x95, 0x5b, 0xaf, 0x3b, 0x30, 0xca, 0x4d, 0xab, - 0xe3, 0xb3, 0x7c, 0x00, 0xa3, 0x2a, 0xe6, 0xe6, 0xc4, 0x2b, 0xfd, 0x27, 0x30, 0xa1, 0x47, 0xdf, - 0x9c, 0x5c, 0x91, 0x1f, 0xe1, 0xf1, 0xad, 0x3c, 0x25, 0xc9, 0xe7, 0x9f, 0x49, 0x24, 0x85, 0x11, - 0x2a, 0xe5, 0x13, 0xa4, 0x04, 0xe6, 0x56, 0xff, 0x4c, 0x8a, 0x9b, 0x7c, 0x20, 0x6f, 0x32, 0x29, - 0xe6, 0x34, 0x51, 0x17, 0x9d, 0x4d, 0x72, 0x35, 0x3f, 0x0f, 0xb3, 0x9a, 0x60, 0x7b, 0x56, 0xfb, - 0x38, 0xc7, 0xcc, 0xbd, 0x55, 0x97, 0x27, 0x65, 0x03, 0x77, 0x69, 0xa9, 0x47, 0x02, 0xf3, 0x05, - 0x5d, 0xca, 0x7f, 0x57, 0x10, 0x3b, 0xe3, 0x3e, 0x5a, 0x81, 0x29, 0x6c, 0x6e, 0xf3, 0xba, 0xbc, - 0x53, 0x18, 0x9b, 0xbd, 0x69, 0x71, 0x5d, 0xd8, 0xba, 0x59, 0xd1, 0xe2, 0x7e, 0xe6, 0x4b, 0x11, - 0xb7, 0x22, 0x83, 0x18, 0x8f, 0xdf, 0xd8, 0xfc, 0x9a, 0x9d, 0xcf, 0x38, 0xd8, 0xee, 0xd9, 0x17, - 0x79, 0xe2, 0x7e, 0x01, 0x77, 0x87, 0x99, 0x59, 0xc1, 0xf2, 0x85, 0x5d, 0xd7, 0x62, 0x23, 0x32, - 0x39, 0xd5, 0xa2, 0xf7, 0x18, 0xaf, 0x88, 0x65, 0x3f, 0xa3, 0xf8, 0x6a, 0x0f, 0x29, 0x52, 0x13, - 0xaf, 0xf5, 0xa4, 0x53, 0xc7, 0xa4, 0xe7, 0xf9, 0x0a, 0x9b, 0x5d, 0x5e, 0x8f, 0x67, 0x21, 0x33, - 0x4e, 0xae, 0x55, 0x84, 0x68, 0xb6, 0x40, 0x33, 0x42, 0xb4, 0x6b, 0x1b, 0xf2, 0xd4, 0xff, 0x19, - 0x94, 0xe3, 0x00, 0x90, 0x93, 0x75, 0x42, 0x7e, 0x60, 0x22, 0x49, 0x69, 0x2a, 0x24, 0xdd, 0x9e, - 0x13, 0x9a, 0xbb, 0x92, 0xa7, 0x61, 0xfd, 0x1a, 0x8c, 0x08, 0x6c, 0x4b, 0x3c, 0x28, 0x9a, 0xf7, - 0x34, 0x69, 0x17, 0x3f, 0xac, 0xb8, 0x33, 0xf7, 0x52, 0x04, 0xa5, 0x7b, 0xfb, 0xe4, 0x82, 0x54, - 0x7c, 0x46, 0x42, 0x90, 0xd5, 0xa5, 0x7b, 0x7b, 0x1f, 0x3d, 0x96, 0x72, 0xfa, 0xf5, 0xe4, 0x1d, - 0xea, 0xc4, 0xf7, 0xc4, 0x12, 0x49, 0x04, 0xf5, 0xbb, 0xb9, 0x69, 0x54, 0xf2, 0x92, 0x53, 0x16, - 0x85, 0x0a, 0x8a, 0x2a, 0xc9, 0x22, 0x18, 0x9c, 0x99, 0x22, 0x7e, 0xe0, 0x46, 0xcf, 0x16, 0xec, - 0xd5, 0xd8, 0xad, 0xa0, 0x23, 0xa4, 0x6c, 0x90, 0x48, 0x7b, 0x95, 0x7c, 0x89, 0x53, 0x89, 0x10, - 0x5f, 0xf5, 0xfd, 0x28, 0x8c, 0x02, 0xa7, 0x5d, 0xc3, 0x87, 0x96, 0x73, 0x1b, 0x1d, 0xc7, 0x70, - 0x67, 0xb1, 0x69, 0x21, 0xa5, 0x22, 0x8f, 0x7d, 0x56, 0xe6, 0x1b, 0x75, 0xad, 0x26, 0x0b, 0xd9, - 0xc5, 0x72, 0xa9, 0xc9, 0xcc, 0xf5, 0x2f, 0x53, 0x68, 0x1d, 0x66, 0x73, 0xf2, 0x05, 0xa9, 0xd3, - 0xdb, 0xee, 0xf9, 0x84, 0xe6, 0xba, 0x17, 0x4c, 0xbe, 0x82, 0x99, 0xcc, 0x84, 0x42, 0xca, 0x03, - 0xdd, 0x2d, 0xdd, 0x50, 0x2f, 0xe1, 0x8f, 0xa1, 0xc4, 0x2f, 0x74, 0x60, 0xdc, 0xb2, 0x91, 0x5b, - 0x26, 0xbe, 0xe6, 0x93, 0x43, 0x90, 0x9c, 0xaf, 0xf3, 0xe9, 0xd4, 0x65, 0xf3, 0x69, 0x4c, 0x2a, - 0x22, 0x5f, 0x86, 0x16, 0xcf, 0xfb, 0xab, 0x0f, 0x2f, 0x0b, 0xd9, 0xed, 0x2e, 0xd1, 0x26, 0xcc, - 0xec, 0xd0, 0xc0, 0x7d, 0xf4, 0x2c, 0x29, 0x50, 0x6a, 0x26, 0x13, 0xdb, 0x4d, 0xe2, 0xe7, 0x30, - 0xbb, 0xe0, 0x1f, 0xb4, 0xc5, 0xad, 0x3d, 0x43, 0xa6, 0x3a, 0x8a, 0xcf, 0xc6, 0xf7, 0x8e, 0x65, - 0x9a, 0x53, 0xd7, 0x0a, 0x75, 0xbe, 0x05, 0xbc, 0xce, 0x7a, 0xdd, 0x0c, 0x27, 0xc8, 0x20, 0x89, - 0x2f, 0x63, 0x48, 0x53, 0x4e, 0xe7, 0xdf, 0xc2, 0x41, 0x98, 0xe0, 0xe3, 0xbe, 0x39, 0x6d, 0x10, - 0x66, 0xe1, 0xbb, 0xdf, 0x01, 0xcb, 0x90, 0xca, 0x0b, 0xcc, 0x97, 0x7a, 0x8c, 0xda, 0xae, 0xcb, - 0xb5, 0xc5, 0x7c, 0xc9, 0x3f, 0x11, 0x34, 0x9d, 0xf9, 0xcc, 0x7f, 0x66, 0x3d, 0xb5, 0xac, 0x0a, - 0xad, 0x56, 0x97, 0x2d, 0x16, 0xd1, 0xd3, 0x2a, 0x30, 0x4a, 0x74, 0xe2, 0x4f, 0xe8, 0xbc, 0xdd, - 0x66, 0xeb, 0x14, 0x33, 0x6e, 0x6a, 0xdf, 0x87, 0xf1, 0x9a, 0x5e, 0x78, 0x46, 0x21, 0xb9, 0x83, - 0x42, 0xdd, 0x02, 0xea, 0x5d, 0xf7, 0x2e, 0xb1, 0xa0, 0x6a, 0xe1, 0x39, 0x56, 0x2b, 0x72, 0x43, - 0x67, 0x8c, 0xb7, 0xe7, 0xd4, 0x2a, 0x90, 0xf5, 0x34, 0xa4, 0x0a, 0x9d, 0xc9, 0x7e, 0xae, 0xae, - 0xce, 0x5f, 0xb4, 0x49, 0xbe, 0xfc, 0x49, 0xac, 0xde, 0x4f, 0xec, 0xaa, 0x98, 0xf8, 0xae, 0x4f, - 0x87, 0xf2, 0x38, 0x9f, 0xf8, 0xb5, 0x3d, 0x3d, 0xce, 0x27, 0xf5, 0x86, 0x9f, 0x1e, 0xe7, 0x93, - 0xf1, 0x40, 0xdf, 0x12, 0xca, 0x8a, 0x9f, 0x02, 0xea, 0xe2, 0x8c, 0x50, 0x62, 0x32, 0x5e, 0x1c, - 0x7a, 0xa0, 0x27, 0xe7, 0xe0, 0x0f, 0x08, 0x75, 0xf1, 0xb5, 0x26, 0x93, 0x72, 0x24, 0x5e, 0x1c, - 0xba, 0x0b, 0x45, 0xfe, 0x96, 0x42, 0x9c, 0xd3, 0x30, 0x0e, 0xfd, 0x4b, 0x3f, 0xf1, 0xd0, 0xa5, - 0x53, 0x8b, 0xc9, 0x4c, 0x70, 0xca, 0x65, 0x96, 0x93, 0x22, 0xae, 0xcb, 0x50, 0x85, 0x38, 0xdf, - 0x9b, 0x72, 0x4c, 0xa5, 0x52, 0xc0, 0xcd, 0x9d, 0xcb, 0xc0, 0xa8, 0x2d, 0xe5, 0xb8, 0x9e, 0x1d, - 0x4e, 0x35, 0x29, 0x23, 0x65, 0xdc, 0xdc, 0xf9, 0x4c, 0x9c, 0x10, 0x14, 0xf1, 0x57, 0xa6, 0xb3, - 0x1f, 0xfd, 0x8e, 0x2f, 0x72, 0x75, 0xa1, 0x91, 0xc5, 0xdc, 0x38, 0x0e, 0xa9, 0x28, 0x95, 0xaa, - 0x87, 0x90, 0x32, 0x5e, 0x1a, 0x7f, 0x2d, 0xe3, 0xae, 0x85, 0x41, 0x11, 0x47, 0x83, 0x75, 0x7f, - 0xf6, 0x9c, 0x3c, 0x94, 0x0f, 0xd3, 0xe4, 0x94, 0xd4, 0x4b, 0x40, 0x6e, 0x0f, 0x3e, 0x94, 0x4f, - 0xd1, 0xbc, 0x6c, 0xc1, 0xbb, 0x70, 0x21, 0x71, 0x81, 0xc3, 0x14, 0x7c, 0x23, 0xfb, 0x96, 0x47, - 0xa6, 0x7a, 0xf2, 0xf7, 0xec, 0x97, 0xd3, 0x17, 0x3d, 0x12, 0xfd, 0x7e, 0xd2, 0x39, 0x6f, 0x0d, - 0x26, 0x71, 0x9a, 0x91, 0x6f, 0xe6, 0xc7, 0xb9, 0x61, 0x4c, 0x70, 0x32, 0x49, 0x51, 0x12, 0xab, - 0xee, 0x8f, 0x8f, 0x8b, 0x4b, 0xc1, 0xfc, 0x05, 0xfe, 0x39, 0xf3, 0xa6, 0x30, 0x02, 0xb3, 0x56, - 0x31, 0xf1, 0xb0, 0x3f, 0xf9, 0x08, 0x4e, 0xc7, 0x77, 0x85, 0xb9, 0x88, 0x0c, 0xb2, 0x2e, 0x8e, - 0xb2, 0xd3, 0xf1, 0x85, 0xe1, 0x93, 0xb3, 0x2f, 0xcb, 0xa5, 0x28, 0x66, 0xbf, 0x98, 0xba, 0xee, - 0x62, 0xb4, 0xe1, 0x38, 0x2b, 0x92, 0xa6, 0xdb, 0x93, 0xf6, 0x4e, 0x03, 0x3f, 0xb7, 0xec, 0xb4, - 0x87, 0xfa, 0xe7, 0xd6, 0x35, 0x35, 0xa3, 0xda, 0xfe, 0xe6, 0xc8, 0x59, 0x83, 0xab, 0x98, 0x2a, - 0x65, 0x93, 0x27, 0xc7, 0xcb, 0xa6, 0xca, 0xaf, 0x7b, 0x32, 0xc1, 0x4a, 0x0b, 0xae, 0xf4, 0xcc, - 0xfb, 0x48, 0x6e, 0x19, 0x21, 0x2e, 0xbd, 0x33, 0x44, 0x76, 0xb1, 0x3c, 0xa6, 0xb3, 0xd2, 0x27, - 0xaa, 0x75, 0xb6, 0x4b, 0x26, 0x47, 0xb5, 0xce, 0x76, 0xcd, 0xbf, 0xf8, 0x39, 0xbe, 0xf6, 0x24, - 0xd6, 0x28, 0x4c, 0x7f, 0x44, 0x3d, 0x9e, 0x14, 0xba, 0xeb, 0xb1, 0xcf, 0x15, 0xf3, 0x50, 0x34, - 0xc5, 0x88, 0x36, 0xcd, 0x25, 0x61, 0x89, 0xe5, 0x09, 0xef, 0x2d, 0xa4, 0x4b, 0x68, 0xf5, 0x25, - 0x3e, 0x00, 0x4f, 0x5c, 0xf3, 0x1c, 0x78, 0x75, 0xf1, 0x27, 0xff, 0xf5, 0x52, 0xe1, 0x27, 0x3f, - 0xbd, 0x54, 0xf8, 0x8f, 0x3f, 0xbd, 0x54, 0xf8, 0x2f, 0x3f, 0xbd, 0x54, 0xf8, 0x72, 0xfe, 0x78, - 0xa9, 0x89, 0xf9, 0xfb, 0x8c, 0xb7, 0xb8, 0xb8, 0x21, 0xfc, 0xef, 0xcd, 0xff, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0x6f, 0x43, 0x95, 0x44, 0x34, 0xef, 0x00, 0x00, + // 15544 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x5b, 0x6c, 0x5c, 0x49, + 0x7a, 0x18, 0xac, 0x6e, 0xde, 0x3f, 0xde, 0x5a, 0x45, 0x52, 0x6c, 0x51, 0x97, 0x96, 0x8e, 0x46, + 0x33, 0x1a, 0xed, 0xac, 0x2e, 0x9c, 0xcb, 0xce, 0x7d, 0xa6, 0x9b, 0xa4, 0x48, 0x4a, 0xbc, 0xcd, + 0x69, 0x92, 0x9a, 0x9b, 0xb7, 0xf7, 0xb0, 0xbb, 0x44, 0x1e, 0xab, 0xd9, 0xa7, 0xf7, 0x9c, 0xd3, + 0xd2, 0x68, 0xfd, 0xaf, 0x7f, 0xd8, 0xfe, 0xff, 0xc4, 0x41, 0x90, 0xc4, 0x06, 0xe2, 0xc0, 0x86, + 0x03, 0x38, 0x01, 0x1c, 0x20, 0x08, 0x10, 0xc0, 0x2f, 0x81, 0x9f, 0xfc, 0x90, 0xa7, 0x6c, 0x0c, + 0x04, 0x89, 0x61, 0xfb, 0x25, 0x40, 0xe8, 0x64, 0x01, 0xbf, 0x10, 0xc9, 0x83, 0x11, 0x24, 0x40, + 0x36, 0x30, 0x10, 0xd4, 0x57, 0x97, 0x53, 0x75, 0x2e, 0xdd, 0xa4, 0xa4, 0x59, 0xe7, 0x45, 0x62, + 0x7f, 0xb7, 0xaa, 0xfa, 0xaa, 0x4e, 0x55, 0x7d, 0x5f, 0x7d, 0xf5, 0x15, 0xdc, 0x0a, 0x69, 0x93, + 0xb6, 0x3d, 0x3f, 0xbc, 0xdd, 0xa4, 0xfb, 0x4e, 0xfd, 0xd9, 0xed, 0x7a, 0xd3, 0xa5, 0xad, 0xf0, + 0x76, 0xdb, 0xf7, 0x42, 0xef, 0xb6, 0xd3, 0x09, 0x0f, 0x02, 0xea, 0x3f, 0x71, 0xeb, 0xf4, 0x16, + 0x42, 0xc8, 0x00, 0xfe, 0x37, 0x37, 0xbd, 0xef, 0xed, 0x7b, 0x9c, 0x86, 0xfd, 0xc5, 0x91, 0x73, + 0x17, 0xf6, 0x3d, 0x6f, 0xbf, 0x49, 0x39, 0xf3, 0x5e, 0xe7, 0xd1, 0x6d, 0x7a, 0xd8, 0x0e, 0x9f, + 0x09, 0x64, 0x29, 0x8e, 0x0c, 0xdd, 0x43, 0x1a, 0x84, 0xce, 0x61, 0x5b, 0x10, 0xbc, 0xae, 0xaa, + 0xe2, 0x84, 0x21, 0xc3, 0x84, 0xae, 0xd7, 0xba, 0xfd, 0xe4, 0xae, 0xfe, 0x53, 0x90, 0xde, 0xe8, + 0x5a, 0xeb, 0x3a, 0xf5, 0xc3, 0xe0, 0x44, 0x94, 0xf4, 0x09, 0x6d, 0x85, 0x89, 0xe2, 0x05, 0x65, + 0xf8, 0xac, 0x4d, 0x03, 0x4e, 0x22, 0xff, 0x13, 0xa4, 0x57, 0xd3, 0x49, 0xf1, 0x5f, 0x41, 0xf2, + 0xdd, 0x74, 0x92, 0xa7, 0x74, 0x8f, 0xe9, 0xb4, 0xa5, 0xfe, 0xe8, 0x41, 0xee, 0x3b, 0xed, 0x36, + 0xf5, 0xa3, 0x3f, 0x04, 0xf9, 0x79, 0x45, 0x7e, 0xf8, 0xc8, 0x61, 0x2a, 0x3a, 0x7c, 0xe4, 0x24, + 0x9a, 0xd1, 0x09, 0x9c, 0x7d, 0x2a, 0xaa, 0xff, 0xe4, 0xae, 0xfe, 0x93, 0x93, 0x5a, 0xbf, 0x97, + 0x83, 0x81, 0x87, 0x4e, 0x58, 0x3f, 0x20, 0x9f, 0xc0, 0xc0, 0x03, 0xb7, 0xd5, 0x08, 0x8a, 0xb9, + 0x2b, 0x7d, 0x37, 0x46, 0xe7, 0x0b, 0xb7, 0x78, 0x53, 0x10, 0xc9, 0x10, 0x95, 0xd9, 0x9f, 0x1c, + 0x95, 0xce, 0x1c, 0x1f, 0x95, 0x26, 0x1f, 0x33, 0xb2, 0x37, 0xbc, 0x43, 0x37, 0xc4, 0xbe, 0xb5, + 0x39, 0x1f, 0xd9, 0x81, 0xa9, 0x72, 0xb3, 0xe9, 0x3d, 0xdd, 0x72, 0xfc, 0xd0, 0x75, 0x9a, 0xd5, + 0x4e, 0xbd, 0x4e, 0x83, 0xa0, 0x98, 0xbf, 0x92, 0xbb, 0x31, 0x5c, 0xb9, 0x76, 0x7c, 0x54, 0x2a, + 0x39, 0x0c, 0x5d, 0x6b, 0x73, 0x7c, 0x2d, 0xe0, 0x04, 0x9a, 0xa0, 0x34, 0x7e, 0xeb, 0x8f, 0x07, + 0xa1, 0xb0, 0xe2, 0x05, 0xe1, 0x02, 0xeb, 0x51, 0x9b, 0xfe, 0xb0, 0x43, 0x83, 0x90, 0x5c, 0x83, + 0x41, 0x06, 0x5b, 0x5d, 0x2c, 0xe6, 0xae, 0xe4, 0x6e, 0x8c, 0x54, 0x46, 0x8f, 0x8f, 0x4a, 0x43, + 0x07, 0x5e, 0x10, 0xd6, 0xdc, 0x86, 0x2d, 0x50, 0xe4, 0x75, 0x18, 0xde, 0xf0, 0x1a, 0x74, 0xc3, + 0x39, 0xa4, 0x58, 0x8b, 0x91, 0xca, 0xf8, 0xf1, 0x51, 0x69, 0xa4, 0xe5, 0x35, 0x68, 0xad, 0xe5, + 0x1c, 0x52, 0x5b, 0xa1, 0xc9, 0x2e, 0xf4, 0xdb, 0x5e, 0x93, 0x16, 0xfb, 0x90, 0xac, 0x72, 0x7c, + 0x54, 0xea, 0xf7, 0xbd, 0x26, 0xfd, 0xd9, 0x51, 0xe9, 0x9d, 0x7d, 0x37, 0x3c, 0xe8, 0xec, 0xdd, + 0xaa, 0x7b, 0x87, 0xb7, 0xf7, 0x7d, 0xe7, 0x89, 0xcb, 0x07, 0xa1, 0xd3, 0xbc, 0x1d, 0x0d, 0xd5, + 0xb6, 0x2b, 0xfa, 0xbd, 0xfa, 0x2c, 0x08, 0xe9, 0x21, 0x93, 0x64, 0xa3, 0x3c, 0xf2, 0x10, 0xa6, + 0xcb, 0x8d, 0x86, 0xcb, 0x39, 0xb6, 0x7c, 0xb7, 0x55, 0x77, 0xdb, 0x4e, 0x33, 0x28, 0xf6, 0x5f, + 0xe9, 0xbb, 0x31, 0x22, 0x94, 0xa2, 0xf0, 0xb5, 0xb6, 0x22, 0xd0, 0x94, 0x92, 0x2a, 0x80, 0xbc, + 0x09, 0xc3, 0x8b, 0x1b, 0x55, 0x56, 0xf7, 0xa0, 0x38, 0x80, 0xc2, 0x66, 0x8f, 0x8f, 0x4a, 0x53, + 0x8d, 0x56, 0x80, 0x4d, 0xd3, 0x05, 0x28, 0x42, 0xf2, 0x0e, 0x8c, 0x6d, 0x75, 0xf6, 0x9a, 0x6e, + 0x7d, 0x7b, 0xad, 0xfa, 0x80, 0x3e, 0x2b, 0x0e, 0x5e, 0xc9, 0xdd, 0x18, 0xab, 0x90, 0xe3, 0xa3, + 0xd2, 0x44, 0x1b, 0xe1, 0xb5, 0xb0, 0x19, 0xd4, 0x1e, 0xd3, 0x67, 0xb6, 0x41, 0x17, 0xf1, 0x55, + 0xab, 0x2b, 0x8c, 0x6f, 0x28, 0xc1, 0x17, 0x04, 0x07, 0x3a, 0x1f, 0xa7, 0x23, 0xb7, 0x01, 0x6c, + 0x7a, 0xe8, 0x85, 0xb4, 0xdc, 0x68, 0xf8, 0xc5, 0x61, 0xd4, 0xed, 0xe4, 0xf1, 0x51, 0x69, 0xd4, + 0x47, 0x68, 0xcd, 0x69, 0x34, 0x7c, 0x5b, 0x23, 0x21, 0x0b, 0x30, 0x6c, 0x7b, 0x5c, 0xc1, 0xc5, + 0x91, 0x2b, 0xb9, 0x1b, 0xa3, 0xf3, 0x93, 0x62, 0x18, 0x4a, 0x70, 0xe5, 0xdc, 0xf1, 0x51, 0x89, + 0xf8, 0xe2, 0x97, 0xde, 0x4a, 0x49, 0x41, 0x4a, 0x30, 0xb4, 0xe1, 0x2d, 0x38, 0xf5, 0x03, 0x5a, + 0x04, 0x1c, 0x7b, 0x03, 0xc7, 0x47, 0xa5, 0xdc, 0x77, 0x6d, 0x09, 0x25, 0x4f, 0x60, 0x34, 0xea, + 0xa8, 0xa0, 0x38, 0x8a, 0xea, 0xdb, 0x3e, 0x3e, 0x2a, 0x9d, 0x0b, 0x10, 0x5c, 0x63, 0x5d, 0xaf, + 0x69, 0xf0, 0x05, 0x46, 0x81, 0x5e, 0x10, 0xf9, 0x1a, 0x66, 0xa2, 0x9f, 0xe5, 0x20, 0xa0, 0x3e, + 0x93, 0xb1, 0xba, 0x58, 0x1c, 0x47, 0xcd, 0xbc, 0x7a, 0x7c, 0x54, 0xb2, 0xb4, 0x1a, 0xd4, 0x1c, + 0x49, 0x52, 0x73, 0x1b, 0x5a, 0x4b, 0xd3, 0x85, 0xdc, 0xef, 0x1f, 0x1e, 0x2b, 0x8c, 0xdb, 0x97, + 0x76, 0x5a, 0x41, 0xe8, 0xec, 0x35, 0x69, 0x2a, 0x91, 0xf5, 0xd7, 0x39, 0x20, 0x9b, 0x6d, 0xda, + 0xaa, 0x56, 0x57, 0xd8, 0xf7, 0x24, 0x3f, 0xa7, 0x37, 0x60, 0x84, 0x77, 0x1c, 0xeb, 0xdd, 0x3c, + 0xf6, 0xee, 0xc4, 0xf1, 0x51, 0x09, 0x44, 0xef, 0xb2, 0x9e, 0x8d, 0x08, 0xc8, 0x75, 0xe8, 0xdb, + 0xde, 0x5e, 0xc3, 0x6f, 0xa5, 0xaf, 0x32, 0x75, 0x7c, 0x54, 0xea, 0x0b, 0xc3, 0xe6, 0xcf, 0x8e, + 0x4a, 0xc3, 0x8b, 0x1d, 0x1f, 0xd5, 0x62, 0x33, 0x3c, 0xb9, 0x0e, 0x43, 0x0b, 0xcd, 0x4e, 0x10, + 0x52, 0xbf, 0xd8, 0x1f, 0x7d, 0xa4, 0x75, 0x0e, 0xb2, 0x25, 0x8e, 0x7c, 0x07, 0xfa, 0x77, 0x02, + 0xea, 0x17, 0x07, 0xb0, 0xbf, 0xc7, 0x45, 0x7f, 0x33, 0xd0, 0xee, 0x7c, 0x65, 0x98, 0x7d, 0x89, + 0x9d, 0x80, 0xfa, 0x36, 0x12, 0x91, 0x5b, 0x30, 0xc0, 0x3b, 0x6d, 0x10, 0x27, 0xa9, 0x71, 0x35, + 0x3a, 0x9a, 0x74, 0xf7, 0x9d, 0xca, 0xc8, 0xf1, 0x51, 0x69, 0x00, 0x3b, 0xcf, 0xe6, 0x64, 0xf7, + 0xfb, 0x87, 0x73, 0x85, 0xbc, 0x3d, 0xcc, 0x78, 0xd9, 0x67, 0x61, 0x7d, 0x07, 0x46, 0xb5, 0xe6, + 0x93, 0x8b, 0xd0, 0xcf, 0xfe, 0xc7, 0x49, 0x64, 0x8c, 0x17, 0xc6, 0x16, 0x0e, 0x1b, 0xa1, 0xd6, + 0x3f, 0x99, 0x82, 0x02, 0xe3, 0x34, 0x66, 0x9e, 0x5b, 0xba, 0xaa, 0x38, 0x5f, 0xc1, 0x54, 0x55, + 0x31, 0xa7, 0x2b, 0xeb, 0x06, 0xa8, 0xd2, 0xc5, 0x24, 0x34, 0x76, 0x7c, 0x54, 0x1a, 0xee, 0x08, + 0x58, 0x54, 0x37, 0x52, 0x85, 0xa1, 0xa5, 0x6f, 0xda, 0xae, 0x4f, 0x03, 0x54, 0xed, 0xe8, 0xfc, + 0xdc, 0x2d, 0xbe, 0x5c, 0xde, 0x92, 0xcb, 0xe5, 0xad, 0x6d, 0xb9, 0x5c, 0x56, 0x2e, 0x89, 0xc9, + 0xf8, 0x2c, 0xe5, 0x2c, 0xd1, 0xf8, 0xf8, 0x8d, 0xbf, 0x28, 0xe5, 0x6c, 0x29, 0x89, 0xbc, 0x01, + 0x83, 0xf7, 0x3c, 0xff, 0xd0, 0x09, 0x45, 0x1f, 0x4c, 0x1f, 0x1f, 0x95, 0x0a, 0x8f, 0x10, 0xa2, + 0x0d, 0x29, 0x41, 0x43, 0xee, 0xc1, 0x84, 0xed, 0x75, 0x42, 0xba, 0xed, 0xc9, 0x9e, 0x1b, 0x40, + 0xae, 0xcb, 0xc7, 0x47, 0xa5, 0x39, 0x9f, 0x61, 0x6a, 0xa1, 0x57, 0x13, 0x5d, 0xa8, 0xf1, 0xc7, + 0xb8, 0xc8, 0x12, 0x4c, 0x94, 0x71, 0xf6, 0x16, 0x5a, 0xe3, 0xfd, 0x35, 0x52, 0xb9, 0x74, 0x7c, + 0x54, 0x3a, 0xef, 0x20, 0xa6, 0xe6, 0x0b, 0x94, 0x2e, 0xc6, 0x64, 0x22, 0x1b, 0x70, 0xf6, 0x41, + 0x67, 0x8f, 0xfa, 0x2d, 0x1a, 0xd2, 0x40, 0xd6, 0x68, 0x08, 0x6b, 0x74, 0xe5, 0xf8, 0xa8, 0x74, + 0xf1, 0xb1, 0x42, 0xa6, 0xd4, 0x29, 0xc9, 0x4a, 0x28, 0x4c, 0x8a, 0x8a, 0x2e, 0x3a, 0xa1, 0xb3, + 0xe7, 0x04, 0x14, 0x27, 0xa5, 0xd1, 0xf9, 0x73, 0x5c, 0xc5, 0xb7, 0x62, 0xd8, 0xca, 0x35, 0xa1, + 0xe5, 0x0b, 0xaa, 0xed, 0x0d, 0x81, 0xd2, 0x0a, 0x8a, 0xcb, 0x64, 0x73, 0xb3, 0x5a, 0x77, 0x46, + 0xb0, 0xb6, 0x38, 0x37, 0xab, 0x75, 0x47, 0x9f, 0xb5, 0xd4, 0x0a, 0xb4, 0x06, 0x03, 0x3b, 0x6c, + 0x75, 0xc6, 0x39, 0x6b, 0x62, 0xfe, 0xaa, 0xa8, 0x51, 0x7c, 0xfc, 0xdd, 0x62, 0x3f, 0x90, 0x10, + 0xbf, 0xbc, 0x49, 0x5c, 0xd1, 0xf5, 0xb5, 0x18, 0x71, 0xe4, 0x33, 0x00, 0x51, 0xab, 0x72, 0xbb, + 0x5d, 0x1c, 0xc5, 0x46, 0x9e, 0x35, 0x1b, 0x59, 0x6e, 0xb7, 0x2b, 0x97, 0x45, 0xfb, 0xce, 0xa9, + 0xf6, 0x39, 0xed, 0xb6, 0x26, 0x4d, 0x13, 0x42, 0x3e, 0x81, 0x31, 0x9c, 0xd2, 0x64, 0x8f, 0x8e, + 0x61, 0x8f, 0x5e, 0x38, 0x3e, 0x2a, 0xcd, 0xe2, 0x6c, 0x95, 0xd2, 0x9f, 0x06, 0x03, 0xf9, 0x65, + 0x98, 0x11, 0xe2, 0x1e, 0xba, 0xad, 0x86, 0xf7, 0x34, 0x58, 0xa4, 0xc1, 0xe3, 0xd0, 0x6b, 0xe3, + 0xf4, 0x37, 0x3a, 0x7f, 0xd1, 0xac, 0x9e, 0x49, 0x53, 0xb9, 0x29, 0x6a, 0x6a, 0xa9, 0x9a, 0x3e, + 0xe5, 0x04, 0xb5, 0x06, 0xa7, 0xd0, 0x27, 0xc8, 0x54, 0x11, 0x64, 0x15, 0x26, 0x77, 0x02, 0x6a, + 0xb4, 0x61, 0x02, 0xd7, 0x87, 0x12, 0xeb, 0xe1, 0x4e, 0x40, 0x6b, 0x59, 0xed, 0x88, 0xf3, 0x11, + 0x1b, 0xc8, 0xa2, 0xef, 0xb5, 0x63, 0x63, 0x7c, 0x12, 0x35, 0x62, 0x1d, 0x1f, 0x95, 0x2e, 0x37, + 0x7c, 0xaf, 0x5d, 0xcb, 0x1e, 0xe8, 0x29, 0xdc, 0xe4, 0xfb, 0x70, 0x6e, 0xc1, 0x6b, 0xb5, 0x68, + 0x9d, 0xcd, 0xa0, 0x8b, 0xae, 0xb3, 0xdf, 0xf2, 0x82, 0xd0, 0xad, 0xaf, 0x2e, 0x16, 0x0b, 0xd1, + 0xf2, 0x50, 0x57, 0x14, 0xb5, 0x86, 0x22, 0x31, 0x97, 0x87, 0x0c, 0x29, 0xe4, 0x2b, 0x18, 0x17, + 0x65, 0x51, 0x1f, 0x87, 0xe6, 0xd9, 0xee, 0x03, 0x4d, 0x11, 0xf3, 0x85, 0xde, 0x97, 0x3f, 0xf9, + 0xd6, 0xc9, 0x94, 0x45, 0xbe, 0x86, 0xd1, 0xf5, 0x7b, 0x65, 0x9b, 0x06, 0x6d, 0xaf, 0x15, 0xd0, + 0x22, 0xc1, 0x1e, 0xbd, 0x2c, 0x44, 0xaf, 0xdf, 0x2b, 0x97, 0x3b, 0xe1, 0x01, 0x6d, 0x85, 0x6e, + 0xdd, 0x09, 0xa9, 0xa4, 0xaa, 0xcc, 0xb1, 0x91, 0x77, 0xf8, 0xc8, 0xa9, 0xf9, 0x02, 0xa2, 0xb5, + 0x42, 0x17, 0x47, 0xe6, 0x60, 0xb8, 0x5a, 0x5d, 0x59, 0xf3, 0xf6, 0xdd, 0x56, 0x71, 0x8a, 0x29, + 0xc3, 0x56, 0xbf, 0xc9, 0x23, 0x98, 0xd1, 0x6c, 0x83, 0x1a, 0xfb, 0x9f, 0x1e, 0xd2, 0x56, 0x58, + 0x9c, 0xc6, 0x3a, 0x7c, 0x57, 0x19, 0x37, 0xb7, 0x74, 0x13, 0xe2, 0xc9, 0xdd, 0x5b, 0xe5, 0xe8, + 0x67, 0x55, 0x32, 0x55, 0xf2, 0xc5, 0x9c, 0x3d, 0xed, 0xa4, 0x60, 0xc8, 0x36, 0x0c, 0x6d, 0x75, + 0xfc, 0xb6, 0x17, 0xd0, 0xe2, 0x0c, 0x2a, 0xee, 0x5a, 0xb7, 0x2f, 0x54, 0x90, 0x56, 0x66, 0xd8, + 0x14, 0xdd, 0xe6, 0x3f, 0xb4, 0xd6, 0x49, 0x51, 0xe4, 0x53, 0x18, 0xab, 0x56, 0x57, 0xa2, 0x05, + 0xe5, 0x1c, 0x2e, 0x28, 0x17, 0x8f, 0x8f, 0x4a, 0x45, 0xb6, 0xa5, 0x8a, 0x16, 0x15, 0xfd, 0xab, + 0xd2, 0x39, 0x98, 0x84, 0xed, 0xb5, 0x6a, 0x24, 0x61, 0x36, 0x92, 0xc0, 0x36, 0x73, 0xe9, 0x12, + 0x74, 0x0e, 0xf2, 0x2f, 0x73, 0x70, 0x45, 0x17, 0x99, 0xa6, 0x98, 0xe2, 0xf9, 0xe7, 0xd1, 0xe6, + 0xfc, 0xf1, 0x51, 0xe9, 0x96, 0xd9, 0x8e, 0x5a, 0x6a, 0x67, 0x69, 0x75, 0xeb, 0x59, 0x15, 0xac, + 0xaf, 0xde, 0x80, 0xd4, 0xfa, 0xce, 0x3d, 0x77, 0x7d, 0x4d, 0xad, 0xf5, 0xae, 0x6f, 0xaf, 0xaa, + 0x58, 0x9f, 0xc3, 0x88, 0x9a, 0xb4, 0xc9, 0x10, 0xf4, 0x95, 0x9b, 0xcd, 0xc2, 0x19, 0xf6, 0x47, + 0xb5, 0xba, 0x52, 0xc8, 0x91, 0x09, 0x80, 0x68, 0xa5, 0x2a, 0xe4, 0xc9, 0x18, 0x0c, 0xcb, 0x95, + 0xa4, 0xd0, 0x87, 0xf4, 0xed, 0x76, 0xa1, 0x9f, 0x10, 0x98, 0x30, 0xe7, 0xb3, 0xc2, 0x80, 0xf5, + 0x9b, 0x39, 0x18, 0x51, 0xdf, 0x21, 0x99, 0x84, 0xd1, 0x9d, 0x8d, 0xea, 0xd6, 0xd2, 0xc2, 0xea, + 0xbd, 0xd5, 0xa5, 0xc5, 0xc2, 0x19, 0x72, 0x09, 0xce, 0x6f, 0x57, 0x57, 0x6a, 0x8b, 0x95, 0xda, + 0xda, 0xe6, 0x42, 0x79, 0xad, 0xb6, 0x65, 0x6f, 0x7e, 0xfe, 0x45, 0x6d, 0x7b, 0x67, 0x63, 0x63, + 0x69, 0xad, 0x90, 0x23, 0x45, 0x98, 0x66, 0xe8, 0x07, 0x3b, 0x95, 0x25, 0x9d, 0xa0, 0x90, 0x27, + 0x57, 0xe1, 0x52, 0x1a, 0xa6, 0xb6, 0xb2, 0x54, 0x5e, 0x5c, 0x5b, 0xaa, 0x56, 0x0b, 0x7d, 0x64, + 0x16, 0xa6, 0x18, 0x49, 0x79, 0x6b, 0xcb, 0xe0, 0xed, 0xb7, 0x9a, 0x30, 0xaa, 0x7d, 0x00, 0xe4, + 0x22, 0x14, 0x17, 0x96, 0xec, 0xed, 0xda, 0xd6, 0x8e, 0xbd, 0xb5, 0x59, 0x5d, 0xaa, 0x99, 0x35, + 0x8c, 0x63, 0xd7, 0x36, 0x97, 0x57, 0x37, 0x6a, 0x0c, 0x54, 0x2d, 0xe4, 0x58, 0x35, 0x0c, 0x6c, + 0x75, 0x75, 0x63, 0x79, 0x6d, 0xa9, 0xb6, 0x53, 0x5d, 0x12, 0x24, 0x79, 0xeb, 0x57, 0xf3, 0x89, + 0x25, 0x9d, 0xcc, 0xc3, 0x68, 0x95, 0xfb, 0x2b, 0x70, 0x9a, 0xe3, 0x06, 0x22, 0xdb, 0xa3, 0x8d, + 0x09, 0x37, 0x06, 0x9f, 0xc1, 0x74, 0x22, 0xb6, 0x4b, 0xdb, 0x62, 0x5f, 0x73, 0xdd, 0x6b, 0xea, + 0xbb, 0xb4, 0xb6, 0x80, 0xd9, 0x0a, 0x4b, 0xe6, 0xb5, 0xfd, 0x1c, 0xb7, 0x16, 0xd1, 0x22, 0x91, + 0xfb, 0x39, 0x7d, 0x6d, 0x57, 0x3b, 0xbb, 0xf9, 0xa8, 0x4b, 0xc5, 0x36, 0x0c, 0x79, 0x52, 0xf6, + 0x12, 0x8a, 0x8e, 0xbc, 0x2e, 0x77, 0xba, 0xdc, 0xba, 0xc3, 0xc5, 0x3e, 0x66, 0x97, 0x88, 0x4d, + 0xae, 0xd5, 0xc9, 0x58, 0x58, 0xc9, 0x07, 0xf1, 0x31, 0x23, 0x94, 0x81, 0xc2, 0x62, 0xeb, 0xa7, + 0x1d, 0x23, 0x25, 0x25, 0x18, 0xe0, 0x33, 0x2e, 0xd7, 0x07, 0xee, 0xad, 0x9b, 0x0c, 0x60, 0x73, + 0xb8, 0xf5, 0x27, 0x7d, 0xfa, 0x26, 0x83, 0xed, 0xa5, 0x35, 0x7d, 0xe3, 0x5e, 0x1a, 0xf5, 0x8c, + 0x50, 0x66, 0x0a, 0xf2, 0xaf, 0x04, 0x4d, 0xc1, 0xbe, 0xc8, 0x14, 0x14, 0x9f, 0x1a, 0x37, 0x05, + 0x23, 0x12, 0xd6, 0x8b, 0x62, 0xdb, 0x86, 0x52, 0xfb, 0xa3, 0x5e, 0x14, 0x5b, 0x3d, 0xd1, 0x8b, + 0x1a, 0x11, 0x79, 0x1f, 0xa0, 0xfc, 0xb0, 0x8a, 0x36, 0x8f, 0xbd, 0x21, 0xb6, 0xae, 0xb8, 0xc8, + 0x38, 0x4f, 0x03, 0x61, 0x52, 0xf9, 0xba, 0xcd, 0xa8, 0x51, 0x93, 0x0a, 0x8c, 0x97, 0x7f, 0xd4, + 0xf1, 0xe9, 0x6a, 0x83, 0xad, 0x53, 0x21, 0x37, 0x8e, 0x47, 0xf8, 0x44, 0xea, 0x30, 0x44, 0xcd, + 0x15, 0x18, 0x4d, 0x80, 0xc9, 0x42, 0x36, 0xe1, 0xec, 0xf2, 0xc2, 0x96, 0x18, 0x57, 0xe5, 0x7a, + 0xdd, 0xeb, 0xb4, 0x42, 0xb1, 0x5f, 0xbd, 0x7a, 0x7c, 0x54, 0xba, 0xb4, 0x5f, 0x6f, 0xd7, 0xe4, + 0x18, 0x74, 0x38, 0x5a, 0xdf, 0xb0, 0x26, 0x78, 0xc9, 0x35, 0xe8, 0xdb, 0xb1, 0x57, 0x85, 0xe5, + 0x7c, 0xf6, 0xf8, 0xa8, 0x34, 0xde, 0xf1, 0x5d, 0x8d, 0x85, 0x61, 0xc9, 0x7b, 0x00, 0xdb, 0x8e, + 0xbf, 0x4f, 0xc3, 0x2d, 0xcf, 0x0f, 0x71, 0xc3, 0x39, 0x5e, 0x39, 0x7f, 0x7c, 0x54, 0x9a, 0x09, + 0x11, 0x5a, 0x63, 0xd3, 0x9f, 0xde, 0xe8, 0x88, 0xf8, 0x7e, 0xff, 0x70, 0xbe, 0xd0, 0x67, 0x8f, + 0x54, 0x69, 0x10, 0x70, 0xfb, 0xb0, 0x09, 0x13, 0xcb, 0x34, 0x64, 0x03, 0x57, 0xda, 0x3b, 0xdd, + 0xbb, 0xf5, 0x43, 0x18, 0x7d, 0xe8, 0x86, 0x07, 0x55, 0x5a, 0xf7, 0x69, 0x28, 0x7d, 0x3d, 0xa8, + 0xf2, 0xa7, 0x6e, 0x78, 0x50, 0x0b, 0x38, 0x5c, 0x5f, 0xd7, 0x35, 0x72, 0x6b, 0x09, 0x26, 0x45, + 0x69, 0xca, 0xbc, 0x9a, 0x37, 0x05, 0xe6, 0x50, 0x20, 0x76, 0xbb, 0x2e, 0xd0, 0x14, 0xf3, 0xaf, + 0xf2, 0x30, 0xb3, 0x70, 0xe0, 0xb4, 0xf6, 0xe9, 0x96, 0x13, 0x04, 0x4f, 0x3d, 0xbf, 0xa1, 0x55, + 0x1e, 0x6d, 0xcb, 0x44, 0xe5, 0xd1, 0x98, 0x9c, 0x87, 0xd1, 0xcd, 0x66, 0x43, 0xf2, 0x08, 0xbb, + 0x17, 0xcb, 0xf2, 0x9a, 0x8d, 0x5a, 0x5b, 0xca, 0xd2, 0x89, 0x18, 0xcf, 0x06, 0x7d, 0xaa, 0x78, + 0xfa, 0x22, 0x9e, 0x16, 0x7d, 0xaa, 0xf1, 0x68, 0x44, 0x64, 0x09, 0xce, 0x56, 0x69, 0xdd, 0x6b, + 0x35, 0xee, 0x39, 0xf5, 0xd0, 0xf3, 0xb7, 0xbd, 0xc7, 0xb4, 0x25, 0x06, 0x34, 0x1a, 0x06, 0x01, + 0x22, 0x6b, 0x8f, 0x10, 0x5b, 0x0b, 0x19, 0xda, 0x4e, 0x72, 0x90, 0x4d, 0x18, 0x7e, 0x28, 0x3c, + 0x86, 0xc2, 0x58, 0xbe, 0x7e, 0x4b, 0xb9, 0x10, 0x17, 0x7c, 0x8a, 0xa3, 0xd0, 0x69, 0x2a, 0x73, + 0x5f, 0xed, 0xb3, 0x70, 0x2a, 0x93, 0x94, 0xb6, 0x12, 0x62, 0xed, 0xc0, 0xf8, 0x56, 0xb3, 0xb3, + 0xef, 0xb6, 0xd8, 0xa4, 0x53, 0xa5, 0x3f, 0x24, 0x8b, 0x00, 0x11, 0x40, 0xf8, 0x01, 0xa7, 0x84, + 0x89, 0x1d, 0x21, 0x76, 0xdf, 0x14, 0x5f, 0x2e, 0x42, 0xd0, 0x22, 0xb2, 0x35, 0x3e, 0xeb, 0x7f, + 0xf5, 0x01, 0x11, 0x1d, 0x80, 0x8b, 0x60, 0x95, 0x86, 0x6c, 0x79, 0x3a, 0x07, 0x79, 0xe5, 0xae, + 0x1b, 0x3c, 0x3e, 0x2a, 0xe5, 0xdd, 0x86, 0x9d, 0x5f, 0x5d, 0x24, 0x6f, 0xc1, 0x00, 0x92, 0xa1, + 0xfe, 0x27, 0x54, 0x79, 0xba, 0x04, 0x3e, 0xf9, 0xe0, 0xea, 0x6b, 0x73, 0x62, 0xf2, 0x36, 0x8c, + 0x2c, 0xd2, 0x26, 0xdd, 0x77, 0x42, 0x4f, 0x4e, 0x27, 0xdc, 0x01, 0x26, 0x81, 0xda, 0x98, 0x8b, + 0x28, 0x99, 0x39, 0x6c, 0x53, 0x27, 0xf0, 0x5a, 0xba, 0x39, 0xec, 0x23, 0x44, 0x37, 0x87, 0x39, + 0x0d, 0xf9, 0xad, 0x1c, 0x8c, 0x96, 0x5b, 0x2d, 0xe1, 0x58, 0x0a, 0x84, 0xd6, 0x67, 0x6e, 0x29, + 0x4f, 0xec, 0x9a, 0xb3, 0x47, 0x9b, 0xbb, 0x4e, 0xb3, 0x43, 0x83, 0xca, 0xd7, 0xcc, 0x42, 0xf9, + 0x8f, 0x47, 0xa5, 0x0f, 0x4e, 0xe1, 0x2a, 0x8a, 0x7c, 0xba, 0xdb, 0xbe, 0xe3, 0x86, 0x01, 0xfb, + 0x6a, 0x9d, 0xa8, 0x40, 0xfd, 0xbb, 0xd1, 0xea, 0x11, 0xad, 0x0d, 0x83, 0xbd, 0xd6, 0x06, 0x72, + 0x08, 0x93, 0xe5, 0x20, 0xe8, 0x1c, 0xd2, 0x6a, 0xe8, 0xf8, 0xe1, 0xb6, 0x7b, 0x48, 0x71, 0x42, + 0xea, 0xee, 0x5c, 0x78, 0xed, 0x27, 0x47, 0xa5, 0x1c, 0x33, 0x8a, 0x1c, 0x64, 0x65, 0xfb, 0x1e, + 0x3f, 0xac, 0x85, 0xae, 0xbe, 0xbc, 0xa1, 0x9b, 0x21, 0x2e, 0xdb, 0xba, 0xa6, 0x36, 0x24, 0xab, + 0x8b, 0x59, 0x3d, 0x6e, 0x2d, 0xc0, 0xc5, 0x65, 0x1a, 0xda, 0x34, 0xa0, 0xa1, 0xfc, 0x46, 0x70, + 0x84, 0x47, 0xce, 0xdd, 0x21, 0xfc, 0xad, 0x98, 0xb1, 0xfb, 0xf9, 0x77, 0x21, 0x31, 0xd6, 0xff, + 0x97, 0x83, 0xd2, 0x82, 0x4f, 0xb9, 0x3d, 0x91, 0x21, 0xa8, 0xfb, 0xdc, 0x75, 0x11, 0xfa, 0xb7, + 0x9f, 0xb5, 0xa5, 0x57, 0x06, 0xb1, 0xac, 0x53, 0x6c, 0x84, 0x9e, 0xd0, 0xc9, 0x65, 0x3d, 0x82, + 0x19, 0x9b, 0xb6, 0xe8, 0x53, 0x67, 0xaf, 0x49, 0x0d, 0x3f, 0x51, 0x09, 0x06, 0xf8, 0x87, 0x9e, + 0x68, 0x02, 0x87, 0x9f, 0xce, 0xe7, 0x66, 0x8d, 0xc3, 0xe8, 0x96, 0xdb, 0xda, 0x17, 0xd2, 0xad, + 0xbf, 0xec, 0x87, 0x31, 0xfe, 0x5b, 0x98, 0x48, 0xb1, 0xe5, 0x32, 0x77, 0x92, 0xe5, 0xf2, 0x5d, + 0x18, 0x67, 0xeb, 0x0d, 0xf5, 0x77, 0xa9, 0xcf, 0xe6, 0x7f, 0xa1, 0x09, 0x34, 0xf7, 0x02, 0x44, + 0xd4, 0x9e, 0x70, 0x8c, 0x6d, 0x12, 0x92, 0x35, 0x98, 0xe0, 0x80, 0x7b, 0xd4, 0x09, 0x3b, 0x91, + 0xc7, 0x6a, 0x52, 0xd8, 0x44, 0x12, 0xcc, 0x87, 0xa6, 0x90, 0xf5, 0x48, 0x00, 0xed, 0x18, 0x2f, + 0xf9, 0x04, 0x26, 0xb7, 0x7c, 0xef, 0x9b, 0x67, 0xda, 0x06, 0x81, 0x7f, 0x9d, 0xdc, 0x7a, 0x62, + 0xa8, 0x9a, 0xbe, 0x4d, 0x88, 0x53, 0x93, 0xd7, 0x61, 0x78, 0x35, 0xa8, 0x78, 0xbe, 0xdb, 0xda, + 0xc7, 0x6f, 0x74, 0x98, 0x3b, 0xfa, 0xdd, 0xa0, 0xb6, 0x87, 0x40, 0x5b, 0xa1, 0x63, 0x2e, 0xe9, + 0xa1, 0xde, 0x2e, 0xe9, 0x3b, 0x00, 0x6b, 0x9e, 0xd3, 0x28, 0x37, 0x9b, 0x0b, 0xe5, 0x00, 0x57, + 0x62, 0xb1, 0x1e, 0x35, 0x3d, 0xa7, 0x51, 0x73, 0x9a, 0xcd, 0x5a, 0xdd, 0x09, 0x6c, 0x8d, 0x86, + 0x7c, 0x09, 0xe7, 0x03, 0x77, 0xbf, 0x85, 0x8d, 0xab, 0x39, 0xcd, 0x7d, 0xcf, 0x77, 0xc3, 0x83, + 0xc3, 0x5a, 0xd0, 0x71, 0x43, 0xee, 0x0f, 0x9a, 0x98, 0xbf, 0x2c, 0x26, 0xb9, 0xaa, 0xa4, 0x2b, + 0x4b, 0xb2, 0x2a, 0xa3, 0xb2, 0x67, 0x83, 0x74, 0x04, 0x79, 0x08, 0xe3, 0x6b, 0x6e, 0x9d, 0xb6, + 0x02, 0x8a, 0x0e, 0xbe, 0x67, 0xe8, 0x2d, 0xea, 0xfe, 0x31, 0x33, 0x25, 0x8e, 0x37, 0x75, 0x26, + 0xfc, 0x74, 0x4d, 0x39, 0xf7, 0xfb, 0x87, 0x07, 0x0b, 0x43, 0xf6, 0xa4, 0x00, 0x3e, 0x74, 0xfc, + 0x96, 0xdb, 0xda, 0x0f, 0xac, 0xbf, 0x4b, 0x60, 0x58, 0xf5, 0xd3, 0x2d, 0xdd, 0x52, 0x11, 0x4b, + 0x33, 0x0e, 0xd9, 0xc8, 0x0f, 0x67, 0x6b, 0x14, 0xe4, 0x3c, 0xda, 0x2e, 0x62, 0x53, 0x30, 0xc4, + 0x3e, 0x21, 0xa7, 0xdd, 0xb6, 0x19, 0x8c, 0x4d, 0x0d, 0x8b, 0x15, 0x1c, 0x34, 0xc3, 0x7c, 0x6a, + 0x68, 0xec, 0xd9, 0xf9, 0xc5, 0x0a, 0xfb, 0x26, 0x37, 0x57, 0x17, 0x17, 0xb0, 0xff, 0x87, 0xf9, + 0x37, 0xe9, 0xb9, 0x8d, 0xba, 0x8d, 0x50, 0x86, 0xad, 0x96, 0xd7, 0xd7, 0x44, 0x1f, 0x23, 0x36, + 0x70, 0x0e, 0x9b, 0x36, 0x42, 0xd9, 0x6e, 0x97, 0xbb, 0x54, 0x16, 0xbc, 0x56, 0xe8, 0x7b, 0xcd, + 0x00, 0xb7, 0x70, 0xc3, 0x7c, 0x0c, 0x0a, 0x5f, 0x4c, 0x5d, 0xa0, 0xec, 0x18, 0x29, 0x79, 0x08, + 0xb3, 0xe5, 0xc6, 0x13, 0xa7, 0x55, 0xa7, 0x0d, 0x8e, 0x79, 0xe8, 0xf9, 0x8f, 0x1f, 0x35, 0xbd, + 0xa7, 0x01, 0x0e, 0x92, 0x61, 0xe1, 0xba, 0x14, 0x24, 0xd2, 0xb5, 0xf3, 0x54, 0x12, 0xd9, 0x59, + 0xdc, 0x6c, 0x1e, 0x58, 0x68, 0x7a, 0x9d, 0x86, 0x18, 0x3a, 0x38, 0x0f, 0xd4, 0x19, 0xc0, 0xe6, + 0x70, 0xa6, 0xa5, 0x95, 0xea, 0x3a, 0x0e, 0x0c, 0xa1, 0xa5, 0x83, 0xe0, 0xd0, 0x66, 0x30, 0x72, + 0x1d, 0x86, 0xe4, 0xc6, 0x9d, 0x9f, 0x64, 0xa0, 0x07, 0x5d, 0x6e, 0xd8, 0x25, 0x8e, 0x7d, 0xc7, + 0x36, 0xad, 0x7b, 0x4f, 0xa8, 0xff, 0x6c, 0xc1, 0x6b, 0x50, 0xe9, 0xd6, 0x12, 0x6e, 0x1b, 0x8e, + 0xa8, 0xd5, 0x19, 0xc6, 0x36, 0x09, 0x59, 0x01, 0x7c, 0xe1, 0x0e, 0x8a, 0x93, 0x51, 0x01, 0x7c, + 0x61, 0x0f, 0x6c, 0x89, 0x23, 0x8b, 0x70, 0xb6, 0xdc, 0x09, 0xbd, 0x43, 0x27, 0x74, 0xeb, 0x3b, + 0xed, 0x7d, 0xdf, 0x61, 0x85, 0x14, 0x90, 0x01, 0x0d, 0x19, 0x47, 0x22, 0x6b, 0x1d, 0x81, 0xb5, + 0x93, 0x0c, 0xe4, 0x1d, 0x18, 0x5b, 0x0d, 0xb8, 0xeb, 0xd2, 0x09, 0x68, 0x03, 0xfd, 0x4f, 0xa2, + 0x96, 0x6e, 0x50, 0x43, 0x47, 0x66, 0x8d, 0x99, 0x3e, 0x0d, 0xdb, 0xa0, 0x23, 0x16, 0x0c, 0x96, + 0x83, 0xc0, 0x0d, 0x42, 0x74, 0x2b, 0x0d, 0x57, 0xe0, 0xf8, 0xa8, 0x34, 0xe8, 0x20, 0xc4, 0x16, + 0x18, 0xf2, 0x10, 0x46, 0x17, 0x29, 0xdb, 0x39, 0x6f, 0xfb, 0x9d, 0x20, 0x44, 0x27, 0xd1, 0xe8, + 0xfc, 0x79, 0x31, 0x1b, 0x69, 0x18, 0x31, 0x96, 0xf9, 0x16, 0xb5, 0x81, 0xf0, 0x5a, 0xc8, 0x10, + 0xfa, 0x52, 0xab, 0xd1, 0x33, 0xb3, 0x40, 0xf0, 0xac, 0xb8, 0x0d, 0x36, 0xbf, 0x4c, 0x63, 0x1d, + 0xd0, 0x2c, 0x10, 0x13, 0x5a, 0xed, 0x00, 0x31, 0xba, 0x59, 0x60, 0xb0, 0x90, 0x7a, 0xc2, 0x1b, + 0x3e, 0x63, 0x78, 0x3c, 0x4d, 0xa4, 0xac, 0xe2, 0x29, 0x7d, 0xe5, 0x1f, 0xc2, 0xe8, 0x42, 0x27, + 0x08, 0xbd, 0xc3, 0xed, 0x03, 0x7a, 0x48, 0xd1, 0x91, 0x24, 0x8c, 0x9f, 0x3a, 0x82, 0x6b, 0x21, + 0x83, 0xeb, 0xcd, 0xd4, 0xc8, 0xc9, 0x67, 0x40, 0xa4, 0x15, 0xb3, 0xcc, 0xc6, 0x47, 0x8b, 0x8d, + 0x65, 0xf4, 0x25, 0x0d, 0x73, 0xd3, 0x45, 0x1a, 0x3f, 0xb5, 0x7d, 0x85, 0xd6, 0xfd, 0x99, 0x49, + 0x66, 0x56, 0x21, 0x5e, 0xc5, 0x65, 0xdf, 0x69, 0x1f, 0x14, 0x8b, 0x91, 0x69, 0x20, 0x1a, 0xb5, + 0xcf, 0xe0, 0xc6, 0x16, 0x27, 0x22, 0x27, 0x55, 0x00, 0xfe, 0x73, 0x8d, 0x75, 0x3c, 0xf7, 0x3e, + 0x15, 0x0d, 0x7d, 0x31, 0x84, 0xd4, 0x15, 0x9a, 0x3b, 0x42, 0x6c, 0xd3, 0x35, 0x7a, 0x53, 0x13, + 0x43, 0x1e, 0x43, 0x81, 0xff, 0x5a, 0xf7, 0x5a, 0x6e, 0xc8, 0xd7, 0x8b, 0x39, 0xc3, 0x55, 0x19, + 0x47, 0xcb, 0x02, 0xd0, 0x45, 0x2c, 0x0a, 0x38, 0x54, 0x58, 0xad, 0x98, 0x84, 0x60, 0xb2, 0x05, + 0xa3, 0x5b, 0xbe, 0xd7, 0xe8, 0xd4, 0x43, 0xdc, 0x65, 0x5c, 0xc0, 0x89, 0x9f, 0x88, 0x72, 0x34, + 0x0c, 0xd7, 0x49, 0x9b, 0x03, 0x6a, 0x6c, 0x5d, 0xd0, 0x75, 0xa2, 0x11, 0x92, 0x0a, 0x0c, 0x6e, + 0x79, 0x4d, 0xb7, 0xfe, 0xac, 0x78, 0x11, 0x2b, 0x3d, 0x2d, 0x85, 0x21, 0x50, 0x56, 0x15, 0xb7, + 0xb4, 0x6d, 0x04, 0xe9, 0x5b, 0x5a, 0x4e, 0x44, 0xca, 0x30, 0xfe, 0x19, 0x1b, 0x30, 0xae, 0xd7, + 0x6a, 0x39, 0xae, 0x4f, 0x8b, 0x97, 0xb0, 0x5f, 0xd0, 0x8d, 0xff, 0x43, 0x1d, 0xa1, 0x0f, 0x67, + 0x83, 0x83, 0xac, 0xc2, 0xe4, 0x6a, 0x50, 0x0d, 0x7d, 0xb7, 0x4d, 0xd7, 0x9d, 0x96, 0xb3, 0x4f, + 0x1b, 0xc5, 0xcb, 0x91, 0x1f, 0xdd, 0x0d, 0x6a, 0x01, 0xe2, 0x6a, 0x87, 0x1c, 0xa9, 0xfb, 0xd1, + 0x63, 0x7c, 0xe4, 0x73, 0x98, 0x5e, 0xfa, 0x26, 0x64, 0x23, 0xa6, 0x59, 0xee, 0x34, 0xdc, 0xb0, + 0x1a, 0x7a, 0xbe, 0xb3, 0x4f, 0x8b, 0x25, 0x94, 0xf7, 0xca, 0xf1, 0x51, 0xe9, 0x0a, 0x15, 0xf8, + 0x9a, 0xc3, 0x08, 0x6a, 0x01, 0xa7, 0xd0, 0xcf, 0xc7, 0xd3, 0x24, 0x30, 0xed, 0x57, 0x3b, 0x6d, + 0xb6, 0xdb, 0x46, 0xed, 0x5f, 0x31, 0xb4, 0xaf, 0x61, 0xb8, 0xf6, 0x03, 0x0e, 0x48, 0x68, 0x5f, + 0x23, 0x24, 0x36, 0x90, 0xfb, 0x9e, 0xdb, 0x2a, 0xd7, 0x43, 0xf7, 0x09, 0x15, 0x16, 0x73, 0x50, + 0xbc, 0x8a, 0x35, 0x45, 0x9f, 0xff, 0x2f, 0x7a, 0x6e, 0xab, 0xe6, 0x20, 0xba, 0x16, 0x08, 0xbc, + 0xfe, 0x8d, 0x24, 0xb9, 0xc9, 0xf7, 0xe1, 0xdc, 0xba, 0xb7, 0xe7, 0x36, 0x29, 0x9f, 0x72, 0xb8, + 0x5a, 0xd0, 0x7f, 0x69, 0xa1, 0x5c, 0xf4, 0xf9, 0x1f, 0x22, 0x45, 0x4d, 0xcc, 0x56, 0x87, 0x8a, + 0x46, 0xf7, 0xf9, 0xa7, 0x4b, 0x21, 0x4b, 0x30, 0x86, 0xdf, 0x65, 0x13, 0x7f, 0x06, 0xc5, 0x6b, + 0x68, 0xd2, 0x5d, 0x8d, 0xed, 0xd2, 0x6e, 0x2d, 0x69, 0x34, 0x4b, 0xad, 0xd0, 0x7f, 0x66, 0x1b, + 0x6c, 0xe4, 0x63, 0x98, 0x8b, 0x0f, 0xef, 0x05, 0xaf, 0xf5, 0xc8, 0xdd, 0xef, 0xf8, 0xb4, 0x51, + 0x7c, 0x85, 0x55, 0xd5, 0xee, 0x42, 0x41, 0xbe, 0x82, 0x19, 0x5c, 0xeb, 0xca, 0x2d, 0xaf, 0xf5, + 0xec, 0xd0, 0xfd, 0x11, 0xee, 0x9f, 0xd9, 0xb6, 0xf7, 0x3a, 0x6e, 0x7b, 0xaf, 0x1f, 0x1f, 0x95, + 0xae, 0xe2, 0x9a, 0x58, 0x73, 0x74, 0x8a, 0x98, 0xd7, 0x3a, 0x5d, 0xc6, 0xdc, 0x43, 0x38, 0x9b, + 0xa8, 0x3f, 0x29, 0x40, 0xdf, 0x63, 0x71, 0x3e, 0x3b, 0x62, 0xb3, 0x3f, 0xc9, 0x1b, 0x30, 0xf0, + 0x84, 0x19, 0x6a, 0xb8, 0x1d, 0x89, 0x4e, 0xfc, 0x34, 0xd6, 0xd5, 0xd6, 0x23, 0xcf, 0xe6, 0x44, + 0xef, 0xe7, 0xdf, 0xcd, 0xdd, 0xef, 0x1f, 0x1e, 0x2d, 0x8c, 0xf1, 0x63, 0xf5, 0xfb, 0xfd, 0xc3, + 0xe3, 0x85, 0x09, 0xab, 0x0c, 0x93, 0x31, 0x7a, 0x52, 0x84, 0x21, 0xda, 0x62, 0x9b, 0xff, 0x06, + 0xdf, 0x10, 0xd9, 0xf2, 0x27, 0x99, 0x86, 0x81, 0xa6, 0x7b, 0xe8, 0x86, 0x58, 0xe0, 0x80, 0xcd, + 0x7f, 0x58, 0xbf, 0x9d, 0x03, 0x92, 0x5c, 0x8f, 0xc8, 0xed, 0x98, 0x18, 0xbe, 0xf5, 0x15, 0x20, + 0xfd, 0xe0, 0x40, 0x4a, 0xff, 0x0c, 0xa6, 0xf8, 0x80, 0x90, 0x2b, 0xa7, 0x56, 0x16, 0x9f, 0xb1, + 0x53, 0xd0, 0xba, 0xb3, 0x49, 0xa0, 0x71, 0x9d, 0x5d, 0xc3, 0xaa, 0x75, 0x60, 0x26, 0x75, 0x25, + 0x22, 0xeb, 0x30, 0x73, 0xe8, 0xb5, 0xc2, 0x83, 0xe6, 0x33, 0xb9, 0x10, 0x89, 0xd2, 0x72, 0x58, + 0x1a, 0x4e, 0xbe, 0xa9, 0x04, 0xf6, 0x94, 0x00, 0x0b, 0x89, 0x58, 0x8e, 0x70, 0x3a, 0xc9, 0x96, + 0x58, 0x36, 0x9c, 0x4d, 0x4c, 0xe8, 0xe4, 0x23, 0x18, 0xab, 0xa3, 0x71, 0x67, 0x94, 0xc4, 0x97, + 0x33, 0x0d, 0xae, 0x7f, 0xab, 0x1c, 0xce, 0x9b, 0xf2, 0xcf, 0x72, 0x30, 0x9b, 0x31, 0x95, 0x9f, + 0x5e, 0xd5, 0x5f, 0xc0, 0xb9, 0x43, 0xe7, 0x9b, 0x9a, 0x8f, 0xb6, 0x7b, 0xcd, 0x77, 0x5a, 0x31, + 0x6d, 0xe3, 0x34, 0x95, 0x4e, 0xa1, 0xc7, 0x36, 0x1d, 0x3a, 0xdf, 0xd8, 0x48, 0x60, 0x33, 0x3c, + 0xaf, 0xe7, 0xa7, 0x30, 0x6e, 0x4c, 0xde, 0xa7, 0xae, 0x9c, 0x75, 0x17, 0xce, 0x2e, 0xd2, 0x26, + 0x0d, 0xe9, 0x89, 0x7d, 0x76, 0xd6, 0x16, 0x40, 0x95, 0x1e, 0x3a, 0xed, 0x03, 0x8f, 0x6d, 0xea, + 0x2b, 0xfa, 0x2f, 0xe1, 0xf3, 0x21, 0xd2, 0x3c, 0x91, 0x88, 0xdd, 0x37, 0xf9, 0x46, 0x3f, 0x50, + 0x94, 0xb6, 0xc6, 0x65, 0xfd, 0xbb, 0x3c, 0x10, 0x31, 0xfb, 0xfa, 0xd4, 0x39, 0x94, 0xd5, 0x78, + 0x0f, 0xc6, 0xb8, 0x85, 0xce, 0xc1, 0x58, 0x9d, 0xd1, 0xf9, 0x29, 0xf1, 0xe5, 0xe9, 0xa8, 0x95, + 0x33, 0xb6, 0x41, 0xca, 0x58, 0x6d, 0xca, 0x5d, 0x0b, 0xc8, 0x9a, 0x37, 0x58, 0x75, 0x14, 0x63, + 0xd5, 0x7f, 0x93, 0x4f, 0x60, 0x62, 0xc1, 0x3b, 0x6c, 0x33, 0x9d, 0x08, 0xe6, 0x3e, 0xe1, 0xb6, + 0x11, 0xe5, 0x1a, 0xc8, 0x95, 0x33, 0x76, 0x8c, 0x9c, 0x6c, 0xc0, 0xd4, 0xbd, 0x66, 0x27, 0x38, + 0x28, 0xb7, 0x1a, 0x0b, 0x4d, 0x2f, 0x90, 0x52, 0xfa, 0x85, 0xa5, 0x25, 0xe6, 0xce, 0x24, 0xc5, + 0xca, 0x19, 0x3b, 0x8d, 0x91, 0x5c, 0x87, 0x81, 0xa5, 0x27, 0x6c, 0x4e, 0x97, 0x11, 0x2e, 0x22, + 0x00, 0x6f, 0xb3, 0x45, 0x37, 0x1f, 0xad, 0x9c, 0xb1, 0x39, 0xb6, 0x32, 0x02, 0x43, 0xd2, 0xba, + 0xbf, 0xcd, 0xf6, 0xdb, 0x4a, 0x9d, 0xd5, 0xd0, 0x09, 0x3b, 0x01, 0x99, 0x83, 0xe1, 0x9d, 0x36, + 0x33, 0x3a, 0xa5, 0x5b, 0xc4, 0x56, 0xbf, 0xad, 0x37, 0x4c, 0x4d, 0x93, 0x8b, 0x10, 0xf9, 0x74, + 0x05, 0xb1, 0xe6, 0xe4, 0x5d, 0x31, 0x95, 0xdb, 0x9d, 0xda, 0x28, 0x37, 0x1f, 0x2b, 0xb7, 0x10, + 0xd7, 0xb5, 0x35, 0x93, 0xaa, 0x3c, 0xeb, 0x73, 0xb8, 0xbc, 0xd3, 0x0e, 0xa8, 0x1f, 0x96, 0xdb, + 0xed, 0xa6, 0x5b, 0xe7, 0x27, 0x64, 0xe8, 0x05, 0x90, 0x83, 0xe5, 0x1d, 0x18, 0xe4, 0x00, 0x31, + 0x4c, 0xe4, 0x18, 0x2c, 0xb7, 0xdb, 0xc2, 0xf7, 0xf0, 0x26, 0xdf, 0xf9, 0x73, 0x6f, 0x82, 0x2d, + 0xa8, 0xad, 0xdf, 0xc8, 0xc1, 0x65, 0xfe, 0x05, 0x64, 0x8a, 0xfe, 0x0e, 0x8c, 0x60, 0xfc, 0x5b, + 0xdb, 0xa9, 0xcb, 0x6f, 0x82, 0x07, 0x02, 0x4a, 0xa0, 0x1d, 0xe1, 0xb5, 0xc8, 0xc2, 0x7c, 0x76, + 0x64, 0xa1, 0xfc, 0xc0, 0xfa, 0x52, 0x3f, 0xb0, 0xcf, 0xc0, 0x12, 0x35, 0x6a, 0x36, 0x13, 0x95, + 0x0a, 0x9e, 0xa7, 0x56, 0xd6, 0x7f, 0xcb, 0xc3, 0xec, 0x32, 0x6d, 0x51, 0xdf, 0xc1, 0x76, 0x1a, + 0x5e, 0x2e, 0x3d, 0xc2, 0x28, 0xd7, 0x35, 0xc2, 0xa8, 0x24, 0xfd, 0x86, 0x79, 0xf4, 0x1b, 0x26, + 0xc2, 0xa5, 0x98, 0x2d, 0xba, 0x63, 0xaf, 0x8a, 0x66, 0xa1, 0x2d, 0xda, 0xf1, 0x5d, 0x7e, 0xca, + 0xb0, 0x1a, 0x45, 0x27, 0xf5, 0xf7, 0xf4, 0x39, 0x4c, 0x89, 0x68, 0x8d, 0x21, 0x11, 0x9d, 0x64, + 0xc6, 0x24, 0x6d, 0xc0, 0x20, 0x77, 0x77, 0xe2, 0xd9, 0xd6, 0xe8, 0xfc, 0x4d, 0xf1, 0x4d, 0x65, + 0x34, 0x50, 0xf8, 0x46, 0x71, 0x61, 0xe7, 0x43, 0x20, 0x44, 0x80, 0x2d, 0xa4, 0xcc, 0x7d, 0x06, + 0xa3, 0x1a, 0xc9, 0x49, 0xd6, 0x7e, 0xe5, 0x76, 0x65, 0xdb, 0xd1, 0xd6, 0x3e, 0xf7, 0xe0, 0x6a, + 0x6b, 0xbf, 0xf5, 0x01, 0x14, 0x93, 0xb5, 0x11, 0xae, 0xb6, 0x5e, 0x9e, 0x3d, 0x6b, 0x11, 0xa6, + 0x97, 0x69, 0x88, 0x03, 0x17, 0x3f, 0x22, 0x2d, 0xca, 0x2e, 0xf6, 0x9d, 0xc9, 0x59, 0x15, 0x81, + 0x6c, 0x80, 0x69, 0x5f, 0x69, 0x15, 0x66, 0x62, 0x52, 0x44, 0xf9, 0xef, 0xc3, 0x90, 0x00, 0xa9, + 0x19, 0x55, 0x84, 0xea, 0xd2, 0x3d, 0x81, 0xd8, 0x9d, 0xe7, 0xe3, 0x56, 0x48, 0xb6, 0x25, 0x83, + 0x75, 0x00, 0xe7, 0xd8, 0x32, 0x1b, 0x49, 0x55, 0xc3, 0xf1, 0x02, 0x8c, 0xb4, 0xd9, 0x46, 0x21, + 0x70, 0x7f, 0xc4, 0x87, 0xd1, 0x80, 0x3d, 0xcc, 0x00, 0x55, 0xf7, 0x47, 0x94, 0x5c, 0x02, 0x40, + 0x24, 0x36, 0x53, 0xcc, 0x02, 0x48, 0xce, 0x5d, 0x99, 0x04, 0x30, 0x46, 0x8f, 0x8f, 0x1b, 0x1b, + 0xff, 0xb6, 0x7c, 0x98, 0x4d, 0x94, 0x24, 0x1a, 0x70, 0x1b, 0x86, 0xe5, 0xfe, 0x38, 0x76, 0xc8, + 0xa0, 0xb7, 0xc0, 0x56, 0x44, 0xe4, 0x55, 0x98, 0x6c, 0xd1, 0x6f, 0xc2, 0x5a, 0xa2, 0x0e, 0xe3, + 0x0c, 0xbc, 0x25, 0xeb, 0x61, 0xfd, 0x02, 0x3a, 0x96, 0xab, 0x2d, 0xef, 0xe9, 0xa3, 0xa6, 0xf3, + 0x98, 0x26, 0x0a, 0xfe, 0x08, 0x86, 0xab, 0xbd, 0x0b, 0xe6, 0x9f, 0x8f, 0x2c, 0xdc, 0x56, 0x2c, + 0x56, 0x13, 0xe6, 0x58, 0x93, 0xaa, 0xe5, 0xf5, 0xb5, 0xd5, 0xc6, 0xd6, 0xb7, 0xad, 0xc0, 0x27, + 0x70, 0x21, 0xb5, 0xb4, 0x6f, 0x5b, 0x89, 0x7f, 0xd4, 0x0f, 0xb3, 0x7c, 0x31, 0x49, 0x8e, 0xe0, + 0x93, 0x4f, 0x35, 0x3f, 0x97, 0xf3, 0xde, 0x3b, 0x29, 0xe7, 0xbd, 0xc8, 0xa2, 0x9f, 0xf7, 0x1a, + 0xa7, 0xbc, 0xef, 0xa6, 0x9f, 0xf2, 0xa2, 0x13, 0xca, 0x3c, 0xe5, 0x8d, 0x9f, 0xed, 0x2e, 0x65, + 0x9f, 0xed, 0xe2, 0xc1, 0x53, 0xca, 0xd9, 0x6e, 0xda, 0x89, 0x6e, 0x2c, 0x50, 0x6a, 0xf8, 0xe5, + 0x06, 0x4a, 0xbd, 0x0a, 0x43, 0xe5, 0x76, 0x5b, 0x0b, 0x3c, 0xc4, 0xee, 0x71, 0xda, 0x6d, 0xae, + 0x3c, 0x89, 0x94, 0xf3, 0x3c, 0xa4, 0xcc, 0xf3, 0xef, 0x01, 0x2c, 0xe0, 0xf5, 0x08, 0xec, 0xb8, + 0x51, 0xa4, 0xc0, 0x1d, 0x3e, 0xbf, 0x34, 0x81, 0x1d, 0xa7, 0xbb, 0x57, 0x22, 0x62, 0xbe, 0xb1, + 0xb7, 0x76, 0xa1, 0x98, 0x1c, 0x3e, 0x2f, 0x61, 0xea, 0xfa, 0xc3, 0x1c, 0x5c, 0x12, 0x9b, 0x9c, + 0xd8, 0x07, 0x7e, 0xfa, 0xd1, 0xf9, 0x36, 0x8c, 0x09, 0xde, 0xed, 0xe8, 0x43, 0xe0, 0x07, 0xec, + 0x72, 0x32, 0xe6, 0x33, 0xba, 0x41, 0x46, 0xde, 0x86, 0x61, 0xfc, 0x23, 0x3a, 0x18, 0x62, 0x9a, + 0x19, 0x41, 0xd2, 0x5a, 0xfc, 0x78, 0x48, 0x91, 0x5a, 0x5f, 0xc3, 0xe5, 0xac, 0x8a, 0xbf, 0x04, + 0xbd, 0xfc, 0xeb, 0x1c, 0x5c, 0x10, 0xe2, 0x8d, 0xa9, 0xe2, 0xb9, 0x56, 0x9d, 0x53, 0x84, 0x2b, + 0xdf, 0x87, 0x51, 0x56, 0xa0, 0xac, 0x77, 0x9f, 0x58, 0x5a, 0x85, 0xe5, 0x10, 0x61, 0x16, 0x9d, + 0xd0, 0x11, 0xe1, 0x37, 0xce, 0x61, 0x53, 0x7a, 0x46, 0x6c, 0x9d, 0xd9, 0xfa, 0x12, 0x2e, 0xa6, + 0x37, 0xe1, 0x25, 0xe8, 0xe7, 0x3e, 0xcc, 0xa5, 0x2c, 0x0a, 0xcf, 0xb7, 0x26, 0x7f, 0x01, 0x17, + 0x52, 0x65, 0xbd, 0x84, 0x6a, 0xae, 0xb0, 0x1d, 0x47, 0xf8, 0x12, 0xba, 0xd0, 0x7a, 0x08, 0xe7, + 0x53, 0x24, 0xbd, 0x84, 0x2a, 0x2e, 0xc3, 0xac, 0xda, 0x69, 0xbf, 0x50, 0x0d, 0xd7, 0xe1, 0x12, + 0x17, 0xf4, 0x72, 0x7a, 0xe5, 0x01, 0x5c, 0x10, 0xe2, 0x5e, 0x82, 0xf6, 0x56, 0xe0, 0x62, 0x64, + 0x50, 0xa7, 0xec, 0x93, 0x4e, 0x3c, 0xc9, 0x58, 0x6b, 0x70, 0x25, 0x92, 0x94, 0xb1, 0x69, 0x38, + 0xb9, 0x34, 0xbe, 0x1d, 0x8c, 0x7a, 0xe9, 0xa5, 0xf4, 0xe8, 0x43, 0x38, 0x67, 0x08, 0x7d, 0x69, + 0x5b, 0xa5, 0x55, 0x98, 0xe2, 0x82, 0xcd, 0xad, 0xf3, 0xbc, 0xbe, 0x75, 0x1e, 0x9d, 0x3f, 0x1b, + 0x89, 0x44, 0xf0, 0xee, 0x9b, 0x29, 0xbb, 0xe9, 0x75, 0xdc, 0x4d, 0x4b, 0x92, 0xa8, 0x86, 0x6f, + 0xc3, 0x20, 0x87, 0x88, 0xfa, 0xa5, 0x08, 0xe3, 0xc6, 0x02, 0x67, 0x13, 0xc4, 0xd6, 0xf7, 0xe1, + 0x12, 0xb7, 0x44, 0xa3, 0x83, 0x4a, 0xd3, 0x5a, 0xfc, 0x28, 0x66, 0x88, 0x9e, 0x17, 0x72, 0xe3, + 0xf4, 0x19, 0xf6, 0xe8, 0x9e, 0x1c, 0xdb, 0x59, 0xf2, 0x4f, 0x74, 0x75, 0x4d, 0x1a, 0x98, 0xf9, + 0x54, 0x03, 0xf3, 0x1a, 0x5c, 0x55, 0x06, 0x66, 0xbc, 0x18, 0x39, 0xb4, 0xac, 0x2f, 0xe1, 0x02, + 0x6f, 0xa8, 0x0c, 0x29, 0x34, 0xab, 0xf1, 0x41, 0xac, 0x99, 0xb3, 0xa2, 0x99, 0x26, 0x75, 0x46, + 0x23, 0xff, 0x5e, 0x4e, 0x7e, 0x72, 0xe9, 0xc2, 0x7f, 0xde, 0x16, 0xf7, 0x06, 0x94, 0x94, 0x42, + 0xcc, 0x1a, 0x3d, 0x9f, 0xb9, 0xbd, 0x0e, 0x33, 0xba, 0x18, 0xb7, 0x4e, 0x77, 0xef, 0xe2, 0x09, + 0xd2, 0x5b, 0xec, 0xb3, 0x40, 0x80, 0x1c, 0x76, 0xc5, 0x14, 0xbd, 0x21, 0xbd, 0xad, 0x28, 0xad, + 0x1a, 0x5c, 0x4c, 0x76, 0x85, 0x5b, 0x97, 0xf7, 0x09, 0xc8, 0x27, 0xec, 0x13, 0x46, 0x88, 0xe8, + 0x8c, 0x4c, 0xa1, 0xf2, 0x3b, 0xe6, 0xec, 0x92, 0xcb, 0xb2, 0xe4, 0x54, 0x13, 0x6b, 0x3f, 0x2b, + 0x5d, 0x8e, 0x87, 0x1f, 0x03, 0x91, 0xa8, 0x85, 0xaa, 0x2d, 0x8b, 0x3e, 0x0f, 0x7d, 0x0b, 0x55, + 0x5b, 0x5c, 0x64, 0xc2, 0x9d, 0x60, 0x3d, 0xf0, 0x6d, 0x06, 0x8b, 0xef, 0xc8, 0xf3, 0x27, 0xd8, + 0x91, 0xdf, 0xef, 0x1f, 0xee, 0x2b, 0xf4, 0xdb, 0xa4, 0xea, 0xee, 0xb7, 0x1e, 0xba, 0xe1, 0x81, + 0x2a, 0xb0, 0x6c, 0x7d, 0x05, 0x53, 0x46, 0xf1, 0xe2, 0x2b, 0xee, 0x7a, 0x03, 0x8b, 0xed, 0x67, + 0x17, 0xca, 0x18, 0x56, 0x83, 0x2e, 0x8b, 0x31, 0x3e, 0xdf, 0xd4, 0x9d, 0x1a, 0x5e, 0xef, 0xb5, + 0x25, 0xd2, 0xfa, 0xfd, 0x7e, 0x4d, 0xba, 0x76, 0xaf, 0xad, 0x4b, 0xeb, 0xee, 0x02, 0xf0, 0x11, + 0xa2, 0x35, 0x8e, 0x6d, 0x00, 0x47, 0x45, 0xb4, 0x0a, 0x9f, 0x92, 0x6d, 0x8d, 0xe8, 0xa4, 0xf7, + 0xde, 0x44, 0xfc, 0x31, 0x67, 0x92, 0x57, 0x3d, 0x55, 0xfc, 0xb1, 0x10, 0x1d, 0xd8, 0x3a, 0x11, + 0xf9, 0x7e, 0xfc, 0x72, 0xc6, 0x00, 0x1e, 0x58, 0xbd, 0x22, 0x4f, 0xb0, 0x93, 0x6d, 0x3b, 0xdd, + 0xfd, 0x8c, 0xa7, 0x30, 0xc3, 0x78, 0xdd, 0x47, 0x68, 0x58, 0x2c, 0x7d, 0x13, 0xd2, 0x16, 0x9f, + 0xdb, 0x07, 0xb1, 0x9c, 0xeb, 0x5d, 0xca, 0x89, 0x88, 0x85, 0xff, 0x3d, 0x92, 0x53, 0xa3, 0x0a, + 0x67, 0xa7, 0xcb, 0xc7, 0x41, 0x64, 0xaf, 0x2d, 0xb5, 0x1a, 0x6d, 0xcf, 0x55, 0x06, 0x13, 0x1f, + 0x44, 0x7e, 0xb3, 0x46, 0x05, 0xdc, 0xd6, 0x89, 0xac, 0x57, 0xbb, 0x46, 0xb5, 0x0f, 0x43, 0xff, + 0xf6, 0xc2, 0xf6, 0x5a, 0x21, 0x67, 0xdd, 0x06, 0xd0, 0x4a, 0x02, 0x18, 0xdc, 0xd8, 0xb4, 0xd7, + 0xcb, 0x6b, 0x85, 0x33, 0x64, 0x06, 0xce, 0x3e, 0x5c, 0xdd, 0x58, 0xdc, 0x7c, 0x58, 0xad, 0x55, + 0xd7, 0xcb, 0xf6, 0xf6, 0x42, 0xd9, 0x5e, 0x2c, 0xe4, 0xac, 0xaf, 0x61, 0xda, 0x6c, 0xe1, 0x4b, + 0x1d, 0x84, 0x21, 0x4c, 0xa9, 0xfd, 0xcc, 0xfd, 0x87, 0xdb, 0x5a, 0x44, 0xab, 0x30, 0xfe, 0xe2, + 0x91, 0x59, 0xc2, 0x4c, 0x14, 0x9f, 0x91, 0x46, 0x44, 0x5e, 0xe7, 0xdb, 0x82, 0xf8, 0xcd, 0x65, + 0xb6, 0x2d, 0xa8, 0x45, 0xfb, 0x02, 0x9c, 0xfa, 0xbe, 0x07, 0xd3, 0x66, 0xa9, 0x27, 0xf5, 0x52, + 0xbd, 0x82, 0xa1, 0xbe, 0xda, 0xb5, 0x26, 0x42, 0xf4, 0x63, 0x03, 0x31, 0xb3, 0x7e, 0x0f, 0x0a, + 0x82, 0x2a, 0x5a, 0x79, 0xaf, 0x49, 0x37, 0x62, 0x2e, 0xe5, 0x12, 0xa6, 0x0c, 0x4a, 0xf7, 0xa0, + 0xc0, 0x66, 0x4c, 0xc1, 0xc9, 0x0b, 0x98, 0x86, 0x81, 0xb5, 0xe8, 0x38, 0xc7, 0xe6, 0x3f, 0xf0, + 0x76, 0x4f, 0xe8, 0xf8, 0xa1, 0x8c, 0x83, 0x1b, 0xb1, 0xd5, 0x6f, 0xf2, 0x3a, 0x0c, 0xde, 0x73, + 0x9b, 0xa1, 0x70, 0x8d, 0x44, 0x8b, 0x3c, 0x13, 0xcb, 0x11, 0xb6, 0x20, 0xb0, 0x6c, 0x38, 0xab, + 0x15, 0x78, 0x8a, 0xaa, 0x92, 0x22, 0x0c, 0x6d, 0xd0, 0x6f, 0xb4, 0xf2, 0xe5, 0x4f, 0xeb, 0x1d, + 0x38, 0x2b, 0x62, 0x0c, 0x35, 0x35, 0x5d, 0x15, 0x77, 0xc5, 0x73, 0xc6, 0x85, 0x55, 0x21, 0x12, + 0x51, 0x8c, 0x6f, 0xa7, 0xdd, 0x78, 0x4e, 0x3e, 0xb6, 0x50, 0x9c, 0x92, 0xef, 0x35, 0x79, 0x0a, + 0xd4, 0xab, 0x3b, 0xff, 0x56, 0x1e, 0x8a, 0x31, 0x2f, 0xc3, 0xc2, 0x81, 0xd3, 0x6c, 0xd2, 0xd6, + 0x3e, 0x25, 0x37, 0xa0, 0x7f, 0x7b, 0x73, 0x7b, 0x4b, 0x78, 0x49, 0x65, 0x74, 0x01, 0x03, 0x29, + 0x1a, 0x1b, 0x29, 0xc8, 0x03, 0x38, 0x2b, 0xa3, 0x88, 0x15, 0x4a, 0xf4, 0xd0, 0xa5, 0xee, 0x31, + 0xc9, 0x49, 0x3e, 0xf2, 0x96, 0x70, 0x89, 0xfc, 0xb0, 0xe3, 0xfa, 0xb4, 0x81, 0x9e, 0x9f, 0xe8, + 0xa8, 0x5e, 0xc3, 0xd8, 0x3a, 0x19, 0xf9, 0x1e, 0x8c, 0x55, 0xab, 0x9b, 0x51, 0xe9, 0x03, 0xc6, + 0x09, 0x91, 0x8e, 0xb2, 0x0d, 0x42, 0x7e, 0x25, 0xd8, 0xfa, 0xa3, 0x1c, 0xcc, 0x66, 0xb8, 0x5b, + 0xc8, 0xeb, 0x86, 0x1e, 0xa6, 0x34, 0x3d, 0x48, 0x92, 0x95, 0x33, 0x42, 0x11, 0x0b, 0x5a, 0x4c, + 0x76, 0xdf, 0x29, 0x62, 0xb2, 0x57, 0xce, 0x44, 0x71, 0xd8, 0xe4, 0x55, 0xe8, 0xab, 0x56, 0x37, + 0x85, 0x5b, 0x9d, 0x44, 0x2d, 0xd0, 0x88, 0x19, 0x41, 0x05, 0x60, 0x58, 0x82, 0xac, 0x49, 0x18, + 0x37, 0x3a, 0xc6, 0xb2, 0x60, 0x4c, 0xaf, 0x21, 0xeb, 0xfd, 0x05, 0xaf, 0xa1, 0x7a, 0x9f, 0xfd, + 0x6d, 0xfd, 0xd8, 0xd4, 0x19, 0xb9, 0x04, 0x20, 0xcf, 0x6b, 0xdd, 0x86, 0x3c, 0xf9, 0x11, 0x90, + 0xd5, 0x06, 0xb9, 0x0a, 0x63, 0x3e, 0x6d, 0xb8, 0x3e, 0xad, 0x87, 0xb5, 0x8e, 0x2f, 0x2e, 0xc6, + 0xd8, 0xa3, 0x12, 0xb6, 0xe3, 0x37, 0xc9, 0x77, 0x60, 0x90, 0x1f, 0x24, 0x8b, 0xd6, 0x4b, 0x23, + 0xa1, 0x5a, 0xdd, 0x5c, 0xbf, 0x57, 0xe6, 0x07, 0xdd, 0xb6, 0x20, 0xb1, 0x2a, 0x30, 0xaa, 0xb5, + 0xaa, 0x57, 0xe9, 0xd3, 0x30, 0xa0, 0x7b, 0x29, 0xf9, 0x0f, 0xeb, 0x37, 0x73, 0x30, 0x8d, 0xc3, + 0x60, 0xdf, 0x65, 0xcb, 0x43, 0xd4, 0x96, 0x79, 0xa3, 0xd3, 0x2e, 0x1a, 0x9d, 0x16, 0xa3, 0x55, + 0xbd, 0xf7, 0x7e, 0xa2, 0xf7, 0x2e, 0xa6, 0xf5, 0x1e, 0x4e, 0x01, 0xae, 0xd7, 0xd2, 0x3b, 0x4d, + 0x3f, 0xae, 0xfb, 0xed, 0x1c, 0x4c, 0x69, 0x75, 0x52, 0x0d, 0xbc, 0x6b, 0x54, 0xe9, 0x42, 0x4a, + 0x95, 0x12, 0xe3, 0xa9, 0x92, 0xa8, 0xd1, 0x2b, 0xdd, 0x6a, 0x94, 0x36, 0x9c, 0x8c, 0x61, 0xf2, + 0x97, 0x39, 0x98, 0x49, 0xd5, 0x01, 0x39, 0xc7, 0xf6, 0xff, 0x75, 0x9f, 0x86, 0x42, 0xf3, 0xe2, + 0x17, 0x83, 0xaf, 0x06, 0x41, 0x87, 0xfa, 0x42, 0xef, 0xe2, 0x17, 0x79, 0x05, 0xc6, 0xb7, 0xa8, + 0xef, 0x7a, 0x0d, 0x7e, 0x31, 0x81, 0x47, 0xfc, 0x8e, 0xdb, 0x26, 0x90, 0x5c, 0x84, 0x11, 0x15, + 0xb1, 0xca, 0x7d, 0xb8, 0x76, 0x04, 0x60, 0xb2, 0x17, 0xdd, 0x7d, 0x7e, 0xf0, 0xc3, 0x98, 0xc5, + 0x2f, 0x36, 0x01, 0x4b, 0x8f, 0xea, 0x20, 0x9f, 0x80, 0xa5, 0xbb, 0xf4, 0x1c, 0x0c, 0x7e, 0x66, + 0xe3, 0x38, 0xc6, 0x9c, 0x13, 0xb6, 0xf8, 0x45, 0x26, 0x30, 0xb4, 0x1c, 0xef, 0xc5, 0x60, 0x48, + 0xf9, 0xfb, 0x30, 0x9d, 0xa6, 0xd7, 0xb4, 0xaf, 0x40, 0xf0, 0xe6, 0x15, 0xef, 0x97, 0x30, 0x55, + 0x6e, 0x34, 0xa2, 0xe1, 0xca, 0x7b, 0x95, 0xcf, 0x13, 0xdc, 0xa7, 0x29, 0xb6, 0xb5, 0xfd, 0xab, + 0x2d, 0x37, 0xb4, 0xa7, 0x96, 0xbe, 0x71, 0x83, 0xd0, 0x6d, 0xed, 0x6b, 0x8e, 0x57, 0xfb, 0xdc, + 0x06, 0x7d, 0x9a, 0x32, 0x04, 0xd8, 0x8e, 0xc3, 0x94, 0xcd, 0xe1, 0x29, 0xc2, 0xa7, 0x35, 0xb1, + 0xd1, 0xd4, 0x35, 0x6b, 0xca, 0x8d, 0x10, 0x7d, 0xe5, 0xfa, 0x63, 0xeb, 0x7b, 0x70, 0x8e, 0x4f, + 0xfb, 0xdd, 0x2a, 0x2f, 0xaa, 0xad, 0xfb, 0x89, 0xad, 0x77, 0xa5, 0x27, 0xa7, 0x6b, 0xcd, 0xec, + 0x31, 0xa3, 0x2e, 0x58, 0xe4, 0x7f, 0xcd, 0xc1, 0x5c, 0x8c, 0xb5, 0xfa, 0xac, 0x55, 0x97, 0x6b, + 0xce, 0xab, 0xf1, 0xd0, 0x7d, 0xdc, 0x2b, 0x71, 0x07, 0xa9, 0xdb, 0x50, 0xd1, 0xfb, 0xe4, 0x36, + 0x00, 0x67, 0xd6, 0xb6, 0x38, 0x78, 0x3c, 0x20, 0xa2, 0x9c, 0x70, 0x93, 0xa3, 0x91, 0x90, 0x0e, + 0xa4, 0xe9, 0x5d, 0x7c, 0x23, 0xbd, 0xfc, 0xe7, 0x98, 0x67, 0x85, 0x0a, 0xf6, 0x5a, 0x86, 0x23, + 0x3d, 0x4d, 0xbe, 0xf5, 0xf7, 0xfb, 0x60, 0x56, 0xef, 0xc0, 0xe7, 0x69, 0xeb, 0x16, 0x8c, 0x2e, + 0x78, 0xad, 0x90, 0x7e, 0x13, 0x6a, 0x79, 0x2e, 0x88, 0x8a, 0x46, 0x50, 0x18, 0xb1, 0xbd, 0xe6, + 0x80, 0x1a, 0xdb, 0xeb, 0x19, 0xd1, 0x9a, 0x11, 0x21, 0x59, 0x80, 0xf1, 0x0d, 0xfa, 0x34, 0xa1, + 0x40, 0x8c, 0x18, 0x6d, 0xd1, 0xa7, 0x35, 0x4d, 0x89, 0x7a, 0x18, 0x9f, 0xc1, 0x43, 0xf6, 0x60, + 0x42, 0x0e, 0x2e, 0x43, 0x99, 0x73, 0xfa, 0xca, 0x6b, 0x0e, 0x67, 0x9e, 0x07, 0x82, 0x95, 0x90, + 0xa1, 0xc3, 0x98, 0x44, 0xd6, 0x74, 0x5e, 0x22, 0x4f, 0x6d, 0x60, 0x2e, 0xed, 0x1a, 0xc6, 0x88, + 0xc7, 0x8d, 0xa7, 0x34, 0xd0, 0x45, 0x58, 0x5b, 0x50, 0x4c, 0xf6, 0x87, 0x28, 0xed, 0x2d, 0x18, + 0xe4, 0x50, 0xb1, 0x55, 0x92, 0x29, 0x8c, 0x14, 0x35, 0xf7, 0x65, 0x34, 0xc4, 0xaa, 0xc4, 0x61, + 0xd6, 0x0a, 0xfa, 0x97, 0x14, 0x8d, 0xda, 0xac, 0xde, 0x89, 0x77, 0x2f, 0x86, 0x3a, 0xcb, 0xee, + 0xd5, 0x63, 0x71, 0xe4, 0x95, 0x94, 0x05, 0x74, 0xd1, 0xe9, 0x92, 0x44, 0xc5, 0x6e, 0xc2, 0x90, + 0x00, 0xc5, 0x92, 0x2b, 0x45, 0x9f, 0x9f, 0x24, 0xb0, 0xde, 0x87, 0xf3, 0xe8, 0x2f, 0x74, 0x5b, + 0xfb, 0x4d, 0xba, 0x13, 0x18, 0x97, 0x4a, 0x7a, 0x7d, 0xd6, 0x1f, 0xc2, 0x5c, 0x1a, 0x6f, 0xcf, + 0x2f, 0x9b, 0xa7, 0x3b, 0xf9, 0xf3, 0x3c, 0x4c, 0xaf, 0x06, 0xfa, 0x86, 0x4b, 0xa5, 0x3c, 0x49, + 0x49, 0xc3, 0x81, 0x3a, 0x59, 0x39, 0x93, 0x96, 0x66, 0xe3, 0x2d, 0xed, 0xba, 0x6b, 0xbe, 0x5b, + 0x7e, 0x0d, 0xb6, 0x6c, 0xa9, 0x0b, 0xaf, 0xaf, 0x42, 0xff, 0x06, 0x9b, 0xaa, 0xfb, 0x44, 0xdf, + 0x71, 0x0e, 0x06, 0xc2, 0xeb, 0xa6, 0x6c, 0x89, 0x64, 0x3f, 0xc8, 0xbd, 0xc4, 0xa5, 0xd6, 0xfe, + 0xde, 0xf9, 0x23, 0x56, 0xce, 0x24, 0xee, 0xb7, 0xbe, 0x03, 0xa3, 0xe5, 0xc6, 0x21, 0x0f, 0xc9, + 0xf4, 0x5a, 0xb1, 0xcf, 0x52, 0xc3, 0xac, 0x9c, 0xb1, 0x75, 0x42, 0x72, 0x9d, 0xdf, 0x6a, 0x18, + 0xcc, 0xc8, 0xa9, 0xc1, 0x36, 0x6b, 0xe5, 0x76, 0xbb, 0x32, 0x0c, 0x83, 0xfc, 0xa2, 0xa5, 0xf5, + 0x25, 0xcc, 0x89, 0x40, 0x1e, 0xee, 0x1d, 0xc5, 0x70, 0x9f, 0x20, 0x8a, 0xd5, 0xea, 0x16, 0x7c, + 0x73, 0x19, 0x00, 0x6d, 0xa1, 0xd5, 0x56, 0x83, 0x7e, 0x23, 0x22, 0x09, 0x35, 0x88, 0xf5, 0x36, + 0x8c, 0x28, 0x0d, 0xe1, 0x86, 0x5f, 0x5b, 0xec, 0x50, 0x5b, 0xd3, 0xc6, 0x2d, 0x5e, 0x79, 0x75, + 0xf7, 0xbc, 0xd1, 0x76, 0x91, 0x25, 0x87, 0x5b, 0x08, 0x2e, 0xcc, 0xc4, 0x06, 0x41, 0x94, 0x84, + 0x41, 0xed, 0xd1, 0x79, 0xa8, 0xa3, 0xfa, 0x1d, 0xdf, 0xc2, 0xe7, 0x4f, 0xb4, 0x85, 0xb7, 0xfe, + 0x45, 0x1e, 0x8d, 0xcb, 0x84, 0x3e, 0x62, 0x7e, 0x3a, 0xdd, 0x57, 0x58, 0x81, 0x11, 0x6c, 0xfd, + 0xa2, 0xbc, 0x30, 0xd8, 0x3d, 0x0e, 0x65, 0xf8, 0x27, 0x47, 0xa5, 0x33, 0x18, 0x7c, 0x12, 0xb1, + 0x91, 0x8f, 0x61, 0x68, 0xa9, 0xd5, 0x40, 0x09, 0x7d, 0xa7, 0x90, 0x20, 0x99, 0x58, 0x9f, 0x60, + 0x95, 0xb7, 0xd9, 0x27, 0xcc, 0xdd, 0x3b, 0xb6, 0x06, 0x89, 0xac, 0xdc, 0x81, 0x2c, 0x2b, 0x77, + 0x30, 0x66, 0xe5, 0x5a, 0x30, 0xb0, 0xe9, 0x37, 0x44, 0x6e, 0x9b, 0x89, 0xf9, 0x31, 0xa1, 0x38, + 0x84, 0xd9, 0x1c, 0x65, 0xfd, 0xf7, 0x1c, 0xcc, 0x2e, 0xd3, 0x30, 0x75, 0x0c, 0x19, 0x5a, 0xc9, + 0xbd, 0xb0, 0x56, 0xf2, 0xcf, 0xa3, 0x15, 0xd5, 0xea, 0xbe, 0xac, 0x56, 0xf7, 0x67, 0xb5, 0x7a, + 0x20, 0xbb, 0xd5, 0xcb, 0x30, 0xc8, 0x9b, 0xca, 0x2c, 0xf9, 0xd5, 0x90, 0x1e, 0x46, 0x96, 0xbc, + 0x1e, 0x45, 0x67, 0x73, 0x1c, 0xdb, 0x48, 0xae, 0x39, 0x81, 0x6e, 0xc9, 0x8b, 0x9f, 0xd6, 0x0f, + 0xf0, 0xaa, 0xf1, 0x9a, 0x57, 0x7f, 0xac, 0x79, 0x84, 0x87, 0xf8, 0x17, 0x1a, 0x3f, 0x41, 0x60, + 0x54, 0x1c, 0x63, 0x4b, 0x0a, 0x72, 0x05, 0x46, 0x57, 0x5b, 0xf7, 0x3c, 0xbf, 0x4e, 0x37, 0x5b, + 0x4d, 0x2e, 0x7d, 0xd8, 0xd6, 0x41, 0xc2, 0x53, 0x22, 0x4a, 0x88, 0xdc, 0x0f, 0x08, 0x88, 0xb9, + 0x1f, 0x18, 0x6c, 0x77, 0xde, 0xe6, 0x38, 0xe1, 0x88, 0x61, 0x7f, 0x77, 0xb3, 0xdc, 0x95, 0x89, + 0xdf, 0x8b, 0x70, 0x0f, 0xce, 0xdb, 0xb4, 0xdd, 0x74, 0xd8, 0x9e, 0xee, 0xd0, 0xe3, 0xf4, 0xaa, + 0xcd, 0x57, 0x52, 0xae, 0x09, 0x9a, 0x31, 0x15, 0xaa, 0xca, 0xf9, 0x2e, 0x55, 0x3e, 0x84, 0xab, + 0xcb, 0x34, 0x34, 0x27, 0xd4, 0xc8, 0xdf, 0x2c, 0x1a, 0xbf, 0x02, 0xc3, 0x81, 0xe9, 0x2b, 0x97, + 0xd7, 0xde, 0x52, 0x19, 0x77, 0xdf, 0x94, 0xa7, 0x49, 0x42, 0x8e, 0xfa, 0xcb, 0xfa, 0x04, 0x4a, + 0x59, 0xc5, 0x9d, 0x2c, 0xe4, 0xd5, 0x85, 0x2b, 0xd9, 0x02, 0x44, 0x75, 0x97, 0x40, 0xfa, 0xd5, + 0xc5, 0x27, 0xd4, 0xab, 0xb6, 0xa6, 0x2b, 0x5e, 0xfc, 0x61, 0x55, 0x64, 0xf0, 0xdf, 0x0b, 0x54, + 0xb7, 0x86, 0x47, 0xd6, 0xa6, 0x80, 0x48, 0xaf, 0x65, 0x18, 0x96, 0x30, 0xa1, 0xd7, 0xd9, 0xd4, + 0x9a, 0x4a, 0x85, 0x36, 0xa4, 0x00, 0xc5, 0x66, 0xfd, 0x40, 0x1e, 0xdf, 0x98, 0x1c, 0x27, 0xbb, + 0x37, 0x7b, 0x92, 0xf3, 0x1a, 0xcb, 0x83, 0xf3, 0xa6, 0x6c, 0xdd, 0x2d, 0x5f, 0xd0, 0xdc, 0xf2, + 0xdc, 0x1b, 0x7f, 0xc5, 0x74, 0x13, 0x0b, 0x4f, 0x83, 0x06, 0x22, 0x97, 0x75, 0xe7, 0xfb, 0x58, + 0xf2, 0x22, 0xee, 0x1d, 0x98, 0x4b, 0x2b, 0x50, 0xb3, 0x03, 0x95, 0x87, 0x57, 0xec, 0x77, 0x16, + 0xe1, 0xb2, 0xcc, 0x2e, 0xe5, 0x79, 0x61, 0x10, 0xfa, 0x4e, 0xbb, 0x5a, 0xf7, 0xdd, 0x76, 0xc4, + 0x65, 0xc1, 0x20, 0x87, 0x08, 0x4d, 0xf0, 0xa3, 0x30, 0x4e, 0x23, 0x30, 0xd6, 0xaf, 0xe4, 0xc0, + 0x32, 0xe2, 0xb4, 0xb0, 0x9f, 0xb7, 0x7c, 0xef, 0x89, 0xdb, 0xd0, 0x8e, 0x9f, 0x5e, 0x37, 0x5c, + 0x9f, 0xfc, 0x4e, 0x62, 0x3c, 0x44, 0x5c, 0xcc, 0x99, 0x77, 0x62, 0xee, 0x48, 0xbe, 0xf1, 0xc4, + 0xd8, 0x2d, 0xf3, 0x42, 0x84, 0x72, 0x53, 0xfe, 0xcf, 0x1c, 0x5c, 0xeb, 0x5a, 0x07, 0xd1, 0x9e, + 0x3d, 0x28, 0xc4, 0x71, 0x62, 0x04, 0x95, 0xb4, 0xb8, 0x8d, 0xa4, 0x84, 0xdd, 0xbb, 0x3c, 0x0e, + 0x5d, 0xc6, 0x37, 0xb5, 0x95, 0xe4, 0x84, 0xbc, 0xd3, 0xd7, 0x1e, 0xf3, 0x57, 0x78, 0xa1, 0xd3, + 0x5c, 0x40, 0x07, 0x40, 0x5f, 0x74, 0xa7, 0x20, 0x64, 0xd0, 0x5a, 0x3c, 0x4d, 0x86, 0x46, 0x6c, + 0x7d, 0x8a, 0xdf, 0x75, 0x7a, 0xa5, 0x4f, 0xf6, 0xa9, 0x2d, 0xc0, 0xb5, 0x58, 0xec, 0xc0, 0x73, + 0x08, 0x09, 0x61, 0x86, 0xa9, 0x9f, 0xed, 0xbd, 0x97, 0x7d, 0xaf, 0xd3, 0xfe, 0xf9, 0xf4, 0xfa, + 0x1f, 0xe7, 0x78, 0x30, 0xa7, 0x5e, 0xac, 0xe8, 0xe8, 0x05, 0x80, 0x08, 0x1a, 0x0b, 0xea, 0x57, + 0x88, 0xdd, 0xbb, 0xdc, 0xe4, 0xc6, 0x53, 0x85, 0x7d, 0x2e, 0x40, 0x63, 0xfb, 0xf9, 0xf6, 0xe4, + 0x9b, 0x18, 0x30, 0xa0, 0x4a, 0x3f, 0x99, 0xde, 0xdf, 0x91, 0xfe, 0x8f, 0x53, 0xf2, 0x1d, 0xc0, + 0x34, 0x9b, 0x01, 0xca, 0x9d, 0xf0, 0xc0, 0xf3, 0xdd, 0x50, 0x5e, 0x4f, 0x21, 0x5b, 0x22, 0x23, + 0x00, 0xe7, 0xfa, 0xf0, 0x67, 0x47, 0xa5, 0x77, 0x4f, 0x93, 0xf7, 0x53, 0xca, 0xdc, 0x56, 0x59, + 0x04, 0xac, 0x59, 0xe8, 0x5b, 0xb0, 0xd7, 0x70, 0xc2, 0xb3, 0xd7, 0xd4, 0x84, 0x67, 0xaf, 0x59, + 0x7f, 0x95, 0x87, 0x12, 0xcf, 0x59, 0x82, 0x71, 0x26, 0x91, 0xd7, 0x42, 0x0b, 0x5c, 0x39, 0xa9, + 0x83, 0x21, 0x96, 0x93, 0x24, 0x7f, 0x92, 0x9c, 0x24, 0xbf, 0x04, 0x19, 0x2e, 0xab, 0x13, 0x78, + 0x01, 0x5e, 0x3b, 0x3e, 0x2a, 0x5d, 0x8b, 0xbc, 0x00, 0x1c, 0x9b, 0xe6, 0x0e, 0xc8, 0x28, 0x22, + 0xe9, 0xbf, 0xe8, 0x7f, 0x0e, 0xff, 0xc5, 0x1d, 0x18, 0x42, 0x63, 0x66, 0x75, 0x4b, 0x44, 0x7e, + 0xe2, 0xf0, 0xc4, 0x0c, 0x45, 0x35, 0x57, 0x4f, 0x07, 0x28, 0xc9, 0xac, 0x7f, 0x94, 0x87, 0x2b, + 0xd9, 0x3a, 0x17, 0x75, 0x5b, 0x04, 0x88, 0x22, 0x5c, 0xba, 0x45, 0xd4, 0xe0, 0xb7, 0xf3, 0x94, + 0xee, 0xa9, 0x88, 0x36, 0x8d, 0x8f, 0xed, 0x7d, 0xe4, 0x4d, 0xeb, 0xd8, 0x71, 0x8a, 0x71, 0x01, + 0x5b, 0x64, 0xb3, 0x15, 0x20, 0x23, 0x9b, 0xad, 0x80, 0x91, 0x3d, 0x98, 0xdd, 0xf2, 0xdd, 0x27, + 0x4e, 0x48, 0x1f, 0xd0, 0x67, 0xfc, 0xb2, 0xd0, 0x92, 0xb8, 0x21, 0xc4, 0xaf, 0xcf, 0xdf, 0x38, + 0x3e, 0x2a, 0xbd, 0xd2, 0xe6, 0x24, 0x98, 0xb1, 0x8c, 0xdf, 0xfd, 0xac, 0x25, 0x2f, 0x0d, 0x65, + 0x09, 0xb2, 0xfe, 0x6d, 0x0e, 0x2e, 0xe0, 0xb6, 0x5c, 0xb8, 0x5d, 0x65, 0xe1, 0xcf, 0x15, 0x58, + 0xa9, 0x37, 0x50, 0x8c, 0x45, 0x0c, 0xac, 0x34, 0x6e, 0xa2, 0xdb, 0x06, 0x19, 0x59, 0x85, 0x51, + 0xf1, 0x1b, 0xbf, 0xbf, 0x3e, 0x34, 0x08, 0x66, 0xb4, 0x09, 0x0b, 0x87, 0x3a, 0x77, 0x15, 0xe1, + 0xc0, 0x16, 0xc2, 0xf0, 0xc2, 0xa6, 0xad, 0xf3, 0x5a, 0x3f, 0xcd, 0xc3, 0xc5, 0x5d, 0xea, 0xbb, + 0x8f, 0x9e, 0x65, 0x34, 0x66, 0x13, 0xa6, 0x25, 0x88, 0xe7, 0x2d, 0x31, 0x3e, 0x31, 0x9e, 0xcf, + 0x52, 0x56, 0x55, 0x24, 0x3e, 0x91, 0x5f, 0x5c, 0x2a, 0xe3, 0x29, 0x42, 0x26, 0xdf, 0x82, 0xe1, + 0x58, 0xe6, 0x20, 0xec, 0x7f, 0xf9, 0x85, 0x46, 0x5d, 0xb5, 0x72, 0xc6, 0x56, 0x94, 0xe4, 0xd7, + 0xb2, 0x8f, 0xaa, 0x84, 0xeb, 0xa3, 0x97, 0xff, 0x13, 0x3f, 0x58, 0xf6, 0xb1, 0x3a, 0x1a, 0x36, + 0xe5, 0x83, 0x5d, 0x39, 0x63, 0x67, 0x95, 0x54, 0x19, 0x85, 0x91, 0x32, 0x9e, 0xdb, 0x31, 0xcb, + 0xfd, 0x7f, 0xe4, 0xe1, 0xb2, 0xbc, 0xf8, 0x93, 0xa1, 0xe6, 0xcf, 0x61, 0x56, 0x82, 0xca, 0x6d, + 0xb6, 0x61, 0xa0, 0x0d, 0x53, 0xd3, 0x3c, 0xa7, 0xac, 0xd4, 0xb4, 0x23, 0x68, 0x22, 0x65, 0x67, + 0xb1, 0xbf, 0x1c, 0xef, 0xe7, 0xc7, 0x69, 0x79, 0x9c, 0xd0, 0x0b, 0xa9, 0xcf, 0x99, 0x86, 0x6a, + 0x8c, 0xf9, 0xb3, 0x91, 0xf0, 0x9e, 0xf6, 0xbf, 0xa8, 0xf7, 0x74, 0xe5, 0x4c, 0xdc, 0x7f, 0x5a, + 0x99, 0x80, 0xb1, 0x0d, 0xfa, 0x34, 0xd2, 0xfb, 0xff, 0x9f, 0x8b, 0xa5, 0x7a, 0x60, 0x3b, 0x0c, + 0x9e, 0xf3, 0x21, 0x17, 0xa5, 0x02, 0xc2, 0x54, 0x0f, 0xfa, 0x0e, 0x83, 0x93, 0xae, 0xc2, 0x10, + 0x3f, 0xcc, 0x6e, 0x9c, 0xc0, 0xc2, 0x57, 0x37, 0x78, 0xf8, 0xb5, 0xca, 0x06, 0x37, 0xf6, 0x05, + 0xbf, 0xf5, 0x00, 0xae, 0x8a, 0x18, 0x6f, 0xb3, 0xf3, 0xb1, 0xa0, 0x53, 0x2e, 0x5f, 0x96, 0x03, + 0x97, 0x97, 0x69, 0x7c, 0xea, 0x31, 0x6e, 0x38, 0x7d, 0x02, 0x93, 0x06, 0x5c, 0x49, 0xc4, 0x5d, + 0xa9, 0x1a, 0x43, 0x4a, 0x74, 0x9c, 0xda, 0xba, 0x92, 0x56, 0x84, 0x5e, 0x59, 0x8b, 0x62, 0x72, + 0x58, 0x3f, 0x3a, 0x62, 0x0b, 0x4e, 0x31, 0xeb, 0xdd, 0xd0, 0xbe, 0x6b, 0x3e, 0xe3, 0xf1, 0xec, + 0x81, 0x72, 0xe5, 0x55, 0x58, 0x6b, 0xdc, 0x38, 0x0b, 0xb0, 0x26, 0x60, 0x4c, 0xa2, 0x9a, 0x34, + 0x08, 0xac, 0xff, 0x34, 0x00, 0x96, 0x50, 0x6c, 0xda, 0x09, 0xbd, 0xd4, 0xc7, 0x5e, 0xa2, 0xb2, + 0x62, 0xa1, 0x3a, 0xa7, 0xe7, 0x24, 0x8d, 0xb0, 0x7c, 0xe4, 0xe1, 0x3e, 0xaf, 0x1e, 0x41, 0x8d, + 0x91, 0x97, 0x68, 0xfd, 0x57, 0x19, 0xd3, 0x24, 0xff, 0xd8, 0xf0, 0xca, 0x76, 0xc6, 0x34, 0x69, + 0xc8, 0x4d, 0x9f, 0x32, 0x6d, 0xf3, 0x48, 0xa4, 0xef, 0x79, 0x8e, 0x44, 0xd8, 0x17, 0xa9, 0x1f, + 0x8a, 0xec, 0x98, 0xba, 0x14, 0xdf, 0xa3, 0x3c, 0xbd, 0xd7, 0x51, 0x22, 0xe3, 0x82, 0x06, 0x31, + 0xa4, 0x1a, 0x62, 0x88, 0x0b, 0x05, 0xcd, 0x67, 0xb9, 0x70, 0x40, 0xeb, 0x8f, 0x85, 0xaf, 0x58, + 0x1e, 0xe8, 0xa6, 0xf9, 0xcc, 0x79, 0x7e, 0x6a, 0xfe, 0x9d, 0x73, 0x44, 0xad, 0xce, 0x58, 0xf5, + 0x8c, 0x11, 0x71, 0xb1, 0xe4, 0x47, 0x30, 0xa5, 0xba, 0x3a, 0x16, 0xa2, 0x35, 0x3a, 0xff, 0x4a, + 0x94, 0xca, 0xf4, 0xf0, 0x91, 0x73, 0xeb, 0xc9, 0xdd, 0x5b, 0x29, 0xb4, 0x3c, 0x11, 0x41, 0x5d, + 0x22, 0xb4, 0xf8, 0x2c, 0xfd, 0xa0, 0x2b, 0x85, 0x91, 0x7c, 0x01, 0xd3, 0xd5, 0xea, 0x26, 0xbf, + 0xcc, 0x61, 0xcb, 0x03, 0x7e, 0x7b, 0x4d, 0x04, 0x6c, 0x61, 0x77, 0x07, 0x81, 0x57, 0x13, 0x97, + 0x40, 0xf4, 0xb0, 0x00, 0x3d, 0x15, 0x43, 0x9a, 0x08, 0xfd, 0xa4, 0xfc, 0x1f, 0xaa, 0xbb, 0x0a, + 0x6c, 0x2b, 0xe2, 0x36, 0xa9, 0xb8, 0x74, 0x24, 0x07, 0x76, 0xc6, 0x29, 0x5f, 0xee, 0x5b, 0x3e, + 0xe5, 0xfb, 0x83, 0xbc, 0xbc, 0xa1, 0x91, 0x3c, 0x68, 0x3d, 0xf5, 0x61, 0x5f, 0x6a, 0x0b, 0x4e, + 0xb4, 0x4e, 0xa7, 0x56, 0x8e, 0x54, 0xe4, 0x51, 0xa9, 0x4a, 0x56, 0x36, 0xa1, 0x8e, 0x1d, 0x22, + 0x84, 0x71, 0x7a, 0x8a, 0xbb, 0x22, 0x8d, 0x2b, 0x7e, 0x0e, 0xd7, 0xf7, 0xe2, 0xe7, 0x70, 0x3f, + 0x86, 0x19, 0x79, 0x35, 0x6a, 0x81, 0xb6, 0x42, 0xea, 0xcb, 0x13, 0xfb, 0x89, 0x28, 0xe9, 0x1b, + 0xa6, 0xf7, 0x2b, 0x40, 0x5f, 0xd9, 0xde, 0x10, 0x1e, 0x1d, 0xf6, 0x27, 0xb9, 0x62, 0x06, 0xc4, + 0xf1, 0x3b, 0x6f, 0x46, 0xf8, 0xdb, 0x15, 0x56, 0x5d, 0xee, 0x67, 0x71, 0x65, 0xaa, 0x3e, 0x5b, + 0x07, 0x59, 0x0b, 0x70, 0xc1, 0x2c, 0x7e, 0x8b, 0xfa, 0x87, 0x2e, 0xee, 0xbd, 0xab, 0x34, 0x94, + 0x85, 0xe6, 0xa2, 0x42, 0x89, 0x1e, 0x50, 0x2d, 0xcc, 0xc0, 0xff, 0x9d, 0x87, 0x52, 0x6a, 0x23, + 0xca, 0x41, 0xe0, 0xee, 0xb7, 0x30, 0x83, 0xc6, 0x45, 0xe8, 0x7f, 0xe0, 0xb6, 0x1a, 0xba, 0x21, + 0xf9, 0xd8, 0x6d, 0x35, 0x6c, 0x84, 0x32, 0x1b, 0xa4, 0xda, 0xd9, 0x43, 0x02, 0xcd, 0x44, 0x0e, + 0x3a, 0x7b, 0x35, 0x46, 0xa4, 0xdb, 0x20, 0x82, 0x8c, 0x5c, 0x87, 0x21, 0x99, 0x6d, 0xad, 0x2f, + 0xf2, 0x9e, 0xc9, 0x34, 0x6b, 0x12, 0x47, 0x3e, 0x82, 0xe1, 0x75, 0x1a, 0x3a, 0x0d, 0x27, 0x74, + 0xc4, 0xd8, 0x91, 0x0f, 0x61, 0x48, 0x70, 0xa5, 0x20, 0x56, 0xe8, 0xe1, 0x43, 0x01, 0xb1, 0x15, + 0x0b, 0x2a, 0xd0, 0x0d, 0xda, 0x4d, 0xe7, 0x99, 0x0a, 0x26, 0x65, 0x0a, 0x8c, 0x40, 0xe4, 0x1d, + 0x33, 0xe4, 0x22, 0x3a, 0x3e, 0x4b, 0x55, 0x48, 0x14, 0x90, 0xb1, 0x82, 0x61, 0x20, 0x91, 0xaa, + 0x45, 0x36, 0x41, 0x2b, 0x95, 0xdb, 0xa0, 0xb4, 0x4d, 0x46, 0xeb, 0xb7, 0x46, 0xe1, 0xec, 0x96, + 0xb3, 0xef, 0xb6, 0xd8, 0x8e, 0xc2, 0xa6, 0x81, 0xd7, 0xf1, 0xeb, 0x94, 0x94, 0x61, 0xc2, 0x0c, + 0xe0, 0xee, 0x11, 0x9e, 0xce, 0x36, 0x4d, 0x26, 0x8c, 0xcc, 0xc3, 0x88, 0xba, 0x34, 0x2e, 0x76, + 0x3a, 0x29, 0x97, 0xc9, 0x57, 0xce, 0xd8, 0x11, 0x19, 0x79, 0xcf, 0x38, 0x7c, 0x9c, 0x54, 0xf9, + 0x0f, 0x90, 0x76, 0x9e, 0x47, 0xd8, 0xb6, 0xbc, 0x86, 0xb9, 0x5b, 0xe3, 0x27, 0x6c, 0x3f, 0x48, + 0x9c, 0x47, 0x0e, 0x18, 0x35, 0x4e, 0x38, 0x65, 0x71, 0xa3, 0x9a, 0x99, 0xbd, 0x3e, 0xe5, 0xa4, + 0xf2, 0x4b, 0x18, 0x7d, 0xd0, 0xd9, 0xa3, 0xf2, 0xe4, 0x75, 0x50, 0x6c, 0xde, 0xe2, 0xd7, 0x12, + 0x04, 0x7e, 0xf7, 0x4d, 0xfe, 0x15, 0x3f, 0xee, 0xec, 0xd1, 0xe4, 0xb3, 0x08, 0x6c, 0xd5, 0xd4, + 0x84, 0x91, 0x03, 0x28, 0xc4, 0x6f, 0x10, 0x88, 0x2e, 0xed, 0x72, 0xef, 0x01, 0x13, 0xfd, 0x68, + 0x8f, 0x2f, 0xf0, 0xb8, 0x66, 0xa3, 0x90, 0x84, 0x54, 0xf2, 0x63, 0x98, 0x49, 0x75, 0x89, 0xab, + 0x3b, 0x90, 0xdd, 0xbd, 0xed, 0xb8, 0x04, 0xc5, 0xb4, 0x26, 0x2f, 0x5c, 0x1a, 0x25, 0xa7, 0x97, + 0x42, 0x1a, 0x30, 0x19, 0x8b, 0x8c, 0x17, 0x2f, 0xcc, 0x64, 0xc7, 0xda, 0xe3, 0xae, 0x49, 0x26, + 0x69, 0x4e, 0x2d, 0x2b, 0x2e, 0x92, 0xac, 0xc1, 0x88, 0xf2, 0x45, 0x89, 0xdc, 0x7c, 0x69, 0x7e, + 0xb7, 0xe2, 0xf1, 0x51, 0x69, 0x3a, 0xf2, 0xbb, 0x19, 0x32, 0x23, 0x01, 0xe4, 0x97, 0xe1, 0xaa, + 0x1a, 0xa2, 0x9b, 0x7e, 0xba, 0x87, 0x52, 0x3c, 0xee, 0x70, 0x33, 0x3e, 0xc2, 0xb3, 0xe8, 0x77, + 0xef, 0x56, 0xf2, 0xc5, 0xdc, 0xca, 0x19, 0xbb, 0xb7, 0x68, 0xf2, 0xab, 0x39, 0x38, 0x97, 0x51, + 0xea, 0x18, 0x96, 0xda, 0xd3, 0x6d, 0x8c, 0x96, 0x27, 0xde, 0xfb, 0x73, 0x1b, 0xd1, 0xfd, 0x58, + 0xe9, 0x3f, 0x36, 0xda, 0x9d, 0x51, 0x12, 0xb9, 0x03, 0xb0, 0xef, 0x86, 0x62, 0x8c, 0x61, 0x9a, + 0xba, 0xe4, 0x07, 0xca, 0xd4, 0xb6, 0xef, 0x86, 0x62, 0xa4, 0xfd, 0x7e, 0xae, 0xe7, 0xbc, 0x8e, + 0xd9, 0xeb, 0x46, 0xe7, 0x5f, 0xed, 0x36, 0xe9, 0x45, 0xd4, 0x95, 0x3b, 0xc7, 0x47, 0xa5, 0x37, + 0x54, 0x0a, 0xb4, 0x3a, 0x52, 0xc9, 0x5b, 0xbe, 0x35, 0x47, 0xd1, 0x19, 0xed, 0xe9, 0xb9, 0xb4, + 0xbc, 0x01, 0x83, 0xe8, 0x99, 0x0a, 0x8a, 0xe3, 0x68, 0xbb, 0x61, 0xe2, 0x2e, 0xf4, 0x5f, 0xe9, + 0xbb, 0x35, 0x41, 0x43, 0x56, 0x98, 0x0d, 0x84, 0xbb, 0x45, 0x69, 0xb3, 0x88, 0x34, 0x7f, 0xc2, + 0x8e, 0xe6, 0x28, 0x99, 0x7f, 0xc7, 0x78, 0x9e, 0xc4, 0x64, 0xab, 0x00, 0x0c, 0xfb, 0x62, 0xba, + 0xbd, 0xdf, 0x3f, 0xdc, 0x5f, 0x18, 0xe0, 0x33, 0x82, 0xbc, 0x4b, 0xf2, 0xeb, 0xc3, 0xfc, 0xe2, + 0xf9, 0x4e, 0xcb, 0x7d, 0xe4, 0x46, 0x33, 0xb3, 0xee, 0xd3, 0x8e, 0xde, 0x09, 0x13, 0x16, 0x67, + 0xc6, 0x8b, 0x60, 0xca, 0xfd, 0x9d, 0xef, 0xe9, 0xfe, 0x7e, 0x53, 0x3b, 0x28, 0xd6, 0xd2, 0xf9, + 0x72, 0xcb, 0xc2, 0x74, 0x37, 0x47, 0x27, 0xc8, 0x5f, 0xc3, 0x20, 0x66, 0xe0, 0xe5, 0xa7, 0xf0, + 0xa3, 0xf3, 0xb7, 0x44, 0x77, 0x76, 0xa9, 0x3e, 0x4f, 0xd9, 0x2b, 0x92, 0x49, 0x70, 0x8d, 0x23, + 0xc0, 0xd0, 0x38, 0x42, 0xc8, 0x36, 0x4c, 0x6d, 0xb1, 0x8d, 0x2e, 0xbf, 0xd1, 0xd0, 0xf6, 0x85, + 0x4b, 0x90, 0x3b, 0x1b, 0x71, 0xa3, 0xdd, 0x96, 0xe8, 0x1a, 0x55, 0x78, 0x7d, 0xaf, 0x99, 0xc2, + 0x4e, 0x96, 0x60, 0xa2, 0x4a, 0x1d, 0xbf, 0x7e, 0xf0, 0x80, 0x3e, 0x63, 0x46, 0x86, 0xf1, 0x34, + 0x4e, 0x80, 0x18, 0xd6, 0x5e, 0x44, 0xe9, 0x91, 0x55, 0x26, 0x13, 0xf9, 0x14, 0x06, 0xab, 0x9e, + 0x1f, 0x56, 0x9e, 0x89, 0xd9, 0x5a, 0x9e, 0xd3, 0x72, 0x60, 0xe5, 0xbc, 0x7c, 0x1e, 0x28, 0xf0, + 0xfc, 0xb0, 0xb6, 0x67, 0x64, 0x82, 0xe3, 0x24, 0xe4, 0x19, 0x4c, 0x9b, 0x33, 0xa5, 0x08, 0xb4, + 0x1f, 0x16, 0xc6, 0x4d, 0xda, 0x74, 0xcc, 0x49, 0x2a, 0x37, 0x84, 0xf4, 0x2b, 0xf1, 0xf9, 0xf8, + 0x11, 0xe2, 0x75, 0x8b, 0x20, 0x8d, 0x9f, 0xac, 0xe3, 0xbb, 0x4a, 0xbc, 0x45, 0xe5, 0x80, 0x07, + 0xe8, 0x8f, 0x44, 0xb9, 0x06, 0x3b, 0x38, 0xdb, 0xa2, 0x26, 0x9c, 0x20, 0xfe, 0x18, 0x97, 0x9d, + 0x60, 0x25, 0x5b, 0x70, 0x76, 0x27, 0xa0, 0x5b, 0x3e, 0x7d, 0xe2, 0xd2, 0xa7, 0x52, 0x1e, 0x44, + 0x89, 0xd9, 0x98, 0xbc, 0x36, 0xc7, 0xa6, 0x09, 0x4c, 0x32, 0x93, 0xf7, 0x00, 0xb6, 0xdc, 0x56, + 0x8b, 0x36, 0xf0, 0xb0, 0x7f, 0x14, 0x45, 0xe1, 0x41, 0x46, 0x1b, 0xa1, 0x35, 0xaf, 0xd5, 0xd4, + 0x55, 0xaa, 0x11, 0x93, 0x0a, 0x8c, 0xaf, 0xb6, 0xea, 0xcd, 0x8e, 0x08, 0xca, 0x09, 0x70, 0xa6, + 0x14, 0x09, 0x23, 0x5d, 0x8e, 0xa8, 0x25, 0x3e, 0x72, 0x93, 0x85, 0x3c, 0x00, 0x22, 0x00, 0x62, + 0xd4, 0x3a, 0x7b, 0x4d, 0x2a, 0x3e, 0x77, 0x74, 0x50, 0x4a, 0x41, 0x38, 0xdc, 0x8d, 0x3c, 0x8c, + 0x09, 0xb6, 0xb9, 0xf7, 0x60, 0x54, 0x1b, 0xf3, 0x29, 0xd9, 0x51, 0xa6, 0xf5, 0xec, 0x28, 0x23, + 0x7a, 0x16, 0x94, 0x7f, 0x9a, 0x83, 0x8b, 0xe9, 0xdf, 0x92, 0xb0, 0x4d, 0x36, 0x61, 0x44, 0x01, + 0xd5, 0x7d, 0x38, 0x69, 0x70, 0xc7, 0xb6, 0x76, 0xfc, 0x83, 0x96, 0x33, 0x8f, 0xde, 0xfa, 0x48, + 0xc6, 0x73, 0x9c, 0x82, 0xfd, 0xed, 0x61, 0x98, 0xc6, 0x7b, 0x1f, 0xf1, 0x79, 0xea, 0x13, 0xcc, + 0x72, 0x84, 0x30, 0xed, 0x50, 0x47, 0xf8, 0x77, 0x39, 0x3c, 0x9e, 0xef, 0xcf, 0x60, 0x20, 0x6f, + 0xeb, 0x91, 0x48, 0x79, 0xed, 0x1d, 0x27, 0x09, 0xd4, 0x9b, 0x10, 0x85, 0x28, 0xbd, 0x6e, 0x04, + 0xc2, 0x9c, 0x78, 0xd2, 0xeb, 0x3f, 0xe9, 0xa4, 0xb7, 0xa3, 0x26, 0x3d, 0x9e, 0x3d, 0xe7, 0x35, + 0x6d, 0xd2, 0x7b, 0xf9, 0xb3, 0xdd, 0xe0, 0xcb, 0x9e, 0xed, 0x86, 0x5e, 0x6c, 0xb6, 0x1b, 0x7e, + 0xce, 0xd9, 0xee, 0x1e, 0x4c, 0x6c, 0x50, 0xda, 0xd0, 0x8e, 0x27, 0x47, 0xa2, 0xd5, 0xb3, 0x45, + 0xd1, 0xf1, 0x9c, 0x76, 0x46, 0x19, 0xe3, 0xca, 0x9c, 0x35, 0xe1, 0x6f, 0x66, 0xd6, 0x1c, 0x7d, + 0xc9, 0xb3, 0xe6, 0xd8, 0x8b, 0xcc, 0x9a, 0x89, 0xa9, 0x6f, 0xfc, 0xd4, 0x53, 0xdf, 0x8b, 0xcc, + 0x56, 0xff, 0x38, 0x0f, 0xb3, 0xec, 0x03, 0x68, 0x3e, 0xa1, 0xd5, 0xea, 0x8a, 0x08, 0xe0, 0x8a, + 0x02, 0xa5, 0x0e, 0xbc, 0x40, 0xde, 0x75, 0xc0, 0xbf, 0x19, 0xac, 0xed, 0xf9, 0x32, 0xd8, 0x04, + 0xff, 0x26, 0x15, 0x18, 0xe4, 0x5f, 0x48, 0xb1, 0xcf, 0x48, 0x4d, 0x95, 0x21, 0x57, 0xff, 0xbe, + 0x6c, 0xc1, 0x49, 0xee, 0xc2, 0x74, 0xda, 0xa7, 0x22, 0xdc, 0x18, 0x53, 0xed, 0x94, 0xcf, 0xe4, + 0x35, 0x98, 0x8c, 0x7d, 0x0c, 0xfc, 0xd9, 0x17, 0x7b, 0x22, 0x30, 0x3e, 0x84, 0x17, 0x51, 0xcf, + 0x02, 0x14, 0x93, 0xad, 0x10, 0xf3, 0xf8, 0x6b, 0x20, 0x6e, 0x78, 0x0b, 0x6b, 0x3b, 0xbe, 0xbf, + 0xb6, 0x05, 0xda, 0xfa, 0x18, 0x83, 0xa5, 0x95, 0x80, 0x40, 0xd3, 0xef, 0x8a, 0xa6, 0xdf, 0x15, + 0xa1, 0xdf, 0x2d, 0x4d, 0xbf, 0xec, 0x6f, 0xab, 0x82, 0x21, 0xd2, 0x3a, 0xbf, 0xba, 0x73, 0x35, + 0x24, 0x2e, 0x6c, 0x8b, 0x75, 0x24, 0x51, 0x05, 0x89, 0xb7, 0xfe, 0x3c, 0xc7, 0xc3, 0x2d, 0xfe, + 0x6f, 0x5c, 0x8e, 0x5e, 0x24, 0x04, 0xe2, 0xd7, 0xa2, 0x44, 0x2e, 0x22, 0xe9, 0x8c, 0xef, 0xd4, + 0x1f, 0x47, 0x31, 0x28, 0xdf, 0x67, 0x73, 0xa9, 0x8e, 0x10, 0xc6, 0xd0, 0xac, 0xd2, 0x94, 0x8e, + 0xdc, 0xbd, 0x2b, 0x27, 0x59, 0x91, 0xcf, 0x86, 0x83, 0xcd, 0x49, 0x56, 0x67, 0xc0, 0x28, 0xe0, + 0x49, 0xcb, 0xe6, 0x79, 0x48, 0x52, 0x6b, 0xf0, 0x4e, 0x32, 0x93, 0x06, 0x5a, 0xb2, 0x51, 0x26, + 0x0d, 0x5d, 0x8d, 0x51, 0x4e, 0x8d, 0x1d, 0xb8, 0x60, 0xd3, 0x43, 0xef, 0x09, 0x7d, 0xb9, 0x62, + 0xbf, 0x82, 0xf3, 0xa6, 0x40, 0x7e, 0xe7, 0x92, 0x3f, 0x10, 0xf2, 0x71, 0xfa, 0xb3, 0x22, 0x82, + 0x81, 0x3f, 0x2b, 0xc2, 0x5f, 0x27, 0x60, 0x7f, 0xea, 0x6b, 0x33, 0xe2, 0x2c, 0x0f, 0x2e, 0x9a, + 0xc2, 0xcb, 0x8d, 0x06, 0xbe, 0x4c, 0x5c, 0x77, 0xdb, 0x4e, 0x2b, 0x24, 0x9b, 0x30, 0xaa, 0xfd, + 0x8c, 0xf9, 0x99, 0x34, 0x8c, 0xd8, 0x37, 0x46, 0x00, 0x23, 0xbb, 0x73, 0x04, 0xb6, 0x28, 0x94, + 0xe2, 0xea, 0x61, 0x2a, 0xd3, 0xcb, 0xac, 0xc0, 0xb8, 0xf6, 0x53, 0x1d, 0xc6, 0xe0, 0x04, 0xab, + 0x95, 0x60, 0x2a, 0xcc, 0x64, 0xb1, 0xea, 0x30, 0x97, 0xa6, 0x34, 0xfe, 0x0c, 0x00, 0x59, 0x8a, + 0xb2, 0xfc, 0xf5, 0x8e, 0x23, 0x9e, 0xcc, 0xca, 0xf0, 0x67, 0xfd, 0x83, 0x7e, 0xb8, 0x20, 0x3a, + 0xe3, 0x65, 0xf6, 0x38, 0xf9, 0x01, 0x8c, 0x6a, 0x7d, 0x2c, 0x94, 0x7e, 0x45, 0xde, 0x98, 0xcc, + 0x1a, 0x0b, 0xdc, 0x1f, 0xd6, 0x41, 0x40, 0x2d, 0xd6, 0xdd, 0x2b, 0x67, 0x6c, 0x5d, 0x24, 0x69, + 0xc2, 0x84, 0xd9, 0xd1, 0xc2, 0x25, 0x78, 0x2d, 0xb5, 0x10, 0x93, 0x54, 0xbe, 0x11, 0xd0, 0xa8, + 0xa5, 0x76, 0xf7, 0xca, 0x19, 0x3b, 0x26, 0x9b, 0x7c, 0x03, 0x67, 0x13, 0xbd, 0x2c, 0xfc, 0xbd, + 0xaf, 0xa6, 0x16, 0x98, 0xa0, 0xe6, 0x07, 0x4d, 0x3e, 0x82, 0x33, 0x8b, 0x4d, 0x16, 0x42, 0x1a, + 0x30, 0xa6, 0x77, 0xbc, 0xf0, 0x59, 0x5e, 0xed, 0xa2, 0x4a, 0x4e, 0xc8, 0x37, 0xd0, 0x42, 0x97, + 0xd8, 0xf7, 0xcf, 0xcc, 0xc3, 0x33, 0x83, 0x78, 0x18, 0x06, 0xf9, 0x6f, 0xeb, 0x0f, 0x72, 0x70, + 0x61, 0xcb, 0xa7, 0x01, 0x6d, 0xd5, 0xa9, 0x71, 0xf7, 0xe4, 0x05, 0x47, 0x44, 0xd6, 0xb9, 0x55, + 0xfe, 0x85, 0xcf, 0xad, 0xac, 0x7f, 0x93, 0x83, 0x62, 0x5a, 0x95, 0xab, 0xb4, 0xd5, 0x20, 0x5b, + 0x50, 0x88, 0xb7, 0x41, 0x7c, 0x31, 0x96, 0x4a, 0xf1, 0x9e, 0xd9, 0xda, 0x95, 0x33, 0x76, 0x82, + 0x9b, 0x6c, 0xc0, 0x59, 0x0d, 0x26, 0xce, 0x8d, 0xf2, 0x27, 0x39, 0x37, 0x62, 0x3d, 0x9c, 0x60, + 0xd5, 0x8f, 0xdd, 0x56, 0x70, 0xd5, 0x5d, 0xf4, 0x0e, 0x1d, 0xb7, 0xc5, 0x0c, 0x15, 0x2d, 0x89, + 0x20, 0x44, 0x50, 0xa1, 0x76, 0x7e, 0x90, 0x84, 0x50, 0x79, 0x0d, 0x4f, 0x91, 0x58, 0x1f, 0xe2, + 0xea, 0x20, 0x9c, 0xc7, 0x3c, 0xf1, 0x81, 0x12, 0x76, 0x05, 0x06, 0xb6, 0xd7, 0xaa, 0x0b, 0x65, + 0x91, 0x46, 0x81, 0x27, 0xdf, 0x69, 0x06, 0xb5, 0xba, 0x63, 0x73, 0x84, 0xf5, 0x01, 0x90, 0x65, + 0x1a, 0x8a, 0x37, 0x46, 0x14, 0xdf, 0x75, 0x18, 0x12, 0x20, 0xc1, 0x89, 0x47, 0x22, 0xe2, 0xc5, + 0x12, 0x5b, 0xe2, 0xac, 0x2d, 0x69, 0xe7, 0x35, 0xa9, 0x13, 0x68, 0x8b, 0xfe, 0xbb, 0x30, 0xec, + 0x0b, 0x98, 0x58, 0xf3, 0x27, 0xd4, 0x13, 0x52, 0x08, 0xe6, 0x47, 0x75, 0x92, 0xc6, 0x56, 0x7f, + 0x59, 0x6b, 0x98, 0x28, 0x6b, 0x73, 0x75, 0x71, 0x81, 0x69, 0x55, 0x28, 0x4b, 0x76, 0xc7, 0x6d, + 0xbc, 0x79, 0x13, 0x52, 0x3d, 0x89, 0x02, 0xaa, 0x06, 0x27, 0x10, 0x91, 0x1e, 0x4e, 0x23, 0xb1, + 0xde, 0x54, 0x69, 0xb7, 0x52, 0xa4, 0x65, 0x3d, 0x85, 0xb4, 0x81, 0x09, 0xc5, 0x96, 0x31, 0xc8, + 0xf0, 0x65, 0x54, 0xc2, 0x81, 0x39, 0xbe, 0x85, 0x60, 0xad, 0x12, 0x0f, 0xc1, 0x7a, 0x6a, 0xda, + 0x5d, 0x80, 0x11, 0x05, 0x53, 0x11, 0x03, 0x5c, 0x57, 0x06, 0xfd, 0xee, 0x9b, 0x3c, 0xdf, 0x44, + 0x5d, 0x09, 0x88, 0xf8, 0x58, 0x11, 0xfc, 0x9b, 0xfe, 0x96, 0x8b, 0x08, 0xa8, 0x1f, 0x7e, 0xab, + 0x45, 0x44, 0x19, 0xe7, 0x4e, 0x53, 0x84, 0x41, 0xbf, 0x3b, 0x7f, 0x12, 0x45, 0x7d, 0xcb, 0x45, + 0x30, 0x45, 0x7d, 0x7b, 0x45, 0x50, 0x99, 0x9a, 0x8f, 0x0f, 0xd2, 0x44, 0x21, 0x4b, 0xc9, 0x42, + 0xe4, 0x89, 0x4a, 0x8c, 0xa3, 0x6b, 0x7f, 0x50, 0xb8, 0xc8, 0x95, 0xf5, 0x73, 0x28, 0x86, 0x29, + 0xec, 0xdb, 0x2d, 0xe6, 0x77, 0x72, 0x3c, 0x51, 0x60, 0x75, 0x53, 0x7b, 0x82, 0xb9, 0xf5, 0xc8, + 0xd3, 0x02, 0x9a, 0xb4, 0xaf, 0x5d, 0x3b, 0x60, 0xc6, 0x80, 0x26, 0xa7, 0x13, 0x1e, 0xa8, 0x44, + 0xfa, 0x78, 0xda, 0x1c, 0xa7, 0x26, 0xef, 0xc1, 0xb8, 0x06, 0x52, 0x3b, 0x41, 0xfe, 0xd4, 0x91, + 0xce, 0xee, 0x36, 0x6c, 0x93, 0xd2, 0xfa, 0xeb, 0x1c, 0x4c, 0x55, 0x9f, 0x05, 0x21, 0x3d, 0xc4, + 0xa4, 0xa8, 0x32, 0x33, 0x05, 0x3a, 0xa3, 0xd0, 0xc2, 0x52, 0x13, 0x95, 0x78, 0x9c, 0x10, 0x73, + 0x16, 0x19, 0xeb, 0xaf, 0x22, 0xc4, 0x47, 0x5e, 0xa4, 0x04, 0x55, 0x0b, 0xfe, 0xc8, 0x8b, 0x04, + 0x9b, 0xac, 0x3a, 0x39, 0x09, 0x00, 0xa2, 0x9a, 0x08, 0xb7, 0x7f, 0x95, 0x6d, 0x97, 0x03, 0x84, + 0xa2, 0xcf, 0x21, 0xe2, 0xfd, 0xd9, 0x51, 0xe9, 0x9d, 0xd3, 0x84, 0x63, 0x47, 0xa2, 0x6d, 0xad, + 0x18, 0xeb, 0xd7, 0xf2, 0x70, 0x2e, 0xa5, 0xfd, 0x55, 0x1a, 0xfe, 0x4d, 0xa8, 0xe0, 0x09, 0x8c, + 0x46, 0x95, 0xe1, 0x5e, 0x87, 0x91, 0xca, 0x36, 0xbe, 0x49, 0x12, 0xe9, 0x20, 0x78, 0x29, 0x4a, + 0xd0, 0x0b, 0xb2, 0xfe, 0x24, 0x0f, 0xe7, 0x76, 0xda, 0x01, 0xde, 0x4b, 0x5d, 0x6d, 0x3d, 0xa1, + 0xad, 0xd0, 0xf3, 0x9f, 0xe1, 0x5d, 0x3a, 0xf2, 0x36, 0x0c, 0xac, 0xd0, 0x66, 0xd3, 0x13, 0xe3, + 0xff, 0x92, 0x8c, 0x29, 0x8b, 0x53, 0x23, 0xd1, 0xca, 0x19, 0x9b, 0x53, 0x93, 0xf7, 0x60, 0x64, + 0x85, 0x3a, 0x7e, 0xb8, 0x47, 0x1d, 0x69, 0x0e, 0xc9, 0x07, 0x98, 0x34, 0x16, 0x41, 0xb0, 0x72, + 0xc6, 0x8e, 0xa8, 0xc9, 0x3c, 0xf4, 0x6f, 0x79, 0xad, 0x7d, 0x95, 0x83, 0x23, 0xa3, 0x40, 0x46, + 0xb3, 0x72, 0xc6, 0x46, 0x5a, 0xb2, 0x0e, 0xe3, 0xe5, 0x7d, 0xda, 0x0a, 0x63, 0x61, 0x12, 0xd7, + 0xb3, 0x98, 0x0d, 0xe2, 0x95, 0x33, 0xb6, 0xc9, 0x4d, 0x3e, 0x80, 0xa1, 0x65, 0xcf, 0x6b, 0xec, + 0x3d, 0x93, 0x99, 0x64, 0x4a, 0x59, 0x82, 0x04, 0xd9, 0xca, 0x19, 0x5b, 0x72, 0x54, 0x06, 0xa0, + 0x6f, 0x3d, 0xd8, 0xb7, 0x8e, 0x72, 0x50, 0x5c, 0xf4, 0x9e, 0xb6, 0x52, 0xb5, 0xfa, 0x3d, 0x53, + 0xab, 0x52, 0x7c, 0x0a, 0x7d, 0x4c, 0xaf, 0x6f, 0x41, 0xff, 0x96, 0xdb, 0xda, 0x8f, 0x6d, 0x05, + 0x53, 0xf8, 0x18, 0x15, 0xaa, 0xc7, 0x6d, 0xed, 0x93, 0x35, 0xb9, 0xbf, 0x5f, 0x93, 0xee, 0x2c, + 0xdd, 0xa8, 0x48, 0xe1, 0xd6, 0xa9, 0xa3, 0x7d, 0x3c, 0xff, 0x2d, 0x1b, 0xf8, 0x3a, 0xcc, 0x66, + 0x94, 0xab, 0x85, 0xfd, 0xf4, 0xe3, 0xc6, 0xe6, 0xef, 0xe4, 0x60, 0x26, 0xb5, 0x03, 0xe3, 0x94, + 0xcc, 0xa6, 0xe3, 0x03, 0x73, 0xa1, 0xe9, 0xd5, 0x1f, 0x9f, 0x20, 0x34, 0xd5, 0x12, 0x7e, 0x54, + 0xf9, 0x85, 0xd4, 0x19, 0x5f, 0xec, 0x61, 0x4a, 0x5d, 0xa4, 0xf5, 0xcf, 0xd3, 0xc6, 0x3a, 0x57, + 0x6e, 0x31, 0x0a, 0xc7, 0xe1, 0xae, 0x2b, 0x15, 0x81, 0x33, 0xa7, 0xcd, 0x05, 0x32, 0x2b, 0x95, + 0xfc, 0xe4, 0x77, 0xb5, 0x2c, 0x80, 0xfc, 0x8b, 0x7d, 0xff, 0x05, 0xbe, 0x4b, 0x25, 0x8b, 0x95, + 0xb9, 0xe2, 0x05, 0x61, 0x4b, 0x5d, 0x89, 0xb0, 0xd5, 0x6f, 0x72, 0x13, 0x0a, 0xf2, 0xa1, 0x23, + 0xf1, 0xa2, 0x9a, 0x2f, 0xe2, 0x7a, 0x12, 0x70, 0xf2, 0x2e, 0xcc, 0xc6, 0x61, 0xb2, 0x95, 0xfc, + 0xea, 0x71, 0x16, 0xda, 0xfa, 0xb3, 0x3c, 0x3e, 0xd4, 0xd0, 0xe5, 0xd3, 0x61, 0xfd, 0xb7, 0x59, + 0x95, 0x01, 0x5e, 0x9b, 0x55, 0x72, 0x11, 0x46, 0x36, 0xab, 0xc6, 0x0b, 0x92, 0x76, 0x04, 0x60, + 0xd5, 0x66, 0x4d, 0x28, 0xfb, 0xf5, 0x03, 0x37, 0xa4, 0xf5, 0xb0, 0xe3, 0xcb, 0x88, 0xaf, 0x04, + 0x9c, 0x58, 0x30, 0xb6, 0xdc, 0x74, 0xf7, 0xea, 0x52, 0x18, 0x57, 0x81, 0x01, 0x23, 0xaf, 0xc2, + 0xc4, 0x6a, 0x2b, 0x08, 0x9d, 0x66, 0x73, 0x9d, 0x86, 0x07, 0x5e, 0xe4, 0x28, 0x35, 0xa1, 0xac, + 0xdc, 0x05, 0xaf, 0x15, 0x3a, 0x6e, 0x8b, 0xfa, 0x76, 0xa7, 0x15, 0xba, 0x87, 0x54, 0xb4, 0x3d, + 0x01, 0x27, 0x6f, 0xc1, 0x8c, 0x82, 0x6d, 0xfa, 0xf5, 0x03, 0x1a, 0x84, 0x3e, 0xbe, 0x2b, 0x8b, + 0xc1, 0x8f, 0x76, 0x3a, 0x12, 0x4b, 0x68, 0x7a, 0x9d, 0xc6, 0x52, 0xeb, 0x89, 0xeb, 0x7b, 0x3c, + 0xaa, 0x60, 0x58, 0x94, 0x10, 0x83, 0x5b, 0xbf, 0x37, 0x9c, 0x3a, 0x33, 0xbc, 0xc8, 0x18, 0xfc, + 0x02, 0xc6, 0x16, 0x9c, 0xb6, 0xb3, 0xe7, 0x36, 0xdd, 0xd0, 0x55, 0x0f, 0x70, 0xbe, 0xdd, 0x63, + 0x5a, 0x91, 0x4f, 0x5f, 0xd1, 0x86, 0xce, 0x6c, 0x1b, 0xa2, 0xe6, 0xfe, 0x6a, 0x10, 0x66, 0x52, + 0xe9, 0xc8, 0x0d, 0xf1, 0x52, 0xa7, 0x9a, 0xba, 0xc5, 0x33, 0x90, 0x76, 0x1c, 0xcc, 0xfa, 0x12, + 0x41, 0x0b, 0x4d, 0xea, 0xb4, 0x3a, 0xe2, 0x11, 0x48, 0xdb, 0x80, 0xb1, 0xbe, 0x64, 0x5b, 0x13, + 0x4d, 0x18, 0xde, 0x68, 0xb1, 0x63, 0x50, 0x0c, 0x18, 0xec, 0x84, 0x07, 0x52, 0x54, 0x3f, 0xbf, + 0x7b, 0xad, 0x81, 0x98, 0xa4, 0x0d, 0xaf, 0x41, 0x35, 0x49, 0x03, 0x5c, 0x92, 0x09, 0x65, 0x92, + 0x18, 0x44, 0x4a, 0x1a, 0xe4, 0x92, 0x34, 0x10, 0x79, 0x05, 0xc6, 0xcb, 0xed, 0xb6, 0x26, 0x08, + 0x5f, 0x7f, 0xb4, 0x4d, 0x20, 0xb9, 0x0c, 0x50, 0x6e, 0xb7, 0xa5, 0x18, 0x7c, 0xd9, 0xd1, 0xd6, + 0x20, 0xe4, 0x56, 0x94, 0x6b, 0x53, 0x13, 0x85, 0x27, 0x4e, 0x76, 0x0a, 0x86, 0xe9, 0x55, 0x25, + 0x26, 0x14, 0x42, 0x81, 0xeb, 0x35, 0x06, 0x26, 0x1f, 0xc2, 0xf9, 0x58, 0xcc, 0x91, 0x56, 0x00, + 0x9e, 0x06, 0xd9, 0xd9, 0x04, 0xe4, 0x1d, 0x38, 0x17, 0x43, 0xca, 0xe2, 0xf0, 0xe0, 0xc7, 0xce, + 0xc0, 0x92, 0xf7, 0xa1, 0x18, 0xcb, 0xa7, 0x11, 0x15, 0x8a, 0x87, 0x3c, 0x76, 0x26, 0x9e, 0x7d, + 0x5d, 0xb1, 0x8b, 0xb9, 0xa2, 0x48, 0x3c, 0xcf, 0xb6, 0xd3, 0x91, 0x64, 0x05, 0x4a, 0xa9, 0x71, + 0x5c, 0x5a, 0xc1, 0xf8, 0x62, 0xa5, 0xdd, 0x8b, 0x8c, 0x54, 0xe0, 0x62, 0x2a, 0x89, 0xac, 0x06, + 0xbe, 0x63, 0x69, 0x77, 0xa5, 0x21, 0xf3, 0x30, 0x1d, 0xc5, 0xb3, 0x69, 0x55, 0xc0, 0x27, 0x2c, + 0xed, 0x54, 0x1c, 0x79, 0xc3, 0xcc, 0x9a, 0xc2, 0x0b, 0xc3, 0x17, 0x2c, 0xed, 0x24, 0xc2, 0x3a, + 0xce, 0xc1, 0xc5, 0xd4, 0xb5, 0x58, 0x9a, 0x0c, 0x73, 0xf1, 0xbd, 0xa9, 0x36, 0x17, 0xdc, 0x14, + 0x41, 0xaa, 0xdc, 0xd5, 0x2d, 0x2f, 0x01, 0x20, 0x3f, 0x17, 0xf5, 0x20, 0x0a, 0x59, 0x5d, 0x56, + 0xc7, 0xc7, 0xfc, 0x84, 0xeb, 0x76, 0x7c, 0x8f, 0x96, 0x52, 0xb8, 0x79, 0xcc, 0xc5, 0x7f, 0xbc, + 0xc8, 0x51, 0xd4, 0x9f, 0xe5, 0xa0, 0xd4, 0x63, 0x0b, 0xa2, 0xda, 0x94, 0x3b, 0x41, 0x9b, 0xee, + 0xab, 0x36, 0xf1, 0xa4, 0x05, 0xf3, 0x27, 0xdb, 0xe6, 0xbc, 0xec, 0x66, 0xfd, 0x75, 0x0e, 0x48, + 0x72, 0xab, 0x4b, 0xbe, 0x0b, 0x23, 0xd5, 0xea, 0x4a, 0xb5, 0xeb, 0xf9, 0x5a, 0x44, 0x41, 0xee, + 0x9c, 0x28, 0x7c, 0x55, 0x0f, 0x5e, 0xfd, 0x24, 0x11, 0x33, 0xdb, 0xd7, 0x35, 0x66, 0x36, 0x11, + 0x31, 0xbb, 0x94, 0x12, 0x04, 0xda, 0xdf, 0x23, 0x08, 0x34, 0x19, 0xe1, 0x69, 0x2d, 0x42, 0x31, + 0x6b, 0xb7, 0x8c, 0x33, 0x1c, 0xcf, 0x50, 0xa9, 0x1d, 0xd0, 0xf1, 0x19, 0xce, 0x04, 0x5b, 0xef, + 0xc0, 0x39, 0xc5, 0xcd, 0x9f, 0xbe, 0xd2, 0x52, 0xc3, 0x08, 0x13, 0x5b, 0xa5, 0xa0, 0x89, 0x00, + 0xd6, 0x9f, 0xf6, 0x27, 0x18, 0xab, 0x9d, 0xc3, 0x43, 0xc7, 0x7f, 0x46, 0xca, 0x26, 0x63, 0x5f, + 0x4f, 0xab, 0xa6, 0xd2, 0xcf, 0xf6, 0x98, 0x9a, 0x74, 0xb6, 0x2e, 0xe0, 0x0e, 0xa3, 0x55, 0xa7, + 0xfc, 0x68, 0x2f, 0xcf, 0xd3, 0xdf, 0x19, 0x40, 0xb2, 0x0b, 0xe3, 0x62, 0xed, 0xc6, 0xdf, 0xf2, + 0x1b, 0xbb, 0x13, 0xff, 0xc6, 0x8c, 0xea, 0xdd, 0x32, 0x58, 0xf8, 0x68, 0x34, 0xc5, 0x90, 0x2f, + 0x60, 0x42, 0xee, 0xd4, 0x84, 0x60, 0x1e, 0xf0, 0x76, 0xb7, 0xbb, 0x60, 0x93, 0x87, 0x4b, 0x8e, + 0x09, 0x62, 0x55, 0x96, 0x93, 0x1d, 0x97, 0x3c, 0x70, 0x92, 0x2a, 0x1b, 0x2c, 0xa2, 0xca, 0x06, + 0x6c, 0xee, 0x53, 0x20, 0xc9, 0x76, 0xf5, 0xfa, 0x9c, 0xc6, 0xb5, 0xcf, 0x69, 0xae, 0x0c, 0x53, + 0x29, 0x0d, 0x38, 0x95, 0x88, 0x4f, 0x81, 0x24, 0x6b, 0x7a, 0x1a, 0x09, 0xd6, 0x0d, 0x78, 0x55, + 0xa9, 0x40, 0x8d, 0x06, 0x43, 0xa6, 0x74, 0xb2, 0xff, 0x4a, 0x1e, 0x4a, 0x3d, 0x48, 0xc9, 0xef, + 0xe6, 0xe2, 0xda, 0xe6, 0xa3, 0xf1, 0xbd, 0xb8, 0xb6, 0xd3, 0xf9, 0x53, 0xd4, 0x5e, 0x79, 0xff, + 0x57, 0xff, 0xe2, 0xb9, 0x2d, 0x8f, 0x64, 0x97, 0x9d, 0x5e, 0x5b, 0xfd, 0xba, 0xb6, 0x76, 0x61, + 0xda, 0x30, 0x0b, 0x4f, 0xb2, 0x78, 0x59, 0x00, 0xe2, 0x15, 0xee, 0x35, 0x6f, 0x5f, 0x3c, 0x16, + 0x9e, 0x2f, 0xe6, 0x6c, 0x0d, 0x6a, 0xdd, 0x83, 0x99, 0x98, 0x5c, 0xe1, 0xfc, 0xff, 0x2e, 0xa8, + 0x34, 0x20, 0x28, 0xb8, 0xaf, 0x72, 0xf6, 0x67, 0x47, 0xa5, 0x71, 0xb6, 0xad, 0xbf, 0x15, 0xbd, + 0xc4, 0x22, 0xff, 0xb2, 0xd6, 0xf5, 0xe3, 0x8b, 0x72, 0x53, 0x4f, 0x8f, 0x46, 0xee, 0xc2, 0x20, + 0x87, 0xc4, 0xde, 0x3b, 0xd0, 0xa9, 0xc5, 0xbc, 0x20, 0x08, 0xad, 0x19, 0x4c, 0x5a, 0x80, 0x3f, + 0xca, 0x51, 0x92, 0x1d, 0x6b, 0x87, 0xbf, 0xff, 0x15, 0x81, 0xd5, 0x9b, 0x0a, 0xfd, 0xe5, 0x28, + 0x19, 0x90, 0x8c, 0x15, 0x92, 0x74, 0x2d, 0xef, 0x69, 0x93, 0x36, 0xf8, 0xc3, 0xad, 0x95, 0x31, + 0x61, 0xe3, 0xf6, 0x3b, 0x4c, 0x00, 0xb2, 0x59, 0x9f, 0xc0, 0x0c, 0xdb, 0x2d, 0xf8, 0xf1, 0xf2, + 0xf0, 0xd5, 0x1f, 0x06, 0x33, 0xef, 0x26, 0x39, 0x0c, 0x84, 0x77, 0x93, 0x04, 0xd2, 0x5a, 0x83, + 0xf3, 0xdc, 0xf9, 0xa9, 0x37, 0x29, 0x3a, 0x6a, 0x18, 0xc0, 0xdf, 0xb1, 0x2b, 0xef, 0x29, 0xad, + 0xe7, 0x74, 0xd6, 0xc7, 0x78, 0xa7, 0x52, 0x0c, 0x54, 0xd7, 0x6b, 0x45, 0x9e, 0xce, 0x93, 0x25, + 0x61, 0xf8, 0x7f, 0xe1, 0x62, 0xb9, 0xdd, 0xa6, 0xad, 0x46, 0xc4, 0xb8, 0xed, 0x3b, 0x27, 0x4c, + 0x91, 0x43, 0xca, 0x30, 0x80, 0xd4, 0xea, 0x0c, 0x58, 0x54, 0x37, 0xa5, 0x3a, 0x48, 0x27, 0x12, + 0x60, 0x63, 0x01, 0x9c, 0xd3, 0x6a, 0xc0, 0x6c, 0xb5, 0xb3, 0x77, 0xe8, 0x86, 0x78, 0xa3, 0x09, + 0xd3, 0x4c, 0xc9, 0xb2, 0x57, 0xe5, 0x93, 0x8d, 0x5c, 0x19, 0x37, 0xa2, 0xbb, 0x77, 0x78, 0x29, + 0x4a, 0xa4, 0x9e, 0x7a, 0x72, 0xf7, 0x56, 0xc4, 0x8a, 0x5e, 0x1e, 0x5e, 0x0a, 0xa2, 0xc5, 0xb3, + 0x8e, 0xd6, 0x14, 0x9c, 0xd5, 0xcf, 0xbc, 0xf8, 0x08, 0x99, 0x81, 0x29, 0xf3, 0x2c, 0x8b, 0x83, + 0xbf, 0x86, 0x69, 0xee, 0x6b, 0xe7, 0x0f, 0x58, 0xcc, 0x47, 0x6f, 0x35, 0xe4, 0x77, 0xe7, 0x63, + 0x17, 0x61, 0x30, 0x3e, 0x5e, 0x3d, 0x4d, 0xb4, 0x3b, 0xcf, 0xef, 0xc5, 0x3f, 0x99, 0x37, 0x4e, + 0x63, 0xf3, 0xbb, 0xf3, 0x95, 0x21, 0x91, 0x08, 0x9c, 0x49, 0xe7, 0xdd, 0xff, 0xad, 0x48, 0x9f, + 0xc7, 0x54, 0x2c, 0x2b, 0xd4, 0xc1, 0x6b, 0x93, 0xe9, 0x09, 0x2d, 0x26, 0x20, 0xaf, 0x32, 0xfd, + 0xe6, 0xdd, 0x86, 0xf5, 0x87, 0x39, 0xb8, 0xc1, 0x37, 0x64, 0xe9, 0x7c, 0x78, 0xb0, 0x95, 0xc1, + 0x4c, 0xde, 0x85, 0x81, 0x40, 0x0b, 0xf0, 0xb0, 0x44, 0xcd, 0xbb, 0x49, 0xe2, 0x0c, 0xa4, 0x0c, + 0x63, 0xfa, 0xed, 0xc0, 0x93, 0x25, 0x11, 0xb5, 0x47, 0x0f, 0x1f, 0x39, 0xea, 0xc6, 0xe0, 0x63, + 0xb8, 0xb0, 0xf4, 0x0d, 0x1b, 0x10, 0x62, 0x85, 0x12, 0xd6, 0x43, 0x94, 0x30, 0x61, 0x72, 0x5b, + 0x8c, 0x18, 0xd3, 0xb4, 0x8f, 0x83, 0x99, 0x9d, 0x2c, 0x17, 0xb9, 0xe8, 0x1a, 0x99, 0x6d, 0xc0, + 0xac, 0x3f, 0xcd, 0xc1, 0xc5, 0xf4, 0xd2, 0xc4, 0xc4, 0xb2, 0x0a, 0x67, 0x17, 0x9c, 0x96, 0xd7, + 0x72, 0xeb, 0x4e, 0xb3, 0x5a, 0x3f, 0xa0, 0x8d, 0x8e, 0x4a, 0x17, 0xae, 0x66, 0x99, 0x7d, 0xda, + 0x92, 0xec, 0x92, 0xc4, 0x4e, 0x72, 0x31, 0x0b, 0x11, 0xaf, 0x07, 0xf1, 0xb9, 0xb7, 0x49, 0x7d, + 0x25, 0x8f, 0xd7, 0x2c, 0x03, 0x4b, 0xee, 0xc8, 0x43, 0x85, 0xc6, 0x4e, 0xcb, 0x0d, 0x15, 0x13, + 0x77, 0xf5, 0xa4, 0xa1, 0xac, 0x7f, 0x9f, 0x83, 0xf3, 0xf8, 0x42, 0xa0, 0xf1, 0xe6, 0x70, 0x94, + 0x35, 0x5f, 0x26, 0x7e, 0xcf, 0x19, 0xd7, 0x9d, 0x0c, 0x6a, 0x33, 0x03, 0x3c, 0x79, 0x03, 0xfa, + 0xab, 0x32, 0xe0, 0x6c, 0x22, 0xf6, 0x5a, 0xbc, 0xe0, 0x60, 0x78, 0x1b, 0xa9, 0x98, 0x0d, 0xbf, + 0x48, 0x83, 0x3a, 0x6d, 0xe1, 0xb3, 0xfe, 0xdc, 0xf3, 0xa0, 0x41, 0xa2, 0x84, 0x76, 0xfd, 0x59, + 0x09, 0xed, 0x06, 0xcc, 0x84, 0x76, 0xd6, 0x13, 0xfe, 0x3e, 0x60, 0xbc, 0x41, 0xa2, 0x93, 0x3e, + 0x86, 0xd8, 0x93, 0xfd, 0x62, 0x1d, 0x38, 0x97, 0xd6, 0x32, 0xb6, 0x49, 0x8f, 0x3d, 0xf0, 0x9f, + 0x9d, 0xa5, 0x7e, 0x0b, 0x5e, 0x31, 0x68, 0xcb, 0xcd, 0xa6, 0xf7, 0x94, 0x36, 0xb6, 0x7c, 0xef, + 0xd0, 0x0b, 0x8d, 0xf7, 0xd1, 0x26, 0x1d, 0x9d, 0x4e, 0x2d, 0xc6, 0x71, 0xb0, 0xf5, 0xff, 0xc0, + 0xf5, 0x1e, 0x12, 0x45, 0xa3, 0xaa, 0x70, 0xd6, 0x89, 0xe1, 0x64, 0xe4, 0xd0, 0xf5, 0xb4, 0x76, + 0xc5, 0x05, 0x05, 0x76, 0x92, 0xff, 0xe6, 0xb6, 0xf1, 0x72, 0x3e, 0x29, 0xc2, 0xf4, 0x96, 0xbd, + 0xb9, 0xb8, 0xb3, 0xb0, 0x5d, 0xdb, 0xfe, 0x62, 0x6b, 0xa9, 0xb6, 0xb3, 0xf1, 0x60, 0x63, 0xf3, + 0xe1, 0x06, 0x7f, 0xe6, 0xc1, 0xc0, 0x6c, 0x2f, 0x95, 0xd7, 0x0b, 0x39, 0x32, 0x0d, 0x05, 0x03, + 0xbc, 0xb4, 0x53, 0x29, 0xe4, 0x6f, 0x7e, 0x6d, 0xbc, 0x08, 0x4f, 0x2e, 0x42, 0xb1, 0xba, 0xb3, + 0xb5, 0xb5, 0x69, 0x2b, 0xa9, 0xfa, 0x23, 0x13, 0x33, 0x70, 0xd6, 0xc0, 0xde, 0xb3, 0x97, 0x96, + 0x0a, 0x39, 0x56, 0x15, 0x03, 0xbc, 0x65, 0x2f, 0xad, 0xaf, 0xee, 0xac, 0x17, 0xf2, 0x37, 0x6b, + 0xfa, 0x2d, 0x5d, 0x72, 0x01, 0x66, 0x17, 0x97, 0x76, 0x57, 0x17, 0x96, 0xd2, 0x64, 0x4f, 0x43, + 0x41, 0x47, 0x6e, 0x6f, 0x6e, 0x6f, 0x71, 0xd1, 0x3a, 0xf4, 0xe1, 0x52, 0xa5, 0xbc, 0xb3, 0xbd, + 0xb2, 0x51, 0xe8, 0xb3, 0xfa, 0x87, 0xf3, 0x85, 0xfc, 0xcd, 0x1f, 0x18, 0x57, 0x78, 0x59, 0xf5, + 0x05, 0xf9, 0x4e, 0xb5, 0xbc, 0x9c, 0x5d, 0x04, 0xc7, 0xae, 0xdf, 0x2b, 0x17, 0x72, 0xe4, 0x12, + 0x9c, 0x37, 0xa0, 0x5b, 0xe5, 0x6a, 0xf5, 0xe1, 0xa6, 0xbd, 0xb8, 0xb6, 0x54, 0xad, 0x16, 0xf2, + 0x37, 0x77, 0x8d, 0x24, 0x9e, 0xac, 0x84, 0xf5, 0x7b, 0xe5, 0x9a, 0xbd, 0xf4, 0xd9, 0xce, 0xaa, + 0xbd, 0xb4, 0x98, 0x2c, 0xc1, 0xc0, 0x7e, 0xb1, 0x54, 0x2d, 0xe4, 0xc8, 0x14, 0x4c, 0x1a, 0xd0, + 0x8d, 0xcd, 0x42, 0xfe, 0xe6, 0xab, 0x22, 0xcf, 0x23, 0x99, 0x00, 0x58, 0x5c, 0xaa, 0x2e, 0x2c, + 0x6d, 0x2c, 0xae, 0x6e, 0x2c, 0x17, 0xce, 0x90, 0x71, 0x18, 0x29, 0xab, 0x9f, 0xb9, 0x9b, 0xef, + 0xc3, 0x64, 0xcc, 0xbc, 0x67, 0x14, 0xca, 0x30, 0x2e, 0x9c, 0x41, 0xf5, 0xcb, 0x9f, 0xe8, 0x63, + 0xe5, 0x96, 0x7a, 0x21, 0x77, 0xb3, 0x22, 0x1f, 0x11, 0xd7, 0xbe, 0x73, 0x32, 0x0a, 0x43, 0x8b, + 0x4b, 0xf7, 0xca, 0x3b, 0x6b, 0xdb, 0x85, 0x33, 0xec, 0xc7, 0x82, 0xbd, 0x54, 0xde, 0x5e, 0x5a, + 0x2c, 0xe4, 0xc8, 0x08, 0x0c, 0x54, 0xb7, 0xcb, 0xdb, 0x4b, 0x85, 0x3c, 0x19, 0x86, 0xfe, 0x9d, + 0xea, 0x92, 0x5d, 0xe8, 0x9b, 0xff, 0x9d, 0xdf, 0xcd, 0x71, 0x47, 0xa3, 0xbc, 0xcc, 0xf7, 0xb5, + 0x66, 0x50, 0x8a, 0x29, 0x4f, 0xbc, 0x98, 0x9c, 0x69, 0x3d, 0xe2, 0x2e, 0x60, 0xae, 0xcb, 0xe1, + 0x0e, 0x12, 0xdc, 0xc8, 0xdd, 0xc9, 0x11, 0x1b, 0x83, 0x61, 0x62, 0xf6, 0x95, 0x92, 0x9c, 0x6e, + 0x02, 0xcf, 0x5d, 0xea, 0x6a, 0x96, 0x91, 0x5f, 0x02, 0x4b, 0x97, 0x99, 0x61, 0x85, 0x7c, 0xf7, + 0x64, 0xd6, 0x86, 0x2c, 0xf3, 0xd5, 0x93, 0x91, 0x93, 0xfb, 0x30, 0xce, 0xf6, 0xe6, 0x8a, 0x8c, + 0x5c, 0x88, 0x33, 0x6a, 0x26, 0xc1, 0xdc, 0xc5, 0x74, 0xa4, 0x7a, 0xd4, 0x6c, 0x0c, 0x1b, 0xc2, + 0x8d, 0xeb, 0x80, 0xc8, 0x5c, 0x40, 0x12, 0xc2, 0x67, 0xfc, 0xb9, 0xb3, 0x31, 0xf0, 0xee, 0xdd, + 0x3b, 0x39, 0x52, 0xc5, 0x44, 0x9c, 0xc6, 0x26, 0x9f, 0xc8, 0xdb, 0xa5, 0xc9, 0xdd, 0x3f, 0xaf, + 0x4d, 0x49, 0x3d, 0x41, 0x9c, 0x61, 0x1d, 0x6c, 0x00, 0x49, 0xee, 0x9d, 0xc9, 0x95, 0x68, 0x1c, + 0xa4, 0x6f, 0xab, 0xe7, 0xce, 0x25, 0x0e, 0xb2, 0x96, 0xd8, 0xee, 0x89, 0x2c, 0xc1, 0x84, 0x48, + 0xf4, 0x21, 0x76, 0xf3, 0xa4, 0x9b, 0x3d, 0x90, 0x29, 0x66, 0x19, 0xf5, 0xa4, 0x2c, 0x02, 0x32, + 0x17, 0xb5, 0x23, 0x6e, 0x26, 0xcc, 0x5d, 0x48, 0xc5, 0x89, 0xf6, 0xdd, 0x83, 0x09, 0xd3, 0xb8, + 0x20, 0xb2, 0x83, 0x52, 0x6d, 0x8e, 0xcc, 0x0a, 0xd5, 0x60, 0x76, 0xdd, 0x71, 0xf1, 0xbc, 0x44, + 0x04, 0xe9, 0xc9, 0x38, 0x38, 0x52, 0xea, 0x12, 0x18, 0x57, 0xa5, 0xad, 0x86, 0xea, 0x84, 0xac, + 0x07, 0x4a, 0xf0, 0xb3, 0xa9, 0xca, 0x3d, 0xb2, 0x19, 0xa3, 0x48, 0x2c, 0xf3, 0x59, 0xf9, 0xb4, + 0xb0, 0xd3, 0xb9, 0xac, 0x48, 0x69, 0xb2, 0x8e, 0x9b, 0xf4, 0x98, 0x44, 0x6d, 0x4c, 0x9c, 0x5a, + 0x5c, 0x11, 0xd3, 0xcd, 0x84, 0x6e, 0x3c, 0xe4, 0x39, 0x20, 0x19, 0x8a, 0xcb, 0x14, 0x76, 0x27, + 0x47, 0xbe, 0xc6, 0xaf, 0x3a, 0x55, 0xdc, 0x43, 0x37, 0x3c, 0x10, 0xbb, 0x9f, 0x0b, 0xa9, 0x02, + 0xc4, 0x87, 0xd2, 0x45, 0xba, 0x0d, 0xd3, 0x69, 0xc1, 0xd9, 0x4a, 0xa1, 0x5d, 0x22, 0xb7, 0x33, + 0x47, 0x81, 0xcd, 0x4c, 0x8d, 0x46, 0x76, 0x27, 0x75, 0x89, 0x0d, 0xce, 0x94, 0xf9, 0x21, 0x4c, + 0xb0, 0x51, 0xf2, 0x80, 0xd2, 0x76, 0xb9, 0xe9, 0x3e, 0xa1, 0x01, 0x91, 0x59, 0xd4, 0x15, 0x28, + 0x8b, 0xf7, 0x46, 0x8e, 0x7c, 0x07, 0x46, 0x1f, 0x3a, 0x61, 0xfd, 0x40, 0x64, 0x13, 0x96, 0xc9, + 0x86, 0x11, 0x36, 0x27, 0x7f, 0x21, 0xf2, 0x4e, 0x8e, 0x7c, 0x04, 0x43, 0xcb, 0x34, 0xc4, 0xdb, + 0xfd, 0x57, 0x55, 0x2c, 0x21, 0xf7, 0x4f, 0xae, 0xb6, 0xd4, 0x4d, 0x2f, 0x59, 0xe1, 0xb8, 0x33, + 0x97, 0xdc, 0x06, 0xe0, 0x13, 0x02, 0x4a, 0x88, 0xa3, 0xe7, 0x12, 0xd5, 0x26, 0xcb, 0x6c, 0xf3, + 0xd0, 0xa4, 0x21, 0x3d, 0x69, 0x91, 0x59, 0x3a, 0x5a, 0x83, 0x09, 0xf5, 0x0e, 0xdc, 0x06, 0x26, + 0x7d, 0xb2, 0x62, 0xc2, 0x82, 0x53, 0x48, 0x7b, 0x9f, 0x7d, 0x15, 0xfc, 0x11, 0x74, 0xcc, 0x0e, + 0x84, 0x33, 0xe9, 0xac, 0x9e, 0x62, 0x48, 0x9f, 0x42, 0xa5, 0x12, 0x39, 0x99, 0xc6, 0xbb, 0xe2, + 0x05, 0xa1, 0xc9, 0xab, 0x20, 0xe9, 0xbc, 0xbf, 0x08, 0x73, 0x7a, 0xb9, 0x66, 0x3a, 0xfb, 0x68, + 0xce, 0xcd, 0xca, 0x92, 0x3f, 0x77, 0xb5, 0x0b, 0x85, 0xb0, 0xdf, 0xfa, 0x7e, 0x3d, 0x9f, 0xc3, + 0xe9, 0x64, 0x11, 0xa6, 0x64, 0x59, 0x9b, 0x6d, 0xda, 0xaa, 0x56, 0x57, 0xf0, 0xcd, 0x2f, 0x19, + 0xb9, 0xa2, 0xc1, 0xa4, 0x74, 0x92, 0x44, 0xb1, 0xa5, 0xcf, 0xc8, 0x02, 0x44, 0xba, 0xe5, 0x06, + 0x8a, 0x96, 0xbe, 0xd4, 0x3c, 0xeb, 0x0f, 0xb8, 0x53, 0xc9, 0xd8, 0xfc, 0xef, 0xce, 0x93, 0x2e, + 0x06, 0xd0, 0x5c, 0x86, 0x09, 0x71, 0x27, 0x47, 0xbe, 0x00, 0x92, 0x34, 0x49, 0x94, 0x0a, 0x33, + 0xcd, 0x2f, 0xa5, 0xc2, 0x2e, 0xf6, 0xcc, 0x32, 0xcc, 0xa8, 0x1c, 0x60, 0x5a, 0xa9, 0xf3, 0x24, + 0xa3, 0x36, 0x59, 0xb5, 0x24, 0x9f, 0xc0, 0x94, 0x18, 0xb4, 0x3a, 0x82, 0x14, 0xd4, 0xfc, 0x23, + 0xac, 0x92, 0xcc, 0x71, 0x7a, 0x1f, 0x66, 0xaa, 0x31, 0x8d, 0xf1, 0x60, 0xfe, 0xf3, 0xa6, 0x08, + 0x04, 0x56, 0x69, 0xc8, 0x55, 0x96, 0x2e, 0xeb, 0x01, 0x10, 0xee, 0x14, 0x92, 0xe2, 0x9e, 0xb8, + 0xf4, 0x29, 0xb9, 0x14, 0xab, 0x3a, 0x03, 0x22, 0x19, 0x4e, 0x60, 0x99, 0x2d, 0xdb, 0xe6, 0x4f, + 0xf8, 0x23, 0xd4, 0x38, 0x47, 0xbf, 0x62, 0x30, 0x18, 0x47, 0xf1, 0xa2, 0x03, 0xce, 0x67, 0x52, + 0x90, 0x5f, 0xc6, 0xe4, 0xdb, 0xdd, 0xcd, 0x2a, 0xf2, 0x9d, 0x34, 0xeb, 0x37, 0xc3, 0x30, 0x9c, + 0x7b, 0xe3, 0x64, 0xc4, 0xca, 0x90, 0x1d, 0x5f, 0xa6, 0xe1, 0x56, 0xb3, 0xb3, 0xef, 0xe2, 0xe3, + 0xce, 0x44, 0x39, 0x8d, 0x14, 0x48, 0x8c, 0x4b, 0x99, 0xf3, 0x32, 0x42, 0x54, 0xe9, 0x0f, 0xc9, + 0x2a, 0x14, 0xf8, 0xfc, 0xaf, 0x89, 0xb8, 0x94, 0x10, 0x21, 0x48, 0x1c, 0xdf, 0x39, 0x0c, 0x32, + 0x7b, 0xeb, 0x36, 0x8f, 0x8d, 0x22, 0xf2, 0x9b, 0xd4, 0x37, 0x98, 0x53, 0x06, 0x4c, 0x3d, 0x48, + 0xc2, 0x7a, 0xc4, 0xa6, 0x01, 0x0d, 0x65, 0x96, 0x2f, 0xfe, 0xb4, 0xf7, 0xb5, 0x68, 0xb1, 0x4f, + 0x62, 0xa3, 0x4f, 0x3f, 0x96, 0x91, 0x72, 0xf7, 0x4d, 0xa2, 0x9e, 0x3b, 0x4f, 0x11, 0xfa, 0xaa, + 0xb1, 0x27, 0x39, 0x9d, 0xdc, 0xb7, 0x70, 0x0d, 0xc2, 0xcc, 0x66, 0x33, 0x51, 0xdd, 0xd8, 0x6f, + 0xc9, 0x35, 0xae, 0x71, 0xed, 0xce, 0xe3, 0x94, 0xc6, 0x16, 0x49, 0xb6, 0x85, 0xed, 0xf8, 0x3e, + 0x6d, 0x71, 0xe6, 0xac, 0xfd, 0x46, 0x1a, 0xf7, 0xc7, 0x38, 0xf5, 0x68, 0xdc, 0xfc, 0x5e, 0x67, + 0x2f, 0x11, 0xfc, 0x29, 0xba, 0x3b, 0x39, 0xf2, 0x2e, 0x0c, 0x8b, 0x3a, 0x32, 0x26, 0xa3, 0xd2, + 0x41, 0x97, 0x5a, 0x23, 0x27, 0x70, 0x25, 0x61, 0x9d, 0x4d, 0x9a, 0xac, 0xde, 0xe7, 0x75, 0x7e, + 0x97, 0x2d, 0xb6, 0x8d, 0xe7, 0xe1, 0x5c, 0x90, 0xab, 0x2e, 0x72, 0x16, 0x55, 0x36, 0x2c, 0x09, + 0xea, 0xb1, 0x3c, 0x72, 0x21, 0x6c, 0xdf, 0x8c, 0x29, 0x65, 0x55, 0x66, 0x48, 0xb5, 0x6f, 0x36, + 0xc0, 0xbd, 0xd6, 0xda, 0x55, 0x28, 0x94, 0xeb, 0xb8, 0x12, 0x54, 0xe9, 0xa1, 0xd3, 0x3e, 0xf0, + 0x7c, 0xaa, 0x8c, 0x96, 0x38, 0x42, 0xca, 0x9a, 0x51, 0x3b, 0x0b, 0x81, 0x58, 0xa3, 0x0e, 0xe6, + 0xdd, 0x9f, 0x55, 0x5b, 0x8b, 0x18, 0x2a, 0x9d, 0xa3, 0x8b, 0x91, 0x32, 0xbd, 0xc0, 0xcc, 0xaa, + 0xe6, 0x8b, 0x89, 0x79, 0x1f, 0x27, 0x0c, 0x45, 0x1c, 0xa8, 0x15, 0x42, 0x81, 0x94, 0x39, 0x27, + 0xaf, 0x1f, 0x29, 0xd2, 0xb2, 0x3c, 0x37, 0x8e, 0xd4, 0x92, 0xc5, 0x9d, 0x55, 0xfc, 0xf7, 0x60, + 0x62, 0x89, 0x4d, 0xe8, 0x9d, 0x86, 0xcb, 0xdf, 0x1a, 0x21, 0xe6, 0xe3, 0x11, 0x99, 0x8c, 0x2b, + 0xf2, 0xf5, 0x47, 0x64, 0x15, 0xa6, 0xbf, 0x5c, 0x53, 0x34, 0x98, 0xec, 0x8f, 0x69, 0x29, 0x56, + 0x3c, 0xf7, 0x82, 0xa6, 0xb9, 0xb0, 0xf5, 0x67, 0xf9, 0x8e, 0xb0, 0xdc, 0x6e, 0x37, 0xa5, 0x4b, + 0x9a, 0x9f, 0xbd, 0x5f, 0x37, 0x4c, 0xc8, 0x04, 0x5e, 0xca, 0x4e, 0x6e, 0x1a, 0x3f, 0xd7, 0x5e, + 0x63, 0xcf, 0x90, 0x99, 0x81, 0xef, 0x35, 0x16, 0xd5, 0xeb, 0x00, 0xe5, 0x66, 0x33, 0xc1, 0x1c, + 0x90, 0xd7, 0x4d, 0xe9, 0x69, 0x34, 0xbd, 0x4a, 0x40, 0x13, 0x9d, 0xef, 0xba, 0xca, 0xed, 0x36, + 0x9f, 0x2c, 0x2f, 0xab, 0x09, 0xc3, 0x44, 0x24, 0x4d, 0xf4, 0x38, 0x5e, 0xcc, 0xed, 0xf7, 0x71, + 0x98, 0x45, 0x4f, 0xb6, 0x13, 0xdd, 0xe0, 0x8d, 0xbf, 0x58, 0xaf, 0x36, 0x61, 0x31, 0xa4, 0x5a, + 0x27, 0x26, 0x71, 0xeb, 0x13, 0xbd, 0xff, 0xae, 0x3c, 0x33, 0x31, 0xb8, 0x94, 0x77, 0x39, 0x0b, + 0xad, 0x3c, 0xa5, 0x05, 0x31, 0x98, 0xa2, 0x0a, 0x5e, 0x36, 0xd6, 0x87, 0x64, 0x1d, 0x4b, 0x99, + 0x78, 0xd5, 0xe4, 0x42, 0xfc, 0x45, 0x7e, 0x25, 0x34, 0xe3, 0xa9, 0xfe, 0xcc, 0x3e, 0xb9, 0x07, + 0xd3, 0x7a, 0x8f, 0xaa, 0x76, 0x67, 0xcd, 0xfe, 0x59, 0x72, 0xb6, 0x61, 0x26, 0xf5, 0x01, 0x7d, + 0xb5, 0xc4, 0x76, 0x7b, 0x5e, 0x3f, 0x53, 0x2a, 0x85, 0x73, 0xc2, 0xb2, 0x97, 0x8f, 0xdd, 0xca, + 0xf6, 0xbe, 0x62, 0x1a, 0xfe, 0x31, 0xb4, 0x94, 0x7b, 0xbd, 0x07, 0x95, 0x50, 0xe8, 0xd7, 0xb8, + 0x02, 0x26, 0xca, 0xb8, 0xaa, 0xb9, 0x02, 0x32, 0x0a, 0xb0, 0xba, 0x91, 0xa8, 0x31, 0x30, 0x9d, + 0x82, 0xce, 0x56, 0xf1, 0xb5, 0x6c, 0x99, 0xd1, 0xc0, 0xda, 0x95, 0x49, 0xf0, 0x33, 0x35, 0x93, + 0x8e, 0xee, 0x6d, 0x4b, 0xce, 0xa9, 0xf1, 0x70, 0xf2, 0x2a, 0x67, 0x49, 0x6b, 0x28, 0xb7, 0x8d, + 0xcc, 0xf2, 0xc5, 0xeb, 0x18, 0x73, 0xdb, 0x18, 0x48, 0x59, 0xc3, 0x6b, 0x5d, 0x69, 0x34, 0x8b, + 0x8e, 0x7c, 0xc5, 0xfd, 0x38, 0x66, 0x11, 0xba, 0x1f, 0x27, 0x55, 0xfe, 0x95, 0x6c, 0x02, 0x5d, + 0xb8, 0xc3, 0x0f, 0x6d, 0x4d, 0x92, 0x80, 0xe8, 0xa6, 0x52, 0x0c, 0x17, 0x1f, 0x1b, 0xa9, 0x24, + 0x7a, 0x11, 0x0f, 0xe5, 0x37, 0x98, 0xa1, 0xa5, 0x34, 0xe4, 0x89, 0xb6, 0x29, 0x9b, 0x50, 0x8c, + 0x3a, 0x33, 0xd6, 0x80, 0x53, 0x76, 0xa5, 0x54, 0xc6, 0xf9, 0xe8, 0x3b, 0x8e, 0x4b, 0x7c, 0x2d, + 0xf1, 0xa5, 0x67, 0x28, 0xa6, 0x6b, 0x11, 0x7c, 0x3e, 0xd7, 0x92, 0xea, 0x5f, 0x88, 0x9c, 0xb8, + 0x11, 0x34, 0x65, 0x3e, 0xd7, 0x91, 0xca, 0x58, 0x9d, 0x30, 0x10, 0xd9, 0xad, 0xbe, 0x94, 0x26, + 0x27, 0x48, 0xce, 0xb8, 0x5a, 0xbd, 0xe4, 0x3e, 0x2d, 0x8e, 0x38, 0xcd, 0x8c, 0x7b, 0x92, 0xaa, + 0x65, 0xc9, 0x59, 0x84, 0x51, 0x5e, 0x5b, 0xbe, 0x90, 0x9e, 0x37, 0xd4, 0x64, 0xac, 0xa1, 0x73, + 0x46, 0xe3, 0xcc, 0xe5, 0x73, 0x01, 0x5d, 0xc9, 0x12, 0x9c, 0x5d, 0x8b, 0x0b, 0x49, 0x19, 0x86, + 0x1b, 0x59, 0x69, 0x81, 0xd7, 0xe6, 0x62, 0x5c, 0x39, 0x46, 0x85, 0xb2, 0x9b, 0x44, 0x74, 0xd5, + 0xf4, 0xa8, 0x52, 0xf6, 0xfe, 0x75, 0x4a, 0x3c, 0xc3, 0x8d, 0x2f, 0x61, 0xc9, 0x9c, 0x97, 0xe7, + 0x94, 0x4f, 0x4c, 0x83, 0xa2, 0x83, 0x22, 0x5d, 0xcc, 0x16, 0x5e, 0x1f, 0xa1, 0x7e, 0x98, 0xc8, + 0x69, 0xf9, 0x8a, 0xb1, 0x79, 0x8b, 0xa3, 0xb3, 0xf7, 0x6e, 0x6a, 0xce, 0xce, 0x94, 0x98, 0x8e, + 0xee, 0xa5, 0xb6, 0xef, 0x6b, 0x73, 0x76, 0x9c, 0x37, 0x20, 0x37, 0xe2, 0x1b, 0xb7, 0x04, 0x49, + 0xef, 0x35, 0x41, 0x84, 0x90, 0xc4, 0x02, 0x48, 0x2d, 0x43, 0x0f, 0x26, 0x32, 0x5b, 0x0b, 0xb6, + 0x1c, 0xff, 0x19, 0xd2, 0xd2, 0x90, 0xbd, 0x6a, 0xf8, 0xa5, 0x36, 0xd1, 0x99, 0x9c, 0x81, 0x32, + 0xc7, 0xb3, 0x08, 0x7a, 0xc9, 0xde, 0xc0, 0x2b, 0x4d, 0xb1, 0x06, 0xba, 0x75, 0xaa, 0x76, 0x36, + 0xa9, 0xd8, 0xec, 0xf6, 0x2f, 0xcb, 0x9d, 0x52, 0x5c, 0xde, 0xb9, 0x98, 0xd3, 0xb6, 0x57, 0xc5, + 0xbe, 0x96, 0x93, 0x71, 0xac, 0x4d, 0x78, 0xa9, 0xe8, 0xb5, 0x6e, 0xad, 0xd6, 0x1e, 0x3c, 0xed, + 0x62, 0x06, 0x4d, 0x56, 0xdd, 0xfd, 0x96, 0xba, 0x89, 0x50, 0xb5, 0x95, 0x11, 0xa4, 0xc1, 0xe2, + 0x53, 0x8c, 0x81, 0x52, 0xf9, 0x79, 0xa6, 0xe5, 0xee, 0x5d, 0xa1, 0xa9, 0x1f, 0x92, 0x04, 0x8f, + 0xe6, 0x6e, 0xbd, 0x90, 0x8a, 0x4b, 0x0a, 0x54, 0x5b, 0x94, 0xfb, 0x0f, 0xb7, 0x95, 0x40, 0x1d, + 0x18, 0x17, 0x68, 0xe2, 0x54, 0x42, 0x84, 0xa1, 0x65, 0x8a, 0xaf, 0xef, 0xeb, 0x5e, 0x17, 0xed, + 0x55, 0xfd, 0x98, 0xd3, 0x83, 0x7c, 0x0c, 0x23, 0x18, 0xc9, 0x85, 0x8e, 0x92, 0x59, 0x3d, 0x15, + 0x1b, 0x83, 0x48, 0xa6, 0x62, 0x12, 0x21, 0x0a, 0x7c, 0x5b, 0x3a, 0x3e, 0xb0, 0xcc, 0xa2, 0xe9, + 0x30, 0xca, 0x2e, 0xf6, 0x6d, 0xe9, 0xf5, 0x30, 0xd8, 0x22, 0x50, 0x06, 0xdb, 0xf7, 0x60, 0x8c, + 0x8f, 0x51, 0xfc, 0x3d, 0xaf, 0x31, 0x4a, 0x60, 0x06, 0xe3, 0xbb, 0xf2, 0x48, 0x03, 0xcb, 0x33, + 0x91, 0xdd, 0x57, 0xf1, 0x8f, 0xa5, 0x97, 0xc5, 0xa8, 0x69, 0x04, 0xea, 0x35, 0xfa, 0xb6, 0x60, + 0x4c, 0x7f, 0xf0, 0x57, 0x75, 0x6d, 0xca, 0x93, 0xdd, 0xaa, 0x6b, 0xd3, 0x9e, 0xdc, 0x8e, 0x5c, + 0xfe, 0x5f, 0x48, 0x97, 0x42, 0x24, 0xf4, 0x92, 0x51, 0xad, 0x84, 0xdc, 0xcb, 0x59, 0xe8, 0xb8, + 0xe8, 0x2a, 0x14, 0xe2, 0xaf, 0x13, 0x2b, 0x7b, 0x2c, 0xe3, 0x19, 0x69, 0x65, 0xe4, 0x65, 0x3e, + 0x6b, 0xbc, 0x25, 0xfd, 0xe3, 0xa6, 0xdc, 0xab, 0xe9, 0x95, 0xd2, 0x45, 0x67, 0x3b, 0xcc, 0xc7, + 0x8d, 0x87, 0x8a, 0x75, 0x4b, 0x39, 0xf1, 0x10, 0xb2, 0xbe, 0xb3, 0x4a, 0x79, 0xdb, 0xd8, 0x95, + 0x49, 0xab, 0x52, 0x8f, 0x6c, 0x95, 0xb3, 0xa0, 0xf7, 0xab, 0x16, 0x3d, 0x8f, 0x7f, 0xc9, 0x2f, + 0xc0, 0x6c, 0x46, 0x96, 0x7e, 0x72, 0x3d, 0xe6, 0x69, 0x4d, 0xcf, 0xe2, 0xaf, 0x06, 0x48, 0xda, + 0x93, 0xea, 0x64, 0x1d, 0xe3, 0x06, 0x8c, 0x14, 0x12, 0x89, 0xb3, 0xb8, 0x87, 0x6e, 0x78, 0xc0, + 0x1f, 0xca, 0xd7, 0xa6, 0xcd, 0xd4, 0xdc, 0x13, 0xa4, 0x8a, 0xb6, 0x88, 0x01, 0x4d, 0x39, 0x8e, + 0x4b, 0x11, 0x38, 0x97, 0x2e, 0x90, 0xcd, 0x1d, 0x6c, 0x2c, 0xa4, 0xe4, 0xf7, 0x50, 0x63, 0x21, + 0x3b, 0xf7, 0x47, 0x66, 0x35, 0xb7, 0xe4, 0x1e, 0x29, 0x5d, 0x62, 0x76, 0xaa, 0x8f, 0x4c, 0x89, + 0xf7, 0x99, 0xc4, 0x44, 0xf6, 0x0e, 0x92, 0x41, 0xde, 0x7d, 0xf6, 0xb0, 0xe5, 0x92, 0x6b, 0x72, + 0xcd, 0x6b, 0xf5, 0xcb, 0xca, 0x13, 0x92, 0x59, 0xbf, 0x25, 0xf9, 0x3d, 0xa5, 0xd7, 0xef, 0xa4, + 0x8b, 0xae, 0x3a, 0xff, 0x8a, 0x25, 0x90, 0x31, 0x1a, 0xaa, 0xc1, 0xe7, 0x32, 0xe0, 0x64, 0x03, + 0x03, 0x81, 0xe2, 0x50, 0xcd, 0x28, 0x4d, 0xcf, 0x50, 0x93, 0x29, 0x8f, 0x8f, 0x63, 0x23, 0xc3, + 0xc7, 0x69, 0xc6, 0x71, 0x2c, 0x35, 0x88, 0x18, 0xc7, 0x06, 0xf4, 0x74, 0xe3, 0x38, 0x26, 0xd0, + 0x1c, 0xc7, 0xf1, 0x6a, 0xc6, 0x2d, 0xfd, 0xcc, 0x5e, 0x8d, 0x57, 0x53, 0x8d, 0xe3, 0x74, 0x89, + 0xd9, 0x99, 0x58, 0x32, 0x25, 0xaa, 0x71, 0x6c, 0x4a, 0xcc, 0x20, 0x3f, 0xe1, 0x38, 0x8e, 0x17, + 0x62, 0x8e, 0xe3, 0x53, 0xd5, 0x4f, 0x8d, 0xe3, 0xf4, 0xfa, 0x9d, 0x7a, 0x1c, 0xc7, 0x52, 0x17, + 0x19, 0x0d, 0x4d, 0x1b, 0xc7, 0x71, 0x7a, 0x3e, 0x8e, 0xe3, 0xd0, 0x98, 0x73, 0xa5, 0xcb, 0x38, + 0x8e, 0x73, 0x7e, 0x86, 0xf2, 0x62, 0x69, 0x57, 0x4e, 0x32, 0x92, 0x33, 0x33, 0xb6, 0x90, 0x87, + 0xe8, 0xde, 0x8b, 0xc1, 0x4f, 0x36, 0x9a, 0x2f, 0x66, 0x09, 0xc5, 0xf1, 0xbc, 0x2b, 0x95, 0x18, + 0xaf, 0xae, 0xe9, 0xbb, 0x4a, 0xcf, 0x3a, 0xd3, 0xa5, 0xc2, 0xbb, 0x6c, 0xdc, 0x34, 0xba, 0xc8, + 0xed, 0x96, 0x34, 0xa7, 0x8b, 0x5c, 0x65, 0xca, 0xc4, 0xe5, 0x66, 0xb2, 0x74, 0x1f, 0xdf, 0x9f, + 0xcb, 0x03, 0x8e, 0x38, 0xdf, 0x7c, 0xcc, 0x38, 0x3a, 0x75, 0x4d, 0x95, 0x91, 0x14, 0xaf, 0xe9, + 0x69, 0xc7, 0xf9, 0xba, 0xdc, 0x3d, 0x24, 0xb2, 0x6d, 0xc5, 0x1a, 0xad, 0x8f, 0xf5, 0x4c, 0x0c, + 0xd9, 0x46, 0x5f, 0x6e, 0x12, 0xae, 0xf9, 0x81, 0xb3, 0xd2, 0x7a, 0xf5, 0x94, 0x9a, 0xc8, 0x1b, + 0xa4, 0x4b, 0xcd, 0x4a, 0x2a, 0xa4, 0xa4, 0x26, 0xb9, 0x3f, 0x41, 0xef, 0x97, 0xb8, 0x71, 0xd5, + 0x7a, 0xe4, 0x65, 0x7b, 0x52, 0xa6, 0x8c, 0x60, 0x25, 0x46, 0x8b, 0x31, 0x62, 0x1f, 0x8a, 0x13, + 0x3c, 0x09, 0xcc, 0x54, 0x7e, 0x1a, 0x3f, 0xf9, 0x04, 0x0a, 0x62, 0x7a, 0x8b, 0x04, 0xa4, 0x11, + 0x66, 0x76, 0x5d, 0x45, 0x3a, 0xdd, 0x4e, 0x50, 0x83, 0x93, 0x38, 0xdb, 0x4e, 0xa2, 0x89, 0x6c, + 0xcf, 0x14, 0x5b, 0x0e, 0xb7, 0xfd, 0x4e, 0x10, 0xd2, 0x46, 0xd2, 0xa3, 0x64, 0x56, 0x46, 0x46, + 0x46, 0x98, 0xe4, 0xbb, 0xf3, 0x64, 0x15, 0xe7, 0x36, 0x13, 0xdc, 0xcd, 0xe5, 0x96, 0x2e, 0x06, + 0xa7, 0x9e, 0x75, 0x75, 0xad, 0xc7, 0xac, 0x53, 0x56, 0xd9, 0x99, 0x95, 0x92, 0x07, 0xda, 0x42, + 0x4f, 0x27, 0x6c, 0x62, 0x96, 0x9e, 0x3e, 0xc0, 0x58, 0x00, 0xee, 0x03, 0xec, 0xa5, 0x9e, 0xf8, + 0x6d, 0x23, 0xf2, 0x29, 0x8c, 0x48, 0xe6, 0xde, 0x5a, 0x89, 0x73, 0xa3, 0x56, 0x16, 0x61, 0xdc, + 0xb8, 0x4a, 0xa5, 0x4c, 0x9c, 0xb4, 0x0b, 0x56, 0x5d, 0x3a, 0x7b, 0xdc, 0xb8, 0x32, 0xa5, 0xa4, + 0xa4, 0x5d, 0xa4, 0xca, 0x94, 0xf2, 0x11, 0x8c, 0x0a, 0x95, 0x76, 0xd5, 0x46, 0xb6, 0xd3, 0x6d, + 0x46, 0x0b, 0x4b, 0xee, 0x34, 0xdc, 0x70, 0xc1, 0x6b, 0x3d, 0x72, 0xf7, 0x7b, 0x2a, 0x26, 0xc9, + 0xb2, 0x3b, 0x4f, 0xbe, 0xc2, 0xb7, 0xe5, 0xe5, 0x8b, 0xff, 0x34, 0x7c, 0xea, 0xf9, 0x8f, 0xdd, + 0xd6, 0x7e, 0x0f, 0x91, 0x57, 0x4c, 0x91, 0x71, 0x3e, 0x39, 0x78, 0xbe, 0x82, 0xb9, 0x6a, 0xb6, + 0xf0, 0x9e, 0x42, 0xba, 0xaf, 0x31, 0x55, 0xb8, 0x88, 0x21, 0x34, 0xa7, 0xad, 0x7b, 0x57, 0xa1, + 0x5f, 0xf0, 0xac, 0x8d, 0xd2, 0x61, 0x5f, 0xf7, 0xfc, 0x46, 0x6f, 0x89, 0x25, 0x33, 0x9a, 0x36, + 0xc6, 0x26, 0x95, 0xf1, 0x05, 0x9c, 0xaf, 0x66, 0x8a, 0xee, 0x25, 0xa2, 0xd7, 0x76, 0xf2, 0x02, + 0xaa, 0xe2, 0x94, 0xf5, 0xee, 0x2a, 0x73, 0x15, 0x27, 0x36, 0xb6, 0x18, 0x6d, 0xf9, 0xf4, 0x11, + 0xf5, 0x31, 0x66, 0xbb, 0x57, 0xb4, 0xb2, 0x49, 0x2e, 0x5b, 0xbe, 0x0a, 0x67, 0xab, 0x09, 0x51, + 0x59, 0x2c, 0xbd, 0x0e, 0x81, 0xa6, 0xb0, 0xa5, 0x27, 0xac, 0x57, 0x8f, 0x50, 0xa1, 0xd1, 0x65, + 0x1a, 0xee, 0xac, 0xf6, 0xd0, 0x92, 0xbc, 0x54, 0x20, 0x09, 0x77, 0xef, 0x32, 0xce, 0xaa, 0xc6, + 0x99, 0xa4, 0xc8, 0xfc, 0x78, 0x3f, 0x95, 0x07, 0x22, 0x3d, 0x8b, 0xcd, 0x92, 0xf0, 0x26, 0xce, + 0x85, 0x22, 0x6e, 0x79, 0x36, 0xda, 0x07, 0x70, 0x48, 0xe4, 0xaf, 0xd3, 0x42, 0x98, 0x03, 0x52, + 0xe6, 0x36, 0x20, 0x1f, 0x1e, 0x02, 0x76, 0x39, 0x11, 0xcf, 0xde, 0x55, 0x04, 0x77, 0x85, 0xae, + 0x79, 0xf5, 0xc7, 0xba, 0x2b, 0x94, 0xfd, 0x8e, 0xfb, 0x08, 0x19, 0x6c, 0x77, 0x5e, 0xcc, 0xf8, + 0xec, 0x87, 0x11, 0xfd, 0x85, 0x80, 0x68, 0xc6, 0x8f, 0xc3, 0x85, 0x1b, 0xe9, 0x4d, 0xe9, 0x60, + 0xc4, 0x02, 0x4d, 0xc9, 0x99, 0xaa, 0x51, 0xbe, 0x45, 0x64, 0x32, 0x7d, 0x8b, 0x7a, 0x45, 0xb3, + 0x1d, 0xfa, 0xc4, 0xa6, 0xed, 0x26, 0x86, 0x42, 0x1f, 0x7a, 0x9c, 0x27, 0x8a, 0x8e, 0x4d, 0xa2, + 0x7a, 0x07, 0x71, 0x4d, 0x89, 0xd0, 0x1f, 0x43, 0xf1, 0x2a, 0xab, 0x72, 0x12, 0x17, 0xa9, 0x52, + 0x8f, 0x48, 0xba, 0x93, 0x23, 0x1b, 0x70, 0x6e, 0x99, 0x86, 0x62, 0x8e, 0xb3, 0x69, 0x10, 0xfa, + 0x6e, 0x3d, 0xec, 0x7a, 0x3a, 0x28, 0x0d, 0x94, 0x14, 0x9e, 0xdd, 0xb7, 0x98, 0xbc, 0x6a, 0xba, + 0xbc, 0xae, 0x7c, 0x5d, 0xe2, 0x64, 0xc5, 0x91, 0xc3, 0x69, 0xaa, 0x98, 0x3d, 0xc4, 0x87, 0x78, + 0x18, 0x4e, 0x36, 0x6b, 0x21, 0x4a, 0x81, 0x22, 0x4c, 0xae, 0x5b, 0x30, 0xc8, 0x99, 0x32, 0x17, + 0xd4, 0x31, 0x9d, 0x87, 0xdc, 0x85, 0x11, 0x15, 0x47, 0x43, 0x0c, 0x54, 0x66, 0xbd, 0xee, 0xc2, + 0x08, 0xb7, 0xaf, 0x4e, 0xce, 0xf2, 0x01, 0x8c, 0xa8, 0xc0, 0x9b, 0x53, 0xaf, 0xf4, 0x9f, 0xc0, + 0xb8, 0x1e, 0x82, 0x73, 0x7a, 0x45, 0x7e, 0x84, 0x67, 0xb8, 0xf2, 0xa8, 0x24, 0x9b, 0x7f, 0x26, + 0x96, 0x19, 0x46, 0xa8, 0x94, 0x4f, 0x90, 0x12, 0x98, 0x59, 0xfd, 0xb3, 0x09, 0x6e, 0xf2, 0x81, + 0xbc, 0xce, 0xa4, 0x98, 0x93, 0x44, 0x5d, 0x74, 0x36, 0xc1, 0xd5, 0xfc, 0x3c, 0xcc, 0x6a, 0x82, + 0xed, 0x59, 0xed, 0x93, 0x9c, 0x35, 0xf7, 0x56, 0x5d, 0x96, 0x94, 0x4d, 0xdc, 0xa5, 0x25, 0x5e, + 0x63, 0xcc, 0x16, 0x74, 0x39, 0xfb, 0x01, 0x47, 0xec, 0x8c, 0xfb, 0x68, 0x0a, 0x26, 0xb0, 0x99, + 0xcd, 0xeb, 0xf2, 0x20, 0x64, 0x64, 0xfb, 0x26, 0xc5, 0x75, 0x61, 0xeb, 0x66, 0x4a, 0x8b, 0x4b, + 0x9a, 0x2f, 0x45, 0xdc, 0xaa, 0x8c, 0x64, 0x3c, 0x79, 0x63, 0xb3, 0x6b, 0x76, 0x21, 0xe5, 0x74, + 0xbb, 0x67, 0x5f, 0x64, 0x89, 0xfb, 0x05, 0xdc, 0x1d, 0xa6, 0xa6, 0x06, 0xcb, 0x16, 0x76, 0x43, + 0x0b, 0x90, 0x48, 0xe5, 0x54, 0x8b, 0xde, 0x63, 0xbc, 0x27, 0x96, 0xfe, 0x5e, 0xe5, 0xab, 0x3d, + 0xa4, 0x48, 0x4d, 0xbc, 0xd6, 0x93, 0x4e, 0x9d, 0x95, 0x5e, 0xe0, 0x2b, 0x6c, 0x7a, 0x79, 0x3d, + 0xde, 0xdf, 0x4c, 0x39, 0xbe, 0x56, 0x61, 0xa2, 0xe9, 0x02, 0xcd, 0x30, 0xd1, 0xae, 0x6d, 0xc8, + 0x52, 0xff, 0x67, 0x50, 0x8a, 0xa2, 0x40, 0x4e, 0xd7, 0x09, 0xd9, 0xd1, 0x89, 0x24, 0xa1, 0xa9, + 0x80, 0x74, 0x7b, 0xb7, 0x69, 0xee, 0x6a, 0x96, 0x86, 0xf5, 0xbb, 0x30, 0x22, 0xba, 0x2d, 0xf6, + 0x72, 0x6b, 0xd6, 0x1b, 0xb0, 0x5d, 0x9c, 0xb1, 0xe2, 0xe2, 0xdc, 0x4b, 0x11, 0x94, 0xec, 0xed, + 0xd3, 0x0b, 0x52, 0x41, 0x1a, 0x31, 0x41, 0x56, 0x97, 0xee, 0xed, 0x7d, 0xfe, 0x58, 0xcc, 0xe8, + 0xd7, 0xd3, 0x77, 0xa8, 0x13, 0x5d, 0x16, 0x8b, 0x65, 0x12, 0xd4, 0x2f, 0xe8, 0x26, 0x51, 0xf1, + 0x9b, 0x4e, 0x69, 0x14, 0x2a, 0x32, 0xaa, 0x28, 0x8b, 0x60, 0x70, 0x66, 0x8a, 0x78, 0xbe, 0x1b, + 0x3e, 0x5b, 0xb0, 0xd7, 0x22, 0xb7, 0x82, 0x8e, 0x90, 0xb2, 0x41, 0x22, 0xed, 0x35, 0xf2, 0x25, + 0x4e, 0x25, 0x42, 0x7c, 0xc5, 0xf3, 0xc2, 0x20, 0xf4, 0x9d, 0x76, 0x15, 0x5f, 0xb4, 0xce, 0x6c, + 0x74, 0x14, 0xc8, 0x9d, 0xc6, 0xa6, 0xc5, 0x95, 0x8a, 0x64, 0xf6, 0x69, 0xe9, 0x6f, 0xd4, 0xdd, + 0x9a, 0x34, 0x64, 0x17, 0xcb, 0xa5, 0x2a, 0xd3, 0xd7, 0xbf, 0x4c, 0xa1, 0x35, 0x98, 0xcd, 0x48, + 0x1a, 0xa4, 0x8e, 0x70, 0xbb, 0x27, 0x15, 0x9a, 0xeb, 0x5e, 0x30, 0xf9, 0x0a, 0x66, 0x52, 0xb3, + 0x0a, 0x29, 0x37, 0x74, 0xb7, 0x9c, 0x43, 0xbd, 0x84, 0x3f, 0x86, 0x22, 0xbf, 0xd5, 0x81, 0xc1, + 0xcb, 0x46, 0x82, 0x99, 0xe8, 0xae, 0x4f, 0x06, 0x41, 0x7c, 0xbe, 0xce, 0xa6, 0x53, 0x37, 0xce, + 0xa7, 0x31, 0xb3, 0x88, 0x7c, 0x82, 0x9b, 0xd6, 0xbd, 0x27, 0xd4, 0x7f, 0xa6, 0x3e, 0xbc, 0x34, + 0x64, 0xb7, 0x0b, 0x45, 0x5b, 0x30, 0xb3, 0x4b, 0x7d, 0xf7, 0xd1, 0xb3, 0xb8, 0x40, 0xa9, 0x99, + 0x54, 0x6c, 0x37, 0x89, 0x9f, 0xc3, 0xec, 0x82, 0x77, 0xd8, 0x16, 0x57, 0xf7, 0x0c, 0x99, 0xea, + 0x3c, 0x3e, 0x1d, 0xdf, 0x3b, 0xa0, 0x69, 0x4e, 0xdd, 0x2d, 0xd4, 0xf9, 0x16, 0xf0, 0x4e, 0xeb, + 0x0d, 0x33, 0xa6, 0x20, 0x85, 0x24, 0xba, 0x91, 0x21, 0x4d, 0x39, 0x9d, 0x7f, 0x1b, 0x07, 0x61, + 0x8c, 0x8f, 0xfb, 0xe6, 0xb4, 0x41, 0x98, 0x86, 0xef, 0x7e, 0x11, 0x2c, 0x45, 0x2a, 0x2f, 0x30, + 0x5b, 0xea, 0x09, 0x6a, 0xbb, 0x21, 0xd7, 0x96, 0x2d, 0xdf, 0x7d, 0xe2, 0x36, 0xe9, 0xbe, 0x70, + 0x23, 0x9a, 0x91, 0xd3, 0x26, 0xb2, 0x5b, 0x3d, 0xb5, 0xd4, 0x0a, 0xcd, 0x66, 0x97, 0x2d, 0x16, + 0xd1, 0x73, 0x2b, 0x30, 0x4a, 0xf4, 0xe4, 0x8f, 0xeb, 0xbc, 0xdd, 0x66, 0xeb, 0x04, 0x33, 0x6e, + 0x6a, 0xdf, 0x87, 0xb1, 0xaa, 0x5e, 0x78, 0x4a, 0x21, 0x99, 0x83, 0x42, 0x5d, 0x05, 0xea, 0x5d, + 0xf7, 0x2e, 0x01, 0xa1, 0x6a, 0xe1, 0x39, 0x51, 0x2b, 0x32, 0xe3, 0x67, 0x8c, 0x07, 0xe8, 0xd4, + 0x2a, 0x90, 0xf6, 0x06, 0xa7, 0x8a, 0x9f, 0x49, 0x7f, 0xb3, 0xae, 0xc6, 0x9f, 0xb5, 0x89, 0x3f, + 0xb1, 0x4a, 0xac, 0xde, 0x6f, 0x19, 0xab, 0xc0, 0xf8, 0xae, 0x6f, 0xb4, 0xf2, 0x60, 0x9f, 0xe8, + 0xc9, 0x3d, 0x3d, 0xd8, 0x27, 0xf1, 0x90, 0x9f, 0x1e, 0xec, 0x93, 0xf2, 0x4a, 0x5f, 0x15, 0x0a, + 0xf1, 0x37, 0x04, 0x95, 0x5b, 0x29, 0xe3, 0x89, 0x44, 0x15, 0xd6, 0x93, 0xf9, 0xf8, 0xe0, 0x12, + 0x56, 0x30, 0x7a, 0x64, 0xa8, 0x8b, 0x87, 0x43, 0xd5, 0x2d, 0xe5, 0x2d, 0xa3, 0x07, 0x7a, 0xda, + 0x0f, 0xfe, 0x34, 0x51, 0x17, 0x07, 0x6e, 0x3c, 0xdd, 0x47, 0xec, 0x2d, 0xa3, 0x7b, 0x50, 0xe0, + 0xaf, 0x34, 0x44, 0xd9, 0x12, 0xa3, 0xa0, 0xc2, 0xe4, 0xe3, 0x11, 0x5d, 0x46, 0x4a, 0x21, 0x9e, + 0x63, 0x4e, 0x29, 0x2c, 0x23, 0xf9, 0x5c, 0x97, 0xf1, 0x0f, 0x51, 0x26, 0x39, 0xe5, 0xed, 0x4a, + 0x24, 0x97, 0x9b, 0x3b, 0x9f, 0x82, 0x51, 0xfb, 0xd4, 0x31, 0x3d, 0xef, 0x9c, 0x6a, 0x52, 0x4a, + 0x32, 0xba, 0xb9, 0x0b, 0xa9, 0x38, 0x21, 0x28, 0xe4, 0x6f, 0x84, 0xa7, 0x3f, 0xd9, 0x1e, 0x5d, + 0x11, 0xeb, 0x42, 0x23, 0x8b, 0xb9, 0x79, 0x12, 0x52, 0x51, 0x2a, 0x55, 0x4f, 0x2c, 0xa5, 0xbc, + 0x13, 0xff, 0x5a, 0xca, 0x2d, 0x0e, 0x83, 0x22, 0x1a, 0x90, 0xdd, 0x1f, 0xad, 0x27, 0x0f, 0xe5, + 0x93, 0x37, 0x19, 0x25, 0xf5, 0x12, 0x90, 0xd9, 0x83, 0x0f, 0xe5, 0x23, 0x37, 0x2f, 0x5b, 0xf0, + 0x1e, 0x5c, 0x8c, 0x5d, 0x0d, 0x31, 0x05, 0xdf, 0x4c, 0xbf, 0x3f, 0x92, 0xaa, 0x9e, 0x6c, 0x43, + 0xe0, 0x4a, 0xf2, 0x0a, 0x49, 0xac, 0xdf, 0x4f, 0x3b, 0x91, 0xae, 0xc3, 0x04, 0xce, 0x5d, 0x01, + 0xf5, 0x97, 0x7d, 0xaf, 0xd3, 0x8e, 0xb2, 0xce, 0x98, 0xe0, 0x78, 0xfa, 0xa3, 0x38, 0x56, 0xdd, + 0x4c, 0x1f, 0x13, 0xd7, 0x8d, 0x11, 0xa1, 0x67, 0xc3, 0x51, 0xc0, 0xb4, 0xa5, 0x11, 0x11, 0xbb, + 0x77, 0xc9, 0x47, 0x30, 0x19, 0xdd, 0x42, 0xe6, 0x22, 0x52, 0xc8, 0xba, 0x78, 0xdf, 0x26, 0xa3, + 0xab, 0xc8, 0xa7, 0x67, 0x5f, 0x91, 0xeb, 0x5b, 0xc4, 0x7e, 0x29, 0x71, 0x91, 0xc6, 0x68, 0xc3, + 0x49, 0x96, 0x39, 0x4d, 0xb7, 0xa7, 0xed, 0x9d, 0x3a, 0x7e, 0x6e, 0xe9, 0x09, 0x15, 0xf5, 0xcf, + 0xad, 0x6b, 0xd2, 0x47, 0xb5, 0xa7, 0xce, 0x90, 0xb3, 0x0e, 0xd7, 0x30, 0x09, 0xcb, 0x16, 0x4f, + 0xbb, 0x97, 0x4e, 0x95, 0x5d, 0xf7, 0x78, 0xea, 0x96, 0x26, 0x5c, 0xed, 0x99, 0x51, 0x92, 0xdc, + 0x36, 0x82, 0x67, 0x7a, 0xe7, 0x9e, 0xec, 0x62, 0xce, 0x4c, 0xa7, 0x25, 0x66, 0x54, 0x8b, 0x77, + 0x97, 0x1c, 0x91, 0x6a, 0xf1, 0xee, 0x9a, 0xd9, 0xf1, 0x73, 0x7c, 0x47, 0x4a, 0xac, 0x51, 0x98, + 0x58, 0x89, 0xb6, 0x78, 0xba, 0xe9, 0xae, 0x67, 0x49, 0x57, 0xcd, 0x93, 0xd6, 0x04, 0x23, 0x1a, + 0x4a, 0x97, 0x85, 0x79, 0x97, 0x25, 0xbc, 0xb7, 0x90, 0x2e, 0x41, 0xdb, 0x97, 0xf9, 0x00, 0x3c, + 0x75, 0xcd, 0x33, 0xe0, 0x95, 0xc5, 0x9f, 0xfc, 0x97, 0xcb, 0xb9, 0x9f, 0xfc, 0xf4, 0x72, 0xee, + 0x3f, 0xfc, 0xf4, 0x72, 0xee, 0x3f, 0xff, 0xf4, 0x72, 0xee, 0xcb, 0xf9, 0x93, 0x25, 0x3d, 0xe6, + 0x2f, 0x3f, 0xde, 0xe6, 0xe2, 0x06, 0xf1, 0xbf, 0x37, 0xff, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xf4, 0x4b, 0x4f, 0x24, 0xf2, 0xf0, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -17457,6 +17612,8 @@ type AuthServiceClient interface { // GetTrustedClusters gets all current Trusted Cluster resources. GetTrustedClusters(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.TrustedClusterV2List, error) // UpsertTrustedCluster upserts a Trusted Cluster in a backend. + // + // Deprecated: Use [teleport.trust.v1.UpsertTrustedCluster] instead. UpsertTrustedCluster(ctx context.Context, in *types.TrustedClusterV2, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) // DeleteTrustedCluster deletes an existing Trusted Cluster in a backend by name. DeleteTrustedCluster(ctx context.Context, in *types.ResourceRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) @@ -17687,6 +17844,8 @@ type AuthServiceClient interface { // which is what we want when handling things like ambiguous host errors and resource-based access requests, // but may result in confusing behavior if it is used outside of those contexts. GetSSHTargets(ctx context.Context, in *GetSSHTargetsRequest, opts ...grpc.CallOption) (*GetSSHTargetsResponse, error) + // ResolveSSHTarget returns the server that would be resolved in an equivalent ssh dial request. + ResolveSSHTarget(ctx context.Context, in *ResolveSSHTargetRequest, opts ...grpc.CallOption) (*ResolveSSHTargetResponse, error) // GetDomainName returns local auth domain of the current auth server GetDomainName(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetDomainNameResponse, error) // GetClusterCACert returns the PEM-encoded TLS certs for the local cluster @@ -19436,6 +19595,7 @@ func (c *authServiceClient) GetTrustedClusters(ctx context.Context, in *emptypb. return out, nil } +// Deprecated: Do not use. func (c *authServiceClient) UpsertTrustedCluster(ctx context.Context, in *types.TrustedClusterV2, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) { out := new(types.TrustedClusterV2) err := c.cc.Invoke(ctx, "/proto.AuthService/UpsertTrustedCluster", in, out, opts...) @@ -20215,6 +20375,15 @@ func (c *authServiceClient) GetSSHTargets(ctx context.Context, in *GetSSHTargets return out, nil } +func (c *authServiceClient) ResolveSSHTarget(ctx context.Context, in *ResolveSSHTargetRequest, opts ...grpc.CallOption) (*ResolveSSHTargetResponse, error) { + out := new(ResolveSSHTargetResponse) + err := c.cc.Invoke(ctx, "/proto.AuthService/ResolveSSHTarget", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *authServiceClient) GetDomainName(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetDomainNameResponse, error) { out := new(GetDomainNameResponse) err := c.cc.Invoke(ctx, "/proto.AuthService/GetDomainName", in, out, opts...) @@ -20835,6 +21004,8 @@ type AuthServiceServer interface { // GetTrustedClusters gets all current Trusted Cluster resources. GetTrustedClusters(context.Context, *emptypb.Empty) (*types.TrustedClusterV2List, error) // UpsertTrustedCluster upserts a Trusted Cluster in a backend. + // + // Deprecated: Use [teleport.trust.v1.UpsertTrustedCluster] instead. UpsertTrustedCluster(context.Context, *types.TrustedClusterV2) (*types.TrustedClusterV2, error) // DeleteTrustedCluster deletes an existing Trusted Cluster in a backend by name. DeleteTrustedCluster(context.Context, *types.ResourceRequest) (*emptypb.Empty, error) @@ -21065,6 +21236,8 @@ type AuthServiceServer interface { // which is what we want when handling things like ambiguous host errors and resource-based access requests, // but may result in confusing behavior if it is used outside of those contexts. GetSSHTargets(context.Context, *GetSSHTargetsRequest) (*GetSSHTargetsResponse, error) + // ResolveSSHTarget returns the server that would be resolved in an equivalent ssh dial request. + ResolveSSHTarget(context.Context, *ResolveSSHTargetRequest) (*ResolveSSHTargetResponse, error) // GetDomainName returns local auth domain of the current auth server GetDomainName(context.Context, *emptypb.Empty) (*GetDomainNameResponse, error) // GetClusterCACert returns the PEM-encoded TLS certs for the local cluster @@ -21817,6 +21990,9 @@ func (*UnimplementedAuthServiceServer) ListUnifiedResources(ctx context.Context, func (*UnimplementedAuthServiceServer) GetSSHTargets(ctx context.Context, req *GetSSHTargetsRequest) (*GetSSHTargetsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetSSHTargets not implemented") } +func (*UnimplementedAuthServiceServer) ResolveSSHTarget(ctx context.Context, req *ResolveSSHTargetRequest) (*ResolveSSHTargetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ResolveSSHTarget not implemented") +} func (*UnimplementedAuthServiceServer) GetDomainName(ctx context.Context, req *emptypb.Empty) (*GetDomainNameResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetDomainName not implemented") } @@ -26120,6 +26296,24 @@ func _AuthService_GetSSHTargets_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _AuthService_ResolveSSHTarget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResolveSSHTargetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).ResolveSSHTarget(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.AuthService/ResolveSSHTarget", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).ResolveSSHTarget(ctx, req.(*ResolveSSHTargetRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AuthService_GetDomainName_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 { @@ -27433,6 +27627,10 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetSSHTargets", Handler: _AuthService_GetSSHTargets_Handler, }, + { + MethodName: "ResolveSSHTarget", + Handler: _AuthService_ResolveSSHTarget_Handler, + }, { MethodName: "GetDomainName", Handler: _AuthService_GetDomainName_Handler, @@ -36310,6 +36508,121 @@ func (m *ListResourcesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ResolveSSHTargetRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveSSHTargetRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveSSHTargetRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.SearchKeywords) > 0 { + for iNdEx := len(m.SearchKeywords) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SearchKeywords[iNdEx]) + copy(dAtA[i:], m.SearchKeywords[iNdEx]) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.SearchKeywords[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } + if len(m.PredicateExpression) > 0 { + i -= len(m.PredicateExpression) + copy(dAtA[i:], m.PredicateExpression) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.PredicateExpression))) + i-- + dAtA[i] = 0x22 + } + if len(m.Labels) > 0 { + for k := range m.Labels { + v := m.Labels[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintAuthservice(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintAuthservice(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintAuthservice(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Port) > 0 { + i -= len(m.Port) + copy(dAtA[i:], m.Port) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.Port))) + i-- + dAtA[i] = 0x12 + } + if len(m.Host) > 0 { + i -= len(m.Host) + copy(dAtA[i:], m.Host) + i = encodeVarintAuthservice(dAtA, i, uint64(len(m.Host))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ResolveSSHTargetResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResolveSSHTargetResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResolveSSHTargetResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Server != nil { + { + size, err := m.Server.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthservice(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *GetSSHTargetsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -36682,12 +36995,12 @@ func (m *SessionTrackerUpdateExpiry) MarshalToSizedBuffer(dAtA []byte) (int, err copy(dAtA[i:], m.XXX_unrecognized) } if m.Expires != nil { - n107, err107 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expires):]) - if err107 != nil { - return 0, err107 + n108, err108 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.Expires):]) + if err108 != nil { + return 0, err108 } - i -= n107 - i = encodeVarintAuthservice(dAtA, i, uint64(n107)) + i -= n108 + i = encodeVarintAuthservice(dAtA, i, uint64(n108)) i-- dAtA[i] = 0xa } @@ -37971,12 +38284,12 @@ func (m *UpstreamInventoryPong) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - n131, err131 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SystemClock, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SystemClock):]) - if err131 != nil { - return 0, err131 + n132, err132 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.SystemClock, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.SystemClock):]) + if err132 != nil { + return 0, err132 } - i -= n131 - i = encodeVarintAuthservice(dAtA, i, uint64(n131)) + i -= n132 + i = encodeVarintAuthservice(dAtA, i, uint64(n132)) i-- dAtA[i] = 0x12 if m.ID != 0 { @@ -43754,6 +44067,60 @@ func (m *ListResourcesRequest) Size() (n int) { return n } +func (m *ResolveSSHTargetRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Host) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } + l = len(m.Port) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } + if len(m.Labels) > 0 { + for k, v := range m.Labels { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovAuthservice(uint64(len(k))) + 1 + len(v) + sovAuthservice(uint64(len(v))) + n += mapEntrySize + 1 + sovAuthservice(uint64(mapEntrySize)) + } + } + l = len(m.PredicateExpression) + if l > 0 { + n += 1 + l + sovAuthservice(uint64(l)) + } + if len(m.SearchKeywords) > 0 { + for _, s := range m.SearchKeywords { + l = len(s) + n += 1 + l + sovAuthservice(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *ResolveSSHTargetResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Server != nil { + l = m.Server.Size() + n += 1 + l + sovAuthservice(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *GetSSHTargetsRequest) Size() (n int) { if m == nil { return 0 @@ -67095,6 +67462,399 @@ func (m *ListResourcesRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResolveSSHTargetRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveSSHTargetRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveSSHTargetRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Host", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Host = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Port = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Labels == nil { + m.Labels = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthAuthservice + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthAuthservice + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthAuthservice + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthAuthservice + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthservice + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Labels[mapkey] = mapvalue + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PredicateExpression", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PredicateExpression = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SearchKeywords", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SearchKeywords = append(m.SearchKeywords, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResolveSSHTargetResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResolveSSHTargetResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResolveSSHTargetResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthservice + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthservice + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthservice + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Server == nil { + m.Server = &types.ServerV2{} + } + if err := m.Server.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthservice(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthservice + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *GetSSHTargetsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/api/client/proto/event.pb.go b/api/client/proto/event.pb.go index 826cb7de67995..0cd4d8e9a4eb5 100644 --- a/api/client/proto/event.pb.go +++ b/api/client/proto/event.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/legacy/client/proto/event.proto diff --git a/api/gen/proto/go/teleport/accessgraph/v1/authorized_key.pb.go b/api/gen/proto/go/teleport/accessgraph/v1/authorized_key.pb.go index 012d25f7f71e1..58afbe766d1bb 100644 --- a/api/gen/proto/go/teleport/accessgraph/v1/authorized_key.pb.go +++ b/api/gen/proto/go/teleport/accessgraph/v1/authorized_key.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/access_graph/v1/authorized_key.proto diff --git a/api/gen/proto/go/teleport/accessgraph/v1/private_key.pb.go b/api/gen/proto/go/teleport/accessgraph/v1/private_key.pb.go index 201326357ea5d..4b93f506a0a29 100644 --- a/api/gen/proto/go/teleport/accessgraph/v1/private_key.pb.go +++ b/api/gen/proto/go/teleport/accessgraph/v1/private_key.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/access_graph/v1/private_key.proto diff --git a/api/gen/proto/go/teleport/accessgraph/v1/secrets_service.pb.go b/api/gen/proto/go/teleport/accessgraph/v1/secrets_service.pb.go index 6925d822a55fe..0159b47a0950d 100644 --- a/api/gen/proto/go/teleport/accessgraph/v1/secrets_service.pb.go +++ b/api/gen/proto/go/teleport/accessgraph/v1/secrets_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/access_graph/v1/secrets_service.proto diff --git a/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go b/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go index ef450e28039cc..1eefd6d3e6c28 100644 --- a/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go +++ b/api/gen/proto/go/teleport/accesslist/v1/accesslist.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/accesslist/v1/accesslist.proto diff --git a/api/gen/proto/go/teleport/accesslist/v1/accesslist_service.pb.go b/api/gen/proto/go/teleport/accesslist/v1/accesslist_service.pb.go index 507d3551927f9..d79fa7dd8b5ce 100644 --- a/api/gen/proto/go/teleport/accesslist/v1/accesslist_service.pb.go +++ b/api/gen/proto/go/teleport/accesslist/v1/accesslist_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/accesslist/v1/accesslist_service.proto diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go index fb61929055642..e5f23f5ae32ab 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/accessmonitoringrules/v1/access_monitoring_rules.proto diff --git a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go index 72b194b85bbb7..624bdd8c8c339 100644 --- a/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go +++ b/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/accessmonitoringrules/v1/access_monitoring_rules_service.proto diff --git a/api/gen/proto/go/teleport/auditlog/v1/auditlog.pb.go b/api/gen/proto/go/teleport/auditlog/v1/auditlog.pb.go index 3b89ae810bf19..6915adf45f0b7 100644 --- a/api/gen/proto/go/teleport/auditlog/v1/auditlog.pb.go +++ b/api/gen/proto/go/teleport/auditlog/v1/auditlog.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/auditlog/v1/auditlog.proto diff --git a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go index 8d7e52517814b..e984e2ff98295 100644 --- a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go +++ b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/autoupdate/v1/autoupdate.proto diff --git a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate_service.pb.go b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate_service.pb.go index d8fcfb70bd150..46fd39e2c983d 100644 --- a/api/gen/proto/go/teleport/autoupdate/v1/autoupdate_service.pb.go +++ b/api/gen/proto/go/teleport/autoupdate/v1/autoupdate_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/autoupdate/v1/autoupdate_service.proto diff --git a/api/gen/proto/go/teleport/clusterconfig/v1/access_graph.pb.go b/api/gen/proto/go/teleport/clusterconfig/v1/access_graph.pb.go index e24b8daa15281..0bbe9d081d7e1 100644 --- a/api/gen/proto/go/teleport/clusterconfig/v1/access_graph.pb.go +++ b/api/gen/proto/go/teleport/clusterconfig/v1/access_graph.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/clusterconfig/v1/access_graph.proto diff --git a/api/gen/proto/go/teleport/clusterconfig/v1/access_graph_settings.pb.go b/api/gen/proto/go/teleport/clusterconfig/v1/access_graph_settings.pb.go index 82e6501c0e96d..78ae3205b43dd 100644 --- a/api/gen/proto/go/teleport/clusterconfig/v1/access_graph_settings.pb.go +++ b/api/gen/proto/go/teleport/clusterconfig/v1/access_graph_settings.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/clusterconfig/v1/access_graph_settings.proto diff --git a/api/gen/proto/go/teleport/clusterconfig/v1/clusterconfig_service.pb.go b/api/gen/proto/go/teleport/clusterconfig/v1/clusterconfig_service.pb.go index 986a699fd3a74..41e324787bdeb 100644 --- a/api/gen/proto/go/teleport/clusterconfig/v1/clusterconfig_service.pb.go +++ b/api/gen/proto/go/teleport/clusterconfig/v1/clusterconfig_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/clusterconfig/v1/clusterconfig_service.proto diff --git a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go index 22de09bae306e..701b289b159ac 100644 --- a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go +++ b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/crownjewel/v1/crownjewel.proto diff --git a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel_service.pb.go b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel_service.pb.go index 8f77287d54363..8db11e390b127 100644 --- a/api/gen/proto/go/teleport/crownjewel/v1/crownjewel_service.pb.go +++ b/api/gen/proto/go/teleport/crownjewel/v1/crownjewel_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/crownjewel/v1/crownjewel_service.proto diff --git a/api/gen/proto/go/teleport/dbobject/v1/dbobject.pb.go b/api/gen/proto/go/teleport/dbobject/v1/dbobject.pb.go index d6b586ff33c53..3c4ac98b7619e 100644 --- a/api/gen/proto/go/teleport/dbobject/v1/dbobject.pb.go +++ b/api/gen/proto/go/teleport/dbobject/v1/dbobject.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/dbobject/v1/dbobject.proto diff --git a/api/gen/proto/go/teleport/dbobject/v1/dbobject_service.pb.go b/api/gen/proto/go/teleport/dbobject/v1/dbobject_service.pb.go index 187fa7c19624f..a0ce791c81ad2 100644 --- a/api/gen/proto/go/teleport/dbobject/v1/dbobject_service.pb.go +++ b/api/gen/proto/go/teleport/dbobject/v1/dbobject_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/dbobject/v1/dbobject_service.proto diff --git a/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule.pb.go b/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule.pb.go index d4fb2a479a8a2..0549857f14423 100644 --- a/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule.pb.go +++ b/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/dbobjectimportrule/v1/dbobjectimportrule.proto diff --git a/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule_service.pb.go b/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule_service.pb.go index f2b80b39c7310..480b571dec331 100644 --- a/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule_service.pb.go +++ b/api/gen/proto/go/teleport/dbobjectimportrule/v1/dbobjectimportrule_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/dbobjectimportrule/v1/dbobjectimportrule_service.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/database_access.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/database_access.pb.go index 6fd8cdf14f083..60bd864abcfcf 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/database_access.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/database_access.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/database_access.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/decision_service.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/decision_service.pb.go index d69083027a3e4..d50f86f8a1a7f 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/decision_service.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/decision_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/decision_service.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/denial_metadata.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/denial_metadata.pb.go index f0652e9f0d836..d915867e0186d 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/denial_metadata.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/denial_metadata.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/denial_metadata.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/enforcement_feature.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/enforcement_feature.pb.go index 1305cecf1767f..4f62700671f18 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/enforcement_feature.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/enforcement_feature.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/enforcement_feature.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/permit_metadata.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/permit_metadata.pb.go index b317a9f4ee7c5..619193d751c90 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/permit_metadata.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/permit_metadata.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/permit_metadata.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/request_metadata.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/request_metadata.pb.go index 07f8daaa7b59a..4ad047ca54f6f 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/request_metadata.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/request_metadata.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/request_metadata.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/resource.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/resource.pb.go index 67717c7513743..a7d7f19e53d09 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/resource.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/resource.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/resource.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_access.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_access.pb.go index 832975efc9392..2c88519fe0668 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_access.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_access.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/ssh_access.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go index 714e0f84f6307..34833d21cb83b 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/ssh_identity.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/ssh_identity.proto diff --git a/api/gen/proto/go/teleport/decision/v1alpha1/tls_identity.pb.go b/api/gen/proto/go/teleport/decision/v1alpha1/tls_identity.pb.go index 2ca338f5b2310..08547f70b19e3 100644 --- a/api/gen/proto/go/teleport/decision/v1alpha1/tls_identity.pb.go +++ b/api/gen/proto/go/teleport/decision/v1alpha1/tls_identity.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/decision/v1alpha1/tls_identity.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/assert.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/assert.pb.go index 56364d3a69173..5a3baf76bed4d 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/assert.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/assert.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/assert.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/authenticate_challenge.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/authenticate_challenge.pb.go index 4169f9b6c9108..b77c2bb6e60f7 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/authenticate_challenge.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/authenticate_challenge.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/authenticate_challenge.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device.pb.go index 06b7efe8cf492..28982e37a9833 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_collected_data.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_collected_data.pb.go index 6fddf6604b72a..9a4c6852c7c98 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_collected_data.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_collected_data.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_collected_data.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_confirmation_token.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_confirmation_token.pb.go index 79e086c32bfe2..437859da2de81 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_confirmation_token.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_confirmation_token.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_confirmation_token.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_enroll_token.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_enroll_token.pb.go index cd2cc9679c4bb..870d58b0c8191 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_enroll_token.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_enroll_token.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_enroll_token.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_profile.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_profile.pb.go index 3146c89f2dd95..25d07d180601d 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_profile.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_profile.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_profile.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_source.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_source.pb.go index 5949addc0b84f..05e94ea93924e 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_source.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_source.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_source.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/device_web_token.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/device_web_token.pb.go index 3b81002fb9c9c..6ed47b8c22ef1 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/device_web_token.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/device_web_token.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/device_web_token.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/devicetrust_service.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/devicetrust_service.pb.go index 792c213d5fe81..fa9bcb045acd0 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/devicetrust_service.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/devicetrust_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/devicetrust_service.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/os_type.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/os_type.pb.go index 284e4ffc0e2a9..86f87c2696f2c 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/os_type.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/os_type.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/os_type.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/tpm.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/tpm.pb.go index dad838ee35095..8f096a0b12fab 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/tpm.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/tpm.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/tpm.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/usage.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/usage.pb.go index ed4d2bf1f3e51..7017dc863c8e7 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/usage.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/usage.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/usage.proto diff --git a/api/gen/proto/go/teleport/devicetrust/v1/user_certificates.pb.go b/api/gen/proto/go/teleport/devicetrust/v1/user_certificates.pb.go index 417b8ea699ee8..2e1777356b79e 100644 --- a/api/gen/proto/go/teleport/devicetrust/v1/user_certificates.pb.go +++ b/api/gen/proto/go/teleport/devicetrust/v1/user_certificates.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/devicetrust/v1/user_certificates.proto diff --git a/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig.pb.go b/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig.pb.go index 2297bbd87c396..45246e9784a65 100644 --- a/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig.pb.go +++ b/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/discoveryconfig/v1/discoveryconfig.proto diff --git a/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig_service.pb.go b/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig_service.pb.go index 2edf5bf751a67..ed9ba6ca3192f 100644 --- a/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig_service.pb.go +++ b/api/gen/proto/go/teleport/discoveryconfig/v1/discoveryconfig_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/discoveryconfig/v1/discoveryconfig_service.proto diff --git a/api/gen/proto/go/teleport/dynamicwindows/v1/dynamicwindows_service.pb.go b/api/gen/proto/go/teleport/dynamicwindows/v1/dynamicwindows_service.pb.go index d50508e8f15be..2775a75226d38 100644 --- a/api/gen/proto/go/teleport/dynamicwindows/v1/dynamicwindows_service.pb.go +++ b/api/gen/proto/go/teleport/dynamicwindows/v1/dynamicwindows_service.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/dynamicwindows/v1/dynamicwindows_service.proto diff --git a/api/gen/proto/go/teleport/embedding/v1/embedding.pb.go b/api/gen/proto/go/teleport/embedding/v1/embedding.pb.go index 72d02a36c9c54..e8e6468e43d50 100644 --- a/api/gen/proto/go/teleport/embedding/v1/embedding.pb.go +++ b/api/gen/proto/go/teleport/embedding/v1/embedding.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/embedding/v1/embedding.proto diff --git a/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage.pb.go b/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage.pb.go index a24fab7a7b678..8c5496ac23f7e 100644 --- a/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage.pb.go +++ b/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/externalauditstorage/v1/externalauditstorage.proto diff --git a/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage_service.pb.go b/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage_service.pb.go index 8edabb94ee258..a92b3db942e2e 100644 --- a/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage_service.pb.go +++ b/api/gen/proto/go/teleport/externalauditstorage/v1/externalauditstorage_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/externalauditstorage/v1/externalauditstorage_service.proto diff --git a/api/gen/proto/go/teleport/gitserver/v1/git_server_service.pb.go b/api/gen/proto/go/teleport/gitserver/v1/git_server_service.pb.go index f07d22a859201..f27cca6f71657 100644 --- a/api/gen/proto/go/teleport/gitserver/v1/git_server_service.pb.go +++ b/api/gen/proto/go/teleport/gitserver/v1/git_server_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/gitserver/v1/git_server_service.proto diff --git a/api/gen/proto/go/teleport/header/v1/metadata.pb.go b/api/gen/proto/go/teleport/header/v1/metadata.pb.go index 2cd0f77409150..08cb5db8f338e 100644 --- a/api/gen/proto/go/teleport/header/v1/metadata.pb.go +++ b/api/gen/proto/go/teleport/header/v1/metadata.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/header/v1/metadata.proto diff --git a/api/gen/proto/go/teleport/header/v1/resourceheader.pb.go b/api/gen/proto/go/teleport/header/v1/resourceheader.pb.go index 37cda50a08225..432d595d89825 100644 --- a/api/gen/proto/go/teleport/header/v1/resourceheader.pb.go +++ b/api/gen/proto/go/teleport/header/v1/resourceheader.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/header/v1/resourceheader.proto diff --git a/api/gen/proto/go/teleport/identitycenter/v1/identitycenter.pb.go b/api/gen/proto/go/teleport/identitycenter/v1/identitycenter.pb.go index 00189e9add99a..f2c2277101eae 100644 --- a/api/gen/proto/go/teleport/identitycenter/v1/identitycenter.pb.go +++ b/api/gen/proto/go/teleport/identitycenter/v1/identitycenter.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/identitycenter/v1/identitycenter.proto diff --git a/api/gen/proto/go/teleport/identitycenter/v1/identitycenter_service.pb.go b/api/gen/proto/go/teleport/identitycenter/v1/identitycenter_service.pb.go index c8c09f385c4e9..d35581691f971 100644 --- a/api/gen/proto/go/teleport/identitycenter/v1/identitycenter_service.pb.go +++ b/api/gen/proto/go/teleport/identitycenter/v1/identitycenter_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/identitycenter/v1/identitycenter_service.proto 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 6c21f0556d576..31b04b0e44c15 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 @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/integration/v1/awsoidc_service.proto diff --git a/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go b/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go index f2d42625cef51..e2585cd02c4c3 100644 --- a/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go +++ b/api/gen/proto/go/teleport/integration/v1/integration_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/integration/v1/integration_service.proto diff --git a/api/gen/proto/go/teleport/kube/v1/kube_service.pb.go b/api/gen/proto/go/teleport/kube/v1/kube_service.pb.go index b674dd5c68d83..883afa302bc90 100644 --- a/api/gen/proto/go/teleport/kube/v1/kube_service.pb.go +++ b/api/gen/proto/go/teleport/kube/v1/kube_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/kube/v1/kube_service.proto diff --git a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go index 1a49e853154e6..a2f027e4d512f 100644 --- a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go +++ b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto diff --git a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer_service.pb.go b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer_service.pb.go index 87484d4c22375..10a50822351e5 100644 --- a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer_service.pb.go +++ b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/kubewaitingcontainer/v1/kubewaitingcontainer_service.proto diff --git a/api/gen/proto/go/teleport/label/v1/label.pb.go b/api/gen/proto/go/teleport/label/v1/label.pb.go index 94821f0483abd..25b3eb2f0f2e0 100644 --- a/api/gen/proto/go/teleport/label/v1/label.pb.go +++ b/api/gen/proto/go/teleport/label/v1/label.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/label/v1/label.proto diff --git a/api/gen/proto/go/teleport/loginrule/v1/loginrule.pb.go b/api/gen/proto/go/teleport/loginrule/v1/loginrule.pb.go index 5a61ef4bd8f71..43c89fb3572c9 100644 --- a/api/gen/proto/go/teleport/loginrule/v1/loginrule.pb.go +++ b/api/gen/proto/go/teleport/loginrule/v1/loginrule.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/loginrule/v1/loginrule.proto diff --git a/api/gen/proto/go/teleport/loginrule/v1/loginrule_service.pb.go b/api/gen/proto/go/teleport/loginrule/v1/loginrule_service.pb.go index 3b350879b446f..cb1b8d15ab424 100644 --- a/api/gen/proto/go/teleport/loginrule/v1/loginrule_service.pb.go +++ b/api/gen/proto/go/teleport/loginrule/v1/loginrule_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/loginrule/v1/loginrule_service.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/bot.pb.go b/api/gen/proto/go/teleport/machineid/v1/bot.pb.go index 6b056460688f4..49ae2c9dacf97 100644 --- a/api/gen/proto/go/teleport/machineid/v1/bot.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/bot.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/bot.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/bot_instance.pb.go b/api/gen/proto/go/teleport/machineid/v1/bot_instance.pb.go index b794040d05ba0..d76fabf179435 100644 --- a/api/gen/proto/go/teleport/machineid/v1/bot_instance.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/bot_instance.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/bot_instance.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/bot_instance_service.pb.go b/api/gen/proto/go/teleport/machineid/v1/bot_instance_service.pb.go index f665ce529cafc..c7035de1776ae 100644 --- a/api/gen/proto/go/teleport/machineid/v1/bot_instance_service.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/bot_instance_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/bot_instance_service.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/bot_service.pb.go b/api/gen/proto/go/teleport/machineid/v1/bot_service.pb.go index 4d3beeb3a29f1..1f475a16c9ea9 100644 --- a/api/gen/proto/go/teleport/machineid/v1/bot_service.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/bot_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/bot_service.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/federation.pb.go b/api/gen/proto/go/teleport/machineid/v1/federation.pb.go index 8e279f5d5adc4..7dfe88cd93e28 100644 --- a/api/gen/proto/go/teleport/machineid/v1/federation.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/federation.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/federation.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go b/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go index e9f0fcaf60c53..bfa2ee7f2546a 100644 --- a/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/federation_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/federation_service.proto diff --git a/api/gen/proto/go/teleport/machineid/v1/workload_identity_service.pb.go b/api/gen/proto/go/teleport/machineid/v1/workload_identity_service.pb.go index c4bb080435a56..21a488a6c2c98 100644 --- a/api/gen/proto/go/teleport/machineid/v1/workload_identity_service.pb.go +++ b/api/gen/proto/go/teleport/machineid/v1/workload_identity_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/machineid/v1/workload_identity_service.proto diff --git a/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go b/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go index 560f2a75be616..996bd7492ecb9 100644 --- a/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go +++ b/api/gen/proto/go/teleport/notifications/v1/notifications.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/notifications/v1/notifications.proto diff --git a/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go b/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go index 655da01ddc32f..3a5e485bdf899 100644 --- a/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go +++ b/api/gen/proto/go/teleport/notifications/v1/notifications_service.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/notifications/v1/notifications_service.proto diff --git a/api/gen/proto/go/teleport/okta/v1/okta_service.pb.go b/api/gen/proto/go/teleport/okta/v1/okta_service.pb.go index 70d79a741e7f6..a093e7aa22673 100644 --- a/api/gen/proto/go/teleport/okta/v1/okta_service.pb.go +++ b/api/gen/proto/go/teleport/okta/v1/okta_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/okta/v1/okta_service.proto diff --git a/api/gen/proto/go/teleport/plugins/v1/plugin_service.pb.go b/api/gen/proto/go/teleport/plugins/v1/plugin_service.pb.go index 44a02cb8588e5..17992a7f0ec61 100644 --- a/api/gen/proto/go/teleport/plugins/v1/plugin_service.pb.go +++ b/api/gen/proto/go/teleport/plugins/v1/plugin_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/plugins/v1/plugin_service.proto diff --git a/api/gen/proto/go/teleport/presence/v1/service.pb.go b/api/gen/proto/go/teleport/presence/v1/service.pb.go index dd0f2a5cdbb96..7e730569d135f 100644 --- a/api/gen/proto/go/teleport/presence/v1/service.pb.go +++ b/api/gen/proto/go/teleport/presence/v1/service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/presence/v1/service.proto diff --git a/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go b/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go index 61160a9f7df37..89f958940e704 100644 --- a/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go +++ b/api/gen/proto/go/teleport/provisioning/v1/provisioning.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/provisioning/v1/provisioning.proto diff --git a/api/gen/proto/go/teleport/provisioning/v1/provisioning_service.pb.go b/api/gen/proto/go/teleport/provisioning/v1/provisioning_service.pb.go index d800f6d268d64..9afe3669e6b5c 100644 --- a/api/gen/proto/go/teleport/provisioning/v1/provisioning_service.pb.go +++ b/api/gen/proto/go/teleport/provisioning/v1/provisioning_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/provisioning/v1/provisioning_service.proto diff --git a/api/gen/proto/go/teleport/resourceusage/v1/access_requests.pb.go b/api/gen/proto/go/teleport/resourceusage/v1/access_requests.pb.go index f62bcf10293d4..b0f800e4cc531 100644 --- a/api/gen/proto/go/teleport/resourceusage/v1/access_requests.pb.go +++ b/api/gen/proto/go/teleport/resourceusage/v1/access_requests.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/resourceusage/v1/access_requests.proto diff --git a/api/gen/proto/go/teleport/resourceusage/v1/account_usage_type.pb.go b/api/gen/proto/go/teleport/resourceusage/v1/account_usage_type.pb.go index 7db2483018589..774a416ac63be 100644 --- a/api/gen/proto/go/teleport/resourceusage/v1/account_usage_type.pb.go +++ b/api/gen/proto/go/teleport/resourceusage/v1/account_usage_type.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/resourceusage/v1/account_usage_type.proto diff --git a/api/gen/proto/go/teleport/resourceusage/v1/device_trust.pb.go b/api/gen/proto/go/teleport/resourceusage/v1/device_trust.pb.go index 8b7d128131517..2f1edefaa1d97 100644 --- a/api/gen/proto/go/teleport/resourceusage/v1/device_trust.pb.go +++ b/api/gen/proto/go/teleport/resourceusage/v1/device_trust.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/resourceusage/v1/device_trust.proto diff --git a/api/gen/proto/go/teleport/resourceusage/v1/resourceusage_service.pb.go b/api/gen/proto/go/teleport/resourceusage/v1/resourceusage_service.pb.go index 10ce0bb44dcbf..56434b3e61391 100644 --- a/api/gen/proto/go/teleport/resourceusage/v1/resourceusage_service.pb.go +++ b/api/gen/proto/go/teleport/resourceusage/v1/resourceusage_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/resourceusage/v1/resourceusage_service.proto diff --git a/api/gen/proto/go/teleport/samlidp/v1/samlidp.pb.go b/api/gen/proto/go/teleport/samlidp/v1/samlidp.pb.go index f7d7df1e650c7..3907eb1233c15 100644 --- a/api/gen/proto/go/teleport/samlidp/v1/samlidp.pb.go +++ b/api/gen/proto/go/teleport/samlidp/v1/samlidp.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/samlidp/v1/samlidp.proto diff --git a/api/gen/proto/go/teleport/scim/v1/scim_service.pb.go b/api/gen/proto/go/teleport/scim/v1/scim_service.pb.go index 85fe68affaca4..6011ca60f276f 100644 --- a/api/gen/proto/go/teleport/scim/v1/scim_service.pb.go +++ b/api/gen/proto/go/teleport/scim/v1/scim_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/scim/v1/scim_service.proto diff --git a/api/gen/proto/go/teleport/secreports/v1/secreports.pb.go b/api/gen/proto/go/teleport/secreports/v1/secreports.pb.go index 881dbaf878341..09ac982395bf1 100644 --- a/api/gen/proto/go/teleport/secreports/v1/secreports.pb.go +++ b/api/gen/proto/go/teleport/secreports/v1/secreports.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/secreports/v1/secreports.proto diff --git a/api/gen/proto/go/teleport/secreports/v1/secreports_service.pb.go b/api/gen/proto/go/teleport/secreports/v1/secreports_service.pb.go index 1b0375cd03e29..8a73244cc5a72 100644 --- a/api/gen/proto/go/teleport/secreports/v1/secreports_service.pb.go +++ b/api/gen/proto/go/teleport/secreports/v1/secreports_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/secreports/v1/secreports_service.proto diff --git a/api/gen/proto/go/teleport/trait/v1/trait.pb.go b/api/gen/proto/go/teleport/trait/v1/trait.pb.go index 89031f6f5aa19..019987e24e0fb 100644 --- a/api/gen/proto/go/teleport/trait/v1/trait.pb.go +++ b/api/gen/proto/go/teleport/trait/v1/trait.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/trait/v1/trait.proto diff --git a/api/gen/proto/go/teleport/transport/v1/transport_service.pb.go b/api/gen/proto/go/teleport/transport/v1/transport_service.pb.go index f20c2cff21066..38d8b33eb7511 100644 --- a/api/gen/proto/go/teleport/transport/v1/transport_service.pb.go +++ b/api/gen/proto/go/teleport/transport/v1/transport_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/transport/v1/transport_service.proto diff --git a/api/gen/proto/go/teleport/trust/v1/trust_service.pb.go b/api/gen/proto/go/teleport/trust/v1/trust_service.pb.go index 349eb18c6ae9e..ca26508234431 100644 --- a/api/gen/proto/go/teleport/trust/v1/trust_service.pb.go +++ b/api/gen/proto/go/teleport/trust/v1/trust_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/trust/v1/trust_service.proto @@ -38,6 +38,144 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Request for UpsertTrustedCluster. +type UpsertTrustedClusterRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // TrustedCluster specifies a Trusted Cluster resource. + TrustedCluster *types.TrustedClusterV2 `protobuf:"bytes,1,opt,name=trusted_cluster,json=trustedCluster,proto3" json:"trusted_cluster,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpsertTrustedClusterRequest) Reset() { + *x = UpsertTrustedClusterRequest{} + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpsertTrustedClusterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpsertTrustedClusterRequest) ProtoMessage() {} + +func (x *UpsertTrustedClusterRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[0] + 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 UpsertTrustedClusterRequest.ProtoReflect.Descriptor instead. +func (*UpsertTrustedClusterRequest) Descriptor() ([]byte, []int) { + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{0} +} + +func (x *UpsertTrustedClusterRequest) GetTrustedCluster() *types.TrustedClusterV2 { + if x != nil { + return x.TrustedCluster + } + return nil +} + +// Request for CreateTrustedCluster. +type CreateTrustedClusterRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // TrustedCluster specifies a Trusted Cluster resource. + TrustedCluster *types.TrustedClusterV2 `protobuf:"bytes,1,opt,name=trusted_cluster,json=trustedCluster,proto3" json:"trusted_cluster,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateTrustedClusterRequest) Reset() { + *x = CreateTrustedClusterRequest{} + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateTrustedClusterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTrustedClusterRequest) ProtoMessage() {} + +func (x *CreateTrustedClusterRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[1] + 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 CreateTrustedClusterRequest.ProtoReflect.Descriptor instead. +func (*CreateTrustedClusterRequest) Descriptor() ([]byte, []int) { + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{1} +} + +func (x *CreateTrustedClusterRequest) GetTrustedCluster() *types.TrustedClusterV2 { + if x != nil { + return x.TrustedCluster + } + return nil +} + +// Request for UpdateTrustedCluster. +type UpdateTrustedClusterRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // TrustedCluster specifies a Trusted Cluster resource. + TrustedCluster *types.TrustedClusterV2 `protobuf:"bytes,1,opt,name=trusted_cluster,json=trustedCluster,proto3" json:"trusted_cluster,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateTrustedClusterRequest) Reset() { + *x = UpdateTrustedClusterRequest{} + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateTrustedClusterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateTrustedClusterRequest) ProtoMessage() {} + +func (x *UpdateTrustedClusterRequest) ProtoReflect() protoreflect.Message { + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[2] + 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 UpdateTrustedClusterRequest.ProtoReflect.Descriptor instead. +func (*UpdateTrustedClusterRequest) Descriptor() ([]byte, []int) { + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{2} +} + +func (x *UpdateTrustedClusterRequest) GetTrustedCluster() *types.TrustedClusterV2 { + if x != nil { + return x.TrustedCluster + } + return nil +} + // Request for GetCertAuthority type GetCertAuthorityRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -53,7 +191,7 @@ type GetCertAuthorityRequest struct { func (x *GetCertAuthorityRequest) Reset() { *x = GetCertAuthorityRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[0] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -65,7 +203,7 @@ func (x *GetCertAuthorityRequest) String() string { func (*GetCertAuthorityRequest) ProtoMessage() {} func (x *GetCertAuthorityRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[0] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -78,7 +216,7 @@ func (x *GetCertAuthorityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCertAuthorityRequest.ProtoReflect.Descriptor instead. func (*GetCertAuthorityRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{0} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{3} } func (x *GetCertAuthorityRequest) GetType() string { @@ -115,7 +253,7 @@ type GetCertAuthoritiesRequest struct { func (x *GetCertAuthoritiesRequest) Reset() { *x = GetCertAuthoritiesRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[1] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -127,7 +265,7 @@ func (x *GetCertAuthoritiesRequest) String() string { func (*GetCertAuthoritiesRequest) ProtoMessage() {} func (x *GetCertAuthoritiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[1] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -140,7 +278,7 @@ func (x *GetCertAuthoritiesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCertAuthoritiesRequest.ProtoReflect.Descriptor instead. func (*GetCertAuthoritiesRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{1} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{4} } func (x *GetCertAuthoritiesRequest) GetType() string { @@ -168,7 +306,7 @@ type GetCertAuthoritiesResponse struct { func (x *GetCertAuthoritiesResponse) Reset() { *x = GetCertAuthoritiesResponse{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[2] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -180,7 +318,7 @@ func (x *GetCertAuthoritiesResponse) String() string { func (*GetCertAuthoritiesResponse) ProtoMessage() {} func (x *GetCertAuthoritiesResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[2] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -193,7 +331,7 @@ func (x *GetCertAuthoritiesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCertAuthoritiesResponse.ProtoReflect.Descriptor instead. func (*GetCertAuthoritiesResponse) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{2} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{5} } func (x *GetCertAuthoritiesResponse) GetCertAuthoritiesV2() []*types.CertAuthorityV2 { @@ -216,7 +354,7 @@ type DeleteCertAuthorityRequest struct { func (x *DeleteCertAuthorityRequest) Reset() { *x = DeleteCertAuthorityRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[3] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -228,7 +366,7 @@ func (x *DeleteCertAuthorityRequest) String() string { func (*DeleteCertAuthorityRequest) ProtoMessage() {} func (x *DeleteCertAuthorityRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[3] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -241,7 +379,7 @@ func (x *DeleteCertAuthorityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteCertAuthorityRequest.ProtoReflect.Descriptor instead. func (*DeleteCertAuthorityRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{3} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{6} } func (x *DeleteCertAuthorityRequest) GetType() string { @@ -269,7 +407,7 @@ type UpsertCertAuthorityRequest struct { func (x *UpsertCertAuthorityRequest) Reset() { *x = UpsertCertAuthorityRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[4] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -281,7 +419,7 @@ func (x *UpsertCertAuthorityRequest) String() string { func (*UpsertCertAuthorityRequest) ProtoMessage() {} func (x *UpsertCertAuthorityRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[4] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -294,7 +432,7 @@ func (x *UpsertCertAuthorityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpsertCertAuthorityRequest.ProtoReflect.Descriptor instead. func (*UpsertCertAuthorityRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{4} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{7} } func (x *UpsertCertAuthorityRequest) GetCertAuthority() *types.CertAuthorityV2 { @@ -333,7 +471,7 @@ type RotateCertAuthorityRequest struct { func (x *RotateCertAuthorityRequest) Reset() { *x = RotateCertAuthorityRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[5] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -345,7 +483,7 @@ func (x *RotateCertAuthorityRequest) String() string { func (*RotateCertAuthorityRequest) ProtoMessage() {} func (x *RotateCertAuthorityRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[5] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -358,7 +496,7 @@ func (x *RotateCertAuthorityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateCertAuthorityRequest.ProtoReflect.Descriptor instead. func (*RotateCertAuthorityRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{5} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{8} } func (x *RotateCertAuthorityRequest) GetType() string { @@ -411,7 +549,7 @@ type RotationSchedule struct { func (x *RotationSchedule) Reset() { *x = RotationSchedule{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[6] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +561,7 @@ func (x *RotationSchedule) String() string { func (*RotationSchedule) ProtoMessage() {} func (x *RotationSchedule) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[6] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +574,7 @@ func (x *RotationSchedule) ProtoReflect() protoreflect.Message { // Deprecated: Use RotationSchedule.ProtoReflect.Descriptor instead. func (*RotationSchedule) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{6} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{9} } func (x *RotationSchedule) GetUpdateClients() *timestamppb.Timestamp { @@ -469,7 +607,7 @@ type RotateCertAuthorityResponse struct { func (x *RotateCertAuthorityResponse) Reset() { *x = RotateCertAuthorityResponse{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[7] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -481,7 +619,7 @@ func (x *RotateCertAuthorityResponse) String() string { func (*RotateCertAuthorityResponse) ProtoMessage() {} func (x *RotateCertAuthorityResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[7] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -494,7 +632,7 @@ func (x *RotateCertAuthorityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RotateCertAuthorityResponse.ProtoReflect.Descriptor instead. func (*RotateCertAuthorityResponse) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{7} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{10} } // Request for RotateExternalCertAuthority. @@ -508,7 +646,7 @@ type RotateExternalCertAuthorityRequest struct { func (x *RotateExternalCertAuthorityRequest) Reset() { *x = RotateExternalCertAuthorityRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[8] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -520,7 +658,7 @@ func (x *RotateExternalCertAuthorityRequest) String() string { func (*RotateExternalCertAuthorityRequest) ProtoMessage() {} func (x *RotateExternalCertAuthorityRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[8] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -533,7 +671,7 @@ func (x *RotateExternalCertAuthorityRequest) ProtoReflect() protoreflect.Message // Deprecated: Use RotateExternalCertAuthorityRequest.ProtoReflect.Descriptor instead. func (*RotateExternalCertAuthorityRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{8} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{11} } func (x *RotateExternalCertAuthorityRequest) GetCertAuthority() *types.CertAuthorityV2 { @@ -552,7 +690,7 @@ type RotateExternalCertAuthorityResponse struct { func (x *RotateExternalCertAuthorityResponse) Reset() { *x = RotateExternalCertAuthorityResponse{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[9] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -564,7 +702,7 @@ func (x *RotateExternalCertAuthorityResponse) String() string { func (*RotateExternalCertAuthorityResponse) ProtoMessage() {} func (x *RotateExternalCertAuthorityResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[9] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -577,7 +715,7 @@ func (x *RotateExternalCertAuthorityResponse) ProtoReflect() protoreflect.Messag // Deprecated: Use RotateExternalCertAuthorityResponse.ProtoReflect.Descriptor instead. func (*RotateExternalCertAuthorityResponse) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{9} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{12} } // GenerateHostCertRequest is the request for GenerateHostCert. @@ -603,7 +741,7 @@ type GenerateHostCertRequest struct { func (x *GenerateHostCertRequest) Reset() { *x = GenerateHostCertRequest{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[10] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -615,7 +753,7 @@ func (x *GenerateHostCertRequest) String() string { func (*GenerateHostCertRequest) ProtoMessage() {} func (x *GenerateHostCertRequest) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[10] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -628,7 +766,7 @@ func (x *GenerateHostCertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateHostCertRequest.ProtoReflect.Descriptor instead. func (*GenerateHostCertRequest) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{10} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{13} } func (x *GenerateHostCertRequest) GetKey() []byte { @@ -691,7 +829,7 @@ type GenerateHostCertResponse struct { func (x *GenerateHostCertResponse) Reset() { *x = GenerateHostCertResponse{} - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[11] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -703,7 +841,7 @@ func (x *GenerateHostCertResponse) String() string { func (*GenerateHostCertResponse) ProtoMessage() {} func (x *GenerateHostCertResponse) ProtoReflect() protoreflect.Message { - mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[11] + mi := &file_teleport_trust_v1_trust_service_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -716,7 +854,7 @@ func (x *GenerateHostCertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GenerateHostCertResponse.ProtoReflect.Descriptor instead. func (*GenerateHostCertResponse) Descriptor() ([]byte, []int) { - return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{11} + return file_teleport_trust_v1_trust_service_proto_rawDescGZIP(), []int{14} } func (x *GenerateHostCertResponse) GetSshCertificate() []byte { @@ -740,147 +878,183 @@ var file_teleport_trust_v1_trust_service_proto_rawDesc = []byte{ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x66, 0x0a, 0x17, 0x47, - 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6b, 0x65, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x4b, 0x65, 0x79, 0x22, 0x50, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, - 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x64, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x13, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x76, 0x32, 0x18, 0x01, 0x20, 0x03, 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, 0x52, 0x11, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x56, 0x32, 0x22, 0x48, 0x0a, 0x1a, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5f, 0x0a, 0x1b, 0x55, + 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x0f, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x32, 0x52, 0x0e, 0x74, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x22, 0x5f, 0x0a, 0x1b, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x0f, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x32, 0x52, 0x0e, 0x74, + 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x22, 0x5f, 0x0a, + 0x1b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, + 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x0f, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x56, 0x32, 0x52, 0x0e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x22, 0x66, + 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, - 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x5b, 0x0a, 0x1a, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 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, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x22, 0xe6, 0x01, 0x0a, 0x1a, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, - 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x67, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x70, - 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x67, 0x72, 0x61, 0x63, 0x65, 0x50, 0x65, 0x72, - 0x69, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x68, - 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x73, 0x63, - 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, - 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, - 0x65, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0xce, 0x01, 0x0a, 0x10, - 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, - 0x12, 0x41, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x50, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, + 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x64, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x43, + 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x13, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x5f, 0x76, 0x32, 0x18, 0x01, 0x20, + 0x03, 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, 0x52, 0x11, 0x63, 0x65, 0x72, + 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x56, 0x32, 0x22, 0x48, + 0x0a, 0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x5b, 0x0a, 0x1a, 0x55, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 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, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0xe6, 0x01, 0x0a, 0x1a, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x67, 0x72, 0x61, 0x63, + 0x65, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x67, 0x72, 0x61, 0x63, 0x65, + 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x3f, 0x0a, + 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x23, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, + 0x64, 0x75, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x22, 0xce, + 0x01, 0x0a, 0x10, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, - 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x07, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x22, 0x1d, 0x0a, 0x1b, - 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, 0x0a, 0x22, 0x52, - 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, - 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x18, 0x01, 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, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, - 0x22, 0x25, 0x0a, 0x23, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe5, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x1b, - 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, - 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, - 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x6f, - 0x6c, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x22, - 0x43, 0x0a, 0x18, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, - 0x73, 0x68, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x73, 0x68, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x32, 0x87, 0x06, 0x0a, 0x0c, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x65, - 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, 0x12, 0x71, 0x0a, - 0x12, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, - 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, - 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x5c, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x5c, - 0x0a, 0x13, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 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, 0x0d, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x73, 0x74, 0x61, + 0x6e, 0x64, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x62, 0x79, 0x22, + 0x1d, 0x0a, 0x1b, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x63, + 0x0a, 0x22, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x65, 0x72, - 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, 0x12, 0x74, 0x0a, 0x13, - 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, - 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, - 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, - 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, - 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, - 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x8c, 0x01, 0x0a, 0x1b, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 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, 0x52, 0x0d, 0x63, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x22, 0x25, 0x0a, 0x23, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, - 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, 0x65, 0x6c, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, - 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6b, 0x0a, 0x10, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, - 0x74, 0x43, 0x65, 0x72, 0x74, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, - 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, - 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x4e, - 0x5a, 0x4c, 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, 0x74, 0x72, - 0x75, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x72, 0x75, 0x73, 0x74, 0x76, 0x31, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe5, 0x01, 0x0a, 0x17, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, + 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x73, 0x12, 0x21, + 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x74, 0x6c, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x74, + 0x74, 0x6c, 0x22, 0x43, 0x0a, 0x18, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, + 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, + 0x0a, 0x0f, 0x73, 0x73, 0x68, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x73, 0x73, 0x68, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x32, 0xaa, 0x08, 0x0a, 0x0c, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x56, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, + 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2a, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x2e, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, + 0x12, 0x71, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, + 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x65, 0x72, + 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x12, 0x5c, 0x0a, 0x13, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x73, + 0x65, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, + 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x56, 0x32, 0x12, + 0x74, 0x0a, 0x13, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, + 0x65, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x8c, 0x01, 0x0a, 0x1b, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x35, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, + 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x43, + 0x65, 0x72, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, 0x0a, 0x10, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, + 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x12, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x48, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, + 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, + 0x73, 0x65, 0x72, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x56, 0x32, 0x12, 0x5f, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e, 0x74, 0x65, 0x6c, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, + 0x72, 0x56, 0x32, 0x12, 0x5f, 0x0a, 0x14, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x2e, 0x2e, 0x74, 0x65, + 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x43, 0x6c, 0x75, 0x73, 0x74, + 0x65, 0x72, 0x56, 0x32, 0x42, 0x4e, 0x5a, 0x4c, 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, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x74, 0x72, 0x75, + 0x73, 0x74, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -895,54 +1069,67 @@ func file_teleport_trust_v1_trust_service_proto_rawDescGZIP() []byte { return file_teleport_trust_v1_trust_service_proto_rawDescData } -var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_teleport_trust_v1_trust_service_proto_msgTypes = make([]protoimpl.MessageInfo, 15) var file_teleport_trust_v1_trust_service_proto_goTypes = []any{ - (*GetCertAuthorityRequest)(nil), // 0: teleport.trust.v1.GetCertAuthorityRequest - (*GetCertAuthoritiesRequest)(nil), // 1: teleport.trust.v1.GetCertAuthoritiesRequest - (*GetCertAuthoritiesResponse)(nil), // 2: teleport.trust.v1.GetCertAuthoritiesResponse - (*DeleteCertAuthorityRequest)(nil), // 3: teleport.trust.v1.DeleteCertAuthorityRequest - (*UpsertCertAuthorityRequest)(nil), // 4: teleport.trust.v1.UpsertCertAuthorityRequest - (*RotateCertAuthorityRequest)(nil), // 5: teleport.trust.v1.RotateCertAuthorityRequest - (*RotationSchedule)(nil), // 6: teleport.trust.v1.RotationSchedule - (*RotateCertAuthorityResponse)(nil), // 7: teleport.trust.v1.RotateCertAuthorityResponse - (*RotateExternalCertAuthorityRequest)(nil), // 8: teleport.trust.v1.RotateExternalCertAuthorityRequest - (*RotateExternalCertAuthorityResponse)(nil), // 9: teleport.trust.v1.RotateExternalCertAuthorityResponse - (*GenerateHostCertRequest)(nil), // 10: teleport.trust.v1.GenerateHostCertRequest - (*GenerateHostCertResponse)(nil), // 11: teleport.trust.v1.GenerateHostCertResponse - (*types.CertAuthorityV2)(nil), // 12: types.CertAuthorityV2 - (*durationpb.Duration)(nil), // 13: google.protobuf.Duration - (*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 15: google.protobuf.Empty + (*UpsertTrustedClusterRequest)(nil), // 0: teleport.trust.v1.UpsertTrustedClusterRequest + (*CreateTrustedClusterRequest)(nil), // 1: teleport.trust.v1.CreateTrustedClusterRequest + (*UpdateTrustedClusterRequest)(nil), // 2: teleport.trust.v1.UpdateTrustedClusterRequest + (*GetCertAuthorityRequest)(nil), // 3: teleport.trust.v1.GetCertAuthorityRequest + (*GetCertAuthoritiesRequest)(nil), // 4: teleport.trust.v1.GetCertAuthoritiesRequest + (*GetCertAuthoritiesResponse)(nil), // 5: teleport.trust.v1.GetCertAuthoritiesResponse + (*DeleteCertAuthorityRequest)(nil), // 6: teleport.trust.v1.DeleteCertAuthorityRequest + (*UpsertCertAuthorityRequest)(nil), // 7: teleport.trust.v1.UpsertCertAuthorityRequest + (*RotateCertAuthorityRequest)(nil), // 8: teleport.trust.v1.RotateCertAuthorityRequest + (*RotationSchedule)(nil), // 9: teleport.trust.v1.RotationSchedule + (*RotateCertAuthorityResponse)(nil), // 10: teleport.trust.v1.RotateCertAuthorityResponse + (*RotateExternalCertAuthorityRequest)(nil), // 11: teleport.trust.v1.RotateExternalCertAuthorityRequest + (*RotateExternalCertAuthorityResponse)(nil), // 12: teleport.trust.v1.RotateExternalCertAuthorityResponse + (*GenerateHostCertRequest)(nil), // 13: teleport.trust.v1.GenerateHostCertRequest + (*GenerateHostCertResponse)(nil), // 14: teleport.trust.v1.GenerateHostCertResponse + (*types.TrustedClusterV2)(nil), // 15: types.TrustedClusterV2 + (*types.CertAuthorityV2)(nil), // 16: types.CertAuthorityV2 + (*durationpb.Duration)(nil), // 17: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 18: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 19: google.protobuf.Empty } var file_teleport_trust_v1_trust_service_proto_depIdxs = []int32{ - 12, // 0: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2 - 12, // 1: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2 - 13, // 2: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration - 6, // 3: teleport.trust.v1.RotateCertAuthorityRequest.schedule:type_name -> teleport.trust.v1.RotationSchedule - 14, // 4: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp - 14, // 5: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp - 14, // 6: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp - 12, // 7: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2 - 13, // 8: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration - 0, // 9: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest - 1, // 10: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest - 3, // 11: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest - 4, // 12: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest - 5, // 13: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest - 8, // 14: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest - 10, // 15: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest - 12, // 16: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2 - 2, // 17: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse - 15, // 18: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty - 12, // 19: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2 - 7, // 20: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse - 9, // 21: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse - 11, // 22: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse - 16, // [16:23] is the sub-list for method output_type - 9, // [9:16] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 15, // 0: teleport.trust.v1.UpsertTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2 + 15, // 1: teleport.trust.v1.CreateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2 + 15, // 2: teleport.trust.v1.UpdateTrustedClusterRequest.trusted_cluster:type_name -> types.TrustedClusterV2 + 16, // 3: teleport.trust.v1.GetCertAuthoritiesResponse.cert_authorities_v2:type_name -> types.CertAuthorityV2 + 16, // 4: teleport.trust.v1.UpsertCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2 + 17, // 5: teleport.trust.v1.RotateCertAuthorityRequest.grace_period:type_name -> google.protobuf.Duration + 9, // 6: teleport.trust.v1.RotateCertAuthorityRequest.schedule:type_name -> teleport.trust.v1.RotationSchedule + 18, // 7: teleport.trust.v1.RotationSchedule.update_clients:type_name -> google.protobuf.Timestamp + 18, // 8: teleport.trust.v1.RotationSchedule.update_servers:type_name -> google.protobuf.Timestamp + 18, // 9: teleport.trust.v1.RotationSchedule.standby:type_name -> google.protobuf.Timestamp + 16, // 10: teleport.trust.v1.RotateExternalCertAuthorityRequest.cert_authority:type_name -> types.CertAuthorityV2 + 17, // 11: teleport.trust.v1.GenerateHostCertRequest.ttl:type_name -> google.protobuf.Duration + 3, // 12: teleport.trust.v1.TrustService.GetCertAuthority:input_type -> teleport.trust.v1.GetCertAuthorityRequest + 4, // 13: teleport.trust.v1.TrustService.GetCertAuthorities:input_type -> teleport.trust.v1.GetCertAuthoritiesRequest + 6, // 14: teleport.trust.v1.TrustService.DeleteCertAuthority:input_type -> teleport.trust.v1.DeleteCertAuthorityRequest + 7, // 15: teleport.trust.v1.TrustService.UpsertCertAuthority:input_type -> teleport.trust.v1.UpsertCertAuthorityRequest + 8, // 16: teleport.trust.v1.TrustService.RotateCertAuthority:input_type -> teleport.trust.v1.RotateCertAuthorityRequest + 11, // 17: teleport.trust.v1.TrustService.RotateExternalCertAuthority:input_type -> teleport.trust.v1.RotateExternalCertAuthorityRequest + 13, // 18: teleport.trust.v1.TrustService.GenerateHostCert:input_type -> teleport.trust.v1.GenerateHostCertRequest + 0, // 19: teleport.trust.v1.TrustService.UpsertTrustedCluster:input_type -> teleport.trust.v1.UpsertTrustedClusterRequest + 1, // 20: teleport.trust.v1.TrustService.CreateTrustedCluster:input_type -> teleport.trust.v1.CreateTrustedClusterRequest + 2, // 21: teleport.trust.v1.TrustService.UpdateTrustedCluster:input_type -> teleport.trust.v1.UpdateTrustedClusterRequest + 16, // 22: teleport.trust.v1.TrustService.GetCertAuthority:output_type -> types.CertAuthorityV2 + 5, // 23: teleport.trust.v1.TrustService.GetCertAuthorities:output_type -> teleport.trust.v1.GetCertAuthoritiesResponse + 19, // 24: teleport.trust.v1.TrustService.DeleteCertAuthority:output_type -> google.protobuf.Empty + 16, // 25: teleport.trust.v1.TrustService.UpsertCertAuthority:output_type -> types.CertAuthorityV2 + 10, // 26: teleport.trust.v1.TrustService.RotateCertAuthority:output_type -> teleport.trust.v1.RotateCertAuthorityResponse + 12, // 27: teleport.trust.v1.TrustService.RotateExternalCertAuthority:output_type -> teleport.trust.v1.RotateExternalCertAuthorityResponse + 14, // 28: teleport.trust.v1.TrustService.GenerateHostCert:output_type -> teleport.trust.v1.GenerateHostCertResponse + 15, // 29: teleport.trust.v1.TrustService.UpsertTrustedCluster:output_type -> types.TrustedClusterV2 + 15, // 30: teleport.trust.v1.TrustService.CreateTrustedCluster:output_type -> types.TrustedClusterV2 + 15, // 31: teleport.trust.v1.TrustService.UpdateTrustedCluster:output_type -> types.TrustedClusterV2 + 22, // [22:32] is the sub-list for method output_type + 12, // [12:22] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_teleport_trust_v1_trust_service_proto_init() } @@ -956,7 +1143,7 @@ func file_teleport_trust_v1_trust_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_teleport_trust_v1_trust_service_proto_rawDesc, NumEnums: 0, - NumMessages: 12, + NumMessages: 15, NumExtensions: 0, NumServices: 1, }, diff --git a/api/gen/proto/go/teleport/trust/v1/trust_service_grpc.pb.go b/api/gen/proto/go/teleport/trust/v1/trust_service_grpc.pb.go index 5a91787708411..4cdc57fe369e1 100644 --- a/api/gen/proto/go/teleport/trust/v1/trust_service_grpc.pb.go +++ b/api/gen/proto/go/teleport/trust/v1/trust_service_grpc.pb.go @@ -42,6 +42,9 @@ const ( TrustService_RotateCertAuthority_FullMethodName = "/teleport.trust.v1.TrustService/RotateCertAuthority" TrustService_RotateExternalCertAuthority_FullMethodName = "/teleport.trust.v1.TrustService/RotateExternalCertAuthority" TrustService_GenerateHostCert_FullMethodName = "/teleport.trust.v1.TrustService/GenerateHostCert" + TrustService_UpsertTrustedCluster_FullMethodName = "/teleport.trust.v1.TrustService/UpsertTrustedCluster" + TrustService_CreateTrustedCluster_FullMethodName = "/teleport.trust.v1.TrustService/CreateTrustedCluster" + TrustService_UpdateTrustedCluster_FullMethodName = "/teleport.trust.v1.TrustService/UpdateTrustedCluster" ) // TrustServiceClient is the client API for TrustService service. @@ -65,6 +68,12 @@ type TrustServiceClient interface { // GenerateHostCert takes a public key in the OpenSSH `authorized_keys` format and returns // a SSH certificate signed by the Host CA. GenerateHostCert(ctx context.Context, in *GenerateHostCertRequest, opts ...grpc.CallOption) (*GenerateHostCertResponse, error) + // UpsertTrustedCluster upserts a Trusted Cluster in a backend. + UpsertTrustedCluster(ctx context.Context, in *UpsertTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) + // CreateTrustedCluster creates a Trusted Cluster in a backend. + CreateTrustedCluster(ctx context.Context, in *CreateTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) + // UpdateTrustedCluster updates a Trusted Cluster in a backend. + UpdateTrustedCluster(ctx context.Context, in *UpdateTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) } type trustServiceClient struct { @@ -145,6 +154,36 @@ func (c *trustServiceClient) GenerateHostCert(ctx context.Context, in *GenerateH return out, nil } +func (c *trustServiceClient) UpsertTrustedCluster(ctx context.Context, in *UpsertTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(types.TrustedClusterV2) + err := c.cc.Invoke(ctx, TrustService_UpsertTrustedCluster_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *trustServiceClient) CreateTrustedCluster(ctx context.Context, in *CreateTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(types.TrustedClusterV2) + err := c.cc.Invoke(ctx, TrustService_CreateTrustedCluster_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *trustServiceClient) UpdateTrustedCluster(ctx context.Context, in *UpdateTrustedClusterRequest, opts ...grpc.CallOption) (*types.TrustedClusterV2, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(types.TrustedClusterV2) + err := c.cc.Invoke(ctx, TrustService_UpdateTrustedCluster_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // TrustServiceServer is the server API for TrustService service. // All implementations must embed UnimplementedTrustServiceServer // for forward compatibility. @@ -166,6 +205,12 @@ type TrustServiceServer interface { // GenerateHostCert takes a public key in the OpenSSH `authorized_keys` format and returns // a SSH certificate signed by the Host CA. GenerateHostCert(context.Context, *GenerateHostCertRequest) (*GenerateHostCertResponse, error) + // UpsertTrustedCluster upserts a Trusted Cluster in a backend. + UpsertTrustedCluster(context.Context, *UpsertTrustedClusterRequest) (*types.TrustedClusterV2, error) + // CreateTrustedCluster creates a Trusted Cluster in a backend. + CreateTrustedCluster(context.Context, *CreateTrustedClusterRequest) (*types.TrustedClusterV2, error) + // UpdateTrustedCluster updates a Trusted Cluster in a backend. + UpdateTrustedCluster(context.Context, *UpdateTrustedClusterRequest) (*types.TrustedClusterV2, error) mustEmbedUnimplementedTrustServiceServer() } @@ -197,6 +242,15 @@ func (UnimplementedTrustServiceServer) RotateExternalCertAuthority(context.Conte func (UnimplementedTrustServiceServer) GenerateHostCert(context.Context, *GenerateHostCertRequest) (*GenerateHostCertResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GenerateHostCert not implemented") } +func (UnimplementedTrustServiceServer) UpsertTrustedCluster(context.Context, *UpsertTrustedClusterRequest) (*types.TrustedClusterV2, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpsertTrustedCluster not implemented") +} +func (UnimplementedTrustServiceServer) CreateTrustedCluster(context.Context, *CreateTrustedClusterRequest) (*types.TrustedClusterV2, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateTrustedCluster not implemented") +} +func (UnimplementedTrustServiceServer) UpdateTrustedCluster(context.Context, *UpdateTrustedClusterRequest) (*types.TrustedClusterV2, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateTrustedCluster not implemented") +} func (UnimplementedTrustServiceServer) mustEmbedUnimplementedTrustServiceServer() {} func (UnimplementedTrustServiceServer) testEmbeddedByValue() {} @@ -344,6 +398,60 @@ func _TrustService_GenerateHostCert_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _TrustService_UpsertTrustedCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpsertTrustedClusterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TrustServiceServer).UpsertTrustedCluster(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TrustService_UpsertTrustedCluster_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TrustServiceServer).UpsertTrustedCluster(ctx, req.(*UpsertTrustedClusterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TrustService_CreateTrustedCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateTrustedClusterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TrustServiceServer).CreateTrustedCluster(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TrustService_CreateTrustedCluster_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TrustServiceServer).CreateTrustedCluster(ctx, req.(*CreateTrustedClusterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TrustService_UpdateTrustedCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateTrustedClusterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TrustServiceServer).UpdateTrustedCluster(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: TrustService_UpdateTrustedCluster_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TrustServiceServer).UpdateTrustedCluster(ctx, req.(*UpdateTrustedClusterRequest)) + } + return interceptor(ctx, in, info, handler) +} + // TrustService_ServiceDesc is the grpc.ServiceDesc for TrustService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -379,6 +487,18 @@ var TrustService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GenerateHostCert", Handler: _TrustService_GenerateHostCert_Handler, }, + { + MethodName: "UpsertTrustedCluster", + Handler: _TrustService_UpsertTrustedCluster_Handler, + }, + { + MethodName: "CreateTrustedCluster", + Handler: _TrustService_CreateTrustedCluster_Handler, + }, + { + MethodName: "UpdateTrustedCluster", + Handler: _TrustService_UpdateTrustedCluster_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "teleport/trust/v1/trust_service.proto", diff --git a/api/gen/proto/go/teleport/userloginstate/v1/userloginstate.pb.go b/api/gen/proto/go/teleport/userloginstate/v1/userloginstate.pb.go index 47cc1b04c3b40..f187235904554 100644 --- a/api/gen/proto/go/teleport/userloginstate/v1/userloginstate.pb.go +++ b/api/gen/proto/go/teleport/userloginstate/v1/userloginstate.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userloginstate/v1/userloginstate.proto diff --git a/api/gen/proto/go/teleport/userloginstate/v1/userloginstate_service.pb.go b/api/gen/proto/go/teleport/userloginstate/v1/userloginstate_service.pb.go index 94e7e6d20a167..a6b8739ee3c3b 100644 --- a/api/gen/proto/go/teleport/userloginstate/v1/userloginstate_service.pb.go +++ b/api/gen/proto/go/teleport/userloginstate/v1/userloginstate_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userloginstate/v1/userloginstate_service.proto diff --git a/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser.pb.go b/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser.pb.go index a691f54eb07a9..d35b9ecbe57f4 100644 --- a/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser.pb.go +++ b/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userprovisioning/v2/statichostuser.proto diff --git a/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_service.pb.go b/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_service.pb.go index 851b9a6e51f61..aa0b0003d9055 100644 --- a/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_service.pb.go +++ b/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userprovisioning/v2/statichostuser_service.proto diff --git a/api/gen/proto/go/teleport/users/v1/users_service.pb.go b/api/gen/proto/go/teleport/users/v1/users_service.pb.go index 02f3e0e61422a..8ba0773b86f3e 100644 --- a/api/gen/proto/go/teleport/users/v1/users_service.pb.go +++ b/api/gen/proto/go/teleport/users/v1/users_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/users/v1/users_service.proto diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go index 9ca8b2c58e82c..65e4e25b7e9c6 100644 --- a/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/usertasks/v1/user_tasks.proto diff --git a/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go index 48b39ad547064..4356cbbb9032e 100644 --- a/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go +++ b/api/gen/proto/go/teleport/usertasks/v1/user_tasks_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/usertasks/v1/user_tasks_service.proto diff --git a/api/gen/proto/go/teleport/vnet/v1/vnet_config.pb.go b/api/gen/proto/go/teleport/vnet/v1/vnet_config.pb.go index 9fab3a94da42a..46ed1e982180c 100644 --- a/api/gen/proto/go/teleport/vnet/v1/vnet_config.pb.go +++ b/api/gen/proto/go/teleport/vnet/v1/vnet_config.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/vnet/v1/vnet_config.proto diff --git a/api/gen/proto/go/teleport/vnet/v1/vnet_config_service.pb.go b/api/gen/proto/go/teleport/vnet/v1/vnet_config_service.pb.go index d57baacc956f0..f55eff558f365 100644 --- a/api/gen/proto/go/teleport/vnet/v1/vnet_config_service.pb.go +++ b/api/gen/proto/go/teleport/vnet/v1/vnet_config_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/vnet/v1/vnet_config_service.proto diff --git a/api/gen/proto/go/teleport/workloadidentity/v1/attrs.pb.go b/api/gen/proto/go/teleport/workloadidentity/v1/attrs.pb.go index bc75d65f597e0..67865b0ae7c3e 100644 --- a/api/gen/proto/go/teleport/workloadidentity/v1/attrs.pb.go +++ b/api/gen/proto/go/teleport/workloadidentity/v1/attrs.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/workloadidentity/v1/attrs.proto diff --git a/api/gen/proto/go/teleport/workloadidentity/v1/issuance_service.pb.go b/api/gen/proto/go/teleport/workloadidentity/v1/issuance_service.pb.go index 36166c852d564..48f8d95b87375 100644 --- a/api/gen/proto/go/teleport/workloadidentity/v1/issuance_service.pb.go +++ b/api/gen/proto/go/teleport/workloadidentity/v1/issuance_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/workloadidentity/v1/issuance_service.proto diff --git a/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go b/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go index 3b9ce3b695f5c..6e52820acbc26 100644 --- a/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go +++ b/api/gen/proto/go/teleport/workloadidentity/v1/resource.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/workloadidentity/v1/resource.proto diff --git a/api/gen/proto/go/teleport/workloadidentity/v1/resource_service.pb.go b/api/gen/proto/go/teleport/workloadidentity/v1/resource_service.pb.go index 0c2ca023db938..0a32a67a1f38f 100644 --- a/api/gen/proto/go/teleport/workloadidentity/v1/resource_service.pb.go +++ b/api/gen/proto/go/teleport/workloadidentity/v1/resource_service.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/workloadidentity/v1/resource_service.proto diff --git a/api/gen/proto/go/userpreferences/v1/access_graph.pb.go b/api/gen/proto/go/userpreferences/v1/access_graph.pb.go index dc4878ae0a10d..da763ea0f2e94 100644 --- a/api/gen/proto/go/userpreferences/v1/access_graph.pb.go +++ b/api/gen/proto/go/userpreferences/v1/access_graph.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/access_graph.proto diff --git a/api/gen/proto/go/userpreferences/v1/assist.pb.go b/api/gen/proto/go/userpreferences/v1/assist.pb.go index b84132e2ac5c9..e757960c0ed10 100644 --- a/api/gen/proto/go/userpreferences/v1/assist.pb.go +++ b/api/gen/proto/go/userpreferences/v1/assist.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/assist.proto diff --git a/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go b/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go index 466fafb8a6c9f..c77a39093f94d 100644 --- a/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go +++ b/api/gen/proto/go/userpreferences/v1/cluster_preferences.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/cluster_preferences.proto diff --git a/api/gen/proto/go/userpreferences/v1/onboard.pb.go b/api/gen/proto/go/userpreferences/v1/onboard.pb.go index 2212834896d79..4088c0ce805de 100644 --- a/api/gen/proto/go/userpreferences/v1/onboard.pb.go +++ b/api/gen/proto/go/userpreferences/v1/onboard.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/onboard.proto diff --git a/api/gen/proto/go/userpreferences/v1/sidenav_preferences.pb.go b/api/gen/proto/go/userpreferences/v1/sidenav_preferences.pb.go index 1e3329f173011..4ee547cce5245 100644 --- a/api/gen/proto/go/userpreferences/v1/sidenav_preferences.pb.go +++ b/api/gen/proto/go/userpreferences/v1/sidenav_preferences.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/sidenav_preferences.proto diff --git a/api/gen/proto/go/userpreferences/v1/theme.pb.go b/api/gen/proto/go/userpreferences/v1/theme.pb.go index 7d6a579015f19..62e274bbe9d62 100644 --- a/api/gen/proto/go/userpreferences/v1/theme.pb.go +++ b/api/gen/proto/go/userpreferences/v1/theme.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/theme.proto diff --git a/api/gen/proto/go/userpreferences/v1/unified_resource_preferences.pb.go b/api/gen/proto/go/userpreferences/v1/unified_resource_preferences.pb.go index 6c8dae4a985d6..0806e1631a803 100644 --- a/api/gen/proto/go/userpreferences/v1/unified_resource_preferences.pb.go +++ b/api/gen/proto/go/userpreferences/v1/unified_resource_preferences.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/unified_resource_preferences.proto diff --git a/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go b/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go index c14a0344a16b2..c4280fee817c7 100644 --- a/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go +++ b/api/gen/proto/go/userpreferences/v1/userpreferences.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/userpreferences/v1/userpreferences.proto diff --git a/api/go.mod b/api/go.mod index e01ed6bbbfcd6..6073fd17e0fd3 100644 --- a/api/go.mod +++ b/api/go.mod @@ -28,7 +28,7 @@ require ( golang.org/x/term v0.27.0 google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 google.golang.org/grpc v1.68.0 - google.golang.org/protobuf v1.36.0 + google.golang.org/protobuf v1.36.1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/api/go.sum b/api/go.sum index 4c35d634358ec..88d97741a7056 100644 --- a/api/go.sum +++ b/api/go.sum @@ -1565,8 +1565,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/api/proto/teleport/legacy/client/proto/authservice.proto b/api/proto/teleport/legacy/client/proto/authservice.proto index 79eb5fc2b56d7..fc6dc146ff248 100644 --- a/api/proto/teleport/legacy/client/proto/authservice.proto +++ b/api/proto/teleport/legacy/client/proto/authservice.proto @@ -2145,6 +2145,36 @@ message ListResourcesRequest { bool IncludeLogins = 13 [(gogoproto.jsontag) = "include_logins,omitempty"]; } +// ResolveSSHTargetRequest provides details about a server to be resolved in +// an equivalent manner to a ssh dial request. +// +// Resolution can happen in two modes: +// 1) searching for hosts based on labels, a predicate expression, or keywords +// 2) searching based on hostname +// +// If a Host is provided, resolution will only operate in the second mode and +// will not perform any resolution based on labels. In order to resolve via +// labels the Host must not be populated. +message ResolveSSHTargetRequest { + // The target host as would be sent to the proxy during a dial request. + string host = 1; + // The ssh port. This value is optional, and both empty string and "0" are typically + // treated as meaning that any port should match. + string port = 2; + // If not empty, a label-based matcher. + map labels = 3; + // Boolean conditions that will be matched against the resource. + string predicate_expression = 4; + // A list of search keywords to match against resource field values. + repeated string search_keywords = 5; +} + +// GetSSHTargetsResponse holds ssh servers that match an ssh targets request. +message ResolveSSHTargetResponse { + // The target matching the supplied request. + types.ServerV2 server = 1; +} + // GetSSHTargetsRequest gets all servers that might match an equivalent ssh dial request. message GetSSHTargetsRequest { // Host is the target host as would be sent to the proxy during a dial request. @@ -3278,7 +3308,11 @@ service AuthService { // GetTrustedClusters gets all current Trusted Cluster resources. rpc GetTrustedClusters(google.protobuf.Empty) returns (types.TrustedClusterV2List); // UpsertTrustedCluster upserts a Trusted Cluster in a backend. - rpc UpsertTrustedCluster(types.TrustedClusterV2) returns (types.TrustedClusterV2); + // + // Deprecated: Use [teleport.trust.v1.UpsertTrustedCluster] instead. + rpc UpsertTrustedCluster(types.TrustedClusterV2) returns (types.TrustedClusterV2) { + option deprecated = true; + } // DeleteTrustedCluster deletes an existing Trusted Cluster in a backend by name. rpc DeleteTrustedCluster(types.ResourceRequest) returns (google.protobuf.Empty); @@ -3553,6 +3587,9 @@ service AuthService { // but may result in confusing behavior if it is used outside of those contexts. rpc GetSSHTargets(GetSSHTargetsRequest) returns (GetSSHTargetsResponse); + // ResolveSSHTarget returns the server that would be resolved in an equivalent ssh dial request. + rpc ResolveSSHTarget(ResolveSSHTargetRequest) returns (ResolveSSHTargetResponse); + // GetDomainName returns local auth domain of the current auth server rpc GetDomainName(google.protobuf.Empty) returns (GetDomainNameResponse); // GetClusterCACert returns the PEM-encoded TLS certs for the local cluster diff --git a/api/proto/teleport/legacy/types/types.proto b/api/proto/teleport/legacy/types/types.proto index 41d980906ef9a..3d4081073e01e 100644 --- a/api/proto/teleport/legacy/types/types.proto +++ b/api/proto/teleport/legacy/types/types.proto @@ -6470,6 +6470,8 @@ message PluginSpecV1 { PluginEmailSettings email = 17; // Settings for the Microsoft Teams plugin PluginMSTeamsSettings msteams = 18; + // Settings for the OpenTex NetIQ plugin. + PluginNetIQSettings net_iq = 19; } // generation contains a unique ID that should: @@ -6896,6 +6898,18 @@ message PluginMSTeamsSettings { string default_recipient = 5; } +// PluginNetIQSettings defines the settings for a NetIQ integration plugin +message PluginNetIQSettings { + option (gogoproto.equal) = true; + // oauth_issuer_endpoint is the NetIQ Oauth Issuer endpoint. + // Usually, it's equal to https://osp.domain.ext/a/idm/auth/oauth2 + string oauth_issuer_endpoint = 1; + // api_endpoint is the IDM PROV Rest API location. + string api_endpoint = 2; + // insecure_skip_verify controls whether the NetIQ certificate validation should be skipped. + bool insecure_skip_verify = 3; +} + message PluginBootstrapCredentialsV1 { oneof credentials { PluginOAuth2AuthorizationCodeCredentials oauth2_authorization_code = 1; @@ -6934,6 +6948,8 @@ message PluginStatusV1 { PluginOktaStatusV1 okta = 7; // AWSIC holds status details for the AWS Identity Center plugin. PluginAWSICStatusV1 aws_ic = 8; + // NetIQ holds status details for the NetIQ plugin. + PluginNetIQStatusV1 net_iq = 9; } // last_raw_error variable stores the most recent raw error message received from an API or service. @@ -6943,6 +6959,18 @@ message PluginStatusV1 { string last_raw_error = 6; } +// PluginNetIQStatusV1 is the status details for the NetIQ plugin. +message PluginNetIQStatusV1 { + // imported_users is the number of users imported from NetIQ eDirectory. + uint32 imported_users = 1; + // imported_groups is the number of groups imported from NetIQ eDirectory. + uint32 imported_groups = 2; + // imported_roles is the number of roles imported from NetIQ eDirectory. + uint32 imported_roles = 3; + // imported_resources is the number of resources imported from NetIQ eDirectory. + uint32 imported_resources = 4; +} + // PluginGitlabStatusV1 is the status details for the Gitlab plugin. message PluginGitlabStatusV1 { // imported_users is the number of users imported from Gitlab. diff --git a/api/proto/teleport/trust/v1/trust_service.proto b/api/proto/teleport/trust/v1/trust_service.proto index a6b3fc3282c44..7d8748f2375f7 100644 --- a/api/proto/teleport/trust/v1/trust_service.proto +++ b/api/proto/teleport/trust/v1/trust_service.proto @@ -40,6 +40,31 @@ service TrustService { // GenerateHostCert takes a public key in the OpenSSH `authorized_keys` format and returns // a SSH certificate signed by the Host CA. rpc GenerateHostCert(GenerateHostCertRequest) returns (GenerateHostCertResponse); + + // UpsertTrustedCluster upserts a Trusted Cluster in a backend. + rpc UpsertTrustedCluster(UpsertTrustedClusterRequest) returns (types.TrustedClusterV2); + // CreateTrustedCluster creates a Trusted Cluster in a backend. + rpc CreateTrustedCluster(CreateTrustedClusterRequest) returns (types.TrustedClusterV2); + // UpdateTrustedCluster updates a Trusted Cluster in a backend. + rpc UpdateTrustedCluster(UpdateTrustedClusterRequest) returns (types.TrustedClusterV2); +} + +// Request for UpsertTrustedCluster. +message UpsertTrustedClusterRequest { + // TrustedCluster specifies a Trusted Cluster resource. + types.TrustedClusterV2 trusted_cluster = 1; +} + +// Request for CreateTrustedCluster. +message CreateTrustedClusterRequest { + // TrustedCluster specifies a Trusted Cluster resource. + types.TrustedClusterV2 trusted_cluster = 1; +} + +// Request for UpdateTrustedCluster. +message UpdateTrustedClusterRequest { + // TrustedCluster specifies a Trusted Cluster resource. + types.TrustedClusterV2 trusted_cluster = 1; } // Request for GetCertAuthority diff --git a/api/types/plugin.go b/api/types/plugin.go index fc69231cc6622..f6c0b96ec1aa3 100644 --- a/api/types/plugin.go +++ b/api/types/plugin.go @@ -17,6 +17,7 @@ limitations under the License. package types import ( + "net/url" "time" "github.com/gravitational/trace" @@ -83,6 +84,8 @@ const ( PluginTypeEmail = "email" // PluginTypeMSTeams indicates a Microsoft Teams integration PluginTypeMSTeams = "msteams" + // PluginTypeNetIQ indicates a NetIQ integration + PluginTypeNetIQ = "netiq" ) // PluginSubkind represents the type of the plugin, e.g., access request, MDM etc. @@ -377,6 +380,20 @@ func (p *PluginV1) CheckAndSetDefaults() error { if len(staticCreds.Labels) == 0 { return trace.BadParameter("labels must be specified") } + case *PluginSpecV1_NetIq: + if settings.NetIq == nil { + return trace.BadParameter("missing NetIQ settings") + } + if err := settings.NetIq.Validate(); err != nil { + return trace.Wrap(err) + } + staticCreds := p.Credentials.GetStaticCredentialsRef() + if staticCreds == nil { + return trace.BadParameter("NetIQ plugin must be used with the static credentials ref type") + } + if len(staticCreds.Labels) == 0 { + return trace.BadParameter("labels must be specified") + } default: return nil } @@ -837,3 +854,22 @@ func (c *PluginGitlabSettings) Validate() error { return nil } + +func (c *PluginNetIQSettings) Validate() error { + if c.OauthIssuerEndpoint == "" { + return trace.BadParameter("oauth_issuer endpoint must be set") + } + + if _, err := url.Parse(c.OauthIssuerEndpoint); err != nil { + return trace.BadParameter("oauth_issuer endpoint must be a valid URL") + } + + if c.ApiEndpoint == "" { + return trace.BadParameter("api_endpoint must be set") + } + if _, err := url.Parse(c.ApiEndpoint); err != nil { + return trace.BadParameter("api_endpoint endpoint must be a valid URL") + } + + return nil +} diff --git a/api/types/plugin_test.go b/api/types/plugin_test.go index 87d3d6182675b..db33043e3ea7a 100644 --- a/api/types/plugin_test.go +++ b/api/types/plugin_test.go @@ -1336,3 +1336,78 @@ func TestPluginEmailSettings(t *testing.T) { }) } } + +func TestNetIQPluginSettings(t *testing.T) { + + validSettings := func() *PluginSpecV1_NetIq { + return &PluginSpecV1_NetIq{ + NetIq: &PluginNetIQSettings{ + OauthIssuerEndpoint: "https://example.com", + ApiEndpoint: "https://example.com", + }, + } + } + testCases := []struct { + name string + mutateSettings func(*PluginSpecV1_NetIq) + assertErr require.ErrorAssertionFunc + }{ + { + name: "valid", + mutateSettings: nil, + assertErr: require.NoError, + }, + { + name: "missing OauthIssuer", + mutateSettings: func(s *PluginSpecV1_NetIq) { + s.NetIq.OauthIssuerEndpoint = "" + }, + assertErr: requireNamedBadParameterError("oauth_issuer"), + }, + { + name: "missing ApiEndpoint", + mutateSettings: func(s *PluginSpecV1_NetIq) { + s.NetIq.ApiEndpoint = "" + }, + assertErr: requireNamedBadParameterError("api_endpoint"), + }, + { + name: "incorrect OauthIssuer", + mutateSettings: func(s *PluginSpecV1_NetIq) { + s.NetIq.OauthIssuerEndpoint = "invalidURL%%#" + }, + assertErr: requireNamedBadParameterError("oauth_issuer"), + }, + { + name: "missing ApiEndpoint", + mutateSettings: func(s *PluginSpecV1_NetIq) { + s.NetIq.ApiEndpoint = "invalidURL%%#" + }, + assertErr: requireNamedBadParameterError("api_endpoint"), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + settings := validSettings() + if tc.mutateSettings != nil { + tc.mutateSettings(settings) + } + + plugin := NewPluginV1( + Metadata{Name: "uut"}, + PluginSpecV1{Settings: settings}, + &PluginCredentialsV1{ + Credentials: &PluginCredentialsV1_StaticCredentialsRef{ + StaticCredentialsRef: &PluginStaticCredentialsRef{ + Labels: map[string]string{ + "label1": "value1", + }, + }, + }, + }) + tc.assertErr(t, plugin.CheckAndSetDefaults()) + }) + } + +} diff --git a/api/types/session_tracker.go b/api/types/session_tracker.go index db07ea2578db5..2892db170085c 100644 --- a/api/types/session_tracker.go +++ b/api/types/session_tracker.go @@ -39,6 +39,7 @@ const ( DatabaseSessionKind SessionKind = "db" AppSessionKind SessionKind = "app" WindowsDesktopSessionKind SessionKind = "desktop" + UnknownSessionKind SessionKind = "" ) // SessionParticipantMode is the mode that determines what you can do when you join a session. diff --git a/api/types/trustedcluster.go b/api/types/trustedcluster.go index 27d8129f70cfe..17d397525a7df 100644 --- a/api/types/trustedcluster.go +++ b/api/types/trustedcluster.go @@ -29,8 +29,8 @@ import ( // TrustedCluster holds information needed for a cluster that can not be directly // accessed (maybe be behind firewall without any open ports) to join a parent cluster. type TrustedCluster interface { - // Resource provides common resource properties - Resource + // ResourceWithOrigin provides common resource properties + ResourceWithOrigin // SetMetadata sets object metadata SetMetadata(meta Metadata) // GetEnabled returns the state of the TrustedCluster. @@ -184,6 +184,16 @@ func (c *TrustedClusterV2) SetName(e string) { c.Metadata.Name = e } +// Origin returns the origin value of the resource. +func (c *TrustedClusterV2) Origin() string { + return c.Metadata.Origin() +} + +// SetOrigin sets the origin value of the resource. +func (c *TrustedClusterV2) SetOrigin(origin string) { + c.Metadata.SetOrigin(origin) +} + // GetEnabled returns the state of the TrustedCluster. func (c *TrustedClusterV2) GetEnabled() bool { return c.Spec.Enabled @@ -252,14 +262,6 @@ func (c *TrustedClusterV2) CanChangeStateTo(t TrustedCluster) error { if !slices.Equal(c.GetRoles(), t.GetRoles()) { return immutableFieldErr("roles") } - - if c.GetEnabled() == t.GetEnabled() && c.GetRoleMap().IsEqual(t.GetRoleMap()) { - if t.GetEnabled() { - return trace.AlreadyExists("leaf cluster is already enabled, this update would have no effect") - } - return trace.AlreadyExists("leaf cluster is already disabled, this update would have no effect") - } - return nil } diff --git a/api/types/types.pb.go b/api/types/types.pb.go index b8eec25929456..10387e25bd555 100644 --- a/api/types/types.pb.go +++ b/api/types/types.pb.go @@ -1226,7 +1226,7 @@ func (x OktaAssignmentSpecV1_OktaAssignmentStatus) String() string { } func (OktaAssignmentSpecV1_OktaAssignmentStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{345, 0} + return fileDescriptor_9198ee693835762e, []int{347, 0} } // OktaAssignmentTargetType is the type of Okta object that an assignment is targeting. @@ -1258,7 +1258,7 @@ func (x OktaAssignmentTargetV1_OktaAssignmentTargetType) String() string { } func (OktaAssignmentTargetV1_OktaAssignmentTargetType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{346, 0} + return fileDescriptor_9198ee693835762e, []int{348, 0} } type KeepAlive struct { @@ -16222,6 +16222,7 @@ type PluginSpecV1 struct { // *PluginSpecV1_AwsIc // *PluginSpecV1_Email // *PluginSpecV1_Msteams + // *PluginSpecV1_NetIq Settings isPluginSpecV1_Settings `protobuf_oneof:"settings"` // generation contains a unique ID that should: // - Be created by the backend on plugin creation. @@ -16325,6 +16326,9 @@ type PluginSpecV1_Email struct { type PluginSpecV1_Msteams struct { Msteams *PluginMSTeamsSettings `protobuf:"bytes,18,opt,name=msteams,proto3,oneof" json:"msteams,omitempty"` } +type PluginSpecV1_NetIq struct { + NetIq *PluginNetIQSettings `protobuf:"bytes,19,opt,name=net_iq,json=netIq,proto3,oneof" json:"net_iq,omitempty"` +} func (*PluginSpecV1_SlackAccessPlugin) isPluginSpecV1_Settings() {} func (*PluginSpecV1_Opsgenie) isPluginSpecV1_Settings() {} @@ -16343,6 +16347,7 @@ func (*PluginSpecV1_Datadog) isPluginSpecV1_Settings() {} func (*PluginSpecV1_AwsIc) isPluginSpecV1_Settings() {} func (*PluginSpecV1_Email) isPluginSpecV1_Settings() {} func (*PluginSpecV1_Msteams) isPluginSpecV1_Settings() {} +func (*PluginSpecV1_NetIq) isPluginSpecV1_Settings() {} func (m *PluginSpecV1) GetSettings() isPluginSpecV1_Settings { if m != nil { @@ -16470,6 +16475,13 @@ func (m *PluginSpecV1) GetMsteams() *PluginMSTeamsSettings { return nil } +func (m *PluginSpecV1) GetNetIq() *PluginNetIQSettings { + if x, ok := m.GetSettings().(*PluginSpecV1_NetIq); ok { + return x.NetIq + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*PluginSpecV1) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -16490,6 +16502,7 @@ func (*PluginSpecV1) XXX_OneofWrappers() []interface{} { (*PluginSpecV1_AwsIc)(nil), (*PluginSpecV1_Email)(nil), (*PluginSpecV1_Msteams)(nil), + (*PluginSpecV1_NetIq)(nil), } } @@ -17867,6 +17880,53 @@ func (m *PluginMSTeamsSettings) XXX_DiscardUnknown() { var xxx_messageInfo_PluginMSTeamsSettings proto.InternalMessageInfo +// PluginNetIQSettings defines the settings for a NetIQ integration plugin +type PluginNetIQSettings struct { + // oauth_issuer_endpoint is the NetIQ Oauth Issuer endpoint. + // Usually, it's equal to https://osp.domain.ext/a/idm/auth/oauth2 + OauthIssuerEndpoint string `protobuf:"bytes,1,opt,name=oauth_issuer_endpoint,json=oauthIssuerEndpoint,proto3" json:"oauth_issuer_endpoint,omitempty"` + // api_endpoint is the IDM PROV Rest API location. + ApiEndpoint string `protobuf:"bytes,2,opt,name=api_endpoint,json=apiEndpoint,proto3" json:"api_endpoint,omitempty"` + // insecure_skip_verify controls whether the NetIQ certificate validation should be skipped. + InsecureSkipVerify bool `protobuf:"varint,3,opt,name=insecure_skip_verify,json=insecureSkipVerify,proto3" json:"insecure_skip_verify,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PluginNetIQSettings) Reset() { *m = PluginNetIQSettings{} } +func (m *PluginNetIQSettings) String() string { return proto.CompactTextString(m) } +func (*PluginNetIQSettings) ProtoMessage() {} +func (*PluginNetIQSettings) Descriptor() ([]byte, []int) { + return fileDescriptor_9198ee693835762e, []int{304} +} +func (m *PluginNetIQSettings) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginNetIQSettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PluginNetIQSettings.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PluginNetIQSettings) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginNetIQSettings.Merge(m, src) +} +func (m *PluginNetIQSettings) XXX_Size() int { + return m.Size() +} +func (m *PluginNetIQSettings) XXX_DiscardUnknown() { + xxx_messageInfo_PluginNetIQSettings.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginNetIQSettings proto.InternalMessageInfo + type PluginBootstrapCredentialsV1 struct { // Types that are valid to be assigned to Credentials: // @@ -17883,7 +17943,7 @@ func (m *PluginBootstrapCredentialsV1) Reset() { *m = PluginBootstrapCre func (m *PluginBootstrapCredentialsV1) String() string { return proto.CompactTextString(m) } func (*PluginBootstrapCredentialsV1) ProtoMessage() {} func (*PluginBootstrapCredentialsV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{304} + return fileDescriptor_9198ee693835762e, []int{305} } func (m *PluginBootstrapCredentialsV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -17983,7 +18043,7 @@ func (m *PluginIdSecretCredential) Reset() { *m = PluginIdSecretCredenti func (m *PluginIdSecretCredential) String() string { return proto.CompactTextString(m) } func (*PluginIdSecretCredential) ProtoMessage() {} func (*PluginIdSecretCredential) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{305} + return fileDescriptor_9198ee693835762e, []int{306} } func (m *PluginIdSecretCredential) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18026,7 +18086,7 @@ func (m *PluginOAuth2AuthorizationCodeCredentials) Reset() { func (m *PluginOAuth2AuthorizationCodeCredentials) String() string { return proto.CompactTextString(m) } func (*PluginOAuth2AuthorizationCodeCredentials) ProtoMessage() {} func (*PluginOAuth2AuthorizationCodeCredentials) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{306} + return fileDescriptor_9198ee693835762e, []int{307} } func (m *PluginOAuth2AuthorizationCodeCredentials) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18070,6 +18130,7 @@ type PluginStatusV1 struct { // *PluginStatusV1_EntraId // *PluginStatusV1_Okta // *PluginStatusV1_AwsIc + // *PluginStatusV1_NetIq Details isPluginStatusV1_Details `protobuf_oneof:"details"` // last_raw_error variable stores the most recent raw error message received from an API or service. // It is intended to capture the original error message without any modifications or formatting. @@ -18085,7 +18146,7 @@ func (m *PluginStatusV1) Reset() { *m = PluginStatusV1{} } func (m *PluginStatusV1) String() string { return proto.CompactTextString(m) } func (*PluginStatusV1) ProtoMessage() {} func (*PluginStatusV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{307} + return fileDescriptor_9198ee693835762e, []int{308} } func (m *PluginStatusV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18132,11 +18193,15 @@ type PluginStatusV1_Okta struct { type PluginStatusV1_AwsIc struct { AwsIc *PluginAWSICStatusV1 `protobuf:"bytes,8,opt,name=aws_ic,json=awsIc,proto3,oneof" json:"aws_ic,omitempty"` } +type PluginStatusV1_NetIq struct { + NetIq *PluginNetIQStatusV1 `protobuf:"bytes,9,opt,name=net_iq,json=netIq,proto3,oneof" json:"net_iq,omitempty"` +} func (*PluginStatusV1_Gitlab) isPluginStatusV1_Details() {} func (*PluginStatusV1_EntraId) isPluginStatusV1_Details() {} func (*PluginStatusV1_Okta) isPluginStatusV1_Details() {} func (*PluginStatusV1_AwsIc) isPluginStatusV1_Details() {} +func (*PluginStatusV1_NetIq) isPluginStatusV1_Details() {} func (m *PluginStatusV1) GetDetails() isPluginStatusV1_Details { if m != nil { @@ -18173,6 +18238,13 @@ func (m *PluginStatusV1) GetAwsIc() *PluginAWSICStatusV1 { return nil } +func (m *PluginStatusV1) GetNetIq() *PluginNetIQStatusV1 { + if x, ok := m.GetDetails().(*PluginStatusV1_NetIq); ok { + return x.NetIq + } + return nil +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*PluginStatusV1) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -18180,9 +18252,58 @@ func (*PluginStatusV1) XXX_OneofWrappers() []interface{} { (*PluginStatusV1_EntraId)(nil), (*PluginStatusV1_Okta)(nil), (*PluginStatusV1_AwsIc)(nil), + (*PluginStatusV1_NetIq)(nil), } } +// PluginNetIQStatusV1 is the status details for the NetIQ plugin. +type PluginNetIQStatusV1 struct { + // imported_users is the number of users imported from NetIQ eDirectory. + ImportedUsers uint32 `protobuf:"varint,1,opt,name=imported_users,json=importedUsers,proto3" json:"imported_users,omitempty"` + // imported_groups is the number of groups imported from NetIQ eDirectory. + ImportedGroups uint32 `protobuf:"varint,2,opt,name=imported_groups,json=importedGroups,proto3" json:"imported_groups,omitempty"` + // imported_roles is the number of roles imported from NetIQ eDirectory. + ImportedRoles uint32 `protobuf:"varint,3,opt,name=imported_roles,json=importedRoles,proto3" json:"imported_roles,omitempty"` + // imported_resources is the number of resources imported from NetIQ eDirectory. + ImportedResources uint32 `protobuf:"varint,4,opt,name=imported_resources,json=importedResources,proto3" json:"imported_resources,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PluginNetIQStatusV1) Reset() { *m = PluginNetIQStatusV1{} } +func (m *PluginNetIQStatusV1) String() string { return proto.CompactTextString(m) } +func (*PluginNetIQStatusV1) ProtoMessage() {} +func (*PluginNetIQStatusV1) Descriptor() ([]byte, []int) { + return fileDescriptor_9198ee693835762e, []int{309} +} +func (m *PluginNetIQStatusV1) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginNetIQStatusV1) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PluginNetIQStatusV1.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PluginNetIQStatusV1) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginNetIQStatusV1.Merge(m, src) +} +func (m *PluginNetIQStatusV1) XXX_Size() int { + return m.Size() +} +func (m *PluginNetIQStatusV1) XXX_DiscardUnknown() { + xxx_messageInfo_PluginNetIQStatusV1.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginNetIQStatusV1 proto.InternalMessageInfo + // PluginGitlabStatusV1 is the status details for the Gitlab plugin. type PluginGitlabStatusV1 struct { // imported_users is the number of users imported from Gitlab. @@ -18200,7 +18321,7 @@ func (m *PluginGitlabStatusV1) Reset() { *m = PluginGitlabStatusV1{} } func (m *PluginGitlabStatusV1) String() string { return proto.CompactTextString(m) } func (*PluginGitlabStatusV1) ProtoMessage() {} func (*PluginGitlabStatusV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{308} + return fileDescriptor_9198ee693835762e, []int{310} } func (m *PluginGitlabStatusV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18244,7 +18365,7 @@ func (m *PluginEntraIDStatusV1) Reset() { *m = PluginEntraIDStatusV1{} } func (m *PluginEntraIDStatusV1) String() string { return proto.CompactTextString(m) } func (*PluginEntraIDStatusV1) ProtoMessage() {} func (*PluginEntraIDStatusV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{309} + return fileDescriptor_9198ee693835762e, []int{311} } func (m *PluginEntraIDStatusV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18298,7 +18419,7 @@ func (m *PluginOktaStatusV1) Reset() { *m = PluginOktaStatusV1{} } func (m *PluginOktaStatusV1) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusV1) ProtoMessage() {} func (*PluginOktaStatusV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{310} + return fileDescriptor_9198ee693835762e, []int{312} } func (m *PluginOktaStatusV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18346,7 +18467,7 @@ func (m *PluginOktaStatusDetailsSSO) Reset() { *m = PluginOktaStatusDeta func (m *PluginOktaStatusDetailsSSO) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusDetailsSSO) ProtoMessage() {} func (*PluginOktaStatusDetailsSSO) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{311} + return fileDescriptor_9198ee693835762e, []int{313} } func (m *PluginOktaStatusDetailsSSO) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18403,7 +18524,7 @@ func (m *PluginOktaStatusDetailsAppGroupSync) Reset() { *m = PluginOktaS func (m *PluginOktaStatusDetailsAppGroupSync) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusDetailsAppGroupSync) ProtoMessage() {} func (*PluginOktaStatusDetailsAppGroupSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{312} + return fileDescriptor_9198ee693835762e, []int{314} } func (m *PluginOktaStatusDetailsAppGroupSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18457,7 +18578,7 @@ func (m *PluginOktaStatusDetailsUsersSync) Reset() { *m = PluginOktaStat func (m *PluginOktaStatusDetailsUsersSync) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusDetailsUsersSync) ProtoMessage() {} func (*PluginOktaStatusDetailsUsersSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{313} + return fileDescriptor_9198ee693835762e, []int{315} } func (m *PluginOktaStatusDetailsUsersSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18500,7 +18621,7 @@ func (m *PluginOktaStatusDetailsSCIM) Reset() { *m = PluginOktaStatusDet func (m *PluginOktaStatusDetailsSCIM) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusDetailsSCIM) ProtoMessage() {} func (*PluginOktaStatusDetailsSCIM) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{314} + return fileDescriptor_9198ee693835762e, []int{316} } func (m *PluginOktaStatusDetailsSCIM) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18562,7 +18683,7 @@ func (m *PluginOktaStatusDetailsAccessListsSync) Reset() { func (m *PluginOktaStatusDetailsAccessListsSync) String() string { return proto.CompactTextString(m) } func (*PluginOktaStatusDetailsAccessListsSync) ProtoMessage() {} func (*PluginOktaStatusDetailsAccessListsSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{315} + return fileDescriptor_9198ee693835762e, []int{317} } func (m *PluginOktaStatusDetailsAccessListsSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18610,7 +18731,7 @@ func (m *PluginCredentialsV1) Reset() { *m = PluginCredentialsV1{} } func (m *PluginCredentialsV1) String() string { return proto.CompactTextString(m) } func (*PluginCredentialsV1) ProtoMessage() {} func (*PluginCredentialsV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{316} + return fileDescriptor_9198ee693835762e, []int{318} } func (m *PluginCredentialsV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18721,7 +18842,7 @@ func (m *PluginOAuth2AccessTokenCredentials) Reset() { *m = PluginOAuth2 func (m *PluginOAuth2AccessTokenCredentials) String() string { return proto.CompactTextString(m) } func (*PluginOAuth2AccessTokenCredentials) ProtoMessage() {} func (*PluginOAuth2AccessTokenCredentials) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{317} + return fileDescriptor_9198ee693835762e, []int{319} } func (m *PluginOAuth2AccessTokenCredentials) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18762,7 +18883,7 @@ func (m *PluginBearerTokenCredentials) Reset() { *m = PluginBearerTokenC func (m *PluginBearerTokenCredentials) String() string { return proto.CompactTextString(m) } func (*PluginBearerTokenCredentials) ProtoMessage() {} func (*PluginBearerTokenCredentials) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{318} + return fileDescriptor_9198ee693835762e, []int{320} } func (m *PluginBearerTokenCredentials) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18804,7 +18925,7 @@ func (m *PluginStaticCredentialsRef) Reset() { *m = PluginStaticCredenti func (m *PluginStaticCredentialsRef) String() string { return proto.CompactTextString(m) } func (*PluginStaticCredentialsRef) ProtoMessage() {} func (*PluginStaticCredentialsRef) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{319} + return fileDescriptor_9198ee693835762e, []int{321} } func (m *PluginStaticCredentialsRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18846,7 +18967,7 @@ func (m *PluginListV1) Reset() { *m = PluginListV1{} } func (m *PluginListV1) String() string { return proto.CompactTextString(m) } func (*PluginListV1) ProtoMessage() {} func (*PluginListV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{320} + return fileDescriptor_9198ee693835762e, []int{322} } func (m *PluginListV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18889,7 +19010,7 @@ type PluginStaticCredentialsV1 struct { func (m *PluginStaticCredentialsV1) Reset() { *m = PluginStaticCredentialsV1{} } func (*PluginStaticCredentialsV1) ProtoMessage() {} func (*PluginStaticCredentialsV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{321} + return fileDescriptor_9198ee693835762e, []int{323} } func (m *PluginStaticCredentialsV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18936,7 +19057,7 @@ func (m *PluginStaticCredentialsSpecV1) Reset() { *m = PluginStaticCrede func (m *PluginStaticCredentialsSpecV1) String() string { return proto.CompactTextString(m) } func (*PluginStaticCredentialsSpecV1) ProtoMessage() {} func (*PluginStaticCredentialsSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{322} + return fileDescriptor_9198ee693835762e, []int{324} } func (m *PluginStaticCredentialsSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19051,7 +19172,7 @@ func (m *PluginStaticCredentialsBasicAuth) Reset() { *m = PluginStaticCr func (m *PluginStaticCredentialsBasicAuth) String() string { return proto.CompactTextString(m) } func (*PluginStaticCredentialsBasicAuth) ProtoMessage() {} func (*PluginStaticCredentialsBasicAuth) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{323} + return fileDescriptor_9198ee693835762e, []int{325} } func (m *PluginStaticCredentialsBasicAuth) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19097,7 +19218,7 @@ func (m *PluginStaticCredentialsOAuthClientSecret) Reset() { func (m *PluginStaticCredentialsOAuthClientSecret) String() string { return proto.CompactTextString(m) } func (*PluginStaticCredentialsOAuthClientSecret) ProtoMessage() {} func (*PluginStaticCredentialsOAuthClientSecret) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{324} + return fileDescriptor_9198ee693835762e, []int{326} } func (m *PluginStaticCredentialsOAuthClientSecret) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19145,7 +19266,7 @@ func (m *PluginStaticCredentialsSSHCertAuthorities) String() string { } func (*PluginStaticCredentialsSSHCertAuthorities) ProtoMessage() {} func (*PluginStaticCredentialsSSHCertAuthorities) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{325} + return fileDescriptor_9198ee693835762e, []int{327} } func (m *PluginStaticCredentialsSSHCertAuthorities) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19188,7 +19309,7 @@ type SAMLIdPServiceProviderV1 struct { func (m *SAMLIdPServiceProviderV1) Reset() { *m = SAMLIdPServiceProviderV1{} } func (*SAMLIdPServiceProviderV1) ProtoMessage() {} func (*SAMLIdPServiceProviderV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{326} + return fileDescriptor_9198ee693835762e, []int{328} } func (m *SAMLIdPServiceProviderV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19259,7 +19380,7 @@ func (m *SAMLIdPServiceProviderSpecV1) Reset() { *m = SAMLIdPServiceProv func (m *SAMLIdPServiceProviderSpecV1) String() string { return proto.CompactTextString(m) } func (*SAMLIdPServiceProviderSpecV1) ProtoMessage() {} func (*SAMLIdPServiceProviderSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{327} + return fileDescriptor_9198ee693835762e, []int{329} } func (m *SAMLIdPServiceProviderSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19306,7 +19427,7 @@ func (m *SAMLAttributeMapping) Reset() { *m = SAMLAttributeMapping{} } func (m *SAMLAttributeMapping) String() string { return proto.CompactTextString(m) } func (*SAMLAttributeMapping) ProtoMessage() {} func (*SAMLAttributeMapping) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{328} + return fileDescriptor_9198ee693835762e, []int{330} } func (m *SAMLAttributeMapping) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19348,7 +19469,7 @@ func (m *IdPOptions) Reset() { *m = IdPOptions{} } func (m *IdPOptions) String() string { return proto.CompactTextString(m) } func (*IdPOptions) ProtoMessage() {} func (*IdPOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{329} + return fileDescriptor_9198ee693835762e, []int{331} } func (m *IdPOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19390,7 +19511,7 @@ func (m *IdPSAMLOptions) Reset() { *m = IdPSAMLOptions{} } func (m *IdPSAMLOptions) String() string { return proto.CompactTextString(m) } func (*IdPSAMLOptions) ProtoMessage() {} func (*IdPSAMLOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{330} + return fileDescriptor_9198ee693835762e, []int{332} } func (m *IdPSAMLOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19440,7 +19561,7 @@ func (m *KubernetesResourceV1) Reset() { *m = KubernetesResourceV1{} } func (m *KubernetesResourceV1) String() string { return proto.CompactTextString(m) } func (*KubernetesResourceV1) ProtoMessage() {} func (*KubernetesResourceV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{331} + return fileDescriptor_9198ee693835762e, []int{333} } func (m *KubernetesResourceV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19482,7 +19603,7 @@ func (m *KubernetesResourceSpecV1) Reset() { *m = KubernetesResourceSpec func (m *KubernetesResourceSpecV1) String() string { return proto.CompactTextString(m) } func (*KubernetesResourceSpecV1) ProtoMessage() {} func (*KubernetesResourceSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{332} + return fileDescriptor_9198ee693835762e, []int{334} } func (m *KubernetesResourceSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19528,7 +19649,7 @@ func (m *ClusterMaintenanceConfigV1) Reset() { *m = ClusterMaintenanceCo func (m *ClusterMaintenanceConfigV1) String() string { return proto.CompactTextString(m) } func (*ClusterMaintenanceConfigV1) ProtoMessage() {} func (*ClusterMaintenanceConfigV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{333} + return fileDescriptor_9198ee693835762e, []int{335} } func (m *ClusterMaintenanceConfigV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19570,7 +19691,7 @@ func (m *ClusterMaintenanceConfigSpecV1) Reset() { *m = ClusterMaintenan func (m *ClusterMaintenanceConfigSpecV1) String() string { return proto.CompactTextString(m) } func (*ClusterMaintenanceConfigSpecV1) ProtoMessage() {} func (*ClusterMaintenanceConfigSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{334} + return fileDescriptor_9198ee693835762e, []int{336} } func (m *ClusterMaintenanceConfigSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19616,7 +19737,7 @@ func (m *AgentUpgradeWindow) Reset() { *m = AgentUpgradeWindow{} } func (m *AgentUpgradeWindow) String() string { return proto.CompactTextString(m) } func (*AgentUpgradeWindow) ProtoMessage() {} func (*AgentUpgradeWindow) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{335} + return fileDescriptor_9198ee693835762e, []int{337} } func (m *AgentUpgradeWindow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19663,7 +19784,7 @@ func (m *ScheduledAgentUpgradeWindow) Reset() { *m = ScheduledAgentUpgra func (m *ScheduledAgentUpgradeWindow) String() string { return proto.CompactTextString(m) } func (*ScheduledAgentUpgradeWindow) ProtoMessage() {} func (*ScheduledAgentUpgradeWindow) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{336} + return fileDescriptor_9198ee693835762e, []int{338} } func (m *ScheduledAgentUpgradeWindow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19706,7 +19827,7 @@ func (m *AgentUpgradeSchedule) Reset() { *m = AgentUpgradeSchedule{} } func (m *AgentUpgradeSchedule) String() string { return proto.CompactTextString(m) } func (*AgentUpgradeSchedule) ProtoMessage() {} func (*AgentUpgradeSchedule) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{337} + return fileDescriptor_9198ee693835762e, []int{339} } func (m *AgentUpgradeSchedule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19749,7 +19870,7 @@ type UserGroupV1 struct { func (m *UserGroupV1) Reset() { *m = UserGroupV1{} } func (*UserGroupV1) ProtoMessage() {} func (*UserGroupV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{338} + return fileDescriptor_9198ee693835762e, []int{340} } func (m *UserGroupV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19791,7 +19912,7 @@ func (m *UserGroupSpecV1) Reset() { *m = UserGroupSpecV1{} } func (m *UserGroupSpecV1) String() string { return proto.CompactTextString(m) } func (*UserGroupSpecV1) ProtoMessage() {} func (*UserGroupSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{339} + return fileDescriptor_9198ee693835762e, []int{341} } func (m *UserGroupSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19835,7 +19956,7 @@ func (m *OktaImportRuleSpecV1) Reset() { *m = OktaImportRuleSpecV1{} } func (m *OktaImportRuleSpecV1) String() string { return proto.CompactTextString(m) } func (*OktaImportRuleSpecV1) ProtoMessage() {} func (*OktaImportRuleSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{340} + return fileDescriptor_9198ee693835762e, []int{342} } func (m *OktaImportRuleSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19879,7 +20000,7 @@ func (m *OktaImportRuleMappingV1) Reset() { *m = OktaImportRuleMappingV1 func (m *OktaImportRuleMappingV1) String() string { return proto.CompactTextString(m) } func (*OktaImportRuleMappingV1) ProtoMessage() {} func (*OktaImportRuleMappingV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{341} + return fileDescriptor_9198ee693835762e, []int{343} } func (m *OktaImportRuleMappingV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19922,7 +20043,7 @@ type OktaImportRuleV1 struct { func (m *OktaImportRuleV1) Reset() { *m = OktaImportRuleV1{} } func (*OktaImportRuleV1) ProtoMessage() {} func (*OktaImportRuleV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{342} + return fileDescriptor_9198ee693835762e, []int{344} } func (m *OktaImportRuleV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -19970,7 +20091,7 @@ func (m *OktaImportRuleMatchV1) Reset() { *m = OktaImportRuleMatchV1{} } func (m *OktaImportRuleMatchV1) String() string { return proto.CompactTextString(m) } func (*OktaImportRuleMatchV1) ProtoMessage() {} func (*OktaImportRuleMatchV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{343} + return fileDescriptor_9198ee693835762e, []int{345} } func (m *OktaImportRuleMatchV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20013,7 +20134,7 @@ type OktaAssignmentV1 struct { func (m *OktaAssignmentV1) Reset() { *m = OktaAssignmentV1{} } func (*OktaAssignmentV1) ProtoMessage() {} func (*OktaAssignmentV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{344} + return fileDescriptor_9198ee693835762e, []int{346} } func (m *OktaAssignmentV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20067,7 +20188,7 @@ func (m *OktaAssignmentSpecV1) Reset() { *m = OktaAssignmentSpecV1{} } func (m *OktaAssignmentSpecV1) String() string { return proto.CompactTextString(m) } func (*OktaAssignmentSpecV1) ProtoMessage() {} func (*OktaAssignmentSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{345} + return fileDescriptor_9198ee693835762e, []int{347} } func (m *OktaAssignmentSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20111,7 +20232,7 @@ func (m *OktaAssignmentTargetV1) Reset() { *m = OktaAssignmentTargetV1{} func (m *OktaAssignmentTargetV1) String() string { return proto.CompactTextString(m) } func (*OktaAssignmentTargetV1) ProtoMessage() {} func (*OktaAssignmentTargetV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{346} + return fileDescriptor_9198ee693835762e, []int{348} } func (m *OktaAssignmentTargetV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20156,7 +20277,7 @@ type IntegrationV1 struct { func (m *IntegrationV1) Reset() { *m = IntegrationV1{} } func (*IntegrationV1) ProtoMessage() {} func (*IntegrationV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{347} + return fileDescriptor_9198ee693835762e, []int{349} } func (m *IntegrationV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20204,7 +20325,7 @@ func (m *IntegrationSpecV1) Reset() { *m = IntegrationSpecV1{} } func (m *IntegrationSpecV1) String() string { return proto.CompactTextString(m) } func (*IntegrationSpecV1) ProtoMessage() {} func (*IntegrationSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{348} + return fileDescriptor_9198ee693835762e, []int{350} } func (m *IntegrationSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20323,7 +20444,7 @@ func (m *AWSOIDCIntegrationSpecV1) Reset() { *m = AWSOIDCIntegrationSpec func (m *AWSOIDCIntegrationSpecV1) String() string { return proto.CompactTextString(m) } func (*AWSOIDCIntegrationSpecV1) ProtoMessage() {} func (*AWSOIDCIntegrationSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{349} + return fileDescriptor_9198ee693835762e, []int{351} } func (m *AWSOIDCIntegrationSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20369,7 +20490,7 @@ func (m *AzureOIDCIntegrationSpecV1) Reset() { *m = AzureOIDCIntegration func (m *AzureOIDCIntegrationSpecV1) String() string { return proto.CompactTextString(m) } func (*AzureOIDCIntegrationSpecV1) ProtoMessage() {} func (*AzureOIDCIntegrationSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{350} + return fileDescriptor_9198ee693835762e, []int{352} } func (m *AzureOIDCIntegrationSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20411,7 +20532,7 @@ func (m *GitHubIntegrationSpecV1) Reset() { *m = GitHubIntegrationSpecV1 func (m *GitHubIntegrationSpecV1) String() string { return proto.CompactTextString(m) } func (*GitHubIntegrationSpecV1) ProtoMessage() {} func (*GitHubIntegrationSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{351} + return fileDescriptor_9198ee693835762e, []int{353} } func (m *GitHubIntegrationSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20472,7 +20593,7 @@ func (m *HeadlessAuthentication) Reset() { *m = HeadlessAuthentication{} func (m *HeadlessAuthentication) String() string { return proto.CompactTextString(m) } func (*HeadlessAuthentication) ProtoMessage() {} func (*HeadlessAuthentication) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{352} + return fileDescriptor_9198ee693835762e, []int{354} } func (m *HeadlessAuthentication) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20529,7 +20650,7 @@ func (m *WatchKind) Reset() { *m = WatchKind{} } func (m *WatchKind) String() string { return proto.CompactTextString(m) } func (*WatchKind) ProtoMessage() {} func (*WatchKind) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{353} + return fileDescriptor_9198ee693835762e, []int{355} } func (m *WatchKind) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20579,7 +20700,7 @@ func (m *WatchStatusV1) Reset() { *m = WatchStatusV1{} } func (m *WatchStatusV1) String() string { return proto.CompactTextString(m) } func (*WatchStatusV1) ProtoMessage() {} func (*WatchStatusV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{354} + return fileDescriptor_9198ee693835762e, []int{356} } func (m *WatchStatusV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20620,7 +20741,7 @@ func (m *WatchStatusSpecV1) Reset() { *m = WatchStatusSpecV1{} } func (m *WatchStatusSpecV1) String() string { return proto.CompactTextString(m) } func (*WatchStatusSpecV1) ProtoMessage() {} func (*WatchStatusSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{355} + return fileDescriptor_9198ee693835762e, []int{357} } func (m *WatchStatusSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20670,7 +20791,7 @@ func (m *ServerInfoV1) Reset() { *m = ServerInfoV1{} } func (m *ServerInfoV1) String() string { return proto.CompactTextString(m) } func (*ServerInfoV1) ProtoMessage() {} func (*ServerInfoV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{356} + return fileDescriptor_9198ee693835762e, []int{358} } func (m *ServerInfoV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20712,7 +20833,7 @@ func (m *ServerInfoSpecV1) Reset() { *m = ServerInfoSpecV1{} } func (m *ServerInfoSpecV1) String() string { return proto.CompactTextString(m) } func (*ServerInfoSpecV1) ProtoMessage() {} func (*ServerInfoSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{357} + return fileDescriptor_9198ee693835762e, []int{359} } func (m *ServerInfoSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20769,7 +20890,7 @@ func (m *JamfSpecV1) Reset() { *m = JamfSpecV1{} } func (m *JamfSpecV1) String() string { return proto.CompactTextString(m) } func (*JamfSpecV1) ProtoMessage() {} func (*JamfSpecV1) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{358} + return fileDescriptor_9198ee693835762e, []int{360} } func (m *JamfSpecV1) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20834,7 +20955,7 @@ func (m *JamfInventoryEntry) Reset() { *m = JamfInventoryEntry{} } func (m *JamfInventoryEntry) String() string { return proto.CompactTextString(m) } func (*JamfInventoryEntry) ProtoMessage() {} func (*JamfInventoryEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{359} + return fileDescriptor_9198ee693835762e, []int{361} } func (m *JamfInventoryEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20891,7 +21012,7 @@ type MessageWithHeader struct { func (m *MessageWithHeader) Reset() { *m = MessageWithHeader{} } func (*MessageWithHeader) ProtoMessage() {} func (*MessageWithHeader) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{360} + return fileDescriptor_9198ee693835762e, []int{362} } func (m *MessageWithHeader) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -20955,7 +21076,7 @@ func (m *AWSMatcher) Reset() { *m = AWSMatcher{} } func (m *AWSMatcher) String() string { return proto.CompactTextString(m) } func (*AWSMatcher) ProtoMessage() {} func (*AWSMatcher) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{361} + return fileDescriptor_9198ee693835762e, []int{363} } func (m *AWSMatcher) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21000,7 +21121,7 @@ func (m *AssumeRole) Reset() { *m = AssumeRole{} } func (m *AssumeRole) String() string { return proto.CompactTextString(m) } func (*AssumeRole) ProtoMessage() {} func (*AssumeRole) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{362} + return fileDescriptor_9198ee693835762e, []int{364} } func (m *AssumeRole) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21062,7 +21183,7 @@ func (m *InstallerParams) Reset() { *m = InstallerParams{} } func (m *InstallerParams) String() string { return proto.CompactTextString(m) } func (*InstallerParams) ProtoMessage() {} func (*InstallerParams) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{363} + return fileDescriptor_9198ee693835762e, []int{365} } func (m *InstallerParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21105,7 +21226,7 @@ func (m *AWSSSM) Reset() { *m = AWSSSM{} } func (m *AWSSSM) String() string { return proto.CompactTextString(m) } func (*AWSSSM) ProtoMessage() {} func (*AWSSSM) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{364} + return fileDescriptor_9198ee693835762e, []int{366} } func (m *AWSSSM) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21148,7 +21269,7 @@ func (m *AzureInstallerParams) Reset() { *m = AzureInstallerParams{} } func (m *AzureInstallerParams) String() string { return proto.CompactTextString(m) } func (*AzureInstallerParams) ProtoMessage() {} func (*AzureInstallerParams) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{365} + return fileDescriptor_9198ee693835762e, []int{367} } func (m *AzureInstallerParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21202,7 +21323,7 @@ func (m *AzureMatcher) Reset() { *m = AzureMatcher{} } func (m *AzureMatcher) String() string { return proto.CompactTextString(m) } func (*AzureMatcher) ProtoMessage() {} func (*AzureMatcher) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{366} + return fileDescriptor_9198ee693835762e, []int{368} } func (m *AzureMatcher) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21257,7 +21378,7 @@ func (m *GCPMatcher) Reset() { *m = GCPMatcher{} } func (m *GCPMatcher) String() string { return proto.CompactTextString(m) } func (*GCPMatcher) ProtoMessage() {} func (*GCPMatcher) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{367} + return fileDescriptor_9198ee693835762e, []int{369} } func (m *GCPMatcher) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21303,7 +21424,7 @@ func (m *KubernetesMatcher) Reset() { *m = KubernetesMatcher{} } func (m *KubernetesMatcher) String() string { return proto.CompactTextString(m) } func (*KubernetesMatcher) ProtoMessage() {} func (*KubernetesMatcher) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{368} + return fileDescriptor_9198ee693835762e, []int{370} } func (m *KubernetesMatcher) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21345,7 +21466,7 @@ func (m *OktaOptions) Reset() { *m = OktaOptions{} } func (m *OktaOptions) String() string { return proto.CompactTextString(m) } func (*OktaOptions) ProtoMessage() {} func (*OktaOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{369} + return fileDescriptor_9198ee693835762e, []int{371} } func (m *OktaOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21391,7 +21512,7 @@ func (m *AccessGraphSync) Reset() { *m = AccessGraphSync{} } func (m *AccessGraphSync) String() string { return proto.CompactTextString(m) } func (*AccessGraphSync) ProtoMessage() {} func (*AccessGraphSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{370} + return fileDescriptor_9198ee693835762e, []int{372} } func (m *AccessGraphSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21437,7 +21558,7 @@ func (m *AccessGraphAWSSync) Reset() { *m = AccessGraphAWSSync{} } func (m *AccessGraphAWSSync) String() string { return proto.CompactTextString(m) } func (*AccessGraphAWSSync) ProtoMessage() {} func (*AccessGraphAWSSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{371} + return fileDescriptor_9198ee693835762e, []int{373} } func (m *AccessGraphAWSSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21481,7 +21602,7 @@ func (m *AccessGraphAzureSync) Reset() { *m = AccessGraphAzureSync{} } func (m *AccessGraphAzureSync) String() string { return proto.CompactTextString(m) } func (*AccessGraphAzureSync) ProtoMessage() {} func (*AccessGraphAzureSync) Descriptor() ([]byte, []int) { - return fileDescriptor_9198ee693835762e, []int{372} + return fileDescriptor_9198ee693835762e, []int{374} } func (m *AccessGraphAzureSync) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -21875,10 +21996,12 @@ func init() { proto.RegisterType((*MailgunSpec)(nil), "types.MailgunSpec") proto.RegisterType((*SMTPSpec)(nil), "types.SMTPSpec") proto.RegisterType((*PluginMSTeamsSettings)(nil), "types.PluginMSTeamsSettings") + proto.RegisterType((*PluginNetIQSettings)(nil), "types.PluginNetIQSettings") proto.RegisterType((*PluginBootstrapCredentialsV1)(nil), "types.PluginBootstrapCredentialsV1") proto.RegisterType((*PluginIdSecretCredential)(nil), "types.PluginIdSecretCredential") proto.RegisterType((*PluginOAuth2AuthorizationCodeCredentials)(nil), "types.PluginOAuth2AuthorizationCodeCredentials") proto.RegisterType((*PluginStatusV1)(nil), "types.PluginStatusV1") + proto.RegisterType((*PluginNetIQStatusV1)(nil), "types.PluginNetIQStatusV1") proto.RegisterType((*PluginGitlabStatusV1)(nil), "types.PluginGitlabStatusV1") proto.RegisterType((*PluginEntraIDStatusV1)(nil), "types.PluginEntraIDStatusV1") proto.RegisterType((*PluginOktaStatusV1)(nil), "types.PluginOktaStatusV1") @@ -21953,1909 +22076,1916 @@ func init() { func init() { proto.RegisterFile("teleport/legacy/types/types.proto", fileDescriptor_9198ee693835762e) } var fileDescriptor_9198ee693835762e = []byte{ - // 30421 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6d, 0x70, 0x1c, 0x49, - 0x76, 0x20, 0x36, 0xdd, 0x8d, 0x8f, 0xc6, 0xc3, 0x57, 0x23, 0x01, 0x92, 0x20, 0x66, 0x86, 0xcd, - 0xa9, 0x99, 0xe1, 0x90, 0xb3, 0x33, 0xe4, 0x12, 0xdc, 0xe1, 0xee, 0xec, 0x7c, 0x6d, 0xa3, 0x1b, - 0x24, 0x9a, 0x04, 0x40, 0x6c, 0x35, 0x40, 0xec, 0x68, 0x3f, 0x6a, 0x0b, 0xdd, 0x09, 0xa0, 0x06, - 0xdd, 0x5d, 0xbd, 0x55, 0xd5, 0x04, 0xa1, 0x3d, 0xf9, 0xee, 0xf4, 0x71, 0xb2, 0x42, 0xd6, 0xe7, - 0x49, 0xa7, 0x3d, 0x87, 0x4e, 0x56, 0xc8, 0x77, 0x3e, 0xc5, 0x39, 0xa4, 0x38, 0x4b, 0x96, 0x7d, - 0xf6, 0x85, 0x65, 0xe9, 0xe2, 0x2c, 0xcb, 0x8a, 0x8b, 0x93, 0xc2, 0x3e, 0xdb, 0xe1, 0xf5, 0x05, - 0x64, 0x59, 0xfe, 0xe1, 0x40, 0x84, 0x23, 0x24, 0x5f, 0x84, 0x23, 0xbc, 0x0e, 0xdd, 0x39, 0xf2, - 0x65, 0x66, 0x55, 0x66, 0x55, 0x75, 0xa3, 0x31, 0xe4, 0xe8, 0xc4, 0x0d, 0xfd, 0x21, 0xd1, 0x2f, - 0xdf, 0x7b, 0x59, 0xf9, 0xfd, 0xf2, 0xe5, 0xfb, 0x80, 0x97, 0x02, 0xda, 0xa4, 0x1d, 0xd7, 0x0b, - 0x6e, 0x34, 0xe9, 0x9e, 0x5d, 0x3f, 0xba, 0x11, 0x1c, 0x75, 0xa8, 0xcf, 0xff, 0xbd, 0xde, 0xf1, - 0xdc, 0xc0, 0x25, 0xc3, 0xf8, 0x63, 0x61, 0x6e, 0xcf, 0xdd, 0x73, 0x11, 0x72, 0x83, 0xfd, 0xc5, - 0x0b, 0x17, 0x2e, 0xed, 0xb9, 0xee, 0x5e, 0x93, 0xde, 0xc0, 0x5f, 0x3b, 0xdd, 0xdd, 0x1b, 0x8d, - 0xae, 0x67, 0x07, 0x8e, 0xdb, 0x16, 0xe5, 0xc5, 0x78, 0x79, 0xe0, 0xb4, 0xa8, 0x1f, 0xd8, 0xad, - 0x4e, 0x2f, 0x06, 0x87, 0x9e, 0xdd, 0xe9, 0x50, 0x4f, 0xd4, 0xbe, 0x70, 0x2d, 0xfc, 0x40, 0x3b, - 0x08, 0x18, 0x25, 0x63, 0x7e, 0xe3, 0xd1, 0x4d, 0xf5, 0xa7, 0x40, 0xbd, 0xdd, 0xa3, 0x2d, 0x5e, - 0xd7, 0x0f, 0x68, 0xc3, 0x6a, 0xd0, 0x47, 0x4e, 0x9d, 0x5a, 0x1e, 0xfd, 0x46, 0xd7, 0xf1, 0x68, - 0x8b, 0xb6, 0x03, 0x41, 0xf7, 0x66, 0x3a, 0x9d, 0xfc, 0x90, 0xd8, 0x17, 0x19, 0xbf, 0x90, 0x83, - 0xb1, 0xfb, 0x94, 0x76, 0x4a, 0x4d, 0xe7, 0x11, 0x25, 0x2f, 0xc3, 0xd0, 0xba, 0xdd, 0xa2, 0xf3, - 0x99, 0xcb, 0x99, 0xab, 0x63, 0x4b, 0xd3, 0x27, 0xc7, 0xc5, 0x71, 0x9f, 0x7a, 0x8f, 0xa8, 0x67, - 0xb5, 0xed, 0x16, 0x35, 0xb1, 0x90, 0x7c, 0x0a, 0xc6, 0xd8, 0xff, 0x7e, 0xc7, 0xae, 0xd3, 0xf9, - 0x2c, 0x62, 0x4e, 0x9e, 0x1c, 0x17, 0xc7, 0xda, 0x12, 0x68, 0x46, 0xe5, 0xa4, 0x0a, 0xa3, 0xcb, - 0x8f, 0x3b, 0x8e, 0x47, 0xfd, 0xf9, 0xa1, 0xcb, 0x99, 0xab, 0xe3, 0x8b, 0x0b, 0xd7, 0x79, 0x1f, - 0x5d, 0x97, 0x7d, 0x74, 0x7d, 0x53, 0x76, 0xe2, 0xd2, 0xec, 0xef, 0x1e, 0x17, 0x9f, 0x3b, 0x39, - 0x2e, 0x8e, 0x52, 0x4e, 0xf2, 0x93, 0x7f, 0x58, 0xcc, 0x98, 0x92, 0x9e, 0xbc, 0x0b, 0x43, 0x9b, - 0x47, 0x1d, 0x3a, 0x3f, 0x76, 0x39, 0x73, 0x75, 0x6a, 0xf1, 0xd2, 0x75, 0x3e, 0xac, 0xe1, 0xc7, - 0x47, 0x7f, 0x31, 0xac, 0xa5, 0xfc, 0xc9, 0x71, 0x71, 0x88, 0xa1, 0x98, 0x48, 0x45, 0xde, 0x84, - 0x91, 0x15, 0xd7, 0x0f, 0xaa, 0x95, 0x79, 0xc0, 0x4f, 0x3e, 0x77, 0x72, 0x5c, 0x9c, 0xd9, 0x77, - 0xfd, 0xc0, 0x72, 0x1a, 0x6f, 0xb8, 0x2d, 0x27, 0xa0, 0xad, 0x4e, 0x70, 0x64, 0x0a, 0x24, 0xe3, - 0x31, 0x4c, 0x6a, 0xfc, 0xc8, 0x38, 0x8c, 0x6e, 0xad, 0xdf, 0x5f, 0x7f, 0xb0, 0xbd, 0x5e, 0x78, - 0x8e, 0xe4, 0x61, 0x68, 0xfd, 0x41, 0x65, 0xb9, 0x90, 0x21, 0xa3, 0x90, 0x2b, 0x6d, 0x6c, 0x14, - 0xb2, 0x64, 0x02, 0xf2, 0x95, 0xd2, 0x66, 0x69, 0xa9, 0x54, 0x5b, 0x2e, 0xe4, 0xc8, 0x2c, 0x4c, - 0x6f, 0x57, 0xd7, 0x2b, 0x0f, 0xb6, 0x6b, 0x56, 0x65, 0xb9, 0x76, 0x7f, 0xf3, 0xc1, 0x46, 0x61, - 0x88, 0x4c, 0x01, 0xdc, 0xdf, 0x5a, 0x5a, 0x36, 0xd7, 0x97, 0x37, 0x97, 0x6b, 0x85, 0x61, 0x32, - 0x07, 0x05, 0x49, 0x62, 0xd5, 0x96, 0xcd, 0x87, 0xd5, 0xf2, 0x72, 0x61, 0xe4, 0xde, 0x50, 0x3e, - 0x57, 0x18, 0x32, 0x47, 0x57, 0xa9, 0xed, 0xd3, 0x6a, 0xc5, 0xf8, 0x0f, 0x73, 0x90, 0x5f, 0xa3, - 0x81, 0xdd, 0xb0, 0x03, 0x9b, 0xbc, 0xa0, 0x8d, 0x0f, 0x36, 0x51, 0x19, 0x98, 0x97, 0x93, 0x03, - 0x33, 0x7c, 0x72, 0x5c, 0xcc, 0xbc, 0xa9, 0x0e, 0xc8, 0x3b, 0x30, 0x5e, 0xa1, 0x7e, 0xdd, 0x73, - 0x3a, 0x6c, 0xb2, 0xcd, 0xe7, 0x10, 0xed, 0xe2, 0xc9, 0x71, 0xf1, 0x5c, 0x23, 0x02, 0x2b, 0x1d, - 0xa2, 0x62, 0x93, 0x2a, 0x8c, 0xac, 0xda, 0x3b, 0xb4, 0xe9, 0xcf, 0x0f, 0x5f, 0xce, 0x5d, 0x1d, - 0x5f, 0x7c, 0x5e, 0x0c, 0x82, 0xfc, 0xc0, 0xeb, 0xbc, 0x74, 0xb9, 0x1d, 0x78, 0x47, 0x4b, 0x73, - 0x27, 0xc7, 0xc5, 0x42, 0x13, 0x01, 0x6a, 0x07, 0x73, 0x14, 0x52, 0x8b, 0x26, 0xc6, 0xc8, 0xa9, - 0x13, 0xe3, 0xc5, 0xdf, 0x3d, 0x2e, 0x66, 0xd8, 0x80, 0x89, 0x89, 0x11, 0xf1, 0xd3, 0xa7, 0xc8, - 0x22, 0xe4, 0x4d, 0xfa, 0xc8, 0xf1, 0x59, 0xcb, 0xf2, 0xd8, 0xb2, 0xf3, 0x27, 0xc7, 0x45, 0xe2, - 0x09, 0x98, 0xf2, 0x19, 0x21, 0xde, 0xc2, 0xdb, 0x30, 0xae, 0x7c, 0x35, 0x29, 0x40, 0xee, 0x80, - 0x1e, 0xf1, 0x1e, 0x36, 0xd9, 0x9f, 0x64, 0x0e, 0x86, 0x1f, 0xd9, 0xcd, 0xae, 0xe8, 0x52, 0x93, - 0xff, 0xf8, 0x7c, 0xf6, 0x73, 0x99, 0x7b, 0x43, 0xf9, 0xd1, 0x42, 0xde, 0xcc, 0x56, 0x2b, 0xc6, - 0x4f, 0x0f, 0x41, 0xde, 0x74, 0xf9, 0x02, 0x26, 0xd7, 0x60, 0xb8, 0x16, 0xd8, 0x81, 0x1c, 0xa6, - 0xd9, 0x93, 0xe3, 0xe2, 0x34, 0x5b, 0xdc, 0x54, 0xa9, 0x9f, 0x63, 0x30, 0xd4, 0x8d, 0x7d, 0xdb, - 0x97, 0xc3, 0x85, 0xa8, 0x1d, 0x06, 0x50, 0x51, 0x11, 0x83, 0x5c, 0x81, 0xa1, 0x35, 0xb7, 0x41, - 0xc5, 0x88, 0x91, 0x93, 0xe3, 0xe2, 0x54, 0xcb, 0x6d, 0xa8, 0x88, 0x58, 0x4e, 0xde, 0x80, 0xb1, - 0x72, 0xd7, 0xf3, 0x68, 0x9b, 0xcd, 0xf5, 0x21, 0x44, 0x9e, 0x3a, 0x39, 0x2e, 0x42, 0x9d, 0x03, - 0x2d, 0xa7, 0x61, 0x46, 0x08, 0x6c, 0x18, 0x6a, 0x81, 0xed, 0x05, 0xb4, 0x31, 0x3f, 0x3c, 0xd0, - 0x30, 0xb0, 0xf5, 0x39, 0xe3, 0x73, 0x92, 0xf8, 0x30, 0x08, 0x4e, 0x64, 0x05, 0xc6, 0xef, 0x7a, - 0x76, 0x9d, 0x6e, 0x50, 0xcf, 0x71, 0x1b, 0x38, 0xbe, 0xb9, 0xa5, 0x2b, 0x27, 0xc7, 0xc5, 0xf3, - 0x7b, 0x0c, 0x6c, 0x75, 0x10, 0x1e, 0x51, 0x7f, 0xe7, 0xb8, 0x98, 0xaf, 0x88, 0xad, 0xd6, 0x54, - 0x49, 0xc9, 0xd7, 0xd9, 0xe0, 0xf8, 0x01, 0x76, 0x2d, 0x6d, 0xcc, 0x8f, 0x9e, 0xfa, 0x89, 0x86, - 0xf8, 0xc4, 0xf3, 0x4d, 0xdb, 0x0f, 0x2c, 0x8f, 0xd3, 0xc5, 0xbe, 0x53, 0x65, 0x49, 0x1e, 0x40, - 0xbe, 0x56, 0xdf, 0xa7, 0x8d, 0x6e, 0x93, 0xe2, 0x94, 0x19, 0x5f, 0xbc, 0x20, 0x26, 0xb5, 0x1c, - 0x4f, 0x59, 0xbc, 0xb4, 0x20, 0x78, 0x13, 0x5f, 0x40, 0xd4, 0xf9, 0x24, 0xb1, 0x3e, 0x9f, 0xff, - 0xd6, 0x2f, 0x16, 0x9f, 0xfb, 0x6b, 0xff, 0xf2, 0xf2, 0x73, 0xc6, 0x7f, 0x9e, 0x85, 0x42, 0x9c, - 0x09, 0xd9, 0x85, 0xc9, 0xad, 0x4e, 0xc3, 0x0e, 0x68, 0xb9, 0xe9, 0xd0, 0x76, 0xe0, 0xe3, 0x24, - 0xe9, 0xdf, 0xa6, 0x57, 0x44, 0xbd, 0xf3, 0x5d, 0x24, 0xb4, 0xea, 0x9c, 0x32, 0xd6, 0x2a, 0x9d, - 0x6d, 0x54, 0x4f, 0x0d, 0x37, 0x70, 0x1f, 0x67, 0xd8, 0xd9, 0xea, 0xe1, 0x5b, 0x7f, 0x8f, 0x7a, - 0x04, 0x5b, 0x31, 0x81, 0xda, 0x8d, 0x9d, 0x23, 0x9c, 0x99, 0x83, 0x4f, 0x20, 0x46, 0x92, 0x32, - 0x81, 0x18, 0xd8, 0xf8, 0x3f, 0x32, 0x30, 0x65, 0x52, 0xdf, 0xed, 0x7a, 0x75, 0xba, 0x42, 0xed, - 0x06, 0xf5, 0xd8, 0xf4, 0xbf, 0xef, 0xb4, 0x1b, 0x62, 0x4d, 0xe1, 0xf4, 0x3f, 0x70, 0xda, 0xea, - 0xd6, 0x8d, 0xe5, 0xe4, 0xd3, 0x30, 0x5a, 0xeb, 0xee, 0x20, 0x6a, 0x36, 0xda, 0x01, 0xfc, 0xee, - 0x8e, 0x15, 0x43, 0x97, 0x68, 0xe4, 0x06, 0x8c, 0x3e, 0xa4, 0x9e, 0x1f, 0xed, 0x86, 0x78, 0x34, - 0x3c, 0xe2, 0x20, 0x95, 0x40, 0x60, 0x91, 0xbb, 0xd1, 0x8e, 0x2c, 0x0e, 0xb5, 0xe9, 0xd8, 0x3e, - 0x18, 0x4d, 0x95, 0x96, 0x80, 0xa8, 0x53, 0x45, 0x62, 0x19, 0x3f, 0x95, 0x85, 0x42, 0xc5, 0x0e, - 0xec, 0x1d, 0xdb, 0x17, 0xfd, 0xf9, 0xf0, 0x16, 0xdb, 0xe3, 0x95, 0x86, 0xe2, 0x1e, 0xcf, 0xbe, - 0xfc, 0x63, 0x37, 0xef, 0xd5, 0x78, 0xf3, 0xc6, 0xd9, 0x09, 0x2b, 0x9a, 0x17, 0x35, 0xea, 0xbd, - 0xd3, 0x1b, 0x55, 0x10, 0x8d, 0xca, 0xcb, 0x46, 0x45, 0x4d, 0x21, 0xef, 0xc1, 0x50, 0xad, 0x43, - 0xeb, 0x62, 0x13, 0x91, 0xe7, 0x82, 0xde, 0x38, 0x86, 0xf0, 0xf0, 0xd6, 0xd2, 0x84, 0x60, 0x33, - 0xe4, 0x77, 0x68, 0xdd, 0x44, 0x32, 0x65, 0xd1, 0xfc, 0xa3, 0x1c, 0xcc, 0xa5, 0x91, 0xa9, 0xed, - 0x18, 0xe9, 0xd3, 0x8e, 0xab, 0x90, 0x67, 0x47, 0x38, 0x3b, 0x16, 0x71, 0xbb, 0x18, 0x5b, 0x9a, - 0x60, 0x9f, 0xbc, 0x2f, 0x60, 0x66, 0x58, 0x4a, 0x5e, 0x0e, 0x25, 0x82, 0x7c, 0xc4, 0x4f, 0x48, - 0x04, 0x52, 0x0e, 0x60, 0x63, 0x2d, 0x97, 0x30, 0x0a, 0x0e, 0x51, 0xb7, 0x48, 0x70, 0x34, 0xd6, - 0x9e, 0x80, 0x68, 0xc7, 0x8c, 0x3c, 0x14, 0x96, 0x21, 0x2f, 0x9b, 0x35, 0x3f, 0x81, 0x8c, 0x66, - 0x62, 0x9d, 0xf4, 0xf0, 0x16, 0x1f, 0xcc, 0x86, 0xf8, 0xad, 0xb2, 0x91, 0x38, 0xe4, 0x16, 0xe4, - 0x37, 0x3c, 0xf7, 0xf1, 0x51, 0xb5, 0xe2, 0xcf, 0x4f, 0x5e, 0xce, 0x5d, 0x1d, 0x5b, 0xba, 0x70, - 0x72, 0x5c, 0x9c, 0xed, 0x30, 0x98, 0xe5, 0x34, 0xd4, 0x93, 0x36, 0x44, 0xbc, 0x37, 0x94, 0xcf, - 0x14, 0xb2, 0xf7, 0x86, 0xf2, 0xd9, 0x42, 0x8e, 0x8b, 0x17, 0xf7, 0x86, 0xf2, 0x43, 0x85, 0xe1, - 0x7b, 0x43, 0xf9, 0x61, 0x14, 0x38, 0xc6, 0x0a, 0x70, 0x6f, 0x28, 0x3f, 0x5e, 0x98, 0xd0, 0x4e, - 0x7b, 0x64, 0x10, 0xb8, 0x75, 0xb7, 0x69, 0xe6, 0xb6, 0xcc, 0xaa, 0x39, 0x52, 0x2e, 0x95, 0xa9, - 0x17, 0x98, 0xb9, 0xd2, 0x76, 0xcd, 0x9c, 0xac, 0x1c, 0xb5, 0xed, 0x96, 0x53, 0xe7, 0x47, 0xa7, - 0x99, 0xbb, 0x5b, 0xde, 0x30, 0x4a, 0x30, 0x15, 0xb5, 0x65, 0xd5, 0xf1, 0x03, 0x72, 0x03, 0xc6, - 0x24, 0x84, 0x6d, 0x74, 0xb9, 0xd4, 0x56, 0x9b, 0x11, 0x8e, 0xf1, 0x3b, 0x59, 0x80, 0xa8, 0xe4, - 0x19, 0x5d, 0x0b, 0x9f, 0xd5, 0xd6, 0xc2, 0xb9, 0xf8, 0x5a, 0xe8, 0xb9, 0x0a, 0xc8, 0x07, 0x30, - 0xc2, 0xc4, 0x82, 0xae, 0x14, 0x89, 0x2e, 0xc4, 0x49, 0xb1, 0xf0, 0xe1, 0xad, 0xa5, 0x29, 0x41, - 0x3c, 0xe2, 0x23, 0xc4, 0x14, 0x64, 0xca, 0x32, 0xfa, 0x85, 0xd1, 0x68, 0x30, 0xc4, 0x02, 0xba, - 0x0a, 0xe1, 0x80, 0x8a, 0x0e, 0xc5, 0x95, 0xd1, 0x91, 0x83, 0x1c, 0x96, 0x92, 0x8b, 0xc0, 0x06, - 0x5c, 0x74, 0xea, 0xe8, 0xc9, 0x71, 0x31, 0xd7, 0xf5, 0x1c, 0x9c, 0x04, 0xe4, 0x06, 0x88, 0x69, - 0x20, 0x3a, 0x90, 0xcd, 0xbe, 0x99, 0xba, 0x6d, 0xd5, 0xa9, 0x17, 0x44, 0x3d, 0x3e, 0x9f, 0x91, - 0xb3, 0x85, 0x74, 0x40, 0x9f, 0x2a, 0xf3, 0x43, 0x38, 0x0d, 0xae, 0xa6, 0xf6, 0xca, 0x75, 0x0d, - 0x95, 0x8b, 0x91, 0x97, 0xe5, 0xa9, 0xd4, 0xe0, 0x65, 0x56, 0x42, 0xa4, 0xd4, 0x2b, 0x20, 0xb7, - 0x80, 0xcd, 0x50, 0xd1, 0xfb, 0x20, 0xea, 0x29, 0x6d, 0xd7, 0x96, 0xce, 0x09, 0x4e, 0x93, 0xf6, - 0xa1, 0x4a, 0xce, 0xb0, 0xc9, 0x3b, 0xc0, 0xa6, 0xb0, 0xe8, 0x77, 0x22, 0x88, 0xee, 0x96, 0x37, - 0xca, 0x4d, 0xb7, 0xdb, 0xa8, 0x7d, 0x71, 0x35, 0x22, 0xde, 0xab, 0x77, 0x54, 0xe2, 0xbb, 0xe5, - 0x0d, 0xf2, 0x0e, 0x0c, 0x97, 0xbe, 0xb7, 0xeb, 0x51, 0x21, 0x9f, 0x4c, 0xc8, 0x3a, 0x19, 0x6c, - 0xe9, 0x82, 0x20, 0x9c, 0xb6, 0xd9, 0x4f, 0x55, 0xae, 0xc3, 0x72, 0x56, 0xf3, 0xe6, 0x6a, 0x4d, - 0xc8, 0x1e, 0x24, 0xd6, 0x2d, 0x9b, 0xab, 0xca, 0x67, 0x07, 0x5a, 0xab, 0x19, 0x15, 0xb9, 0x01, - 0xd9, 0x52, 0x05, 0x6f, 0x44, 0xe3, 0x8b, 0x63, 0xb2, 0xda, 0xca, 0xd2, 0x9c, 0x20, 0x99, 0xb0, - 0xd5, 0x65, 0x90, 0x2d, 0x55, 0xc8, 0x12, 0x0c, 0xaf, 0x1d, 0xd5, 0xbe, 0xb8, 0x2a, 0x36, 0xb3, - 0x59, 0x39, 0xaf, 0x19, 0xec, 0x01, 0x2e, 0x7b, 0x3f, 0xfa, 0xe2, 0xd6, 0x91, 0xff, 0x8d, 0xa6, - 0xfa, 0xc5, 0x88, 0x46, 0x36, 0x60, 0xac, 0xd4, 0x68, 0x39, 0xed, 0x2d, 0x9f, 0x7a, 0xf3, 0xe3, - 0xc8, 0x67, 0x3e, 0xf6, 0xdd, 0x61, 0xf9, 0xd2, 0xfc, 0xc9, 0x71, 0x71, 0xce, 0x66, 0x3f, 0xad, - 0xae, 0x4f, 0x3d, 0x85, 0x5b, 0xc4, 0x84, 0x6c, 0x00, 0xac, 0xb9, 0xed, 0x3d, 0xb7, 0x14, 0x34, - 0x6d, 0x3f, 0xb6, 0x3d, 0x46, 0x05, 0xa1, 0xf8, 0x70, 0xae, 0xc5, 0x60, 0x96, 0xcd, 0x80, 0x0a, - 0x43, 0x85, 0x07, 0xb9, 0x03, 0x23, 0x0f, 0x3c, 0xbb, 0xde, 0xa4, 0xf3, 0x93, 0xc8, 0x6d, 0x4e, - 0x70, 0xe3, 0x40, 0xd9, 0xd2, 0x79, 0xc1, 0xb0, 0xe0, 0x22, 0x58, 0xbd, 0xa6, 0x70, 0xc4, 0x85, - 0x6d, 0x20, 0xc9, 0x39, 0x99, 0x72, 0x49, 0xf8, 0x94, 0x7a, 0x49, 0x88, 0x16, 0x7d, 0xd9, 0x6d, - 0xb5, 0xec, 0x76, 0x03, 0x69, 0x1f, 0x2e, 0x2a, 0x77, 0x07, 0xe3, 0x1b, 0x30, 0x93, 0xe8, 0xac, - 0x53, 0xee, 0x77, 0xef, 0xc3, 0x74, 0x85, 0xee, 0xda, 0xdd, 0x66, 0x10, 0x9e, 0x24, 0x7c, 0x89, - 0xe2, 0x4d, 0xab, 0xc1, 0x8b, 0x2c, 0x79, 0x7c, 0x98, 0x71, 0x64, 0xe3, 0x3d, 0x98, 0xd4, 0x9a, - 0xcf, 0xae, 0x0a, 0xa5, 0x6e, 0xc3, 0x09, 0x70, 0x20, 0x33, 0xd1, 0x55, 0xc1, 0x66, 0x40, 0x1c, - 0x2e, 0x33, 0x42, 0x30, 0xfe, 0xae, 0x2a, 0xad, 0x88, 0x9d, 0x88, 0x5d, 0xab, 0xc5, 0x7e, 0x90, - 0x89, 0x64, 0xa7, 0xc4, 0x7e, 0x10, 0xee, 0x06, 0xd7, 0xf8, 0xda, 0xcc, 0x26, 0xd6, 0xe6, 0xb8, - 0x18, 0x89, 0x9c, 0x7d, 0xe8, 0xf3, 0x15, 0x19, 0xce, 0xd4, 0xdc, 0xc7, 0x9f, 0xa9, 0x1f, 0xc0, - 0xc4, 0x9a, 0xdd, 0xb6, 0xf7, 0x68, 0x83, 0xb5, 0x80, 0xef, 0x3d, 0x63, 0x4b, 0xcf, 0x9f, 0x1c, - 0x17, 0x2f, 0xb4, 0x38, 0x1c, 0x5b, 0xa9, 0x4e, 0x22, 0x8d, 0x80, 0xdc, 0x94, 0x2b, 0x7b, 0x38, - 0x65, 0x65, 0x4f, 0x8a, 0xda, 0x87, 0x71, 0x65, 0x8b, 0xf5, 0x6c, 0xfc, 0xd6, 0x18, 0xb6, 0x91, - 0xbc, 0x01, 0x23, 0x26, 0xdd, 0x63, 0x47, 0x4d, 0x26, 0x1a, 0x24, 0x0f, 0x21, 0x6a, 0xc7, 0x70, - 0x1c, 0x94, 0x33, 0x68, 0xc3, 0xdf, 0x77, 0x76, 0x03, 0xd1, 0x3b, 0xa1, 0x9c, 0x21, 0xc0, 0x8a, - 0x9c, 0x21, 0x20, 0xfa, 0x75, 0x96, 0xc3, 0xd8, 0xee, 0x67, 0x56, 0x6a, 0xa2, 0xd3, 0x64, 0x0f, - 0x9b, 0x15, 0x65, 0x1b, 0xf1, 0x34, 0x29, 0x81, 0x61, 0x93, 0xdb, 0x30, 0x56, 0xaa, 0xd7, 0xdd, - 0xae, 0x72, 0x67, 0xe4, 0xeb, 0x96, 0x03, 0x75, 0x15, 0x49, 0x84, 0x4a, 0x6a, 0x30, 0xbe, 0xcc, - 0x2e, 0x5a, 0x4e, 0xd9, 0xae, 0xef, 0xcb, 0x4e, 0x92, 0x7b, 0x98, 0x52, 0x12, 0xad, 0x5c, 0x8a, - 0xc0, 0x3a, 0x03, 0xaa, 0x4a, 0x06, 0x05, 0x97, 0x6c, 0xc2, 0x78, 0x8d, 0xd6, 0x3d, 0x1a, 0xd4, - 0x02, 0xd7, 0xa3, 0xb1, 0x2d, 0x59, 0x29, 0x59, 0xba, 0x24, 0xef, 0x7a, 0x3e, 0x02, 0x2d, 0x9f, - 0x41, 0x55, 0xae, 0x0a, 0x32, 0x17, 0xda, 0x5b, 0xae, 0x77, 0x54, 0x59, 0x12, 0xdb, 0x74, 0x74, - 0xa6, 0x73, 0xb0, 0x2a, 0xb4, 0x33, 0x48, 0x63, 0x47, 0x17, 0xda, 0x39, 0x16, 0x8e, 0x54, 0xa5, - 0x86, 0xb2, 0x95, 0xd8, 0xb4, 0xa7, 0xa3, 0x5e, 0x46, 0xb0, 0x32, 0x52, 0x0d, 0x1f, 0x25, 0x33, - 0x6d, 0xa4, 0x04, 0x16, 0xe9, 0x00, 0x91, 0xa3, 0xc6, 0x05, 0xdd, 0x26, 0xf5, 0x7d, 0xb1, 0x97, - 0x5f, 0x8c, 0x0d, 0x7e, 0x84, 0xb0, 0xf4, 0xaa, 0x60, 0xfe, 0xa2, 0x9c, 0x06, 0xe2, 0x9e, 0xc6, - 0x0a, 0x95, 0x7a, 0x52, 0x78, 0x93, 0xb7, 0x01, 0x96, 0x1f, 0x07, 0xd4, 0x6b, 0xdb, 0xcd, 0x50, - 0x0f, 0x86, 0xaa, 0x1f, 0x2a, 0xa0, 0xfa, 0x40, 0x2b, 0xc8, 0xa4, 0x0c, 0x93, 0x25, 0xdf, 0xef, - 0xb6, 0xa8, 0xe9, 0x36, 0x69, 0xc9, 0x5c, 0xc7, 0x7d, 0x7f, 0x6c, 0xe9, 0xc5, 0x93, 0xe3, 0xe2, - 0x45, 0x1b, 0x0b, 0x2c, 0xcf, 0x6d, 0x52, 0xcb, 0xf6, 0xd4, 0xd9, 0xad, 0xd3, 0x90, 0x07, 0x00, - 0x0f, 0x3a, 0xb4, 0x5d, 0xa3, 0xb6, 0x57, 0xdf, 0x8f, 0x6d, 0xf3, 0x51, 0xc1, 0xd2, 0x0b, 0xa2, - 0x85, 0x73, 0x6e, 0x87, 0xb6, 0x7d, 0x84, 0xa9, 0x5f, 0x15, 0x61, 0x92, 0x6d, 0x98, 0xae, 0x96, - 0xd6, 0x36, 0xdc, 0xa6, 0x53, 0x3f, 0x12, 0x92, 0xd3, 0x14, 0x6a, 0x07, 0xcf, 0x0b, 0xae, 0xb1, - 0x52, 0xbe, 0x3d, 0x39, 0x76, 0xcb, 0xea, 0x20, 0xd4, 0x12, 0xf2, 0x53, 0x9c, 0x0b, 0xf9, 0x90, - 0xcd, 0x41, 0x9f, 0x09, 0x83, 0x9b, 0xf6, 0x9e, 0x3f, 0x3f, 0xad, 0x69, 0xbb, 0x4a, 0xdb, 0xb5, - 0xeb, 0x4a, 0x29, 0x17, 0x53, 0x16, 0xf8, 0x44, 0x44, 0xa8, 0x15, 0xd8, 0x7b, 0xbe, 0x3e, 0x11, - 0x43, 0x6c, 0x72, 0x0f, 0xa0, 0xe2, 0xd6, 0xbb, 0x2d, 0xda, 0x0e, 0x2a, 0x4b, 0xf3, 0x05, 0xfd, - 0x2a, 0x10, 0x16, 0x44, 0x5b, 0x5b, 0xc3, 0xad, 0x6b, 0x33, 0x51, 0xa1, 0x5e, 0x78, 0x1f, 0x0a, - 0xf1, 0x0f, 0x39, 0xa3, 0x02, 0x6b, 0xb2, 0x30, 0xa5, 0xb4, 0x7e, 0xf9, 0xb1, 0xe3, 0x07, 0xbe, - 0xf1, 0x4d, 0x6d, 0x05, 0xb2, 0xdd, 0xe1, 0x3e, 0x3d, 0xda, 0xf0, 0xe8, 0xae, 0xf3, 0x58, 0x6c, - 0x66, 0xb8, 0x3b, 0x1c, 0xd0, 0x23, 0xab, 0x83, 0x50, 0x75, 0x77, 0x08, 0x51, 0xc9, 0x67, 0x20, - 0x7f, 0x7f, 0xad, 0x76, 0x9f, 0x1e, 0x55, 0x2b, 0xe2, 0xa0, 0xe2, 0x64, 0x2d, 0xdf, 0x62, 0xa4, - 0xda, 0x5c, 0x0b, 0x31, 0x8d, 0xa5, 0x68, 0x27, 0x64, 0x35, 0x97, 0x9b, 0x5d, 0x3f, 0xa0, 0x5e, - 0xb5, 0xa2, 0xd6, 0x5c, 0xe7, 0xc0, 0xd8, 0xbe, 0x14, 0xa2, 0x1a, 0xff, 0x26, 0x8b, 0xbb, 0x20, - 0x9b, 0xf0, 0xd5, 0xb6, 0x1f, 0xd8, 0xed, 0x3a, 0x0d, 0x19, 0xe0, 0x84, 0x77, 0x04, 0x34, 0x36, - 0xe1, 0x23, 0x64, 0xbd, 0xea, 0xec, 0xc0, 0x55, 0xb3, 0x2a, 0xa5, 0xe6, 0xa2, 0x5a, 0x51, 0xd5, - 0xab, 0x9e, 0x80, 0xc6, 0xaa, 0x8c, 0x90, 0xc9, 0x15, 0x18, 0xad, 0x96, 0xd6, 0x4a, 0xdd, 0x60, - 0x1f, 0xf7, 0xe0, 0x3c, 0x97, 0xcf, 0xd9, 0x6c, 0xb5, 0xbb, 0xc1, 0xbe, 0x29, 0x0b, 0xc9, 0x0d, - 0xbc, 0xf7, 0xb4, 0x69, 0xc0, 0xd5, 0xb0, 0xe2, 0xd0, 0xf5, 0x39, 0x28, 0x76, 0xed, 0x61, 0x20, - 0xf2, 0x3a, 0x0c, 0x3f, 0xdc, 0x28, 0x57, 0x2b, 0xe2, 0xe2, 0x8c, 0x27, 0xd1, 0xa3, 0x4e, 0x5d, - 0xff, 0x12, 0x8e, 0x42, 0x96, 0x61, 0xaa, 0x46, 0xeb, 0x5d, 0xcf, 0x09, 0x8e, 0xee, 0x7a, 0x6e, - 0xb7, 0xe3, 0xcf, 0x8f, 0x62, 0x1d, 0xb8, 0xd2, 0x7d, 0x51, 0x62, 0xed, 0x61, 0x91, 0x42, 0x1d, - 0x23, 0x32, 0x7e, 0x3b, 0x13, 0x6d, 0x93, 0xe4, 0x8a, 0x26, 0xd6, 0xa0, 0xee, 0x86, 0x89, 0x35, - 0xaa, 0xee, 0x06, 0x05, 0x1c, 0x13, 0x48, 0xb9, 0xeb, 0x07, 0x6e, 0x6b, 0xb9, 0xdd, 0xe8, 0xb8, - 0x4e, 0x3b, 0x40, 0x2a, 0xde, 0xf9, 0xc6, 0xc9, 0x71, 0xf1, 0x52, 0x1d, 0x4b, 0x2d, 0x2a, 0x8a, - 0xad, 0x18, 0x97, 0x14, 0xea, 0x27, 0x18, 0x0f, 0xe3, 0xf7, 0xb2, 0xda, 0xf1, 0xc6, 0x3e, 0xcf, - 0xa4, 0x9d, 0xa6, 0x53, 0xc7, 0x1b, 0x3d, 0x36, 0x34, 0x9c, 0x55, 0xf8, 0x79, 0x5e, 0x54, 0xca, - 0x7b, 0x48, 0xe7, 0x9d, 0x42, 0x4d, 0xbe, 0x00, 0x13, 0x4c, 0xd2, 0x10, 0x3f, 0xfd, 0xf9, 0x2c, - 0x76, 0xf6, 0x0b, 0xa8, 0x85, 0xf3, 0xa9, 0x17, 0xb2, 0xd1, 0x44, 0x14, 0x95, 0x82, 0x34, 0x60, - 0x7e, 0xd3, 0xb3, 0xdb, 0xbe, 0x13, 0x2c, 0xb7, 0xeb, 0xde, 0x11, 0x4a, 0x46, 0xcb, 0x6d, 0x7b, - 0xa7, 0x49, 0x1b, 0xd8, 0xdc, 0xfc, 0xd2, 0xd5, 0x93, 0xe3, 0xe2, 0x2b, 0x01, 0xc7, 0xb1, 0x68, - 0x88, 0x64, 0x51, 0x8e, 0xa5, 0x70, 0xee, 0xc9, 0x89, 0x49, 0x52, 0xb2, 0x5b, 0xf1, 0x11, 0x86, - 0x0b, 0x09, 0x28, 0x49, 0x85, 0xa3, 0xc1, 0xf6, 0x30, 0xf5, 0x33, 0x55, 0x02, 0xe3, 0xff, 0xc9, - 0x44, 0x07, 0x30, 0x79, 0x17, 0xc6, 0xc5, 0x8a, 0x51, 0xe6, 0x05, 0xee, 0xa0, 0x72, 0x79, 0xc5, - 0x46, 0x56, 0x45, 0x67, 0xf7, 0xfe, 0x52, 0x79, 0x55, 0x99, 0x1b, 0x78, 0xef, 0xb7, 0xeb, 0xcd, - 0x38, 0x95, 0x44, 0x63, 0x93, 0x60, 0x73, 0xb5, 0xa6, 0xf7, 0x0a, 0x4e, 0x82, 0xa0, 0xe9, 0xa7, - 0x74, 0x83, 0x82, 0xfc, 0xe4, 0x0d, 0xff, 0x9f, 0x33, 0x69, 0xe7, 0x3c, 0x59, 0x82, 0xc9, 0x6d, - 0xd7, 0x3b, 0xc0, 0xf1, 0x55, 0x3a, 0x01, 0x47, 0xfe, 0x50, 0x16, 0xc4, 0x1b, 0xa4, 0x93, 0xa8, - 0xdf, 0xa6, 0xf4, 0x86, 0xfe, 0x6d, 0x31, 0x0e, 0x1a, 0x01, 0x1b, 0x87, 0x90, 0x63, 0xb8, 0x3a, - 0x70, 0x1c, 0xa2, 0x4f, 0xd0, 0xa6, 0xb0, 0x8a, 0x6e, 0xfc, 0x57, 0x19, 0xf5, 0x3c, 0x67, 0x9d, - 0x5c, 0x71, 0x5b, 0xb6, 0xd3, 0x56, 0x9a, 0xc3, 0x1f, 0x96, 0x10, 0x1a, 0xff, 0x12, 0x05, 0x99, - 0xdc, 0x82, 0x3c, 0xff, 0x15, 0xee, 0xb5, 0xa8, 0xd5, 0x12, 0x84, 0xfa, 0x41, 0x21, 0x11, 0x13, - 0x23, 0x93, 0x3b, 0xeb, 0xc8, 0xfc, 0x56, 0x46, 0x3d, 0x8a, 0x3f, 0xee, 0x61, 0x13, 0x3b, 0x64, - 0xb2, 0x67, 0x39, 0x64, 0x9e, 0xb8, 0x09, 0x7f, 0x2d, 0x03, 0xe3, 0x8a, 0x96, 0x82, 0xb5, 0x61, - 0xc3, 0x73, 0x3f, 0xa2, 0xf5, 0x40, 0x6f, 0x43, 0x87, 0x03, 0x63, 0x6d, 0x08, 0x51, 0x9f, 0xa0, - 0x0d, 0xc6, 0x9f, 0x66, 0xc4, 0x1d, 0x69, 0xe0, 0x6d, 0x5e, 0xdf, 0x92, 0xb3, 0x67, 0x39, 0x22, - 0xbf, 0x00, 0xc3, 0x26, 0x6d, 0x38, 0xbe, 0xb8, 0xdf, 0xcc, 0xa8, 0xf7, 0x31, 0x2c, 0x88, 0xe4, - 0x26, 0x8f, 0xfd, 0x54, 0xcf, 0x37, 0x2c, 0x67, 0x82, 0x6c, 0xd5, 0xbf, 0xd3, 0xa4, 0x8f, 0x1d, - 0xbe, 0x18, 0xc5, 0x51, 0x8b, 0xc7, 0x9b, 0xe3, 0x5b, 0xbb, 0xac, 0x44, 0x48, 0xd4, 0xea, 0xc2, - 0xd3, 0x68, 0x8c, 0x0f, 0x01, 0xa2, 0x2a, 0xc9, 0x7d, 0x28, 0x88, 0xd9, 0xe0, 0xb4, 0xf7, 0xb8, - 0x20, 0x25, 0xfa, 0xa0, 0x78, 0x72, 0x5c, 0x7c, 0xbe, 0x1e, 0x96, 0x09, 0xa9, 0x53, 0xe1, 0x9b, - 0x20, 0x34, 0xfe, 0x7e, 0x16, 0xb2, 0x25, 0x1c, 0x90, 0xfb, 0xf4, 0x28, 0xb0, 0x77, 0xee, 0x38, - 0x4d, 0x6d, 0x31, 0x1d, 0x20, 0xd4, 0xda, 0x75, 0x34, 0x75, 0x85, 0x82, 0xcc, 0x16, 0xd3, 0x7d, - 0x6f, 0xe7, 0x2d, 0x24, 0x54, 0x16, 0xd3, 0x81, 0xb7, 0xf3, 0x56, 0x9c, 0x2c, 0x44, 0x24, 0x06, - 0x8c, 0xf0, 0x85, 0x25, 0xe6, 0x20, 0x9c, 0x1c, 0x17, 0x47, 0xf8, 0xfa, 0x33, 0x45, 0x09, 0xb9, - 0x08, 0xb9, 0xda, 0xc6, 0xba, 0xd8, 0x01, 0x51, 0x2d, 0xe8, 0x77, 0xda, 0x26, 0x83, 0xb1, 0x3a, - 0x57, 0x2b, 0xa5, 0x0d, 0x54, 0x04, 0x0c, 0x47, 0x75, 0x36, 0x1b, 0x76, 0x27, 0xae, 0x0a, 0x08, - 0x11, 0xc9, 0x7b, 0x30, 0x7e, 0xbf, 0x52, 0x5e, 0x71, 0x7d, 0xbe, 0x7b, 0x8d, 0x44, 0x93, 0xff, - 0xa0, 0x51, 0xb7, 0x50, 0x13, 0x1f, 0x3f, 0x06, 0x14, 0x7c, 0xe3, 0x87, 0xb2, 0x30, 0xae, 0xe8, - 0xc9, 0xc8, 0x67, 0xc4, 0x03, 0x69, 0x46, 0xbb, 0x01, 0x28, 0x18, 0xac, 0x94, 0x2b, 0x55, 0x5a, - 0x6e, 0x83, 0x8a, 0xe7, 0xd2, 0x48, 0x81, 0x91, 0x1d, 0x44, 0x81, 0xf1, 0x36, 0x00, 0x9f, 0x03, - 0xf8, 0xc9, 0x8a, 0x38, 0xa1, 0xd8, 0x49, 0xa8, 0xe3, 0x12, 0x21, 0x93, 0x87, 0x30, 0xbb, 0xe9, - 0x75, 0xfd, 0xa0, 0x76, 0xe4, 0x07, 0xb4, 0xc5, 0xb8, 0x6d, 0xb8, 0x6e, 0x53, 0xcc, 0xbf, 0x57, - 0x4e, 0x8e, 0x8b, 0x97, 0xd1, 0xb8, 0xc3, 0xf2, 0xb1, 0x1c, 0x3f, 0xc0, 0xea, 0xb8, 0xae, 0xaa, - 0xd6, 0x48, 0x63, 0x60, 0x98, 0x30, 0xa1, 0x2a, 0x45, 0xd8, 0xc9, 0x22, 0x1e, 0x93, 0x84, 0xaa, - 0x5b, 0x39, 0x59, 0xc4, 0x57, 0x26, 0x1f, 0xb7, 0x74, 0x12, 0xe3, 0x33, 0xaa, 0x42, 0x6e, 0xd0, - 0x85, 0x6d, 0x7c, 0x7f, 0x26, 0xda, 0x46, 0x1e, 0xde, 0x24, 0xef, 0xc0, 0x08, 0x7f, 0xbc, 0x13, - 0x6f, 0x9c, 0xe7, 0xc2, 0x4b, 0xad, 0xfa, 0xb2, 0xc7, 0x35, 0xe1, 0x7f, 0xc0, 0x1f, 0xf8, 0x9f, - 0x33, 0x05, 0x49, 0xa8, 0x44, 0xd7, 0xf5, 0x69, 0x92, 0x3b, 0xaa, 0x8b, 0x6f, 0xa6, 0x29, 0xd1, - 0x8d, 0x1f, 0x1b, 0x86, 0x29, 0x1d, 0x4d, 0x7d, 0xe1, 0xcb, 0x0c, 0xf4, 0xc2, 0xf7, 0x05, 0xc8, - 0xb3, 0xfe, 0x70, 0xea, 0x54, 0x4a, 0x64, 0xaf, 0xe0, 0xd3, 0x82, 0x80, 0x69, 0x2f, 0xd7, 0xc0, - 0x87, 0x83, 0xdd, 0x71, 0xcd, 0x90, 0x8a, 0x2c, 0x2a, 0xcf, 0x50, 0xb9, 0x48, 0x48, 0x91, 0xcf, - 0x50, 0xea, 0x7a, 0x08, 0x1f, 0xa4, 0xde, 0x84, 0x11, 0x26, 0xdf, 0x87, 0x2a, 0x18, 0xfc, 0x4a, - 0x26, 0xfa, 0xc7, 0x4c, 0x54, 0x38, 0x12, 0xd9, 0x86, 0xfc, 0xaa, 0xed, 0x07, 0x35, 0x4a, 0xdb, - 0x03, 0xbc, 0xdd, 0x17, 0x45, 0x57, 0xcd, 0xe2, 0xc3, 0xb8, 0x4f, 0x69, 0x3b, 0xf6, 0xf8, 0x1a, - 0x32, 0x23, 0x5f, 0x05, 0x28, 0xbb, 0xed, 0xc0, 0x73, 0x9b, 0xab, 0xee, 0xde, 0xfc, 0x08, 0xde, - 0x7d, 0x2f, 0xc5, 0x06, 0x20, 0x42, 0xe0, 0xd7, 0xdf, 0x50, 0xc1, 0x53, 0xe7, 0x05, 0x56, 0xd3, - 0xdd, 0x53, 0xd7, 0x41, 0x84, 0x4f, 0xee, 0x40, 0x41, 0x2a, 0x16, 0xb6, 0x3a, 0x7b, 0x1e, 0x4e, - 0x90, 0xd1, 0x48, 0xf2, 0xa0, 0x8f, 0x03, 0xab, 0x2b, 0xe0, 0xea, 0x4e, 0x19, 0xa7, 0x21, 0x5f, - 0x81, 0x0b, 0x71, 0x98, 0x1c, 0xe5, 0x7c, 0x24, 0x93, 0xab, 0xec, 0x52, 0xe6, 0x7d, 0x2f, 0x16, - 0xe4, 0x2e, 0x4c, 0xb3, 0x0e, 0x59, 0xa3, 0xb6, 0xdf, 0xe5, 0x06, 0x56, 0x42, 0x35, 0xf3, 0xa2, - 0xd4, 0x44, 0xf1, 0x55, 0xd8, 0x74, 0xeb, 0x07, 0x0a, 0x92, 0x19, 0xa7, 0x32, 0x8e, 0xb3, 0x70, - 0x3e, 0x1d, 0x97, 0xfc, 0x55, 0x38, 0x27, 0xfa, 0xa5, 0x49, 0x3d, 0x05, 0x67, 0x00, 0x9b, 0x80, - 0x37, 0x45, 0x7f, 0xbf, 0x54, 0x0f, 0x19, 0x84, 0x1b, 0x07, 0x63, 0x11, 0x1b, 0xdc, 0xf4, 0x7a, - 0xc8, 0xd7, 0x61, 0x5c, 0xad, 0x36, 0x3b, 0xb8, 0x79, 0x45, 0x9f, 0xba, 0x54, 0x96, 0xc4, 0x86, - 0x69, 0x93, 0x7e, 0xa3, 0x4b, 0xfd, 0x40, 0x1a, 0x78, 0x88, 0xa3, 0xfb, 0x62, 0xa2, 0x16, 0x89, - 0x10, 0xea, 0x7f, 0x0a, 0x1e, 0xa7, 0xb4, 0xa4, 0x19, 0xde, 0xb7, 0x18, 0xfb, 0x38, 0x3f, 0xe3, - 0x3b, 0x59, 0xb8, 0xd0, 0x63, 0x5a, 0xb2, 0x9d, 0x0b, 0x05, 0x2b, 0x65, 0xe7, 0x8a, 0xc9, 0x53, - 0xdc, 0x3a, 0xec, 0x32, 0x64, 0x85, 0x28, 0x32, 0xb4, 0x54, 0x38, 0x39, 0x2e, 0x4e, 0x68, 0x2b, - 0x2e, 0x5b, 0xad, 0x90, 0x7b, 0x30, 0xc4, 0xba, 0x61, 0x00, 0x23, 0x07, 0xa9, 0xfd, 0x9b, 0x0a, - 0x1c, 0x75, 0xa1, 0x63, 0xdf, 0x20, 0x0f, 0xf2, 0x19, 0xc8, 0x6d, 0x6e, 0xae, 0xe2, 0x2a, 0xcf, - 0xe1, 0x2c, 0x9d, 0x0c, 0x82, 0xa6, 0xb6, 0xa9, 0x4c, 0x32, 0xda, 0xb0, 0x47, 0x4c, 0x86, 0x4e, - 0xbe, 0x14, 0x33, 0xbe, 0x7a, 0xbd, 0xff, 0x92, 0x1c, 0xdc, 0x16, 0xeb, 0x09, 0x4c, 0xa0, 0x8c, - 0x9f, 0xcf, 0x46, 0xbb, 0xed, 0x1d, 0xa7, 0x19, 0x50, 0x8f, 0x2c, 0xf0, 0xcd, 0x33, 0x12, 0xa3, - 0xcd, 0xf0, 0x37, 0x99, 0x8f, 0x76, 0x62, 0xce, 0x2a, 0xdc, 0x72, 0x5f, 0x57, 0xb6, 0xdc, 0x1c, - 0x6e, 0xb9, 0x53, 0x3d, 0x37, 0xd7, 0xd7, 0x53, 0x76, 0x10, 0xdc, 0x32, 0x53, 0x76, 0x89, 0x57, - 0x60, 0x72, 0xdd, 0x5d, 0x7e, 0x1c, 0x84, 0x88, 0x6c, 0xab, 0xcc, 0x9b, 0x3a, 0x90, 0x71, 0x7c, - 0xd0, 0x6c, 0x50, 0x6f, 0x73, 0xdf, 0x6e, 0x6b, 0x56, 0x06, 0x66, 0x02, 0xce, 0x70, 0xd7, 0xe9, - 0xa1, 0x8e, 0x3b, 0xca, 0x71, 0xe3, 0x70, 0xe3, 0xaf, 0x67, 0x65, 0x67, 0x3c, 0x5c, 0x7c, 0x46, - 0x5f, 0xb3, 0xdf, 0xd2, 0x5e, 0xb3, 0x67, 0x43, 0x3d, 0x7c, 0x68, 0x9a, 0xb1, 0x78, 0x8a, 0x45, - 0xc7, 0xdf, 0x1d, 0x81, 0x09, 0x15, 0x9d, 0xf5, 0x43, 0xa9, 0xd1, 0xf0, 0xd4, 0x7e, 0xb0, 0x1b, - 0x0d, 0xcf, 0x44, 0xa8, 0x66, 0xc0, 0x91, 0xeb, 0x6b, 0xc0, 0xf1, 0x35, 0x18, 0x2b, 0xb7, 0x1a, - 0xda, 0xb3, 0xb2, 0x91, 0xf2, 0x79, 0xd7, 0x43, 0x24, 0xbe, 0x16, 0x42, 0xf5, 0x72, 0xbd, 0xd5, - 0x48, 0x3e, 0x26, 0x47, 0x2c, 0x35, 0xdb, 0x8f, 0xe1, 0x27, 0xb1, 0xfd, 0xb8, 0x0d, 0x63, 0x5b, - 0x3e, 0xdd, 0xec, 0xb6, 0xdb, 0xb4, 0x89, 0xd3, 0x2a, 0xcf, 0x6f, 0x65, 0x5d, 0x9f, 0x5a, 0x01, - 0x42, 0xd5, 0x0f, 0x08, 0x51, 0xd5, 0x01, 0x1e, 0xed, 0x33, 0xc0, 0xb7, 0x20, 0xbf, 0x41, 0xa9, - 0x87, 0x7d, 0x3a, 0x1e, 0x09, 0xdf, 0x1d, 0x4a, 0x3d, 0x8b, 0x75, 0xac, 0x66, 0x13, 0x22, 0x10, - 0x35, 0x43, 0x92, 0x89, 0x01, 0x0d, 0x49, 0xc8, 0x4b, 0x30, 0xd1, 0xe9, 0xee, 0x34, 0x9d, 0x3a, - 0xf2, 0x15, 0x16, 0x28, 0xe6, 0x38, 0x87, 0x31, 0xb6, 0x3e, 0xf9, 0x12, 0x4c, 0xe2, 0x6d, 0x34, - 0x9c, 0x72, 0x53, 0xda, 0xfb, 0xab, 0x56, 0xc6, 0x65, 0xd2, 0x3a, 0x03, 0x59, 0x29, 0x86, 0x52, - 0x3a, 0x23, 0x72, 0x0f, 0x46, 0xf7, 0x9c, 0xc0, 0xda, 0xef, 0xee, 0xcc, 0x4f, 0x6b, 0x56, 0x46, - 0x77, 0x9d, 0x60, 0xa5, 0xbb, 0xc3, 0x87, 0x3c, 0x64, 0x8d, 0x3b, 0xde, 0x9e, 0x13, 0xec, 0x77, - 0x55, 0xe5, 0xf9, 0xc8, 0x1e, 0xe2, 0x2e, 0xd4, 0x60, 0x4a, 0x9f, 0x15, 0x4f, 0xe1, 0x49, 0x37, - 0x34, 0xb0, 0xc9, 0x17, 0xc6, 0xee, 0x0d, 0xe5, 0xa1, 0x30, 0xce, 0x4d, 0x6b, 0x4c, 0xd8, 0x08, - 0xfb, 0xc7, 0x24, 0xf7, 0xbb, 0x3b, 0xd4, 0x6b, 0xd3, 0x80, 0xfa, 0xe2, 0xea, 0xe7, 0x9b, 0x43, - 0xa5, 0x4e, 0xc7, 0x37, 0xfe, 0xd3, 0x2c, 0x8c, 0x96, 0xb6, 0x6b, 0xd5, 0xf6, 0xae, 0x8b, 0x0f, - 0xb3, 0xe1, 0x7b, 0x9c, 0xfa, 0x30, 0x1b, 0xbe, 0xc7, 0xa9, 0xaf, 0x70, 0x37, 0x52, 0x2e, 0xef, - 0x68, 0xbb, 0xad, 0x5c, 0xde, 0x35, 0xb5, 0x43, 0xf4, 0x34, 0x99, 0x1b, 0xe0, 0x69, 0x32, 0xd4, - 0x1e, 0x0f, 0x9d, 0xae, 0x3d, 0x7e, 0x07, 0xc6, 0xab, 0xed, 0x80, 0xee, 0x79, 0xd1, 0xaa, 0x09, - 0x15, 0x09, 0x21, 0x58, 0xbd, 0xd0, 0x29, 0xd8, 0x6c, 0x4a, 0x72, 0x8d, 0x75, 0xa8, 0xa9, 0xc6, - 0x29, 0xc9, 0x15, 0xdb, 0x31, 0x2d, 0x90, 0x44, 0x34, 0x2a, 0xb1, 0xf9, 0x26, 0xcd, 0x3f, 0xb8, - 0x08, 0x35, 0x15, 0x3d, 0xd9, 0xb0, 0x8e, 0x5d, 0x9a, 0x49, 0x37, 0xff, 0x30, 0xfe, 0x66, 0x06, - 0xe6, 0xd2, 0xa6, 0x11, 0x79, 0x1f, 0x26, 0x5c, 0x6f, 0xcf, 0x6e, 0x3b, 0xdf, 0xcb, 0x5b, 0xa4, - 0xa8, 0x2a, 0x55, 0xb8, 0xaa, 0xa0, 0x51, 0xe1, 0xac, 0x43, 0x94, 0x96, 0xeb, 0x9a, 0x95, 0xd4, - 0x0e, 0x51, 0xc0, 0xc6, 0x0f, 0x67, 0x61, 0xbc, 0xd4, 0xe9, 0x3c, 0xe3, 0xa6, 0x81, 0x9f, 0xd3, - 0x0e, 0x10, 0x79, 0x2f, 0x0f, 0xdb, 0x35, 0x90, 0x55, 0xe0, 0xaf, 0x66, 0x61, 0x3a, 0x46, 0xa1, - 0x7e, 0x7d, 0x66, 0x40, 0x83, 0xc0, 0xec, 0x80, 0x06, 0x81, 0xb9, 0xc1, 0x0c, 0x02, 0x87, 0x9e, - 0xe4, 0x50, 0x78, 0x0d, 0x72, 0xa5, 0x4e, 0x27, 0x6e, 0x58, 0xd0, 0xe9, 0x3c, 0xbc, 0xc5, 0x75, - 0x2b, 0x76, 0xa7, 0x63, 0x32, 0x0c, 0x6d, 0xa7, 0x1e, 0x19, 0x70, 0xa7, 0x36, 0xde, 0x84, 0x31, - 0xe4, 0x85, 0x66, 0x78, 0x97, 0x01, 0xb7, 0x18, 0x61, 0x81, 0xa7, 0xd5, 0x25, 0x36, 0x9f, 0xff, - 0x2f, 0x03, 0xc3, 0xf8, 0xfb, 0x19, 0x9d, 0x63, 0x8b, 0xda, 0x1c, 0x2b, 0x28, 0x73, 0x6c, 0x90, - 0xd9, 0xf5, 0x0f, 0x72, 0x00, 0xe5, 0x07, 0x66, 0x8d, 0xab, 0xe0, 0xc8, 0x1d, 0x98, 0xb6, 0x9b, - 0x4d, 0xf7, 0x90, 0x36, 0x2c, 0xd7, 0x73, 0xf6, 0x9c, 0x36, 0xef, 0x39, 0xf9, 0xda, 0xad, 0x17, - 0xa9, 0x6f, 0x60, 0xa2, 0xe8, 0x01, 0x2f, 0x51, 0xf9, 0xb4, 0x68, 0xb0, 0xef, 0x36, 0xa4, 0x32, - 0x41, 0xe3, 0x23, 0x8a, 0x52, 0xf8, 0xac, 0xf1, 0x12, 0x95, 0xcf, 0x3e, 0x2a, 0x47, 0xa4, 0x84, - 0xac, 0xf1, 0x11, 0x45, 0x29, 0x7c, 0xb8, 0x46, 0xc5, 0x27, 0xab, 0x30, 0x83, 0x10, 0xab, 0xee, - 0xd1, 0x06, 0x6d, 0x07, 0x8e, 0xdd, 0xf4, 0x85, 0xfa, 0x09, 0x15, 0x95, 0x89, 0x42, 0xf5, 0xfa, - 0x8d, 0x85, 0xe5, 0xa8, 0x8c, 0x5c, 0x87, 0xd1, 0x96, 0xfd, 0xd8, 0xb2, 0xf7, 0xb8, 0xdd, 0xc7, - 0x24, 0x57, 0x57, 0x08, 0x90, 0x7a, 0x8c, 0xb4, 0xec, 0xc7, 0xa5, 0x3d, 0xca, 0x5a, 0x41, 0x1f, - 0x77, 0x5c, 0x5f, 0x69, 0xc5, 0x48, 0xd4, 0x8a, 0x58, 0x91, 0xda, 0x0a, 0x51, 0x24, 0x5a, 0x61, - 0xfc, 0x4a, 0x06, 0x9e, 0xaf, 0xe2, 0x57, 0x04, 0x47, 0x65, 0xda, 0x0e, 0xa8, 0xb7, 0x41, 0xbd, - 0x96, 0x83, 0xaf, 0xe0, 0x35, 0x1a, 0x90, 0x97, 0x21, 0x57, 0x32, 0xd7, 0xc5, 0xfc, 0xe5, 0xfb, - 0xbd, 0x66, 0x93, 0xc0, 0x4a, 0x43, 0x8d, 0x56, 0xf6, 0x14, 0x55, 0x75, 0x09, 0x26, 0x4a, 0xbe, - 0xef, 0xec, 0xb5, 0x5b, 0xdc, 0x9f, 0x22, 0xa7, 0x59, 0x3d, 0x08, 0x78, 0xe2, 0x8d, 0x45, 0x25, - 0x31, 0xfe, 0xb3, 0x0c, 0xcc, 0x94, 0x3a, 0x1d, 0xfd, 0x93, 0x75, 0x8b, 0x9b, 0xcc, 0xe0, 0x16, - 0x37, 0x0e, 0x4c, 0x69, 0xcd, 0xe5, 0x53, 0x2a, 0x12, 0x7c, 0xfb, 0xf4, 0x0c, 0xff, 0xec, 0x4e, - 0x08, 0xb2, 0x7c, 0xfd, 0xb9, 0x38, 0xc6, 0xd8, 0xf8, 0x0f, 0x46, 0x71, 0x0f, 0x11, 0xbb, 0xad, - 0xb0, 0x09, 0xcd, 0xa4, 0xd8, 0x84, 0xbe, 0x0d, 0x8a, 0x84, 0xa3, 0x1e, 0x71, 0x8a, 0xac, 0xa8, - 0xea, 0x82, 0x22, 0x64, 0x72, 0x10, 0xb7, 0x0e, 0xcd, 0x61, 0x6b, 0x5e, 0x8e, 0x2f, 0xe0, 0xa7, - 0x62, 0x18, 0xba, 0x02, 0xa4, 0xda, 0xc6, 0x27, 0x6c, 0x5a, 0x3b, 0x70, 0x3a, 0x0f, 0xa9, 0xe7, - 0xec, 0x1e, 0x89, 0x05, 0x80, 0x9d, 0xef, 0x88, 0x52, 0xcb, 0x3f, 0x70, 0x3a, 0xd6, 0x23, 0x2c, - 0x37, 0x53, 0x68, 0xc8, 0x07, 0x30, 0x6a, 0xd2, 0x43, 0xcf, 0x09, 0xa4, 0xcd, 0xd3, 0x54, 0xa8, - 0xda, 0x44, 0x28, 0x5f, 0x0b, 0x1e, 0xff, 0xa1, 0xee, 0x8a, 0xa2, 0x9c, 0x2c, 0x72, 0x21, 0x85, - 0xdb, 0x36, 0x4d, 0x46, 0xad, 0x2d, 0x6d, 0xd7, 0x7a, 0xc9, 0x28, 0xe4, 0x1a, 0x0c, 0xa3, 0xa4, - 0x23, 0xee, 0x02, 0xe8, 0x2b, 0x84, 0xb2, 0xb3, 0x2a, 0x86, 0x21, 0x06, 0xb9, 0x04, 0x10, 0xbe, - 0x11, 0xfb, 0xf3, 0x79, 0x94, 0xd2, 0x15, 0x48, 0x5c, 0x4c, 0x1b, 0x3b, 0x93, 0x98, 0xb6, 0x0a, - 0x05, 0x93, 0xbb, 0x1d, 0x36, 0x4a, 0x1d, 0x7c, 0x88, 0xf4, 0xe7, 0x01, 0x57, 0xf2, 0xe5, 0x93, - 0xe3, 0xe2, 0x0b, 0xc2, 0x25, 0xb1, 0x61, 0xd9, 0x1d, 0xfe, 0x7e, 0xa9, 0x6d, 0x23, 0x71, 0x4a, - 0xf2, 0x36, 0x0c, 0xb1, 0xad, 0x57, 0xd8, 0x91, 0xca, 0x07, 0x9d, 0x68, 0x37, 0xe6, 0x8b, 0xb3, - 0xee, 0x6a, 0x7b, 0x02, 0x92, 0x10, 0x0b, 0xa6, 0xf4, 0xe9, 0x2e, 0x4c, 0x8a, 0xe6, 0xa3, 0xfe, - 0xd4, 0xcb, 0xc5, 0x2b, 0x8f, 0x80, 0x59, 0x75, 0x04, 0xaa, 0x2b, 0x20, 0xb6, 0x48, 0x97, 0x21, - 0xbf, 0x59, 0xde, 0xd8, 0x70, 0xbd, 0x80, 0x5f, 0x75, 0xa2, 0x93, 0x85, 0xc1, 0x4c, 0xbb, 0xbd, - 0x47, 0xf9, 0x59, 0x1c, 0xd4, 0x3b, 0x56, 0x87, 0xa1, 0xa9, 0x67, 0xb1, 0x24, 0xfd, 0xe4, 0x6c, - 0x48, 0x7f, 0x35, 0x0b, 0x2f, 0x87, 0x52, 0xd1, 0x03, 0xaf, 0x56, 0x5a, 0x5b, 0xad, 0x36, 0x36, - 0x84, 0x9a, 0x64, 0xc3, 0x73, 0x1f, 0x39, 0x0d, 0xea, 0x3d, 0xbc, 0x79, 0xca, 0x99, 0xbe, 0xca, - 0x97, 0x39, 0x7f, 0x0d, 0xcb, 0x6a, 0xd6, 0x76, 0x8a, 0xf0, 0x29, 0xb6, 0xa7, 0x4e, 0x27, 0xf1, - 0x38, 0xb6, 0xf2, 0x9c, 0x19, 0x31, 0x20, 0xdf, 0x9f, 0x81, 0xf3, 0xe9, 0x1f, 0x22, 0x54, 0x67, - 0x45, 0x79, 0x45, 0xef, 0xf1, 0xb5, 0x4b, 0xaf, 0x9d, 0x1c, 0x17, 0x5f, 0xf6, 0xed, 0x56, 0xd3, - 0x72, 0x1a, 0xbc, 0x36, 0xa7, 0x4e, 0xad, 0x8e, 0x40, 0xd0, 0xea, 0xed, 0x51, 0xd3, 0xe7, 0x41, - 0x1e, 0xed, 0xf3, 0x99, 0x25, 0x80, 0xbc, 0x7c, 0x70, 0x30, 0x7e, 0x23, 0x03, 0xca, 0x12, 0xcc, - 0x9b, 0xb4, 0xe1, 0x78, 0xb4, 0x1e, 0x88, 0xe3, 0x5d, 0xf8, 0x0a, 0x72, 0x58, 0xcc, 0xb8, 0x12, - 0x61, 0xe4, 0x7d, 0x18, 0x15, 0xc7, 0x90, 0xd8, 0x76, 0xe5, 0xd2, 0x15, 0x4f, 0x19, 0xdc, 0xa9, - 0x34, 0x71, 0x84, 0x49, 0x22, 0xb6, 0xeb, 0xdf, 0xdb, 0xde, 0x2c, 0x37, 0x6d, 0xa7, 0xe5, 0x8b, - 0xb3, 0x04, 0xbb, 0xf5, 0xa3, 0xc3, 0xc0, 0xaa, 0x23, 0x54, 0xdd, 0xf5, 0x43, 0x54, 0xe3, 0xae, - 0x7c, 0x49, 0x39, 0xc5, 0x42, 0xb8, 0x08, 0xc3, 0x0f, 0x23, 0x3d, 0xdd, 0xd2, 0xd8, 0xc9, 0x71, - 0x91, 0x4f, 0x17, 0x93, 0xc3, 0x0d, 0x0a, 0x63, 0xe1, 0xd4, 0x65, 0xbc, 0xd8, 0x0f, 0xe4, 0x35, - 0xc9, 0x79, 0xb1, 0x49, 0x6c, 0x22, 0x94, 0x89, 0x7a, 0xcb, 0xed, 0x06, 0x22, 0x64, 0x11, 0x01, - 0xbb, 0x87, 0xb6, 0x1b, 0x38, 0xd3, 0xd5, 0xd6, 0x09, 0x34, 0x45, 0xa0, 0xfa, 0xd1, 0x0c, 0x4c, - 0xe9, 0xd3, 0x96, 0x5c, 0x87, 0x11, 0xe1, 0x0e, 0x98, 0x41, 0xb5, 0x27, 0xe3, 0x36, 0xc2, 0x1d, - 0x01, 0x35, 0xf7, 0x3f, 0x81, 0xc5, 0xe4, 0x46, 0xc1, 0x41, 0x08, 0x4d, 0x28, 0x37, 0xd6, 0x39, - 0xc8, 0x94, 0x65, 0xc4, 0x60, 0x57, 0x59, 0xbf, 0xdb, 0x0c, 0xd4, 0x77, 0x4b, 0x0f, 0x21, 0xa6, - 0x28, 0x31, 0xca, 0x30, 0xc2, 0xb7, 0xd6, 0x98, 0x01, 0x64, 0xe6, 0x0c, 0x06, 0x90, 0xc6, 0x71, - 0x06, 0xa0, 0x56, 0x5b, 0xb9, 0x4f, 0x8f, 0x36, 0x6c, 0x07, 0xcf, 0x6f, 0x7e, 0x8c, 0xdd, 0x17, - 0x6b, 0x78, 0x42, 0x3c, 0xb4, 0xf3, 0x23, 0xef, 0x80, 0x1e, 0x69, 0x0f, 0xed, 0x12, 0x15, 0xcf, - 0x4a, 0xcf, 0x79, 0x64, 0x07, 0x94, 0x11, 0x66, 0x91, 0x90, 0x9f, 0x95, 0x1c, 0x1a, 0xa3, 0x54, - 0x90, 0xc9, 0x57, 0x61, 0x2a, 0xfa, 0x15, 0x9a, 0x0b, 0x4c, 0x85, 0xfb, 0x84, 0x5e, 0xb8, 0x74, - 0xe9, 0xe4, 0xb8, 0xb8, 0xa0, 0x70, 0x8d, 0x1b, 0x12, 0xc4, 0x98, 0x19, 0xbf, 0x94, 0x41, 0x23, - 0x19, 0xd9, 0xc0, 0x2b, 0x30, 0x14, 0x9a, 0x75, 0x4f, 0x88, 0x4d, 0x58, 0x7f, 0x12, 0xc5, 0x72, - 0x26, 0x6e, 0x45, 0x2d, 0xc1, 0xa3, 0x4b, 0x6f, 0x01, 0x2b, 0x25, 0x77, 0x61, 0x74, 0xa0, 0x6f, - 0xc6, 0x29, 0x96, 0xf2, 0xad, 0x92, 0x1a, 0x47, 0xe1, 0xde, 0xf6, 0xe6, 0x77, 0xef, 0x28, 0xfc, - 0x44, 0x16, 0xa6, 0x59, 0xbf, 0x96, 0xba, 0xc1, 0xbe, 0xeb, 0x39, 0xc1, 0xd1, 0x33, 0xab, 0x37, - 0x7e, 0x57, 0xbb, 0x92, 0x2d, 0xc8, 0xc3, 0x4c, 0x6d, 0xdb, 0x40, 0xea, 0xe3, 0x7f, 0x36, 0x0c, - 0xb3, 0x29, 0x54, 0xe4, 0x0d, 0xed, 0x69, 0x67, 0x5e, 0xba, 0xfb, 0x7f, 0xe7, 0xb8, 0x38, 0x21, - 0xd1, 0x37, 0x23, 0xf7, 0xff, 0x45, 0xdd, 0xe2, 0x8c, 0xf7, 0x14, 0xbe, 0xf4, 0xa8, 0x16, 0x67, - 0xba, 0x9d, 0xd9, 0x35, 0x18, 0x36, 0xdd, 0x26, 0x95, 0x56, 0x96, 0x28, 0x70, 0x79, 0x0c, 0xa0, - 0x59, 0x95, 0x30, 0x00, 0x59, 0x81, 0x51, 0xf6, 0xc7, 0x9a, 0xdd, 0x11, 0xef, 0xa5, 0x24, 0x54, - 0x0a, 0x20, 0xb4, 0xe3, 0xb4, 0xf7, 0x54, 0xbd, 0x40, 0x93, 0x5a, 0x2d, 0xbb, 0xa3, 0x49, 0x86, - 0x1c, 0x51, 0xd3, 0x2f, 0xe4, 0x7b, 0xeb, 0x17, 0x32, 0xa7, 0xea, 0x17, 0x76, 0x01, 0x6a, 0xce, - 0x5e, 0xdb, 0x69, 0xef, 0x95, 0x9a, 0x7b, 0x22, 0x68, 0xc2, 0xb5, 0xde, 0xa3, 0x70, 0x3d, 0x42, - 0xc6, 0x89, 0xfb, 0x3c, 0x1a, 0x35, 0x70, 0x98, 0x65, 0x37, 0xf7, 0x34, 0xe7, 0x2e, 0x85, 0x33, - 0x59, 0x07, 0x28, 0xd5, 0x03, 0xe7, 0x11, 0x9b, 0xc2, 0xbe, 0x10, 0xe3, 0xe4, 0x27, 0x97, 0x4b, - 0xf7, 0xe9, 0x11, 0x5e, 0x3d, 0xe4, 0xf3, 0xb0, 0x8d, 0xa8, 0x6c, 0x25, 0x68, 0x9e, 0x3b, 0x11, - 0x07, 0xd2, 0x81, 0x73, 0xa5, 0x46, 0xc3, 0x61, 0x6d, 0xb0, 0x9b, 0x9b, 0x3c, 0xdc, 0x05, 0xb2, - 0x9e, 0x48, 0x67, 0x7d, 0x4d, 0xbe, 0x84, 0xda, 0x21, 0x95, 0x25, 0xa3, 0x64, 0xc4, 0xaa, 0x49, - 0x67, 0x6c, 0xd4, 0x60, 0x4a, 0x6f, 0xbc, 0x1e, 0xec, 0x61, 0x02, 0xf2, 0x66, 0xad, 0x64, 0xd5, - 0x56, 0x4a, 0x37, 0x0b, 0x19, 0x52, 0x80, 0x09, 0xf1, 0x6b, 0xd1, 0x5a, 0x7c, 0xeb, 0x76, 0x21, - 0xab, 0x41, 0xde, 0xba, 0xb9, 0x58, 0xc8, 0x2d, 0x64, 0xe7, 0x33, 0x31, 0x3f, 0xcb, 0xd1, 0x42, - 0x9e, 0xab, 0x84, 0x8d, 0x5f, 0xcb, 0x40, 0x5e, 0x7e, 0x3b, 0xb9, 0x0d, 0xb9, 0x5a, 0x6d, 0x25, - 0xe6, 0x19, 0x19, 0x9d, 0x32, 0x7c, 0x3f, 0xf5, 0x7d, 0xd5, 0xfc, 0x9d, 0x11, 0x30, 0xba, 0xcd, - 0xd5, 0x9a, 0x90, 0x41, 0x24, 0x5d, 0xb4, 0x79, 0x73, 0xba, 0x14, 0x77, 0xb1, 0xdb, 0x90, 0xbb, - 0xb7, 0xbd, 0x29, 0x2e, 0x59, 0x92, 0x2e, 0xda, 0x4f, 0x39, 0xdd, 0x47, 0x87, 0xea, 0x2e, 0xcf, - 0x08, 0x0c, 0x13, 0xc6, 0x95, 0x89, 0xcc, 0x0f, 0xdd, 0x96, 0x1b, 0x46, 0x38, 0x10, 0x87, 0x2e, - 0x83, 0x98, 0xa2, 0x84, 0x89, 0x22, 0xab, 0x6e, 0xdd, 0x6e, 0x8a, 0xd3, 0x1b, 0x45, 0x91, 0x26, - 0x03, 0x98, 0x1c, 0x6e, 0xfc, 0x76, 0x06, 0x0a, 0x28, 0xb0, 0xa1, 0xf9, 0xba, 0x7b, 0x40, 0xdb, - 0x0f, 0x6f, 0x92, 0x37, 0xe5, 0x92, 0xcb, 0x84, 0x8a, 0xae, 0x61, 0x5c, 0x72, 0xb1, 0xb7, 0x40, - 0xb1, 0xec, 0x94, 0x20, 0x12, 0xd9, 0xc1, 0x9d, 0xcf, 0x4f, 0x09, 0x22, 0x51, 0x84, 0x61, 0xfc, - 0x1c, 0xb1, 0x39, 0xe2, 0x97, 0x07, 0x0c, 0x60, 0x72, 0xb8, 0xb2, 0x37, 0xfd, 0x54, 0x36, 0xd1, - 0x86, 0xc5, 0xef, 0x2a, 0x07, 0x6e, 0xbd, 0x71, 0x03, 0xed, 0xd7, 0x1f, 0xc2, 0x5c, 0xbc, 0x4b, - 0x50, 0x09, 0x59, 0x82, 0x69, 0x1d, 0x2e, 0xf5, 0x91, 0x17, 0x52, 0xeb, 0x7a, 0xb8, 0x68, 0xc6, - 0xf1, 0x8d, 0xff, 0x3d, 0x03, 0x63, 0xf8, 0xa7, 0xd9, 0x6d, 0xa2, 0x19, 0x61, 0x69, 0xbb, 0x26, - 0x54, 0x23, 0xaa, 0x30, 0x67, 0x1f, 0xfa, 0x96, 0xd0, 0xa3, 0x68, 0x7b, 0x4c, 0x88, 0x2c, 0x48, - 0xf9, 0xfb, 0x86, 0x54, 0xca, 0x85, 0xa4, 0xfc, 0x21, 0xc4, 0x8f, 0x91, 0x0a, 0x64, 0x34, 0x3e, - 0xde, 0xae, 0xb1, 0xe9, 0xa7, 0xda, 0xf5, 0x20, 0x9d, 0xdb, 0xd4, 0x8d, 0x8f, 0x39, 0x1a, 0x9a, - 0xf5, 0x6c, 0xd7, 0x4a, 0xe6, 0xba, 0x66, 0xd6, 0xc3, 0xbe, 0x51, 0xd3, 0x4b, 0x09, 0x24, 0xe3, - 0xe7, 0xc7, 0xe3, 0x1d, 0x28, 0x0e, 0xbc, 0x33, 0xae, 0x8d, 0x77, 0x60, 0xb8, 0xd4, 0x6c, 0xba, - 0x87, 0x62, 0x97, 0x90, 0x37, 0xd7, 0xb0, 0xff, 0xf8, 0x79, 0x86, 0x6a, 0x3d, 0xcd, 0x29, 0x95, - 0x01, 0x48, 0x19, 0xc6, 0x4a, 0xdb, 0xb5, 0x6a, 0xb5, 0xb2, 0xb9, 0xc9, 0x1d, 0xf0, 0x72, 0x4b, - 0xaf, 0xca, 0xfe, 0x71, 0x9c, 0x86, 0x15, 0xb7, 0x57, 0x88, 0xe4, 0xf7, 0x88, 0x8e, 0xbc, 0x07, - 0x70, 0xcf, 0x75, 0xda, 0x5c, 0x8d, 0x29, 0x1a, 0xcf, 0x6e, 0xe0, 0xe3, 0x1f, 0xb9, 0x4e, 0x5b, - 0xe8, 0x3d, 0xd9, 0xb7, 0x47, 0x48, 0xa6, 0xf2, 0x37, 0xeb, 0xe9, 0x25, 0x97, 0x9b, 0x06, 0x0e, - 0x47, 0x3d, 0xbd, 0xe3, 0x26, 0xf4, 0x6d, 0x12, 0x8d, 0xb4, 0x60, 0xba, 0xd6, 0xdd, 0xdb, 0xa3, - 0x6c, 0x67, 0x17, 0xfa, 0xa4, 0x11, 0x71, 0x95, 0x0e, 0xc3, 0x1e, 0xf1, 0xfb, 0x08, 0xbb, 0x0c, - 0xf9, 0x4b, 0x6f, 0xb0, 0x89, 0xfc, 0xed, 0xe3, 0xa2, 0xb0, 0x83, 0x60, 0xa2, 0x9a, 0x2f, 0xe9, - 0x93, 0xda, 0xa4, 0x38, 0x6f, 0xf2, 0x00, 0x46, 0xf8, 0x9b, 0x91, 0x70, 0x28, 0x7b, 0xa9, 0xcf, - 0xa2, 0xe1, 0x88, 0xbd, 0x5e, 0x25, 0x79, 0x29, 0xd9, 0x86, 0x7c, 0xd9, 0xf1, 0xea, 0x4d, 0x5a, - 0xae, 0x8a, 0xb3, 0xff, 0xe5, 0x3e, 0x2c, 0x25, 0x2a, 0xef, 0x97, 0x3a, 0xfe, 0xaa, 0x3b, 0xaa, - 0x2c, 0x20, 0x31, 0xc8, 0xdf, 0xcc, 0xc0, 0xf3, 0xe1, 0xd7, 0x97, 0xf6, 0x68, 0x3b, 0x58, 0xb3, - 0x83, 0xfa, 0x3e, 0xf5, 0x44, 0x2f, 0x8d, 0xf5, 0xeb, 0xa5, 0xcf, 0x27, 0x7a, 0xe9, 0x6a, 0xd4, - 0x4b, 0x36, 0x63, 0x66, 0xb5, 0x38, 0xb7, 0x64, 0x9f, 0xf5, 0xab, 0x95, 0x58, 0x00, 0xd1, 0x6b, - 0xa8, 0x70, 0x48, 0x7e, 0xb5, 0x4f, 0x83, 0x23, 0x64, 0xe1, 0x48, 0x14, 0xfe, 0xd6, 0x2c, 0x61, - 0x43, 0x28, 0xb9, 0x2f, 0xbd, 0x37, 0xb9, 0x54, 0x72, 0xb9, 0x0f, 0x6f, 0xee, 0xd1, 0x39, 0xdb, - 0xc7, 0x4f, 0x9b, 0x8f, 0xf6, 0xaa, 0xbd, 0x23, 0x04, 0x91, 0x53, 0x46, 0x7b, 0xd5, 0x8e, 0x46, - 0xbb, 0x69, 0xc7, 0x47, 0x7b, 0xd5, 0xde, 0x21, 0x65, 0xee, 0x72, 0xce, 0xfd, 0x93, 0x2f, 0xf5, - 0xe3, 0x56, 0xde, 0xe0, 0x27, 0x73, 0x8a, 0xeb, 0xf9, 0x97, 0x61, 0xac, 0xd6, 0xb1, 0xeb, 0xb4, - 0xe9, 0xec, 0x06, 0xe2, 0xa9, 0xfd, 0x95, 0x3e, 0xac, 0x42, 0x5c, 0xf1, 0xb4, 0x2a, 0x7f, 0xaa, - 0xd7, 0xa4, 0x10, 0x87, 0x7d, 0xe1, 0xe6, 0xc6, 0x9a, 0x78, 0x6d, 0xef, 0xf7, 0x85, 0x9b, 0x1b, - 0x6b, 0x42, 0xe6, 0xe8, 0xb4, 0x34, 0x99, 0x63, 0x63, 0x8d, 0x74, 0x60, 0x6a, 0x93, 0x7a, 0x9e, - 0xbd, 0xeb, 0x7a, 0x2d, 0xae, 0xbf, 0xe4, 0x3e, 0x6f, 0xd7, 0xfa, 0xf1, 0xd3, 0x08, 0xb8, 0xda, - 0x2e, 0x90, 0x30, 0x2b, 0xae, 0xf4, 0x8c, 0xf1, 0x67, 0x7d, 0xb2, 0xe4, 0x04, 0x3b, 0xdd, 0xfa, - 0x01, 0x0d, 0xe6, 0x67, 0x4e, 0xed, 0x93, 0x10, 0x97, 0xf7, 0xc9, 0x8e, 0xfc, 0xa9, 0xf6, 0x49, - 0x88, 0x63, 0xfc, 0xe3, 0x1c, 0x5c, 0xe8, 0xd1, 0x05, 0x64, 0x5d, 0x6e, 0xb9, 0x19, 0x4d, 0x8b, - 0xdd, 0x03, 0xfd, 0xfa, 0xa9, 0xbb, 0xf0, 0x2a, 0x14, 0x96, 0xef, 0xa3, 0xac, 0xce, 0x1f, 0x72, - 0xca, 0x25, 0x79, 0x58, 0xa1, 0xa6, 0x95, 0x1e, 0xa0, 0x8d, 0xb0, 0x7c, 0x00, 0xaa, 0x6b, 0xce, - 0xf0, 0x09, 0xca, 0x85, 0xbf, 0x9e, 0x85, 0x21, 0x3c, 0x38, 0x63, 0x21, 0xc0, 0x32, 0x67, 0x0a, - 0x01, 0xf6, 0x05, 0x98, 0x58, 0xbe, 0xcf, 0x6f, 0xd2, 0x2b, 0xb6, 0xbf, 0x2f, 0xb6, 0x75, 0x34, - 0xe4, 0xa0, 0x07, 0x96, 0xb8, 0x78, 0xef, 0xdb, 0x9a, 0xcc, 0xaa, 0x51, 0x90, 0x2d, 0x98, 0xe5, - 0xdf, 0xe6, 0xec, 0x3a, 0x75, 0x1e, 0x49, 0xc8, 0xb1, 0x9b, 0x62, 0x8f, 0x7f, 0xf9, 0xe4, 0xb8, - 0x58, 0xa4, 0x07, 0x68, 0xfd, 0x2c, 0xca, 0x2d, 0x1f, 0x11, 0x54, 0x33, 0xe8, 0x14, 0x7a, 0x35, - 0xbc, 0x89, 0x39, 0x86, 0x15, 0xb2, 0xda, 0x58, 0xdd, 0x0c, 0x97, 0x23, 0x19, 0x7f, 0x32, 0x0c, - 0x0b, 0xbd, 0xb7, 0x67, 0xf2, 0x45, 0x7d, 0x00, 0xaf, 0x9c, 0xba, 0xa1, 0x9f, 0x3e, 0x86, 0x5f, - 0x82, 0xb9, 0xe5, 0x76, 0x40, 0xbd, 0x8e, 0xe7, 0xc8, 0x80, 0x36, 0x2b, 0xae, 0x2f, 0xad, 0xcd, - 0xd1, 0xec, 0x9b, 0x86, 0xe5, 0x42, 0xb7, 0x8a, 0xb6, 0xef, 0x0a, 0xab, 0x54, 0x0e, 0x64, 0x19, - 0xa6, 0x14, 0x78, 0xb3, 0xbb, 0xa7, 0xbe, 0x4e, 0xa9, 0x3c, 0x9b, 0x5d, 0xd5, 0x14, 0x37, 0x46, - 0x84, 0x16, 0xed, 0xec, 0xca, 0x58, 0xbf, 0xb7, 0x7d, 0xbf, 0x26, 0x86, 0x93, 0x5b, 0xb4, 0x23, - 0xd4, 0xfa, 0xe8, 0xf0, 0x40, 0xdb, 0x5f, 0x23, 0xe4, 0x85, 0x5f, 0xca, 0x89, 0x19, 0xf5, 0x32, - 0xe4, 0x6a, 0xdd, 0x1d, 0xf5, 0xcd, 0xcd, 0xd7, 0x0e, 0x38, 0x56, 0x4a, 0x3e, 0x07, 0x60, 0xd2, - 0x8e, 0xeb, 0x3b, 0x81, 0xeb, 0x1d, 0xa9, 0x2e, 0x95, 0x5e, 0x08, 0xd5, 0xbd, 0x3e, 0x24, 0x94, - 0xac, 0xc0, 0x74, 0xf4, 0xeb, 0xc1, 0x61, 0x5b, 0xe8, 0x92, 0xc7, 0xb8, 0x76, 0x25, 0x22, 0xb7, - 0x5c, 0x56, 0xa6, 0x1e, 0xd9, 0x31, 0x32, 0xb2, 0x08, 0xf9, 0x6d, 0xd7, 0x3b, 0xd8, 0x65, 0x63, - 0x3c, 0x14, 0x09, 0x15, 0x87, 0x02, 0xa6, 0x1e, 0x9e, 0x12, 0x8f, 0x2d, 0x97, 0xe5, 0xf6, 0x23, - 0xc7, 0x73, 0xf1, 0x45, 0x4f, 0xb5, 0x69, 0xa1, 0x11, 0x58, 0x73, 0x66, 0x8f, 0xc0, 0xe4, 0x1a, - 0x0c, 0x97, 0xea, 0x81, 0xeb, 0x09, 0x83, 0x16, 0x3e, 0x53, 0x18, 0x40, 0x9b, 0x29, 0x0c, 0xc0, - 0x3a, 0xd1, 0xa4, 0xbb, 0xe2, 0x75, 0x07, 0x3b, 0xd1, 0xa3, 0xbb, 0x9a, 0xa7, 0x3e, 0xdd, 0x65, - 0x42, 0x91, 0x49, 0x77, 0x51, 0xf1, 0xa1, 0x05, 0xb8, 0xdb, 0x4d, 0xa8, 0xcc, 0x04, 0x9a, 0xf1, - 0xbb, 0x63, 0x3d, 0xa7, 0x3c, 0x3b, 0x85, 0xce, 0x36, 0xe5, 0x57, 0xed, 0x01, 0xa6, 0xfc, 0x1b, - 0xa1, 0x2f, 0x89, 0x1a, 0x9e, 0x02, 0x21, 0xea, 0x31, 0xc8, 0x71, 0x16, 0x7e, 0x39, 0x7f, 0x96, - 0x49, 0x24, 0x3a, 0x29, 0x3b, 0x68, 0x27, 0xe5, 0x06, 0xea, 0x24, 0xb2, 0x04, 0x93, 0x61, 0x88, - 0xc4, 0x0d, 0x3b, 0xd0, 0xb6, 0xb5, 0x30, 0xae, 0xa5, 0xd5, 0xb1, 0x03, 0x75, 0x5b, 0xd3, 0x49, - 0xc8, 0xbb, 0x30, 0x2e, 0x1c, 0xaa, 0x90, 0xc3, 0x70, 0x64, 0x29, 0x24, 0xbd, 0xaf, 0x62, 0xf4, - 0x2a, 0x3a, 0x5b, 0xcd, 0x1b, 0x4e, 0x87, 0x36, 0x9d, 0x36, 0xad, 0xe1, 0x63, 0x85, 0x98, 0x31, - 0xfc, 0xd1, 0x56, 0x94, 0x58, 0xfc, 0x1d, 0x43, 0xd3, 0x1f, 0x6a, 0x44, 0xf1, 0xc9, 0x3a, 0x7a, - 0xa6, 0xc9, 0xca, 0xed, 0x14, 0xbd, 0x55, 0x77, 0xcf, 0x91, 0x36, 0xf4, 0xd2, 0x4e, 0xd1, 0xb3, - 0x9a, 0x0c, 0x1a, 0xb3, 0x53, 0xe4, 0xa8, 0xec, 0x86, 0xc3, 0x7e, 0x54, 0x2b, 0xe2, 0x25, 0x11, - 0x6f, 0x38, 0x48, 0xa4, 0x3b, 0x2e, 0x70, 0x24, 0x59, 0xcd, 0x72, 0xcb, 0x76, 0x9a, 0x22, 0x0a, - 0x41, 0x54, 0x0d, 0x65, 0xd0, 0x78, 0x35, 0x88, 0x4a, 0xea, 0x30, 0x61, 0xd2, 0xdd, 0x0d, 0xcf, - 0x0d, 0x68, 0x3d, 0xa0, 0x0d, 0x21, 0xd5, 0xc9, 0x8b, 0xcd, 0x92, 0xeb, 0x72, 0x89, 0x15, 0x6d, - 0xe3, 0x33, 0xdf, 0x3e, 0x2e, 0x02, 0x03, 0x71, 0xaf, 0x98, 0x93, 0xe3, 0xe2, 0x05, 0x36, 0xfe, - 0x1d, 0x49, 0xac, 0x9e, 0x4e, 0x2a, 0x53, 0xf2, 0x4d, 0xb6, 0x5f, 0x87, 0x5d, 0x12, 0x55, 0x36, - 0xd1, 0xa3, 0xb2, 0xb7, 0x52, 0x2b, 0x2b, 0x2a, 0xbd, 0x9d, 0x5a, 0x69, 0x6a, 0x25, 0xe4, 0x3d, - 0x18, 0x2f, 0x57, 0xcb, 0x6e, 0x7b, 0xd7, 0xd9, 0xab, 0xad, 0x94, 0x50, 0x34, 0x14, 0x1e, 0x51, - 0x75, 0xc7, 0xaa, 0x23, 0xdc, 0xf2, 0xf7, 0x6d, 0xcd, 0x31, 0x36, 0xc2, 0x27, 0x77, 0x61, 0x4a, - 0xfe, 0x34, 0xe9, 0xee, 0x96, 0x59, 0x45, 0x89, 0x50, 0xba, 0xa1, 0x85, 0x1c, 0x58, 0x47, 0x74, - 0x3d, 0xf5, 0xa6, 0x10, 0x23, 0x63, 0x93, 0xb1, 0x42, 0x3b, 0x4d, 0xf7, 0x88, 0x7d, 0xde, 0xa6, - 0x43, 0x3d, 0x94, 0x01, 0xc5, 0x64, 0x6c, 0x84, 0x25, 0x56, 0xe0, 0xe8, 0xef, 0xa7, 0x3a, 0x11, - 0x59, 0x87, 0x19, 0x31, 0xc5, 0x1f, 0x3a, 0xbe, 0xb3, 0xe3, 0x34, 0x9d, 0xe0, 0x08, 0xa5, 0x3f, - 0x21, 0xc0, 0xc8, 0x75, 0xf1, 0x28, 0x2c, 0x55, 0x98, 0x25, 0x49, 0x8d, 0x5f, 0xcb, 0xc2, 0x0b, - 0xfd, 0x6e, 0x42, 0xa4, 0xa6, 0x6f, 0x66, 0x57, 0x07, 0xb8, 0x3d, 0x9d, 0xbe, 0x9d, 0x2d, 0xc3, - 0xd4, 0x03, 0xc5, 0xa4, 0x2f, 0x34, 0xb1, 0xc4, 0xce, 0x50, 0x8d, 0xfd, 0xf4, 0xd9, 0x1e, 0x23, - 0x5a, 0x78, 0x24, 0xb6, 0xb9, 0x8f, 0xeb, 0xa2, 0x79, 0x1b, 0xc6, 0xca, 0x6e, 0x3b, 0xa0, 0x8f, - 0x83, 0x58, 0x40, 0x02, 0x0e, 0x8c, 0xbb, 0xa7, 0x4a, 0x54, 0xe3, 0xdf, 0x64, 0xe1, 0xc5, 0xbe, - 0x57, 0x01, 0xb2, 0xa9, 0xf7, 0xda, 0xb5, 0x41, 0xee, 0x0f, 0xa7, 0x77, 0xdb, 0x62, 0xc2, 0xee, - 0xee, 0x54, 0x0f, 0xa8, 0x85, 0xff, 0x21, 0x23, 0x3a, 0xe9, 0xd3, 0x30, 0x8a, 0x55, 0x85, 0x5d, - 0xc4, 0xb5, 0x64, 0xb8, 0x0b, 0x3b, 0xba, 0x96, 0x8c, 0xa3, 0x91, 0x5b, 0x90, 0x2f, 0xdb, 0xcd, - 0xa6, 0x12, 0xae, 0x01, 0xa5, 0xf9, 0x3a, 0xc2, 0x62, 0xc6, 0xa3, 0x12, 0x91, 0xc9, 0x3e, 0xfc, - 0x6f, 0xe5, 0xac, 0xc0, 0xcd, 0x52, 0x90, 0xc5, 0x8e, 0x0b, 0x05, 0x19, 0x83, 0xbc, 0xd6, 0xdd, - 0xd0, 0x21, 0x9c, 0x07, 0x79, 0x65, 0x00, 0x2d, 0xc8, 0x2b, 0x03, 0x18, 0xbf, 0x9e, 0x83, 0x4b, - 0xfd, 0xef, 0xb3, 0x64, 0x4b, 0x1f, 0x82, 0xd7, 0x07, 0xba, 0x05, 0x9f, 0x3e, 0x06, 0x32, 0x64, - 0x32, 0xef, 0x90, 0xab, 0x49, 0xf7, 0x97, 0xef, 0x1c, 0x17, 0x15, 0x8b, 0xe4, 0x7b, 0xae, 0xd3, - 0x56, 0xde, 0x4c, 0xbe, 0xa1, 0x49, 0x86, 0xfc, 0xf5, 0xfe, 0xf6, 0x60, 0x5f, 0x16, 0xd1, 0xf1, - 0x7d, 0x65, 0x50, 0x89, 0xf2, 0xf3, 0x50, 0x88, 0x93, 0x92, 0x2b, 0x30, 0x84, 0x1f, 0xa0, 0xf8, - 0xf0, 0xc4, 0x38, 0x60, 0xf9, 0xc2, 0x9a, 0x98, 0x3b, 0x18, 0xc1, 0x02, 0xed, 0x01, 0x74, 0xdd, - 0xa0, 0x88, 0x60, 0xc1, 0xcd, 0x09, 0x92, 0xfa, 0xc1, 0x18, 0x91, 0xf1, 0x67, 0x19, 0xb8, 0xd8, - 0x53, 0x53, 0x40, 0x36, 0xf4, 0x01, 0x7b, 0xf5, 0x34, 0xd5, 0xc2, 0xa9, 0x63, 0xb5, 0xf0, 0x63, - 0x72, 0xee, 0xbf, 0x0f, 0x13, 0xb5, 0xee, 0x4e, 0xfc, 0x7e, 0xc6, 0xe3, 0xcb, 0x28, 0x70, 0xf5, - 0x04, 0x53, 0xf1, 0x59, 0xfb, 0xa5, 0xc1, 0x83, 0x30, 0x00, 0x52, 0xac, 0x0e, 0x43, 0x17, 0xeb, - 0x64, 0x04, 0x0f, 0x9d, 0xc8, 0xf8, 0xd5, 0x6c, 0xfa, 0x45, 0xf7, 0x6e, 0x79, 0xe3, 0x2c, 0x17, - 0xdd, 0xbb, 0xe5, 0x8d, 0xd3, 0xdb, 0xfe, 0x4f, 0x64, 0xdb, 0xf1, 0x61, 0x56, 0xec, 0x78, 0x52, - 0xd1, 0x29, 0x1e, 0x66, 0xe5, 0xee, 0xe8, 0xeb, 0x0f, 0xb3, 0x12, 0x99, 0xbc, 0x05, 0x63, 0xab, - 0x2e, 0x0f, 0xae, 0x21, 0x5b, 0xcc, 0x7d, 0x90, 0x25, 0x50, 0xdd, 0x1e, 0x43, 0x4c, 0x76, 0xb7, - 0xd0, 0x07, 0x5e, 0x1a, 0x57, 0xe2, 0xdd, 0x22, 0x36, 0x5d, 0x74, 0x75, 0xa0, 0x4e, 0x66, 0xfc, - 0x27, 0xc3, 0x60, 0x9c, 0xae, 0xcc, 0x20, 0x1f, 0xea, 0x7d, 0x77, 0x7d, 0x60, 0x35, 0xc8, 0x40, - 0x5b, 0x6e, 0xa9, 0xdb, 0x70, 0x68, 0xbb, 0xae, 0x47, 0xc6, 0x10, 0x30, 0x75, 0x0b, 0x94, 0x78, - 0x1f, 0xc7, 0x51, 0x75, 0xe1, 0xbf, 0xcd, 0x45, 0x4b, 0x2d, 0x76, 0x34, 0x66, 0x3e, 0xc6, 0xd1, - 0x48, 0xee, 0x43, 0x41, 0x85, 0x28, 0x2f, 0xb4, 0x28, 0xb9, 0x68, 0x8c, 0x62, 0x1f, 0x95, 0x20, - 0xd4, 0xcf, 0xd7, 0xdc, 0xe0, 0xe7, 0x6b, 0x24, 0xbe, 0x63, 0xfd, 0x43, 0x49, 0xf1, 0x3d, 0xee, - 0x8c, 0xae, 0xa0, 0xcb, 0x48, 0x1a, 0xbe, 0x38, 0xb4, 0x86, 0xf5, 0x48, 0x1a, 0x29, 0x07, 0x97, - 0x8a, 0x2e, 0x83, 0x81, 0xe0, 0x4f, 0xc5, 0x17, 0x3e, 0x0c, 0x06, 0xc2, 0xe9, 0xd3, 0x82, 0x81, - 0x84, 0x24, 0xec, 0x00, 0x34, 0xbb, 0x6d, 0x1e, 0x4d, 0x7c, 0x34, 0x3a, 0x00, 0xbd, 0x6e, 0xdb, - 0x8a, 0x47, 0x14, 0x0f, 0x11, 0x8d, 0x7f, 0x34, 0x94, 0x2e, 0x1c, 0x84, 0xfa, 0xae, 0xb3, 0x08, - 0x07, 0x21, 0xd1, 0x27, 0x33, 0x53, 0xb7, 0x60, 0x56, 0xda, 0xe7, 0x49, 0x43, 0xaf, 0x2d, 0x73, - 0x55, 0x0c, 0x31, 0xea, 0x8d, 0x42, 0xcb, 0x3e, 0x69, 0x2c, 0x66, 0x75, 0x3d, 0x4d, 0x6f, 0x94, - 0x42, 0xbf, 0xf0, 0x1b, 0x52, 0x2d, 0xa6, 0x0e, 0xc2, 0xd6, 0x56, 0x38, 0x97, 0x63, 0x83, 0xd0, - 0xed, 0x6a, 0xc3, 0xa8, 0x93, 0xf0, 0xbd, 0x57, 0xaa, 0x1c, 0x90, 0x89, 0x22, 0x2b, 0x2a, 0x8a, - 0x8a, 0x18, 0x97, 0x18, 0x11, 0xd9, 0x83, 0x8b, 0x91, 0x28, 0xad, 0xdc, 0x14, 0x90, 0x23, 0x6f, - 0xf0, 0xb5, 0x93, 0xe3, 0xe2, 0xab, 0x8a, 0x28, 0xae, 0x5e, 0x38, 0x62, 0xdc, 0x7b, 0xf3, 0x62, - 0xfb, 0xed, 0x92, 0x67, 0xb7, 0xeb, 0xfb, 0xca, 0x9c, 0xc7, 0xfd, 0x76, 0x07, 0xa1, 0x89, 0x70, - 0x06, 0x11, 0xb2, 0xf1, 0x63, 0x59, 0x98, 0xe2, 0x67, 0x35, 0x7f, 0x9d, 0x7b, 0x66, 0x5f, 0x3e, - 0xdf, 0xd1, 0x5e, 0x3e, 0x65, 0xe4, 0x3d, 0xb5, 0x69, 0x03, 0xbd, 0x7b, 0xee, 0x03, 0x49, 0xd2, - 0x10, 0x13, 0x26, 0x54, 0x68, 0xff, 0x27, 0xcf, 0x9b, 0x51, 0x90, 0x46, 0x21, 0x2a, 0xe1, 0xbb, - 0xb3, 0x6f, 0x6a, 0x3c, 0x8c, 0x1f, 0xcd, 0xc2, 0xa4, 0x62, 0xa7, 0xf2, 0xcc, 0x76, 0xfc, 0xe7, - 0xb5, 0x8e, 0x9f, 0x0f, 0x3d, 0x04, 0xc3, 0x96, 0x0d, 0xd4, 0xef, 0x5d, 0x98, 0x49, 0x90, 0xc4, - 0xcd, 0x7d, 0x32, 0x83, 0x98, 0xfb, 0xbc, 0x91, 0x8c, 0xf8, 0xc6, 0x13, 0x27, 0x84, 0xf1, 0x7f, - 0xd4, 0x10, 0x73, 0x3f, 0x91, 0x85, 0x39, 0xf1, 0x0b, 0x43, 0xa4, 0x72, 0x61, 0xf5, 0x99, 0x1d, - 0x8b, 0x92, 0x36, 0x16, 0x45, 0x7d, 0x2c, 0x94, 0x06, 0xf6, 0x1e, 0x12, 0xe3, 0x07, 0x01, 0xe6, - 0x7b, 0x11, 0x0c, 0xec, 0x88, 0x1f, 0xb9, 0x26, 0x66, 0x07, 0x70, 0x4d, 0x5c, 0x85, 0x02, 0x56, - 0x25, 0x82, 0x20, 0xfa, 0x5b, 0x66, 0x55, 0x74, 0x12, 0xea, 0x17, 0x78, 0x1c, 0x5b, 0x11, 0x94, - 0xd1, 0x8f, 0xe9, 0x3c, 0x12, 0x94, 0xe4, 0x97, 0x32, 0x30, 0x85, 0xc0, 0xe5, 0x47, 0xb4, 0x1d, - 0x20, 0xb3, 0x21, 0xe1, 0xb3, 0x16, 0x3e, 0x8c, 0xd6, 0x02, 0xcf, 0x69, 0xef, 0x89, 0x97, 0xd1, - 0x1d, 0xf1, 0x32, 0xfa, 0x2e, 0x7f, 0xd1, 0xbd, 0x5e, 0x77, 0x5b, 0x37, 0xf6, 0x3c, 0xfb, 0x91, - 0xc3, 0x4d, 0xb0, 0xec, 0xe6, 0x8d, 0x28, 0xdf, 0x4f, 0xc7, 0x89, 0x65, 0xe2, 0x11, 0xac, 0xf0, - 0xd5, 0x99, 0x7f, 0x28, 0xc5, 0x6a, 0xe3, 0xaa, 0x19, 0xfd, 0x8b, 0xc8, 0xf7, 0xc0, 0x05, 0x1e, - 0x9a, 0x8c, 0xdd, 0xf0, 0x9d, 0x76, 0xd7, 0xed, 0xfa, 0x4b, 0x76, 0xfd, 0x80, 0x89, 0xf9, 0xdc, - 0xb3, 0x18, 0x5b, 0x5e, 0x0f, 0x0b, 0xad, 0x1d, 0x5e, 0xaa, 0xc5, 0xbc, 0x48, 0x67, 0x40, 0x56, - 0x60, 0x86, 0x17, 0x95, 0xba, 0x81, 0x5b, 0xab, 0xdb, 0x4d, 0xa7, 0xbd, 0x87, 0xb2, 0x44, 0x9e, - 0x8b, 0x32, 0x76, 0x37, 0x70, 0x2d, 0x9f, 0xc3, 0x55, 0x4d, 0x4d, 0x82, 0x88, 0x54, 0x61, 0xda, - 0xa4, 0x76, 0x63, 0xcd, 0x7e, 0x5c, 0xb6, 0x3b, 0x76, 0xdd, 0x09, 0x78, 0xac, 0xd4, 0x1c, 0x17, - 0xe8, 0x3c, 0x6a, 0x37, 0xac, 0x96, 0xfd, 0xd8, 0xaa, 0x8b, 0x42, 0x5d, 0x65, 0xaf, 0xd1, 0x85, - 0xac, 0x9c, 0x76, 0xc8, 0x6a, 0x2c, 0xce, 0xca, 0x69, 0xf7, 0x66, 0x15, 0xd1, 0x49, 0x56, 0x9b, - 0xb6, 0xb7, 0x47, 0x03, 0x6e, 0x28, 0x0d, 0x97, 0x33, 0x57, 0x33, 0x0a, 0xab, 0x00, 0xcb, 0x2c, - 0x34, 0x9a, 0x8e, 0xb3, 0x52, 0xe8, 0xd8, 0xcc, 0xdb, 0xf6, 0x9c, 0x80, 0xaa, 0x2d, 0x1c, 0xc7, - 0xcf, 0xc2, 0xfe, 0x47, 0x13, 0xf3, 0x5e, 0x4d, 0x4c, 0x50, 0x46, 0xdc, 0x94, 0x46, 0x4e, 0x24, - 0xb8, 0xa5, 0xb7, 0x32, 0x41, 0x19, 0x72, 0x53, 0xdb, 0x39, 0x89, 0xed, 0x54, 0xb8, 0xf5, 0x68, - 0x68, 0x82, 0x92, 0xac, 0xb3, 0x4e, 0x0b, 0x98, 0xdc, 0xe4, 0xb6, 0x85, 0x05, 0xf7, 0x14, 0x7e, - 0xda, 0x2b, 0xc2, 0x0c, 0xb1, 0xe0, 0xc9, 0x62, 0x2b, 0xc5, 0x9e, 0x3b, 0x4e, 0x4c, 0xfe, 0x0a, - 0x4c, 0x6f, 0xf9, 0xf4, 0x4e, 0x75, 0xa3, 0x26, 0x23, 0x99, 0xa1, 0x72, 0x71, 0x6a, 0xf1, 0xe6, - 0x29, 0x9b, 0xce, 0x75, 0x95, 0x06, 0xd3, 0xe7, 0xf0, 0x71, 0xeb, 0xfa, 0xd4, 0xda, 0x75, 0x3a, - 0x7e, 0x18, 0x16, 0x52, 0x1d, 0xb7, 0x58, 0x55, 0xc6, 0x0a, 0xcc, 0x24, 0xd8, 0x90, 0x29, 0x00, - 0x06, 0xb4, 0xb6, 0xd6, 0x6b, 0xcb, 0x9b, 0x85, 0xe7, 0x48, 0x01, 0x26, 0xf0, 0xf7, 0xf2, 0x7a, - 0x69, 0x69, 0x75, 0xb9, 0x52, 0xc8, 0x90, 0x19, 0x98, 0x44, 0x48, 0xa5, 0x5a, 0xe3, 0xa0, 0x2c, - 0x4f, 0x9e, 0x60, 0x16, 0xf8, 0xd2, 0x0d, 0xd8, 0x02, 0xc0, 0x33, 0xc5, 0xf8, 0xdb, 0x59, 0xb8, - 0x28, 0x8f, 0x15, 0x1a, 0x30, 0xc1, 0xd1, 0x69, 0xef, 0x3d, 0xe3, 0xa7, 0xc3, 0x1d, 0xed, 0x74, - 0x78, 0x25, 0x76, 0x52, 0xc7, 0x5a, 0xd9, 0xe7, 0x88, 0xf8, 0xad, 0x31, 0x78, 0xb1, 0x2f, 0x15, - 0xf9, 0x22, 0x3b, 0xcd, 0x1d, 0xda, 0x0e, 0xaa, 0x8d, 0x26, 0xdd, 0x74, 0x5a, 0xd4, 0xed, 0x06, - 0xc2, 0x63, 0xe0, 0x65, 0xd4, 0xe7, 0x61, 0xa1, 0xe5, 0x34, 0x9a, 0xd4, 0x0a, 0x78, 0xb1, 0x36, - 0xdd, 0x92, 0xd4, 0x8c, 0x65, 0x98, 0xca, 0xab, 0xda, 0x0e, 0xa8, 0xf7, 0x08, 0xad, 0x12, 0x43, - 0x96, 0x07, 0x94, 0x76, 0x2c, 0x9b, 0x95, 0x5a, 0x8e, 0x28, 0xd6, 0x59, 0x26, 0xa8, 0xc9, 0x1d, - 0x85, 0x65, 0x99, 0xdd, 0xfe, 0xd7, 0xec, 0xc7, 0xc2, 0x4c, 0x4a, 0x44, 0xc6, 0x0d, 0x59, 0x72, - 0x77, 0xbe, 0x96, 0xfd, 0xd8, 0x4c, 0x92, 0x90, 0xaf, 0xc2, 0x39, 0x71, 0x00, 0x89, 0xe0, 0x2d, - 0xb2, 0xc5, 0x3c, 0x34, 0xcc, 0x6b, 0x27, 0xc7, 0xc5, 0x0b, 0x32, 0xa6, 0xb0, 0x0c, 0xac, 0x94, - 0xd6, 0xea, 0x74, 0x2e, 0x64, 0x93, 0x1d, 0xc8, 0xb1, 0xee, 0x58, 0xa3, 0xbe, 0x2f, 0x7d, 0x36, - 0xc5, 0xcd, 0x58, 0xed, 0x4c, 0xab, 0xc5, 0xcb, 0xcd, 0x9e, 0x94, 0x64, 0x05, 0xa6, 0xb6, 0xe9, - 0x8e, 0x3a, 0x3e, 0x23, 0xe1, 0x56, 0x55, 0x38, 0xa4, 0x3b, 0xbd, 0x07, 0x27, 0x46, 0x47, 0x1c, - 0x7c, 0x1f, 0x78, 0x7c, 0xb4, 0xea, 0xf8, 0x01, 0x6d, 0x53, 0x0f, 0xc3, 0xb7, 0x8d, 0xe2, 0x66, - 0x30, 0x1f, 0x49, 0xc8, 0x7a, 0xf9, 0xd2, 0x4b, 0x27, 0xc7, 0xc5, 0x17, 0xb9, 0xf3, 0x73, 0x53, - 0xc0, 0xad, 0x58, 0x22, 0xac, 0x24, 0x57, 0xf2, 0x75, 0x98, 0x36, 0xdd, 0x6e, 0xe0, 0xb4, 0xf7, - 0x6a, 0x81, 0x67, 0x07, 0x74, 0x8f, 0x1f, 0x48, 0x51, 0x9c, 0xb8, 0x58, 0xa9, 0x78, 0x5a, 0xe6, - 0x40, 0xcb, 0x17, 0x50, 0xed, 0x44, 0xd0, 0x09, 0xc8, 0xd7, 0x60, 0x8a, 0x87, 0xed, 0x08, 0x2b, - 0x18, 0xd3, 0x92, 0x78, 0xe8, 0x85, 0x0f, 0x6f, 0x0a, 0xab, 0x16, 0x84, 0xa6, 0x55, 0x10, 0xe3, - 0x46, 0xbe, 0x2c, 0x3a, 0x6b, 0xc3, 0x69, 0xef, 0x85, 0xd3, 0x18, 0xb0, 0xe7, 0xdf, 0x8c, 0xba, - 0xa4, 0xc3, 0x3e, 0x57, 0x4e, 0xe3, 0x1e, 0x26, 0x7a, 0x49, 0x3e, 0x24, 0x80, 0x17, 0x4b, 0xbe, - 0xef, 0xf8, 0x81, 0xf0, 0xab, 0x59, 0x7e, 0x4c, 0xeb, 0x5d, 0x86, 0xcc, 0xae, 0xb7, 0xd4, 0xe3, - 0x76, 0xdd, 0xc3, 0x4b, 0xd7, 0x4f, 0x8e, 0x8b, 0xaf, 0xdb, 0x88, 0x68, 0x09, 0x57, 0x1c, 0x8b, - 0x4a, 0x54, 0xeb, 0x90, 0xe3, 0x2a, 0x6d, 0xe8, 0xcf, 0x94, 0x7c, 0x0d, 0xce, 0x97, 0x6d, 0x9f, - 0x56, 0xdb, 0x3e, 0x6d, 0xfb, 0x4e, 0xe0, 0x3c, 0xa2, 0xa2, 0x53, 0xf1, 0xf0, 0xcb, 0x63, 0xca, - 0x30, 0xa3, 0x6e, 0xfb, 0x6c, 0x61, 0x86, 0x28, 0x96, 0x18, 0x14, 0xa5, 0x9a, 0x1e, 0x5c, 0x88, - 0x09, 0x53, 0xb5, 0xda, 0x4a, 0xc5, 0xb1, 0xc3, 0x75, 0x35, 0x89, 0xfd, 0xf5, 0x3a, 0xaa, 0xf6, - 0xfc, 0x7d, 0xab, 0xe1, 0xd8, 0xe1, 0x82, 0xea, 0xd1, 0x59, 0x31, 0x0e, 0xc6, 0x71, 0x06, 0x0a, - 0xf1, 0xa1, 0x24, 0x5f, 0x82, 0x31, 0x6e, 0xdf, 0x46, 0xfd, 0x7d, 0x11, 0x79, 0x42, 0x9a, 0x4b, - 0x85, 0x70, 0x9d, 0x48, 0xb8, 0xd3, 0x71, 0xeb, 0x39, 0xaa, 0x5a, 0xcb, 0xa0, 0x3b, 0x9d, 0x24, - 0x22, 0x0d, 0x98, 0xe0, 0xa3, 0x45, 0x31, 0x48, 0xa4, 0x30, 0x73, 0x7e, 0x49, 0x5d, 0x1d, 0xa2, - 0x28, 0xc6, 0x1f, 0x5f, 0x0d, 0xc5, 0x9c, 0xe0, 0x08, 0x5a, 0x15, 0x1a, 0xd7, 0x25, 0x80, 0xbc, - 0x24, 0x34, 0x2e, 0xc2, 0x85, 0x1e, 0xdf, 0x6c, 0x3c, 0x42, 0x4b, 0x82, 0x1e, 0x35, 0x92, 0x2f, - 0xc1, 0x1c, 0x12, 0x96, 0xdd, 0x76, 0x9b, 0xd6, 0x03, 0xdc, 0x8e, 0xa4, 0xf6, 0x3d, 0xc7, 0x2d, - 0x5d, 0x78, 0x7b, 0xeb, 0x21, 0x82, 0x15, 0x57, 0xc2, 0xa7, 0x72, 0x30, 0x7e, 0x2e, 0x0b, 0xf3, - 0x62, 0x87, 0x33, 0x69, 0xdd, 0xf5, 0x1a, 0xcf, 0xfe, 0x89, 0xba, 0xac, 0x9d, 0xa8, 0x2f, 0x87, - 0x61, 0x8b, 0xd2, 0x1a, 0xd9, 0xe7, 0x40, 0xfd, 0xd5, 0x0c, 0xbc, 0xd0, 0x8f, 0x88, 0xf5, 0x4e, - 0x18, 0x14, 0x73, 0x2c, 0x11, 0xfc, 0xb2, 0x03, 0xb3, 0x38, 0xa0, 0xe5, 0x7d, 0x5a, 0x3f, 0xf0, - 0x57, 0x5c, 0x3f, 0x40, 0x4f, 0x8b, 0x6c, 0x8f, 0xb7, 0xee, 0x37, 0x52, 0xdf, 0xba, 0xcf, 0xf3, - 0x59, 0x56, 0x47, 0x1e, 0x3c, 0x6c, 0xe7, 0x01, 0x3d, 0xf2, 0xcd, 0x34, 0xd6, 0x68, 0x31, 0x5f, - 0xea, 0x06, 0xfb, 0x1b, 0x1e, 0xdd, 0xa5, 0x1e, 0x6d, 0xd7, 0xe9, 0x77, 0x99, 0xc5, 0xbc, 0xde, - 0xb8, 0x81, 0x34, 0x18, 0xff, 0x64, 0x12, 0xe6, 0xd2, 0xc8, 0x58, 0xbf, 0x28, 0x97, 0xe6, 0x78, - 0x46, 0xd3, 0x1f, 0xc8, 0xc0, 0x44, 0x8d, 0xd6, 0xdd, 0x76, 0xe3, 0x0e, 0x5a, 0x14, 0x89, 0xde, - 0xb1, 0xb8, 0xd0, 0xc0, 0xe0, 0xd6, 0x6e, 0xcc, 0xd4, 0xe8, 0x3b, 0xc7, 0xc5, 0x2f, 0x0c, 0x76, - 0x57, 0xad, 0xbb, 0x18, 0x2e, 0x28, 0xc0, 0x8c, 0x1b, 0x61, 0x15, 0xf8, 0x38, 0xa8, 0x55, 0x4a, - 0x96, 0x60, 0x52, 0x2c, 0x57, 0x57, 0x8d, 0x89, 0xca, 0x23, 0x3b, 0xc9, 0x82, 0x84, 0xea, 0x5a, - 0x23, 0x21, 0xb7, 0x20, 0xb7, 0xb5, 0x78, 0x47, 0x8c, 0x81, 0xcc, 0x59, 0xb2, 0xb5, 0x78, 0x07, - 0xd5, 0x61, 0xec, 0x8a, 0x31, 0xd9, 0x5d, 0xd4, 0x8c, 0x7c, 0xb6, 0x16, 0xef, 0x90, 0xbf, 0x0a, - 0xe7, 0x2a, 0x8e, 0x2f, 0xaa, 0xe0, 0xbe, 0x1b, 0x0d, 0xf4, 0x58, 0x1c, 0xe9, 0x31, 0x7b, 0x3f, - 0x9b, 0x3a, 0x7b, 0x5f, 0x6a, 0x84, 0x4c, 0x2c, 0xee, 0x18, 0xd2, 0x88, 0xc7, 0x7e, 0x4d, 0xaf, - 0x87, 0x7c, 0x04, 0x53, 0xa8, 0xcc, 0x46, 0x77, 0x16, 0x8c, 0xda, 0x3f, 0xda, 0xa3, 0xe6, 0x4f, - 0xa7, 0xd6, 0xbc, 0xc0, 0xe3, 0x6d, 0xa0, 0x53, 0x0c, 0x46, 0xf8, 0xd7, 0x6e, 0xfd, 0x1a, 0x67, - 0x72, 0x0f, 0xa6, 0x85, 0xf8, 0xf5, 0x60, 0x77, 0x73, 0x9f, 0x56, 0xec, 0x23, 0x61, 0x9f, 0x83, - 0x37, 0x3a, 0x21, 0xb3, 0x59, 0xee, 0xae, 0x15, 0xec, 0x53, 0xab, 0x61, 0x6b, 0x82, 0x4a, 0x8c, - 0x90, 0x7c, 0x13, 0xc6, 0x57, 0xdd, 0x3a, 0x93, 0xbc, 0x71, 0x67, 0xe0, 0x26, 0x3b, 0x1f, 0x62, - 0xce, 0x4c, 0x0e, 0x8e, 0x89, 0x53, 0xdf, 0x39, 0x2e, 0xbe, 0x73, 0xd6, 0x49, 0xa3, 0x54, 0x60, - 0xaa, 0xb5, 0x91, 0x32, 0xe4, 0xb7, 0xe9, 0x0e, 0x6b, 0x6d, 0x3c, 0x9f, 0x9e, 0x04, 0x0b, 0x8b, - 0x3c, 0xf1, 0x4b, 0xb3, 0xc8, 0x13, 0x30, 0xe2, 0xc1, 0x0c, 0xf6, 0xcf, 0x86, 0xed, 0xfb, 0x87, - 0xae, 0xd7, 0xc0, 0xc4, 0x29, 0xbd, 0xac, 0x81, 0x16, 0x53, 0x3b, 0xff, 0x05, 0xde, 0xf9, 0x1d, - 0x85, 0x83, 0x2a, 0x40, 0x26, 0xd8, 0x93, 0xaf, 0xc3, 0x94, 0x88, 0x5d, 0xb0, 0x76, 0xa7, 0x84, - 0xab, 0x72, 0x42, 0xf3, 0xfb, 0xd4, 0x0b, 0xb9, 0x94, 0x2a, 0x42, 0x21, 0x48, 0x0d, 0x94, 0xd5, - 0xda, 0xb5, 0x75, 0xa5, 0xbf, 0x4a, 0x42, 0x36, 0x60, 0xbc, 0x82, 0x59, 0x9d, 0xd1, 0x37, 0x4d, - 0xd8, 0x85, 0x87, 0x09, 0xc1, 0xa2, 0x12, 0xae, 0x8b, 0x11, 0x09, 0xa0, 0xd1, 0xd3, 0x4d, 0xb7, - 0xd5, 0x0d, 0x11, 0xc9, 0x6d, 0xc8, 0x55, 0x2b, 0x1b, 0xc2, 0x2c, 0x7c, 0x26, 0x8c, 0x10, 0xb2, - 0x21, 0xd3, 0x27, 0xa1, 0xfd, 0x9c, 0xd3, 0xd0, 0x8c, 0xca, 0xab, 0x95, 0x0d, 0xb2, 0x0b, 0x93, - 0xd8, 0x01, 0x2b, 0xd4, 0xe6, 0x7d, 0x3b, 0xdd, 0xa3, 0x6f, 0xaf, 0xa7, 0xf6, 0xed, 0x3c, 0xef, - 0xdb, 0x7d, 0x41, 0xad, 0xe5, 0x83, 0x51, 0xd9, 0x32, 0x91, 0x56, 0xe4, 0xa8, 0x92, 0x59, 0x4c, - 0x36, 0x57, 0xd1, 0x3e, 0x48, 0x88, 0xb4, 0x32, 0xa5, 0x55, 0x98, 0x56, 0xa5, 0xa7, 0xd7, 0x49, - 0x92, 0x0f, 0xf9, 0x3c, 0x0c, 0x3d, 0x38, 0x08, 0x6c, 0x61, 0x00, 0x2e, 0xfb, 0x91, 0x81, 0x64, - 0xf3, 0x51, 0x0b, 0xe9, 0x1e, 0x68, 0x31, 0xe7, 0x90, 0x86, 0x0d, 0xc5, 0x8a, 0xed, 0x35, 0x0e, - 0x6d, 0x0f, 0x1d, 0x84, 0x67, 0x35, 0x16, 0x4a, 0x09, 0x1f, 0x8a, 0x7d, 0x01, 0x88, 0x79, 0x0d, - 0xab, 0x2c, 0xc8, 0xf7, 0xc0, 0x45, 0xdf, 0xd9, 0x6b, 0xdb, 0x41, 0xd7, 0xa3, 0x96, 0xdd, 0xdc, - 0x73, 0x3d, 0x27, 0xd8, 0x6f, 0x59, 0x7e, 0xd7, 0x09, 0xe8, 0xfc, 0x9c, 0x96, 0xd1, 0xba, 0x26, - 0xf1, 0x4a, 0x12, 0xad, 0xc6, 0xb0, 0xcc, 0x0b, 0x7e, 0x7a, 0x01, 0xf9, 0x32, 0x4c, 0xaa, 0x5b, - 0xb2, 0x3f, 0x7f, 0xee, 0x72, 0xee, 0xea, 0x54, 0x78, 0xf1, 0x88, 0x6f, 0xe0, 0x32, 0x12, 0xb4, - 0x72, 0x42, 0xf8, 0x7a, 0x24, 0x68, 0x85, 0x57, 0x98, 0x23, 0x92, 0x14, 0x66, 0xcd, 0x19, 0x31, - 0x63, 0x45, 0x2f, 0xaf, 0xdd, 0x29, 0x99, 0xa3, 0x1b, 0xd5, 0x87, 0xb5, 0xa6, 0x1b, 0x18, 0xff, - 0x45, 0x06, 0x37, 0x71, 0xf2, 0x3a, 0x06, 0x92, 0x0a, 0x5f, 0xcf, 0x50, 0x7f, 0x6b, 0x77, 0x62, - 0x69, 0x04, 0x38, 0x0a, 0x79, 0x03, 0x46, 0xee, 0xd8, 0x75, 0x19, 0xc4, 0x46, 0x20, 0xef, 0x22, - 0x44, 0x55, 0xf6, 0x72, 0x1c, 0x26, 0x5f, 0xf2, 0xc9, 0x5d, 0x8a, 0x92, 0xa5, 0x97, 0x4b, 0xf2, - 0xb9, 0x1e, 0xe5, 0x4b, 0xb1, 0x28, 0x94, 0x6c, 0xea, 0x31, 0xab, 0xf8, 0x54, 0x0e, 0xc6, 0x9f, - 0x64, 0xa2, 0x5d, 0x89, 0xbc, 0x06, 0x43, 0xe6, 0x46, 0xf8, 0xfd, 0xdc, 0xe9, 0x37, 0xf6, 0xf9, - 0x88, 0x40, 0xbe, 0x0c, 0xe7, 0x14, 0x3e, 0x09, 0x13, 0xfd, 0x57, 0xd1, 0x27, 0x55, 0xf9, 0x92, - 0x74, 0x3b, 0xfd, 0x74, 0x1e, 0x28, 0x4c, 0x47, 0x05, 0x15, 0xda, 0x76, 0x38, 0x6f, 0xa5, 0xb1, - 0x2a, 0xef, 0x06, 0x22, 0xc4, 0x1b, 0x9b, 0xc6, 0x81, 0xbb, 0xa4, 0x1a, 0xbf, 0x99, 0xd1, 0x76, - 0x9b, 0x30, 0xbb, 0x74, 0xe6, 0x94, 0xec, 0xd2, 0x6f, 0x03, 0x94, 0xba, 0x81, 0xbb, 0xdc, 0xf6, - 0xdc, 0x26, 0xd7, 0xa2, 0x88, 0x4c, 0x1a, 0xa8, 0x1b, 0xa6, 0x08, 0xd6, 0x3c, 0xe7, 0x42, 0xe4, - 0x54, 0x6f, 0x86, 0xdc, 0xc7, 0xf5, 0x66, 0x30, 0x7e, 0x2f, 0xa3, 0xad, 0x51, 0x26, 0x25, 0x8a, - 0xa9, 0xa8, 0x5a, 0x8c, 0x75, 0x9c, 0x47, 0x96, 0xdf, 0x74, 0xb5, 0x70, 0x15, 0x02, 0x8d, 0xfc, - 0xbb, 0x19, 0x38, 0xcf, 0xdd, 0x02, 0xd6, 0xbb, 0xad, 0x1d, 0xea, 0x3d, 0xb4, 0x9b, 0x4e, 0x23, - 0x0a, 0xd3, 0x17, 0x99, 0x0f, 0x2a, 0xd5, 0xa4, 0xe3, 0xf3, 0x8b, 0x2a, 0x77, 0x53, 0xb0, 0xda, - 0x58, 0x68, 0x3d, 0x0a, 0x4b, 0xd5, 0x8b, 0x6a, 0x3a, 0xbd, 0xf1, 0x6b, 0x19, 0x78, 0xe9, 0xd4, - 0x5a, 0xc8, 0x0d, 0x18, 0x95, 0x29, 0x4c, 0x32, 0xd8, 0xf1, 0x68, 0x67, 0x9b, 0x4c, 0x5f, 0x22, - 0xb1, 0xc8, 0x57, 0xe0, 0x9c, 0xca, 0x6a, 0xd3, 0xb3, 0x1d, 0x35, 0x51, 0x48, 0xca, 0x57, 0x07, - 0x0c, 0x25, 0x2e, 0xad, 0xa5, 0x33, 0x31, 0xfe, 0xdf, 0x8c, 0x92, 0x6f, 0xfe, 0x19, 0x95, 0xe1, - 0x6f, 0x6b, 0x32, 0xbc, 0x0c, 0x52, 0x1a, 0xb6, 0x8a, 0x95, 0xa5, 0xde, 0xbb, 0xa6, 0x15, 0x7b, - 0x71, 0x04, 0xfc, 0x70, 0x16, 0xc6, 0xb7, 0x7c, 0xea, 0xf1, 0x87, 0xdc, 0xef, 0xae, 0x50, 0x8d, - 0x61, 0xbb, 0x06, 0x0a, 0xa6, 0xf7, 0x47, 0x19, 0x54, 0xf0, 0xab, 0x14, 0xac, 0x37, 0x94, 0x1c, - 0x93, 0xd8, 0x1b, 0x98, 0x5d, 0x12, 0xa1, 0x3c, 0xb4, 0xd8, 0xaa, 0x9e, 0x6e, 0x16, 0x73, 0x0e, - 0xaf, 0x92, 0x2f, 0xc0, 0xf0, 0x16, 0xaa, 0x2b, 0xf5, 0x20, 0x1b, 0x21, 0x7f, 0x2c, 0xe4, 0x9b, - 0x74, 0xd7, 0xd7, 0xe3, 0xce, 0x71, 0x42, 0x52, 0x83, 0xd1, 0xb2, 0x47, 0x31, 0x7b, 0xfc, 0xd0, - 0xe0, 0x2e, 0xe2, 0x75, 0x4e, 0x12, 0x77, 0x11, 0x17, 0x9c, 0x8c, 0x9f, 0xcd, 0x02, 0x89, 0xda, - 0x88, 0xa9, 0xd2, 0xfc, 0x67, 0x76, 0xd0, 0x3f, 0xd0, 0x06, 0xfd, 0xc5, 0xc4, 0xa0, 0xf3, 0xe6, - 0x0d, 0x34, 0xf6, 0xbf, 0x9d, 0x81, 0xf3, 0xe9, 0x84, 0xe4, 0x65, 0x18, 0x79, 0xb0, 0xb9, 0x21, - 0xe3, 0xb4, 0x88, 0xa6, 0xb8, 0x1d, 0xd4, 0x15, 0x98, 0xa2, 0x88, 0xbc, 0x09, 0x23, 0x5f, 0x34, - 0xcb, 0xec, 0x1c, 0x52, 0x92, 0x71, 0x7c, 0xc3, 0xb3, 0xea, 0xfa, 0x51, 0x24, 0x90, 0xd4, 0xb1, - 0xcd, 0x3d, 0xb5, 0xb1, 0xfd, 0x89, 0x2c, 0x4c, 0x97, 0xea, 0x75, 0xea, 0xfb, 0x22, 0xd0, 0xfc, - 0x33, 0x3b, 0xb0, 0xe9, 0x11, 0x58, 0xb4, 0xb6, 0x0d, 0x34, 0xaa, 0xbf, 0x93, 0x81, 0x73, 0x92, - 0xea, 0x91, 0x43, 0x0f, 0x37, 0xf7, 0x3d, 0xea, 0xef, 0xbb, 0xcd, 0xc6, 0xc0, 0x19, 0x7f, 0x98, - 0xa0, 0x87, 0xc1, 0xe1, 0xd5, 0x57, 0xfd, 0x5d, 0x84, 0x68, 0x82, 0x1e, 0x0f, 0x20, 0x7f, 0x03, - 0x46, 0x4b, 0x9d, 0x8e, 0xe7, 0x3e, 0xe2, 0xcb, 0x5e, 0x44, 0x96, 0xb4, 0x39, 0x48, 0xf3, 0xb0, - 0xe7, 0x20, 0xf6, 0x19, 0x15, 0xda, 0xe6, 0xa1, 0xfc, 0x26, 0xf9, 0x67, 0x34, 0x68, 0x5b, 0x95, - 0xc5, 0xb1, 0xdc, 0xa8, 0x01, 0xd9, 0xf0, 0xdc, 0x96, 0x1b, 0xd0, 0x06, 0x6f, 0x0f, 0x06, 0x26, - 0x38, 0x35, 0xa4, 0xd6, 0xa6, 0x13, 0x34, 0xb5, 0x90, 0x5a, 0x01, 0x03, 0x98, 0x1c, 0x6e, 0xfc, - 0xdf, 0xc3, 0x30, 0xa1, 0xf6, 0x0e, 0x31, 0x78, 0x1a, 0x0f, 0xd7, 0x53, 0xa3, 0x63, 0xd8, 0x08, - 0x31, 0x45, 0x49, 0x14, 0x5a, 0x26, 0x7b, 0x6a, 0x68, 0x99, 0x6d, 0x98, 0xdc, 0xf0, 0x5c, 0x0c, - 0x81, 0x89, 0xaf, 0x95, 0x62, 0x2b, 0x9c, 0x55, 0xee, 0x9d, 0x6c, 0x20, 0xf1, 0x3d, 0x14, 0x25, - 0xfb, 0x8e, 0xc0, 0xc6, 0xe4, 0x96, 0x9a, 0xd6, 0x45, 0xe3, 0xc3, 0x4d, 0x2d, 0x6c, 0x5f, 0xc4, - 0xb1, 0x0d, 0x4d, 0x2d, 0x18, 0x44, 0x37, 0xb5, 0x60, 0x10, 0x75, 0xad, 0x0d, 0x3f, 0xad, 0xb5, - 0x46, 0x7e, 0x36, 0x03, 0xe3, 0xa5, 0x76, 0x5b, 0x84, 0xac, 0x39, 0xc5, 0x5b, 0xff, 0x2b, 0xc2, - 0xda, 0xe2, 0x9d, 0x8f, 0x65, 0x6d, 0x81, 0x72, 0x8b, 0x8f, 0x92, 0x6a, 0x54, 0xa1, 0x7a, 0x5b, - 0x53, 0xbe, 0x83, 0xbc, 0x03, 0x85, 0x70, 0x92, 0x57, 0xdb, 0x0d, 0xfa, 0x98, 0xf2, 0x34, 0x88, - 0x93, 0x22, 0xae, 0xb6, 0x2a, 0x99, 0xc6, 0x11, 0xc9, 0x26, 0x80, 0x1d, 0xce, 0xae, 0x58, 0x3e, - 0xd7, 0xe4, 0xf4, 0x13, 0xd2, 0x33, 0xfe, 0xc6, 0x07, 0x2d, 0x55, 0x7a, 0x8e, 0xf8, 0x90, 0x16, - 0x4c, 0xf3, 0x64, 0xaa, 0xb5, 0xc0, 0xf6, 0x02, 0x4c, 0x45, 0x01, 0xa7, 0x8e, 0xc3, 0x6b, 0x42, - 0x7f, 0xf6, 0xbc, 0x48, 0xd1, 0xea, 0x33, 0x5a, 0x2b, 0x25, 0x2f, 0x45, 0x9c, 0x37, 0x8f, 0x62, - 0x6e, 0x5e, 0x48, 0x7e, 0x2f, 0x9f, 0xf4, 0x3f, 0x91, 0x81, 0xf3, 0xea, 0xa4, 0xaf, 0x75, 0x77, - 0x44, 0xe8, 0x50, 0x72, 0x1d, 0xc6, 0xc4, 0x9c, 0x0c, 0x2f, 0x51, 0xc9, 0x8c, 0x1a, 0x11, 0x0a, - 0x59, 0x66, 0xd3, 0x90, 0xf1, 0x10, 0x52, 0xf7, 0x6c, 0x6c, 0x9f, 0x62, 0x45, 0x51, 0xa2, 0x6e, - 0x0f, 0x7f, 0xeb, 0xf3, 0x93, 0x41, 0x8c, 0xf7, 0x61, 0x46, 0x1f, 0x89, 0x1a, 0x0d, 0xc8, 0x35, - 0x18, 0x95, 0xc3, 0x97, 0x49, 0x1f, 0x3e, 0x59, 0x6e, 0x6c, 0x03, 0x49, 0xd0, 0xfb, 0x68, 0x16, - 0xc5, 0xee, 0xa7, 0xdc, 0x6c, 0x4f, 0x3e, 0x4a, 0x26, 0x10, 0x97, 0x66, 0xc5, 0xf7, 0x8d, 0x6b, - 0x6e, 0x09, 0x18, 0x46, 0xf5, 0x4f, 0xa6, 0x60, 0x36, 0x65, 0xcf, 0x3d, 0x45, 0x26, 0x2a, 0xea, - 0x1b, 0xc4, 0x58, 0x18, 0xec, 0x43, 0x6e, 0x0b, 0xef, 0xc3, 0xf0, 0xa9, 0xdb, 0x01, 0x77, 0x4a, - 0x89, 0xed, 0x02, 0x9c, 0xec, 0x13, 0x91, 0x8b, 0xd4, 0x78, 0x3c, 0xc3, 0x4f, 0x2d, 0x1e, 0xcf, - 0x12, 0x4c, 0x8a, 0x56, 0x89, 0xed, 0x4a, 0x31, 0x8e, 0x96, 0x19, 0x62, 0x12, 0xdb, 0x96, 0x4e, - 0xc2, 0x79, 0xf8, 0x6e, 0xf3, 0x11, 0x15, 0x3c, 0x46, 0x55, 0x1e, 0x58, 0x90, 0xca, 0x43, 0x21, - 0x21, 0xff, 0x31, 0x26, 0x72, 0x44, 0x88, 0xba, 0x67, 0xe5, 0xfb, 0xed, 0x59, 0x8d, 0xa7, 0xb3, - 0x67, 0xbd, 0x28, 0xbf, 0x31, 0x7d, 0xef, 0x4a, 0xf9, 0x2c, 0xf2, 0xcb, 0x19, 0x98, 0xe1, 0x41, - 0x61, 0xd4, 0x8f, 0xed, 0x1b, 0xe8, 0xa3, 0xfe, 0x74, 0x3e, 0xf6, 0x05, 0x91, 0x1b, 0x28, 0xfd, - 0x5b, 0x93, 0x1f, 0x45, 0xbe, 0x07, 0x20, 0x5c, 0x51, 0x3c, 0x94, 0xec, 0xf8, 0xe2, 0x0b, 0x29, - 0xbb, 0x40, 0x88, 0x14, 0xa5, 0xf0, 0x08, 0x42, 0x3a, 0x2d, 0x7d, 0x67, 0x08, 0x25, 0x7f, 0x15, - 0xe6, 0xd8, 0x7a, 0x09, 0x21, 0x22, 0x84, 0xd5, 0xfc, 0x38, 0xd6, 0xf2, 0x99, 0xde, 0x32, 0xd1, - 0xf5, 0x34, 0x32, 0x1e, 0x78, 0x38, 0xca, 0xa4, 0x1e, 0xa8, 0xd1, 0x2e, 0x52, 0x2b, 0xc2, 0xc8, - 0x70, 0xf8, 0xf5, 0x3c, 0xcd, 0x46, 0x8f, 0xfd, 0xed, 0xa2, 0x5c, 0x0b, 0x7c, 0x7f, 0xf3, 0x75, - 0x1f, 0x65, 0x04, 0x91, 0x2f, 0x02, 0x09, 0xa3, 0xa9, 0x70, 0x18, 0x95, 0x29, 0x38, 0xb8, 0xba, - 0x39, 0x8a, 0xca, 0xe2, 0xc9, 0x62, 0x75, 0x92, 0x24, 0x89, 0x09, 0x85, 0x39, 0xd1, 0x68, 0x06, - 0x95, 0x59, 0x16, 0xfd, 0xf9, 0x29, 0x2d, 0x40, 0x58, 0x54, 0x12, 0xa5, 0x5c, 0x57, 0x52, 0x35, - 0x6a, 0x2a, 0xa7, 0x34, 0x76, 0xe4, 0x36, 0x8c, 0xa1, 0xa3, 0xf0, 0x8a, 0x34, 0xf6, 0x12, 0x86, - 0x27, 0xe8, 0x52, 0x6c, 0xed, 0xeb, 0x26, 0x5b, 0x11, 0x2a, 0xbb, 0x0e, 0x54, 0xbc, 0x23, 0xb3, - 0xdb, 0x46, 0xa5, 0xb0, 0xd0, 0x77, 0x34, 0xbc, 0x23, 0xcb, 0xeb, 0xea, 0x9e, 0xe4, 0x88, 0x44, - 0xbe, 0x0e, 0xe3, 0x6b, 0xf6, 0xe3, 0x30, 0xcf, 0xd4, 0xcc, 0xe0, 0xd9, 0xac, 0x5a, 0xf6, 0xe3, - 0x30, 0xc9, 0x54, 0x3c, 0x9b, 0x95, 0xc2, 0x92, 0x7c, 0x15, 0x40, 0xd1, 0x54, 0x93, 0x53, 0x2b, - 0x78, 0x49, 0x86, 0xbd, 0x4b, 0xd5, 0x60, 0x23, 0x7f, 0x85, 0x61, 0x4c, 0x72, 0x98, 0xfb, 0xe4, - 0x24, 0x87, 0x73, 0x9f, 0x9c, 0xe4, 0xb0, 0xb0, 0x03, 0x17, 0x7b, 0x2e, 0x9d, 0x94, 0xa0, 0xc7, - 0x37, 0xf4, 0xa0, 0xc7, 0x17, 0x7b, 0x1d, 0xb1, 0xbe, 0x9e, 0x69, 0x65, 0xb6, 0x30, 0xd7, 0x5b, - 0x3a, 0xf9, 0x76, 0x36, 0x76, 0xe4, 0x8a, 0x8b, 0x05, 0xcf, 0xf2, 0xd5, 0x4b, 0x26, 0xc9, 0x62, - 0x0a, 0x6e, 0x7e, 0x28, 0x2b, 0x71, 0xe1, 0xd9, 0xa1, 0xac, 0x1e, 0xea, 0x78, 0x3c, 0x3f, 0xe9, - 0xe9, 0xfb, 0x2e, 0x4c, 0xf1, 0xac, 0xb9, 0xf7, 0xe9, 0xd1, 0xa1, 0xeb, 0x35, 0x78, 0xfe, 0x22, - 0x21, 0x83, 0x27, 0x52, 0xde, 0xc7, 0x70, 0x49, 0x45, 0xfa, 0x9e, 0x0e, 0x63, 0xed, 0x17, 0x53, - 0x77, 0x31, 0x86, 0xd0, 0xcf, 0x2d, 0x95, 0xbc, 0x15, 0x0a, 0x6a, 0xd4, 0x53, 0xf3, 0xad, 0x78, - 0x12, 0x98, 0x22, 0xaf, 0x51, 0xcf, 0xf8, 0x97, 0x39, 0x20, 0xbc, 0xa6, 0xb2, 0xdd, 0xb1, 0xd1, - 0x33, 0xdb, 0xc1, 0x58, 0x4b, 0x05, 0x81, 0x63, 0xef, 0x34, 0xa9, 0x1a, 0xa8, 0x4c, 0x18, 0xd7, - 0x86, 0x65, 0x56, 0xfc, 0xa2, 0x93, 0x20, 0xec, 0xb1, 0xd5, 0x65, 0x9f, 0x64, 0xab, 0xfb, 0x3a, - 0x3c, 0x5f, 0xea, 0x60, 0xfa, 0x6d, 0x59, 0xcb, 0x1d, 0xd7, 0x93, 0x9b, 0x94, 0xe6, 0xf3, 0x67, - 0x87, 0x68, 0x89, 0x2f, 0xed, 0xc7, 0x42, 0x91, 0x53, 0xd8, 0xbc, 0xec, 0x04, 0x6a, 0x0c, 0x09, - 0x29, 0xa7, 0x74, 0xb0, 0x24, 0x45, 0x4e, 0xe1, 0x24, 0x92, 0x87, 0xe3, 0x49, 0x39, 0x05, 0xb3, - 0x95, 0x45, 0x3c, 0x1c, 0x8f, 0xf6, 0x90, 0x75, 0x42, 0x12, 0xf2, 0x2e, 0x8c, 0x97, 0xba, 0x81, - 0x2b, 0x18, 0x0b, 0xab, 0xf0, 0xc8, 0x7e, 0x5b, 0x7c, 0x8a, 0x76, 0xf5, 0x89, 0xd0, 0x8d, 0x3f, - 0xce, 0xc1, 0xc5, 0xe4, 0xf0, 0x8a, 0xd2, 0x70, 0x7d, 0x64, 0x4e, 0x59, 0x1f, 0x69, 0xb3, 0x21, - 0x1b, 0x65, 0x9a, 0x78, 0x1a, 0xb3, 0x81, 0x67, 0xf1, 0xfe, 0x98, 0xb3, 0xa1, 0x06, 0xe3, 0xea, - 0x79, 0x37, 0xf4, 0x71, 0xcf, 0x3b, 0x95, 0x0b, 0xbb, 0xd4, 0xf3, 0xd0, 0x19, 0xc3, 0xd1, 0xd3, - 0x51, 0x3c, 0x6a, 0x06, 0xc7, 0x20, 0xff, 0x0e, 0x5c, 0xe6, 0x7b, 0x52, 0xbc, 0xb1, 0x4b, 0x47, - 0x92, 0xa3, 0x18, 0xb8, 0xc5, 0x93, 0xe3, 0xe2, 0x75, 0xae, 0x2a, 0xb1, 0x12, 0xdd, 0x66, 0xed, - 0x1c, 0x59, 0xf2, 0xcb, 0x94, 0x4a, 0x4e, 0xe5, 0x6d, 0x94, 0xe1, 0xa2, 0x28, 0x8d, 0x9c, 0xb6, - 0x65, 0x21, 0x1b, 0xe4, 0x83, 0x48, 0xdb, 0x85, 0x83, 0x1c, 0x53, 0x64, 0x61, 0x39, 0xe6, 0xff, - 0x56, 0x72, 0x33, 0xbf, 0x99, 0xe6, 0x73, 0xc3, 0xa3, 0x76, 0x73, 0xb0, 0xee, 0x6e, 0x23, 0x75, - 0x6a, 0xd9, 0x54, 0x9d, 0x9a, 0x54, 0xca, 0xe4, 0x52, 0x95, 0x32, 0x15, 0x98, 0xae, 0x75, 0x77, - 0x64, 0xdd, 0x71, 0x7f, 0x4d, 0xbf, 0xbb, 0x93, 0xd6, 0x2b, 0x71, 0x12, 0xe3, 0x47, 0xb2, 0x30, - 0xb1, 0xd1, 0xec, 0xee, 0x39, 0xed, 0x8a, 0x1d, 0xd8, 0xcf, 0xac, 0x9a, 0xef, 0x6d, 0x4d, 0xcd, - 0x17, 0xba, 0x96, 0x85, 0x0d, 0x1b, 0x48, 0xc7, 0xf7, 0x33, 0x19, 0x98, 0x8e, 0x48, 0xf8, 0x61, - 0xbd, 0x02, 0x43, 0xec, 0x87, 0xb8, 0xfc, 0x5e, 0x4e, 0x30, 0xe6, 0x69, 0x26, 0xc3, 0xbf, 0x84, - 0xe2, 0x4d, 0xcf, 0xe1, 0x86, 0x1c, 0x16, 0x3e, 0x0b, 0x63, 0x11, 0xdb, 0xb3, 0xa4, 0x97, 0xfc, - 0xf5, 0x0c, 0x14, 0xe2, 0x2d, 0x21, 0xf7, 0x61, 0x94, 0x71, 0x72, 0xa8, 0xbc, 0x97, 0xbf, 0xd2, - 0xa3, 0xcd, 0xd7, 0x05, 0x1a, 0xff, 0x3c, 0xec, 0x7c, 0xca, 0x21, 0xa6, 0xe4, 0xb0, 0x60, 0xc2, - 0x84, 0x8a, 0x95, 0xf2, 0x75, 0x6f, 0xe8, 0x12, 0xca, 0xf9, 0xf4, 0x7e, 0xd0, 0x92, 0x62, 0x6a, - 0x5f, 0x2d, 0x84, 0x8f, 0x2b, 0xda, 0xe4, 0x4a, 0x5d, 0x55, 0x38, 0x69, 0x16, 0xa3, 0x7c, 0x05, - 0xea, 0x3c, 0x4b, 0x99, 0xd0, 0x21, 0x1e, 0x79, 0x03, 0x46, 0x78, 0x7d, 0x6a, 0x42, 0xb7, 0x0e, - 0x42, 0x54, 0x39, 0x99, 0xe3, 0x18, 0x7f, 0x27, 0x07, 0xe7, 0xa3, 0xcf, 0xdb, 0xea, 0x34, 0xec, - 0x80, 0x6e, 0xd8, 0x9e, 0xdd, 0xf2, 0x4f, 0x59, 0x01, 0x57, 0x13, 0x9f, 0x86, 0xa9, 0xb4, 0xe4, - 0xa7, 0x29, 0x1f, 0x64, 0xc4, 0x3e, 0x08, 0x75, 0xa0, 0xfc, 0x83, 0xe4, 0x67, 0x90, 0xfb, 0x90, - 0xab, 0xd1, 0x40, 0xec, 0xbd, 0x57, 0x12, 0xbd, 0xaa, 0x7e, 0xd7, 0xf5, 0x1a, 0x0d, 0xf8, 0x20, - 0xf2, 0xb8, 0x50, 0x5a, 0x70, 0x3e, 0xc6, 0x85, 0x6c, 0xc3, 0xc8, 0xf2, 0xe3, 0x0e, 0xad, 0x07, - 0x22, 0x39, 0xea, 0xb5, 0xfe, 0xfc, 0x38, 0xae, 0x92, 0x1b, 0x95, 0x22, 0x40, 0xed, 0x2c, 0x8e, - 0xb2, 0x70, 0x1b, 0xf2, 0xb2, 0xf2, 0xb3, 0xcc, 0xdc, 0x85, 0xb7, 0x61, 0x5c, 0xa9, 0xe4, 0x4c, - 0x93, 0xfe, 0x17, 0xd8, 0xbe, 0xea, 0x36, 0x65, 0x3e, 0xd5, 0xe5, 0x84, 0xac, 0xa8, 0x64, 0xa3, - 0xe2, 0xb2, 0xa2, 0x75, 0x20, 0x8a, 0xfa, 0x08, 0x8d, 0x55, 0x98, 0xae, 0x1d, 0x38, 0x9d, 0x28, - 0x50, 0xac, 0x76, 0x22, 0x63, 0xc6, 0x1b, 0x71, 0x71, 0x8f, 0x9f, 0xc8, 0x71, 0x3a, 0xe3, 0xcf, - 0x32, 0x30, 0xc2, 0xfe, 0x7a, 0x78, 0xfb, 0x19, 0xdd, 0x32, 0x6f, 0x69, 0x5b, 0xe6, 0x8c, 0x12, - 0xab, 0x1d, 0x37, 0x8e, 0xdb, 0xa7, 0x6c, 0x96, 0xc7, 0x62, 0x80, 0x38, 0x32, 0xb9, 0x0b, 0xa3, - 0xc2, 0xa4, 0x48, 0xd8, 0x7e, 0xab, 0xc1, 0xdf, 0xa5, 0xb1, 0x51, 0x78, 0xc3, 0x77, 0x3b, 0x71, - 0x95, 0x88, 0xa4, 0x66, 0x72, 0xbd, 0x0c, 0xd9, 0xab, 0xe5, 0x4b, 0x77, 0xd1, 0x59, 0x8f, 0x87, - 0x2e, 0xf7, 0x97, 0x2e, 0x08, 0x4e, 0xbd, 0x7c, 0xeb, 0x4b, 0xe2, 0x35, 0x24, 0xd7, 0x8f, 0xc9, - 0x79, 0x99, 0xa4, 0x38, 0xf5, 0xa1, 0xa4, 0x05, 0xe7, 0x6b, 0xb5, 0x15, 0x34, 0x3f, 0xdc, 0x70, - 0xbd, 0xe0, 0x8e, 0xeb, 0x1d, 0xda, 0x68, 0x5b, 0x8c, 0x1a, 0x3e, 0xc5, 0x06, 0x21, 0xcd, 0x28, - 0xec, 0xb5, 0x54, 0xa3, 0xb0, 0x3e, 0x76, 0x0a, 0x46, 0x1b, 0x2e, 0xd4, 0x6a, 0x2b, 0x3c, 0x70, - 0xf8, 0x9f, 0x47, 0x7d, 0xbf, 0x9e, 0x81, 0x99, 0x5a, 0x6d, 0x25, 0x56, 0xd5, 0xaa, 0x8c, 0x58, - 0x9e, 0xd1, 0xf3, 0x7c, 0xa7, 0x76, 0x04, 0x8e, 0x42, 0x86, 0x4b, 0x78, 0x75, 0x2d, 0x38, 0x25, - 0x67, 0x42, 0x36, 0xc2, 0x18, 0xe9, 0x59, 0xcd, 0x1f, 0xa0, 0x47, 0x43, 0x51, 0xc3, 0x2d, 0xbc, - 0xe9, 0x58, 0xa9, 0xae, 0xe1, 0x66, 0x10, 0xe3, 0xbf, 0x39, 0xcf, 0xa3, 0xb0, 0xcb, 0xd9, 0xf2, - 0x1e, 0x4c, 0x08, 0x7a, 0x34, 0x9a, 0x17, 0x36, 0x21, 0x17, 0xd9, 0x06, 0xb9, 0xcb, 0xe1, 0x3c, - 0x3a, 0xef, 0x77, 0x8e, 0x8b, 0x43, 0xac, 0x6b, 0x4c, 0x0d, 0x9d, 0x3c, 0x80, 0xc9, 0x35, 0xfb, - 0xb1, 0xa2, 0xce, 0xe0, 0x2e, 0x51, 0xd7, 0xd8, 0xae, 0xd2, 0xb2, 0x1f, 0x0f, 0x60, 0x74, 0xa7, - 0xd3, 0x93, 0x03, 0x98, 0xd2, 0xdb, 0x24, 0x66, 0x60, 0x72, 0xc4, 0x6e, 0xa6, 0x8e, 0xd8, 0xc5, - 0x8e, 0xeb, 0x05, 0xd6, 0x6e, 0x48, 0xae, 0x65, 0x1c, 0x88, 0xb1, 0x26, 0xef, 0xc1, 0x8c, 0x12, - 0x02, 0xf4, 0x8e, 0xeb, 0xb5, 0x6c, 0x79, 0xe1, 0x42, 0x1d, 0x3f, 0xda, 0x12, 0xed, 0x22, 0xd8, - 0x4c, 0x62, 0x92, 0x2f, 0xa7, 0xb9, 0x99, 0x0d, 0x47, 0x96, 0x87, 0x29, 0x6e, 0x66, 0xbd, 0x2c, - 0x0f, 0x93, 0x0e, 0x67, 0x7b, 0xfd, 0x2c, 0x93, 0xf3, 0xbc, 0xf5, 0x03, 0x59, 0x1e, 0x87, 0x23, - 0xd7, 0xc3, 0x02, 0x79, 0x11, 0x72, 0x4b, 0x1b, 0x77, 0xf0, 0x65, 0x4a, 0x1a, 0x51, 0xb5, 0xf7, - 0xed, 0x76, 0x1d, 0x2f, 0x42, 0xc2, 0x1b, 0x40, 0x3d, 0x28, 0x97, 0x36, 0xee, 0x10, 0x1b, 0x66, - 0x31, 0xcf, 0x5b, 0xf0, 0xa5, 0x9b, 0x37, 0x95, 0xa1, 0xca, 0xe3, 0xa7, 0xdd, 0x10, 0x9f, 0x56, - 0xc4, 0x2c, 0x71, 0x81, 0xf5, 0xf8, 0xe6, 0xcd, 0xd4, 0x01, 0x09, 0x3f, 0x2c, 0x8d, 0x17, 0x3b, - 0xb0, 0xd6, 0xec, 0xc7, 0x91, 0x13, 0x87, 0x2f, 0x1c, 0x76, 0x5f, 0x94, 0x53, 0x2b, 0x72, 0x00, - 0xd1, 0x0e, 0x2c, 0x9d, 0x88, 0xdd, 0x63, 0xa3, 0x09, 0xe6, 0x0b, 0x57, 0xa7, 0x05, 0xa9, 0xae, - 0x93, 0x5e, 0xdd, 0xea, 0x65, 0x4c, 0x41, 0x27, 0x5b, 0xe1, 0x6d, 0x9c, 0xdf, 0x66, 0x45, 0x66, - 0xe4, 0x1b, 0xea, 0x6d, 0x9c, 0x2b, 0xc9, 0xb4, 0x66, 0x4d, 0x87, 0x2a, 0x1c, 0xee, 0xd5, 0x62, - 0xea, 0x5c, 0x92, 0x97, 0xfc, 0x89, 0xb3, 0x5f, 0xf2, 0x29, 0x0c, 0xad, 0xba, 0xf5, 0x03, 0x11, - 0x9c, 0xef, 0x8b, 0x6c, 0x17, 0xd6, 0xd3, 0xe8, 0x3f, 0xa9, 0xc5, 0x35, 0xb2, 0x27, 0xeb, 0xec, - 0x53, 0xd9, 0x2c, 0x10, 0x7d, 0x22, 0xac, 0x78, 0xe7, 0xc2, 0x5b, 0xae, 0x52, 0xc6, 0xe5, 0x51, - 0x3e, 0x69, 0x64, 0xd7, 0x9a, 0x3a, 0x39, 0xa1, 0x50, 0xa8, 0x50, 0xff, 0x20, 0x70, 0x3b, 0xe5, - 0xa6, 0xd3, 0xd9, 0x71, 0x6d, 0x4f, 0x86, 0x72, 0x1e, 0x78, 0x4f, 0x6e, 0x70, 0x7a, 0xab, 0x2e, - 0x19, 0x98, 0x09, 0x96, 0xe4, 0xcb, 0x30, 0xc5, 0x26, 0xf7, 0xf2, 0xe3, 0x80, 0xb6, 0xf9, 0xc8, - 0xcf, 0xa0, 0x44, 0x37, 0xa7, 0xe4, 0x2e, 0x09, 0x0b, 0xf9, 0x9c, 0xc2, 0xc5, 0x4e, 0x43, 0x02, - 0x2d, 0xb0, 0xa1, 0xc6, 0x8a, 0x34, 0x60, 0x7e, 0xcd, 0x7e, 0xac, 0xe4, 0x60, 0x56, 0x26, 0x29, - 0xc1, 0x09, 0x76, 0xf5, 0xe4, 0xb8, 0xf8, 0x0a, 0x9b, 0x60, 0x51, 0x74, 0xf1, 0x1e, 0xf3, 0xb5, - 0x27, 0x27, 0xf2, 0x4d, 0xb8, 0x20, 0x9a, 0x55, 0xc1, 0xbc, 0x61, 0xae, 0x77, 0x54, 0xdb, 0xb7, - 0xd1, 0x7f, 0x6b, 0xb6, 0x47, 0x87, 0xdd, 0x48, 0xdf, 0x12, 0x65, 0x87, 0x35, 0x24, 0x1f, 0xcb, - 0xe7, 0x8c, 0xcc, 0x5e, 0x35, 0x90, 0x8f, 0x60, 0x8a, 0x3f, 0xc7, 0xad, 0xb8, 0x7e, 0x80, 0xca, - 0x9a, 0xb9, 0xb3, 0xb9, 0x25, 0xf0, 0x37, 0x3e, 0xee, 0xc8, 0x13, 0x53, 0xee, 0xc4, 0x38, 0x93, - 0x77, 0x60, 0x7c, 0xc3, 0x69, 0xf3, 0xd0, 0xa3, 0xd5, 0x0d, 0x54, 0x2b, 0x8b, 0x13, 0xa8, 0xe3, - 0xb4, 0x2d, 0xa9, 0x31, 0xe9, 0x84, 0xdb, 0x85, 0x8a, 0x4d, 0xb6, 0x61, 0xbc, 0x56, 0x5b, 0xb9, - 0xe3, 0x30, 0xb9, 0xa4, 0x73, 0x34, 0x7f, 0xbe, 0xc7, 0x57, 0xbe, 0x9c, 0xfa, 0x95, 0x93, 0xbe, - 0xbf, 0x6f, 0xed, 0x3a, 0x4d, 0x6a, 0xd5, 0xdd, 0xce, 0x91, 0xa9, 0x72, 0x4a, 0x31, 0xd5, 0xbf, - 0xf0, 0x94, 0x4d, 0xf5, 0xab, 0x30, 0xad, 0x18, 0xcf, 0xa2, 0xe1, 0xec, 0x7c, 0x14, 0xaf, 0x4a, - 0x35, 0xcd, 0x8f, 0xbb, 0xa6, 0xc6, 0xe9, 0xa4, 0x8d, 0xfe, 0xc5, 0xb3, 0xda, 0xe8, 0x3b, 0x30, - 0xc3, 0x07, 0x43, 0xcc, 0x03, 0x1c, 0xe9, 0x85, 0x1e, 0x7d, 0x78, 0x2d, 0xb5, 0x0f, 0x67, 0xc5, - 0x48, 0xcb, 0x49, 0x86, 0xcf, 0xcf, 0x49, 0xae, 0x64, 0x17, 0x88, 0x00, 0xda, 0x81, 0xbd, 0x63, - 0xfb, 0x14, 0xeb, 0x7a, 0xbe, 0x47, 0x5d, 0xaf, 0xa4, 0xd6, 0x35, 0x25, 0xeb, 0xda, 0xe1, 0xd5, - 0xa4, 0x70, 0x24, 0x6d, 0x59, 0x8f, 0x9c, 0x5f, 0xd8, 0xb1, 0x2f, 0x68, 0x3a, 0xee, 0x24, 0x02, - 0x0f, 0xfd, 0x14, 0x9f, 0xb4, 0xf1, 0x7e, 0x4f, 0xe1, 0x4c, 0x1e, 0xc3, 0xf9, 0xe4, 0x57, 0x60, - 0x9d, 0x2f, 0x62, 0x9d, 0x2f, 0x6a, 0x75, 0xc6, 0x91, 0xf8, 0xbc, 0xd1, 0x9b, 0x15, 0xaf, 0xb5, - 0x07, 0x7f, 0xf2, 0x83, 0x19, 0xb8, 0xb0, 0x76, 0xa7, 0x84, 0xd9, 0x44, 0x1d, 0x1e, 0x89, 0x2e, - 0x74, 0xe9, 0xbd, 0x24, 0xde, 0x41, 0xe2, 0x6f, 0x33, 0x52, 0xe2, 0xc0, 0xad, 0x82, 0x89, 0xee, - 0x2f, 0xb7, 0x76, 0x6d, 0x9e, 0xa4, 0x54, 0xb0, 0x48, 0xf1, 0xfb, 0xfd, 0xd6, 0x1f, 0x16, 0x33, - 0x66, 0xaf, 0xaa, 0x48, 0x13, 0x16, 0xf4, 0x6e, 0x91, 0x5e, 0x14, 0xfb, 0xb4, 0xd9, 0x9c, 0x2f, - 0xe2, 0x8c, 0x7e, 0xe3, 0xe4, 0xb8, 0x78, 0x35, 0xd1, 0xbb, 0xa1, 0x67, 0x06, 0xc3, 0x54, 0x1a, - 0xdc, 0x87, 0x1f, 0x69, 0xa5, 0x08, 0xdd, 0xf3, 0x97, 0xb5, 0xd8, 0x3f, 0x89, 0xf2, 0xa5, 0x57, - 0x85, 0x44, 0xf2, 0x22, 0x5b, 0xef, 0x3d, 0x05, 0x44, 0x33, 0xc9, 0xf9, 0xde, 0x50, 0x7e, 0xb2, - 0x30, 0x95, 0xe2, 0xb2, 0x60, 0xfc, 0x56, 0x36, 0x76, 0x30, 0x92, 0x2a, 0x8c, 0x8a, 0xf9, 0xde, - 0xf3, 0x92, 0xf1, 0x62, 0xea, 0xac, 0x1e, 0x15, 0x4b, 0xc7, 0x94, 0xf4, 0xe4, 0x90, 0xb1, 0xc2, - 0x46, 0x8b, 0x1b, 0xef, 0x57, 0xf9, 0xb9, 0x87, 0x20, 0xed, 0x84, 0xaf, 0x9c, 0xdd, 0x11, 0x4f, - 0xf7, 0xf3, 0xc4, 0xa3, 0x5e, 0xd6, 0x46, 0x0e, 0x78, 0x2a, 0xa9, 0x5c, 0xe8, 0xcd, 0xa5, 0xe7, - 0x8d, 0x7a, 0x6a, 0x15, 0xb2, 0x5a, 0x8c, 0xdf, 0xcc, 0xc0, 0xa4, 0x76, 0xb2, 0x92, 0xdb, 0x8a, - 0xab, 0x62, 0xe4, 0xbd, 0xaf, 0xe1, 0xe0, 0x66, 0x1b, 0x77, 0x62, 0xbc, 0x2d, 0xfc, 0x0e, 0xb2, - 0xbd, 0xe9, 0x70, 0xb1, 0xc5, 0x3d, 0x57, 0xfb, 0xeb, 0x87, 0xc3, 0x3c, 0x98, 0x43, 0x3d, 0xf2, - 0x60, 0xfe, 0xfd, 0x22, 0x4c, 0xe9, 0x37, 0x62, 0xf2, 0x06, 0x8c, 0xa0, 0x6e, 0x5e, 0xaa, 0x57, - 0x50, 0x2d, 0x84, 0xea, 0x7b, 0xcd, 0x19, 0x85, 0xe3, 0x90, 0x57, 0x01, 0x42, 0x03, 0x70, 0xf9, - 0x32, 0x35, 0x7c, 0x72, 0x5c, 0xcc, 0xbc, 0x69, 0x2a, 0x05, 0xe4, 0x6b, 0x00, 0xeb, 0x6e, 0x83, - 0x86, 0xc9, 0x8d, 0xfb, 0x58, 0x5f, 0xbc, 0x96, 0x48, 0xb3, 0x72, 0xae, 0xed, 0x36, 0x68, 0x32, - 0xa7, 0x8a, 0xc2, 0x91, 0x7c, 0x1e, 0x86, 0xcd, 0x6e, 0x93, 0xca, 0x17, 0x8c, 0x71, 0x79, 0xc2, - 0x75, 0x9b, 0x34, 0xd2, 0x13, 0x78, 0xdd, 0xb8, 0x61, 0x21, 0x03, 0x90, 0x0f, 0x78, 0xfa, 0x15, - 0x11, 0x23, 0x74, 0x38, 0x7a, 0xab, 0x53, 0x24, 0x9f, 0x44, 0x94, 0x50, 0x85, 0x84, 0x3c, 0x80, - 0x51, 0xf5, 0x91, 0x49, 0xf1, 0x79, 0x57, 0x1f, 0x22, 0x15, 0xa5, 0x83, 0xc8, 0x8a, 0x1c, 0x7f, - 0x7f, 0x92, 0x5c, 0xc8, 0xbb, 0x30, 0xc6, 0xd8, 0xb3, 0x9d, 0xc3, 0x17, 0xb7, 0x1a, 0x7c, 0x91, - 0x53, 0x3e, 0x88, 0xed, 0x3e, 0x5a, 0x24, 0xcf, 0x90, 0x80, 0x7c, 0x19, 0xf3, 0xd8, 0x8a, 0xae, - 0xee, 0x6b, 0x95, 0x73, 0x25, 0xd1, 0xd5, 0x98, 0xd8, 0x36, 0xd1, 0xd3, 0x11, 0x3f, 0xb2, 0x17, - 0x86, 0x5c, 0x1b, 0x24, 0x65, 0xce, 0xeb, 0x89, 0x0a, 0xe6, 0x65, 0x14, 0xb1, 0x64, 0x92, 0x6a, - 0x8d, 0x2f, 0xe9, 0x40, 0x21, 0x12, 0x2a, 0x45, 0x5d, 0xd0, 0xaf, 0xae, 0x37, 0x13, 0x75, 0xa9, - 0x03, 0x98, 0xa8, 0x2e, 0xc1, 0x9d, 0x34, 0x60, 0x4a, 0x1e, 0x50, 0xa2, 0xbe, 0xf1, 0x7e, 0xf5, - 0xbd, 0x9a, 0xa8, 0x6f, 0xb6, 0xb1, 0x93, 0xac, 0x27, 0xc6, 0x93, 0xbc, 0x0b, 0x93, 0x12, 0xc2, - 0x53, 0x46, 0x4f, 0x44, 0x39, 0x77, 0x1b, 0x3b, 0x89, 0x44, 0xd1, 0x3a, 0xb2, 0x4a, 0xcd, 0x67, - 0xc7, 0xa4, 0x46, 0x1d, 0x9f, 0x15, 0x3a, 0x32, 0xf9, 0x10, 0xc6, 0xab, 0x2d, 0xd6, 0x10, 0xb7, - 0x6d, 0x07, 0x54, 0xf8, 0x43, 0x4a, 0x0b, 0x23, 0xa5, 0x44, 0x99, 0xaa, 0x3c, 0x19, 0x76, 0x54, - 0xa4, 0x25, 0xc3, 0x8e, 0xc0, 0xac, 0xf3, 0xf8, 0xab, 0xa2, 0x98, 0xc3, 0xd2, 0x57, 0xf2, 0xc5, - 0x14, 0x2b, 0x1f, 0x85, 0xbd, 0x88, 0x07, 0xc9, 0xa0, 0xf2, 0x55, 0x2f, 0x16, 0x8b, 0x57, 0xe5, - 0x49, 0xde, 0x83, 0x71, 0x91, 0x4d, 0xac, 0x64, 0xae, 0xfb, 0xf3, 0x05, 0x6c, 0x3c, 0x46, 0x78, - 0x90, 0x89, 0xc7, 0x2c, 0xdb, 0x8b, 0x99, 0xb3, 0x46, 0xf8, 0xe4, 0x4b, 0x30, 0xb7, 0xed, 0xb4, - 0x1b, 0xee, 0xa1, 0x2f, 0x8e, 0x29, 0xb1, 0xd1, 0xcd, 0x44, 0xce, 0x64, 0x87, 0xbc, 0x3c, 0x94, - 0x05, 0x13, 0x1b, 0x5f, 0x2a, 0x07, 0xf2, 0x7d, 0x09, 0xce, 0x7c, 0x06, 0x91, 0x7e, 0x33, 0x68, - 0x31, 0x31, 0x83, 0x92, 0xd5, 0xc7, 0xa7, 0x53, 0x6a, 0x35, 0xc4, 0x05, 0xa2, 0x9f, 0xef, 0xf7, - 0x5c, 0xa7, 0x3d, 0x3f, 0x8b, 0x7b, 0xe1, 0xf3, 0xf1, 0x98, 0x0a, 0x88, 0x27, 0x92, 0x8a, 0x1b, - 0x27, 0xc7, 0xc5, 0x4b, 0x71, 0x99, 0xff, 0x23, 0x57, 0x7b, 0x2e, 0x49, 0x61, 0x4d, 0x3e, 0x84, - 0x09, 0xf6, 0x7f, 0xa8, 0x94, 0x98, 0xd3, 0xec, 0x42, 0x15, 0x4c, 0x51, 0x0f, 0x8e, 0x11, 0xa6, - 0x3b, 0x4b, 0xd1, 0x57, 0x68, 0xac, 0xc8, 0xdb, 0x00, 0x4c, 0x6c, 0x12, 0xdb, 0xf1, 0xb9, 0x28, - 0xf4, 0x31, 0x4a, 0x5d, 0xc9, 0x8d, 0x38, 0x42, 0x26, 0xef, 0xc2, 0x38, 0xfb, 0x55, 0xeb, 0x36, - 0x5c, 0xb6, 0x36, 0xce, 0x23, 0x2d, 0x77, 0x4d, 0x65, 0xb4, 0x3e, 0x87, 0x6b, 0xae, 0xa9, 0x11, - 0x3a, 0x59, 0x81, 0x69, 0x0c, 0x51, 0x2d, 0x82, 0xa3, 0x3a, 0xd4, 0x9f, 0xbf, 0xa0, 0x58, 0x43, - 0xb0, 0x22, 0xcb, 0x09, 0xcb, 0xd4, 0xbb, 0x4c, 0x8c, 0x8c, 0xf8, 0x30, 0x9b, 0x7c, 0x4e, 0xf6, - 0xe7, 0xe7, 0xb1, 0x93, 0xa4, 0x04, 0x9f, 0xc4, 0xe0, 0xfb, 0x31, 0x1b, 0x11, 0x65, 0xe3, 0x92, - 0x8f, 0x4a, 0x6a, 0x85, 0x69, 0xdc, 0x89, 0x09, 0xe4, 0x6e, 0x79, 0x23, 0x1e, 0xc3, 0xf9, 0x22, - 0xb6, 0x00, 0x87, 0x79, 0xaf, 0x1e, 0x65, 0x11, 0x4f, 0x89, 0xe3, 0x9c, 0x42, 0x4d, 0xbe, 0x17, - 0xce, 0xc9, 0x1d, 0x44, 0x14, 0x89, 0x79, 0xbd, 0x70, 0xc6, 0x9d, 0xb8, 0xb1, 0x13, 0x56, 0x9d, - 0x98, 0xd2, 0xe9, 0x55, 0x10, 0x1b, 0xc6, 0x71, 0x58, 0x45, 0x8d, 0xcf, 0xf7, 0xab, 0xf1, 0x6a, - 0xa2, 0xc6, 0xf3, 0x38, 0x51, 0x92, 0x95, 0xa9, 0x3c, 0xc9, 0x12, 0x4c, 0x8a, 0x75, 0x24, 0x66, - 0xdb, 0x0b, 0xd8, 0x5b, 0xa8, 0xc4, 0x92, 0x2b, 0x30, 0x31, 0xe1, 0x74, 0x12, 0x75, 0x47, 0xe6, - 0x8f, 0x49, 0x2f, 0x6a, 0x3b, 0x72, 0xfc, 0x0d, 0x49, 0x47, 0x66, 0x3b, 0x52, 0x24, 0xc5, 0x2c, - 0x3f, 0xee, 0x78, 0x42, 0x45, 0x75, 0x29, 0xca, 0x8a, 0xa4, 0x08, 0x3f, 0x16, 0x0d, 0x31, 0xd4, - 0x2d, 0x21, 0x8d, 0x03, 0xd9, 0x82, 0xd9, 0xf0, 0xd4, 0x56, 0x18, 0x17, 0xa3, 0x28, 0xc1, 0xd1, - 0x51, 0x9f, 0xce, 0x37, 0x8d, 0x9e, 0xd8, 0x70, 0x41, 0x3b, 0xa7, 0x15, 0xd6, 0x97, 0x91, 0x35, - 0x66, 0xad, 0xd7, 0x0f, 0xf9, 0x74, 0xf6, 0xbd, 0xf8, 0x90, 0x8f, 0x60, 0x21, 0x7e, 0x36, 0x2b, - 0xb5, 0xbc, 0x84, 0xb5, 0xbc, 0x7e, 0x72, 0x5c, 0xbc, 0x92, 0x38, 0xde, 0xd3, 0x2b, 0xea, 0xc3, - 0x8d, 0x7c, 0x0d, 0xe6, 0xf5, 0xf3, 0x59, 0xa9, 0xc9, 0xc0, 0x9a, 0x70, 0xe9, 0x84, 0x07, 0x7b, - 0x7a, 0x0d, 0x3d, 0x79, 0x90, 0x00, 0x8a, 0xa9, 0xb3, 0x5b, 0xa9, 0xe6, 0xe5, 0xa8, 0x41, 0x89, - 0x55, 0x92, 0x5e, 0xdd, 0x69, 0x2c, 0xc9, 0x21, 0x5c, 0x4a, 0x3b, 0x26, 0x94, 0x4a, 0x5f, 0x09, - 0x95, 0xc0, 0x9f, 0x4a, 0x3f, 0x72, 0xd2, 0x6b, 0x3e, 0x85, 0x2d, 0xf9, 0x32, 0x9c, 0x53, 0xd6, - 0x97, 0x52, 0xdf, 0xab, 0x58, 0x1f, 0xba, 0x82, 0xab, 0x0b, 0x33, 0xbd, 0x96, 0x74, 0x1e, 0xa4, - 0x05, 0xb3, 0xb2, 0xe1, 0xa8, 0x6d, 0x17, 0x47, 0xcf, 0x15, 0x6d, 0x57, 0x4d, 0x62, 0x2c, 0x5d, - 0x16, 0xbb, 0xea, 0x7c, 0x63, 0xc7, 0xea, 0x44, 0x84, 0xea, 0x4c, 0x4f, 0xe1, 0x4b, 0x56, 0x60, - 0xa4, 0xb6, 0x51, 0xbd, 0x73, 0x67, 0x79, 0xfe, 0x35, 0xac, 0x41, 0xfa, 0x8d, 0x71, 0xa0, 0x76, - 0x69, 0x12, 0xe6, 0x8a, 0x1d, 0x67, 0x77, 0x57, 0x7b, 0xb0, 0xe2, 0xa8, 0xe4, 0xfb, 0xd0, 0x50, - 0x90, 0xed, 0xa8, 0x25, 0xdf, 0x77, 0xf6, 0x30, 0xea, 0xb4, 0x3f, 0xff, 0xba, 0xf6, 0xde, 0x2f, - 0x23, 0x72, 0x97, 0x31, 0x61, 0x59, 0x02, 0x9d, 0x4b, 0x9b, 0xec, 0xfe, 0x2f, 0x76, 0x6e, 0xcb, - 0x8e, 0x58, 0xa9, 0x9b, 0x78, 0xb2, 0x22, 0xd6, 0x6f, 0x7b, 0x4e, 0x60, 0xed, 0x77, 0xb5, 0xe6, - 0xcf, 0x7f, 0x4a, 0x8b, 0xc0, 0xcc, 0xd3, 0xb8, 0x29, 0xbd, 0xf6, 0x8a, 0xa8, 0xf0, 0x05, 0x7e, - 0x5b, 0xee, 0xd1, 0x73, 0x33, 0x7b, 0x31, 0x3a, 0x9f, 0xfc, 0x40, 0x06, 0xce, 0x6f, 0xbb, 0xde, - 0x41, 0xd3, 0xb5, 0x1b, 0xb2, 0x55, 0x62, 0x0f, 0x7f, 0xa3, 0xdf, 0x1e, 0xfe, 0x99, 0xc4, 0x1e, - 0x6e, 0x1c, 0x0a, 0x36, 0x56, 0x18, 0xd0, 0x3c, 0xb1, 0x9f, 0xf7, 0xa8, 0x8a, 0x7c, 0x1f, 0x5c, - 0x4e, 0x2f, 0x51, 0x26, 0xe5, 0x9b, 0x38, 0x29, 0x6f, 0x9e, 0x1c, 0x17, 0xdf, 0xec, 0x55, 0x53, - 0xfa, 0x04, 0x3d, 0x95, 0xf5, 0xbd, 0xa1, 0xfc, 0xd5, 0xc2, 0xb5, 0x7b, 0x43, 0xf9, 0x6b, 0x85, - 0xd7, 0xcd, 0x17, 0x6a, 0xa5, 0xb5, 0xd5, 0x6a, 0x43, 0x1e, 0xae, 0x32, 0xe6, 0x3a, 0xa7, 0x31, - 0xaf, 0xf4, 0x2b, 0x8d, 0x38, 0x1a, 0x7f, 0x2b, 0x03, 0xc5, 0x53, 0x26, 0x09, 0x3b, 0xcf, 0xa2, - 0x91, 0xa8, 0xd1, 0x40, 0x8d, 0xdc, 0x1e, 0x8d, 0x9f, 0xa5, 0x9b, 0x8d, 0xe8, 0x24, 0xe8, 0x74, - 0x28, 0xd2, 0x85, 0x28, 0xbe, 0xa7, 0xc9, 0x34, 0x21, 0x12, 0xcb, 0x58, 0x85, 0x42, 0x7c, 0xf2, - 0x90, 0xcf, 0xc1, 0xa4, 0x9a, 0xac, 0x40, 0xaa, 0x12, 0x78, 0xa0, 0x11, 0x6f, 0x4f, 0x3b, 0x10, - 0x35, 0x44, 0xe3, 0x17, 0x32, 0x30, 0x9b, 0xb2, 0xc2, 0xc8, 0x15, 0x18, 0xc2, 0x6c, 0x62, 0x8a, - 0xd5, 0x50, 0x2c, 0x8b, 0x18, 0x96, 0x93, 0x4f, 0xc3, 0x68, 0x65, 0xbd, 0x56, 0x2b, 0xad, 0x4b, - 0x65, 0x04, 0x3f, 0x88, 0xdb, 0xbe, 0xe5, 0xdb, 0xba, 0xb1, 0x81, 0x40, 0x23, 0x6f, 0xc2, 0x48, - 0x75, 0x03, 0x09, 0xb8, 0xed, 0x2b, 0xb6, 0xd7, 0xe9, 0xc4, 0xf1, 0x05, 0x92, 0xf1, 0x63, 0x19, - 0x20, 0xc9, 0xed, 0x82, 0xdc, 0x84, 0x71, 0x75, 0x53, 0xe2, 0xed, 0xc5, 0x17, 0x58, 0x65, 0xe1, - 0x98, 0x2a, 0x0e, 0xa9, 0xc0, 0x30, 0xe6, 0x81, 0x0d, 0xad, 0x1c, 0x52, 0x97, 0xc5, 0x85, 0xc4, - 0xb2, 0x18, 0xc6, 0x2c, 0xb3, 0x26, 0x27, 0x36, 0x7e, 0x27, 0x03, 0x24, 0xdd, 0x76, 0x71, 0x20, - 0x2b, 0xab, 0xb7, 0x94, 0xd8, 0x05, 0x6a, 0xbe, 0xa0, 0x30, 0xd9, 0x9b, 0xaa, 0x06, 0x88, 0xa2, - 0x1c, 0x5c, 0xd1, 0xd4, 0x4e, 0xbd, 0x1d, 0x5e, 0xaf, 0xc1, 0xf0, 0x43, 0xea, 0xed, 0x48, 0xb3, - 0x6e, 0x34, 0x05, 0x7d, 0xc4, 0x00, 0xaa, 0x1a, 0x06, 0x31, 0x8c, 0x3f, 0xce, 0xc0, 0x5c, 0xda, - 0x1d, 0xe5, 0x14, 0xbf, 0x54, 0x23, 0xe6, 0x52, 0x8b, 0x16, 0x56, 0xdc, 0x4e, 0x34, 0x74, 0xa4, - 0x2d, 0xc2, 0x30, 0x6b, 0xac, 0x1c, 0x61, 0x54, 0x83, 0xb1, 0xde, 0xf0, 0x4d, 0x0e, 0x67, 0x08, - 0x3c, 0x46, 0xdf, 0x10, 0x86, 0x77, 0x44, 0x04, 0x9c, 0xdd, 0x26, 0x87, 0x33, 0x84, 0x35, 0xb7, - 0x41, 0xa5, 0x7a, 0x08, 0x11, 0x5a, 0x0c, 0x60, 0x72, 0x38, 0xb9, 0x02, 0xa3, 0x0f, 0xda, 0xab, - 0xd4, 0x7e, 0x24, 0x73, 0x56, 0xa0, 0x45, 0x98, 0xdb, 0xb6, 0x9a, 0x0c, 0x66, 0xca, 0x42, 0xe3, - 0x67, 0x32, 0x30, 0x93, 0xb8, 0x1e, 0x9d, 0xee, 0x7a, 0xdb, 0xdf, 0x07, 0x6e, 0x90, 0xf6, 0xf1, - 0xcf, 0x1f, 0x4a, 0xff, 0x7c, 0xe3, 0xbf, 0x1b, 0x81, 0x0b, 0x3d, 0xb4, 0x55, 0x91, 0x8f, 0x6e, - 0xe6, 0x54, 0x1f, 0xdd, 0xaf, 0xc0, 0x64, 0xb9, 0x69, 0x3b, 0x2d, 0x7f, 0xd3, 0x8d, 0xbe, 0x38, - 0x72, 0xf5, 0xc1, 0x32, 0xe1, 0x07, 0x11, 0xfa, 0x84, 0x5c, 0xac, 0x23, 0x85, 0x15, 0xb8, 0x49, - 0x61, 0x59, 0x63, 0x96, 0xf0, 0x92, 0xcd, 0xfd, 0x05, 0xf1, 0x92, 0xd5, 0xfd, 0xb6, 0x86, 0x9e, - 0xaa, 0xdf, 0x56, 0xba, 0xcd, 0xf7, 0xf0, 0x93, 0x78, 0x00, 0x94, 0x61, 0x92, 0x9b, 0xc4, 0x95, - 0x7c, 0x3e, 0x48, 0x23, 0x09, 0x33, 0x3a, 0xdb, 0x4f, 0x8e, 0x85, 0x46, 0x43, 0x56, 0x74, 0x1f, - 0xa3, 0x51, 0x7c, 0x33, 0xbe, 0xd2, 0xdb, 0x87, 0x48, 0xb3, 0x15, 0xd1, 0x7c, 0x89, 0xbe, 0x09, - 0x73, 0x69, 0xd7, 0xdd, 0xf9, 0xbc, 0x66, 0x6d, 0xdb, 0xd3, 0x4a, 0x7b, 0xf0, 0x4b, 0xf3, 0x41, - 0xea, 0xa5, 0x59, 0xfa, 0x7e, 0x8f, 0x69, 0x21, 0x9d, 0x7b, 0xac, 0x05, 0x8e, 0xdb, 0xdf, 0x43, - 0xdc, 0xf8, 0x0a, 0xbc, 0xd8, 0x97, 0x9c, 0xbc, 0xa3, 0xc5, 0x18, 0x7a, 0x2d, 0x19, 0x63, 0xe8, - 0x3b, 0xc7, 0xc5, 0x19, 0xcd, 0x6f, 0x73, 0x2d, 0x54, 0xf8, 0x1b, 0x3f, 0x93, 0xd5, 0x3d, 0x8e, - 0xff, 0x22, 0x2e, 0xd4, 0x6b, 0x30, 0xbc, 0xbd, 0x4f, 0x3d, 0x79, 0x3c, 0xe0, 0x87, 0x1c, 0x32, - 0x80, 0xfa, 0x21, 0x88, 0x41, 0xee, 0xc0, 0xd4, 0x06, 0x9f, 0xb8, 0x72, 0x36, 0x0e, 0x45, 0x3a, - 0x97, 0x8e, 0xd0, 0x0c, 0xa6, 0x4c, 0xc7, 0x18, 0x95, 0x71, 0x37, 0xd6, 0xe9, 0x22, 0x42, 0x12, - 0xf7, 0x8c, 0xe2, 0x02, 0xc4, 0x54, 0xe4, 0x0b, 0x16, 0x6d, 0xb6, 0x66, 0x0c, 0x6a, 0xec, 0xc2, - 0xa5, 0xbe, 0x8c, 0xd8, 0xb9, 0x0d, 0x9d, 0xf0, 0x57, 0xcc, 0xf2, 0xba, 0x2f, 0xa9, 0xa9, 0xd0, - 0x19, 0xdf, 0x84, 0x09, 0xb5, 0x97, 0xf1, 0x08, 0x62, 0xbf, 0xc5, 0xac, 0xe0, 0x47, 0x10, 0x03, - 0x98, 0x1c, 0x1e, 0xbd, 0xe5, 0x64, 0xd3, 0xdf, 0x72, 0xa2, 0xe1, 0xcf, 0x9d, 0x36, 0xfc, 0xac, - 0x72, 0xdc, 0xe1, 0x94, 0xca, 0xf1, 0xb7, 0x5a, 0x39, 0x86, 0x40, 0x32, 0x39, 0xfc, 0xa9, 0x56, - 0xfe, 0x4f, 0x65, 0x92, 0x33, 0x74, 0xbc, 0x92, 0xcb, 0x3d, 0x13, 0x65, 0x2a, 0x4b, 0x5b, 0xbd, - 0x11, 0x66, 0x24, 0x53, 0x64, 0x4f, 0x93, 0x29, 0xce, 0x32, 0x11, 0x51, 0xee, 0xe5, 0x43, 0x3a, - 0x14, 0xc9, 0x81, 0x76, 0xc2, 0xda, 0x45, 0x62, 0x19, 0xdf, 0xca, 0xc0, 0xb9, 0x54, 0x9d, 0x39, - 0xab, 0x95, 0x2b, 0xe7, 0x95, 0x75, 0x18, 0xd7, 0xcc, 0x73, 0x8c, 0xb3, 0xc4, 0xbf, 0x18, 0xbc, - 0x2d, 0xc6, 0x4b, 0x30, 0x16, 0xbe, 0xd8, 0x92, 0x39, 0x39, 0x74, 0x68, 0x17, 0x29, 0x1f, 0xfe, - 0x6a, 0x00, 0xec, 0x0b, 0x9e, 0xaa, 0x69, 0xb5, 0xf1, 0x4f, 0xb3, 0x3c, 0x01, 0xee, 0x33, 0x1b, - 0xca, 0x36, 0xdd, 0x1e, 0x9a, 0x35, 0xa9, 0x77, 0x00, 0x5b, 0xb2, 0x0c, 0x23, 0xb5, 0xc0, 0x0e, - 0xba, 0x32, 0x6c, 0xc7, 0xac, 0x4a, 0x86, 0x05, 0x0f, 0x17, 0xa3, 0xc0, 0x0d, 0x3e, 0x42, 0x34, - 0x2d, 0x01, 0x42, 0x14, 0xb3, 0xea, 0xdf, 0xcf, 0xc0, 0x84, 0x4a, 0x4c, 0x3e, 0x84, 0x29, 0x19, - 0xa0, 0x93, 0x07, 0x33, 0x11, 0xcf, 0xcb, 0xd2, 0x14, 0x4c, 0x06, 0xe8, 0x54, 0x83, 0x9f, 0x68, - 0xf8, 0xea, 0x56, 0xdd, 0x51, 0x91, 0x49, 0x03, 0x48, 0x6b, 0xd7, 0xb6, 0x0e, 0xa9, 0x7d, 0x40, - 0xfd, 0xc0, 0xe2, 0x26, 0x3b, 0xe2, 0x15, 0x5a, 0xb2, 0x5f, 0xbb, 0x53, 0xe2, 0xd6, 0x3a, 0x6c, - 0x24, 0x44, 0xa4, 0xd5, 0x04, 0x8d, 0xfa, 0xb4, 0xd6, 0xda, 0xb5, 0xb7, 0x79, 0x21, 0xa7, 0x33, - 0xfe, 0x64, 0x84, 0x4f, 0x37, 0x11, 0xcf, 0x77, 0x07, 0xa6, 0x1e, 0x54, 0x2b, 0x65, 0x45, 0xd1, - 0xae, 0xa7, 0x83, 0x5a, 0x7e, 0x1c, 0x50, 0xaf, 0x6d, 0x37, 0xe5, 0x7d, 0x37, 0x3a, 0x82, 0x5c, - 0xa7, 0x51, 0x4f, 0x57, 0xc2, 0xc7, 0x38, 0xb2, 0x3a, 0xf8, 0xcd, 0x3a, 0xac, 0x23, 0x3b, 0x60, - 0x1d, 0xbe, 0xdd, 0x6a, 0xf6, 0xa8, 0x43, 0xe7, 0x48, 0xf6, 0xf1, 0xea, 0xbb, 0xdf, 0xdd, 0x51, - 0x6a, 0xc9, 0xf5, 0xaf, 0xe5, 0x65, 0x51, 0xcb, 0xf3, 0x42, 0xad, 0x92, 0x5a, 0x4f, 0x82, 0x6b, - 0xb4, 0x4f, 0x0c, 0x9d, 0xba, 0x4f, 0xfc, 0x8d, 0x0c, 0x8c, 0x70, 0xf1, 0x55, 0x4c, 0xe3, 0x1e, - 0x02, 0xf2, 0xf6, 0xd3, 0x11, 0x90, 0x0b, 0x78, 0x4e, 0x68, 0x13, 0x9a, 0x97, 0x91, 0x4a, 0x6c, - 0x5d, 0x48, 0x6f, 0x00, 0x7c, 0x32, 0xe3, 0x25, 0xa7, 0x2f, 0x0b, 0x52, 0x8d, 0x42, 0x69, 0x8c, - 0x9e, 0xea, 0xad, 0x2d, 0xc3, 0x8f, 0x8c, 0x8a, 0x50, 0x1a, 0x7a, 0x00, 0x8d, 0x55, 0x18, 0x13, - 0x01, 0x3a, 0x96, 0x8e, 0xc4, 0xc3, 0x78, 0x41, 0x33, 0x6d, 0x6a, 0x2c, 0x1d, 0x45, 0xa2, 0xb9, - 0x08, 0xf1, 0x61, 0xed, 0x1c, 0x69, 0xf9, 0x84, 0x25, 0x22, 0x79, 0xc0, 0xf3, 0x6c, 0xf2, 0x88, - 0xc7, 0x7a, 0x8a, 0x83, 0x10, 0x2e, 0x42, 0x7f, 0x49, 0x2f, 0xff, 0x94, 0x00, 0xc7, 0x11, 0x0f, - 0xb2, 0x0a, 0x05, 0x34, 0x87, 0xa3, 0x0d, 0xbe, 0x6a, 0xaa, 0x15, 0x1e, 0x04, 0x42, 0x98, 0x34, - 0x07, 0xbc, 0x4c, 0x2c, 0xb7, 0x98, 0xff, 0x65, 0x82, 0xd2, 0xf8, 0xe9, 0x2c, 0x14, 0xe2, 0xb3, - 0x8f, 0xbc, 0x0b, 0xe3, 0x61, 0xc4, 0xe9, 0xd0, 0x03, 0x1c, 0x1f, 0xc8, 0xa2, 0x10, 0xd5, 0x7a, - 0x76, 0x46, 0x05, 0x9d, 0x2c, 0x42, 0x9e, 0x2d, 0xe2, 0x78, 0x26, 0xe3, 0xae, 0x80, 0xa9, 0x1e, - 0x59, 0x12, 0x8f, 0xd4, 0x60, 0x96, 0x2d, 0x9a, 0x9a, 0xd3, 0xde, 0x6b, 0xd2, 0x55, 0x77, 0xcf, - 0xed, 0x06, 0x51, 0xb2, 0x42, 0x7e, 0x81, 0xb1, 0x5b, 0x4d, 0xad, 0x58, 0x4f, 0x55, 0x98, 0x42, - 0xad, 0xe4, 0x59, 0x1f, 0x1a, 0x20, 0xcf, 0xba, 0xb2, 0xb3, 0xfe, 0x61, 0x16, 0xc6, 0x95, 0xe9, - 0x47, 0xae, 0x41, 0xbe, 0xea, 0xaf, 0xba, 0xf5, 0x83, 0x30, 0x94, 0xe4, 0xe4, 0xc9, 0x71, 0x71, - 0xcc, 0xf1, 0xad, 0x26, 0x02, 0xcd, 0xb0, 0x98, 0x2c, 0xc1, 0x24, 0xff, 0x4b, 0x26, 0x0e, 0xc9, - 0x46, 0xba, 0x35, 0x8e, 0x2c, 0x53, 0x86, 0xa8, 0x9b, 0xad, 0x46, 0x42, 0xbe, 0x0a, 0xc0, 0x01, - 0x18, 0x7c, 0x20, 0x37, 0x78, 0xd8, 0x04, 0x51, 0x41, 0x4a, 0xd8, 0x01, 0x85, 0x21, 0xf9, 0x3a, - 0x0f, 0x68, 0x2d, 0x97, 0xcb, 0xd0, 0xe0, 0x71, 0x1f, 0x18, 0x7f, 0x2b, 0x3d, 0xfc, 0x8c, 0xca, - 0x52, 0xe4, 0xfa, 0x59, 0x30, 0x69, 0xdd, 0x7d, 0x44, 0xbd, 0xa3, 0x52, 0x80, 0x88, 0x0a, 0x86, - 0xf1, 0xbf, 0x64, 0x94, 0x45, 0x46, 0xd6, 0x31, 0x57, 0x37, 0x9f, 0x40, 0xc2, 0xa4, 0x2c, 0xbc, - 0x62, 0x48, 0xb8, 0x49, 0x77, 0x97, 0x9e, 0x17, 0xd6, 0x6d, 0xb3, 0xe1, 0x34, 0x8c, 0xe5, 0xf0, - 0xe6, 0x40, 0xf2, 0x05, 0x18, 0xc2, 0xae, 0xcb, 0x9e, 0xda, 0x34, 0x79, 0xca, 0x0f, 0xb1, 0x3e, - 0xc3, 0x86, 0x20, 0x25, 0xf9, 0xb4, 0x70, 0xdc, 0xe6, 0x9d, 0x3f, 0xa5, 0x1c, 0xd5, 0xec, 0x3b, - 0xc2, 0xe3, 0x3d, 0x8a, 0x40, 0xa4, 0xcc, 0x9e, 0xbf, 0x95, 0x85, 0x42, 0x7c, 0x69, 0x93, 0x0f, - 0x60, 0x42, 0x1e, 0xbf, 0x2b, 0xb6, 0xc8, 0x7a, 0x31, 0x21, 0xb2, 0x4e, 0xc8, 0x33, 0x78, 0xdf, - 0x56, 0x4d, 0xd0, 0x4c, 0x8d, 0x80, 0xc9, 0x42, 0x9b, 0x22, 0x22, 0xa0, 0xb2, 0xa8, 0x02, 0x37, - 0xe8, 0xc4, 0xe2, 0x28, 0x4b, 0x34, 0xf2, 0x16, 0xe4, 0xd6, 0xee, 0x94, 0x84, 0x83, 0x5f, 0x21, - 0x7e, 0x48, 0x73, 0x4b, 0x59, 0xdd, 0x6e, 0x97, 0xe1, 0x93, 0x55, 0x25, 0xe4, 0xf8, 0x88, 0x66, - 0x6e, 0x28, 0xc1, 0x61, 0xe3, 0x4e, 0x8f, 0x3d, 0x7e, 0x6f, 0x28, 0x9f, 0x2b, 0x0c, 0x89, 0x20, - 0xba, 0xff, 0x7d, 0x0e, 0xc6, 0xc2, 0xfa, 0x09, 0x51, 0xdd, 0xa6, 0xb9, 0x8b, 0x34, 0xb9, 0x08, - 0x79, 0x29, 0xdd, 0x09, 0x3f, 0xbf, 0x51, 0x5f, 0x48, 0x76, 0xf3, 0x20, 0xc5, 0x38, 0xbe, 0x2b, - 0x98, 0xf2, 0x27, 0xb9, 0x09, 0xa1, 0x8c, 0xd6, 0x4b, 0x98, 0x1b, 0x62, 0x03, 0x66, 0x86, 0x68, - 0x64, 0x0a, 0xb2, 0x0e, 0x0f, 0xcc, 0x36, 0x66, 0x66, 0x9d, 0x06, 0xf9, 0x00, 0xf2, 0x76, 0xa3, - 0x41, 0x1b, 0x96, 0x2d, 0x6d, 0xb3, 0xfa, 0x4d, 0x9a, 0x3c, 0xe3, 0xc6, 0xcf, 0x0c, 0xa4, 0x2a, - 0x05, 0xa4, 0x04, 0x63, 0x4d, 0x9b, 0x5b, 0x7b, 0x36, 0x06, 0x38, 0x80, 0x22, 0x0e, 0x79, 0x46, - 0xb6, 0xe5, 0xd3, 0x06, 0x79, 0x0d, 0x86, 0xd8, 0x68, 0x8a, 0x13, 0x47, 0x0a, 0x95, 0x6c, 0x30, - 0x79, 0x87, 0xad, 0x3c, 0x67, 0x22, 0x02, 0x79, 0x05, 0x72, 0xdd, 0xc5, 0x5d, 0x71, 0x96, 0x14, - 0xa2, 0xf0, 0xff, 0x21, 0x1a, 0x2b, 0x26, 0xb7, 0x20, 0x7f, 0xa8, 0x47, 0x8e, 0x3f, 0x17, 0x1b, - 0xc6, 0x10, 0x3f, 0x44, 0x24, 0xaf, 0x41, 0xce, 0xf7, 0x5d, 0x61, 0xd0, 0x34, 0x1b, 0x5a, 0x99, - 0x3e, 0x08, 0x47, 0x8d, 0x71, 0xf7, 0x7d, 0x77, 0x29, 0x0f, 0x23, 0xfc, 0x80, 0x31, 0x2e, 0x01, - 0x44, 0xdf, 0x98, 0xf4, 0xdb, 0x34, 0xbe, 0x0a, 0x63, 0xe1, 0xb7, 0x91, 0x17, 0x01, 0x0e, 0xe8, - 0x91, 0xb5, 0x6f, 0xb7, 0x1b, 0x4d, 0x2e, 0x9d, 0x4e, 0x98, 0x63, 0x07, 0xf4, 0x68, 0x05, 0x01, - 0xe4, 0x02, 0x8c, 0x76, 0xd8, 0xf0, 0x8b, 0x39, 0x3e, 0x61, 0x8e, 0x74, 0xba, 0x3b, 0x6c, 0x2a, - 0xcf, 0xc3, 0x28, 0xea, 0x59, 0xc5, 0x8a, 0x9c, 0x34, 0xe5, 0x4f, 0xe3, 0x4f, 0x73, 0x98, 0x5e, - 0x49, 0x69, 0x10, 0x79, 0x19, 0x26, 0xeb, 0x1e, 0xc5, 0xb3, 0xcc, 0x66, 0x12, 0x9a, 0xa8, 0x67, - 0x22, 0x02, 0x56, 0x1b, 0xe4, 0x0a, 0x4c, 0x77, 0xba, 0x3b, 0x4d, 0xa7, 0xce, 0x6a, 0xb3, 0xea, - 0x3b, 0x22, 0x1f, 0xc4, 0x84, 0x39, 0xc9, 0xc1, 0xf7, 0xe9, 0x51, 0x79, 0x07, 0x23, 0x0f, 0x16, - 0xd4, 0xc0, 0xd1, 0x41, 0x98, 0xf8, 0xde, 0x9c, 0x56, 0xe0, 0x68, 0x9b, 0x79, 0x1e, 0x46, 0x6c, - 0x7b, 0xaf, 0xeb, 0xf0, 0x08, 0x61, 0x13, 0xa6, 0xf8, 0x45, 0x3e, 0x05, 0x33, 0x51, 0x2c, 0x73, - 0xd9, 0x8c, 0x61, 0x6c, 0x46, 0x21, 0x2c, 0x28, 0x73, 0x38, 0x79, 0x13, 0x88, 0x5a, 0x9f, 0xbb, - 0xf3, 0x11, 0xad, 0xf3, 0x39, 0x39, 0x61, 0xce, 0x28, 0x25, 0x0f, 0xb0, 0x80, 0xbc, 0x04, 0x13, - 0x1e, 0xf5, 0x51, 0x3a, 0xc4, 0x6e, 0xc3, 0xec, 0x83, 0xe6, 0xb8, 0x84, 0xb1, 0xbe, 0xbb, 0x0a, - 0x05, 0xa5, 0x3b, 0x30, 0x36, 0x37, 0x4f, 0x86, 0x60, 0x4e, 0x45, 0x70, 0xb3, 0x53, 0x6d, 0x90, - 0x2f, 0xc1, 0x82, 0x82, 0xc9, 0x13, 0x21, 0x5a, 0xb4, 0xe9, 0xec, 0x39, 0x3b, 0x4d, 0x2a, 0xe6, - 0x5b, 0x72, 0x56, 0x87, 0x57, 0x48, 0x73, 0x3e, 0xa2, 0xe6, 0x29, 0x12, 0x97, 0x05, 0x2d, 0x59, - 0x85, 0xb9, 0x18, 0x67, 0xda, 0xb0, 0xba, 0x9d, 0x9e, 0x21, 0xf9, 0x22, 0x9e, 0x44, 0xe7, 0x49, - 0x1b, 0x5b, 0x1d, 0xe3, 0x9b, 0x30, 0xa1, 0xce, 0x49, 0xd6, 0x09, 0xaa, 0x5c, 0x22, 0x66, 0xdf, - 0x78, 0x08, 0xab, 0xb2, 0x7b, 0xe1, 0x54, 0x84, 0x12, 0x84, 0x39, 0xfe, 0xcd, 0xc9, 0x10, 0x8a, - 0x43, 0xf8, 0x12, 0x4c, 0x34, 0x1c, 0xbf, 0xd3, 0xb4, 0x8f, 0xac, 0x28, 0xc3, 0xb7, 0x39, 0x2e, - 0x60, 0xa8, 0xf8, 0x59, 0x82, 0x99, 0xc4, 0x3e, 0xa8, 0x48, 0x1a, 0x7c, 0x5f, 0xef, 0x2f, 0x69, - 0x18, 0x6d, 0x98, 0x50, 0xcf, 0xb5, 0x53, 0x12, 0x97, 0x9c, 0xc7, 0x30, 0x3c, 0x7c, 0xd3, 0x1f, - 0x39, 0x39, 0x2e, 0x66, 0x9d, 0x06, 0x06, 0xdf, 0xb9, 0x0a, 0x79, 0x29, 0xb1, 0x09, 0x41, 0x09, - 0x1f, 0x13, 0xe4, 0xd3, 0xa4, 0x19, 0x96, 0x1a, 0xaf, 0xc1, 0xa8, 0x38, 0xba, 0xfa, 0x3f, 0x21, - 0x18, 0x3f, 0x94, 0x85, 0x69, 0x93, 0xb2, 0x8d, 0x95, 0xf2, 0x6c, 0x45, 0xcf, 0xec, 0x15, 0x3d, - 0x3d, 0x98, 0xab, 0xd6, 0xb6, 0x3e, 0x79, 0x82, 0x7e, 0x25, 0x03, 0xb3, 0x29, 0xb8, 0x1f, 0x2b, - 0x4f, 0xee, 0x6d, 0x18, 0xab, 0x38, 0x76, 0xb3, 0xd4, 0x68, 0x84, 0x31, 0x79, 0x50, 0xce, 0xc7, - 0x64, 0x5a, 0x36, 0x83, 0xaa, 0x42, 0x4c, 0x88, 0x4a, 0x5e, 0x17, 0x93, 0x22, 0xca, 0x32, 0x8f, - 0x93, 0xe2, 0x3b, 0xc7, 0x45, 0xe0, 0xdf, 0xb4, 0x19, 0x4e, 0x11, 0x0c, 0xb0, 0xcc, 0x81, 0x91, - 0x5f, 0xd5, 0x33, 0x3b, 0x74, 0xe9, 0x01, 0x96, 0xe3, 0xcd, 0x1b, 0x28, 0x55, 0xd0, 0x8f, 0x67, - 0xe1, 0x7c, 0x3a, 0xe1, 0xc7, 0x4d, 0x79, 0x8c, 0x49, 0x9a, 0x94, 0xa0, 0xf0, 0x98, 0xf2, 0x98, - 0x67, 0x74, 0x42, 0xfc, 0x08, 0x81, 0xec, 0xc2, 0xe4, 0xaa, 0xed, 0x07, 0x2b, 0xd4, 0xf6, 0x82, - 0x1d, 0x6a, 0x07, 0x03, 0x48, 0xf2, 0xd2, 0x9a, 0x62, 0x1e, 0x85, 0x89, 0x7d, 0x49, 0x19, 0x93, - 0xb5, 0x75, 0xb6, 0xe1, 0x44, 0x19, 0x1a, 0x60, 0xa2, 0x7c, 0x03, 0xa6, 0x6b, 0xb4, 0x65, 0x77, - 0xf6, 0x5d, 0x4f, 0xc6, 0x4b, 0xb8, 0x0e, 0x93, 0x21, 0x28, 0x75, 0xb6, 0xe8, 0xc5, 0x1a, 0xbe, - 0xd2, 0x11, 0xd1, 0x56, 0xa2, 0x17, 0x1b, 0x7f, 0x3b, 0x0b, 0x17, 0x4a, 0x75, 0x61, 0x1a, 0x2a, - 0x0a, 0xa4, 0x05, 0xfb, 0x27, 0x5c, 0x37, 0xb9, 0x01, 0x63, 0x6b, 0xf6, 0xe3, 0x55, 0x6a, 0xfb, - 0xd4, 0x17, 0x09, 0x27, 0xb9, 0xd8, 0x6b, 0x3f, 0x8e, 0x1e, 0x7f, 0xcc, 0x08, 0x47, 0x55, 0x23, - 0x0c, 0x3d, 0xa1, 0x1a, 0xc1, 0x80, 0x91, 0x15, 0xb7, 0xd9, 0x10, 0x67, 0xbd, 0x78, 0x71, 0xde, - 0x47, 0x88, 0x29, 0x4a, 0x8c, 0x3f, 0xce, 0xc0, 0x54, 0xf8, 0xc5, 0xf8, 0x09, 0x9f, 0x78, 0x97, - 0x5c, 0x81, 0x51, 0xac, 0x28, 0xcc, 0x8c, 0x8f, 0x87, 0x46, 0x93, 0x62, 0xda, 0xc0, 0x86, 0x29, - 0x0b, 0xd5, 0x9e, 0x18, 0x7e, 0xb2, 0x9e, 0x30, 0xfe, 0x01, 0x3e, 0x66, 0xab, 0xad, 0x64, 0x27, - 0x91, 0xf2, 0x21, 0x99, 0x01, 0x3f, 0x24, 0xfb, 0xd4, 0x86, 0x24, 0xd7, 0x73, 0x48, 0x7e, 0x38, - 0x0b, 0xe3, 0xe1, 0xc7, 0x7e, 0x97, 0x65, 0x26, 0x08, 0xdb, 0x35, 0x50, 0x8c, 0xa3, 0x9a, 0xb2, - 0x57, 0x88, 0x50, 0x42, 0x5f, 0x80, 0x11, 0xb1, 0x98, 0x32, 0x31, 0x4b, 0xee, 0xd8, 0xe8, 0x2e, - 0x4d, 0x09, 0xd6, 0x23, 0x38, 0xa0, 0xbe, 0x29, 0xe8, 0x30, 0x88, 0xd4, 0x36, 0xdd, 0x11, 0xb6, - 0x0d, 0xcf, 0xec, 0x19, 0x95, 0x1e, 0x44, 0x2a, 0x6a, 0xd8, 0x40, 0xa7, 0xd3, 0x3f, 0xcf, 0x43, - 0x21, 0x4e, 0x72, 0x7a, 0xee, 0x87, 0x8d, 0xee, 0x0e, 0xbf, 0xaa, 0xf0, 0xdc, 0x0f, 0x9d, 0xee, - 0x8e, 0xc9, 0x60, 0x68, 0xfa, 0xe4, 0x39, 0x8f, 0xb0, 0xd5, 0x13, 0xc2, 0xf4, 0xc9, 0x73, 0x1e, - 0x69, 0xa6, 0x4f, 0x9e, 0xf3, 0x08, 0x15, 0x09, 0xab, 0x35, 0x0c, 0xb0, 0x80, 0xf7, 0x14, 0xa1, - 0x48, 0x68, 0xfa, 0xf1, 0x3c, 0x6e, 0x12, 0x8d, 0x1d, 0x95, 0x4b, 0xd4, 0xf6, 0x44, 0x9e, 0x02, - 0xb1, 0x9d, 0xe1, 0x51, 0xb9, 0x83, 0x60, 0x2b, 0x60, 0x70, 0x53, 0x45, 0x22, 0x4d, 0x20, 0xca, - 0x4f, 0xb9, 0x80, 0x4f, 0xbf, 0x5b, 0x4b, 0x2b, 0xcc, 0x39, 0x95, 0xb5, 0xa5, 0xae, 0xe6, 0x14, - 0xbe, 0x4f, 0x53, 0xfb, 0xbb, 0x21, 0x82, 0xaf, 0xa2, 0x02, 0x29, 0x7f, 0x2a, 0x33, 0x19, 0x18, - 0x06, 0x78, 0x70, 0xd6, 0x50, 0x8d, 0x14, 0x31, 0x21, 0xef, 0xc3, 0xb8, 0x1a, 0x36, 0x83, 0x07, - 0x77, 0x78, 0x81, 0xc7, 0xd3, 0xec, 0x91, 0xf9, 0x57, 0x25, 0x20, 0x3b, 0x70, 0xa1, 0xec, 0xb6, - 0xfd, 0x6e, 0x4b, 0x46, 0xee, 0x8c, 0xe2, 0x85, 0x03, 0x0e, 0x05, 0xfa, 0xe0, 0xd7, 0x05, 0x8a, - 0x88, 0xd2, 0x20, 0xdd, 0x64, 0xf4, 0x0b, 0x48, 0x2f, 0x46, 0x64, 0x13, 0xc6, 0x51, 0x83, 0x2a, - 0x4c, 0x1e, 0xc7, 0xf5, 0x6d, 0x23, 0x2a, 0xa9, 0xb0, 0x85, 0xc1, 0xa3, 0xc6, 0xd9, 0xad, 0xa6, - 0xf4, 0xd2, 0x50, 0x35, 0xc1, 0x0a, 0x32, 0xf9, 0x2a, 0x4c, 0xf1, 0x2b, 0xda, 0x36, 0xdd, 0xe1, - 0x73, 0x67, 0x42, 0xd3, 0x44, 0xe8, 0x85, 0xfc, 0x31, 0x5f, 0xe8, 0xad, 0x0f, 0xe9, 0x0e, 0x1f, - 0x7b, 0xcd, 0x47, 0x4a, 0xc3, 0x27, 0x5b, 0x30, 0xbb, 0x62, 0xfb, 0x1c, 0xa8, 0xc4, 0x3f, 0x98, - 0x44, 0x0d, 0x2d, 0xda, 0xae, 0xef, 0xdb, 0xbe, 0x54, 0x84, 0xa7, 0xc6, 0x3b, 0x48, 0xa3, 0x27, - 0x3f, 0x94, 0x81, 0x79, 0x4d, 0x4f, 0x2e, 0xec, 0xcc, 0x5a, 0xb4, 0x1d, 0xa0, 0x33, 0xd4, 0xd4, - 0x62, 0x51, 0x0a, 0xa5, 0x3d, 0xd0, 0xf8, 0x90, 0xc4, 0x54, 0xf1, 0x5e, 0x54, 0xae, 0x1a, 0x85, - 0xf7, 0xe2, 0x21, 0x16, 0x2a, 0xae, 0xe9, 0x69, 0x7d, 0xa1, 0xc6, 0xd6, 0xb5, 0x44, 0x33, 0x6e, - 0xc7, 0xfb, 0x5b, 0x28, 0xba, 0x32, 0xa1, 0xa2, 0x6b, 0x0e, 0x86, 0xb1, 0x57, 0x65, 0x14, 0x2d, - 0xfc, 0x61, 0x7c, 0x5a, 0xdd, 0x87, 0x84, 0x58, 0xd8, 0x77, 0x1f, 0x32, 0xfe, 0xc7, 0x11, 0x98, - 0x8e, 0x4d, 0x0b, 0x71, 0x4f, 0xcd, 0x24, 0xee, 0xa9, 0x35, 0x00, 0xae, 0xea, 0x1d, 0x50, 0x27, - 0x2b, 0x1d, 0x31, 0xc7, 0x85, 0x1b, 0x75, 0xb8, 0xa6, 0x14, 0x36, 0x8c, 0x29, 0x5f, 0xb1, 0x03, - 0xea, 0xc8, 0x43, 0xa6, 0x7c, 0xd1, 0x2b, 0x4c, 0x23, 0x36, 0xa4, 0x08, 0xc3, 0x18, 0x3f, 0x57, - 0xf5, 0x83, 0x75, 0x18, 0xc0, 0xe4, 0x70, 0xf2, 0x32, 0x8c, 0x30, 0x21, 0xaa, 0x5a, 0x11, 0x9b, - 0x20, 0x9e, 0x2d, 0x4c, 0xca, 0x62, 0x12, 0x8b, 0x28, 0x22, 0xb7, 0x61, 0x82, 0xff, 0x25, 0xc2, - 0xec, 0x8c, 0xe8, 0xc6, 0x8f, 0x96, 0xd3, 0x90, 0x91, 0x76, 0x34, 0x3c, 0x76, 0xbb, 0xa8, 0x75, - 0x51, 0xad, 0x53, 0xad, 0x88, 0x80, 0xeb, 0x78, 0xbb, 0xf0, 0x39, 0x90, 0x55, 0x11, 0x21, 0x30, - 0x59, 0x46, 0x78, 0xa3, 0xe4, 0xf1, 0x4e, 0x89, 0xb2, 0x0c, 0xf7, 0x42, 0x31, 0x45, 0x09, 0xb9, - 0xc6, 0x5f, 0x62, 0x50, 0x2c, 0xe4, 0x79, 0x2b, 0xf1, 0xdd, 0x02, 0x15, 0x13, 0x28, 0x1b, 0x86, - 0xc5, 0xac, 0x72, 0xf6, 0xf7, 0x72, 0xcb, 0x76, 0x9a, 0x62, 0x5b, 0xc1, 0xca, 0x11, 0x97, 0x32, - 0xa8, 0x19, 0x21, 0x90, 0x77, 0x61, 0x8a, 0xfd, 0x28, 0xbb, 0xad, 0x96, 0xdb, 0x46, 0xf6, 0xe3, - 0x51, 0x20, 0x3d, 0x24, 0xa9, 0x63, 0x11, 0xaf, 0x25, 0x86, 0xcb, 0xce, 0x13, 0x7c, 0xe5, 0xed, - 0xf2, 0x37, 0xa2, 0x89, 0xe8, 0x3c, 0x41, 0x52, 0x9f, 0xc3, 0x4d, 0x15, 0x89, 0xbc, 0x0d, 0x93, - 0xec, 0xe7, 0x5d, 0xe7, 0x11, 0xe5, 0x15, 0x4e, 0x46, 0xe6, 0x0d, 0x48, 0xb5, 0xc7, 0x4a, 0x78, - 0x7d, 0x3a, 0x26, 0xf9, 0x22, 0x9c, 0x43, 0x4e, 0x75, 0xb7, 0x43, 0x1b, 0xa5, 0xdd, 0x5d, 0xa7, - 0xe9, 0x70, 0x6b, 0x34, 0x1e, 0x50, 0x06, 0x75, 0xf0, 0xbc, 0x62, 0xc4, 0xb0, 0xec, 0x08, 0xc5, - 0x4c, 0xa7, 0x24, 0xdb, 0x50, 0x28, 0x77, 0xfd, 0xc0, 0x6d, 0x95, 0x82, 0xc0, 0x73, 0x76, 0xba, - 0x01, 0xf5, 0xe7, 0xa7, 0xb5, 0xb0, 0x2b, 0x6c, 0x71, 0x84, 0x85, 0x5c, 0x1f, 0x54, 0x47, 0x0a, - 0xcb, 0x0e, 0x49, 0xcc, 0x04, 0x13, 0xe3, 0x5f, 0x64, 0x60, 0x52, 0x23, 0x25, 0x6f, 0xc1, 0xc4, - 0x1d, 0xcf, 0xa1, 0xed, 0x46, 0xf3, 0x48, 0xb9, 0xa8, 0xe2, 0x2d, 0x66, 0x57, 0xc0, 0x79, 0xab, - 0x35, 0xb4, 0x50, 0xcf, 0x93, 0x4d, 0x35, 0x15, 0xbd, 0xc1, 0xdd, 0xb1, 0xc5, 0x04, 0xcd, 0x45, - 0x71, 0xa0, 0x70, 0x82, 0x8a, 0xd9, 0xa9, 0xa0, 0x90, 0xf7, 0x60, 0x84, 0xbf, 0x07, 0x0b, 0xbb, - 0xc5, 0x8b, 0x69, 0xcd, 0xe4, 0xae, 0xff, 0x38, 0x11, 0xd1, 0xe8, 0xc7, 0x37, 0x05, 0x91, 0xf1, - 0xb3, 0x19, 0x20, 0x49, 0xd4, 0x53, 0xf4, 0x5e, 0xa7, 0x1a, 0x13, 0x7d, 0x21, 0x5c, 0x8d, 0x39, - 0x4d, 0x67, 0xce, 0x6a, 0xe2, 0x05, 0xbc, 0xe3, 0xc5, 0xaa, 0x53, 0x15, 0x71, 0xbc, 0xd8, 0xf8, - 0xc1, 0x2c, 0x40, 0x84, 0x4d, 0x3e, 0xc7, 0xd3, 0x94, 0x7d, 0xb1, 0x6b, 0x37, 0x9d, 0x5d, 0x47, - 0x8f, 0xdb, 0x8b, 0x4c, 0xbe, 0x21, 0x4b, 0x4c, 0x1d, 0x91, 0x7c, 0x00, 0xd3, 0xb5, 0x0d, 0x9d, - 0x56, 0x31, 0x8b, 0xf7, 0x3b, 0x56, 0x8c, 0x3c, 0x8e, 0x8d, 0xf6, 0xc9, 0xea, 0x68, 0x70, 0xfb, - 0x64, 0x3e, 0x10, 0xa2, 0x84, 0x6d, 0x2c, 0xb5, 0x0d, 0x61, 0xf9, 0xdf, 0x08, 0x5f, 0x35, 0xf1, - 0xeb, 0xfc, 0x8e, 0xd5, 0x11, 0x2e, 0x01, 0x6c, 0x9f, 0xd0, 0xf0, 0xa2, 0x8e, 0x1c, 0xee, 0xe1, - 0xde, 0xff, 0x73, 0xa8, 0xf6, 0x6b, 0xb9, 0x01, 0x15, 0xda, 0x8e, 0x67, 0xf6, 0xde, 0x13, 0x19, - 0x13, 0x0c, 0x6b, 0x5e, 0xcb, 0x5a, 0xeb, 0x84, 0xc1, 0xcc, 0xad, 0xe8, 0x92, 0xc2, 0xcd, 0x0a, - 0x52, 0x6c, 0x6c, 0xfe, 0x5e, 0x06, 0xce, 0xa5, 0xd2, 0x92, 0xeb, 0x00, 0x91, 0x4e, 0x49, 0xf4, - 0x12, 0xee, 0x98, 0x51, 0xf4, 0x23, 0x53, 0xc1, 0x20, 0x5f, 0x89, 0x6b, 0x83, 0x4e, 0x3f, 0x08, - 0x17, 0x64, 0xd0, 0x41, 0x5d, 0x1b, 0x94, 0xa2, 0x03, 0x32, 0x7e, 0x25, 0x07, 0x33, 0x4a, 0x70, - 0x25, 0xfe, 0xad, 0xa7, 0xd8, 0x8b, 0x1f, 0xc0, 0x04, 0x6b, 0x8d, 0x53, 0x17, 0x6e, 0x37, 0xdc, - 0xf0, 0xe5, 0xf5, 0x84, 0xdf, 0xa9, 0xe0, 0x76, 0x5d, 0x45, 0xe6, 0xa1, 0x40, 0x71, 0xeb, 0xc4, - 0x07, 0x89, 0x7a, 0xd2, 0xe5, 0x46, 0x63, 0x4e, 0x7c, 0x98, 0xac, 0x1c, 0xb5, 0xed, 0x56, 0x58, - 0x1b, 0x37, 0x80, 0xf9, 0x54, 0xcf, 0xda, 0x34, 0x6c, 0x5e, 0x5d, 0xe4, 0xa1, 0xc5, 0xcb, 0x52, - 0x82, 0x03, 0x68, 0x54, 0x0b, 0x1f, 0xc0, 0x4c, 0xe2, 0xa3, 0xcf, 0x14, 0x95, 0x74, 0x1b, 0x48, - 0xf2, 0x3b, 0x52, 0x38, 0x7c, 0x4a, 0x8f, 0x79, 0x7b, 0x2e, 0x7c, 0xbc, 0x6e, 0xb5, 0xec, 0x76, - 0x83, 0x9b, 0xd3, 0x2c, 0xaa, 0x31, 0x4b, 0x7f, 0x2e, 0xab, 0xfa, 0xfe, 0x3e, 0xeb, 0xab, 0xee, - 0x0b, 0xda, 0x6d, 0xf8, 0x52, 0xaf, 0x31, 0x1d, 0x48, 0xeb, 0xf0, 0xed, 0x1c, 0x5c, 0xe8, 0x41, - 0x49, 0x8e, 0xe2, 0x93, 0x88, 0x6b, 0x21, 0x6e, 0xf6, 0xaf, 0xf0, 0x69, 0x4c, 0x25, 0xf2, 0x39, - 0x1e, 0xfd, 0xa3, 0xee, 0xb6, 0x77, 0x9d, 0x3d, 0x71, 0xff, 0x46, 0x35, 0xfe, 0x41, 0x08, 0x8d, - 0x87, 0xfd, 0xe0, 0x50, 0xf2, 0x01, 0x0c, 0xa3, 0xe3, 0x77, 0x2c, 0xbc, 0x23, 0xc3, 0x40, 0xb8, - 0x12, 0xa0, 0x94, 0xfd, 0xd4, 0x02, 0x94, 0x32, 0x00, 0xf9, 0x2c, 0xe4, 0x4a, 0xdb, 0x35, 0x31, - 0x2e, 0x53, 0x2a, 0xf9, 0x76, 0x2d, 0x4a, 0xae, 0x62, 0x6b, 0x59, 0x50, 0x18, 0x05, 0x23, 0xbc, - 0x5b, 0xde, 0x10, 0xa3, 0xa2, 0x12, 0xde, 0x2d, 0x6f, 0x44, 0x84, 0x7b, 0x75, 0x2d, 0x58, 0xd6, - 0xdd, 0xf2, 0xc6, 0x27, 0x37, 0xed, 0xff, 0xbd, 0x2c, 0x0f, 0x59, 0xc2, 0x1b, 0xf6, 0x01, 0x4c, - 0x68, 0x31, 0xc9, 0x33, 0x91, 0x3c, 0x16, 0xc6, 0x8f, 0x8f, 0x59, 0x0c, 0x69, 0x04, 0x32, 0x4d, - 0x11, 0xfb, 0x8d, 0x12, 0xaf, 0x6a, 0x6c, 0x13, 0x72, 0x40, 0x99, 0x38, 0x9e, 0xa6, 0x28, 0x24, - 0x21, 0xb7, 0x20, 0xbf, 0x49, 0xdb, 0x76, 0x3b, 0x08, 0x15, 0xa2, 0x68, 0x5c, 0x1c, 0x20, 0x4c, - 0x97, 0x1a, 0x42, 0x44, 0x34, 0x84, 0xed, 0xee, 0xf8, 0x75, 0xcf, 0xc1, 0xd0, 0x46, 0xe1, 0x59, - 0xcc, 0x0d, 0x61, 0x95, 0x12, 0x9d, 0x41, 0x8c, 0xc8, 0xf8, 0xb9, 0x0c, 0x8c, 0x8a, 0x81, 0xe4, - 0xe9, 0xe5, 0xf6, 0xa2, 0xb3, 0x44, 0x38, 0x0f, 0xec, 0x39, 0x71, 0xe7, 0x81, 0x3d, 0x1e, 0x3f, - 0x68, 0x4c, 0x38, 0xd6, 0x85, 0x4f, 0x83, 0x38, 0x1b, 0xa5, 0xdb, 0xa7, 0x9e, 0x3d, 0x2c, 0x44, - 0x1d, 0xd4, 0x21, 0xcb, 0xf8, 0x3b, 0xe2, 0xcb, 0xee, 0x96, 0x37, 0xc8, 0x22, 0xe4, 0x57, 0x5d, - 0x1e, 0x0a, 0x4b, 0xcd, 0x15, 0xdc, 0x14, 0x30, 0xb5, 0x83, 0x24, 0x1e, 0xfb, 0xbe, 0x0d, 0xcf, - 0x15, 0x77, 0x19, 0xe5, 0xfb, 0x3a, 0x1c, 0x18, 0xfb, 0xbe, 0x10, 0x75, 0xe0, 0xef, 0xa3, 0x29, - 0x9b, 0xc4, 0xc3, 0x5b, 0x98, 0xbf, 0xe5, 0x9e, 0xea, 0xe8, 0x26, 0x8a, 0xe4, 0x4e, 0xb1, 0xd0, - 0x6b, 0xa7, 0x78, 0x78, 0xcb, 0x4c, 0xa1, 0xc2, 0x77, 0xb5, 0x08, 0x5c, 0xa3, 0xde, 0xa3, 0x67, - 0x78, 0x97, 0x4e, 0x7f, 0x57, 0x8b, 0x37, 0x6f, 0xa0, 0x4d, 0xfa, 0xf7, 0xb3, 0x70, 0x3e, 0x9d, - 0x50, 0x6d, 0x4b, 0xa6, 0x4f, 0x5b, 0xae, 0x42, 0x7e, 0xc5, 0xf5, 0x03, 0xc5, 0x48, 0x10, 0xd5, - 0xff, 0xfb, 0x02, 0x66, 0x86, 0xa5, 0xec, 0xce, 0xcd, 0xfe, 0x0e, 0x97, 0x27, 0xf2, 0xc3, 0x40, - 0x1d, 0xec, 0xce, 0xcd, 0x8b, 0xc8, 0x5d, 0xc8, 0x9b, 0xc2, 0xd1, 0x2a, 0xd6, 0x35, 0x12, 0x1c, - 0x4a, 0x53, 0xc4, 0x13, 0x10, 0x2d, 0x34, 0xbc, 0x80, 0x91, 0x12, 0x8c, 0x8a, 0xd1, 0x8f, 0x3d, - 0x1d, 0xa7, 0x4c, 0x19, 0x3d, 0x5b, 0x83, 0xa4, 0x63, 0x3b, 0x0a, 0x3e, 0x02, 0x56, 0x2b, 0xd2, - 0x67, 0x0a, 0x77, 0x14, 0xfe, 0x48, 0xa8, 0xdb, 0x63, 0x86, 0x88, 0xc6, 0x0f, 0x65, 0x01, 0xa4, - 0xd6, 0xe6, 0x99, 0x9d, 0x61, 0x9f, 0xd5, 0x66, 0x98, 0x62, 0x6f, 0x34, 0x78, 0x3a, 0xe4, 0x07, - 0x68, 0xce, 0x33, 0x78, 0x32, 0xe4, 0x22, 0x0c, 0x6f, 0x46, 0x0a, 0x2d, 0xe1, 0x92, 0x82, 0xea, - 0x68, 0x0e, 0x37, 0x76, 0x60, 0xee, 0x2e, 0x0d, 0x22, 0xf5, 0x96, 0x7c, 0x7a, 0xec, 0xcf, 0xf6, - 0x0d, 0x18, 0x13, 0xf8, 0xe1, 0xfe, 0xc5, 0x75, 0x31, 0x22, 0xf6, 0x0d, 0xea, 0x62, 0x24, 0x02, - 0xdb, 0x8d, 0x2a, 0xb4, 0x49, 0x03, 0xfa, 0xc9, 0x56, 0x53, 0x03, 0xc2, 0x9b, 0x82, 0x2d, 0x1b, - 0xac, 0x86, 0x53, 0xfb, 0xe7, 0x21, 0x9c, 0x0b, 0xbf, 0xfd, 0x69, 0xf2, 0xbd, 0xc1, 0xae, 0x94, - 0x22, 0xd1, 0x41, 0xc4, 0xb1, 0x8f, 0xed, 0xc9, 0x63, 0x58, 0x90, 0x04, 0xdb, 0x4e, 0x68, 0x38, - 0x39, 0x10, 0x2d, 0x79, 0x17, 0xc6, 0x15, 0x1a, 0x11, 0xa8, 0x1f, 0xd5, 0xd4, 0x87, 0x4e, 0xb0, - 0x6f, 0xf9, 0x1c, 0xae, 0xaa, 0xa9, 0x15, 0x74, 0xe3, 0xcb, 0xf0, 0x7c, 0xe8, 0x36, 0x94, 0x52, - 0x75, 0x8c, 0x79, 0xe6, 0x6c, 0xcc, 0xd7, 0xa3, 0x66, 0x55, 0xdb, 0xa1, 0x67, 0xb4, 0xe4, 0x4d, - 0xd4, 0x66, 0x89, 0xc6, 0xbc, 0x90, 0xf0, 0xb5, 0x56, 0x5c, 0xaa, 0x8d, 0x77, 0x94, 0x8f, 0x4d, - 0x61, 0xa8, 0x11, 0x67, 0xe2, 0xc4, 0x3f, 0x94, 0x85, 0xe9, 0x07, 0xd5, 0x4a, 0x39, 0xb4, 0x3e, - 0xfa, 0x2e, 0x4b, 0xd6, 0xac, 0xb5, 0xad, 0xf7, 0x7e, 0x63, 0x6c, 0xc1, 0x6c, 0xac, 0x1b, 0x50, - 0x74, 0x78, 0x9f, 0x3b, 0x9c, 0x84, 0x60, 0x29, 0x36, 0x9c, 0x4f, 0x63, 0xff, 0xf0, 0x96, 0x19, - 0xc3, 0x36, 0xfe, 0x4b, 0x88, 0xf1, 0x15, 0x5b, 0xd8, 0x1b, 0x30, 0x56, 0xf5, 0xfd, 0x2e, 0xf5, - 0xb6, 0xcc, 0x55, 0x55, 0x55, 0xe0, 0x20, 0xd0, 0xea, 0x7a, 0x4d, 0x33, 0x42, 0x20, 0xd7, 0x20, - 0x2f, 0x82, 0xa4, 0xcb, 0x3d, 0x01, 0xb5, 0xb6, 0x61, 0x8c, 0x75, 0x33, 0x2c, 0x26, 0x6f, 0xc1, - 0x04, 0xff, 0x9b, 0xcf, 0x36, 0xd1, 0xe1, 0xa8, 0x1c, 0x14, 0xe8, 0x7c, 0x76, 0x9a, 0x1a, 0x1a, - 0x79, 0x1d, 0x72, 0xa5, 0xb2, 0x29, 0xd4, 0x41, 0x42, 0x6e, 0xf4, 0x2c, 0xae, 0xb3, 0xd3, 0x2e, - 0x11, 0x65, 0x93, 0x49, 0x7f, 0x32, 0xd8, 0x84, 0xd0, 0x64, 0xe3, 0x0c, 0x90, 0xda, 0xa6, 0xd8, - 0x61, 0x86, 0x30, 0x72, 0x03, 0x46, 0x2b, 0xdc, 0x64, 0x4e, 0xe8, 0xb1, 0x79, 0x26, 0x42, 0x0e, - 0xd2, 0x82, 0x2b, 0x70, 0x10, 0xb9, 0x26, 0x33, 0xb4, 0xe5, 0x23, 0xbf, 0x95, 0x1e, 0x69, 0xd8, - 0xde, 0x80, 0x11, 0x11, 0x4a, 0x7c, 0x4c, 0xc9, 0xdd, 0x12, 0x0f, 0x21, 0x2e, 0x70, 0x92, 0x0e, - 0xac, 0xf0, 0x34, 0x1d, 0x58, 0x77, 0xe0, 0xc2, 0x5d, 0xd4, 0xde, 0xe8, 0x01, 0xb1, 0xb6, 0xcc, - 0xaa, 0xd0, 0x87, 0xe3, 0x33, 0x10, 0x57, 0xf0, 0xc4, 0x63, 0x6a, 0x59, 0x5d, 0x4f, 0x4d, 0xac, - 0xdb, 0x8b, 0x11, 0xf9, 0x12, 0xcc, 0xa5, 0x15, 0x09, 0xad, 0x39, 0x86, 0x7e, 0x4a, 0xaf, 0x40, - 0x0d, 0xfd, 0x94, 0xc6, 0x81, 0xac, 0x42, 0x81, 0xc3, 0x4b, 0x8d, 0x96, 0xd3, 0xe6, 0x9a, 0x7f, - 0xae, 0x55, 0x47, 0x47, 0x12, 0xc1, 0xd5, 0x66, 0x85, 0xfc, 0x05, 0x40, 0x73, 0x3d, 0x8a, 0x51, - 0x92, 0x9f, 0xcc, 0xb0, 0xdb, 0x1c, 0x0f, 0xbc, 0xbd, 0x65, 0xae, 0xfa, 0x22, 0x6c, 0xe0, 0xf9, - 0xc8, 0xab, 0xa8, 0x16, 0x78, 0x4e, 0x7b, 0x4f, 0xb8, 0x15, 0x6d, 0x0a, 0xb7, 0xa2, 0x77, 0x3f, - 0x96, 0x5b, 0x11, 0x67, 0xe5, 0x9f, 0x1c, 0x17, 0x27, 0x3c, 0x51, 0x27, 0xae, 0x22, 0xed, 0x0b, - 0x58, 0xd7, 0xa1, 0x6f, 0xed, 0x56, 0x9b, 0x87, 0xfd, 0xa5, 0x0d, 0xde, 0xc8, 0x69, 0xdc, 0xc1, - 0xb1, 0xeb, 0x30, 0x27, 0x88, 0xd5, 0x0d, 0x11, 0x12, 0x0d, 0x4d, 0xe5, 0xc0, 0x2e, 0x9e, 0xd2, - 0x75, 0x85, 0x7b, 0xe3, 0x16, 0xa2, 0x8b, 0xa7, 0xf4, 0x73, 0xb1, 0x70, 0x1a, 0xa9, 0x93, 0x47, - 0x23, 0x21, 0x37, 0x60, 0x64, 0xcd, 0x7e, 0x5c, 0xda, 0xa3, 0x22, 0xf3, 0xe6, 0xa4, 0xdc, 0xfe, - 0x10, 0xb8, 0x94, 0xff, 0x03, 0xee, 0xeb, 0xf0, 0x9c, 0x29, 0xd0, 0xc8, 0x5f, 0xcb, 0xc0, 0x79, - 0xbe, 0x8c, 0x65, 0x2b, 0x6b, 0x34, 0x08, 0x58, 0x3f, 0x88, 0xf8, 0x81, 0x97, 0x23, 0x83, 0xed, - 0x74, 0x3c, 0xf4, 0xbc, 0x37, 0xc4, 0xce, 0x10, 0x76, 0x9c, 0x2f, 0x4a, 0xb5, 0x40, 0xcc, 0xa9, - 0xf4, 0x64, 0x13, 0xc6, 0xd7, 0xee, 0x94, 0xc2, 0x6a, 0x79, 0x74, 0xf6, 0x62, 0xda, 0xee, 0xa8, - 0xa0, 0xa5, 0x79, 0x1a, 0xa8, 0x6c, 0x84, 0x77, 0xc0, 0x67, 0x65, 0x7f, 0x90, 0x37, 0x55, 0x57, - 0xd4, 0x1c, 0x4a, 0xcf, 0xa3, 0x2d, 0xfb, 0xb1, 0x65, 0xef, 0x51, 0xed, 0x95, 0x5c, 0x68, 0xaf, - 0x7f, 0x26, 0x03, 0x17, 0x7b, 0x36, 0x99, 0xdc, 0x86, 0x0b, 0x36, 0x77, 0xb0, 0xb6, 0xf6, 0x83, - 0xa0, 0xe3, 0x5b, 0xf2, 0x8a, 0x21, 0x9c, 0x57, 0xcd, 0x73, 0xa2, 0x78, 0x85, 0x95, 0xca, 0x5b, - 0x87, 0x4f, 0x3e, 0x80, 0x17, 0x9c, 0xb6, 0x4f, 0xeb, 0x5d, 0x8f, 0x5a, 0x92, 0x41, 0xdd, 0x69, - 0x78, 0x96, 0x67, 0xb7, 0xf7, 0xa4, 0x27, 0xae, 0x79, 0x51, 0xe2, 0x08, 0x27, 0xee, 0xb2, 0xd3, - 0xf0, 0x4c, 0x44, 0x30, 0xfe, 0x45, 0x06, 0xe6, 0x7b, 0x75, 0x09, 0x99, 0x87, 0x51, 0xaa, 0xe4, - 0x69, 0xc9, 0x9b, 0xf2, 0x27, 0x79, 0x1e, 0xa2, 0x9d, 0x5e, 0x9c, 0xfe, 0xf9, 0xba, 0xc8, 0x99, - 0x81, 0xa6, 0xed, 0xea, 0xbe, 0x2e, 0x0c, 0x94, 0x27, 0xea, 0xea, 0xee, 0xfe, 0x22, 0x40, 0xb4, - 0x9d, 0x73, 0xc5, 0x84, 0x39, 0x66, 0xd7, 0x3d, 0xbe, 0xf2, 0xc8, 0x79, 0x18, 0xe1, 0xdb, 0xa5, - 0xf0, 0x7f, 0x10, 0xbf, 0xd8, 0xb9, 0x2d, 0x3a, 0x19, 0xf7, 0xf9, 0xdc, 0xd2, 0x84, 0xd6, 0xd9, - 0x23, 0x2d, 0x1c, 0x1c, 0xe3, 0xa7, 0x26, 0xb9, 0x08, 0x51, 0xea, 0x06, 0xfb, 0x52, 0xe8, 0x58, - 0x4c, 0xf3, 0x17, 0xe3, 0xb6, 0x94, 0x8a, 0x5d, 0xb6, 0xee, 0x25, 0x26, 0xdf, 0x7e, 0xb2, 0xa9, - 0x6f, 0x3f, 0x6f, 0xc0, 0x58, 0x79, 0x9f, 0xd6, 0x0f, 0x42, 0x27, 0x9c, 0xbc, 0x50, 0xae, 0x33, - 0x20, 0x0f, 0x89, 0x1e, 0x21, 0x90, 0x1b, 0x00, 0xe8, 0xa6, 0xca, 0x25, 0x52, 0x25, 0xad, 0x09, - 0x7a, 0xb5, 0x0a, 0xf3, 0x14, 0x05, 0x05, 0xd9, 0xd7, 0xcc, 0x3b, 0xaa, 0x3d, 0x0b, 0x67, 0xef, - 0x7b, 0xbb, 0x02, 0x3d, 0x42, 0x60, 0xcd, 0x53, 0xf6, 0x15, 0x71, 0x0a, 0x16, 0x12, 0x9b, 0x8f, - 0x8a, 0x44, 0xae, 0xc3, 0xd8, 0x86, 0x74, 0x24, 0xc0, 0x43, 0x70, 0x02, 0x29, 0x20, 0x72, 0x3a, - 0x98, 0xcf, 0x98, 0x11, 0x0a, 0xf9, 0x2c, 0x8c, 0x96, 0xa9, 0x17, 0x6c, 0x6e, 0xae, 0xa2, 0xd1, - 0x09, 0xcf, 0xfe, 0x91, 0xc7, 0x4c, 0x0d, 0x41, 0xd0, 0xfc, 0xce, 0x71, 0x71, 0x32, 0x70, 0x5a, - 0x34, 0x8c, 0x6a, 0x6e, 0x4a, 0x6c, 0xb2, 0x04, 0x05, 0xfe, 0x2c, 0x1e, 0xdd, 0x3d, 0xf0, 0x64, - 0xcc, 0xf3, 0x73, 0x5a, 0xbc, 0xa1, 0x1f, 0xd2, 0x9d, 0x30, 0x4f, 0x45, 0x02, 0x9f, 0x2c, 0xcb, - 0xf4, 0x2e, 0x6a, 0x33, 0x21, 0x52, 0x86, 0xc5, 0x77, 0x0c, 0xd6, 0xda, 0x24, 0x05, 0x29, 0xc1, - 0x64, 0xd9, 0x6d, 0x75, 0xec, 0xc0, 0xc1, 0x3c, 0x98, 0x47, 0xe2, 0x10, 0x44, 0x85, 0x5e, 0x5d, - 0x2d, 0xd0, 0x4e, 0x54, 0xb5, 0x80, 0xdc, 0x81, 0x29, 0xd3, 0xed, 0xb2, 0x61, 0x92, 0xb7, 0x70, - 0x7e, 0xce, 0xa1, 0x69, 0x88, 0xc7, 0x4a, 0xd8, 0xb1, 0x2c, 0xae, 0xdc, 0x5a, 0x04, 0x58, 0x8d, - 0x8a, 0xac, 0xa7, 0x3c, 0x87, 0xa8, 0x87, 0x9b, 0x9a, 0xad, 0x22, 0xc1, 0x2c, 0xe5, 0x25, 0xe5, - 0x16, 0x8c, 0xd7, 0x6a, 0x0f, 0x36, 0xa9, 0x1f, 0xdc, 0x69, 0xba, 0x87, 0x78, 0xb6, 0xe5, 0x45, - 0x72, 0x35, 0xdf, 0xb5, 0x02, 0xea, 0x07, 0xd6, 0x6e, 0xd3, 0x3d, 0x34, 0x55, 0x2c, 0xf2, 0x35, - 0xd6, 0x1f, 0x8a, 0x24, 0x28, 0x62, 0xdd, 0xf6, 0x13, 0x56, 0xf1, 0x04, 0x89, 0x16, 0x0d, 0x13, - 0x59, 0xf5, 0xce, 0x52, 0xd0, 0xd1, 0xa7, 0xcc, 0x73, 0x1f, 0x1f, 0x95, 0x1a, 0x0d, 0x8f, 0xfa, - 0xbe, 0x38, 0x84, 0xb8, 0x4f, 0x19, 0x2a, 0x1b, 0x6c, 0x5e, 0xa0, 0xf9, 0x94, 0x29, 0x04, 0xe4, - 0x47, 0x32, 0x70, 0x4e, 0xf5, 0x36, 0xc1, 0xe5, 0x82, 0x66, 0x2e, 0xfc, 0x48, 0x7a, 0xf3, 0xba, - 0x3c, 0x84, 0xaf, 0x2b, 0x68, 0xd7, 0x1f, 0xdd, 0xbc, 0x5e, 0x8a, 0x7e, 0xd6, 0x24, 0x11, 0xc6, - 0xed, 0x2b, 0xa6, 0xf2, 0xd3, 0x72, 0x13, 0xcd, 0xd9, 0x29, 0xc4, 0xa4, 0xcc, 0x24, 0x35, 0x36, - 0xa3, 0xd0, 0x70, 0xaa, 0xba, 0x81, 0x67, 0x9a, 0xd0, 0xa8, 0x8a, 0xf9, 0xc7, 0x4d, 0xac, 0x9c, - 0x8e, 0x2e, 0x90, 0x29, 0x34, 0xa4, 0x0a, 0xd3, 0x1c, 0xc0, 0xb6, 0x05, 0x9e, 0xe6, 0x69, 0x36, - 0x4a, 0x34, 0x21, 0xd8, 0xe0, 0x5b, 0x3f, 0xa6, 0x7a, 0x52, 0x83, 0xb3, 0xc6, 0xe8, 0xc8, 0x07, - 0x30, 0x85, 0x31, 0xf4, 0xa3, 0xf5, 0x3a, 0x87, 0xab, 0x18, 0x63, 0xcc, 0x8a, 0x92, 0x98, 0xe7, - 0xdd, 0x84, 0xef, 0xef, 0x47, 0x2b, 0xfa, 0x03, 0x98, 0x42, 0x5b, 0x9d, 0x88, 0xc1, 0xb9, 0x88, - 0x81, 0x28, 0x89, 0x33, 0x08, 0x9a, 0x7e, 0xc4, 0xe0, 0xa7, 0x33, 0x70, 0x91, 0x55, 0x94, 0x3e, - 0x42, 0xe7, 0x3f, 0xce, 0x08, 0x61, 0xd4, 0xcd, 0x9e, 0x3c, 0x55, 0x71, 0xd4, 0xf7, 0xf7, 0xd3, - 0x38, 0xe0, 0x47, 0xb1, 0x8f, 0x4f, 0xff, 0xa8, 0x0b, 0x1f, 0xfb, 0xa3, 0x7a, 0xf2, 0x54, 0x3f, - 0x2a, 0x68, 0xfa, 0x69, 0x1c, 0xf0, 0x5a, 0x5b, 0x2b, 0xad, 0xad, 0x46, 0x77, 0xb3, 0xef, 0x2e, - 0xb7, 0x15, 0xad, 0x6d, 0x7d, 0xdc, 0x56, 0xb6, 0xb8, 0x17, 0xb5, 0xd2, 0x0d, 0xf2, 0x5a, 0xab, - 0x81, 0xe3, 0xd7, 0xda, 0x18, 0x8d, 0x19, 0xc3, 0x36, 0x7e, 0x09, 0x62, 0x7c, 0x85, 0xa9, 0xaa, - 0x01, 0x23, 0xfc, 0xd6, 0x2a, 0x3a, 0x19, 0x6d, 0x16, 0xf8, 0x9d, 0xd6, 0x14, 0x25, 0xe4, 0x22, - 0xe4, 0x6a, 0xb5, 0x07, 0xa2, 0x93, 0xd1, 0x60, 0xd5, 0xf7, 0x5d, 0x93, 0xc1, 0xd8, 0x08, 0xa1, - 0x15, 0xaa, 0x92, 0x93, 0x80, 0x9d, 0x77, 0x26, 0x42, 0x59, 0x7f, 0xcb, 0x3b, 0xe4, 0x50, 0xd4, - 0xdf, 0xe2, 0x0e, 0x19, 0xdd, 0x1c, 0xcb, 0x30, 0x5f, 0xf2, 0x7d, 0xea, 0xb1, 0x09, 0x21, 0x8c, - 0x1b, 0x3d, 0x71, 0xcf, 0x11, 0x07, 0x3b, 0x56, 0x6a, 0xd7, 0x7d, 0xb3, 0x27, 0x22, 0xb9, 0x0a, - 0xf9, 0x52, 0xb7, 0xe1, 0xd0, 0x76, 0x5d, 0x0b, 0xcb, 0x66, 0x0b, 0x98, 0x19, 0x96, 0x92, 0x2f, - 0xc2, 0xb9, 0x58, 0x04, 0x46, 0xd1, 0x03, 0xa3, 0xd1, 0xde, 0x2b, 0xef, 0x61, 0x91, 0x41, 0x06, - 0xef, 0x92, 0x74, 0x4a, 0x52, 0x82, 0xc2, 0x32, 0xba, 0x69, 0x55, 0x28, 0x7f, 0x1b, 0x72, 0x3d, - 0xee, 0x9f, 0xc7, 0x6f, 0xcd, 0x22, 0xce, 0x64, 0x23, 0x2c, 0x34, 0x13, 0xe8, 0xe4, 0x3e, 0xcc, - 0xc6, 0x61, 0xec, 0x04, 0xe7, 0x17, 0x64, 0xdc, 0x6f, 0x12, 0x5c, 0xf0, 0x0c, 0x4f, 0xa3, 0x22, - 0x3b, 0x30, 0x13, 0x19, 0x24, 0xe9, 0xd7, 0x66, 0x69, 0xe7, 0x1c, 0x96, 0xcb, 0xab, 0xf3, 0xf3, - 0x62, 0x32, 0xce, 0x46, 0xc6, 0x4d, 0xe1, 0xf5, 0xd9, 0x4c, 0xb2, 0x23, 0x0d, 0x98, 0xaa, 0x39, - 0x7b, 0x6d, 0xa7, 0xbd, 0x77, 0x9f, 0x1e, 0x6d, 0xd8, 0x8e, 0x27, 0x2c, 0x4e, 0xa5, 0x3d, 0x79, - 0xc9, 0x3f, 0x6a, 0xb5, 0x68, 0xe0, 0xe1, 0x46, 0xc8, 0xca, 0xd1, 0x07, 0x9d, 0x5d, 0x87, 0x16, - 0x7c, 0x4e, 0x87, 0x6e, 0x9b, 0x1d, 0xdb, 0xd1, 0x84, 0x00, 0x9d, 0xa7, 0xa6, 0xba, 0x98, 0x18, - 0x50, 0x75, 0xd1, 0x84, 0x99, 0xe5, 0x76, 0xdd, 0x3b, 0xc2, 0x27, 0x3a, 0xf9, 0x71, 0x93, 0xa7, - 0x7c, 0xdc, 0x2b, 0xe2, 0xe3, 0x5e, 0xb0, 0xe5, 0x0c, 0x4b, 0xfb, 0xbc, 0x24, 0x63, 0x52, 0x83, - 0x19, 0xbc, 0x38, 0x54, 0x2b, 0x1b, 0xd5, 0xb6, 0x13, 0x38, 0x76, 0x40, 0x1b, 0x42, 0xb8, 0x08, - 0x33, 0xb9, 0xf0, 0x2b, 0xaa, 0xd3, 0xe8, 0x58, 0x8e, 0x44, 0x51, 0x99, 0x26, 0xe8, 0xfb, 0xdd, - 0x13, 0xa7, 0xff, 0x9c, 0xee, 0x89, 0x55, 0x98, 0x8e, 0x87, 0x72, 0x28, 0x44, 0xe7, 0xb0, 0x8f, - 0x45, 0xec, 0x38, 0x77, 0xbb, 0x28, 0x4c, 0x6a, 0xc9, 0x53, 0x63, 0x41, 0x1c, 0x62, 0x57, 0xce, - 0x19, 0xed, 0xca, 0xa9, 0xed, 0x4a, 0x67, 0xb8, 0x72, 0x92, 0x0d, 0x80, 0x3b, 0xae, 0x57, 0xa7, - 0x25, 0xf4, 0x8f, 0x26, 0x5a, 0xbe, 0x2b, 0xc6, 0x34, 0x2a, 0xe4, 0xeb, 0x67, 0x97, 0xfd, 0xb6, - 0xe2, 0x6e, 0xee, 0x0a, 0x0f, 0xe3, 0x47, 0xb3, 0x30, 0xdf, 0xeb, 0x73, 0xfa, 0x5c, 0xf7, 0x3e, - 0x05, 0xc9, 0x15, 0x2e, 0xae, 0x7d, 0x05, 0x1a, 0x5f, 0xe7, 0x8b, 0x90, 0xbe, 0x90, 0xc5, 0x35, - 0x70, 0x36, 0x4e, 0xb0, 0xe5, 0x35, 0xc9, 0x6d, 0x18, 0x57, 0x3e, 0x1e, 0xf7, 0xd2, 0x5e, 0x4d, - 0x35, 0x61, 0x37, 0xfc, 0x9b, 0x5d, 0x13, 0xf9, 0xbe, 0x25, 0xaf, 0x89, 0xfc, 0x17, 0x29, 0x70, - 0x17, 0xf1, 0x11, 0x6e, 0x05, 0xe0, 0xfb, 0x2e, 0x21, 0x80, 0xfb, 0x36, 0xdf, 0x02, 0x4d, 0xfc, - 0xdb, 0xf8, 0x8d, 0x09, 0x7e, 0x22, 0xab, 0xb7, 0xc4, 0x5e, 0xf6, 0xc1, 0xb1, 0xdb, 0x63, 0xf6, - 0x2c, 0xb7, 0xc7, 0xdc, 0xe9, 0xb7, 0xc7, 0xa1, 0xd3, 0x6e, 0x8f, 0xb1, 0xeb, 0xdd, 0xf0, 0x99, - 0xaf, 0x77, 0x23, 0x67, 0xba, 0xde, 0x8d, 0x9e, 0xe9, 0x7a, 0xa7, 0xdd, 0x54, 0xf3, 0xa7, 0xdd, - 0x54, 0xff, 0xf2, 0x32, 0xf8, 0xac, 0x5e, 0x06, 0xd3, 0x44, 0xbc, 0x33, 0x5d, 0x06, 0x7f, 0xb8, - 0xe7, 0x5d, 0xae, 0xf0, 0x71, 0x84, 0xf2, 0x97, 0x07, 0xb8, 0xcb, 0x0d, 0x7a, 0x93, 0x9b, 0x79, - 0x3a, 0x37, 0x39, 0xf2, 0xd4, 0x6e, 0x72, 0xb3, 0x4f, 0x7a, 0x93, 0x9b, 0x7b, 0x9a, 0x37, 0xb9, - 0x73, 0x7f, 0x11, 0x6f, 0x72, 0xe7, 0xff, 0xed, 0xdc, 0xe4, 0xfe, 0x0a, 0x14, 0xe2, 0xc2, 0xe5, - 0xe9, 0x51, 0x8f, 0x9f, 0x5a, 0xc8, 0x49, 0x26, 0xfa, 0xc6, 0x85, 0x3b, 0x72, 0x03, 0x60, 0xc3, - 0x73, 0x1e, 0xd9, 0x01, 0xbd, 0x2f, 0xad, 0xdf, 0x44, 0xc4, 0x6e, 0x0e, 0x65, 0x23, 0x6f, 0x2a, - 0x28, 0xe1, 0xbd, 0x26, 0x9b, 0x76, 0xaf, 0x31, 0x7e, 0x24, 0x0b, 0x33, 0x3c, 0x6e, 0xdb, 0xb3, - 0xff, 0x08, 0xfb, 0xbe, 0x76, 0x5b, 0x7d, 0x21, 0xca, 0x11, 0xa0, 0xb6, 0xae, 0xcf, 0x33, 0xec, - 0x57, 0xe1, 0x5c, 0xa2, 0x2b, 0xf0, 0xc6, 0x5a, 0x91, 0x11, 0xf3, 0x12, 0x77, 0xd6, 0xf9, 0xf4, - 0x4a, 0x1e, 0xde, 0x32, 0x13, 0x14, 0xc6, 0x9f, 0x0e, 0x25, 0xf8, 0x8b, 0x07, 0x59, 0xf5, 0x89, - 0x35, 0x73, 0xb6, 0x27, 0xd6, 0xec, 0x60, 0x4f, 0xac, 0x31, 0xa1, 0x22, 0x37, 0x88, 0x50, 0xf1, - 0x45, 0x98, 0xdc, 0xa4, 0x76, 0xcb, 0xdf, 0x74, 0x45, 0xc2, 0x29, 0xee, 0x6b, 0x21, 0x03, 0xe2, - 0xb1, 0x32, 0x79, 0xe1, 0x0a, 0x6d, 0x46, 0x03, 0x46, 0xc0, 0x8e, 0x41, 0x9e, 0x81, 0xca, 0xd4, - 0x39, 0xa8, 0xb7, 0xe8, 0xe1, 0x3e, 0xb7, 0xe8, 0x1a, 0x4c, 0x08, 0xba, 0x28, 0xd4, 0x73, 0x74, - 0xdd, 0x63, 0x45, 0x08, 0x97, 0xb5, 0x87, 0xd9, 0xf0, 0xc3, 0xda, 0xf9, 0x4d, 0x4f, 0x63, 0xc2, - 0xba, 0x60, 0xb9, 0xdd, 0xe8, 0xb8, 0x4e, 0x1b, 0xbb, 0x60, 0x34, 0xea, 0x02, 0x2a, 0xc0, 0xbc, - 0x0b, 0x14, 0x24, 0xf2, 0x2e, 0x4c, 0x95, 0x36, 0xaa, 0x2a, 0x59, 0x3e, 0x7a, 0xe5, 0xb5, 0x3b, - 0x8e, 0xa5, 0x91, 0xc6, 0x70, 0xfb, 0xdd, 0x7c, 0xc6, 0xfe, 0x7c, 0x6e, 0x3e, 0xc6, 0x3f, 0x9b, - 0x94, 0xcb, 0xfb, 0x93, 0x7d, 0x20, 0xd1, 0x9f, 0x3c, 0x72, 0x67, 0x7c, 0xf2, 0x18, 0x3a, 0x4d, - 0x90, 0xd4, 0xe4, 0xdb, 0xe1, 0x33, 0xc9, 0xb7, 0x23, 0x4f, 0xfc, 0x7c, 0x31, 0x7a, 0x46, 0x89, - 0x35, 0xb6, 0xd6, 0xf2, 0x83, 0xac, 0xb5, 0x54, 0x29, 0x77, 0xec, 0xc9, 0xa5, 0x5c, 0x38, 0xb3, - 0x94, 0x5b, 0x8b, 0x7c, 0x97, 0xc7, 0x4f, 0x75, 0x09, 0x79, 0x51, 0x68, 0x05, 0x66, 0xd2, 0xa3, - 0xf0, 0x85, 0x5e, 0xcc, 0xdf, 0x55, 0xa2, 0xf3, 0xd7, 0xd3, 0x45, 0xe7, 0xfe, 0xe7, 0xcd, 0x99, - 0x84, 0xe7, 0x1f, 0x79, 0xba, 0xc2, 0xf3, 0xd3, 0x7d, 0x08, 0xf9, 0x4b, 0xf1, 0xf9, 0x2f, 0xc5, - 0xe7, 0xc1, 0xc4, 0x67, 0xf2, 0x00, 0x88, 0xdd, 0x0d, 0xf6, 0x69, 0x3b, 0x70, 0xea, 0x18, 0x95, - 0x96, 0x0d, 0x31, 0xbe, 0xca, 0x88, 0xf5, 0x9a, 0x2c, 0x55, 0xd7, 0xab, 0x56, 0x8a, 0x7e, 0xde, - 0x1e, 0xae, 0xd7, 0x6d, 0xdb, 0x6b, 0xa3, 0x1e, 0xeb, 0x06, 0x8c, 0xca, 0xb8, 0xa6, 0x99, 0x48, - 0x45, 0x9d, 0x0c, 0x68, 0x2a, 0xb1, 0xc8, 0x22, 0xe4, 0x25, 0xb1, 0x9a, 0x68, 0xe7, 0x50, 0xc0, - 0xb4, 0x90, 0x91, 0x02, 0x66, 0xfc, 0x47, 0x43, 0xf2, 0x4c, 0x60, 0x9f, 0xb0, 0x61, 0x7b, 0x76, - 0x0b, 0x73, 0xf0, 0x85, 0x4b, 0x56, 0xb9, 0x0d, 0xc4, 0x56, 0x79, 0xcc, 0x57, 0x40, 0x27, 0xf9, - 0x58, 0x81, 0x69, 0xa3, 0x34, 0xc7, 0xb9, 0x01, 0xd2, 0x1c, 0xbf, 0xad, 0xe5, 0x08, 0x1e, 0x8a, - 0x92, 0x52, 0xb2, 0x7d, 0xb2, 0x7f, 0x76, 0xe0, 0xdb, 0x6a, 0x32, 0xdf, 0xe1, 0x28, 0x4c, 0x18, - 0x52, 0xf6, 0x49, 0xe3, 0x1b, 0x5e, 0x6f, 0x46, 0xce, 0x12, 0xf2, 0x79, 0xf4, 0xdf, 0x6a, 0xc8, - 0xe7, 0x65, 0x00, 0x71, 0x76, 0x47, 0xf6, 0x0e, 0xaf, 0xe2, 0x76, 0x22, 0xec, 0x9e, 0x83, 0xa0, - 0xd9, 0x23, 0x27, 0x88, 0x42, 0x68, 0xfc, 0x1e, 0x81, 0x99, 0x5a, 0xed, 0x41, 0xc5, 0xb1, 0xf7, - 0xda, 0xae, 0x1f, 0x38, 0xf5, 0x6a, 0x7b, 0xd7, 0x65, 0xb2, 0x7d, 0x78, 0xbe, 0x28, 0xc1, 0x7a, - 0xa3, 0xb3, 0x25, 0x2c, 0x66, 0x77, 0xc7, 0x65, 0xcf, 0x93, 0x0a, 0x57, 0x7e, 0x77, 0xa4, 0x0c, - 0x60, 0x72, 0x38, 0x13, 0x9f, 0x6b, 0x5d, 0x0c, 0x95, 0x21, 0x8c, 0x50, 0x50, 0x7c, 0xf6, 0x39, - 0xc8, 0x94, 0x65, 0x84, 0x26, 0x27, 0xac, 0xb8, 0x4e, 0x5d, 0xd0, 0x02, 0x47, 0x47, 0xc5, 0x7c, - 0x35, 0x0a, 0xe9, 0x06, 0xf7, 0xe1, 0x0e, 0xc2, 0x55, 0x13, 0xbb, 0xc4, 0x1a, 0x38, 0x82, 0x73, - 0x9a, 0x13, 0xf5, 0xa0, 0xaf, 0x33, 0xaf, 0x0b, 0x71, 0xdd, 0xc0, 0x98, 0x1d, 0x29, 0x4f, 0x34, - 0x6a, 0x52, 0xbd, 0xd4, 0x1a, 0xd8, 0x01, 0xf9, 0x62, 0x6a, 0x49, 0xb8, 0xba, 0xc7, 0xb5, 0xe0, - 0xdd, 0xca, 0xa6, 0xc1, 0xd3, 0x07, 0xf6, 0xaa, 0xda, 0x4a, 0xd9, 0x0a, 0xfa, 0xd7, 0x44, 0xfe, - 0x71, 0x06, 0x2e, 0x68, 0x18, 0xe1, 0xfe, 0xe7, 0x87, 0xf1, 0x45, 0x52, 0xe7, 0xf5, 0x47, 0x4f, - 0x67, 0x5e, 0xbf, 0xac, 0xb7, 0x25, 0xda, 0xa1, 0xd5, 0x36, 0xf4, 0xfa, 0x42, 0xf2, 0x08, 0x66, - 0xb0, 0x48, 0xbe, 0x14, 0xb1, 0x39, 0x2b, 0x1e, 0x98, 0xe6, 0xa2, 0xcf, 0xe6, 0x81, 0x01, 0x30, - 0x05, 0xfc, 0xe2, 0xb7, 0x8f, 0x8b, 0x93, 0x1a, 0xba, 0x0c, 0x87, 0x6d, 0x45, 0xcf, 0x4d, 0x4e, - 0x7b, 0xd7, 0xd5, 0xf2, 0xfb, 0xc7, 0xab, 0x20, 0xff, 0x75, 0x86, 0xbf, 0x4f, 0xf0, 0x66, 0xdc, - 0xf1, 0xdc, 0x56, 0x58, 0x2e, 0x6d, 0x35, 0x7b, 0x74, 0x5b, 0xf3, 0xe9, 0x74, 0xdb, 0xab, 0xf8, - 0xc9, 0x7c, 0x4f, 0xb0, 0x76, 0x3d, 0xb7, 0x15, 0x7d, 0xbe, 0xda, 0x71, 0x3d, 0x3f, 0x92, 0xfc, - 0xf5, 0x0c, 0x5c, 0xd4, 0xd4, 0xa4, 0x6a, 0x6e, 0x12, 0x11, 0x7e, 0x61, 0x36, 0x0c, 0xcc, 0x12, - 0x15, 0x2d, 0x5d, 0x17, 0xf3, 0xff, 0x0a, 0x7e, 0x81, 0x12, 0x07, 0x94, 0x21, 0x59, 0x2d, 0x8e, - 0xa5, 0x7c, 0x42, 0xef, 0x5a, 0x88, 0x03, 0x33, 0x68, 0xb6, 0xa3, 0xd9, 0x14, 0xcf, 0xf5, 0xb6, - 0x29, 0x0e, 0xb3, 0x0e, 0x61, 0x46, 0x82, 0xde, 0x86, 0xc5, 0x49, 0xae, 0xe4, 0xfb, 0xe0, 0x62, - 0x02, 0x18, 0xae, 0xb6, 0x73, 0x3d, 0x57, 0xdb, 0xa7, 0x4e, 0x8e, 0x8b, 0xaf, 0xa5, 0xd5, 0x96, - 0xb6, 0xd2, 0x7a, 0xd7, 0x40, 0x6c, 0x80, 0xa8, 0x50, 0xc8, 0x33, 0xe9, 0x13, 0xf4, 0x53, 0x62, - 0x7e, 0x28, 0xf8, 0x6c, 0x2f, 0x57, 0xbe, 0x41, 0x3d, 0xf2, 0x22, 0x24, 0x42, 0x61, 0x42, 0xc9, - 0xc6, 0x70, 0x24, 0xac, 0x47, 0x7a, 0x54, 0xf2, 0xed, 0xe3, 0xa2, 0x86, 0xcd, 0x6e, 0x58, 0x6a, - 0x9a, 0x07, 0x4d, 0x7c, 0x54, 0x11, 0xc9, 0xaf, 0x67, 0x60, 0x8e, 0x01, 0xa2, 0x49, 0x25, 0x1a, - 0x35, 0xdf, 0x6f, 0xd6, 0xef, 0x3f, 0x9d, 0x59, 0xff, 0x12, 0x7e, 0xa3, 0x3a, 0xeb, 0x13, 0x5d, - 0x92, 0xfa, 0x71, 0x38, 0xdb, 0x35, 0x0b, 0x31, 0x6d, 0xb6, 0x5f, 0x1c, 0x60, 0xb6, 0xf3, 0x01, - 0x38, 0x7d, 0xb6, 0xf7, 0xac, 0x85, 0x6c, 0xc2, 0x84, 0xb8, 0x5c, 0xf1, 0x0e, 0xbb, 0xa4, 0xc5, - 0x85, 0x56, 0x8b, 0xf8, 0x8d, 0x57, 0x24, 0xab, 0x48, 0xb4, 0x50, 0xe3, 0x42, 0xda, 0x30, 0xcb, - 0x7f, 0xeb, 0xca, 0xae, 0x62, 0x4f, 0x65, 0xd7, 0x55, 0xd1, 0xa2, 0xcb, 0x82, 0x7f, 0x4c, 0xe7, - 0xa5, 0xc6, 0x73, 0x4a, 0x61, 0x4c, 0x3a, 0x40, 0x34, 0x30, 0x5f, 0xb4, 0x97, 0xfb, 0xab, 0xb8, - 0x5e, 0x13, 0x75, 0x16, 0xe3, 0x75, 0xc6, 0x57, 0x6e, 0x0a, 0x6f, 0x62, 0xc3, 0xb4, 0x80, 0xba, - 0x07, 0x94, 0xef, 0xf0, 0x2f, 0x69, 0x11, 0xb5, 0x62, 0xa5, 0xfc, 0x56, 0x26, 0x6b, 0xc2, 0x88, - 0x67, 0xb1, 0x0d, 0x3d, 0xce, 0x8f, 0x3c, 0x80, 0x99, 0x52, 0xa7, 0xd3, 0x74, 0x68, 0x03, 0x5b, - 0x69, 0x76, 0x59, 0x9b, 0x8c, 0x28, 0xdf, 0x9b, 0xcd, 0x0b, 0xc5, 0x55, 0xd1, 0xeb, 0xc6, 0xb6, - 0x9b, 0x04, 0xad, 0xf1, 0xc3, 0x99, 0xc4, 0x47, 0x93, 0x37, 0x60, 0x0c, 0x7f, 0x28, 0x41, 0x5a, - 0x50, 0x67, 0xc4, 0x3f, 0x11, 0xb5, 0x51, 0x11, 0x02, 0x13, 0x96, 0xd4, 0x40, 0x8d, 0x39, 0x2e, - 0x2c, 0x09, 0x45, 0x45, 0xa4, 0x9a, 0x28, 0x4a, 0x5f, 0x8f, 0x5c, 0x24, 0x74, 0xa1, 0xaf, 0x87, - 0xf0, 0xf0, 0x30, 0xfe, 0x61, 0x56, 0x9f, 0x76, 0xe4, 0xaa, 0x22, 0xb7, 0x2b, 0xa1, 0x22, 0xa5, - 0xdc, 0xae, 0x48, 0xeb, 0x7f, 0x2f, 0x03, 0xb3, 0x0f, 0x94, 0x44, 0xa1, 0x9b, 0x2e, 0x8e, 0x4b, - 0xff, 0xd4, 0x99, 0x4f, 0x2b, 0x05, 0xa0, 0x9a, 0xa1, 0x94, 0xcd, 0x14, 0x9c, 0x32, 0x66, 0xda, - 0xf7, 0xa0, 0xf7, 0x1c, 0x7e, 0x98, 0x92, 0x89, 0x91, 0xa3, 0x73, 0xf8, 0x19, 0x53, 0x57, 0x18, - 0x3f, 0x9e, 0x85, 0x71, 0x65, 0xc5, 0x90, 0xcf, 0xc0, 0x84, 0x5a, 0xad, 0xaa, 0x70, 0x54, 0xbf, - 0xd2, 0xd4, 0xb0, 0x50, 0xe3, 0x48, 0xed, 0x96, 0xa6, 0x71, 0x64, 0xeb, 0x02, 0xa1, 0x67, 0xbc, - 0x09, 0x7d, 0x90, 0x72, 0x13, 0xc2, 0x59, 0xae, 0x68, 0x8c, 0xfa, 0xde, 0x87, 0xde, 0x4d, 0xde, - 0x87, 0x50, 0x79, 0xa5, 0xd0, 0xf7, 0xbe, 0x15, 0x19, 0x3f, 0x95, 0x81, 0x42, 0x7c, 0x4d, 0x7f, - 0x22, 0xbd, 0x72, 0x86, 0xd7, 0xa5, 0x1f, 0xcb, 0x86, 0x99, 0x5b, 0xa4, 0x0b, 0xf1, 0xb3, 0x6a, - 0xa6, 0xf8, 0x9e, 0xf6, 0xf0, 0xf3, 0xbc, 0x1e, 0x0d, 0x4f, 0x0d, 0xbe, 0x91, 0x1e, 0x02, 0x73, - 0xe8, 0x5b, 0xbf, 0x58, 0x7c, 0xce, 0xf8, 0x10, 0xe6, 0xe2, 0xdd, 0x81, 0x8f, 0x3f, 0x25, 0x98, - 0xd6, 0xe1, 0xf1, 0xbc, 0x4f, 0x71, 0x2a, 0x33, 0x8e, 0x6f, 0xfc, 0x41, 0x36, 0xce, 0x5b, 0x98, - 0x2c, 0xb2, 0x3d, 0x4a, 0x35, 0xc4, 0x11, 0x7b, 0x14, 0x07, 0x99, 0xb2, 0xec, 0x2c, 0xf9, 0xd6, - 0x42, 0x47, 0xd8, 0x5c, 0xba, 0x23, 0x2c, 0xb9, 0x1d, 0xb3, 0xd2, 0x56, 0xa2, 0x36, 0x1d, 0xd2, - 0x1d, 0x2b, 0xb2, 0xd4, 0x8e, 0x19, 0x67, 0x97, 0x61, 0x4e, 0x0b, 0x41, 0x2e, 0xe9, 0x87, 0x23, - 0x5d, 0x7f, 0x80, 0x05, 0x9c, 0x38, 0x15, 0x99, 0xac, 0xc0, 0x28, 0xfb, 0xcc, 0x35, 0xbb, 0x23, - 0xde, 0x74, 0x48, 0xe8, 0x16, 0xdf, 0x0c, 0xef, 0x87, 0x8a, 0x67, 0x7c, 0x93, 0x32, 0x09, 0x41, - 0x9d, 0x58, 0x02, 0xd1, 0xf8, 0x57, 0x19, 0xb6, 0xfe, 0xeb, 0x07, 0xdf, 0x65, 0x49, 0xdb, 0x58, - 0x93, 0xfa, 0x58, 0xd4, 0xfe, 0x51, 0x96, 0xe7, 0xe2, 0x11, 0xd3, 0xe7, 0x6d, 0x18, 0xd9, 0xb4, - 0xbd, 0x3d, 0x91, 0x32, 0x5b, 0xe7, 0xc2, 0x0b, 0xa2, 0x98, 0x52, 0x01, 0xfe, 0x36, 0x05, 0x81, - 0xaa, 0x3a, 0xcb, 0x0e, 0xa4, 0x3a, 0x53, 0xde, 0x05, 0x72, 0x4f, 0xed, 0x5d, 0xe0, 0x7b, 0xc2, - 0xb4, 0x3b, 0xa5, 0x60, 0x80, 0x08, 0xd7, 0x97, 0xe3, 0x59, 0xae, 0x12, 0xb1, 0xc8, 0x23, 0x76, - 0xe4, 0xb6, 0x9a, 0x37, 0x4b, 0xf1, 0x2d, 0x3d, 0x25, 0x43, 0x96, 0xf1, 0x47, 0x39, 0xde, 0xc7, - 0xa2, 0xa3, 0xae, 0x68, 0x7e, 0xe7, 0xb8, 0x4e, 0x62, 0x7a, 0x4a, 0xee, 0x81, 0x7e, 0x05, 0x86, - 0xd8, 0xdc, 0x14, 0xbd, 0x89, 0x78, 0x6c, 0xfe, 0xaa, 0x78, 0xac, 0x9c, 0xad, 0x65, 0x3c, 0x93, - 0xd4, 0x84, 0x88, 0x78, 0x6c, 0xa9, 0x6b, 0x19, 0x31, 0xc8, 0x55, 0x18, 0x5a, 0x77, 0x1b, 0x32, - 0x92, 0xfa, 0x1c, 0x46, 0x1f, 0xd1, 0x32, 0xae, 0xce, 0x67, 0x4c, 0xc4, 0x60, 0x6d, 0x0d, 0xf3, - 0x4f, 0xa8, 0x6d, 0x6d, 0xed, 0xda, 0xc9, 0x44, 0x77, 0x4a, 0xd2, 0x9b, 0x65, 0x98, 0xda, 0x76, - 0xda, 0x0d, 0xf7, 0xd0, 0xaf, 0x50, 0xff, 0x20, 0x70, 0x3b, 0xc2, 0xde, 0x18, 0xb5, 0xfb, 0x87, - 0xbc, 0xc4, 0x6a, 0xf0, 0x22, 0xf5, 0x59, 0x46, 0x27, 0x22, 0x4b, 0x30, 0xa9, 0x45, 0x70, 0x15, - 0x8f, 0xab, 0xa8, 0x0d, 0xd5, 0xe3, 0xbf, 0xaa, 0xda, 0x50, 0x8d, 0x84, 0x9d, 0xe7, 0xe2, 0xfb, - 0x95, 0x27, 0xd6, 0xc4, 0xb7, 0x0b, 0x1c, 0x72, 0x0b, 0xf2, 0x3c, 0xcc, 0x47, 0xb5, 0xa2, 0x3e, - 0x93, 0xf9, 0x08, 0x8b, 0x85, 0xc9, 0x91, 0x88, 0x4a, 0x58, 0x87, 0x4f, 0x43, 0x41, 0x6c, 0x49, - 0x51, 0xae, 0xf6, 0x17, 0x60, 0xa8, 0x5c, 0xad, 0x98, 0xea, 0x36, 0x52, 0x77, 0x1a, 0x9e, 0x89, - 0x50, 0xf4, 0xea, 0x5b, 0xa7, 0xc1, 0xa1, 0xeb, 0x1d, 0x98, 0xd4, 0x0f, 0x3c, 0x87, 0xe7, 0xd3, - 0xc4, 0x85, 0xf8, 0x19, 0xf2, 0x2e, 0x0c, 0xa3, 0xe1, 0x6b, 0xec, 0x64, 0x88, 0xd7, 0xb1, 0x34, - 0x29, 0x26, 0xf0, 0x30, 0x5a, 0xd1, 0x9a, 0x9c, 0x88, 0xbc, 0x0d, 0x43, 0x15, 0xda, 0x3e, 0x8a, - 0xa5, 0xfa, 0x4b, 0x10, 0x87, 0x1b, 0x42, 0x83, 0xb6, 0x8f, 0x4c, 0x24, 0x31, 0x7e, 0x2a, 0x0b, - 0xe7, 0x52, 0x3e, 0xeb, 0xe1, 0x67, 0x9e, 0xd1, 0x5d, 0x71, 0x49, 0xdb, 0x15, 0xe5, 0xfb, 0x78, - 0xcf, 0x8e, 0x4f, 0xdd, 0x24, 0x7f, 0x3e, 0x03, 0x17, 0xf4, 0x09, 0x2a, 0x2c, 0xdd, 0x1f, 0xde, - 0x22, 0xef, 0xc0, 0xc8, 0x0a, 0xb5, 0x1b, 0x54, 0xe6, 0xf5, 0x3a, 0x17, 0x06, 0xe4, 0xe3, 0x31, - 0x0c, 0x78, 0x21, 0x67, 0x1b, 0x79, 0xbc, 0x72, 0x28, 0xa9, 0x88, 0x8f, 0xe3, 0xe2, 0xbb, 0x21, - 0xe3, 0x89, 0xa4, 0x55, 0xd5, 0xc7, 0xca, 0xe4, 0xdb, 0x19, 0x78, 0xbe, 0x0f, 0x0d, 0x1b, 0x38, - 0x36, 0xf4, 0xea, 0xc0, 0xe1, 0x89, 0x8a, 0x50, 0xf2, 0x3e, 0x4c, 0x6f, 0x0a, 0xf1, 0x5f, 0x0e, - 0x47, 0x36, 0x5a, 0x2f, 0xf2, 0x66, 0x60, 0xc9, 0x71, 0x89, 0x23, 0x6b, 0x81, 0x6e, 0x72, 0x7d, - 0x03, 0xdd, 0xa8, 0x71, 0x63, 0x86, 0x06, 0x8d, 0x1b, 0xf3, 0x21, 0xcc, 0xe9, 0x6d, 0x13, 0xe1, - 0x7b, 0xa3, 0xa8, 0x39, 0x99, 0xde, 0x51, 0x73, 0xfa, 0x06, 0x09, 0x35, 0x7e, 0x3c, 0x03, 0x05, - 0x9d, 0xf7, 0x93, 0x8e, 0xe7, 0x7b, 0xda, 0x78, 0x3e, 0x9f, 0x3e, 0x9e, 0xbd, 0x07, 0xf2, 0xff, - 0xca, 0xc4, 0x1b, 0x3b, 0xd0, 0x08, 0x1a, 0x30, 0x52, 0x71, 0x5b, 0xb6, 0xd3, 0x56, 0x53, 0xff, - 0x37, 0x10, 0x62, 0x8a, 0x92, 0xc1, 0x82, 0x0c, 0x5d, 0x86, 0xe1, 0x75, 0xb7, 0x5d, 0xaa, 0x08, - 0x93, 0x62, 0xe4, 0xd3, 0x76, 0xdb, 0x96, 0xdd, 0x30, 0x79, 0x01, 0x59, 0x05, 0xa8, 0xd5, 0x3d, - 0x4a, 0xdb, 0x35, 0xe7, 0x7b, 0x69, 0x4c, 0xd2, 0x60, 0x3d, 0xd4, 0xec, 0xe2, 0xc6, 0xc2, 0x9f, - 0x4e, 0x11, 0xd1, 0xf2, 0x9d, 0xef, 0x55, 0xf7, 0x5b, 0x85, 0x1e, 0xd7, 0x95, 0x88, 0xc3, 0x16, - 0x1b, 0x87, 0x9b, 0x9f, 0xc4, 0xba, 0x4a, 0xad, 0x0a, 0x7b, 0xf8, 0x66, 0xea, 0x70, 0xfc, 0x7e, - 0x06, 0x9e, 0xef, 0x43, 0xf3, 0x14, 0x46, 0xe5, 0xcf, 0xbb, 0xc3, 0x29, 0x40, 0x44, 0x84, 0x99, - 0x94, 0x9d, 0x46, 0xc0, 0x73, 0xf5, 0x4d, 0x8a, 0x4c, 0xca, 0x0c, 0xa0, 0x65, 0x52, 0x66, 0x00, - 0x76, 0x96, 0xae, 0x50, 0x67, 0x6f, 0x9f, 0x9b, 0x87, 0x4d, 0xf2, 0xbd, 0x61, 0x1f, 0x21, 0xea, - 0x59, 0xca, 0x71, 0x8c, 0x7f, 0x3d, 0x0c, 0x17, 0x4d, 0xba, 0xe7, 0xb0, 0x7b, 0xc9, 0x96, 0xef, - 0xb4, 0xf7, 0xb4, 0xb8, 0x3b, 0x46, 0x6c, 0xe5, 0x8a, 0x24, 0x15, 0x0c, 0x12, 0xce, 0xc4, 0x6b, - 0x90, 0x67, 0x62, 0x88, 0xb2, 0x78, 0xf1, 0x8d, 0x8b, 0x09, 0x2b, 0x22, 0xb0, 0xb3, 0x2c, 0x26, - 0xaf, 0x0b, 0x31, 0x49, 0x49, 0x23, 0xc4, 0xc4, 0xa4, 0xef, 0x1c, 0x17, 0xa1, 0x76, 0xe4, 0x07, - 0x14, 0xaf, 0xc8, 0x42, 0x54, 0x0a, 0xef, 0x32, 0x43, 0x3d, 0xee, 0x32, 0x6b, 0x30, 0x57, 0x6a, - 0xf0, 0xd3, 0xd1, 0x6e, 0x6e, 0x78, 0x4e, 0xbb, 0xee, 0x74, 0xec, 0xa6, 0xbc, 0x9f, 0x63, 0x2f, - 0xdb, 0x61, 0xb9, 0xd5, 0x09, 0x11, 0xcc, 0x54, 0x32, 0xd6, 0x8c, 0xca, 0x7a, 0x0d, 0xc3, 0xd3, - 0x88, 0xe7, 0x4b, 0x6c, 0x46, 0xa3, 0xed, 0x63, 0x2b, 0x7c, 0x33, 0x2c, 0xc6, 0x5b, 0x14, 0x1a, - 0x04, 0x6c, 0xae, 0xd6, 0x22, 0x97, 0x6a, 0x9e, 0xe5, 0x80, 0x1b, 0x16, 0x04, 0x4d, 0x1f, 0x4d, - 0x31, 0x35, 0xbc, 0x88, 0xae, 0x56, 0x5b, 0x61, 0x74, 0xf9, 0x04, 0x9d, 0xef, 0xef, 0xab, 0x74, - 0x1c, 0x8f, 0xdc, 0x60, 0x53, 0xa1, 0xe5, 0x06, 0x14, 0xa7, 0xf0, 0x58, 0x74, 0xe7, 0xf2, 0x10, - 0xca, 0xef, 0x5c, 0x0a, 0x0a, 0x79, 0x17, 0x66, 0x97, 0xcb, 0x8b, 0x52, 0xe9, 0x5c, 0x71, 0xeb, - 0x5d, 0x34, 0x04, 0x00, 0xac, 0x0f, 0xc7, 0x90, 0xd6, 0x17, 0xd9, 0x6e, 0x92, 0x86, 0x46, 0xae, - 0xc0, 0x68, 0xb5, 0xc2, 0xfb, 0x7e, 0x5c, 0x4d, 0xe5, 0x25, 0x2c, 0xb3, 0x64, 0x21, 0x79, 0x10, - 0x5d, 0x0a, 0x26, 0x4e, 0x95, 0xde, 0x2f, 0x0e, 0x70, 0x21, 0x78, 0x1b, 0x26, 0x97, 0xdc, 0xa0, - 0xda, 0xf6, 0x03, 0xbb, 0x5d, 0xa7, 0xd5, 0x8a, 0x1a, 0x57, 0x7b, 0xc7, 0x0d, 0x2c, 0x47, 0x94, - 0xb0, 0x2f, 0xd7, 0x31, 0xc9, 0xe7, 0x90, 0xf4, 0x2e, 0x6d, 0x53, 0x2f, 0x8a, 0xa7, 0x3d, 0xcc, - 0xfb, 0x96, 0x91, 0xee, 0x85, 0x25, 0xa6, 0x8e, 0x28, 0xd2, 0x8c, 0xf1, 0xe4, 0xa0, 0x65, 0xb7, - 0x41, 0x7d, 0xbe, 0x5b, 0x7c, 0x17, 0xa5, 0x19, 0x53, 0xda, 0xd6, 0x67, 0x07, 0xfd, 0xf7, 0x31, - 0xcd, 0x58, 0x02, 0x97, 0x7c, 0x0e, 0x86, 0xf1, 0xa7, 0x90, 0x6e, 0x67, 0x53, 0xd8, 0x46, 0x92, - 0x6d, 0x9d, 0x61, 0x9a, 0x9c, 0x80, 0x54, 0x61, 0x54, 0x5c, 0xac, 0xce, 0x92, 0x2c, 0x47, 0xdc, - 0xd0, 0xf8, 0xcc, 0x10, 0xf4, 0x46, 0x03, 0x26, 0xd4, 0x0a, 0xd9, 0x8a, 0x58, 0xb1, 0xfd, 0x7d, - 0xda, 0x60, 0xbf, 0x44, 0x9e, 0x3b, 0x5c, 0x11, 0xfb, 0x08, 0xb5, 0xd8, 0x77, 0x98, 0x0a, 0x0a, - 0x3b, 0x53, 0xab, 0xfe, 0x96, 0x2f, 0x3e, 0x45, 0xa8, 0x5a, 0x1c, 0x54, 0xdb, 0x35, 0x4c, 0x51, - 0x64, 0x7c, 0x0f, 0xcc, 0xad, 0x77, 0x9b, 0x4d, 0x7b, 0xa7, 0x49, 0x65, 0x1e, 0x14, 0x4c, 0x38, - 0xbe, 0x04, 0xc3, 0x35, 0x25, 0x85, 0x79, 0x98, 0x8b, 0x52, 0xc1, 0x41, 0x23, 0xd8, 0x0c, 0x86, - 0x0a, 0x8a, 0x25, 0x2f, 0xe7, 0xa4, 0xc6, 0xef, 0x66, 0x60, 0x4e, 0x9a, 0x0b, 0x78, 0x76, 0xfd, - 0x20, 0xcc, 0x63, 0x7f, 0x45, 0x9b, 0x6b, 0x38, 0x61, 0x63, 0xd3, 0x88, 0xcf, 0xba, 0x7b, 0xf2, - 0x23, 0x74, 0x81, 0x25, 0xed, 0x83, 0x4f, 0xfb, 0x18, 0xf2, 0x2e, 0x8c, 0x8b, 0xe3, 0x51, 0x09, - 0x70, 0x89, 0x51, 0xc4, 0xc4, 0x75, 0x2f, 0x6e, 0xbc, 0xa2, 0xa2, 0xa3, 0x2c, 0xa6, 0x37, 0xe5, - 0x49, 0x65, 0x80, 0x74, 0x59, 0x4c, 0xaf, 0xa3, 0xcf, 0xd4, 0xfd, 0xad, 0xf1, 0x78, 0xdf, 0x8a, - 0xb9, 0x7b, 0x5b, 0x0d, 0x69, 0x97, 0x89, 0x6e, 0xc6, 0x51, 0x48, 0x3b, 0xf5, 0x66, 0x1c, 0xa2, - 0x86, 0x63, 0x92, 0x3d, 0x65, 0x4c, 0xde, 0x97, 0x63, 0x92, 0xeb, 0x3d, 0x31, 0x66, 0xfb, 0x8c, - 0x43, 0x2d, 0x5a, 0x21, 0x43, 0x03, 0xa9, 0x55, 0x9e, 0xc3, 0xd8, 0xfd, 0x9c, 0x24, 0xbe, 0x8b, - 0x0a, 0x4e, 0xaa, 0xae, 0x66, 0x78, 0x70, 0xa6, 0xa7, 0x6c, 0xcd, 0x9f, 0x87, 0x89, 0x52, 0x10, - 0xd8, 0xf5, 0x7d, 0xda, 0xa8, 0xb0, 0xed, 0x49, 0x89, 0xbe, 0x65, 0x0b, 0xb8, 0xfa, 0xc6, 0xa6, - 0xe2, 0xf2, 0x68, 0xb2, 0xb6, 0x2f, 0x8c, 0x69, 0xc3, 0x68, 0xb2, 0x0c, 0xa2, 0x47, 0x93, 0x65, - 0x10, 0x72, 0x03, 0x46, 0xab, 0xed, 0x47, 0x0e, 0xeb, 0x13, 0x1e, 0x80, 0x0b, 0x75, 0x53, 0x0e, - 0x07, 0xa9, 0x9b, 0xab, 0xc0, 0x22, 0x6f, 0x2b, 0x97, 0x9a, 0xb1, 0x48, 0x81, 0xc1, 0x55, 0x5e, - 0x61, 0x84, 0x1d, 0xf5, 0xc2, 0x12, 0xde, 0x72, 0x6e, 0xc3, 0xa8, 0xd4, 0x64, 0x42, 0xa4, 0xb4, - 0x10, 0x94, 0xc9, 0x80, 0x15, 0x12, 0x19, 0x73, 0x92, 0x2b, 0xf9, 0xfa, 0xc6, 0x95, 0x9c, 0xe4, - 0x4a, 0xbe, 0x3e, 0x2d, 0x27, 0xb9, 0x92, 0xb9, 0x2f, 0x54, 0x02, 0x4d, 0x9c, 0xaa, 0x04, 0x7a, - 0x08, 0x13, 0x1b, 0xb6, 0x17, 0x38, 0x4c, 0x46, 0x69, 0x07, 0xfe, 0xfc, 0xa4, 0xa6, 0x37, 0x55, - 0x8a, 0x96, 0x2e, 0xc9, 0xbc, 0xd8, 0x1d, 0x05, 0x5f, 0x4f, 0xe0, 0x1c, 0xc1, 0xd3, 0x4d, 0x69, - 0xa7, 0x9e, 0xc4, 0x94, 0x16, 0x3b, 0x15, 0x75, 0x65, 0xd3, 0x91, 0x46, 0x06, 0x2f, 0x2d, 0x31, - 0x85, 0x59, 0x88, 0x48, 0xbe, 0x02, 0x13, 0xec, 0xef, 0x0d, 0xb7, 0xe9, 0xd4, 0x1d, 0xea, 0xcf, - 0x17, 0xb0, 0x71, 0x97, 0x52, 0x57, 0x3f, 0x22, 0x1d, 0xd5, 0x68, 0xc0, 0x17, 0x30, 0x32, 0x8e, - 0x2b, 0xc1, 0x35, 0x6e, 0xe4, 0x03, 0x98, 0x60, 0xb3, 0x6f, 0xc7, 0xf6, 0xb9, 0x68, 0x3a, 0x13, - 0x19, 0x43, 0x37, 0x04, 0x3c, 0x11, 0xd0, 0x59, 0x25, 0x60, 0xc7, 0x7c, 0xa9, 0xc3, 0x37, 0x48, - 0xa2, 0xcc, 0xf6, 0x4e, 0x62, 0x73, 0x94, 0x68, 0xe4, 0x0b, 0x30, 0x51, 0xea, 0x74, 0xa2, 0x1d, - 0x67, 0x56, 0x51, 0x84, 0x75, 0x3a, 0x56, 0xea, 0xae, 0xa3, 0x51, 0xc4, 0x37, 0xe6, 0xb9, 0x33, - 0x6d, 0xcc, 0xe4, 0xcd, 0x50, 0x5a, 0x3f, 0x17, 0x69, 0x75, 0xc5, 0xc5, 0x51, 0x13, 0xfd, 0xb9, - 0xe0, 0x5e, 0x86, 0x49, 0xae, 0xe6, 0x94, 0xd2, 0xcc, 0xf9, 0xc4, 0xea, 0x49, 0x11, 0x6a, 0x74, - 0x1a, 0xb2, 0x0c, 0x53, 0xdc, 0xdb, 0xbb, 0x29, 0x22, 0x6d, 0xcf, 0x5f, 0xc0, 0x55, 0x8b, 0x5c, - 0xb8, 0x93, 0x78, 0x13, 0x13, 0xb0, 0xd8, 0x1a, 0x97, 0x18, 0x91, 0xf1, 0xc7, 0x19, 0xb8, 0xd0, - 0x63, 0xc4, 0xc3, 0x38, 0xcc, 0x99, 0xfe, 0x71, 0x98, 0xd9, 0xce, 0xa1, 0x6b, 0x45, 0xb0, 0xfd, - 0x42, 0xca, 0x52, 0xc7, 0x4b, 0xca, 0x5b, 0x2e, 0x10, 0x91, 0xe3, 0x48, 0x54, 0x7d, 0xcf, 0x45, - 0xd5, 0x6c, 0x2e, 0x79, 0x08, 0x09, 0x3c, 0xfe, 0x51, 0x4b, 0xc6, 0xc9, 0x71, 0xf1, 0x92, 0x48, - 0xa1, 0x14, 0x0e, 0xeb, 0x47, 0xae, 0xb6, 0x82, 0x53, 0x58, 0x1b, 0xc7, 0x19, 0x18, 0x57, 0xd6, - 0x21, 0xb9, 0xac, 0x78, 0x21, 0x17, 0x78, 0x12, 0x2e, 0x85, 0x43, 0x96, 0x9f, 0x44, 0xb8, 0xa8, - 0xb2, 0xa7, 0x2b, 0xa0, 0xd7, 0x98, 0x28, 0xa4, 0xc4, 0xaa, 0x6e, 0x69, 0xda, 0x62, 0x13, 0xcb, - 0x31, 0x9d, 0xbf, 0xed, 0x07, 0xa5, 0x7a, 0xe0, 0x3c, 0xa2, 0x03, 0x1c, 0x3a, 0x51, 0x3a, 0x7f, - 0xdb, 0x0f, 0x2c, 0x1b, 0xc9, 0x12, 0xe9, 0xfc, 0x43, 0x86, 0xc6, 0xf7, 0x67, 0x00, 0xb6, 0xaa, - 0x65, 0x0c, 0x36, 0xff, 0xa4, 0x42, 0x41, 0x7a, 0x00, 0x5f, 0xc9, 0xbd, 0x8f, 0x38, 0xf0, 0x3f, - 0x65, 0x60, 0x4a, 0x47, 0x23, 0xef, 0xc3, 0x74, 0xad, 0xee, 0xb9, 0xcd, 0xe6, 0x8e, 0x5d, 0x3f, - 0x58, 0x75, 0xda, 0x94, 0x87, 0x4e, 0x1d, 0xe6, 0x67, 0x91, 0x1f, 0x16, 0x59, 0x4d, 0x56, 0x66, - 0xc6, 0x91, 0xc9, 0x0f, 0x64, 0x60, 0xb2, 0xb6, 0xef, 0x1e, 0x86, 0xd1, 0x4e, 0xc5, 0x80, 0x7c, - 0x95, 0xad, 0x6d, 0x7f, 0xdf, 0x3d, 0x8c, 0x32, 0x78, 0x6a, 0xb6, 0xa2, 0xef, 0x0d, 0xf6, 0x8c, - 0x5f, 0x77, 0xf1, 0x26, 0x13, 0xf8, 0xd7, 0xb5, 0x4a, 0x4c, 0xbd, 0x4e, 0xe3, 0xcf, 0x32, 0x30, - 0x8e, 0x77, 0x9e, 0x66, 0x13, 0x65, 0xae, 0xef, 0xa6, 0x74, 0x90, 0x61, 0xbb, 0xfa, 0x0c, 0xec, - 0x5b, 0x30, 0x1d, 0x43, 0x23, 0x06, 0x8c, 0xd4, 0x30, 0xc0, 0x80, 0xaa, 0xa0, 0xe0, 0x21, 0x07, - 0x4c, 0x51, 0x62, 0x2c, 0x2b, 0x64, 0x0f, 0x6f, 0xe2, 0xb3, 0xee, 0x22, 0x80, 0x23, 0x41, 0xf2, - 0x66, 0x43, 0xe2, 0x5f, 0xf2, 0xf0, 0xa6, 0xa9, 0x60, 0x19, 0xeb, 0x30, 0x52, 0x73, 0xbd, 0x60, - 0xe9, 0x88, 0x5f, 0x26, 0x2a, 0xd4, 0xaf, 0xab, 0xef, 0xb6, 0x0e, 0xbe, 0x95, 0xd4, 0x4d, 0x51, - 0x44, 0x8a, 0x30, 0x7c, 0xc7, 0xa1, 0xcd, 0x86, 0x6a, 0xcf, 0xbb, 0xcb, 0x00, 0x26, 0x87, 0xb3, - 0x0b, 0xd7, 0xf9, 0x28, 0x27, 0x4b, 0x64, 0x38, 0xfc, 0xa4, 0xeb, 0xa6, 0xac, 0xf5, 0xef, 0x4b, - 0x61, 0x1e, 0x84, 0x64, 0x4d, 0x7d, 0xba, 0xfa, 0x1f, 0x66, 0x60, 0xa1, 0x37, 0x89, 0x6a, 0x8b, - 0x9c, 0xe9, 0x63, 0x8b, 0xfc, 0x6a, 0xfc, 0x9d, 0x11, 0xd1, 0xc4, 0x3b, 0x63, 0xf4, 0xba, 0x58, - 0x41, 0x53, 0xf0, 0x3a, 0x95, 0x89, 0x58, 0x2e, 0xf7, 0xf9, 0x66, 0x44, 0xe4, 0xc3, 0x1c, 0x20, - 0x8d, 0x29, 0x68, 0x8d, 0xdf, 0x1c, 0x82, 0x8b, 0x3d, 0x29, 0xc8, 0x8a, 0x92, 0xde, 0x69, 0x2a, - 0x4c, 0x2c, 0xd3, 0x13, 0xff, 0x3a, 0xfe, 0x8b, 0xd6, 0x7e, 0x71, 0x6f, 0xb7, 0x07, 0x61, 0x5a, - 0x9f, 0x2c, 0xf2, 0xfa, 0xd4, 0xa9, 0xbc, 0x38, 0x3a, 0x32, 0x83, 0x64, 0x86, 0x1f, 0xf4, 0x8b, - 0xa4, 0x81, 0xed, 0x34, 0x7d, 0x75, 0xd9, 0x35, 0x38, 0xc8, 0x94, 0x65, 0x91, 0x81, 0xf8, 0x50, - 0xba, 0x81, 0xb8, 0xf1, 0xaf, 0x33, 0x30, 0x16, 0x7e, 0x36, 0x59, 0x80, 0xf3, 0x9b, 0x66, 0xa9, - 0xbc, 0x6c, 0x6d, 0x7e, 0xb8, 0xb1, 0x6c, 0x6d, 0xad, 0xd7, 0x36, 0x96, 0xcb, 0xd5, 0x3b, 0xd5, - 0xe5, 0x4a, 0xe1, 0x39, 0x32, 0x03, 0x93, 0x5b, 0xeb, 0xf7, 0xd7, 0x1f, 0x6c, 0xaf, 0x5b, 0xcb, - 0xa6, 0xf9, 0xc0, 0x2c, 0x64, 0xc8, 0x24, 0x8c, 0x99, 0x4b, 0xa5, 0xb2, 0xb5, 0xfe, 0xa0, 0xb2, - 0x5c, 0xc8, 0x92, 0x02, 0x4c, 0x94, 0x1f, 0xac, 0xaf, 0x2f, 0x97, 0x37, 0xab, 0x0f, 0xab, 0x9b, - 0x1f, 0x16, 0x72, 0x84, 0xc0, 0x14, 0x22, 0x6c, 0x98, 0xd5, 0xf5, 0x72, 0x75, 0xa3, 0xb4, 0x5a, - 0x18, 0x62, 0x30, 0x86, 0xaf, 0xc0, 0x86, 0x43, 0x46, 0xf7, 0xb7, 0x96, 0x96, 0x0b, 0x23, 0x0c, - 0x85, 0xfd, 0xa5, 0xa0, 0x8c, 0xb2, 0xea, 0x11, 0xa5, 0x52, 0xda, 0x2c, 0x2d, 0x95, 0x6a, 0xcb, - 0x85, 0x3c, 0xb9, 0x00, 0xb3, 0x1a, 0xc8, 0x5a, 0x7d, 0x70, 0xb7, 0xba, 0x5e, 0x18, 0x23, 0x73, - 0x50, 0x08, 0x61, 0x95, 0x25, 0x6b, 0xab, 0xb6, 0x6c, 0x16, 0x20, 0x0e, 0x5d, 0x2f, 0xad, 0x2d, - 0x17, 0xc6, 0x8d, 0xf7, 0xb8, 0x1f, 0x22, 0xef, 0x6a, 0x72, 0x1e, 0x48, 0x6d, 0xb3, 0xb4, 0xb9, - 0x55, 0x8b, 0x35, 0x7e, 0x1c, 0x46, 0x6b, 0x5b, 0xe5, 0xf2, 0x72, 0xad, 0x56, 0xc8, 0x10, 0x80, - 0x91, 0x3b, 0xa5, 0xea, 0xea, 0x72, 0xa5, 0x90, 0x35, 0x7e, 0x32, 0x03, 0x33, 0x52, 0x02, 0x94, - 0x8f, 0x46, 0x4f, 0xb8, 0x16, 0xdf, 0xd7, 0x2e, 0xb6, 0xd2, 0x49, 0x2c, 0x56, 0x49, 0x9f, 0x65, - 0xf8, 0xf3, 0x19, 0x38, 0x97, 0x8a, 0x4d, 0x3e, 0x84, 0x82, 0xfc, 0x82, 0x35, 0x3b, 0xa8, 0xef, - 0x47, 0xfb, 0xd8, 0xa5, 0x58, 0x2d, 0x31, 0x34, 0xae, 0xd6, 0x8c, 0x12, 0x4e, 0x27, 0xd8, 0x0c, - 0x9e, 0x0e, 0xc1, 0xf8, 0x56, 0x06, 0x2e, 0xf4, 0xa8, 0x86, 0x94, 0x61, 0x24, 0x4c, 0x8c, 0xd3, - 0xc7, 0xe0, 0x6d, 0xee, 0xdb, 0xc7, 0x45, 0x81, 0x88, 0x19, 0x7a, 0xf1, 0x2f, 0x73, 0x24, 0xcc, - 0x74, 0x83, 0xe9, 0x66, 0x78, 0xf7, 0x5d, 0x8c, 0xf5, 0xbc, 0xa8, 0xa9, 0xb4, 0x5d, 0x5b, 0x1a, - 0x17, 0x7d, 0x97, 0xb3, 0x0f, 0x7d, 0xcc, 0x37, 0x63, 0xfc, 0x4c, 0x86, 0x09, 0x77, 0x71, 0x44, - 0x26, 0xf3, 0x96, 0x7c, 0xbf, 0xdb, 0xa2, 0xa6, 0xdb, 0xa4, 0x25, 0x73, 0x5d, 0x1c, 0x1b, 0x28, - 0xad, 0xda, 0x58, 0x80, 0xd7, 0x0a, 0xcb, 0xf6, 0xda, 0xda, 0x6b, 0xb5, 0x4a, 0x43, 0xde, 0x06, - 0x58, 0x7e, 0x1c, 0x50, 0xaf, 0x6d, 0x37, 0xc3, 0x18, 0x31, 0x3c, 0xb2, 0x95, 0x80, 0xea, 0xf2, - 0xb6, 0x82, 0x6c, 0xfc, 0x8d, 0x0c, 0x4c, 0x88, 0x4b, 0x53, 0xa9, 0x49, 0xbd, 0xe0, 0xc9, 0xa6, - 0xd7, 0xdb, 0xda, 0xf4, 0x0a, 0xfd, 0x3b, 0x14, 0xfe, 0xac, 0x38, 0x75, 0x66, 0xfd, 0xf3, 0x0c, - 0x14, 0xe2, 0x88, 0xe4, 0x7d, 0xc8, 0xd7, 0xe8, 0x23, 0xea, 0x39, 0xc1, 0x91, 0xd8, 0x28, 0x65, - 0x0a, 0x41, 0x8e, 0x23, 0xca, 0xf8, 0x7c, 0xf0, 0xc5, 0x2f, 0x33, 0xa4, 0x19, 0x74, 0xbf, 0x57, - 0xd4, 0x1e, 0xb9, 0xa7, 0xa5, 0xf6, 0x30, 0xfe, 0xb7, 0x2c, 0x5c, 0xb8, 0x4b, 0x03, 0xb5, 0x4d, - 0xa1, 0x79, 0xc1, 0xa7, 0x07, 0x6b, 0x97, 0xd2, 0x92, 0x79, 0x18, 0xc5, 0x22, 0x39, 0xbe, 0xa6, - 0xfc, 0x49, 0x96, 0xc2, 0x79, 0x9d, 0xd3, 0x72, 0x94, 0xf5, 0xa8, 0xfb, 0xba, 0x92, 0xb5, 0x28, - 0x9c, 0xd6, 0x57, 0x60, 0x0a, 0xc3, 0xf2, 0x77, 0xd9, 0x72, 0xa0, 0x0d, 0xa1, 0xfe, 0xc9, 0x9b, - 0x31, 0x28, 0x79, 0x1d, 0x0a, 0x0c, 0x52, 0xaa, 0x1f, 0xb4, 0xdd, 0xc3, 0x26, 0x6d, 0xec, 0xd1, - 0x06, 0x1e, 0xeb, 0x79, 0x33, 0x01, 0x97, 0x3c, 0xb7, 0xda, 0xfc, 0xea, 0x46, 0x1b, 0xa8, 0xa3, - 0x11, 0x3c, 0x23, 0xe8, 0xc2, 0xdb, 0x30, 0xfe, 0x31, 0x33, 0x90, 0x19, 0xff, 0x6b, 0x06, 0xe6, - 0xb0, 0x71, 0x4a, 0xc5, 0x32, 0x3b, 0xac, 0xec, 0x2d, 0x25, 0x29, 0x8f, 0xcd, 0x40, 0xfa, 0x52, - 0x08, 0x7b, 0x31, 0xd2, 0x09, 0x65, 0x07, 0xd0, 0x09, 0xd5, 0xce, 0x92, 0x09, 0x7f, 0x40, 0x95, - 0xd6, 0xbd, 0xa1, 0x7c, 0xae, 0x30, 0x14, 0x0d, 0xb9, 0xf1, 0x03, 0x59, 0x18, 0x35, 0x29, 0xa6, - 0x08, 0x27, 0x57, 0x60, 0x74, 0xdd, 0x0d, 0xa8, 0xbf, 0xa6, 0xe5, 0x83, 0x6f, 0x33, 0x90, 0xd5, - 0x6a, 0x98, 0xb2, 0x90, 0x4d, 0xf8, 0x0d, 0xcf, 0x6d, 0x74, 0xeb, 0x81, 0x3a, 0xe1, 0x3b, 0x1c, - 0x64, 0xca, 0x32, 0xf2, 0x06, 0x8c, 0x09, 0xce, 0xe1, 0xa3, 0x2e, 0xda, 0x2e, 0x7b, 0x34, 0x4c, - 0x31, 0x1f, 0x21, 0xa0, 0x4c, 0xcb, 0x05, 0x8c, 0x21, 0x45, 0xa6, 0x4d, 0xc8, 0x0c, 0x52, 0x54, - 0x1f, 0xee, 0x23, 0xaa, 0x7f, 0x1a, 0x46, 0x4a, 0xbe, 0x4f, 0x03, 0x19, 0x45, 0x61, 0x22, 0x0c, - 0x1b, 0xe7, 0xd3, 0x80, 0x33, 0xb6, 0xb1, 0xdc, 0x14, 0x78, 0xc6, 0xbf, 0xca, 0xc2, 0x30, 0xfe, - 0x89, 0x4f, 0xa6, 0x5e, 0x7d, 0x5f, 0x7b, 0x32, 0xf5, 0xea, 0xfb, 0x26, 0x42, 0xc9, 0x4d, 0xd4, - 0x54, 0xc8, 0xfc, 0x51, 0xa2, 0xf5, 0xa8, 0x82, 0x6f, 0x44, 0x60, 0x53, 0xc5, 0x09, 0x5f, 0xf8, - 0x73, 0xa9, 0xb1, 0x53, 0xce, 0x43, 0xf6, 0x41, 0x4d, 0xb4, 0x18, 0x23, 0x72, 0xb9, 0xbe, 0x99, - 0x7d, 0x50, 0xc3, 0xde, 0x58, 0x29, 0x2d, 0xbe, 0x75, 0x5b, 0x34, 0x94, 0xf7, 0xc6, 0xbe, 0xbd, - 0xf8, 0xd6, 0x6d, 0x53, 0x94, 0xb0, 0xfe, 0xc5, 0x6f, 0xc6, 0x87, 0x57, 0xee, 0xf3, 0x8f, 0xfd, - 0x8b, 0x6d, 0xc3, 0x47, 0x56, 0x33, 0x42, 0x20, 0x8b, 0x30, 0x2e, 0x62, 0x4d, 0x20, 0xbe, 0x12, - 0x0b, 0x42, 0xc4, 0xa2, 0xe0, 0x14, 0x2a, 0x12, 0x7f, 0x82, 0x13, 0x03, 0x24, 0xb3, 0xdc, 0x8a, - 0x27, 0x38, 0x39, 0x84, 0xbe, 0xa9, 0xa0, 0xb0, 0x4f, 0xe2, 0x6f, 0x78, 0x91, 0x2f, 0xff, 0x94, - 0x12, 0xb4, 0x00, 0xd3, 0x2c, 0x84, 0x08, 0xc6, 0x2f, 0x67, 0x21, 0xbf, 0xd1, 0xec, 0xee, 0x39, - 0xed, 0x87, 0x37, 0x09, 0x01, 0xbc, 0xc6, 0xc9, 0x3c, 0x1c, 0xec, 0x6f, 0x72, 0x11, 0xf2, 0xf2, - 0xe6, 0x26, 0x37, 0x24, 0x5f, 0xdc, 0xda, 0xe6, 0x41, 0x8e, 0xbb, 0x08, 0xbd, 0x26, 0x7f, 0x92, - 0x9b, 0x10, 0xde, 0xbf, 0x7a, 0x5d, 0xd4, 0x86, 0xd8, 0x62, 0x31, 0x43, 0x34, 0xf2, 0x26, 0xe0, - 0x21, 0x21, 0x2e, 0x0f, 0x52, 0xa1, 0xcd, 0x3f, 0x4d, 0xc8, 0x29, 0x9c, 0x04, 0xd1, 0xc8, 0x2d, - 0x10, 0x13, 0x53, 0x64, 0x53, 0x3f, 0xa7, 0x13, 0xf0, 0xfc, 0x94, 0x92, 0x44, 0xa0, 0x92, 0x77, - 0x61, 0xbc, 0xee, 0x51, 0x7c, 0x75, 0xb4, 0x9b, 0x51, 0x92, 0x74, 0x95, 0xb2, 0x1c, 0x95, 0x3f, - 0xbc, 0x69, 0xaa, 0xe8, 0xc6, 0x2f, 0xe7, 0x61, 0x42, 0xfd, 0x1e, 0x62, 0xc2, 0xac, 0xdf, 0x64, - 0x77, 0x77, 0x61, 0x6c, 0xd6, 0xc1, 0x42, 0x71, 0x9c, 0x5e, 0xd6, 0x3f, 0x88, 0xe1, 0x71, 0xcb, - 0x33, 0x19, 0x24, 0x63, 0xe5, 0x39, 0x73, 0xc6, 0x8f, 0xc0, 0x1c, 0x8f, 0x94, 0x20, 0xef, 0x76, - 0xfc, 0x3d, 0xda, 0x76, 0xe4, 0x7b, 0xcb, 0xcb, 0x1a, 0xa3, 0x07, 0xa2, 0x30, 0xc1, 0x2b, 0x24, - 0x23, 0x6f, 0xc1, 0x88, 0xdb, 0xa1, 0x6d, 0xdb, 0x11, 0x67, 0xdc, 0xf3, 0x31, 0x06, 0xb4, 0x5d, - 0xaa, 0x2a, 0x84, 0x02, 0x99, 0xdc, 0x80, 0x21, 0xf7, 0x20, 0x1c, 0xaf, 0x8b, 0x3a, 0xd1, 0x41, - 0x60, 0x2b, 0x24, 0x88, 0xc8, 0x08, 0x3e, 0xb2, 0x5b, 0xbb, 0x62, 0xc4, 0x74, 0x82, 0x7b, 0x76, - 0x6b, 0x57, 0x25, 0x60, 0x88, 0xe4, 0x03, 0x80, 0x8e, 0xbd, 0x47, 0x3d, 0xab, 0xd1, 0x0d, 0x8e, - 0xc4, 0xb8, 0x5d, 0xd2, 0xc8, 0x36, 0x58, 0x71, 0xa5, 0x1b, 0x1c, 0x29, 0xb4, 0x63, 0x1d, 0x09, - 0x24, 0x25, 0x80, 0x96, 0x1d, 0x04, 0xd4, 0x6b, 0xb9, 0xc2, 0xda, 0x2f, 0x0a, 0x82, 0xc8, 0x19, - 0xac, 0x85, 0xc5, 0x0a, 0x07, 0x85, 0x08, 0x3f, 0xda, 0xf1, 0x6c, 0x91, 0xd3, 0x3e, 0xf6, 0xd1, - 0x8e, 0xa7, 0xb5, 0x92, 0x21, 0x92, 0xcf, 0xc1, 0x68, 0xc3, 0xf1, 0xeb, 0xae, 0xd7, 0x10, 0xd1, - 0x53, 0x5e, 0xd0, 0x68, 0x2a, 0xbc, 0x4c, 0x21, 0x93, 0xe8, 0xec, 0x6b, 0x45, 0x10, 0xd4, 0x75, - 0xf7, 0x10, 0xd5, 0xfc, 0xf1, 0xaf, 0xad, 0x85, 0xc5, 0xea, 0xd7, 0x46, 0x44, 0x6c, 0x28, 0xf7, - 0x9c, 0xa0, 0x69, 0xef, 0x88, 0x77, 0x6e, 0x7d, 0x28, 0xef, 0x62, 0x91, 0x3a, 0x94, 0x1c, 0x99, - 0xbc, 0x0d, 0x79, 0xda, 0x0e, 0x3c, 0xdb, 0x72, 0x1a, 0xc2, 0xa9, 0x52, 0xff, 0x68, 0x76, 0x00, - 0xdb, 0xd5, 0x8a, 0xfa, 0xd1, 0x88, 0x5f, 0x6d, 0xb0, 0xfe, 0xf1, 0xeb, 0x4e, 0x4b, 0xf8, 0x42, - 0xea, 0xfd, 0x53, 0x2b, 0x57, 0xd7, 0xd4, 0xfe, 0x61, 0x88, 0xe4, 0x7d, 0x18, 0x65, 0xeb, 0xb7, - 0xe1, 0xee, 0x89, 0x80, 0x14, 0x86, 0xde, 0x3f, 0xbc, 0x2c, 0x31, 0x5d, 0x25, 0x11, 0x5b, 0xc8, - 0xf6, 0xa1, 0x6f, 0x39, 0x75, 0x11, 0x64, 0x42, 0x5f, 0x8e, 0xa5, 0xed, 0x5a, 0xb5, 0xac, 0x90, - 0x0d, 0xdb, 0x87, 0x7e, 0xb5, 0x4e, 0x16, 0x61, 0x18, 0x53, 0x54, 0x88, 0x40, 0x98, 0x3a, 0x0d, - 0x26, 0xa7, 0x50, 0x69, 0x10, 0x95, 0x0d, 0x64, 0xcb, 0x47, 0xf7, 0x12, 0x91, 0x28, 0x42, 0xef, - 0x93, 0xb5, 0x1a, 0xfa, 0x9c, 0xa8, 0x9f, 0x28, 0xd0, 0xc9, 0x25, 0x80, 0xe8, 0x15, 0x9f, 0xbf, - 0xb9, 0x98, 0x0a, 0xe4, 0xf3, 0x43, 0xff, 0xe7, 0x2f, 0x16, 0x33, 0x4b, 0x00, 0x79, 0x19, 0x21, - 0xc7, 0x58, 0x85, 0x8b, 0x3d, 0xd7, 0x3d, 0xb9, 0x06, 0x85, 0x5d, 0x5b, 0x68, 0xfd, 0xea, 0xfb, - 0x76, 0xbb, 0xfd, 0xff, 0xb3, 0xf7, 0x6c, 0x31, 0x6e, 0x5c, 0xd7, 0x69, 0x48, 0xee, 0x2e, 0xf7, - 0x70, 0x1f, 0xb3, 0x57, 0x8f, 0x5d, 0xaf, 0x64, 0xc9, 0x1a, 0xcb, 0x8a, 0x44, 0xc7, 0x4e, 0x24, - 0xd7, 0xb1, 0x9d, 0xc4, 0x71, 0x66, 0xb9, 0xb3, 0x4b, 0x4a, 0x7c, 0x65, 0x86, 0x5c, 0x45, 0x71, - 0x92, 0xc9, 0x88, 0x9c, 0xdd, 0x9d, 0x84, 0xcb, 0x61, 0x38, 0xa4, 0x15, 0x05, 0x05, 0x9a, 0xa0, - 0x40, 0x02, 0xf4, 0x95, 0x36, 0x6d, 0x51, 0x23, 0x3f, 0xf9, 0x68, 0x50, 0xf4, 0xa3, 0xff, 0x2d, - 0x9a, 0xfe, 0xe4, 0x2f, 0x40, 0x10, 0x20, 0x40, 0xff, 0xd2, 0xc2, 0x68, 0x0d, 0xb4, 0x40, 0x1f, - 0x7f, 0x45, 0xfb, 0x11, 0xa0, 0x40, 0x71, 0xcf, 0xbd, 0x77, 0xe6, 0xce, 0x83, 0xd4, 0x2a, 0x76, - 0xda, 0x06, 0xc8, 0xd7, 0x2e, 0xcf, 0x3d, 0xe7, 0xcc, 0x7d, 0xdf, 0x73, 0xcf, 0x3d, 0x0f, 0x77, - 0xc0, 0x77, 0xdc, 0x75, 0x01, 0xaf, 0x30, 0x30, 0xe3, 0xac, 0xbd, 0x01, 0xe7, 0xb2, 0x06, 0x9c, - 0x5c, 0x85, 0x15, 0x39, 0x18, 0x10, 0x67, 0x52, 0x72, 0x46, 0x9e, 0x08, 0x07, 0xc4, 0x19, 0x7c, - 0x5f, 0x81, 0x4b, 0xf3, 0xb6, 0x0f, 0xb2, 0x0d, 0xc5, 0xd1, 0xd8, 0xf3, 0x51, 0x4c, 0xe5, 0xd9, - 0x16, 0xc4, 0x6f, 0x4c, 0xa4, 0x80, 0xf2, 0xd4, 0xc4, 0x39, 0xe2, 0x0e, 0x1e, 0xe6, 0x32, 0x42, - 0x3a, 0xce, 0x51, 0x40, 0x9e, 0x87, 0x8d, 0xbe, 0x7b, 0xe8, 0x4c, 0x07, 0x13, 0x3b, 0xe8, 0x1d, - 0xbb, 0x7d, 0x74, 0xc1, 0x42, 0xc3, 0x3d, 0x53, 0xe5, 0x05, 0x96, 0x80, 0xa7, 0x6a, 0xbc, 0x30, - 0xa3, 0xc6, 0x77, 0x0a, 0x45, 0x45, 0xcd, 0x99, 0x68, 0x29, 0xa5, 0x7d, 0x2d, 0x07, 0x5b, 0xb3, - 0xd6, 0x0b, 0x79, 0x3d, 0xab, 0x0f, 0xd8, 0xc3, 0x85, 0x0c, 0x97, 0x1f, 0x2e, 0xa4, 0xaf, 0x91, - 0xdb, 0x10, 0x3a, 0x50, 0x3d, 0x2e, 0x18, 0x82, 0x80, 0x51, 0x9a, 0x91, 0x13, 0x04, 0x0f, 0xe9, - 0x96, 0x90, 0x97, 0x02, 0xea, 0x72, 0x98, 0x4c, 0x23, 0x60, 0xe4, 0x15, 0x80, 0xde, 0xc0, 0x0f, - 0x5c, 0xb4, 0x0f, 0xe0, 0xb2, 0x06, 0x33, 0x0b, 0x0f, 0xa1, 0xf2, 0x83, 0x30, 0x42, 0x2b, 0x7e, - 0xdf, 0xe5, 0x03, 0xe8, 0xc0, 0xe6, 0x8c, 0x0d, 0x92, 0x0e, 0x4f, 0x94, 0x9d, 0x5e, 0xe4, 0xba, - 0x9a, 0x86, 0x39, 0xea, 0x93, 0x3d, 0x9e, 0x9b, 0x35, 0x47, 0x1e, 0x01, 0x49, 0xef, 0x82, 0x94, - 0x3b, 0x37, 0x6e, 0x9e, 0x8e, 0x43, 0xee, 0x0c, 0xd2, 0x1d, 0x0f, 0xc8, 0x15, 0x28, 0x89, 0x5c, - 0x96, 0x54, 0x96, 0x67, 0xcc, 0x81, 0x83, 0xee, 0xba, 0x38, 0x79, 0x30, 0x62, 0x2a, 0xba, 0xc9, - 0x71, 0x29, 0x61, 0x19, 0x21, 0x9d, 0x47, 0x23, 0xd1, 0xba, 0x4b, 0x62, 0x7e, 0xc7, 0xcf, 0x26, - 0x5e, 0xfa, 0xc7, 0x8a, 0x18, 0xfe, 0xf4, 0xe6, 0xfe, 0xb8, 0xfa, 0x11, 0x40, 0x2f, 0x25, 0x5e, - 0x31, 0xfc, 0x9f, 0x4a, 0x2d, 0x62, 0xd5, 0x71, 0xa9, 0x85, 0xff, 0x24, 0xd7, 0x61, 0x7d, 0xcc, - 0xec, 0x58, 0x27, 0x3e, 0xef, 0x4f, 0x96, 0x37, 0x64, 0x95, 0x81, 0x3b, 0x3e, 0xf6, 0x29, 0xaf, - 0xd7, 0x9d, 0xb0, 0xc3, 0xa4, 0xb3, 0x8e, 0xbc, 0x08, 0xcb, 0xf4, 0xac, 0xc3, 0x48, 0x3b, 0x09, - 0xf7, 0x08, 0xc4, 0x43, 0xc9, 0xc1, 0x2c, 0x7e, 0x91, 0xff, 0xcf, 0x79, 0xbd, 0x9d, 0x13, 0xcc, - 0xe4, 0x93, 0x96, 0x6c, 0xc2, 0x92, 0x3f, 0x3e, 0x92, 0x9a, 0xb6, 0xe8, 0x8f, 0x8f, 0x68, 0xbb, - 0x6e, 0x80, 0xca, 0xbc, 0x75, 0x58, 0xd4, 0x84, 0xe0, 0xd1, 0x90, 0x5d, 0xc5, 0x8b, 0xe6, 0x1a, - 0x83, 0x63, 0xc2, 0xfe, 0x47, 0xc3, 0x1e, 0xc5, 0x0c, 0x02, 0xdf, 0x96, 0x03, 0x6c, 0xf1, 0x66, - 0xaf, 0x05, 0x81, 0x1f, 0x45, 0xda, 0xea, 0x93, 0x1d, 0x58, 0xa5, 0x7c, 0xc2, 0x30, 0x5f, 0x5c, - 0x10, 0x78, 0x3a, 0x2d, 0x08, 0x3c, 0x1a, 0xf6, 0x44, 0x15, 0xcd, 0x95, 0x40, 0xfa, 0x45, 0xee, - 0x82, 0x2a, 0x49, 0x4c, 0xe8, 0xbe, 0x99, 0xb0, 0xa9, 0x8e, 0xd8, 0x48, 0x92, 0x56, 0x6d, 0x78, - 0xe8, 0x9b, 0xeb, 0xbd, 0x38, 0x80, 0x77, 0xcd, 0x77, 0x15, 0xb1, 0x97, 0x66, 0x10, 0x11, 0x0d, - 0x56, 0x8f, 0x9d, 0xc0, 0x0e, 0x82, 0x13, 0x66, 0x23, 0xc6, 0x03, 0x0b, 0x97, 0x8e, 0x9d, 0xc0, - 0x0a, 0x4e, 0x44, 0xe2, 0x92, 0xf3, 0x14, 0xc7, 0x77, 0xa6, 0x93, 0x63, 0x5b, 0x96, 0xff, 0x58, - 0x8f, 0x9d, 0x3d, 0x76, 0x82, 0x16, 0x2d, 0x93, 0x78, 0x93, 0x6b, 0xb0, 0x86, 0x7c, 0x7b, 0x9e, - 0x60, 0x8c, 0x91, 0x2f, 0xcc, 0x15, 0xca, 0xb8, 0xe7, 0x31, 0xce, 0xbc, 0x86, 0xff, 0x92, 0x83, - 0x0b, 0xd9, 0xbd, 0x83, 0xd3, 0x93, 0xf6, 0x29, 0xfa, 0xe8, 0xf1, 0xba, 0x2d, 0x53, 0x08, 0x8b, - 0x5a, 0x92, 0x35, 0x38, 0xb9, 0xcc, 0xc1, 0x29, 0xc3, 0x06, 0x32, 0xe2, 0x92, 0xe6, 0xc0, 0x0b, - 0x26, 0x3c, 0x18, 0x87, 0xb9, 0x4e, 0x0b, 0xd8, 0x7e, 0x5e, 0xa7, 0x60, 0xf2, 0x1c, 0xac, 0x89, - 0x1d, 0xd9, 0x7f, 0x38, 0xa4, 0x1f, 0x66, 0xdb, 0xf1, 0x2a, 0x87, 0xb6, 0x10, 0x48, 0xce, 0xc3, - 0xa2, 0x33, 0x1a, 0xd1, 0x4f, 0xb2, 0x5d, 0x78, 0xc1, 0x19, 0x8d, 0x58, 0x72, 0x1d, 0xf4, 0x48, - 0xb4, 0x0f, 0xd1, 0x4a, 0x88, 0x9b, 0x24, 0x9a, 0x2b, 0x08, 0x64, 0x96, 0x43, 0x01, 0x5d, 0xf7, - 0x94, 0x56, 0xa0, 0x2c, 0x21, 0x0a, 0x38, 0xa3, 0x10, 0xe1, 0x29, 0x28, 0x8a, 0xf7, 0x6a, 0xe6, - 0x58, 0x61, 0x2e, 0x39, 0xfc, 0xad, 0xfa, 0x65, 0xd8, 0xec, 0x7b, 0x01, 0x4e, 0x5e, 0xd6, 0xa4, - 0xd1, 0x88, 0xfb, 0x40, 0xb2, 0x20, 0xbd, 0xe6, 0x39, 0x5e, 0x4c, 0x7b, 0x52, 0x1f, 0x8d, 0x98, - 0x27, 0x24, 0xef, 0xeb, 0x57, 0x61, 0x9d, 0x4b, 0x5c, 0xfc, 0x88, 0xc4, 0xba, 0xf0, 0x05, 0x4c, - 0xaf, 0x42, 0x3c, 0x9d, 0x11, 0x70, 0x50, 0xad, 0x2f, 0x28, 0xff, 0x5e, 0x81, 0xf3, 0x99, 0x22, - 0x1b, 0xf9, 0x02, 0x30, 0x97, 0xaf, 0x89, 0x6f, 0x8f, 0xdd, 0x9e, 0x37, 0xf2, 0x30, 0x86, 0x06, - 0x53, 0x69, 0xde, 0x9e, 0x27, 0xec, 0xa1, 0xfb, 0x58, 0xc7, 0x37, 0x43, 0x22, 0xa6, 0x6b, 0x51, - 0xc7, 0x09, 0xf0, 0xf6, 0x9b, 0x70, 0x3e, 0x13, 0x35, 0x43, 0x07, 0xf2, 0xc1, 0x78, 0x32, 0x69, - 0xf1, 0x48, 0x95, 0x68, 0xb4, 0xa4, 0x1b, 0xe1, 0xcd, 0xfb, 0x41, 0xd8, 0xbc, 0x84, 0x70, 0x47, - 0x8c, 0xe4, 0xba, 0xce, 0xba, 0x9f, 0x08, 0xa2, 0xd9, 0x4b, 0xfb, 0x4d, 0x38, 0xcf, 0x27, 0xdf, - 0xd1, 0xd8, 0x19, 0x1d, 0x47, 0xec, 0x58, 0x45, 0x3f, 0x90, 0xc5, 0x8e, 0xcd, 0xca, 0x7d, 0x8a, - 0x1f, 0x72, 0x3d, 0xeb, 0xa4, 0x81, 0xbc, 0x0d, 0x5f, 0xcf, 0x89, 0xa5, 0x9e, 0x51, 0x9d, 0x8c, - 0x69, 0xad, 0x64, 0x4d, 0xeb, 0xd3, 0xaf, 0xa9, 0x26, 0x10, 0x79, 0xb3, 0x62, 0x5a, 0x4f, 0x6e, - 0x50, 0x25, 0xe4, 0x74, 0x5e, 0x11, 0x69, 0x6b, 0xb0, 0x58, 0x32, 0xcf, 0x8d, 0x5e, 0x12, 0x44, - 0x2e, 0xc2, 0x72, 0x98, 0x2f, 0x9b, 0x1f, 0x1c, 0x45, 0x06, 0xa8, 0xf5, 0xc9, 0x33, 0xb0, 0xc2, - 0x44, 0xf2, 0xd8, 0x9a, 0x03, 0x84, 0xe9, 0x74, 0xe1, 0x89, 0x3e, 0x50, 0xe0, 0x99, 0xc7, 0xf5, - 0x21, 0xb9, 0x07, 0x17, 0xd0, 0xac, 0x23, 0xf0, 0xc3, 0x61, 0xb0, 0x7b, 0x4e, 0xef, 0xd8, 0xe5, - 0xb3, 0x56, 0xcb, 0x1c, 0x8c, 0xd1, 0xc8, 0xb2, 0x5a, 0xd2, 0x38, 0x8c, 0x46, 0x56, 0xe0, 0x8b, - 0xdf, 0x15, 0x4a, 0xce, 0xeb, 0xd0, 0x87, 0x8b, 0x73, 0x28, 0xa5, 0x8d, 0x43, 0x91, 0x37, 0x8e, - 0x1b, 0xa0, 0x1e, 0xba, 0x7d, 0x2a, 0x13, 0xbb, 0x7d, 0xac, 0xda, 0x5b, 0xb7, 0x59, 0x86, 0x78, - 0x73, 0x2d, 0x84, 0x5b, 0x81, 0x7f, 0x70, 0x9b, 0x7f, 0xe5, 0x44, 0x1c, 0x79, 0xf2, 0xb5, 0x82, - 0xbc, 0x08, 0x67, 0x13, 0xf1, 0x49, 0x22, 0x87, 0x77, 0x73, 0x83, 0x16, 0xc5, 0xa3, 0x59, 0x5d, - 0x85, 0x15, 0x31, 0x2b, 0xc6, 0xa1, 0x1f, 0x9c, 0x59, 0xe2, 0x30, 0xba, 0xea, 0xf8, 0xe7, 0xa6, - 0xa2, 0x51, 0x99, 0x37, 0x92, 0x53, 0xc8, 0xd2, 0xe4, 0x05, 0x20, 0xa1, 0xdc, 0x1e, 0x6e, 0x14, - 0xfc, 0x83, 0x1b, 0xa2, 0x24, 0x5c, 0xe1, 0xfc, 0xb3, 0x7f, 0x93, 0x83, 0xb3, 0x19, 0x57, 0x19, - 0x7a, 0x09, 0xf0, 0x86, 0x13, 0xf7, 0x88, 0x5d, 0x21, 0xe4, 0x46, 0xae, 0x4b, 0x70, 0xae, 0x9f, - 0x5a, 0x64, 0x19, 0xd0, 0xf9, 0xb7, 0xf8, 0x2f, 0xba, 0x79, 0x38, 0x63, 0xa1, 0x7a, 0xa1, 0xff, - 0x92, 0x1a, 0x6c, 0x60, 0x5a, 0x87, 0xc0, 0xf3, 0x31, 0x3b, 0x04, 0x0a, 0x21, 0x85, 0xd8, 0x65, - 0x07, 0x6b, 0xd1, 0x96, 0x90, 0xa8, 0x14, 0x62, 0xaa, 0xa3, 0x04, 0x84, 0x7c, 0x0c, 0xb6, 0xa5, - 0xb3, 0xc6, 0x4e, 0xac, 0x3c, 0xb4, 0x74, 0x37, 0x37, 0x9d, 0xf0, 0xd4, 0xd9, 0x8d, 0xad, 0xc1, - 0x1d, 0xb8, 0x8c, 0x83, 0xe8, 0xf5, 0x47, 0x76, 0x2a, 0x0f, 0x08, 0x36, 0x95, 0x05, 0xce, 0xdf, - 0xa6, 0x58, 0xb5, 0xfe, 0x28, 0x91, 0x12, 0x84, 0xb6, 0x9a, 0x77, 0xdf, 0x9b, 0x70, 0x3e, 0xb3, - 0xc6, 0xf4, 0x80, 0x41, 0x43, 0xaa, 0x48, 0x36, 0x5a, 0xa2, 0xbf, 0xa9, 0x70, 0x74, 0x15, 0x56, - 0x1e, 0xb8, 0xce, 0xd8, 0x1d, 0xf3, 0x93, 0x9b, 0x4f, 0x09, 0x06, 0x93, 0x0f, 0xee, 0x7e, 0x7c, - 0x68, 0xb8, 0xce, 0x88, 0x34, 0xe0, 0x2c, 0x3b, 0x01, 0xbd, 0x13, 0x14, 0x06, 0xb9, 0x9e, 0x49, - 0x89, 0x89, 0x43, 0x48, 0x82, 0x47, 0x53, 0x0d, 0xb1, 0x18, 0xb5, 0xb9, 0x71, 0x94, 0x04, 0xd1, - 0x15, 0x7d, 0x21, 0x1b, 0x9b, 0xec, 0x40, 0x89, 0x31, 0x67, 0xd7, 0x02, 0xf6, 0x40, 0x70, 0x75, - 0xee, 0x17, 0x2a, 0x68, 0x5f, 0x1c, 0x84, 0xff, 0xd3, 0xf3, 0x1a, 0xdf, 0x62, 0xed, 0x13, 0xf9, - 0xfd, 0xc3, 0x5c, 0x41, 0x20, 0x7f, 0xf7, 0xd0, 0xfe, 0x56, 0x11, 0x4d, 0x8d, 0x5d, 0x8e, 0xe9, - 0xd4, 0x0a, 0xdc, 0xa1, 0x78, 0x03, 0x5a, 0x36, 0xf9, 0xaf, 0x27, 0x9c, 0xea, 0xe4, 0x15, 0x58, - 0xa1, 0x6c, 0x8f, 0xa6, 0x43, 0x36, 0xe5, 0xf2, 0xb1, 0xb8, 0x3c, 0x0d, 0x56, 0x44, 0x87, 0xad, - 0x7a, 0xc6, 0x2c, 0x9d, 0x44, 0x3f, 0xa9, 0xb4, 0x1c, 0x9c, 0x4c, 0x46, 0xf2, 0x44, 0x15, 0x8a, - 0x42, 0xab, 0xd1, 0x69, 0x73, 0x92, 0x22, 0xc5, 0x89, 0xa4, 0xe5, 0x9d, 0x45, 0xa6, 0x2a, 0xd4, - 0x9e, 0x87, 0x92, 0xc4, 0x9b, 0x36, 0x86, 0x79, 0xce, 0x88, 0xc6, 0xb0, 0x5f, 0x7c, 0xb0, 0x1f, - 0x40, 0x51, 0xb0, 0xa4, 0xd7, 0x82, 0x63, 0x3f, 0x10, 0x8b, 0x1c, 0xff, 0xa7, 0x30, 0xda, 0xcb, - 0xd8, 0xc8, 0x05, 0x13, 0xff, 0xc7, 0xb3, 0x64, 0xe2, 0xd0, 0xfb, 0xc0, 0x20, 0xb0, 0x47, 0x68, - 0x81, 0x15, 0x0a, 0xcf, 0x14, 0xde, 0x19, 0x04, 0xcc, 0x2e, 0x8b, 0x7f, 0xe3, 0xaf, 0xc2, 0x43, - 0x38, 0xa1, 0x4d, 0x98, 0xb5, 0x67, 0xc6, 0x8e, 0x8c, 0x5c, 0xfa, 0xc8, 0x60, 0xf1, 0x56, 0x38, - 0x25, 0xfb, 0x32, 0x20, 0x0c, 0x8f, 0x0c, 0x69, 0x67, 0x28, 0xc4, 0x76, 0x06, 0xe9, 0x4e, 0x1e, - 0x8d, 0x1e, 0x3b, 0x71, 0xc4, 0x9d, 0x3c, 0xb9, 0x4f, 0xfd, 0x59, 0x4e, 0xa8, 0x08, 0x76, 0x7c, - 0x7f, 0x12, 0x4c, 0xc6, 0xce, 0x28, 0xa6, 0x0a, 0x25, 0x27, 0xf0, 0x14, 0x4a, 0xd0, 0xb7, 0x31, - 0x85, 0x86, 0x3f, 0x16, 0x21, 0x3e, 0xc2, 0x99, 0x5b, 0xba, 0xfd, 0xa1, 0xb8, 0x8c, 0xaf, 0x53, - 0x6c, 0x5d, 0x46, 0xa6, 0x13, 0x56, 0xe2, 0x5a, 0x3d, 0x63, 0x6e, 0x32, 0x9e, 0x29, 0x2c, 0x52, - 0xcd, 0x58, 0xc4, 0x49, 0x5d, 0xe8, 0x4e, 0xb4, 0xa2, 0xe3, 0x5c, 0xe5, 0xb5, 0x4e, 0x3e, 0x01, - 0xcb, 0x5e, 0x5f, 0xce, 0x14, 0x99, 0xd4, 0xc2, 0xd5, 0xfa, 0x2c, 0x5a, 0x75, 0xc4, 0x83, 0xce, - 0x39, 0x8f, 0x43, 0x77, 0x56, 0x63, 0x4a, 0x63, 0x6d, 0x47, 0xdc, 0x46, 0xd3, 0x64, 0x64, 0x0d, - 0x72, 0xe1, 0x08, 0xe7, 0xbc, 0x3e, 0x5b, 0x5e, 0x51, 0xbc, 0x6c, 0x93, 0xff, 0xd2, 0x7e, 0x1d, - 0x6e, 0x9c, 0xb6, 0x8f, 0xe8, 0x52, 0x9c, 0xd1, 0xe1, 0xcb, 0x2c, 0x54, 0x65, 0xbc, 0xdf, 0xae, - 0x82, 0x1c, 0xee, 0xd7, 0x13, 0x9b, 0x9f, 0x80, 0x75, 0xc7, 0x9e, 0xf6, 0x97, 0x79, 0x58, 0x8b, - 0xab, 0xc9, 0xc9, 0xf3, 0x50, 0x90, 0x76, 0xa0, 0xcd, 0x0c, 0x5d, 0x3a, 0xee, 0x3b, 0x88, 0x74, - 0xaa, 0x1d, 0x87, 0xdc, 0x81, 0x35, 0x34, 0xdc, 0x43, 0xd1, 0x73, 0xe2, 0xf1, 0xc7, 0x97, 0xf9, - 0xef, 0x67, 0xc5, 0x1f, 0xbe, 0x73, 0xe5, 0x0c, 0x3e, 0x95, 0xad, 0x50, 0x5a, 0x2a, 0xfd, 0xd1, - 0x42, 0x49, 0x0b, 0x5a, 0x98, 0xad, 0x05, 0xe5, 0x4d, 0x99, 0xa1, 0x05, 0x5d, 0x98, 0xa3, 0x05, - 0x8d, 0x28, 0x65, 0x2d, 0x28, 0xea, 0xc2, 0x97, 0x66, 0xe9, 0xc2, 0x23, 0x1a, 0xa6, 0x0b, 0x8f, - 0xb4, 0x98, 0xc5, 0x99, 0x5a, 0xcc, 0x88, 0x86, 0x6b, 0x31, 0xaf, 0xf1, 0x3e, 0x1a, 0x3b, 0x0f, - 0x6d, 0xec, 0x3c, 0x7e, 0x2c, 0x62, 0xeb, 0x4d, 0xe7, 0x21, 0x1a, 0xd7, 0xec, 0x2c, 0x83, 0xb0, - 0xc8, 0xd1, 0xfe, 0x50, 0x49, 0x68, 0x02, 0xc5, 0xf8, 0x3d, 0x07, 0x6b, 0xec, 0xb0, 0xe2, 0xe1, - 0x4c, 0xd9, 0x69, 0xb5, 0x6a, 0xae, 0x0a, 0x28, 0xbb, 0x6f, 0x7e, 0x00, 0xd6, 0x43, 0x34, 0x7e, - 0xe5, 0x42, 0x4f, 0x3d, 0x33, 0xa4, 0xe6, 0x61, 0x67, 0x9e, 0x87, 0x8d, 0x10, 0x91, 0x6b, 0x73, - 0xd8, 0x75, 0x73, 0xd5, 0x54, 0x45, 0x41, 0x9b, 0xc3, 0xb5, 0xa3, 0xe4, 0xcd, 0xe3, 0x17, 0x54, - 0x2b, 0xed, 0x07, 0xf9, 0x98, 0x96, 0x44, 0x7c, 0x86, 0x9e, 0xa2, 0x81, 0x6f, 0xf3, 0x4e, 0xe2, - 0x7b, 0xd1, 0xd5, 0x19, 0x63, 0xc6, 0x6d, 0x9a, 0x2c, 0xab, 0x65, 0x42, 0x10, 0xf8, 0xc2, 0xc4, - 0xc9, 0x66, 0x12, 0x35, 0x3b, 0xf7, 0x71, 0xce, 0x0a, 0x76, 0x6c, 0xe3, 0x29, 0xcf, 0x67, 0x27, - 0xae, 0xa9, 0x74, 0xca, 0xa2, 0x64, 0x1d, 0xfe, 0x12, 0x1f, 0xe8, 0x02, 0x2a, 0x15, 0x83, 0x38, - 0xf3, 0x7c, 0xc6, 0xdd, 0x29, 0xc5, 0x1c, 0x7b, 0x09, 0x39, 0xab, 0x53, 0xf1, 0xaf, 0x60, 0x6b, - 0xc0, 0x0a, 0xea, 0x28, 0x04, 0xc3, 0x42, 0x86, 0x0a, 0x3e, 0xdd, 0xf8, 0x4a, 0xad, 0x61, 0x96, - 0x28, 0x9d, 0x60, 0x73, 0x0c, 0x4f, 0xc9, 0x9a, 0x85, 0x78, 0x25, 0x17, 0x44, 0x14, 0xdf, 0xb9, - 0x3d, 0x10, 0x29, 0x20, 0xb0, 0xaa, 0x17, 0x9c, 0x38, 0x80, 0xa3, 0x69, 0xc7, 0xb0, 0x3d, 0x7b, - 0x48, 0xe6, 0x64, 0x88, 0x8a, 0x0e, 0xd0, 0x9c, 0x7c, 0x80, 0xca, 0x7a, 0x86, 0x7c, 0x4c, 0xcf, - 0xa0, 0xfd, 0x69, 0x1e, 0x9e, 0x3d, 0xc5, 0x70, 0xcd, 0xf9, 0xe6, 0x27, 0xe3, 0xe2, 0x59, 0x2e, - 0x76, 0x33, 0xa4, 0x4c, 0xf9, 0x06, 0x49, 0x6f, 0xa9, 0xd9, 0xc2, 0xd9, 0x17, 0x60, 0x9d, 0xed, - 0x82, 0xcc, 0x2c, 0xf1, 0x70, 0x3a, 0x38, 0xc5, 0x36, 0x78, 0x51, 0xf8, 0x50, 0x25, 0x48, 0x71, - 0x67, 0xc4, 0x1d, 0xc3, 0x0a, 0x61, 0xa4, 0x03, 0x25, 0x44, 0x3b, 0x74, 0xbc, 0xc1, 0xa9, 0x9c, - 0x79, 0x84, 0x87, 0x96, 0x4c, 0xc6, 0xac, 0xa9, 0x29, 0x60, 0x0f, 0x7f, 0x93, 0xeb, 0xb0, 0x3e, - 0x9c, 0x9e, 0x50, 0xc1, 0x83, 0xcd, 0x05, 0x6e, 0xfd, 0xb1, 0x60, 0xae, 0x0e, 0xa7, 0x27, 0xfa, - 0x68, 0x84, 0x43, 0x8a, 0x66, 0x22, 0x1b, 0x14, 0x8f, 0xad, 0x5a, 0x81, 0xb9, 0x88, 0x98, 0x94, - 0x01, 0x5b, 0xb7, 0x1c, 0xf7, 0x1c, 0x30, 0xa3, 0x41, 0x9e, 0x21, 0x8b, 0xfd, 0xd0, 0xfe, 0x2b, - 0x27, 0xee, 0xbb, 0xb3, 0xe7, 0xfd, 0xaf, 0x86, 0x28, 0x63, 0x88, 0x6e, 0x80, 0x4a, 0xbb, 0x3e, - 0xda, 0x54, 0xc2, 0x31, 0x5a, 0x1b, 0x4e, 0x4f, 0xc2, 0xbe, 0x93, 0x3b, 0x7e, 0x51, 0xee, 0xf8, - 0x57, 0xc4, 0x7d, 0x38, 0x73, 0x7b, 0x98, 0xdd, 0xe5, 0xda, 0xbf, 0xe7, 0xe1, 0xfa, 0xe9, 0x36, - 0x81, 0x5f, 0x8d, 0x5b, 0xc6, 0xb8, 0x25, 0x54, 0xa7, 0x0b, 0x29, 0xd5, 0x69, 0xc6, 0xda, 0x5b, - 0xcc, 0x5a, 0x7b, 0x29, 0x45, 0xed, 0x52, 0x86, 0xa2, 0x36, 0x73, 0x81, 0x16, 0x1f, 0xb3, 0x40, - 0x97, 0xe5, 0x79, 0xf2, 0xcf, 0xa1, 0x02, 0x23, 0x7e, 0x1f, 0x78, 0x13, 0xce, 0x8a, 0xfb, 0x00, - 0x3b, 0x39, 0x22, 0xfd, 0x7b, 0xe9, 0xf6, 0xcd, 0xac, 0x9b, 0x00, 0xa2, 0x65, 0x48, 0xeb, 0x1b, - 0xfc, 0x0e, 0x10, 0x95, 0xff, 0xff, 0x91, 0xfe, 0xc9, 0x7d, 0xb8, 0x80, 0xf1, 0xe5, 0x7b, 0xf2, - 0xcb, 0x81, 0x3d, 0x76, 0x0f, 0xf9, 0x7c, 0xb8, 0x9a, 0x92, 0x95, 0xbd, 0x9e, 0x54, 0x1d, 0xd3, - 0x3d, 0xac, 0x9e, 0x31, 0xcf, 0x05, 0x19, 0xf0, 0xe4, 0xc5, 0xe2, 0x2f, 0x14, 0xd0, 0x1e, 0xdf, - 0x5f, 0xa8, 0xa8, 0x4a, 0x76, 0xf8, 0xb2, 0x59, 0x72, 0xa4, 0xde, 0x7b, 0x16, 0x56, 0xc7, 0xee, - 0xe1, 0xd8, 0x0d, 0x8e, 0x63, 0x1a, 0x90, 0x15, 0x0e, 0x14, 0x1d, 0x23, 0x82, 0x52, 0x3e, 0x91, - 0x64, 0x2e, 0x88, 0xb4, 0xbd, 0xf0, 0xbe, 0x98, 0x39, 0x0e, 0x74, 0x36, 0xc9, 0x15, 0x64, 0x3f, - 0xee, 0x14, 0x8a, 0x39, 0x35, 0x6f, 0xf2, 0xd0, 0x99, 0x87, 0xde, 0xc0, 0xd5, 0xfe, 0x5a, 0x11, - 0x12, 0x41, 0x56, 0xe7, 0x91, 0x37, 0x25, 0x63, 0xde, 0x7c, 0x4a, 0x0c, 0xc9, 0x22, 0x91, 0xed, - 0x1e, 0x79, 0x78, 0x46, 0x04, 0xc4, 0xc2, 0x33, 0x22, 0xe4, 0x3d, 0x58, 0x24, 0xf2, 0x5b, 0xf3, - 0x6b, 0xc2, 0x22, 0x88, 0xee, 0x79, 0x07, 0xb7, 0xc8, 0x4d, 0x58, 0x62, 0x46, 0x40, 0xa2, 0xba, - 0xeb, 0xb1, 0xea, 0x1e, 0xdc, 0x32, 0x45, 0xb9, 0xf6, 0x76, 0xf8, 0xae, 0x95, 0x6a, 0xc4, 0xc1, - 0x2d, 0xf2, 0xca, 0xe9, 0x8c, 0x73, 0x8b, 0xc2, 0x38, 0x37, 0x34, 0xcc, 0x7d, 0x35, 0x66, 0x98, - 0x7b, 0x6d, 0x7e, 0x6f, 0xf1, 0xd7, 0x48, 0x16, 0x8e, 0x30, 0x0a, 0x53, 0xf5, 0xd3, 0x1c, 0x3c, - 0x3d, 0x97, 0x82, 0x5c, 0x82, 0xa2, 0xde, 0xae, 0x75, 0xa2, 0xf1, 0xa5, 0x6b, 0x46, 0x40, 0xc8, - 0x3e, 0x2c, 0xef, 0x38, 0x81, 0xd7, 0xa3, 0xd3, 0x38, 0xf3, 0x79, 0x20, 0xc5, 0x36, 0x44, 0xaf, - 0x9e, 0x31, 0x23, 0x5a, 0x62, 0xc3, 0x06, 0xae, 0x85, 0x58, 0xea, 0xa9, 0x7c, 0x86, 0xae, 0x21, - 0xc5, 0x30, 0x45, 0x46, 0xf7, 0x99, 0x14, 0x90, 0x3c, 0x00, 0x62, 0x59, 0xd5, 0x8a, 0x3b, 0x9e, - 0xf0, 0x3b, 0xf8, 0xc4, 0x0b, 0x2d, 0x3d, 0x3f, 0xfc, 0x98, 0xbe, 0x4b, 0xd1, 0x55, 0xcf, 0x98, - 0x19, 0xdc, 0x92, 0xcb, 0xfc, 0x2d, 0x21, 0xef, 0xcc, 0xee, 0x84, 0x27, 0x08, 0xf5, 0x7a, 0x03, - 0x8a, 0x6d, 0x61, 0x8b, 0x20, 0x59, 0xcc, 0x0b, 0xbb, 0x03, 0x33, 0x2c, 0xd5, 0x7e, 0x47, 0x11, - 0x4a, 0x87, 0xc7, 0x77, 0x96, 0x94, 0x19, 0xac, 0x3f, 0x3f, 0x33, 0x58, 0xff, 0xe7, 0xcc, 0x0c, - 0xa6, 0x79, 0x70, 0xf3, 0xd4, 0x1d, 0x4b, 0x3e, 0x0e, 0x2a, 0x26, 0x51, 0x72, 0xa4, 0x41, 0x62, - 0xeb, 0x6b, 0x23, 0x8c, 0xfd, 0x5d, 0xe5, 0x99, 0xea, 0xcc, 0xf5, 0x5e, 0x9c, 0x5a, 0xfb, 0x73, - 0x1e, 0xf3, 0xbd, 0xd6, 0x6f, 0x27, 0x14, 0xcd, 0xef, 0xd5, 0xc9, 0xc2, 0x88, 0x2d, 0xb6, 0x67, - 0xa5, 0x24, 0x96, 0xe9, 0x6f, 0xcd, 0xf6, 0xb5, 0x90, 0x56, 0xde, 0x9f, 0xe4, 0xe1, 0xd2, 0x3c, - 0xf2, 0xcc, 0x34, 0xd9, 0xca, 0x93, 0xa5, 0xc9, 0xbe, 0x09, 0x45, 0x06, 0x0b, 0x3d, 0x08, 0x70, - 0x6c, 0x39, 0x29, 0x1d, 0x5b, 0x51, 0x4c, 0x9e, 0x85, 0x45, 0xbd, 0x62, 0x45, 0x99, 0xdb, 0xd0, - 0xd4, 0xd7, 0xe9, 0x05, 0x68, 0x44, 0xca, 0x8b, 0xc8, 0xe7, 0xd3, 0xc9, 0x0a, 0x79, 0xca, 0xb6, - 0x8b, 0x52, 0x87, 0xa4, 0xd2, 0x31, 0x60, 0x7d, 0xa3, 0xf4, 0x01, 0x3c, 0x22, 0xb7, 0x99, 0x4e, - 0x7c, 0xa8, 0xc1, 0x62, 0x7b, 0xec, 0x06, 0xee, 0x44, 0x36, 0xc3, 0x1d, 0x21, 0xc4, 0xe4, 0x25, - 0xdc, 0x48, 0xd6, 0x79, 0xc4, 0x62, 0x22, 0x2c, 0xca, 0x71, 0x6a, 0xd0, 0xaa, 0x96, 0x82, 0x4d, - 0x09, 0x85, 0x12, 0xd4, 0x9d, 0xe9, 0xb0, 0x77, 0xdc, 0x35, 0xeb, 0x5c, 0x72, 0x62, 0x04, 0x03, - 0x84, 0xd2, 0x06, 0x06, 0xa6, 0x84, 0xa2, 0x7d, 0x53, 0x81, 0x73, 0x59, 0xed, 0x20, 0x97, 0xa0, - 0x30, 0xcc, 0xcc, 0xcb, 0x38, 0x64, 0xae, 0xdc, 0x25, 0xfa, 0xd7, 0x3e, 0xf4, 0xc7, 0x27, 0xce, - 0x44, 0x36, 0x56, 0x96, 0xc0, 0x26, 0xd0, 0x1f, 0x7b, 0xf8, 0x3f, 0xb9, 0x22, 0x8e, 0x9c, 0x7c, - 0x2a, 0x93, 0x23, 0xfe, 0xd1, 0x74, 0x80, 0x5a, 0xbf, 0xdd, 0x1a, 0xb1, 0x74, 0x00, 0x2f, 0x41, - 0x81, 0x56, 0x2b, 0x31, 0x7b, 0xe9, 0xfc, 0xd1, 0x1b, 0x75, 0x8e, 0xc4, 0x6a, 0x15, 0x38, 0x27, - 0x03, 0x13, 0x91, 0xb5, 0x7b, 0xb0, 0x16, 0xc7, 0x20, 0x46, 0x3c, 0x22, 0x6c, 0xe9, 0xb6, 0xca, - 0x39, 0xed, 0xf8, 0x3e, 0x73, 0x98, 0xd9, 0x79, 0xea, 0xa7, 0xef, 0x5c, 0x01, 0xfa, 0x93, 0xd1, - 0x64, 0x45, 0x8c, 0xd5, 0xbe, 0x95, 0x83, 0x73, 0x91, 0x8f, 0xbe, 0x58, 0x43, 0xbf, 0xb4, 0x0e, - 0xa3, 0x7a, 0xcc, 0xa1, 0x51, 0xc8, 0x8d, 0xe9, 0x06, 0xce, 0xf1, 0xa3, 0xda, 0x87, 0xad, 0x59, - 0xf8, 0xe4, 0x79, 0x58, 0xc6, 0xb0, 0x4e, 0x23, 0xa7, 0xe7, 0xca, 0xdb, 0xec, 0x50, 0x00, 0xcd, - 0xa8, 0x5c, 0xfb, 0xb1, 0x02, 0xdb, 0xdc, 0xcd, 0xa3, 0xe1, 0x78, 0x43, 0x7c, 0x25, 0xe8, 0xb9, - 0xef, 0x8f, 0xc3, 0xf3, 0x7e, 0x6c, 0x1f, 0x7b, 0x2e, 0xee, 0xcd, 0x93, 0xfa, 0xda, 0xec, 0xd6, - 0x92, 0x9b, 0x18, 0xaa, 0x8c, 0xbf, 0xa2, 0x17, 0x58, 0x80, 0x89, 0x21, 0x05, 0xc8, 0x01, 0x26, - 0x10, 0x43, 0xfb, 0x0d, 0xb8, 0x3c, 0xff, 0x03, 0xe4, 0x73, 0xb0, 0x8a, 0xb9, 0xb7, 0xba, 0xa3, - 0xa3, 0xb1, 0xd3, 0x77, 0x85, 0x66, 0x4f, 0x68, 0x63, 0xe5, 0x32, 0x16, 0x79, 0x8d, 0x07, 0x3c, - 0x38, 0xc2, 0xac, 0x5e, 0x9c, 0x28, 0xe6, 0x4b, 0x25, 0x73, 0xd3, 0xbe, 0xa6, 0x00, 0x49, 0xf3, - 0x20, 0x1f, 0x81, 0x95, 0x6e, 0xa7, 0x62, 0x4d, 0x9c, 0xf1, 0xa4, 0xea, 0x4f, 0xc7, 0x3c, 0xec, - 0x19, 0xf3, 0x7f, 0x9f, 0xf4, 0x6c, 0xf6, 0x1e, 0x74, 0xec, 0x4f, 0xc7, 0x66, 0x0c, 0x0f, 0x73, - 0x3c, 0xb9, 0xee, 0x97, 0xfa, 0xce, 0xa3, 0x78, 0x8e, 0x27, 0x0e, 0x8b, 0xe5, 0x78, 0xe2, 0x30, - 0xed, 0x7b, 0x0a, 0x5c, 0x14, 0xc6, 0x91, 0xfd, 0x8c, 0xba, 0x54, 0x30, 0xca, 0xcb, 0x58, 0xc4, - 0xd9, 0x9d, 0x27, 0xa1, 0x6f, 0x88, 0x40, 0x48, 0x58, 0x41, 0x14, 0xd5, 0x19, 0x2d, 0xf9, 0x24, - 0x14, 0xac, 0x89, 0x3f, 0x3a, 0x45, 0x24, 0x24, 0x35, 0x1c, 0xd1, 0x89, 0x3f, 0x42, 0x16, 0x48, - 0xa9, 0xb9, 0x70, 0x4e, 0xae, 0x9c, 0xa8, 0x31, 0x69, 0xc0, 0x12, 0x0f, 0x79, 0x97, 0xb0, 0x3b, - 0x98, 0xd3, 0xa6, 0x9d, 0x75, 0x11, 0x6e, 0x89, 0xc7, 0x79, 0x35, 0x05, 0x0f, 0xed, 0xf7, 0x14, - 0x28, 0x51, 0xc1, 0x06, 0x2f, 0xa5, 0xef, 0x75, 0x4a, 0xc7, 0xe5, 0x60, 0x61, 0x46, 0x13, 0xb2, - 0x3f, 0xd5, 0x69, 0xfc, 0x32, 0xac, 0x27, 0x08, 0x88, 0x86, 0x81, 0x36, 0x06, 0x5e, 0xcf, 0x61, - 0x29, 0x63, 0x98, 0x09, 0x4a, 0x0c, 0xa6, 0xfd, 0x96, 0x02, 0xe7, 0x5a, 0x5f, 0x9a, 0x38, 0xec, - 0xd9, 0xd6, 0x9c, 0x0e, 0xc4, 0x7a, 0xa7, 0xc2, 0x9a, 0xb0, 0xb2, 0x65, 0x41, 0x00, 0x98, 0xb0, - 0xc6, 0x61, 0x66, 0x58, 0x4a, 0xaa, 0x50, 0xe4, 0xe7, 0x4b, 0xc0, 0xc3, 0xb3, 0x5e, 0x96, 0x74, - 0x23, 0x11, 0x63, 0x8e, 0x44, 0x5b, 0x82, 0x5b, 0x18, 0xa7, 0x31, 0x43, 0x6a, 0xed, 0x3f, 0x14, - 0xd8, 0x9c, 0x41, 0x43, 0x5e, 0x87, 0x05, 0x74, 0x50, 0xe4, 0xa3, 0x77, 0x69, 0xc6, 0x27, 0x26, - 0xbd, 0xe3, 0x83, 0x5b, 0xec, 0x20, 0x3a, 0xa1, 0x3f, 0x4c, 0x46, 0x45, 0xde, 0x84, 0x65, 0xbd, - 0xdf, 0xe7, 0xb7, 0xb3, 0x5c, 0xec, 0x76, 0x36, 0xe3, 0x8b, 0x2f, 0x86, 0xf8, 0xec, 0x76, 0xc6, - 0x5c, 0x65, 0xfa, 0x7d, 0x9b, 0x3b, 0x5f, 0x46, 0xfc, 0xb6, 0x3f, 0x0e, 0x6b, 0x71, 0xe4, 0x27, - 0xf2, 0x17, 0x7b, 0x5b, 0x01, 0x35, 0x5e, 0x87, 0x5f, 0x4c, 0xa0, 0xa8, 0xac, 0x61, 0x7e, 0xcc, - 0xa4, 0xfa, 0x83, 0x1c, 0x9c, 0xcf, 0xec, 0x61, 0xf2, 0x02, 0x2c, 0xea, 0xa3, 0x51, 0x6d, 0x97, - 0xcf, 0x2a, 0x2e, 0x21, 0xa1, 0xd2, 0x3b, 0x76, 0x79, 0x65, 0x48, 0xe4, 0x25, 0x28, 0x32, 0xeb, - 0x80, 0x5d, 0xb1, 0xe1, 0x60, 0xe4, 0x1b, 0x6e, 0xba, 0x10, 0x0f, 0x94, 0x2a, 0x10, 0xc9, 0x1e, - 0xac, 0xf1, 0x98, 0x31, 0xa6, 0x7b, 0xe4, 0x7e, 0x25, 0x8c, 0xd8, 0x8f, 0x49, 0x05, 0x84, 0x26, - 0xdd, 0x1e, 0xb3, 0x32, 0x39, 0x6a, 0x4a, 0x9c, 0x8a, 0xd4, 0x41, 0x45, 0x9e, 0x32, 0x27, 0x16, - 0xad, 0x15, 0xa3, 0xf8, 0xb0, 0x4a, 0xcc, 0xe0, 0x95, 0xa2, 0x0c, 0x87, 0x4b, 0x0f, 0x02, 0xef, - 0x68, 0x78, 0xe2, 0x0e, 0x27, 0xbf, 0xb8, 0xe1, 0x8a, 0xbe, 0x71, 0xaa, 0xe1, 0xfa, 0xa3, 0x02, - 0x5b, 0xcc, 0x49, 0x32, 0x2a, 0xd1, 0x48, 0x01, 0xba, 0x51, 0xa2, 0xa1, 0xf7, 0x33, 0x1e, 0x15, - 0x65, 0x17, 0x96, 0x58, 0xb4, 0x1a, 0xb1, 0x32, 0x9e, 0xce, 0xac, 0x02, 0xc3, 0x39, 0xb8, 0xc5, - 0xc4, 0x17, 0xe6, 0x29, 0x19, 0x98, 0x82, 0x94, 0x1c, 0x40, 0xa9, 0x32, 0x70, 0x9d, 0xe1, 0x74, - 0xd4, 0x39, 0xdd, 0x0b, 0xea, 0x16, 0x6f, 0xcb, 0x4a, 0x8f, 0x91, 0xe1, 0xcb, 0x2b, 0xee, 0xe4, - 0x32, 0x23, 0xd2, 0x09, 0x9d, 0xa7, 0x0a, 0xa8, 0x78, 0xfd, 0xf0, 0x9c, 0xfe, 0x49, 0x02, 0x91, - 0x2e, 0xee, 0x19, 0xc8, 0xbd, 0xab, 0x6c, 0x58, 0xab, 0x3b, 0xc1, 0xa4, 0x33, 0x76, 0x86, 0x01, - 0x46, 0xb9, 0x3c, 0x45, 0x14, 0xb0, 0x8b, 0x22, 0x83, 0x33, 0xaa, 0x4c, 0x27, 0x21, 0x29, 0x53, - 0xc8, 0xc6, 0xd9, 0x51, 0x79, 0x69, 0xcf, 0x1b, 0x3a, 0x03, 0xef, 0xab, 0xc2, 0xc7, 0x94, 0xc9, - 0x4b, 0x87, 0x02, 0x68, 0x46, 0xe5, 0xda, 0x67, 0x53, 0xe3, 0xc6, 0x6a, 0x59, 0x82, 0x25, 0x1e, - 0x81, 0x80, 0x79, 0xe4, 0xb7, 0x8d, 0xe6, 0x6e, 0xad, 0xb9, 0xaf, 0x2a, 0x64, 0x0d, 0xa0, 0x6d, - 0xb6, 0x2a, 0x86, 0x65, 0xd1, 0xdf, 0x39, 0xfa, 0x9b, 0xbb, 0xeb, 0xef, 0x75, 0xeb, 0x6a, 0x5e, - 0xf2, 0xd8, 0x2f, 0x68, 0x3f, 0x52, 0xe0, 0x42, 0xf6, 0x50, 0x92, 0x0e, 0x60, 0xcc, 0x06, 0xfe, - 0x96, 0xfe, 0x91, 0xb9, 0xe3, 0x9e, 0x09, 0x4e, 0xc6, 0x7e, 0x98, 0xb0, 0x98, 0x02, 0x39, 0xf1, - 0xf6, 0xc5, 0x9c, 0x14, 0xbd, 0xbe, 0x99, 0xf3, 0xfa, 0x5a, 0x05, 0xb6, 0x66, 0xf1, 0x88, 0x37, - 0x75, 0x1d, 0x4a, 0x7a, 0xbb, 0x5d, 0xaf, 0x55, 0xf4, 0x4e, 0xad, 0xd5, 0x54, 0x15, 0xb2, 0x0c, - 0x0b, 0xfb, 0x66, 0xab, 0xdb, 0x56, 0x73, 0xda, 0xb7, 0x15, 0x58, 0xad, 0x45, 0x56, 0x67, 0xef, - 0x75, 0xf1, 0x7d, 0x34, 0xb6, 0xf8, 0xb6, 0xc2, 0xe8, 0x26, 0xe1, 0x07, 0x4e, 0xb5, 0xf2, 0xde, - 0xcd, 0xc1, 0x46, 0x8a, 0x86, 0x58, 0xb0, 0xa4, 0xdf, 0xb3, 0x5a, 0xb5, 0xdd, 0x0a, 0xaf, 0xd9, - 0x95, 0xc8, 0x5c, 0x0a, 0xf3, 0x5d, 0xa5, 0xbe, 0xc2, 0x3c, 0x82, 0x1f, 0x06, 0xb6, 0xef, 0xf5, - 0xa5, 0xe4, 0xb7, 0xd5, 0x33, 0xa6, 0xe0, 0x84, 0x27, 0xd9, 0x57, 0xa7, 0x63, 0x17, 0xd9, 0xe6, - 0x62, 0x7a, 0xdd, 0x10, 0x9e, 0x66, 0x8c, 0xfe, 0x1b, 0x0e, 0x2d, 0x4f, 0xb3, 0x8e, 0xf8, 0x91, - 0x26, 0x2c, 0xee, 0x7b, 0x93, 0xea, 0xf4, 0x01, 0x5f, 0xbf, 0x97, 0xa3, 0xec, 0x47, 0xd5, 0xe9, - 0x83, 0x34, 0x5b, 0x54, 0x59, 0xb2, 0xe8, 0x3d, 0x31, 0x96, 0x9c, 0x4b, 0xd2, 0x89, 0xb1, 0xf0, - 0x44, 0x4e, 0x8c, 0x3b, 0xab, 0x50, 0xe2, 0x77, 0x28, 0xbc, 0x9e, 0xfc, 0x40, 0x81, 0xad, 0x59, - 0x3d, 0x47, 0xaf, 0x65, 0xf1, 0x60, 0x05, 0x17, 0xc2, 0xf4, 0x18, 0xf1, 0x28, 0x05, 0x02, 0x8d, - 0xbc, 0x01, 0xa5, 0x5a, 0x10, 0x4c, 0xdd, 0xb1, 0xf5, 0x52, 0xd7, 0xac, 0xf1, 0xe9, 0xfa, 0xf4, - 0xbf, 0xbe, 0x73, 0x65, 0x13, 0x7d, 0x3e, 0xc6, 0x76, 0xf0, 0x92, 0x3d, 0x1d, 0x7b, 0xb1, 0x54, - 0x02, 0x32, 0x05, 0x95, 0xa2, 0x9d, 0x69, 0xdf, 0x73, 0xc5, 0x1d, 0x42, 0x38, 0x74, 0x73, 0x98, - 0x7c, 0xa6, 0x09, 0x98, 0xf6, 0x0d, 0x05, 0xb6, 0x67, 0x0f, 0x13, 0x3d, 0x27, 0x3b, 0xcc, 0xa4, - 0x4a, 0xb8, 0x54, 0xe3, 0x39, 0x19, 0xda, 0x5d, 0xc9, 0x3c, 0x05, 0x22, 0x25, 0x0a, 0x53, 0xe3, - 0xe7, 0x52, 0xf9, 0xb0, 0xe3, 0x44, 0x02, 0x51, 0xbb, 0x0f, 0x9b, 0x33, 0x06, 0x95, 0x7c, 0x22, - 0x33, 0xe9, 0x0e, 0xba, 0x29, 0xc9, 0x49, 0x77, 0x62, 0xd9, 0xdb, 0x24, 0xb8, 0xf6, 0x6f, 0x39, - 0xb8, 0x40, 0x57, 0xd7, 0xc0, 0x0d, 0x02, 0x3d, 0xca, 0x4f, 0x4b, 0x77, 0xc5, 0x57, 0x60, 0xf1, - 0xf8, 0xc9, 0x54, 0xc5, 0x0c, 0x9d, 0x10, 0xc0, 0x13, 0x4b, 0x38, 0xc7, 0xd0, 0xff, 0xc9, 0x55, - 0x90, 0x93, 0x9b, 0xe7, 0x31, 0xbc, 0x69, 0x6e, 0x4b, 0x31, 0x97, 0x47, 0x61, 0x1e, 0xe2, 0x57, - 0x61, 0x01, 0xf5, 0x29, 0xfc, 0xec, 0x10, 0x32, 0x7f, 0x76, 0xed, 0x50, 0xdb, 0x62, 0x32, 0x02, - 0xf2, 0x21, 0x80, 0x28, 0x33, 0x04, 0x3f, 0x1c, 0x84, 0x9e, 0x21, 0x4c, 0x0e, 0x61, 0x2e, 0x9f, - 0x1c, 0x3a, 0x3c, 0xdd, 0x42, 0x19, 0x36, 0x44, 0x8f, 0x8f, 0x44, 0x54, 0x44, 0xfe, 0x8a, 0xb9, - 0xce, 0x0a, 0x6a, 0x23, 0x11, 0x19, 0xf1, 0x5a, 0x2a, 0x41, 0x33, 0x06, 0x47, 0x4e, 0x64, 0x61, - 0xbe, 0x96, 0xca, 0xc2, 0x5c, 0x64, 0x58, 0x72, 0xaa, 0x65, 0xed, 0x9f, 0x72, 0xb0, 0x7c, 0x8f, - 0x4a, 0x65, 0xa8, 0x6b, 0x98, 0xaf, 0xbb, 0xb8, 0x0d, 0xa5, 0xba, 0xef, 0xf0, 0xe7, 0x22, 0xee, - 0x53, 0xc2, 0x7c, 0xba, 0x07, 0xbe, 0x23, 0x5e, 0x9e, 0x02, 0x53, 0x46, 0x7a, 0x8c, 0x3f, 0xfa, - 0x1d, 0x58, 0x64, 0xcf, 0x77, 0x5c, 0x8d, 0x26, 0xe4, 0xf2, 0xb0, 0x46, 0x2f, 0xb2, 0x62, 0xe9, - 0x85, 0x83, 0x3d, 0x01, 0xca, 0x42, 0x22, 0x8f, 0xf1, 0x2a, 0x69, 0x56, 0x16, 0x4e, 0xa7, 0x59, - 0x91, 0x62, 0xd9, 0x2d, 0x9e, 0x26, 0x96, 0xdd, 0xf6, 0x6b, 0x50, 0x92, 0xea, 0xf3, 0x44, 0x62, - 0xfa, 0xd7, 0x73, 0xb0, 0x8a, 0xad, 0x0a, 0x6d, 0x79, 0x7e, 0x39, 0xf5, 0x44, 0x1f, 0x8d, 0xe9, - 0x89, 0xb6, 0xe4, 0xf1, 0x62, 0x2d, 0x9b, 0xa3, 0x20, 0xba, 0x03, 0x1b, 0x29, 0x44, 0xf2, 0x32, - 0x2c, 0xd0, 0xea, 0x8b, 0x7b, 0xb5, 0x9a, 0x9c, 0x01, 0x51, 0xdc, 0x63, 0xda, 0xf0, 0xc0, 0x64, - 0xd8, 0xda, 0x7f, 0x2a, 0xb0, 0xc2, 0xd3, 0x8e, 0x0c, 0x0f, 0xfd, 0xc7, 0x76, 0xe7, 0xf5, 0x64, - 0x77, 0xb2, 0xe8, 0x2a, 0xbc, 0x3b, 0xff, 0xb7, 0x3b, 0xf1, 0xb5, 0x58, 0x27, 0x6e, 0x86, 0x51, - 0x10, 0x45, 0x73, 0xe6, 0xf4, 0xe1, 0xf7, 0x31, 0x2e, 0x70, 0x1c, 0x91, 0x7c, 0x1e, 0x96, 0x9b, - 0xee, 0xc3, 0xd8, 0xf5, 0xf4, 0xfa, 0x0c, 0xa6, 0x2f, 0x86, 0x88, 0x6c, 0x4d, 0xe1, 0xc9, 0x3e, - 0x74, 0x1f, 0xda, 0xa9, 0x97, 0xc3, 0x88, 0x25, 0xbd, 0xa1, 0xc6, 0xc9, 0x9e, 0x64, 0xea, 0x73, - 0x07, 0x57, 0x0c, 0x18, 0xf4, 0xcd, 0x3c, 0x40, 0xe4, 0x1b, 0x48, 0x17, 0x60, 0xcc, 0x68, 0x42, - 0x68, 0xf6, 0x11, 0x24, 0xcf, 0x71, 0x61, 0x4b, 0x71, 0x9d, 0x6b, 0xa0, 0x73, 0xb3, 0xa3, 0x54, - 0xa2, 0x2e, 0xba, 0xc2, 0x9d, 0xd1, 0xfa, 0xee, 0xc0, 0x61, 0x7b, 0x7b, 0x7e, 0xe7, 0x1a, 0x06, - 0x25, 0x0e, 0xa1, 0x33, 0xd2, 0x4d, 0xa3, 0xcb, 0xda, 0x2e, 0x45, 0x48, 0xf9, 0xdb, 0x16, 0x9e, - 0xcc, 0xdf, 0xb6, 0x0d, 0xcb, 0xde, 0xf0, 0x2d, 0x77, 0x38, 0xf1, 0xc7, 0x8f, 0x50, 0xed, 0x1e, - 0xe9, 0xf3, 0x68, 0x17, 0xd4, 0x44, 0x19, 0x1b, 0x07, 0x3c, 0x73, 0x43, 0x7c, 0x79, 0x18, 0x42, - 0x60, 0xe8, 0x2f, 0xbc, 0xa0, 0x2e, 0xde, 0x29, 0x14, 0x17, 0xd5, 0xa5, 0x3b, 0x85, 0x62, 0x51, - 0x5d, 0xbe, 0x53, 0x28, 0x2e, 0xab, 0x60, 0x4a, 0x6f, 0x66, 0xe1, 0x9b, 0x98, 0xf4, 0x8c, 0x15, - 0x7f, 0xa2, 0xd2, 0x7e, 0x96, 0x03, 0x92, 0xae, 0x06, 0xf9, 0x28, 0x94, 0xd8, 0x06, 0x6b, 0x8f, - 0x83, 0x2f, 0x73, 0x77, 0x03, 0x16, 0x76, 0x49, 0x02, 0xcb, 0x61, 0x97, 0x18, 0xd8, 0x0c, 0xbe, - 0x3c, 0x20, 0x9f, 0x83, 0xb3, 0xd8, 0xbd, 0x23, 0x77, 0xec, 0xf9, 0x7d, 0x1b, 0x63, 0xe4, 0x3a, - 0x03, 0x9e, 0x1a, 0xf2, 0x05, 0xcc, 0x61, 0x9c, 0x2e, 0x9e, 0x31, 0x0c, 0xe8, 0x02, 0xd8, 0x46, - 0xcc, 0x36, 0x43, 0x24, 0x1d, 0x50, 0x65, 0xfa, 0xc3, 0xe9, 0x60, 0xc0, 0x47, 0xb6, 0x4c, 0x6f, - 0xf4, 0xc9, 0xb2, 0x19, 0x8c, 0xd7, 0x22, 0xc6, 0x7b, 0xd3, 0xc1, 0x80, 0xbc, 0x02, 0xe0, 0x0f, - 0xed, 0x13, 0x2f, 0x08, 0xd8, 0x63, 0x4e, 0xe8, 0xad, 0x1c, 0x41, 0xe5, 0xc1, 0xf0, 0x87, 0x0d, - 0x06, 0x24, 0xbf, 0x06, 0x18, 0xad, 0x01, 0xc3, 0x98, 0x30, 0x6b, 0x24, 0x9e, 0xbd, 0x45, 0x00, - 0xe3, 0xce, 0xd1, 0x47, 0xae, 0xe5, 0x7d, 0x55, 0xb8, 0x7a, 0x7c, 0x06, 0x36, 0xb8, 0xf1, 0xf0, - 0x3d, 0x6f, 0x72, 0xcc, 0xaf, 0x12, 0xef, 0xe5, 0x1e, 0x22, 0xdd, 0x25, 0xfe, 0xae, 0x00, 0xa0, - 0xdf, 0xb3, 0x44, 0x84, 0xb0, 0x9b, 0xb0, 0x40, 0x2f, 0x48, 0x42, 0xd1, 0x82, 0x6a, 0x6a, 0xe4, - 0x2b, 0xab, 0xa9, 0x11, 0x83, 0xae, 0x46, 0x13, 0x8d, 0xea, 0x85, 0x92, 0x05, 0x57, 0x23, 0xb3, - 0xb3, 0x8f, 0x45, 0x68, 0xe6, 0x58, 0xa4, 0x0e, 0x10, 0xc5, 0xec, 0xe2, 0x22, 0xff, 0x46, 0x14, - 0xfc, 0x86, 0x17, 0xf0, 0x2c, 0x11, 0x51, 0xdc, 0x2f, 0x79, 0xfa, 0x44, 0x68, 0xe4, 0x2e, 0x14, - 0x3a, 0x4e, 0xe8, 0x8b, 0x3b, 0x23, 0x92, 0xd9, 0x33, 0x3c, 0x75, 0x67, 0x14, 0xcd, 0x6c, 0x6d, - 0xe2, 0xc4, 0x32, 0x1c, 0x23, 0x13, 0x62, 0xc0, 0x22, 0x4f, 0xcb, 0x3e, 0x23, 0x02, 0x26, 0xcf, - 0xca, 0xce, 0xe3, 0x5e, 0x23, 0x50, 0x96, 0x29, 0x78, 0x02, 0xf6, 0xdb, 0x90, 0xb7, 0xac, 0x06, - 0x8f, 0xdf, 0xb1, 0x1a, 0x5d, 0xbf, 0x2c, 0xab, 0xc1, 0xde, 0x7d, 0x83, 0xe0, 0x44, 0x22, 0xa3, - 0xc8, 0xe4, 0x63, 0x50, 0x92, 0x84, 0x62, 0x1e, 0xf9, 0x06, 0xfb, 0x40, 0xf2, 0x76, 0x92, 0x37, - 0x0d, 0x09, 0x9b, 0xd4, 0x41, 0xbd, 0x3b, 0x7d, 0xe0, 0xea, 0xa3, 0x11, 0xba, 0x41, 0xbe, 0xe5, - 0x8e, 0x99, 0xd8, 0x56, 0x8c, 0x42, 0x46, 0xa3, 0x8f, 0x44, 0x5f, 0x94, 0xca, 0xca, 0xa6, 0x24, - 0x25, 0x69, 0xc3, 0x86, 0xe5, 0x4e, 0xa6, 0x23, 0x66, 0x5f, 0xb3, 0xe7, 0x8f, 0xe9, 0xfd, 0x86, - 0xc5, 0xc9, 0xc1, 0xe8, 0xba, 0x01, 0x2d, 0x14, 0x46, 0x4d, 0x87, 0xfe, 0x38, 0x71, 0xd7, 0x49, - 0x13, 0x6b, 0xae, 0x3c, 0xe4, 0xf4, 0x54, 0x8d, 0xdf, 0x9a, 0xf0, 0x54, 0x15, 0xb7, 0xa6, 0xe8, - 0xae, 0xf4, 0xa1, 0x8c, 0x58, 0x6e, 0xf8, 0x32, 0x28, 0xc5, 0x72, 0x8b, 0x45, 0x70, 0xfb, 0x5e, - 0x41, 0x0a, 0x27, 0xca, 0xc7, 0xe2, 0x75, 0x80, 0x3b, 0xbe, 0x37, 0x6c, 0xb8, 0x93, 0x63, 0xbf, - 0x2f, 0x85, 0x94, 0x2b, 0x7d, 0xd1, 0xf7, 0x86, 0xf6, 0x09, 0x82, 0x7f, 0xf6, 0xce, 0x15, 0x09, - 0xc9, 0x94, 0xfe, 0x27, 0x1f, 0x84, 0x65, 0xfa, 0xab, 0x13, 0x59, 0x09, 0x31, 0x9d, 0x2c, 0x52, - 0xb3, 0xa4, 0x1b, 0x11, 0x02, 0x79, 0x0d, 0xd3, 0xcc, 0x78, 0xa3, 0x89, 0x24, 0xbc, 0x8a, 0x9c, - 0x32, 0xde, 0x68, 0x92, 0x8c, 0x10, 0x2d, 0x21, 0x93, 0x6a, 0x58, 0x75, 0x91, 0x19, 0x8a, 0x67, - 0xb3, 0x41, 0xc5, 0x23, 0x9f, 0x6b, 0xb6, 0x08, 0x4d, 0x2b, 0xa7, 0xfc, 0x4d, 0x90, 0x61, 0x25, - 0xac, 0xea, 0x2e, 0x7b, 0x29, 0xe2, 0x42, 0x2d, 0xab, 0x44, 0x70, 0xdc, 0xb7, 0x7b, 0x08, 0x8e, - 0x55, 0x22, 0x44, 0x26, 0x3b, 0xb0, 0xce, 0x64, 0xfc, 0x30, 0xc3, 0x24, 0x17, 0x71, 0x71, 0x6f, - 0x8b, 0x52, 0x50, 0xca, 0x9f, 0x4f, 0x10, 0x90, 0x3d, 0x58, 0xc0, 0xbb, 0x26, 0x77, 0x0d, 0xb8, - 0x28, 0xab, 0x09, 0x92, 0xeb, 0x08, 0xf7, 0x15, 0x54, 0x10, 0xc8, 0xfb, 0x0a, 0xa2, 0x92, 0x4f, - 0x03, 0x18, 0xc3, 0xb1, 0x3f, 0x18, 0x60, 0xf0, 0xe4, 0x22, 0x5e, 0xa5, 0x9e, 0x8e, 0xaf, 0x47, - 0xe4, 0x12, 0x21, 0xf1, 0x40, 0x7f, 0xf8, 0xdb, 0x4e, 0x84, 0x58, 0x96, 0x78, 0x69, 0x35, 0x58, - 0x64, 0x8b, 0x11, 0x03, 0x91, 0xf3, 0xd4, 0x2a, 0x52, 0x18, 0x6b, 0x16, 0x88, 0x9c, 0xc3, 0xd3, - 0x81, 0xc8, 0x25, 0x02, 0xed, 0x2e, 0x9c, 0xcb, 0x6a, 0x58, 0xec, 0x76, 0xac, 0x9c, 0xf6, 0x76, - 0xfc, 0xdd, 0x3c, 0xac, 0x20, 0x37, 0xb1, 0x0b, 0xeb, 0xb0, 0x6a, 0x4d, 0x1f, 0x84, 0x51, 0xba, - 0xc4, 0x6e, 0x8c, 0xf5, 0x0b, 0xe4, 0x02, 0xf9, 0x0d, 0x2f, 0x46, 0x41, 0x0c, 0x58, 0x13, 0x27, - 0xc1, 0xbe, 0xf0, 0x1c, 0x08, 0x63, 0x80, 0x8b, 0x48, 0x93, 0xe9, 0x0c, 0xbb, 0x09, 0xa2, 0xe8, - 0x3c, 0xc8, 0x3f, 0xc9, 0x79, 0x50, 0x38, 0xd5, 0x79, 0xf0, 0x26, 0xac, 0x88, 0xaf, 0xe1, 0x4e, - 0xbe, 0xf0, 0xde, 0x76, 0xf2, 0x18, 0x33, 0x52, 0x0f, 0x77, 0xf4, 0xc5, 0xb9, 0x3b, 0x3a, 0x3e, - 0x8c, 0x8a, 0x55, 0x36, 0x42, 0x58, 0x7a, 0x63, 0xc7, 0x14, 0x94, 0xfb, 0x95, 0xf6, 0xcf, 0x71, - 0x4a, 0xbe, 0x0c, 0xcb, 0x75, 0x5f, 0xbc, 0x89, 0x49, 0x8f, 0x11, 0x03, 0x01, 0x94, 0xc5, 0x85, - 0x10, 0x33, 0x3c, 0xdd, 0xf2, 0xef, 0xc7, 0xe9, 0xf6, 0x1a, 0x00, 0x77, 0x49, 0x89, 0x52, 0xc7, - 0xe1, 0x92, 0x11, 0x11, 0x4a, 0xe2, 0x6f, 0x22, 0x12, 0x32, 0xdd, 0x9d, 0xb8, 0xb9, 0x8d, 0xde, - 0xeb, 0xf9, 0xd3, 0xe1, 0x24, 0x96, 0x6b, 0x59, 0x78, 0xb0, 0x3a, 0xbc, 0x4c, 0xde, 0x1e, 0x12, - 0x64, 0xef, 0xef, 0x80, 0x90, 0x4f, 0x85, 0xc6, 0x8f, 0x4b, 0xf3, 0x7a, 0x48, 0x4b, 0xf5, 0xd0, - 0x4c, 0x93, 0x47, 0xed, 0x47, 0x8a, 0x9c, 0x80, 0xe1, 0xe7, 0x18, 0xea, 0x57, 0x01, 0x42, 0xa3, - 0x04, 0x31, 0xd6, 0xec, 0xbe, 0x14, 0x42, 0xe5, 0x5e, 0x8e, 0x70, 0xa5, 0xd6, 0xe4, 0xdf, 0xaf, - 0xd6, 0x74, 0xa0, 0xd4, 0xfa, 0xd2, 0xc4, 0x89, 0xac, 0x58, 0xc0, 0x0a, 0x25, 0x59, 0xdc, 0x99, - 0xf2, 0x3b, 0xcf, 0xe1, 0xd9, 0x10, 0xc9, 0xc1, 0x33, 0x44, 0x60, 0x89, 0x50, 0xfb, 0x6f, 0x05, - 0xd6, 0x65, 0xb7, 0xfb, 0x47, 0xc3, 0x1e, 0xf9, 0x04, 0x8b, 0x07, 0xab, 0xc4, 0xae, 0x2c, 0x12, - 0x12, 0xdd, 0x72, 0x1f, 0x0d, 0x7b, 0x4c, 0x00, 0x72, 0x1e, 0xca, 0x95, 0xa5, 0x84, 0xe4, 0x01, - 0xac, 0xb4, 0xfd, 0xc1, 0x80, 0x8a, 0x35, 0xe3, 0xb7, 0xf8, 0x05, 0x80, 0x32, 0x4a, 0x3e, 0x8d, - 0x88, 0x0a, 0xed, 0x3c, 0xcb, 0xef, 0xb9, 0x9b, 0x23, 0xba, 0xdf, 0x7b, 0x9c, 0x2e, 0x62, 0xfb, - 0x36, 0xfa, 0xc9, 0xc9, 0x3c, 0xa3, 0xb3, 0x29, 0x9e, 0x48, 0x40, 0xae, 0x25, 0x2d, 0xc6, 0x7a, - 0xce, 0x39, 0x9b, 0xb4, 0x9f, 0x28, 0x40, 0xd2, 0x4d, 0x93, 0xb7, 0x3e, 0xe5, 0xff, 0x40, 0x14, - 0x4e, 0x88, 0x90, 0x85, 0x27, 0x11, 0x21, 0xb5, 0xef, 0x28, 0x70, 0x2e, 0xab, 0x1f, 0xe8, 0x09, - 0x22, 0x1f, 0x29, 0xe1, 0x81, 0x86, 0x27, 0x88, 0x7c, 0x0a, 0xc5, 0x8f, 0xb5, 0x04, 0x51, 0xb2, - 0x72, 0xb9, 0x27, 0xa9, 0x5c, 0xf9, 0xf7, 0x15, 0x58, 0xaf, 0xe9, 0x0d, 0x9e, 0x77, 0x82, 0x3d, - 0x53, 0x5d, 0x85, 0xa7, 0x6b, 0x7a, 0xc3, 0x6e, 0xb7, 0xea, 0xb5, 0xca, 0x7d, 0x3b, 0x33, 0x9c, - 0xf4, 0xd3, 0xf0, 0x54, 0x1a, 0x25, 0x7a, 0xce, 0xba, 0x04, 0x5b, 0xe9, 0x62, 0x11, 0x72, 0x3a, - 0x9b, 0x58, 0x44, 0xa7, 0xce, 0x97, 0xdf, 0x80, 0x75, 0x11, 0x5e, 0xb9, 0x53, 0xb7, 0x30, 0x81, - 0xc3, 0x3a, 0x94, 0x0e, 0x0c, 0xb3, 0xb6, 0x77, 0xdf, 0xde, 0xeb, 0xd6, 0xeb, 0xea, 0x19, 0xb2, - 0x0a, 0xcb, 0x1c, 0x50, 0xd1, 0x55, 0x85, 0xac, 0x40, 0xb1, 0xd6, 0xb4, 0x8c, 0x4a, 0xd7, 0x34, - 0xd4, 0x5c, 0xf9, 0x0d, 0x58, 0x6b, 0x8f, 0xbd, 0xb7, 0x9c, 0x89, 0x7b, 0xd7, 0x7d, 0x84, 0xaf, - 0x51, 0x4b, 0x90, 0x37, 0xf5, 0x7b, 0xea, 0x19, 0x02, 0xb0, 0xd8, 0xbe, 0x5b, 0xb1, 0x6e, 0xdd, - 0x52, 0x15, 0x52, 0x82, 0xa5, 0xfd, 0x4a, 0xdb, 0xbe, 0xdb, 0xb0, 0xd4, 0x1c, 0xfd, 0xa1, 0xdf, - 0xb3, 0xf0, 0x47, 0xbe, 0xfc, 0x61, 0xd8, 0x40, 0xa9, 0xab, 0xee, 0x05, 0x13, 0x77, 0xe8, 0x8e, - 0xb1, 0x0e, 0x2b, 0x50, 0xb4, 0x5c, 0xba, 0x5d, 0x4e, 0x5c, 0x56, 0x81, 0xc6, 0x74, 0x30, 0xf1, - 0x46, 0x03, 0xf7, 0x2b, 0xaa, 0x52, 0x7e, 0x0d, 0xd6, 0x4d, 0x7f, 0x3a, 0xf1, 0x86, 0x47, 0xd6, - 0x84, 0x62, 0x1c, 0x3d, 0x22, 0xe7, 0x61, 0xa3, 0xdb, 0xd4, 0x1b, 0x3b, 0xb5, 0xfd, 0x6e, 0xab, - 0x6b, 0xd9, 0x0d, 0xbd, 0x53, 0xa9, 0xb2, 0xb7, 0xb0, 0x46, 0xcb, 0xea, 0xd8, 0xa6, 0x51, 0x31, - 0x9a, 0x1d, 0x55, 0x29, 0x7f, 0x0b, 0x15, 0x48, 0x3d, 0x7f, 0xd8, 0xdf, 0x73, 0x7a, 0x13, 0x7f, - 0x8c, 0x15, 0xd6, 0xe0, 0xb2, 0x65, 0x54, 0x5a, 0xcd, 0x5d, 0x7b, 0x4f, 0xaf, 0x74, 0x5a, 0x66, - 0x56, 0x3c, 0xf3, 0x6d, 0xb8, 0x90, 0x81, 0xd3, 0xea, 0xb4, 0x55, 0x85, 0x5c, 0x81, 0x8b, 0x19, - 0x65, 0xf7, 0x8c, 0x1d, 0xbd, 0xdb, 0xa9, 0x36, 0xd5, 0xdc, 0x0c, 0x62, 0xcb, 0x6a, 0xa9, 0xf9, - 0xf2, 0x6f, 0x2b, 0xb0, 0xd6, 0x0d, 0xb8, 0x5d, 0x7d, 0x17, 0x5d, 0x6a, 0x9f, 0x81, 0x4b, 0x5d, - 0xcb, 0x30, 0xed, 0x4e, 0xeb, 0xae, 0xd1, 0xb4, 0xbb, 0x96, 0xbe, 0x9f, 0xac, 0xcd, 0x15, 0xb8, - 0x28, 0x61, 0x98, 0x46, 0xa5, 0x75, 0x60, 0x98, 0x76, 0x5b, 0xb7, 0xac, 0x7b, 0x2d, 0x73, 0x57, - 0x55, 0xe8, 0x17, 0x33, 0x10, 0x1a, 0x7b, 0x3a, 0xab, 0x4d, 0xac, 0xac, 0x69, 0xdc, 0xd3, 0xeb, - 0xf6, 0x4e, 0xab, 0xa3, 0xe6, 0xcb, 0x0d, 0x2a, 0xc4, 0x60, 0x54, 0x61, 0x66, 0x3e, 0x59, 0x84, - 0x42, 0xb3, 0xd5, 0x34, 0x92, 0x2f, 0xa8, 0x2b, 0x50, 0xd4, 0xdb, 0x6d, 0xb3, 0x75, 0x80, 0x53, - 0x0c, 0x60, 0x71, 0xd7, 0x68, 0xd2, 0x9a, 0xe5, 0x69, 0x49, 0xdb, 0x6c, 0x35, 0x5a, 0x1d, 0x63, - 0x57, 0x2d, 0x94, 0x4d, 0xb1, 0xbf, 0x08, 0xa6, 0x3d, 0x9f, 0x3d, 0x57, 0xee, 0x1a, 0x7b, 0x7a, - 0xb7, 0xde, 0xe1, 0x43, 0x74, 0xdf, 0x36, 0x8d, 0x4f, 0x75, 0x0d, 0xab, 0x63, 0xa9, 0x0a, 0x51, - 0x61, 0xa5, 0x69, 0x18, 0xbb, 0x96, 0x6d, 0x1a, 0x07, 0x35, 0xe3, 0x9e, 0x9a, 0xa3, 0x3c, 0xd9, - 0xff, 0xf4, 0x0b, 0xe5, 0xef, 0x29, 0x40, 0x58, 0x44, 0x66, 0x91, 0xe6, 0x07, 0x67, 0xcc, 0x65, - 0xd8, 0xae, 0xd2, 0xa1, 0xc6, 0xa6, 0x35, 0x5a, 0xbb, 0xc9, 0x2e, 0xbb, 0x00, 0x24, 0x51, 0xde, - 0xda, 0xdb, 0x53, 0x15, 0x72, 0x11, 0xce, 0x26, 0xe0, 0xbb, 0x66, 0xab, 0xad, 0xe6, 0xb6, 0x73, - 0x45, 0x85, 0x6c, 0xa6, 0x0a, 0xef, 0x1a, 0x46, 0x5b, 0xcd, 0xd3, 0x21, 0x4a, 0x14, 0x88, 0x25, - 0xc1, 0xc8, 0x0b, 0xe5, 0x6f, 0x28, 0x70, 0x81, 0x55, 0x53, 0xac, 0xaf, 0xb0, 0xaa, 0x97, 0x60, - 0x8b, 0xc7, 0x99, 0xcf, 0xaa, 0xe8, 0x39, 0x50, 0x63, 0xa5, 0xac, 0x9a, 0xe7, 0x61, 0x23, 0x06, - 0xc5, 0x7a, 0xe4, 0xe8, 0xee, 0x11, 0x03, 0xef, 0x18, 0x56, 0xc7, 0x36, 0xf6, 0xf6, 0x5a, 0x66, - 0x87, 0x55, 0x24, 0x5f, 0xd6, 0x60, 0xa3, 0xe2, 0x8e, 0x27, 0xf4, 0x7e, 0x39, 0x0c, 0x3c, 0x7f, - 0x88, 0x55, 0x58, 0x85, 0x65, 0xe3, 0xd3, 0x1d, 0xa3, 0x69, 0xd5, 0x5a, 0x4d, 0xf5, 0x4c, 0xf9, - 0x52, 0x02, 0x47, 0xac, 0x63, 0xcb, 0xaa, 0xaa, 0x67, 0xca, 0x0e, 0xac, 0x0a, 0xeb, 0x72, 0x36, - 0x2b, 0x2e, 0xc3, 0xb6, 0x98, 0x6b, 0xb8, 0xa3, 0x24, 0x9b, 0xb0, 0x05, 0xe7, 0xd2, 0xe5, 0x46, - 0x47, 0x55, 0xe8, 0x28, 0x24, 0x4a, 0x28, 0x3c, 0x57, 0xfe, 0x4d, 0x05, 0x56, 0xc3, 0x97, 0x21, - 0xd4, 0x45, 0x5f, 0x81, 0x8b, 0x8d, 0x3d, 0xdd, 0xde, 0x35, 0x0e, 0x6a, 0x15, 0xc3, 0xbe, 0x5b, - 0x6b, 0xee, 0x26, 0x3e, 0xf2, 0x14, 0x9c, 0xcf, 0x40, 0xc0, 0xaf, 0x6c, 0xc1, 0xb9, 0x64, 0x51, - 0x87, 0x2e, 0xd5, 0x1c, 0xed, 0xfa, 0x64, 0x49, 0xb8, 0x4e, 0xf3, 0xe5, 0x03, 0x58, 0xb3, 0xf4, - 0x46, 0x7d, 0xcf, 0x1f, 0xf7, 0x5c, 0x7d, 0x3a, 0x39, 0x1e, 0x92, 0x8b, 0xb0, 0xb9, 0xd7, 0x32, - 0x2b, 0x86, 0x8d, 0x28, 0x89, 0x1a, 0x9c, 0x85, 0x75, 0xb9, 0xf0, 0xbe, 0x41, 0xa7, 0x2f, 0x81, - 0x35, 0x19, 0xd8, 0x6c, 0xa9, 0xb9, 0xf2, 0x67, 0x61, 0x25, 0x96, 0xed, 0x6f, 0x13, 0xce, 0xca, - 0xbf, 0xdb, 0xee, 0xb0, 0xef, 0x0d, 0x8f, 0xd4, 0x33, 0xc9, 0x02, 0x73, 0x3a, 0x1c, 0xd2, 0x02, - 0x5c, 0xcf, 0x72, 0x41, 0xc7, 0x1d, 0x9f, 0x78, 0x43, 0x67, 0xe2, 0xf6, 0xd5, 0x5c, 0xf9, 0x45, - 0x58, 0x8d, 0xc5, 0x18, 0xa7, 0x03, 0x57, 0x6f, 0xf1, 0x0d, 0xb8, 0x61, 0xec, 0xd6, 0xba, 0x0d, - 0x75, 0x81, 0xae, 0xe4, 0x6a, 0x6d, 0xbf, 0xaa, 0x42, 0xf9, 0xdb, 0x0a, 0xbd, 0x4c, 0x61, 0xe6, - 0xa0, 0xc6, 0x9e, 0x2e, 0x86, 0x9a, 0x4e, 0x33, 0x96, 0xb9, 0xc0, 0xb0, 0x2c, 0x66, 0x38, 0x70, - 0x09, 0xb6, 0xf8, 0x0f, 0x5b, 0x6f, 0xee, 0xda, 0x55, 0xdd, 0xdc, 0xbd, 0xa7, 0x9b, 0x74, 0xee, - 0xdd, 0x57, 0x73, 0xb8, 0xa0, 0x24, 0x88, 0xdd, 0x69, 0x75, 0x2b, 0x55, 0x35, 0x4f, 0xe7, 0x6f, - 0x0c, 0xde, 0xae, 0x35, 0xd5, 0x02, 0x2e, 0xcf, 0x14, 0x36, 0xb2, 0xa5, 0xe5, 0x0b, 0xe5, 0x77, - 0x15, 0xd8, 0xb4, 0xbc, 0xa3, 0xa1, 0x33, 0x99, 0x8e, 0x5d, 0x7d, 0x70, 0xe4, 0x8f, 0xbd, 0xc9, - 0xf1, 0x89, 0x35, 0xf5, 0x26, 0x2e, 0xb9, 0x09, 0xcf, 0x59, 0xb5, 0xfd, 0xa6, 0xde, 0xa1, 0xcb, - 0x4b, 0xaf, 0xef, 0xb7, 0xcc, 0x5a, 0xa7, 0xda, 0xb0, 0xad, 0x6e, 0x2d, 0x35, 0xf3, 0xae, 0xc1, - 0x33, 0xb3, 0x51, 0xeb, 0xc6, 0xbe, 0x5e, 0xb9, 0xaf, 0x2a, 0xf3, 0x19, 0xee, 0xe8, 0x75, 0xbd, - 0x59, 0x31, 0x76, 0xed, 0x83, 0x5b, 0x6a, 0x8e, 0x3c, 0x07, 0x57, 0x67, 0xa3, 0xee, 0xd5, 0xda, - 0x16, 0x45, 0xcb, 0xcf, 0xff, 0x6e, 0xd5, 0x6a, 0x50, 0xac, 0x42, 0xf9, 0x3b, 0x0a, 0x6c, 0xcd, - 0x0a, 0x34, 0x45, 0xae, 0x83, 0x66, 0x34, 0x3b, 0xa6, 0x5e, 0xdb, 0xb5, 0x2b, 0xa6, 0xb1, 0x6b, - 0x34, 0x3b, 0x35, 0xbd, 0x6e, 0xd9, 0x56, 0xab, 0x4b, 0x67, 0x53, 0x64, 0xdf, 0xf1, 0x2c, 0x5c, - 0x99, 0x83, 0xd7, 0xaa, 0xed, 0x56, 0x54, 0x85, 0xdc, 0x82, 0x17, 0xe6, 0x20, 0x59, 0xf7, 0xad, - 0x8e, 0xd1, 0x90, 0x4b, 0xd4, 0x5c, 0xb9, 0x02, 0xdb, 0xb3, 0x23, 0xd1, 0xd0, 0x6d, 0x3a, 0xde, - 0xd3, 0x45, 0x28, 0xec, 0xd2, 0x93, 0x21, 0x96, 0xe0, 0xa2, 0xec, 0x81, 0x9a, 0x0c, 0x26, 0x91, - 0x32, 0xc4, 0x31, 0xbb, 0xcd, 0x26, 0x3b, 0x46, 0xd6, 0xa1, 0xd4, 0xea, 0x54, 0x0d, 0x93, 0xa7, - 0x08, 0xc1, 0x9c, 0x20, 0xdd, 0x26, 0x5d, 0x38, 0x2d, 0xb3, 0xf6, 0x19, 0x3c, 0x4f, 0xb6, 0xe0, - 0x9c, 0x55, 0xd7, 0x2b, 0x77, 0xed, 0x66, 0xab, 0x63, 0xd7, 0x9a, 0x76, 0xa5, 0xaa, 0x37, 0x9b, - 0x46, 0x5d, 0x05, 0xec, 0xcc, 0x59, 0x0e, 0xa4, 0xe4, 0x83, 0x70, 0xa3, 0x75, 0xb7, 0xa3, 0xdb, - 0xed, 0x7a, 0x77, 0xbf, 0xd6, 0xb4, 0xad, 0xfb, 0xcd, 0x8a, 0x90, 0x7d, 0x2a, 0xe9, 0x2d, 0xf7, - 0x06, 0x5c, 0x9b, 0x8b, 0x1d, 0x25, 0xf3, 0xb8, 0x0e, 0xda, 0x5c, 0x4c, 0xde, 0x90, 0xf2, 0x8f, - 0x15, 0xb8, 0x38, 0xe7, 0xa1, 0x9c, 0xbc, 0x00, 0x37, 0xab, 0x86, 0xbe, 0x5b, 0x37, 0x2c, 0x0b, - 0x37, 0x0a, 0x3a, 0x0c, 0xcc, 0x60, 0x27, 0x73, 0x43, 0xbd, 0x09, 0xcf, 0xcd, 0x47, 0x8f, 0x8e, - 0xe6, 0x1b, 0x70, 0x6d, 0x3e, 0x2a, 0x3f, 0xaa, 0x73, 0xa4, 0x0c, 0xd7, 0xe7, 0x63, 0x86, 0x47, - 0x7c, 0xbe, 0xfc, 0xbb, 0x0a, 0x5c, 0xc8, 0xd6, 0x56, 0xd1, 0xba, 0xd5, 0x9a, 0x56, 0x47, 0xaf, - 0xd7, 0xed, 0xb6, 0x6e, 0xea, 0x0d, 0xdb, 0x68, 0x9a, 0xad, 0x7a, 0x3d, 0xeb, 0x68, 0xbb, 0x06, - 0xcf, 0xcc, 0x46, 0xb5, 0x2a, 0x66, 0xad, 0x4d, 0x77, 0x6f, 0x0d, 0x2e, 0xcf, 0xc6, 0x32, 0x6a, - 0x15, 0x43, 0xcd, 0xed, 0xbc, 0xfe, 0xc3, 0x7f, 0xbc, 0x7c, 0xe6, 0x87, 0xef, 0x5e, 0x56, 0x7e, - 0xf2, 0xee, 0x65, 0xe5, 0x1f, 0xde, 0xbd, 0xac, 0x7c, 0xe6, 0xf9, 0xd3, 0xe5, 0xc1, 0xc2, 0x4b, - 0xc9, 0x83, 0x45, 0xbc, 0x86, 0xbd, 0xf4, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x64, 0x0f, 0xaf, - 0x27, 0x13, 0xc0, 0x01, 0x00, + // 30542 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6b, 0x70, 0x1c, 0x49, + 0x7a, 0x20, 0x36, 0xdd, 0x8d, 0x47, 0xe3, 0xc3, 0xab, 0x91, 0x00, 0x49, 0x10, 0xf3, 0x68, 0x4e, + 0xcd, 0x0c, 0x87, 0x9c, 0x9d, 0x21, 0x97, 0xe0, 0x0e, 0x77, 0x67, 0xe7, 0xb5, 0x8d, 0x6e, 0x90, + 0x68, 0x12, 0x00, 0x31, 0xd5, 0x00, 0xb1, 0xa3, 0x7d, 0xd4, 0x16, 0xba, 0x13, 0x40, 0x0d, 0xba, + 0xbb, 0x7a, 0xab, 0xaa, 0x09, 0x42, 0x7b, 0xb2, 0xde, 0x27, 0x2b, 0x64, 0x3d, 0x4f, 0x3a, 0xed, + 0x39, 0x74, 0xb2, 0x42, 0xbe, 0xf3, 0x29, 0xce, 0x21, 0xc5, 0x59, 0xb2, 0xec, 0xb3, 0x2f, 0x2c, + 0x4b, 0x17, 0x67, 0x59, 0x56, 0x5c, 0x9c, 0x14, 0xf6, 0xd9, 0x0e, 0xaf, 0xcf, 0x90, 0x65, 0xf9, + 0x87, 0x03, 0x11, 0x8e, 0x90, 0x7c, 0x11, 0x8e, 0xf0, 0x3a, 0x74, 0x77, 0x91, 0x5f, 0x66, 0x56, + 0x65, 0x56, 0x55, 0x37, 0x1a, 0x43, 0x8e, 0x4e, 0xdc, 0xd0, 0x1f, 0x12, 0xfd, 0xe5, 0xf7, 0x7d, + 0x59, 0xf9, 0xfe, 0xf2, 0xcb, 0xef, 0x01, 0x2f, 0x06, 0xb4, 0x49, 0x3b, 0xae, 0x17, 0x5c, 0x6f, + 0xd2, 0x3d, 0xbb, 0x7e, 0x74, 0x3d, 0x38, 0xea, 0x50, 0x9f, 0xff, 0x7b, 0xad, 0xe3, 0xb9, 0x81, + 0x4b, 0x86, 0xf1, 0xc7, 0xc2, 0xdc, 0x9e, 0xbb, 0xe7, 0x22, 0xe4, 0x3a, 0xfb, 0x8b, 0x17, 0x2e, + 0xbc, 0xb0, 0xe7, 0xba, 0x7b, 0x4d, 0x7a, 0x1d, 0x7f, 0xed, 0x74, 0x77, 0xaf, 0x37, 0xba, 0x9e, + 0x1d, 0x38, 0x6e, 0x5b, 0x94, 0x17, 0xe3, 0xe5, 0x81, 0xd3, 0xa2, 0x7e, 0x60, 0xb7, 0x3a, 0xbd, + 0x18, 0x1c, 0x7a, 0x76, 0xa7, 0x43, 0x3d, 0x51, 0xfb, 0xc2, 0xd5, 0xf0, 0x03, 0xed, 0x20, 0x60, + 0x94, 0x8c, 0xf9, 0xf5, 0x87, 0x37, 0xd4, 0x9f, 0x02, 0xf5, 0x56, 0x8f, 0xb6, 0x78, 0x5d, 0x3f, + 0xa0, 0x0d, 0xab, 0x41, 0x1f, 0x3a, 0x75, 0x6a, 0x79, 0xf4, 0xeb, 0x5d, 0xc7, 0xa3, 0x2d, 0xda, + 0x0e, 0x04, 0xdd, 0x1b, 0xe9, 0x74, 0xf2, 0x43, 0x62, 0x5f, 0x64, 0xfc, 0x62, 0x0e, 0xc6, 0xee, + 0x51, 0xda, 0x29, 0x35, 0x9d, 0x87, 0x94, 0xbc, 0x04, 0x43, 0xeb, 0x76, 0x8b, 0xce, 0x67, 0x2e, + 0x65, 0xae, 0x8c, 0x2d, 0x4d, 0x9f, 0x1c, 0x17, 0xc7, 0x7d, 0xea, 0x3d, 0xa4, 0x9e, 0xd5, 0xb6, + 0x5b, 0xd4, 0xc4, 0x42, 0xf2, 0x29, 0x18, 0x63, 0xff, 0xfb, 0x1d, 0xbb, 0x4e, 0xe7, 0xb3, 0x88, + 0x39, 0x79, 0x72, 0x5c, 0x1c, 0x6b, 0x4b, 0xa0, 0x19, 0x95, 0x93, 0x2a, 0x8c, 0x2e, 0x3f, 0xea, + 0x38, 0x1e, 0xf5, 0xe7, 0x87, 0x2e, 0x65, 0xae, 0x8c, 0x2f, 0x2e, 0x5c, 0xe3, 0x7d, 0x74, 0x4d, + 0xf6, 0xd1, 0xb5, 0x4d, 0xd9, 0x89, 0x4b, 0xb3, 0xbf, 0x77, 0x5c, 0x7c, 0xe6, 0xe4, 0xb8, 0x38, + 0x4a, 0x39, 0xc9, 0x4f, 0xfd, 0x51, 0x31, 0x63, 0x4a, 0x7a, 0xf2, 0x0e, 0x0c, 0x6d, 0x1e, 0x75, + 0xe8, 0xfc, 0xd8, 0xa5, 0xcc, 0x95, 0xa9, 0xc5, 0x17, 0xae, 0xf1, 0x61, 0x0d, 0x3f, 0x3e, 0xfa, + 0x8b, 0x61, 0x2d, 0xe5, 0x4f, 0x8e, 0x8b, 0x43, 0x0c, 0xc5, 0x44, 0x2a, 0xf2, 0x06, 0x8c, 0xac, + 0xb8, 0x7e, 0x50, 0xad, 0xcc, 0x03, 0x7e, 0xf2, 0xb9, 0x93, 0xe3, 0xe2, 0xcc, 0xbe, 0xeb, 0x07, + 0x96, 0xd3, 0x78, 0xdd, 0x6d, 0x39, 0x01, 0x6d, 0x75, 0x82, 0x23, 0x53, 0x20, 0x19, 0x8f, 0x60, + 0x52, 0xe3, 0x47, 0xc6, 0x61, 0x74, 0x6b, 0xfd, 0xde, 0xfa, 0xfd, 0xed, 0xf5, 0xc2, 0x33, 0x24, + 0x0f, 0x43, 0xeb, 0xf7, 0x2b, 0xcb, 0x85, 0x0c, 0x19, 0x85, 0x5c, 0x69, 0x63, 0xa3, 0x90, 0x25, + 0x13, 0x90, 0xaf, 0x94, 0x36, 0x4b, 0x4b, 0xa5, 0xda, 0x72, 0x21, 0x47, 0x66, 0x61, 0x7a, 0xbb, + 0xba, 0x5e, 0xb9, 0xbf, 0x5d, 0xb3, 0x2a, 0xcb, 0xb5, 0x7b, 0x9b, 0xf7, 0x37, 0x0a, 0x43, 0x64, + 0x0a, 0xe0, 0xde, 0xd6, 0xd2, 0xb2, 0xb9, 0xbe, 0xbc, 0xb9, 0x5c, 0x2b, 0x0c, 0x93, 0x39, 0x28, + 0x48, 0x12, 0xab, 0xb6, 0x6c, 0x3e, 0xa8, 0x96, 0x97, 0x0b, 0x23, 0x77, 0x87, 0xf2, 0xb9, 0xc2, + 0x90, 0x39, 0xba, 0x4a, 0x6d, 0x9f, 0x56, 0x2b, 0xc6, 0x7f, 0x98, 0x83, 0xfc, 0x1a, 0x0d, 0xec, + 0x86, 0x1d, 0xd8, 0xe4, 0x39, 0x6d, 0x7c, 0xb0, 0x89, 0xca, 0xc0, 0xbc, 0x94, 0x1c, 0x98, 0xe1, + 0x93, 0xe3, 0x62, 0xe6, 0x0d, 0x75, 0x40, 0xde, 0x86, 0xf1, 0x0a, 0xf5, 0xeb, 0x9e, 0xd3, 0x61, + 0x93, 0x6d, 0x3e, 0x87, 0x68, 0x17, 0x4f, 0x8e, 0x8b, 0xe7, 0x1a, 0x11, 0x58, 0xe9, 0x10, 0x15, + 0x9b, 0x54, 0x61, 0x64, 0xd5, 0xde, 0xa1, 0x4d, 0x7f, 0x7e, 0xf8, 0x52, 0xee, 0xca, 0xf8, 0xe2, + 0xb3, 0x62, 0x10, 0xe4, 0x07, 0x5e, 0xe3, 0xa5, 0xcb, 0xed, 0xc0, 0x3b, 0x5a, 0x9a, 0x3b, 0x39, + 0x2e, 0x16, 0x9a, 0x08, 0x50, 0x3b, 0x98, 0xa3, 0x90, 0x5a, 0x34, 0x31, 0x46, 0x4e, 0x9d, 0x18, + 0xcf, 0xff, 0xde, 0x71, 0x31, 0xc3, 0x06, 0x4c, 0x4c, 0x8c, 0x88, 0x9f, 0x3e, 0x45, 0x16, 0x21, + 0x6f, 0xd2, 0x87, 0x8e, 0xcf, 0x5a, 0x96, 0xc7, 0x96, 0x9d, 0x3f, 0x39, 0x2e, 0x12, 0x4f, 0xc0, + 0x94, 0xcf, 0x08, 0xf1, 0x16, 0xde, 0x82, 0x71, 0xe5, 0xab, 0x49, 0x01, 0x72, 0x07, 0xf4, 0x88, + 0xf7, 0xb0, 0xc9, 0xfe, 0x24, 0x73, 0x30, 0xfc, 0xd0, 0x6e, 0x76, 0x45, 0x97, 0x9a, 0xfc, 0xc7, + 0xe7, 0xb3, 0x9f, 0xcb, 0xdc, 0x1d, 0xca, 0x8f, 0x16, 0xf2, 0x66, 0xb6, 0x5a, 0x31, 0x7e, 0x66, + 0x08, 0xf2, 0xa6, 0xcb, 0x17, 0x30, 0xb9, 0x0a, 0xc3, 0xb5, 0xc0, 0x0e, 0xe4, 0x30, 0xcd, 0x9e, + 0x1c, 0x17, 0xa7, 0xd9, 0xe2, 0xa6, 0x4a, 0xfd, 0x1c, 0x83, 0xa1, 0x6e, 0xec, 0xdb, 0xbe, 0x1c, + 0x2e, 0x44, 0xed, 0x30, 0x80, 0x8a, 0x8a, 0x18, 0xe4, 0x32, 0x0c, 0xad, 0xb9, 0x0d, 0x2a, 0x46, + 0x8c, 0x9c, 0x1c, 0x17, 0xa7, 0x5a, 0x6e, 0x43, 0x45, 0xc4, 0x72, 0xf2, 0x3a, 0x8c, 0x95, 0xbb, + 0x9e, 0x47, 0xdb, 0x6c, 0xae, 0x0f, 0x21, 0xf2, 0xd4, 0xc9, 0x71, 0x11, 0xea, 0x1c, 0x68, 0x39, + 0x0d, 0x33, 0x42, 0x60, 0xc3, 0x50, 0x0b, 0x6c, 0x2f, 0xa0, 0x8d, 0xf9, 0xe1, 0x81, 0x86, 0x81, + 0xad, 0xcf, 0x19, 0x9f, 0x93, 0xc4, 0x87, 0x41, 0x70, 0x22, 0x2b, 0x30, 0x7e, 0xc7, 0xb3, 0xeb, + 0x74, 0x83, 0x7a, 0x8e, 0xdb, 0xc0, 0xf1, 0xcd, 0x2d, 0x5d, 0x3e, 0x39, 0x2e, 0x9e, 0xdf, 0x63, + 0x60, 0xab, 0x83, 0xf0, 0x88, 0xfa, 0xdb, 0xc7, 0xc5, 0x7c, 0x45, 0x6c, 0xb5, 0xa6, 0x4a, 0x4a, + 0xbe, 0xc6, 0x06, 0xc7, 0x0f, 0xb0, 0x6b, 0x69, 0x63, 0x7e, 0xf4, 0xd4, 0x4f, 0x34, 0xc4, 0x27, + 0x9e, 0x6f, 0xda, 0x7e, 0x60, 0x79, 0x9c, 0x2e, 0xf6, 0x9d, 0x2a, 0x4b, 0x72, 0x1f, 0xf2, 0xb5, + 0xfa, 0x3e, 0x6d, 0x74, 0x9b, 0x14, 0xa7, 0xcc, 0xf8, 0xe2, 0x05, 0x31, 0xa9, 0xe5, 0x78, 0xca, + 0xe2, 0xa5, 0x05, 0xc1, 0x9b, 0xf8, 0x02, 0xa2, 0xce, 0x27, 0x89, 0xf5, 0xf9, 0xfc, 0x37, 0x7f, + 0xa9, 0xf8, 0xcc, 0xf7, 0xfd, 0x8b, 0x4b, 0xcf, 0x18, 0xff, 0x79, 0x16, 0x0a, 0x71, 0x26, 0x64, + 0x17, 0x26, 0xb7, 0x3a, 0x0d, 0x3b, 0xa0, 0xe5, 0xa6, 0x43, 0xdb, 0x81, 0x8f, 0x93, 0xa4, 0x7f, + 0x9b, 0x5e, 0x16, 0xf5, 0xce, 0x77, 0x91, 0xd0, 0xaa, 0x73, 0xca, 0x58, 0xab, 0x74, 0xb6, 0x51, + 0x3d, 0x35, 0xdc, 0xc0, 0x7d, 0x9c, 0x61, 0x67, 0xab, 0x87, 0x6f, 0xfd, 0x3d, 0xea, 0x11, 0x6c, + 0xc5, 0x04, 0x6a, 0x37, 0x76, 0x8e, 0x70, 0x66, 0x0e, 0x3e, 0x81, 0x18, 0x49, 0xca, 0x04, 0x62, + 0x60, 0xe3, 0xff, 0xcc, 0xc0, 0x94, 0x49, 0x7d, 0xb7, 0xeb, 0xd5, 0xe9, 0x0a, 0xb5, 0x1b, 0xd4, + 0x63, 0xd3, 0xff, 0x9e, 0xd3, 0x6e, 0x88, 0x35, 0x85, 0xd3, 0xff, 0xc0, 0x69, 0xab, 0x5b, 0x37, + 0x96, 0x93, 0x4f, 0xc3, 0x68, 0xad, 0xbb, 0x83, 0xa8, 0xd9, 0x68, 0x07, 0xf0, 0xbb, 0x3b, 0x56, + 0x0c, 0x5d, 0xa2, 0x91, 0xeb, 0x30, 0xfa, 0x80, 0x7a, 0x7e, 0xb4, 0x1b, 0xe2, 0xd1, 0xf0, 0x90, + 0x83, 0x54, 0x02, 0x81, 0x45, 0xee, 0x44, 0x3b, 0xb2, 0x38, 0xd4, 0xa6, 0x63, 0xfb, 0x60, 0x34, + 0x55, 0x5a, 0x02, 0xa2, 0x4e, 0x15, 0x89, 0x65, 0xfc, 0x74, 0x16, 0x0a, 0x15, 0x3b, 0xb0, 0x77, + 0x6c, 0x5f, 0xf4, 0xe7, 0x83, 0x9b, 0x6c, 0x8f, 0x57, 0x1a, 0x8a, 0x7b, 0x3c, 0xfb, 0xf2, 0x8f, + 0xdd, 0xbc, 0x57, 0xe2, 0xcd, 0x1b, 0x67, 0x27, 0xac, 0x68, 0x5e, 0xd4, 0xa8, 0x77, 0x4f, 0x6f, + 0x54, 0x41, 0x34, 0x2a, 0x2f, 0x1b, 0x15, 0x35, 0x85, 0xbc, 0x0b, 0x43, 0xb5, 0x0e, 0xad, 0x8b, + 0x4d, 0x44, 0x9e, 0x0b, 0x7a, 0xe3, 0x18, 0xc2, 0x83, 0x9b, 0x4b, 0x13, 0x82, 0xcd, 0x90, 0xdf, + 0xa1, 0x75, 0x13, 0xc9, 0x94, 0x45, 0xf3, 0x0f, 0x73, 0x30, 0x97, 0x46, 0xa6, 0xb6, 0x63, 0xa4, + 0x4f, 0x3b, 0xae, 0x40, 0x9e, 0x1d, 0xe1, 0xec, 0x58, 0xc4, 0xed, 0x62, 0x6c, 0x69, 0x82, 0x7d, + 0xf2, 0xbe, 0x80, 0x99, 0x61, 0x29, 0x79, 0x29, 0x94, 0x08, 0xf2, 0x11, 0x3f, 0x21, 0x11, 0x48, + 0x39, 0x80, 0x8d, 0xb5, 0x5c, 0xc2, 0x28, 0x38, 0x44, 0xdd, 0x22, 0xc1, 0xd1, 0x58, 0x7b, 0x02, + 0xa2, 0x1d, 0x33, 0xf2, 0x50, 0x58, 0x86, 0xbc, 0x6c, 0xd6, 0xfc, 0x04, 0x32, 0x9a, 0x89, 0x75, + 0xd2, 0x83, 0x9b, 0x7c, 0x30, 0x1b, 0xe2, 0xb7, 0xca, 0x46, 0xe2, 0x90, 0x9b, 0x90, 0xdf, 0xf0, + 0xdc, 0x47, 0x47, 0xd5, 0x8a, 0x3f, 0x3f, 0x79, 0x29, 0x77, 0x65, 0x6c, 0xe9, 0xc2, 0xc9, 0x71, + 0x71, 0xb6, 0xc3, 0x60, 0x96, 0xd3, 0x50, 0x4f, 0xda, 0x10, 0xf1, 0xee, 0x50, 0x3e, 0x53, 0xc8, + 0xde, 0x1d, 0xca, 0x67, 0x0b, 0x39, 0x2e, 0x5e, 0xdc, 0x1d, 0xca, 0x0f, 0x15, 0x86, 0xef, 0x0e, + 0xe5, 0x87, 0x51, 0xe0, 0x18, 0x2b, 0xc0, 0xdd, 0xa1, 0xfc, 0x78, 0x61, 0x42, 0x3b, 0xed, 0x91, + 0x41, 0xe0, 0xd6, 0xdd, 0xa6, 0x99, 0xdb, 0x32, 0xab, 0xe6, 0x48, 0xb9, 0x54, 0xa6, 0x5e, 0x60, + 0xe6, 0x4a, 0xdb, 0x35, 0x73, 0xb2, 0x72, 0xd4, 0xb6, 0x5b, 0x4e, 0x9d, 0x1f, 0x9d, 0x66, 0xee, + 0x4e, 0x79, 0xc3, 0x28, 0xc1, 0x54, 0xd4, 0x96, 0x55, 0xc7, 0x0f, 0xc8, 0x75, 0x18, 0x93, 0x10, + 0xb6, 0xd1, 0xe5, 0x52, 0x5b, 0x6d, 0x46, 0x38, 0xc6, 0xef, 0x66, 0x01, 0xa2, 0x92, 0xa7, 0x74, + 0x2d, 0x7c, 0x56, 0x5b, 0x0b, 0xe7, 0xe2, 0x6b, 0xa1, 0xe7, 0x2a, 0x20, 0xef, 0xc3, 0x08, 0x13, + 0x0b, 0xba, 0x52, 0x24, 0xba, 0x10, 0x27, 0xc5, 0xc2, 0x07, 0x37, 0x97, 0xa6, 0x04, 0xf1, 0x88, + 0x8f, 0x10, 0x53, 0x90, 0x29, 0xcb, 0xe8, 0x17, 0x47, 0xa3, 0xc1, 0x10, 0x0b, 0xe8, 0x0a, 0x84, + 0x03, 0x2a, 0x3a, 0x14, 0x57, 0x46, 0x47, 0x0e, 0x72, 0x58, 0x4a, 0x2e, 0x02, 0x1b, 0x70, 0xd1, + 0xa9, 0xa3, 0x27, 0xc7, 0xc5, 0x5c, 0xd7, 0x73, 0x70, 0x12, 0x90, 0xeb, 0x20, 0xa6, 0x81, 0xe8, + 0x40, 0x36, 0xfb, 0x66, 0xea, 0xb6, 0x55, 0xa7, 0x5e, 0x10, 0xf5, 0xf8, 0x7c, 0x46, 0xce, 0x16, + 0xd2, 0x01, 0x7d, 0xaa, 0xcc, 0x0f, 0xe1, 0x34, 0xb8, 0x92, 0xda, 0x2b, 0xd7, 0x34, 0x54, 0x2e, + 0x46, 0x5e, 0x92, 0xa7, 0x52, 0x83, 0x97, 0x59, 0x09, 0x91, 0x52, 0xaf, 0x80, 0xdc, 0x04, 0x36, + 0x43, 0x45, 0xef, 0x83, 0xa8, 0xa7, 0xb4, 0x5d, 0x5b, 0x3a, 0x27, 0x38, 0x4d, 0xda, 0x87, 0x2a, + 0x39, 0xc3, 0x26, 0x6f, 0x03, 0x9b, 0xc2, 0xa2, 0xdf, 0x89, 0x20, 0xba, 0x53, 0xde, 0x28, 0x37, + 0xdd, 0x6e, 0xa3, 0xf6, 0xc1, 0x6a, 0x44, 0xbc, 0x57, 0xef, 0xa8, 0xc4, 0x77, 0xca, 0x1b, 0xe4, + 0x6d, 0x18, 0x2e, 0x7d, 0x77, 0xd7, 0xa3, 0x42, 0x3e, 0x99, 0x90, 0x75, 0x32, 0xd8, 0xd2, 0x05, + 0x41, 0x38, 0x6d, 0xb3, 0x9f, 0xaa, 0x5c, 0x87, 0xe5, 0xac, 0xe6, 0xcd, 0xd5, 0x9a, 0x90, 0x3d, + 0x48, 0xac, 0x5b, 0x36, 0x57, 0x95, 0xcf, 0x0e, 0xb4, 0x56, 0x33, 0x2a, 0x72, 0x1d, 0xb2, 0xa5, + 0x0a, 0xde, 0x88, 0xc6, 0x17, 0xc7, 0x64, 0xb5, 0x95, 0xa5, 0x39, 0x41, 0x32, 0x61, 0xab, 0xcb, + 0x20, 0x5b, 0xaa, 0x90, 0x25, 0x18, 0x5e, 0x3b, 0xaa, 0x7d, 0xb0, 0x2a, 0x36, 0xb3, 0x59, 0x39, + 0xaf, 0x19, 0xec, 0x3e, 0x2e, 0x7b, 0x3f, 0xfa, 0xe2, 0xd6, 0x91, 0xff, 0xf5, 0xa6, 0xfa, 0xc5, + 0x88, 0x46, 0x36, 0x60, 0xac, 0xd4, 0x68, 0x39, 0xed, 0x2d, 0x9f, 0x7a, 0xf3, 0xe3, 0xc8, 0x67, + 0x3e, 0xf6, 0xdd, 0x61, 0xf9, 0xd2, 0xfc, 0xc9, 0x71, 0x71, 0xce, 0x66, 0x3f, 0xad, 0xae, 0x4f, + 0x3d, 0x85, 0x5b, 0xc4, 0x84, 0x6c, 0x00, 0xac, 0xb9, 0xed, 0x3d, 0xb7, 0x14, 0x34, 0x6d, 0x3f, + 0xb6, 0x3d, 0x46, 0x05, 0xa1, 0xf8, 0x70, 0xae, 0xc5, 0x60, 0x96, 0xcd, 0x80, 0x0a, 0x43, 0x85, + 0x07, 0xb9, 0x0d, 0x23, 0xf7, 0x3d, 0xbb, 0xde, 0xa4, 0xf3, 0x93, 0xc8, 0x6d, 0x4e, 0x70, 0xe3, + 0x40, 0xd9, 0xd2, 0x79, 0xc1, 0xb0, 0xe0, 0x22, 0x58, 0xbd, 0xa6, 0x70, 0xc4, 0x85, 0x6d, 0x20, + 0xc9, 0x39, 0x99, 0x72, 0x49, 0xf8, 0x94, 0x7a, 0x49, 0x88, 0x16, 0x7d, 0xd9, 0x6d, 0xb5, 0xec, + 0x76, 0x03, 0x69, 0x1f, 0x2c, 0x2a, 0x77, 0x07, 0xe3, 0xeb, 0x30, 0x93, 0xe8, 0xac, 0x53, 0xee, + 0x77, 0xef, 0xc1, 0x74, 0x85, 0xee, 0xda, 0xdd, 0x66, 0x10, 0x9e, 0x24, 0x7c, 0x89, 0xe2, 0x4d, + 0xab, 0xc1, 0x8b, 0x2c, 0x79, 0x7c, 0x98, 0x71, 0x64, 0xe3, 0x5d, 0x98, 0xd4, 0x9a, 0xcf, 0xae, + 0x0a, 0xa5, 0x6e, 0xc3, 0x09, 0x70, 0x20, 0x33, 0xd1, 0x55, 0xc1, 0x66, 0x40, 0x1c, 0x2e, 0x33, + 0x42, 0x30, 0xfe, 0x8e, 0x2a, 0xad, 0x88, 0x9d, 0x88, 0x5d, 0xab, 0xc5, 0x7e, 0x90, 0x89, 0x64, + 0xa7, 0xc4, 0x7e, 0x10, 0xee, 0x06, 0x57, 0xf9, 0xda, 0xcc, 0x26, 0xd6, 0xe6, 0xb8, 0x18, 0x89, + 0x9c, 0x7d, 0xe8, 0xf3, 0x15, 0x19, 0xce, 0xd4, 0xdc, 0xc7, 0x9f, 0xa9, 0xef, 0xc3, 0xc4, 0x9a, + 0xdd, 0xb6, 0xf7, 0x68, 0x83, 0xb5, 0x80, 0xef, 0x3d, 0x63, 0x4b, 0xcf, 0x9e, 0x1c, 0x17, 0x2f, + 0xb4, 0x38, 0x1c, 0x5b, 0xa9, 0x4e, 0x22, 0x8d, 0x80, 0xdc, 0x90, 0x2b, 0x7b, 0x38, 0x65, 0x65, + 0x4f, 0x8a, 0xda, 0x87, 0x71, 0x65, 0x8b, 0xf5, 0x6c, 0xfc, 0xf6, 0x18, 0xb6, 0x91, 0xbc, 0x0e, + 0x23, 0x26, 0xdd, 0x63, 0x47, 0x4d, 0x26, 0x1a, 0x24, 0x0f, 0x21, 0x6a, 0xc7, 0x70, 0x1c, 0x94, + 0x33, 0x68, 0xc3, 0xdf, 0x77, 0x76, 0x03, 0xd1, 0x3b, 0xa1, 0x9c, 0x21, 0xc0, 0x8a, 0x9c, 0x21, + 0x20, 0xfa, 0x75, 0x96, 0xc3, 0xd8, 0xee, 0x67, 0x56, 0x6a, 0xa2, 0xd3, 0x64, 0x0f, 0x9b, 0x15, + 0x65, 0x1b, 0xf1, 0x34, 0x29, 0x81, 0x61, 0x93, 0x5b, 0x30, 0x56, 0xaa, 0xd7, 0xdd, 0xae, 0x72, + 0x67, 0xe4, 0xeb, 0x96, 0x03, 0x75, 0x15, 0x49, 0x84, 0x4a, 0x6a, 0x30, 0xbe, 0xcc, 0x2e, 0x5a, + 0x4e, 0xd9, 0xae, 0xef, 0xcb, 0x4e, 0x92, 0x7b, 0x98, 0x52, 0x12, 0xad, 0x5c, 0x8a, 0xc0, 0x3a, + 0x03, 0xaa, 0x4a, 0x06, 0x05, 0x97, 0x6c, 0xc2, 0x78, 0x8d, 0xd6, 0x3d, 0x1a, 0xd4, 0x02, 0xd7, + 0xa3, 0xb1, 0x2d, 0x59, 0x29, 0x59, 0x7a, 0x41, 0xde, 0xf5, 0x7c, 0x04, 0x5a, 0x3e, 0x83, 0xaa, + 0x5c, 0x15, 0x64, 0x2e, 0xb4, 0xb7, 0x5c, 0xef, 0xa8, 0xb2, 0x24, 0xb6, 0xe9, 0xe8, 0x4c, 0xe7, + 0x60, 0x55, 0x68, 0x67, 0x90, 0xc6, 0x8e, 0x2e, 0xb4, 0x73, 0x2c, 0x1c, 0xa9, 0x4a, 0x0d, 0x65, + 0x2b, 0xb1, 0x69, 0x4f, 0x47, 0xbd, 0x8c, 0x60, 0x65, 0xa4, 0x1a, 0x3e, 0x4a, 0x66, 0xda, 0x48, + 0x09, 0x2c, 0xd2, 0x01, 0x22, 0x47, 0x8d, 0x0b, 0xba, 0x4d, 0xea, 0xfb, 0x62, 0x2f, 0xbf, 0x18, + 0x1b, 0xfc, 0x08, 0x61, 0xe9, 0x15, 0xc1, 0xfc, 0x79, 0x39, 0x0d, 0xc4, 0x3d, 0x8d, 0x15, 0x2a, + 0xf5, 0xa4, 0xf0, 0x26, 0x6f, 0x01, 0x2c, 0x3f, 0x0a, 0xa8, 0xd7, 0xb6, 0x9b, 0xa1, 0x1e, 0x0c, + 0x55, 0x3f, 0x54, 0x40, 0xf5, 0x81, 0x56, 0x90, 0x49, 0x19, 0x26, 0x4b, 0xbe, 0xdf, 0x6d, 0x51, + 0xd3, 0x6d, 0xd2, 0x92, 0xb9, 0x8e, 0xfb, 0xfe, 0xd8, 0xd2, 0xf3, 0x27, 0xc7, 0xc5, 0x8b, 0x36, + 0x16, 0x58, 0x9e, 0xdb, 0xa4, 0x96, 0xed, 0xa9, 0xb3, 0x5b, 0xa7, 0x21, 0xf7, 0x01, 0xee, 0x77, + 0x68, 0xbb, 0x46, 0x6d, 0xaf, 0xbe, 0x1f, 0xdb, 0xe6, 0xa3, 0x82, 0xa5, 0xe7, 0x44, 0x0b, 0xe7, + 0xdc, 0x0e, 0x6d, 0xfb, 0x08, 0x53, 0xbf, 0x2a, 0xc2, 0x24, 0xdb, 0x30, 0x5d, 0x2d, 0xad, 0x6d, + 0xb8, 0x4d, 0xa7, 0x7e, 0x24, 0x24, 0xa7, 0x29, 0xd4, 0x0e, 0x9e, 0x17, 0x5c, 0x63, 0xa5, 0x7c, + 0x7b, 0x72, 0xec, 0x96, 0xd5, 0x41, 0xa8, 0x25, 0xe4, 0xa7, 0x38, 0x17, 0xf2, 0x21, 0x9b, 0x83, + 0x3e, 0x13, 0x06, 0x37, 0xed, 0x3d, 0x7f, 0x7e, 0x5a, 0xd3, 0x76, 0x95, 0xb6, 0x6b, 0xd7, 0x94, + 0x52, 0x2e, 0xa6, 0x2c, 0xf0, 0x89, 0x88, 0x50, 0x2b, 0xb0, 0xf7, 0x7c, 0x7d, 0x22, 0x86, 0xd8, + 0xe4, 0x2e, 0x40, 0xc5, 0xad, 0x77, 0x5b, 0xb4, 0x1d, 0x54, 0x96, 0xe6, 0x0b, 0xfa, 0x55, 0x20, + 0x2c, 0x88, 0xb6, 0xb6, 0x86, 0x5b, 0xd7, 0x66, 0xa2, 0x42, 0xbd, 0xf0, 0x1e, 0x14, 0xe2, 0x1f, + 0x72, 0x46, 0x05, 0xd6, 0x64, 0x61, 0x4a, 0x69, 0xfd, 0xf2, 0x23, 0xc7, 0x0f, 0x7c, 0xe3, 0x1b, + 0xda, 0x0a, 0x64, 0xbb, 0xc3, 0x3d, 0x7a, 0xb4, 0xe1, 0xd1, 0x5d, 0xe7, 0x91, 0xd8, 0xcc, 0x70, + 0x77, 0x38, 0xa0, 0x47, 0x56, 0x07, 0xa1, 0xea, 0xee, 0x10, 0xa2, 0x92, 0xcf, 0x40, 0xfe, 0xde, + 0x5a, 0xed, 0x1e, 0x3d, 0xaa, 0x56, 0xc4, 0x41, 0xc5, 0xc9, 0x5a, 0xbe, 0xc5, 0x48, 0xb5, 0xb9, + 0x16, 0x62, 0x1a, 0x4b, 0xd1, 0x4e, 0xc8, 0x6a, 0x2e, 0x37, 0xbb, 0x7e, 0x40, 0xbd, 0x6a, 0x45, + 0xad, 0xb9, 0xce, 0x81, 0xb1, 0x7d, 0x29, 0x44, 0x35, 0xfe, 0x75, 0x16, 0x77, 0x41, 0x36, 0xe1, + 0xab, 0x6d, 0x3f, 0xb0, 0xdb, 0x75, 0x1a, 0x32, 0xc0, 0x09, 0xef, 0x08, 0x68, 0x6c, 0xc2, 0x47, + 0xc8, 0x7a, 0xd5, 0xd9, 0x81, 0xab, 0x66, 0x55, 0x4a, 0xcd, 0x45, 0xb5, 0xa2, 0xaa, 0x57, 0x3d, + 0x01, 0x8d, 0x55, 0x19, 0x21, 0x93, 0xcb, 0x30, 0x5a, 0x2d, 0xad, 0x95, 0xba, 0xc1, 0x3e, 0xee, + 0xc1, 0x79, 0x2e, 0x9f, 0xb3, 0xd9, 0x6a, 0x77, 0x83, 0x7d, 0x53, 0x16, 0x92, 0xeb, 0x78, 0xef, + 0x69, 0xd3, 0x80, 0xab, 0x61, 0xc5, 0xa1, 0xeb, 0x73, 0x50, 0xec, 0xda, 0xc3, 0x40, 0xe4, 0x35, + 0x18, 0x7e, 0xb0, 0x51, 0xae, 0x56, 0xc4, 0xc5, 0x19, 0x4f, 0xa2, 0x87, 0x9d, 0xba, 0xfe, 0x25, + 0x1c, 0x85, 0x2c, 0xc3, 0x54, 0x8d, 0xd6, 0xbb, 0x9e, 0x13, 0x1c, 0xdd, 0xf1, 0xdc, 0x6e, 0xc7, + 0x9f, 0x1f, 0xc5, 0x3a, 0x70, 0xa5, 0xfb, 0xa2, 0xc4, 0xda, 0xc3, 0x22, 0x85, 0x3a, 0x46, 0x64, + 0xfc, 0x4e, 0x26, 0xda, 0x26, 0xc9, 0x65, 0x4d, 0xac, 0x41, 0xdd, 0x0d, 0x13, 0x6b, 0x54, 0xdd, + 0x0d, 0x0a, 0x38, 0x26, 0x90, 0x72, 0xd7, 0x0f, 0xdc, 0xd6, 0x72, 0xbb, 0xd1, 0x71, 0x9d, 0x76, + 0x80, 0x54, 0xbc, 0xf3, 0x8d, 0x93, 0xe3, 0xe2, 0x0b, 0x75, 0x2c, 0xb5, 0xa8, 0x28, 0xb6, 0x62, + 0x5c, 0x52, 0xa8, 0x1f, 0x63, 0x3c, 0x8c, 0xdf, 0xcf, 0x6a, 0xc7, 0x1b, 0xfb, 0x3c, 0x93, 0x76, + 0x9a, 0x4e, 0x1d, 0x6f, 0xf4, 0xd8, 0xd0, 0x70, 0x56, 0xe1, 0xe7, 0x79, 0x51, 0x29, 0xef, 0x21, + 0x9d, 0x77, 0x0a, 0x35, 0xf9, 0x02, 0x4c, 0x30, 0x49, 0x43, 0xfc, 0xf4, 0xe7, 0xb3, 0xd8, 0xd9, + 0xcf, 0xa1, 0x16, 0xce, 0xa7, 0x5e, 0xc8, 0x46, 0x13, 0x51, 0x54, 0x0a, 0xd2, 0x80, 0xf9, 0x4d, + 0xcf, 0x6e, 0xfb, 0x4e, 0xb0, 0xdc, 0xae, 0x7b, 0x47, 0x28, 0x19, 0x2d, 0xb7, 0xed, 0x9d, 0x26, + 0x6d, 0x60, 0x73, 0xf3, 0x4b, 0x57, 0x4e, 0x8e, 0x8b, 0x2f, 0x07, 0x1c, 0xc7, 0xa2, 0x21, 0x92, + 0x45, 0x39, 0x96, 0xc2, 0xb9, 0x27, 0x27, 0x26, 0x49, 0xc9, 0x6e, 0xc5, 0x47, 0x18, 0x2e, 0x24, + 0xa0, 0x24, 0x15, 0x8e, 0x06, 0xdb, 0xc3, 0xd4, 0xcf, 0x54, 0x09, 0x8c, 0xff, 0x37, 0x13, 0x1d, + 0xc0, 0xe4, 0x1d, 0x18, 0x17, 0x2b, 0x46, 0x99, 0x17, 0xb8, 0x83, 0xca, 0xe5, 0x15, 0x1b, 0x59, + 0x15, 0x9d, 0xdd, 0xfb, 0x4b, 0xe5, 0x55, 0x65, 0x6e, 0xe0, 0xbd, 0xdf, 0xae, 0x37, 0xe3, 0x54, + 0x12, 0x8d, 0x4d, 0x82, 0xcd, 0xd5, 0x9a, 0xde, 0x2b, 0x38, 0x09, 0x82, 0xa6, 0x9f, 0xd2, 0x0d, + 0x0a, 0xf2, 0xe3, 0x37, 0xfc, 0x7f, 0xce, 0xa4, 0x9d, 0xf3, 0x64, 0x09, 0x26, 0xb7, 0x5d, 0xef, + 0x00, 0xc7, 0x57, 0xe9, 0x04, 0x1c, 0xf9, 0x43, 0x59, 0x10, 0x6f, 0x90, 0x4e, 0xa2, 0x7e, 0x9b, + 0xd2, 0x1b, 0xfa, 0xb7, 0xc5, 0x38, 0x68, 0x04, 0x6c, 0x1c, 0x42, 0x8e, 0xe1, 0xea, 0xc0, 0x71, + 0x88, 0x3e, 0x41, 0x9b, 0xc2, 0x2a, 0xba, 0xf1, 0x5f, 0x65, 0xd4, 0xf3, 0x9c, 0x75, 0x72, 0xc5, + 0x6d, 0xd9, 0x4e, 0x5b, 0x69, 0x0e, 0x7f, 0x58, 0x42, 0x68, 0xfc, 0x4b, 0x14, 0x64, 0x72, 0x13, + 0xf2, 0xfc, 0x57, 0xb8, 0xd7, 0xa2, 0x56, 0x4b, 0x10, 0xea, 0x07, 0x85, 0x44, 0x4c, 0x8c, 0x4c, + 0xee, 0xac, 0x23, 0xf3, 0xdb, 0x19, 0xf5, 0x28, 0xfe, 0xb8, 0x87, 0x4d, 0xec, 0x90, 0xc9, 0x9e, + 0xe5, 0x90, 0x79, 0xec, 0x26, 0x7c, 0x5f, 0x06, 0xc6, 0x15, 0x2d, 0x05, 0x6b, 0xc3, 0x86, 0xe7, + 0x7e, 0x44, 0xeb, 0x81, 0xde, 0x86, 0x0e, 0x07, 0xc6, 0xda, 0x10, 0xa2, 0x3e, 0x46, 0x1b, 0x8c, + 0x3f, 0xcb, 0x88, 0x3b, 0xd2, 0xc0, 0xdb, 0xbc, 0xbe, 0x25, 0x67, 0xcf, 0x72, 0x44, 0x7e, 0x01, + 0x86, 0x4d, 0xda, 0x70, 0x7c, 0x71, 0xbf, 0x99, 0x51, 0xef, 0x63, 0x58, 0x10, 0xc9, 0x4d, 0x1e, + 0xfb, 0xa9, 0x9e, 0x6f, 0x58, 0xce, 0x04, 0xd9, 0xaa, 0x7f, 0xbb, 0x49, 0x1f, 0x39, 0x7c, 0x31, + 0x8a, 0xa3, 0x16, 0x8f, 0x37, 0xc7, 0xb7, 0x76, 0x59, 0x89, 0x90, 0xa8, 0xd5, 0x85, 0xa7, 0xd1, + 0x18, 0x1f, 0x02, 0x44, 0x55, 0x92, 0x7b, 0x50, 0x10, 0xb3, 0xc1, 0x69, 0xef, 0x71, 0x41, 0x4a, + 0xf4, 0x41, 0xf1, 0xe4, 0xb8, 0xf8, 0x6c, 0x3d, 0x2c, 0x13, 0x52, 0xa7, 0xc2, 0x37, 0x41, 0x68, + 0xfc, 0xbd, 0x2c, 0x64, 0x4b, 0x38, 0x20, 0xf7, 0xe8, 0x51, 0x60, 0xef, 0xdc, 0x76, 0x9a, 0xda, + 0x62, 0x3a, 0x40, 0xa8, 0xb5, 0xeb, 0x68, 0xea, 0x0a, 0x05, 0x99, 0x2d, 0xa6, 0x7b, 0xde, 0xce, + 0x9b, 0x48, 0xa8, 0x2c, 0xa6, 0x03, 0x6f, 0xe7, 0xcd, 0x38, 0x59, 0x88, 0x48, 0x0c, 0x18, 0xe1, + 0x0b, 0x4b, 0xcc, 0x41, 0x38, 0x39, 0x2e, 0x8e, 0xf0, 0xf5, 0x67, 0x8a, 0x12, 0x72, 0x11, 0x72, + 0xb5, 0x8d, 0x75, 0xb1, 0x03, 0xa2, 0x5a, 0xd0, 0xef, 0xb4, 0x4d, 0x06, 0x63, 0x75, 0xae, 0x56, + 0x4a, 0x1b, 0xa8, 0x08, 0x18, 0x8e, 0xea, 0x6c, 0x36, 0xec, 0x4e, 0x5c, 0x15, 0x10, 0x22, 0x92, + 0x77, 0x61, 0xfc, 0x5e, 0xa5, 0xbc, 0xe2, 0xfa, 0x7c, 0xf7, 0x1a, 0x89, 0x26, 0xff, 0x41, 0xa3, + 0x6e, 0xa1, 0x26, 0x3e, 0x7e, 0x0c, 0x28, 0xf8, 0xc6, 0x0f, 0x67, 0x61, 0x5c, 0xd1, 0x93, 0x91, + 0xcf, 0x88, 0x07, 0xd2, 0x8c, 0x76, 0x03, 0x50, 0x30, 0x58, 0x29, 0x57, 0xaa, 0xb4, 0xdc, 0x06, + 0x15, 0xcf, 0xa5, 0x91, 0x02, 0x23, 0x3b, 0x88, 0x02, 0xe3, 0x2d, 0x00, 0x3e, 0x07, 0xf0, 0x93, + 0x15, 0x71, 0x42, 0xb1, 0x93, 0x50, 0xc7, 0x25, 0x42, 0x26, 0x0f, 0x60, 0x76, 0xd3, 0xeb, 0xfa, + 0x41, 0xed, 0xc8, 0x0f, 0x68, 0x8b, 0x71, 0xdb, 0x70, 0xdd, 0xa6, 0x98, 0x7f, 0x2f, 0x9f, 0x1c, + 0x17, 0x2f, 0xa1, 0x71, 0x87, 0xe5, 0x63, 0x39, 0x7e, 0x80, 0xd5, 0x71, 0x5d, 0x55, 0xad, 0x91, + 0xc6, 0xc0, 0x30, 0x61, 0x42, 0x55, 0x8a, 0xb0, 0x93, 0x45, 0x3c, 0x26, 0x09, 0x55, 0xb7, 0x72, + 0xb2, 0x88, 0xaf, 0x4c, 0x3e, 0x6e, 0xe9, 0x24, 0xc6, 0x67, 0x54, 0x85, 0xdc, 0xa0, 0x0b, 0xdb, + 0xf8, 0x81, 0x4c, 0xb4, 0x8d, 0x3c, 0xb8, 0x41, 0xde, 0x86, 0x11, 0xfe, 0x78, 0x27, 0xde, 0x38, + 0xcf, 0x85, 0x97, 0x5a, 0xf5, 0x65, 0x8f, 0x6b, 0xc2, 0xff, 0x90, 0x3f, 0xf0, 0x3f, 0x63, 0x0a, + 0x92, 0x50, 0x89, 0xae, 0xeb, 0xd3, 0x24, 0x77, 0x54, 0x17, 0xdf, 0x48, 0x53, 0xa2, 0x1b, 0x3f, + 0x3e, 0x0c, 0x53, 0x3a, 0x9a, 0xfa, 0xc2, 0x97, 0x19, 0xe8, 0x85, 0xef, 0x0b, 0x90, 0x67, 0xfd, + 0xe1, 0xd4, 0xa9, 0x94, 0xc8, 0x5e, 0xc6, 0xa7, 0x05, 0x01, 0xd3, 0x5e, 0xae, 0x81, 0x0f, 0x07, + 0xbb, 0xe3, 0x9a, 0x21, 0x15, 0x59, 0x54, 0x9e, 0xa1, 0x72, 0x91, 0x90, 0x22, 0x9f, 0xa1, 0xd4, + 0xf5, 0x10, 0x3e, 0x48, 0xbd, 0x01, 0x23, 0x4c, 0xbe, 0x0f, 0x55, 0x30, 0xf8, 0x95, 0x4c, 0xf4, + 0x8f, 0x99, 0xa8, 0x70, 0x24, 0xb2, 0x0d, 0xf9, 0x55, 0xdb, 0x0f, 0x6a, 0x94, 0xb6, 0x07, 0x78, + 0xbb, 0x2f, 0x8a, 0xae, 0x9a, 0xc5, 0x87, 0x71, 0x9f, 0xd2, 0x76, 0xec, 0xf1, 0x35, 0x64, 0x46, + 0xbe, 0x02, 0x50, 0x76, 0xdb, 0x81, 0xe7, 0x36, 0x57, 0xdd, 0xbd, 0xf9, 0x11, 0xbc, 0xfb, 0xbe, + 0x10, 0x1b, 0x80, 0x08, 0x81, 0x5f, 0x7f, 0x43, 0x05, 0x4f, 0x9d, 0x17, 0x58, 0x4d, 0x77, 0x4f, + 0x5d, 0x07, 0x11, 0x3e, 0xb9, 0x0d, 0x05, 0xa9, 0x58, 0xd8, 0xea, 0xec, 0x79, 0x38, 0x41, 0x46, + 0x23, 0xc9, 0x83, 0x3e, 0x0a, 0xac, 0xae, 0x80, 0xab, 0x3b, 0x65, 0x9c, 0x86, 0x7c, 0x19, 0x2e, + 0xc4, 0x61, 0x72, 0x94, 0xf3, 0x91, 0x4c, 0xae, 0xb2, 0x4b, 0x99, 0xf7, 0xbd, 0x58, 0x90, 0x3b, + 0x30, 0xcd, 0x3a, 0x64, 0x8d, 0xda, 0x7e, 0x97, 0x1b, 0x58, 0x09, 0xd5, 0xcc, 0xf3, 0x52, 0x13, + 0xc5, 0x57, 0x61, 0xd3, 0xad, 0x1f, 0x28, 0x48, 0x66, 0x9c, 0xca, 0x38, 0xce, 0xc2, 0xf9, 0x74, + 0x5c, 0xf2, 0xbd, 0x70, 0x4e, 0xf4, 0x4b, 0x93, 0x7a, 0x0a, 0xce, 0x00, 0x36, 0x01, 0x6f, 0x88, + 0xfe, 0x7e, 0xb1, 0x1e, 0x32, 0x08, 0x37, 0x0e, 0xc6, 0x22, 0x36, 0xb8, 0xe9, 0xf5, 0x90, 0xaf, + 0xc1, 0xb8, 0x5a, 0x6d, 0x76, 0x70, 0xf3, 0x8a, 0x3e, 0x75, 0xa9, 0x2c, 0x89, 0x0d, 0xd3, 0x26, + 0xfd, 0x7a, 0x97, 0xfa, 0x81, 0x34, 0xf0, 0x10, 0x47, 0xf7, 0xc5, 0x44, 0x2d, 0x12, 0x21, 0xd4, + 0xff, 0x14, 0x3c, 0x4e, 0x69, 0x49, 0x33, 0xbc, 0x6f, 0x32, 0xf6, 0x71, 0x7e, 0xc6, 0xb7, 0xb3, + 0x70, 0xa1, 0xc7, 0xb4, 0x64, 0x3b, 0x17, 0x0a, 0x56, 0xca, 0xce, 0x15, 0x93, 0xa7, 0xb8, 0x75, + 0xd8, 0x25, 0xc8, 0x0a, 0x51, 0x64, 0x68, 0xa9, 0x70, 0x72, 0x5c, 0x9c, 0xd0, 0x56, 0x5c, 0xb6, + 0x5a, 0x21, 0x77, 0x61, 0x88, 0x75, 0xc3, 0x00, 0x46, 0x0e, 0x52, 0xfb, 0x37, 0x15, 0x38, 0xea, + 0x42, 0xc7, 0xbe, 0x41, 0x1e, 0xe4, 0x33, 0x90, 0xdb, 0xdc, 0x5c, 0xc5, 0x55, 0x9e, 0xc3, 0x59, + 0x3a, 0x19, 0x04, 0x4d, 0x6d, 0x53, 0x99, 0x64, 0xb4, 0x61, 0x8f, 0x98, 0x0c, 0x9d, 0x7c, 0x31, + 0x66, 0x7c, 0xf5, 0x5a, 0xff, 0x25, 0x39, 0xb8, 0x2d, 0xd6, 0x63, 0x98, 0x40, 0x19, 0xbf, 0x90, + 0x8d, 0x76, 0xdb, 0xdb, 0x4e, 0x33, 0xa0, 0x1e, 0x59, 0xe0, 0x9b, 0x67, 0x24, 0x46, 0x9b, 0xe1, + 0x6f, 0x32, 0x1f, 0xed, 0xc4, 0x9c, 0x55, 0xb8, 0xe5, 0xbe, 0xa6, 0x6c, 0xb9, 0x39, 0xdc, 0x72, + 0xa7, 0x7a, 0x6e, 0xae, 0xaf, 0xa5, 0xec, 0x20, 0xb8, 0x65, 0xa6, 0xec, 0x12, 0x2f, 0xc3, 0xe4, + 0xba, 0xbb, 0xfc, 0x28, 0x08, 0x11, 0xd9, 0x56, 0x99, 0x37, 0x75, 0x20, 0xe3, 0x78, 0xbf, 0xd9, + 0xa0, 0xde, 0xe6, 0xbe, 0xdd, 0xd6, 0xac, 0x0c, 0xcc, 0x04, 0x9c, 0xe1, 0xae, 0xd3, 0x43, 0x1d, + 0x77, 0x94, 0xe3, 0xc6, 0xe1, 0xc6, 0xf7, 0x67, 0x65, 0x67, 0x3c, 0x58, 0x7c, 0x4a, 0x5f, 0xb3, + 0xdf, 0xd4, 0x5e, 0xb3, 0x67, 0x43, 0x3d, 0x7c, 0x68, 0x9a, 0xb1, 0x78, 0x8a, 0x45, 0xc7, 0xdf, + 0x19, 0x81, 0x09, 0x15, 0x9d, 0xf5, 0x43, 0xa9, 0xd1, 0xf0, 0xd4, 0x7e, 0xb0, 0x1b, 0x0d, 0xcf, + 0x44, 0xa8, 0x66, 0xc0, 0x91, 0xeb, 0x6b, 0xc0, 0xf1, 0x55, 0x18, 0x2b, 0xb7, 0x1a, 0xda, 0xb3, + 0xb2, 0x91, 0xf2, 0x79, 0xd7, 0x42, 0x24, 0xbe, 0x16, 0x42, 0xf5, 0x72, 0xbd, 0xd5, 0x48, 0x3e, + 0x26, 0x47, 0x2c, 0x35, 0xdb, 0x8f, 0xe1, 0xc7, 0xb1, 0xfd, 0xb8, 0x05, 0x63, 0x5b, 0x3e, 0xdd, + 0xec, 0xb6, 0xdb, 0xb4, 0x89, 0xd3, 0x2a, 0xcf, 0x6f, 0x65, 0x5d, 0x9f, 0x5a, 0x01, 0x42, 0xd5, + 0x0f, 0x08, 0x51, 0xd5, 0x01, 0x1e, 0xed, 0x33, 0xc0, 0x37, 0x21, 0xbf, 0x41, 0xa9, 0x87, 0x7d, + 0x3a, 0x1e, 0x09, 0xdf, 0x1d, 0x4a, 0x3d, 0x8b, 0x75, 0xac, 0x66, 0x13, 0x22, 0x10, 0x35, 0x43, + 0x92, 0x89, 0x01, 0x0d, 0x49, 0xc8, 0x8b, 0x30, 0xd1, 0xe9, 0xee, 0x34, 0x9d, 0x3a, 0xf2, 0x15, + 0x16, 0x28, 0xe6, 0x38, 0x87, 0x31, 0xb6, 0x3e, 0xf9, 0x22, 0x4c, 0xe2, 0x6d, 0x34, 0x9c, 0x72, + 0x53, 0xda, 0xfb, 0xab, 0x56, 0xc6, 0x65, 0xd2, 0x3a, 0x03, 0x59, 0x29, 0x86, 0x52, 0x3a, 0x23, + 0x72, 0x17, 0x46, 0xf7, 0x9c, 0xc0, 0xda, 0xef, 0xee, 0xcc, 0x4f, 0x6b, 0x56, 0x46, 0x77, 0x9c, + 0x60, 0xa5, 0xbb, 0xc3, 0x87, 0x3c, 0x64, 0x8d, 0x3b, 0xde, 0x9e, 0x13, 0xec, 0x77, 0x55, 0xe5, + 0xf9, 0xc8, 0x1e, 0xe2, 0x2e, 0xd4, 0x60, 0x4a, 0x9f, 0x15, 0x4f, 0xe0, 0x49, 0x37, 0x34, 0xb0, + 0xc9, 0x17, 0xc6, 0xee, 0x0e, 0xe5, 0xa1, 0x30, 0xce, 0x4d, 0x6b, 0x4c, 0xd8, 0x08, 0xfb, 0xc7, + 0x24, 0xf7, 0xba, 0x3b, 0xd4, 0x6b, 0xd3, 0x80, 0xfa, 0xe2, 0xea, 0xe7, 0x9b, 0x43, 0xa5, 0x4e, + 0xc7, 0x37, 0xfe, 0xd3, 0x2c, 0x8c, 0x96, 0xb6, 0x6b, 0xd5, 0xf6, 0xae, 0x8b, 0x0f, 0xb3, 0xe1, + 0x7b, 0x9c, 0xfa, 0x30, 0x1b, 0xbe, 0xc7, 0xa9, 0xaf, 0x70, 0xd7, 0x53, 0x2e, 0xef, 0x68, 0xbb, + 0xad, 0x5c, 0xde, 0x35, 0xb5, 0x43, 0xf4, 0x34, 0x99, 0x1b, 0xe0, 0x69, 0x32, 0xd4, 0x1e, 0x0f, + 0x9d, 0xae, 0x3d, 0x7e, 0x1b, 0xc6, 0xab, 0xed, 0x80, 0xee, 0x79, 0xd1, 0xaa, 0x09, 0x15, 0x09, + 0x21, 0x58, 0xbd, 0xd0, 0x29, 0xd8, 0x6c, 0x4a, 0x72, 0x8d, 0x75, 0xa8, 0xa9, 0xc6, 0x29, 0xc9, + 0x15, 0xdb, 0x31, 0x2d, 0x90, 0x44, 0x34, 0x2a, 0xb1, 0xf9, 0x26, 0xcd, 0x3f, 0xb8, 0x08, 0x35, + 0x15, 0x3d, 0xd9, 0xb0, 0x8e, 0x5d, 0x9a, 0x49, 0x37, 0xff, 0x30, 0xfe, 0x46, 0x06, 0xe6, 0xd2, + 0xa6, 0x11, 0x79, 0x0f, 0x26, 0x5c, 0x6f, 0xcf, 0x6e, 0x3b, 0xdf, 0xcd, 0x5b, 0xa4, 0xa8, 0x2a, + 0x55, 0xb8, 0xaa, 0xa0, 0x51, 0xe1, 0xac, 0x43, 0x94, 0x96, 0xeb, 0x9a, 0x95, 0xd4, 0x0e, 0x51, + 0xc0, 0xc6, 0x8f, 0x64, 0x61, 0xbc, 0xd4, 0xe9, 0x3c, 0xe5, 0xa6, 0x81, 0x9f, 0xd3, 0x0e, 0x10, + 0x79, 0x2f, 0x0f, 0xdb, 0x35, 0x90, 0x55, 0xe0, 0xaf, 0x65, 0x61, 0x3a, 0x46, 0xa1, 0x7e, 0x7d, + 0x66, 0x40, 0x83, 0xc0, 0xec, 0x80, 0x06, 0x81, 0xb9, 0xc1, 0x0c, 0x02, 0x87, 0x1e, 0xe7, 0x50, + 0x78, 0x15, 0x72, 0xa5, 0x4e, 0x27, 0x6e, 0x58, 0xd0, 0xe9, 0x3c, 0xb8, 0xc9, 0x75, 0x2b, 0x76, + 0xa7, 0x63, 0x32, 0x0c, 0x6d, 0xa7, 0x1e, 0x19, 0x70, 0xa7, 0x36, 0xde, 0x80, 0x31, 0xe4, 0x85, + 0x66, 0x78, 0x97, 0x00, 0xb7, 0x18, 0x61, 0x81, 0xa7, 0xd5, 0x25, 0x36, 0x9f, 0xff, 0x3f, 0x03, + 0xc3, 0xf8, 0xfb, 0x29, 0x9d, 0x63, 0x8b, 0xda, 0x1c, 0x2b, 0x28, 0x73, 0x6c, 0x90, 0xd9, 0xf5, + 0xf7, 0x73, 0x00, 0xe5, 0xfb, 0x66, 0x8d, 0xab, 0xe0, 0xc8, 0x6d, 0x98, 0xb6, 0x9b, 0x4d, 0xf7, + 0x90, 0x36, 0x2c, 0xd7, 0x73, 0xf6, 0x9c, 0x36, 0xef, 0x39, 0xf9, 0xda, 0xad, 0x17, 0xa9, 0x6f, + 0x60, 0xa2, 0xe8, 0x3e, 0x2f, 0x51, 0xf9, 0xb4, 0x68, 0xb0, 0xef, 0x36, 0xa4, 0x32, 0x41, 0xe3, + 0x23, 0x8a, 0x52, 0xf8, 0xac, 0xf1, 0x12, 0x95, 0xcf, 0x3e, 0x2a, 0x47, 0xa4, 0x84, 0xac, 0xf1, + 0x11, 0x45, 0x29, 0x7c, 0xb8, 0x46, 0xc5, 0x27, 0xab, 0x30, 0x83, 0x10, 0xab, 0xee, 0xd1, 0x06, + 0x6d, 0x07, 0x8e, 0xdd, 0xf4, 0x85, 0xfa, 0x09, 0x15, 0x95, 0x89, 0x42, 0xf5, 0xfa, 0x8d, 0x85, + 0xe5, 0xa8, 0x8c, 0x5c, 0x83, 0xd1, 0x96, 0xfd, 0xc8, 0xb2, 0xf7, 0xb8, 0xdd, 0xc7, 0x24, 0x57, + 0x57, 0x08, 0x90, 0x7a, 0x8c, 0xb4, 0xec, 0x47, 0xa5, 0x3d, 0xca, 0x5a, 0x41, 0x1f, 0x75, 0x5c, + 0x5f, 0x69, 0xc5, 0x48, 0xd4, 0x8a, 0x58, 0x91, 0xda, 0x0a, 0x51, 0x24, 0x5a, 0x61, 0xfc, 0x6a, + 0x06, 0x9e, 0xad, 0xe2, 0x57, 0x04, 0x47, 0x65, 0xda, 0x0e, 0xa8, 0xb7, 0x41, 0xbd, 0x96, 0x83, + 0xaf, 0xe0, 0x35, 0x1a, 0x90, 0x97, 0x20, 0x57, 0x32, 0xd7, 0xc5, 0xfc, 0xe5, 0xfb, 0xbd, 0x66, + 0x93, 0xc0, 0x4a, 0x43, 0x8d, 0x56, 0xf6, 0x14, 0x55, 0x75, 0x09, 0x26, 0x4a, 0xbe, 0xef, 0xec, + 0xb5, 0x5b, 0xdc, 0x9f, 0x22, 0xa7, 0x59, 0x3d, 0x08, 0x78, 0xe2, 0x8d, 0x45, 0x25, 0x31, 0xfe, + 0xb3, 0x0c, 0xcc, 0x94, 0x3a, 0x1d, 0xfd, 0x93, 0x75, 0x8b, 0x9b, 0xcc, 0xe0, 0x16, 0x37, 0x0e, + 0x4c, 0x69, 0xcd, 0xe5, 0x53, 0x2a, 0x12, 0x7c, 0xfb, 0xf4, 0x0c, 0xff, 0xec, 0x4e, 0x08, 0xb2, + 0x7c, 0xfd, 0xb9, 0x38, 0xc6, 0xd8, 0xf8, 0x0f, 0x46, 0x71, 0x0f, 0x11, 0xbb, 0xad, 0xb0, 0x09, + 0xcd, 0xa4, 0xd8, 0x84, 0xbe, 0x05, 0x8a, 0x84, 0xa3, 0x1e, 0x71, 0x8a, 0xac, 0xa8, 0xea, 0x82, + 0x22, 0x64, 0x72, 0x10, 0xb7, 0x0e, 0xcd, 0x61, 0x6b, 0x5e, 0x8a, 0x2f, 0xe0, 0x27, 0x62, 0x18, + 0xba, 0x02, 0xa4, 0xda, 0xc6, 0x27, 0x6c, 0x5a, 0x3b, 0x70, 0x3a, 0x0f, 0xa8, 0xe7, 0xec, 0x1e, + 0x89, 0x05, 0x80, 0x9d, 0xef, 0x88, 0x52, 0xcb, 0x3f, 0x70, 0x3a, 0xd6, 0x43, 0x2c, 0x37, 0x53, + 0x68, 0xc8, 0xfb, 0x30, 0x6a, 0xd2, 0x43, 0xcf, 0x09, 0xa4, 0xcd, 0xd3, 0x54, 0xa8, 0xda, 0x44, + 0x28, 0x5f, 0x0b, 0x1e, 0xff, 0xa1, 0xee, 0x8a, 0xa2, 0x9c, 0x2c, 0x72, 0x21, 0x85, 0xdb, 0x36, + 0x4d, 0x46, 0xad, 0x2d, 0x6d, 0xd7, 0x7a, 0xc9, 0x28, 0xe4, 0x2a, 0x0c, 0xa3, 0xa4, 0x23, 0xee, + 0x02, 0xe8, 0x2b, 0x84, 0xb2, 0xb3, 0x2a, 0x86, 0x21, 0x06, 0x79, 0x01, 0x20, 0x7c, 0x23, 0xf6, + 0xe7, 0xf3, 0x28, 0xa5, 0x2b, 0x90, 0xb8, 0x98, 0x36, 0x76, 0x26, 0x31, 0x6d, 0x15, 0x0a, 0x26, + 0x77, 0x3b, 0x6c, 0x94, 0x3a, 0xf8, 0x10, 0xe9, 0xcf, 0x03, 0xae, 0xe4, 0x4b, 0x27, 0xc7, 0xc5, + 0xe7, 0x84, 0x4b, 0x62, 0xc3, 0xb2, 0x3b, 0xfc, 0xfd, 0x52, 0xdb, 0x46, 0xe2, 0x94, 0xe4, 0x2d, + 0x18, 0x62, 0x5b, 0xaf, 0xb0, 0x23, 0x95, 0x0f, 0x3a, 0xd1, 0x6e, 0xcc, 0x17, 0x67, 0xdd, 0xd5, + 0xf6, 0x04, 0x24, 0x21, 0x16, 0x4c, 0xe9, 0xd3, 0x5d, 0x98, 0x14, 0xcd, 0x47, 0xfd, 0xa9, 0x97, + 0x8b, 0x57, 0x1e, 0x01, 0xb3, 0xea, 0x08, 0x54, 0x57, 0x40, 0x6c, 0x91, 0x2e, 0x43, 0x7e, 0xb3, + 0xbc, 0xb1, 0xe1, 0x7a, 0x01, 0xbf, 0xea, 0x44, 0x27, 0x0b, 0x83, 0x99, 0x76, 0x7b, 0x8f, 0xf2, + 0xb3, 0x38, 0xa8, 0x77, 0xac, 0x0e, 0x43, 0x53, 0xcf, 0x62, 0x49, 0xfa, 0xc9, 0xd9, 0x90, 0xfe, + 0x5a, 0x16, 0x5e, 0x0a, 0xa5, 0xa2, 0xfb, 0x5e, 0xad, 0xb4, 0xb6, 0x5a, 0x6d, 0x6c, 0x08, 0x35, + 0xc9, 0x86, 0xe7, 0x3e, 0x74, 0x1a, 0xd4, 0x7b, 0x70, 0xe3, 0x94, 0x33, 0x7d, 0x95, 0x2f, 0x73, + 0xfe, 0x1a, 0x96, 0xd5, 0xac, 0xed, 0x14, 0xe1, 0x53, 0x6c, 0x4f, 0x9d, 0x4e, 0xe2, 0x71, 0x6c, + 0xe5, 0x19, 0x33, 0x62, 0x40, 0x7e, 0x20, 0x03, 0xe7, 0xd3, 0x3f, 0x44, 0xa8, 0xce, 0x8a, 0xf2, + 0x8a, 0xde, 0xe3, 0x6b, 0x97, 0x5e, 0x3d, 0x39, 0x2e, 0xbe, 0xe4, 0xdb, 0xad, 0xa6, 0xe5, 0x34, + 0x78, 0x6d, 0x4e, 0x9d, 0x5a, 0x1d, 0x81, 0xa0, 0xd5, 0xdb, 0xa3, 0xa6, 0xcf, 0x83, 0x3c, 0xda, + 0xe7, 0x33, 0x4b, 0x00, 0x79, 0xf9, 0xe0, 0x60, 0xfc, 0x66, 0x06, 0x94, 0x25, 0x98, 0x37, 0x69, + 0xc3, 0xf1, 0x68, 0x3d, 0x10, 0xc7, 0xbb, 0xf0, 0x15, 0xe4, 0xb0, 0x98, 0x71, 0x25, 0xc2, 0xc8, + 0x7b, 0x30, 0x2a, 0x8e, 0x21, 0xb1, 0xed, 0xca, 0xa5, 0x2b, 0x9e, 0x32, 0xb8, 0x53, 0x69, 0xe2, + 0x08, 0x93, 0x44, 0x6c, 0xd7, 0xbf, 0xbb, 0xbd, 0x59, 0x6e, 0xda, 0x4e, 0xcb, 0x17, 0x67, 0x09, + 0x76, 0xeb, 0x47, 0x87, 0x81, 0x55, 0x47, 0xa8, 0xba, 0xeb, 0x87, 0xa8, 0xc6, 0x1d, 0xf9, 0x92, + 0x72, 0x8a, 0x85, 0x70, 0x11, 0x86, 0x1f, 0x44, 0x7a, 0xba, 0xa5, 0xb1, 0x93, 0xe3, 0x22, 0x9f, + 0x2e, 0x26, 0x87, 0x1b, 0x14, 0xc6, 0xc2, 0xa9, 0xcb, 0x78, 0xb1, 0x1f, 0xc8, 0x6b, 0x92, 0xf3, + 0x62, 0x93, 0xd8, 0x44, 0x28, 0x13, 0xf5, 0x96, 0xdb, 0x0d, 0x44, 0xc8, 0x22, 0x02, 0x76, 0x0f, + 0x6d, 0x37, 0x70, 0xa6, 0xab, 0xad, 0x13, 0x68, 0x8a, 0x40, 0xf5, 0x63, 0x19, 0x98, 0xd2, 0xa7, + 0x2d, 0xb9, 0x06, 0x23, 0xc2, 0x1d, 0x30, 0x83, 0x6a, 0x4f, 0xc6, 0x6d, 0x84, 0x3b, 0x02, 0x6a, + 0xee, 0x7f, 0x02, 0x8b, 0xc9, 0x8d, 0x82, 0x83, 0x10, 0x9a, 0x50, 0x6e, 0xac, 0x73, 0x90, 0x29, + 0xcb, 0x88, 0xc1, 0xae, 0xb2, 0x7e, 0xb7, 0x19, 0xa8, 0xef, 0x96, 0x1e, 0x42, 0x4c, 0x51, 0x62, + 0x94, 0x61, 0x84, 0x6f, 0xad, 0x31, 0x03, 0xc8, 0xcc, 0x19, 0x0c, 0x20, 0x8d, 0xe3, 0x0c, 0x40, + 0xad, 0xb6, 0x72, 0x8f, 0x1e, 0x6d, 0xd8, 0x0e, 0x9e, 0xdf, 0xfc, 0x18, 0xbb, 0x27, 0xd6, 0xf0, + 0x84, 0x78, 0x68, 0xe7, 0x47, 0xde, 0x01, 0x3d, 0xd2, 0x1e, 0xda, 0x25, 0x2a, 0x9e, 0x95, 0x9e, + 0xf3, 0xd0, 0x0e, 0x28, 0x23, 0xcc, 0x22, 0x21, 0x3f, 0x2b, 0x39, 0x34, 0x46, 0xa9, 0x20, 0x93, + 0xaf, 0xc0, 0x54, 0xf4, 0x2b, 0x34, 0x17, 0x98, 0x0a, 0xf7, 0x09, 0xbd, 0x70, 0xe9, 0x85, 0x93, + 0xe3, 0xe2, 0x82, 0xc2, 0x35, 0x6e, 0x48, 0x10, 0x63, 0x66, 0xfc, 0x72, 0x06, 0x8d, 0x64, 0x64, + 0x03, 0x2f, 0xc3, 0x50, 0x68, 0xd6, 0x3d, 0x21, 0x36, 0x61, 0xfd, 0x49, 0x14, 0xcb, 0x99, 0xb8, + 0x15, 0xb5, 0x04, 0x8f, 0x2e, 0xbd, 0x05, 0xac, 0x94, 0xdc, 0x81, 0xd1, 0x81, 0xbe, 0x19, 0xa7, + 0x58, 0xca, 0xb7, 0x4a, 0x6a, 0x1c, 0x85, 0xbb, 0xdb, 0x9b, 0xdf, 0xb9, 0xa3, 0xf0, 0x93, 0x59, + 0x98, 0x66, 0xfd, 0x5a, 0xea, 0x06, 0xfb, 0xae, 0xe7, 0x04, 0x47, 0x4f, 0xad, 0xde, 0xf8, 0x1d, + 0xed, 0x4a, 0xb6, 0x20, 0x0f, 0x33, 0xb5, 0x6d, 0x03, 0xa9, 0x8f, 0xff, 0xe9, 0x30, 0xcc, 0xa6, + 0x50, 0x91, 0xd7, 0xb5, 0xa7, 0x9d, 0x79, 0xe9, 0xee, 0xff, 0xed, 0xe3, 0xe2, 0x84, 0x44, 0xdf, + 0x8c, 0xdc, 0xff, 0x17, 0x75, 0x8b, 0x33, 0xde, 0x53, 0xf8, 0xd2, 0xa3, 0x5a, 0x9c, 0xe9, 0x76, + 0x66, 0x57, 0x61, 0xd8, 0x74, 0x9b, 0x54, 0x5a, 0x59, 0xa2, 0xc0, 0xe5, 0x31, 0x80, 0x66, 0x55, + 0xc2, 0x00, 0x64, 0x05, 0x46, 0xd9, 0x1f, 0x6b, 0x76, 0x47, 0xbc, 0x97, 0x92, 0x50, 0x29, 0x80, + 0xd0, 0x8e, 0xd3, 0xde, 0x53, 0xf5, 0x02, 0x4d, 0x6a, 0xb5, 0xec, 0x8e, 0x26, 0x19, 0x72, 0x44, + 0x4d, 0xbf, 0x90, 0xef, 0xad, 0x5f, 0xc8, 0x9c, 0xaa, 0x5f, 0xd8, 0x05, 0xa8, 0x39, 0x7b, 0x6d, + 0xa7, 0xbd, 0x57, 0x6a, 0xee, 0x89, 0xa0, 0x09, 0x57, 0x7b, 0x8f, 0xc2, 0xb5, 0x08, 0x19, 0x27, + 0xee, 0xb3, 0x68, 0xd4, 0xc0, 0x61, 0x96, 0xdd, 0xdc, 0xd3, 0x9c, 0xbb, 0x14, 0xce, 0x64, 0x1d, + 0xa0, 0x54, 0x0f, 0x9c, 0x87, 0x6c, 0x0a, 0xfb, 0x42, 0x8c, 0x93, 0x9f, 0x5c, 0x2e, 0xdd, 0xa3, + 0x47, 0x78, 0xf5, 0x90, 0xcf, 0xc3, 0x36, 0xa2, 0xb2, 0x95, 0xa0, 0x79, 0xee, 0x44, 0x1c, 0x48, + 0x07, 0xce, 0x95, 0x1a, 0x0d, 0x87, 0xb5, 0xc1, 0x6e, 0x6e, 0xf2, 0x70, 0x17, 0xc8, 0x7a, 0x22, + 0x9d, 0xf5, 0x55, 0xf9, 0x12, 0x6a, 0x87, 0x54, 0x96, 0x8c, 0x92, 0x11, 0xab, 0x26, 0x9d, 0xb1, + 0x51, 0x83, 0x29, 0xbd, 0xf1, 0x7a, 0xb0, 0x87, 0x09, 0xc8, 0x9b, 0xb5, 0x92, 0x55, 0x5b, 0x29, + 0xdd, 0x28, 0x64, 0x48, 0x01, 0x26, 0xc4, 0xaf, 0x45, 0x6b, 0xf1, 0xcd, 0x5b, 0x85, 0xac, 0x06, + 0x79, 0xf3, 0xc6, 0x62, 0x21, 0xb7, 0x90, 0x9d, 0xcf, 0xc4, 0xfc, 0x2c, 0x47, 0x0b, 0x79, 0xae, + 0x12, 0x36, 0x7e, 0x3d, 0x03, 0x79, 0xf9, 0xed, 0xe4, 0x16, 0xe4, 0x6a, 0xb5, 0x95, 0x98, 0x67, + 0x64, 0x74, 0xca, 0xf0, 0xfd, 0xd4, 0xf7, 0x55, 0xf3, 0x77, 0x46, 0xc0, 0xe8, 0x36, 0x57, 0x6b, + 0x42, 0x06, 0x91, 0x74, 0xd1, 0xe6, 0xcd, 0xe9, 0x52, 0xdc, 0xc5, 0x6e, 0x41, 0xee, 0xee, 0xf6, + 0xa6, 0xb8, 0x64, 0x49, 0xba, 0x68, 0x3f, 0xe5, 0x74, 0x1f, 0x1d, 0xaa, 0xbb, 0x3c, 0x23, 0x30, + 0x4c, 0x18, 0x57, 0x26, 0x32, 0x3f, 0x74, 0x5b, 0x6e, 0x18, 0xe1, 0x40, 0x1c, 0xba, 0x0c, 0x62, + 0x8a, 0x12, 0x26, 0x8a, 0xac, 0xba, 0x75, 0xbb, 0x29, 0x4e, 0x6f, 0x14, 0x45, 0x9a, 0x0c, 0x60, + 0x72, 0xb8, 0xf1, 0x3b, 0x19, 0x28, 0xa0, 0xc0, 0x86, 0xe6, 0xeb, 0xee, 0x01, 0x6d, 0x3f, 0xb8, + 0x41, 0xde, 0x90, 0x4b, 0x2e, 0x13, 0x2a, 0xba, 0x86, 0x71, 0xc9, 0xc5, 0xde, 0x02, 0xc5, 0xb2, + 0x53, 0x82, 0x48, 0x64, 0x07, 0x77, 0x3e, 0x3f, 0x25, 0x88, 0x44, 0x11, 0x86, 0xf1, 0x73, 0xc4, + 0xe6, 0x88, 0x5f, 0x1e, 0x30, 0x80, 0xc9, 0xe1, 0xca, 0xde, 0xf4, 0xd3, 0xd9, 0x44, 0x1b, 0x16, + 0xbf, 0xa3, 0x1c, 0xb8, 0xf5, 0xc6, 0x0d, 0xb4, 0x5f, 0x7f, 0x08, 0x73, 0xf1, 0x2e, 0x41, 0x25, + 0x64, 0x09, 0xa6, 0x75, 0xb8, 0xd4, 0x47, 0x5e, 0x48, 0xad, 0xeb, 0xc1, 0xa2, 0x19, 0xc7, 0x37, + 0xfe, 0x8f, 0x0c, 0x8c, 0xe1, 0x9f, 0x66, 0xb7, 0x89, 0x66, 0x84, 0xa5, 0xed, 0x9a, 0x50, 0x8d, + 0xa8, 0xc2, 0x9c, 0x7d, 0xe8, 0x5b, 0x42, 0x8f, 0xa2, 0xed, 0x31, 0x21, 0xb2, 0x20, 0xe5, 0xef, + 0x1b, 0x52, 0x29, 0x17, 0x92, 0xf2, 0x87, 0x10, 0x3f, 0x46, 0x2a, 0x90, 0xd1, 0xf8, 0x78, 0xbb, + 0xc6, 0xa6, 0x9f, 0x6a, 0xd7, 0x83, 0x74, 0x6e, 0x53, 0x37, 0x3e, 0xe6, 0x68, 0x68, 0xd6, 0xb3, + 0x5d, 0x2b, 0x99, 0xeb, 0x9a, 0x59, 0x0f, 0xfb, 0x46, 0x4d, 0x2f, 0x25, 0x90, 0x8c, 0x5f, 0x18, + 0x8f, 0x77, 0xa0, 0x38, 0xf0, 0xce, 0xb8, 0x36, 0xde, 0x86, 0xe1, 0x52, 0xb3, 0xe9, 0x1e, 0x8a, + 0x5d, 0x42, 0xde, 0x5c, 0xc3, 0xfe, 0xe3, 0xe7, 0x19, 0xaa, 0xf5, 0x34, 0xa7, 0x54, 0x06, 0x20, + 0x65, 0x18, 0x2b, 0x6d, 0xd7, 0xaa, 0xd5, 0xca, 0xe6, 0x26, 0x77, 0xc0, 0xcb, 0x2d, 0xbd, 0x22, + 0xfb, 0xc7, 0x71, 0x1a, 0x56, 0xdc, 0x5e, 0x21, 0x92, 0xdf, 0x23, 0x3a, 0xf2, 0x2e, 0xc0, 0x5d, + 0xd7, 0x69, 0x73, 0x35, 0xa6, 0x68, 0x3c, 0xbb, 0x81, 0x8f, 0x7f, 0xe4, 0x3a, 0x6d, 0xa1, 0xf7, + 0x64, 0xdf, 0x1e, 0x21, 0x99, 0xca, 0xdf, 0xac, 0xa7, 0x97, 0x5c, 0x6e, 0x1a, 0x38, 0x1c, 0xf5, + 0xf4, 0x8e, 0x9b, 0xd0, 0xb7, 0x49, 0x34, 0xd2, 0x82, 0xe9, 0x5a, 0x77, 0x6f, 0x8f, 0xb2, 0x9d, + 0x5d, 0xe8, 0x93, 0x46, 0xc4, 0x55, 0x3a, 0x0c, 0x7b, 0xc4, 0xef, 0x23, 0xec, 0x32, 0xe4, 0x2f, + 0xbd, 0xce, 0x26, 0xf2, 0xb7, 0x8e, 0x8b, 0xc2, 0x0e, 0x82, 0x89, 0x6a, 0xbe, 0xa4, 0x4f, 0x6a, + 0x93, 0xe2, 0xbc, 0xc9, 0x7d, 0x18, 0xe1, 0x6f, 0x46, 0xc2, 0xa1, 0xec, 0xc5, 0x3e, 0x8b, 0x86, + 0x23, 0xf6, 0x7a, 0x95, 0xe4, 0xa5, 0x64, 0x1b, 0xf2, 0x65, 0xc7, 0xab, 0x37, 0x69, 0xb9, 0x2a, + 0xce, 0xfe, 0x97, 0xfa, 0xb0, 0x94, 0xa8, 0xbc, 0x5f, 0xea, 0xf8, 0xab, 0xee, 0xa8, 0xb2, 0x80, + 0xc4, 0x20, 0x7f, 0x23, 0x03, 0xcf, 0x86, 0x5f, 0x5f, 0xda, 0xa3, 0xed, 0x60, 0xcd, 0x0e, 0xea, + 0xfb, 0xd4, 0x13, 0xbd, 0x34, 0xd6, 0xaf, 0x97, 0x3e, 0x9f, 0xe8, 0xa5, 0x2b, 0x51, 0x2f, 0xd9, + 0x8c, 0x99, 0xd5, 0xe2, 0xdc, 0x92, 0x7d, 0xd6, 0xaf, 0x56, 0x62, 0x01, 0x44, 0xaf, 0xa1, 0xc2, + 0x21, 0xf9, 0x95, 0x3e, 0x0d, 0x8e, 0x90, 0x85, 0x23, 0x51, 0xf8, 0x5b, 0xb3, 0x84, 0x0d, 0xa1, + 0xe4, 0x9e, 0xf4, 0xde, 0xe4, 0x52, 0xc9, 0xa5, 0x3e, 0xbc, 0xb9, 0x47, 0xe7, 0x6c, 0x1f, 0x3f, + 0x6d, 0x3e, 0xda, 0xab, 0xf6, 0x8e, 0x10, 0x44, 0x4e, 0x19, 0xed, 0x55, 0x3b, 0x1a, 0xed, 0xa6, + 0x1d, 0x1f, 0xed, 0x55, 0x7b, 0x87, 0x94, 0xb9, 0xcb, 0x39, 0xf7, 0x4f, 0x7e, 0xa1, 0x1f, 0xb7, + 0xf2, 0x06, 0x3f, 0x99, 0x53, 0x5c, 0xcf, 0xbf, 0x04, 0x63, 0xb5, 0x8e, 0x5d, 0xa7, 0x4d, 0x67, + 0x37, 0x10, 0x4f, 0xed, 0x2f, 0xf7, 0x61, 0x15, 0xe2, 0x8a, 0xa7, 0x55, 0xf9, 0x53, 0xbd, 0x26, + 0x85, 0x38, 0xec, 0x0b, 0x37, 0x37, 0xd6, 0xc4, 0x6b, 0x7b, 0xbf, 0x2f, 0xdc, 0xdc, 0x58, 0x13, + 0x32, 0x47, 0xa7, 0xa5, 0xc9, 0x1c, 0x1b, 0x6b, 0xa4, 0x03, 0x53, 0x9b, 0xd4, 0xf3, 0xec, 0x5d, + 0xd7, 0x6b, 0x71, 0xfd, 0x25, 0xf7, 0x79, 0xbb, 0xda, 0x8f, 0x9f, 0x46, 0xc0, 0xd5, 0x76, 0x81, + 0x84, 0x59, 0x71, 0xa5, 0x67, 0x8c, 0x3f, 0xeb, 0x93, 0x25, 0x27, 0xd8, 0xe9, 0xd6, 0x0f, 0x68, + 0x30, 0x3f, 0x73, 0x6a, 0x9f, 0x84, 0xb8, 0xbc, 0x4f, 0x76, 0xe4, 0x4f, 0xb5, 0x4f, 0x42, 0x1c, + 0xe3, 0x1f, 0xe5, 0xe0, 0x42, 0x8f, 0x2e, 0x20, 0xeb, 0x72, 0xcb, 0xcd, 0x68, 0x5a, 0xec, 0x1e, + 0xe8, 0xd7, 0x4e, 0xdd, 0x85, 0x57, 0xa1, 0xb0, 0x7c, 0x0f, 0x65, 0x75, 0xfe, 0x90, 0x53, 0x2e, + 0xc9, 0xc3, 0x0a, 0x35, 0xad, 0xf4, 0x00, 0x6d, 0x84, 0xe5, 0x03, 0x50, 0x5d, 0x73, 0x86, 0x4f, + 0x50, 0x2e, 0x7c, 0x7f, 0x16, 0x86, 0xf0, 0xe0, 0x8c, 0x85, 0x00, 0xcb, 0x9c, 0x29, 0x04, 0xd8, + 0x17, 0x60, 0x62, 0xf9, 0x1e, 0xbf, 0x49, 0xaf, 0xd8, 0xfe, 0xbe, 0xd8, 0xd6, 0xd1, 0x90, 0x83, + 0x1e, 0x58, 0xe2, 0xe2, 0xbd, 0x6f, 0x6b, 0x32, 0xab, 0x46, 0x41, 0xb6, 0x60, 0x96, 0x7f, 0x9b, + 0xb3, 0xeb, 0xd4, 0x79, 0x24, 0x21, 0xc7, 0x6e, 0x8a, 0x3d, 0xfe, 0xa5, 0x93, 0xe3, 0x62, 0x91, + 0x1e, 0xa0, 0xf5, 0xb3, 0x28, 0xb7, 0x7c, 0x44, 0x50, 0xcd, 0xa0, 0x53, 0xe8, 0xd5, 0xf0, 0x26, + 0xe6, 0x18, 0x56, 0xc8, 0x6a, 0x63, 0x75, 0x33, 0x5c, 0x8e, 0x64, 0xfc, 0xe9, 0x30, 0x2c, 0xf4, + 0xde, 0x9e, 0xc9, 0x07, 0xfa, 0x00, 0x5e, 0x3e, 0x75, 0x43, 0x3f, 0x7d, 0x0c, 0xbf, 0x08, 0x73, + 0xcb, 0xed, 0x80, 0x7a, 0x1d, 0xcf, 0x91, 0x01, 0x6d, 0x56, 0x5c, 0x5f, 0x5a, 0x9b, 0xa3, 0xd9, + 0x37, 0x0d, 0xcb, 0x85, 0x6e, 0x15, 0x6d, 0xdf, 0x15, 0x56, 0xa9, 0x1c, 0xc8, 0x32, 0x4c, 0x29, + 0xf0, 0x66, 0x77, 0x4f, 0x7d, 0x9d, 0x52, 0x79, 0x36, 0xbb, 0xaa, 0x29, 0x6e, 0x8c, 0x08, 0x2d, + 0xda, 0xd9, 0x95, 0xb1, 0x7e, 0x77, 0xfb, 0x5e, 0x4d, 0x0c, 0x27, 0xb7, 0x68, 0x47, 0xa8, 0xf5, + 0xd1, 0xe1, 0x81, 0xb6, 0xbf, 0x46, 0xc8, 0x0b, 0xbf, 0x9c, 0x13, 0x33, 0xea, 0x25, 0xc8, 0xd5, + 0xba, 0x3b, 0xea, 0x9b, 0x9b, 0xaf, 0x1d, 0x70, 0xac, 0x94, 0x7c, 0x0e, 0xc0, 0xa4, 0x1d, 0xd7, + 0x77, 0x02, 0xd7, 0x3b, 0x52, 0x5d, 0x2a, 0xbd, 0x10, 0xaa, 0x7b, 0x7d, 0x48, 0x28, 0x59, 0x81, + 0xe9, 0xe8, 0xd7, 0xfd, 0xc3, 0xb6, 0xd0, 0x25, 0x8f, 0x71, 0xed, 0x4a, 0x44, 0x6e, 0xb9, 0xac, + 0x4c, 0x3d, 0xb2, 0x63, 0x64, 0x64, 0x11, 0xf2, 0xdb, 0xae, 0x77, 0xb0, 0xcb, 0xc6, 0x78, 0x28, + 0x12, 0x2a, 0x0e, 0x05, 0x4c, 0x3d, 0x3c, 0x25, 0x1e, 0x5b, 0x2e, 0xcb, 0xed, 0x87, 0x8e, 0xe7, + 0xe2, 0x8b, 0x9e, 0x6a, 0xd3, 0x42, 0x23, 0xb0, 0xe6, 0xcc, 0x1e, 0x81, 0xc9, 0x55, 0x18, 0x2e, + 0xd5, 0x03, 0xd7, 0x13, 0x06, 0x2d, 0x7c, 0xa6, 0x30, 0x80, 0x36, 0x53, 0x18, 0x80, 0x75, 0xa2, + 0x49, 0x77, 0xc5, 0xeb, 0x0e, 0x76, 0xa2, 0x47, 0x77, 0x35, 0x4f, 0x7d, 0xba, 0xcb, 0x84, 0x22, + 0x93, 0xee, 0xa2, 0xe2, 0x43, 0x0b, 0x70, 0xb7, 0x9b, 0x50, 0x99, 0x09, 0x34, 0xe3, 0xf7, 0xc6, + 0x7a, 0x4e, 0x79, 0x76, 0x0a, 0x9d, 0x6d, 0xca, 0xaf, 0xda, 0x03, 0x4c, 0xf9, 0xd7, 0x43, 0x5f, + 0x12, 0x35, 0x3c, 0x05, 0x42, 0xd4, 0x63, 0x90, 0xe3, 0x2c, 0xfc, 0x4a, 0xfe, 0x2c, 0x93, 0x48, + 0x74, 0x52, 0x76, 0xd0, 0x4e, 0xca, 0x0d, 0xd4, 0x49, 0x64, 0x09, 0x26, 0xc3, 0x10, 0x89, 0x1b, + 0x76, 0xa0, 0x6d, 0x6b, 0x61, 0x5c, 0x4b, 0xab, 0x63, 0x07, 0xea, 0xb6, 0xa6, 0x93, 0x90, 0x77, + 0x60, 0x5c, 0x38, 0x54, 0x21, 0x87, 0xe1, 0xc8, 0x52, 0x48, 0x7a, 0x5f, 0xc5, 0xe8, 0x55, 0x74, + 0xb6, 0x9a, 0x37, 0x9c, 0x0e, 0x6d, 0x3a, 0x6d, 0x5a, 0xc3, 0xc7, 0x0a, 0x31, 0x63, 0xf8, 0xa3, + 0xad, 0x28, 0xb1, 0xf8, 0x3b, 0x86, 0xa6, 0x3f, 0xd4, 0x88, 0xe2, 0x93, 0x75, 0xf4, 0x4c, 0x93, + 0x95, 0xdb, 0x29, 0x7a, 0xab, 0xee, 0x9e, 0x23, 0x6d, 0xe8, 0xa5, 0x9d, 0xa2, 0x67, 0x35, 0x19, + 0x34, 0x66, 0xa7, 0xc8, 0x51, 0xd9, 0x0d, 0x87, 0xfd, 0xa8, 0x56, 0xc4, 0x4b, 0x22, 0xde, 0x70, + 0x90, 0x48, 0x77, 0x5c, 0xe0, 0x48, 0xb2, 0x9a, 0xe5, 0x96, 0xed, 0x34, 0x45, 0x14, 0x82, 0xa8, + 0x1a, 0xca, 0xa0, 0xf1, 0x6a, 0x10, 0x95, 0xd4, 0x61, 0xc2, 0xa4, 0xbb, 0x1b, 0x9e, 0x1b, 0xd0, + 0x7a, 0x40, 0x1b, 0x42, 0xaa, 0x93, 0x17, 0x9b, 0x25, 0xd7, 0xe5, 0x12, 0x2b, 0xda, 0xc6, 0x67, + 0xbe, 0x75, 0x5c, 0x04, 0x06, 0xe2, 0x5e, 0x31, 0x27, 0xc7, 0xc5, 0x0b, 0x6c, 0xfc, 0x3b, 0x92, + 0x58, 0x3d, 0x9d, 0x54, 0xa6, 0xe4, 0x1b, 0x6c, 0xbf, 0x0e, 0xbb, 0x24, 0xaa, 0x6c, 0xa2, 0x47, + 0x65, 0x6f, 0xa6, 0x56, 0x56, 0x54, 0x7a, 0x3b, 0xb5, 0xd2, 0xd4, 0x4a, 0xc8, 0xbb, 0x30, 0x5e, + 0xae, 0x96, 0xdd, 0xf6, 0xae, 0xb3, 0x57, 0x5b, 0x29, 0xa1, 0x68, 0x28, 0x3c, 0xa2, 0xea, 0x8e, + 0x55, 0x47, 0xb8, 0xe5, 0xef, 0xdb, 0x9a, 0x63, 0x6c, 0x84, 0x4f, 0xee, 0xc0, 0x94, 0xfc, 0x69, + 0xd2, 0xdd, 0x2d, 0xb3, 0x8a, 0x12, 0xa1, 0x74, 0x43, 0x0b, 0x39, 0xb0, 0x8e, 0xe8, 0x7a, 0xea, + 0x4d, 0x21, 0x46, 0xc6, 0x26, 0x63, 0x85, 0x76, 0x9a, 0xee, 0x11, 0xfb, 0xbc, 0x4d, 0x87, 0x7a, + 0x28, 0x03, 0x8a, 0xc9, 0xd8, 0x08, 0x4b, 0xac, 0xc0, 0xd1, 0xdf, 0x4f, 0x75, 0x22, 0xb2, 0x0e, + 0x33, 0x62, 0x8a, 0x3f, 0x70, 0x7c, 0x67, 0xc7, 0x69, 0x3a, 0xc1, 0x11, 0x4a, 0x7f, 0x42, 0x80, + 0x91, 0xeb, 0xe2, 0x61, 0x58, 0xaa, 0x30, 0x4b, 0x92, 0x1a, 0xbf, 0x9e, 0x85, 0xe7, 0xfa, 0xdd, + 0x84, 0x48, 0x4d, 0xdf, 0xcc, 0xae, 0x0c, 0x70, 0x7b, 0x3a, 0x7d, 0x3b, 0x5b, 0x86, 0xa9, 0xfb, + 0x8a, 0x49, 0x5f, 0x68, 0x62, 0x89, 0x9d, 0xa1, 0x1a, 0xfb, 0xe9, 0xb3, 0x3d, 0x46, 0xb4, 0xf0, + 0x50, 0x6c, 0x73, 0x1f, 0xd7, 0x45, 0xf3, 0x16, 0x8c, 0x95, 0xdd, 0x76, 0x40, 0x1f, 0x05, 0xb1, + 0x80, 0x04, 0x1c, 0x18, 0x77, 0x4f, 0x95, 0xa8, 0xc6, 0xbf, 0xce, 0xc2, 0xf3, 0x7d, 0xaf, 0x02, + 0x64, 0x53, 0xef, 0xb5, 0xab, 0x83, 0xdc, 0x1f, 0x4e, 0xef, 0xb6, 0xc5, 0x84, 0xdd, 0xdd, 0xa9, + 0x1e, 0x50, 0x0b, 0xff, 0x43, 0x46, 0x74, 0xd2, 0xa7, 0x61, 0x14, 0xab, 0x0a, 0xbb, 0x88, 0x6b, + 0xc9, 0x70, 0x17, 0x76, 0x74, 0x2d, 0x19, 0x47, 0x23, 0x37, 0x21, 0x5f, 0xb6, 0x9b, 0x4d, 0x25, + 0x5c, 0x03, 0x4a, 0xf3, 0x75, 0x84, 0xc5, 0x8c, 0x47, 0x25, 0x22, 0x93, 0x7d, 0xf8, 0xdf, 0xca, + 0x59, 0x81, 0x9b, 0xa5, 0x20, 0x8b, 0x1d, 0x17, 0x0a, 0x32, 0x06, 0x79, 0xad, 0xbb, 0xa1, 0x43, + 0x38, 0x0f, 0xf2, 0xca, 0x00, 0x5a, 0x90, 0x57, 0x06, 0x30, 0x7e, 0x23, 0x07, 0x2f, 0xf4, 0xbf, + 0xcf, 0x92, 0x2d, 0x7d, 0x08, 0x5e, 0x1b, 0xe8, 0x16, 0x7c, 0xfa, 0x18, 0xc8, 0x90, 0xc9, 0xbc, + 0x43, 0xae, 0x24, 0xdd, 0x5f, 0xbe, 0x7d, 0x5c, 0x54, 0x2c, 0x92, 0xef, 0xba, 0x4e, 0x5b, 0x79, + 0x33, 0xf9, 0xba, 0x26, 0x19, 0xf2, 0xd7, 0xfb, 0x5b, 0x83, 0x7d, 0x59, 0x44, 0xc7, 0xf7, 0x95, + 0x41, 0x25, 0xca, 0xcf, 0x43, 0x21, 0x4e, 0x4a, 0x2e, 0xc3, 0x10, 0x7e, 0x80, 0xe2, 0xc3, 0x13, + 0xe3, 0x80, 0xe5, 0x0b, 0x6b, 0x62, 0xee, 0x60, 0x04, 0x0b, 0xb4, 0x07, 0xd0, 0x75, 0x83, 0x22, + 0x82, 0x05, 0x37, 0x27, 0x48, 0xea, 0x07, 0x63, 0x44, 0xc6, 0x9f, 0x67, 0xe0, 0x62, 0x4f, 0x4d, + 0x01, 0xd9, 0xd0, 0x07, 0xec, 0x95, 0xd3, 0x54, 0x0b, 0xa7, 0x8e, 0xd5, 0xc2, 0x8f, 0xcb, 0xb9, + 0xff, 0x1e, 0x4c, 0xd4, 0xba, 0x3b, 0xf1, 0xfb, 0x19, 0x8f, 0x2f, 0xa3, 0xc0, 0xd5, 0x13, 0x4c, + 0xc5, 0x67, 0xed, 0x97, 0x06, 0x0f, 0xc2, 0x00, 0x48, 0xb1, 0x3a, 0x0c, 0x5d, 0xac, 0x93, 0x11, + 0x3c, 0x74, 0x22, 0xe3, 0xd7, 0xb2, 0xe9, 0x17, 0xdd, 0x3b, 0xe5, 0x8d, 0xb3, 0x5c, 0x74, 0xef, + 0x94, 0x37, 0x4e, 0x6f, 0xfb, 0x3f, 0x96, 0x6d, 0xc7, 0x87, 0x59, 0xb1, 0xe3, 0x49, 0x45, 0xa7, + 0x78, 0x98, 0x95, 0xbb, 0xa3, 0xaf, 0x3f, 0xcc, 0x4a, 0x64, 0xf2, 0x26, 0x8c, 0xad, 0xba, 0x3c, + 0xb8, 0x86, 0x6c, 0x31, 0xf7, 0x41, 0x96, 0x40, 0x75, 0x7b, 0x0c, 0x31, 0xd9, 0xdd, 0x42, 0x1f, + 0x78, 0x69, 0x5c, 0x89, 0x77, 0x8b, 0xd8, 0x74, 0xd1, 0xd5, 0x81, 0x3a, 0x99, 0xf1, 0x9f, 0x0c, + 0x83, 0x71, 0xba, 0x32, 0x83, 0x7c, 0xa8, 0xf7, 0xdd, 0xb5, 0x81, 0xd5, 0x20, 0x03, 0x6d, 0xb9, + 0xa5, 0x6e, 0xc3, 0xa1, 0xed, 0xba, 0x1e, 0x19, 0x43, 0xc0, 0xd4, 0x2d, 0x50, 0xe2, 0x7d, 0x1c, + 0x47, 0xd5, 0x85, 0xff, 0x36, 0x17, 0x2d, 0xb5, 0xd8, 0xd1, 0x98, 0xf9, 0x18, 0x47, 0x23, 0xb9, + 0x07, 0x05, 0x15, 0xa2, 0xbc, 0xd0, 0xa2, 0xe4, 0xa2, 0x31, 0x8a, 0x7d, 0x54, 0x82, 0x50, 0x3f, + 0x5f, 0x73, 0x83, 0x9f, 0xaf, 0x91, 0xf8, 0x8e, 0xf5, 0x0f, 0x25, 0xc5, 0xf7, 0xb8, 0x33, 0xba, + 0x82, 0x2e, 0x23, 0x69, 0xf8, 0xe2, 0xd0, 0x1a, 0xd6, 0x23, 0x69, 0xa4, 0x1c, 0x5c, 0x2a, 0xba, + 0x0c, 0x06, 0x82, 0x3f, 0x15, 0x5f, 0xf8, 0x30, 0x18, 0x08, 0xa7, 0x4f, 0x0b, 0x06, 0x12, 0x92, + 0xb0, 0x03, 0xd0, 0xec, 0xb6, 0x79, 0x34, 0xf1, 0xd1, 0xe8, 0x00, 0xf4, 0xba, 0x6d, 0x2b, 0x1e, + 0x51, 0x3c, 0x44, 0x34, 0xfe, 0xe1, 0x50, 0xba, 0x70, 0x10, 0xea, 0xbb, 0xce, 0x22, 0x1c, 0x84, + 0x44, 0x9f, 0xcc, 0x4c, 0xdd, 0x82, 0x59, 0x69, 0x9f, 0x27, 0x0d, 0xbd, 0xb6, 0xcc, 0x55, 0x31, + 0xc4, 0xa8, 0x37, 0x0a, 0x2d, 0xfb, 0xa4, 0xb1, 0x98, 0xd5, 0xf5, 0x34, 0xbd, 0x51, 0x0a, 0xfd, + 0xc2, 0x6f, 0x4a, 0xb5, 0x98, 0x3a, 0x08, 0x5b, 0x5b, 0xe1, 0x5c, 0x8e, 0x0d, 0x42, 0xb7, 0xab, + 0x0d, 0xa3, 0x4e, 0xc2, 0xf7, 0x5e, 0xa9, 0x72, 0x40, 0x26, 0x8a, 0xac, 0xa8, 0x28, 0x2a, 0x62, + 0x5c, 0x62, 0x44, 0x64, 0x0f, 0x2e, 0x46, 0xa2, 0xb4, 0x72, 0x53, 0x40, 0x8e, 0xbc, 0xc1, 0x57, + 0x4f, 0x8e, 0x8b, 0xaf, 0x28, 0xa2, 0xb8, 0x7a, 0xe1, 0x88, 0x71, 0xef, 0xcd, 0x8b, 0xed, 0xb7, + 0x4b, 0x9e, 0xdd, 0xae, 0xef, 0x2b, 0x73, 0x1e, 0xf7, 0xdb, 0x1d, 0x84, 0x26, 0xc2, 0x19, 0x44, + 0xc8, 0xc6, 0x8f, 0x67, 0x61, 0x8a, 0x9f, 0xd5, 0xfc, 0x75, 0xee, 0xa9, 0x7d, 0xf9, 0x7c, 0x5b, + 0x7b, 0xf9, 0x94, 0x91, 0xf7, 0xd4, 0xa6, 0x0d, 0xf4, 0xee, 0xb9, 0x0f, 0x24, 0x49, 0x43, 0x4c, + 0x98, 0x50, 0xa1, 0xfd, 0x9f, 0x3c, 0x6f, 0x44, 0x41, 0x1a, 0x85, 0xa8, 0x84, 0xef, 0xce, 0xbe, + 0xa9, 0xf1, 0x30, 0x7e, 0x2c, 0x0b, 0x93, 0x8a, 0x9d, 0xca, 0x53, 0xdb, 0xf1, 0x9f, 0xd7, 0x3a, + 0x7e, 0x3e, 0xf4, 0x10, 0x0c, 0x5b, 0x36, 0x50, 0xbf, 0x77, 0x61, 0x26, 0x41, 0x12, 0x37, 0xf7, + 0xc9, 0x0c, 0x62, 0xee, 0xf3, 0x7a, 0x32, 0xe2, 0x1b, 0x4f, 0x9c, 0x10, 0xc6, 0xff, 0x51, 0x43, + 0xcc, 0xfd, 0x64, 0x16, 0xe6, 0xc4, 0x2f, 0x0c, 0x91, 0xca, 0x85, 0xd5, 0xa7, 0x76, 0x2c, 0x4a, + 0xda, 0x58, 0x14, 0xf5, 0xb1, 0x50, 0x1a, 0xd8, 0x7b, 0x48, 0x8c, 0x1f, 0x02, 0x98, 0xef, 0x45, + 0x30, 0xb0, 0x23, 0x7e, 0xe4, 0x9a, 0x98, 0x1d, 0xc0, 0x35, 0x71, 0x15, 0x0a, 0x58, 0x95, 0x08, + 0x82, 0xe8, 0x6f, 0x99, 0x55, 0xd1, 0x49, 0xa8, 0x5f, 0xe0, 0x71, 0x6c, 0x45, 0x50, 0x46, 0x3f, + 0xa6, 0xf3, 0x48, 0x50, 0x92, 0x5f, 0xce, 0xc0, 0x14, 0x02, 0x97, 0x1f, 0xd2, 0x76, 0x80, 0xcc, + 0x86, 0x84, 0xcf, 0x5a, 0xf8, 0x30, 0x5a, 0x0b, 0x3c, 0xa7, 0xbd, 0x27, 0x5e, 0x46, 0x77, 0xc4, + 0xcb, 0xe8, 0x3b, 0xfc, 0x45, 0xf7, 0x5a, 0xdd, 0x6d, 0x5d, 0xdf, 0xf3, 0xec, 0x87, 0x0e, 0x37, + 0xc1, 0xb2, 0x9b, 0xd7, 0xa3, 0x7c, 0x3f, 0x1d, 0x27, 0x96, 0x89, 0x47, 0xb0, 0xc2, 0x57, 0x67, + 0xfe, 0xa1, 0x14, 0xab, 0x8d, 0xab, 0x66, 0xf4, 0x2f, 0x22, 0xdf, 0x05, 0x17, 0x78, 0x68, 0x32, + 0x76, 0xc3, 0x77, 0xda, 0x5d, 0xb7, 0xeb, 0x2f, 0xd9, 0xf5, 0x03, 0x26, 0xe6, 0x73, 0xcf, 0x62, + 0x6c, 0x79, 0x3d, 0x2c, 0xb4, 0x76, 0x78, 0xa9, 0x16, 0xf3, 0x22, 0x9d, 0x01, 0x59, 0x81, 0x19, + 0x5e, 0x54, 0xea, 0x06, 0x6e, 0xad, 0x6e, 0x37, 0x9d, 0xf6, 0x1e, 0xca, 0x12, 0x79, 0x2e, 0xca, + 0xd8, 0xdd, 0xc0, 0xb5, 0x7c, 0x0e, 0x57, 0x35, 0x35, 0x09, 0x22, 0x52, 0x85, 0x69, 0x93, 0xda, + 0x8d, 0x35, 0xfb, 0x51, 0xd9, 0xee, 0xd8, 0x75, 0x27, 0xe0, 0xb1, 0x52, 0x73, 0x5c, 0xa0, 0xf3, + 0xa8, 0xdd, 0xb0, 0x5a, 0xf6, 0x23, 0xab, 0x2e, 0x0a, 0x75, 0x95, 0xbd, 0x46, 0x17, 0xb2, 0x72, + 0xda, 0x21, 0xab, 0xb1, 0x38, 0x2b, 0xa7, 0xdd, 0x9b, 0x55, 0x44, 0x27, 0x59, 0x6d, 0xda, 0xde, + 0x1e, 0x0d, 0xb8, 0xa1, 0x34, 0x5c, 0xca, 0x5c, 0xc9, 0x28, 0xac, 0x02, 0x2c, 0xb3, 0xd0, 0x68, + 0x3a, 0xce, 0x4a, 0xa1, 0x63, 0x33, 0x6f, 0xdb, 0x73, 0x02, 0xaa, 0xb6, 0x70, 0x1c, 0x3f, 0x0b, + 0xfb, 0x1f, 0x4d, 0xcc, 0x7b, 0x35, 0x31, 0x41, 0x19, 0x71, 0x53, 0x1a, 0x39, 0x91, 0xe0, 0x96, + 0xde, 0xca, 0x04, 0x65, 0xc8, 0x4d, 0x6d, 0xe7, 0x24, 0xb6, 0x53, 0xe1, 0xd6, 0xa3, 0xa1, 0x09, + 0x4a, 0xb2, 0xce, 0x3a, 0x2d, 0x60, 0x72, 0x93, 0xdb, 0x16, 0x16, 0xdc, 0x53, 0xf8, 0x69, 0x2f, + 0x0b, 0x33, 0xc4, 0x82, 0x27, 0x8b, 0xad, 0x14, 0x7b, 0xee, 0x38, 0x31, 0xf9, 0x6b, 0x30, 0xbd, + 0xe5, 0xd3, 0xdb, 0xd5, 0x8d, 0x9a, 0x8c, 0x64, 0x86, 0xca, 0xc5, 0xa9, 0xc5, 0x1b, 0xa7, 0x6c, + 0x3a, 0xd7, 0x54, 0x1a, 0x4c, 0x9f, 0xc3, 0xc7, 0xad, 0xeb, 0x53, 0x6b, 0xd7, 0xe9, 0xf8, 0x61, + 0x58, 0x48, 0x75, 0xdc, 0x62, 0x55, 0x19, 0x2b, 0x30, 0x93, 0x60, 0x43, 0xa6, 0x00, 0x18, 0xd0, + 0xda, 0x5a, 0xaf, 0x2d, 0x6f, 0x16, 0x9e, 0x21, 0x05, 0x98, 0xc0, 0xdf, 0xcb, 0xeb, 0xa5, 0xa5, + 0xd5, 0xe5, 0x4a, 0x21, 0x43, 0x66, 0x60, 0x12, 0x21, 0x95, 0x6a, 0x8d, 0x83, 0xb2, 0x3c, 0x79, + 0x82, 0x59, 0xe0, 0x4b, 0x37, 0x60, 0x0b, 0x00, 0xcf, 0x14, 0xe3, 0x6f, 0x65, 0xe1, 0xa2, 0x3c, + 0x56, 0x68, 0xc0, 0x04, 0x47, 0xa7, 0xbd, 0xf7, 0x94, 0x9f, 0x0e, 0xb7, 0xb5, 0xd3, 0xe1, 0xe5, + 0xd8, 0x49, 0x1d, 0x6b, 0x65, 0x9f, 0x23, 0xe2, 0xb7, 0xc7, 0xe0, 0xf9, 0xbe, 0x54, 0xe4, 0x03, + 0x76, 0x9a, 0x3b, 0xb4, 0x1d, 0x54, 0x1b, 0x4d, 0xba, 0xe9, 0xb4, 0xa8, 0xdb, 0x0d, 0x84, 0xc7, + 0xc0, 0x4b, 0xa8, 0xcf, 0xc3, 0x42, 0xcb, 0x69, 0x34, 0xa9, 0x15, 0xf0, 0x62, 0x6d, 0xba, 0x25, + 0xa9, 0x19, 0xcb, 0x30, 0x95, 0x57, 0xb5, 0x1d, 0x50, 0xef, 0x21, 0x5a, 0x25, 0x86, 0x2c, 0x0f, + 0x28, 0xed, 0x58, 0x36, 0x2b, 0xb5, 0x1c, 0x51, 0xac, 0xb3, 0x4c, 0x50, 0x93, 0xdb, 0x0a, 0xcb, + 0x32, 0xbb, 0xfd, 0xaf, 0xd9, 0x8f, 0x84, 0x99, 0x94, 0x88, 0x8c, 0x1b, 0xb2, 0xe4, 0xee, 0x7c, + 0x2d, 0xfb, 0x91, 0x99, 0x24, 0x21, 0x5f, 0x81, 0x73, 0xe2, 0x00, 0x12, 0xc1, 0x5b, 0x64, 0x8b, + 0x79, 0x68, 0x98, 0x57, 0x4f, 0x8e, 0x8b, 0x17, 0x64, 0x4c, 0x61, 0x19, 0x58, 0x29, 0xad, 0xd5, + 0xe9, 0x5c, 0xc8, 0x26, 0x3b, 0x90, 0x63, 0xdd, 0xb1, 0x46, 0x7d, 0x5f, 0xfa, 0x6c, 0x8a, 0x9b, + 0xb1, 0xda, 0x99, 0x56, 0x8b, 0x97, 0x9b, 0x3d, 0x29, 0xc9, 0x0a, 0x4c, 0x6d, 0xd3, 0x1d, 0x75, + 0x7c, 0x46, 0xc2, 0xad, 0xaa, 0x70, 0x48, 0x77, 0x7a, 0x0f, 0x4e, 0x8c, 0x8e, 0x38, 0xf8, 0x3e, + 0xf0, 0xe8, 0x68, 0xd5, 0xf1, 0x03, 0xda, 0xa6, 0x1e, 0x86, 0x6f, 0x1b, 0xc5, 0xcd, 0x60, 0x3e, + 0x92, 0x90, 0xf5, 0xf2, 0xa5, 0x17, 0x4f, 0x8e, 0x8b, 0xcf, 0x73, 0xe7, 0xe7, 0xa6, 0x80, 0x5b, + 0xb1, 0x44, 0x58, 0x49, 0xae, 0xe4, 0x6b, 0x30, 0x6d, 0xba, 0xdd, 0xc0, 0x69, 0xef, 0xd5, 0x02, + 0xcf, 0x0e, 0xe8, 0x1e, 0x3f, 0x90, 0xa2, 0x38, 0x71, 0xb1, 0x52, 0xf1, 0xb4, 0xcc, 0x81, 0x96, + 0x2f, 0xa0, 0xda, 0x89, 0xa0, 0x13, 0x90, 0xaf, 0xc2, 0x14, 0x0f, 0xdb, 0x11, 0x56, 0x30, 0xa6, + 0x25, 0xf1, 0xd0, 0x0b, 0x1f, 0xdc, 0x10, 0x56, 0x2d, 0x08, 0x4d, 0xab, 0x20, 0xc6, 0x8d, 0x7c, + 0x49, 0x74, 0xd6, 0x86, 0xd3, 0xde, 0x0b, 0xa7, 0x31, 0x60, 0xcf, 0xbf, 0x11, 0x75, 0x49, 0x87, + 0x7d, 0xae, 0x9c, 0xc6, 0x3d, 0x4c, 0xf4, 0x92, 0x7c, 0x48, 0x00, 0xcf, 0x97, 0x7c, 0xdf, 0xf1, + 0x03, 0xe1, 0x57, 0xb3, 0xfc, 0x88, 0xd6, 0xbb, 0x0c, 0x99, 0x5d, 0x6f, 0xa9, 0xc7, 0xed, 0xba, + 0x87, 0x97, 0xae, 0x9d, 0x1c, 0x17, 0x5f, 0xb3, 0x11, 0xd1, 0x12, 0xae, 0x38, 0x16, 0x95, 0xa8, + 0xd6, 0x21, 0xc7, 0x55, 0xda, 0xd0, 0x9f, 0x29, 0xf9, 0x2a, 0x9c, 0x2f, 0xdb, 0x3e, 0xad, 0xb6, + 0x7d, 0xda, 0xf6, 0x9d, 0xc0, 0x79, 0x48, 0x45, 0xa7, 0xe2, 0xe1, 0x97, 0xc7, 0x94, 0x61, 0x46, + 0xdd, 0xf6, 0xd9, 0xc2, 0x0c, 0x51, 0x2c, 0x31, 0x28, 0x4a, 0x35, 0x3d, 0xb8, 0x10, 0x13, 0xa6, + 0x6a, 0xb5, 0x95, 0x8a, 0x63, 0x87, 0xeb, 0x6a, 0x12, 0xfb, 0xeb, 0x35, 0x54, 0xed, 0xf9, 0xfb, + 0x56, 0xc3, 0xb1, 0xc3, 0x05, 0xd5, 0xa3, 0xb3, 0x62, 0x1c, 0x8c, 0xe3, 0x0c, 0x14, 0xe2, 0x43, + 0x49, 0xbe, 0x08, 0x63, 0xdc, 0xbe, 0x8d, 0xfa, 0xfb, 0x22, 0xf2, 0x84, 0x34, 0x97, 0x0a, 0xe1, + 0x3a, 0x91, 0x70, 0xa7, 0xe3, 0xd6, 0x73, 0x54, 0xb5, 0x96, 0x41, 0x77, 0x3a, 0x49, 0x44, 0x1a, + 0x30, 0xc1, 0x47, 0x8b, 0x62, 0x90, 0x48, 0x61, 0xe6, 0xfc, 0xa2, 0xba, 0x3a, 0x44, 0x51, 0x8c, + 0x3f, 0xbe, 0x1a, 0x8a, 0x39, 0xc1, 0x11, 0xb4, 0x2a, 0x34, 0xae, 0x4b, 0x00, 0x79, 0x49, 0x68, + 0x5c, 0x84, 0x0b, 0x3d, 0xbe, 0xd9, 0x78, 0x88, 0x96, 0x04, 0x3d, 0x6a, 0x24, 0x5f, 0x84, 0x39, + 0x24, 0x2c, 0xbb, 0xed, 0x36, 0xad, 0x07, 0xb8, 0x1d, 0x49, 0xed, 0x7b, 0x8e, 0x5b, 0xba, 0xf0, + 0xf6, 0xd6, 0x43, 0x04, 0x2b, 0xae, 0x84, 0x4f, 0xe5, 0x60, 0xfc, 0x7c, 0x16, 0xe6, 0xc5, 0x0e, + 0x67, 0xd2, 0xba, 0xeb, 0x35, 0x9e, 0xfe, 0x13, 0x75, 0x59, 0x3b, 0x51, 0x5f, 0x0a, 0xc3, 0x16, + 0xa5, 0x35, 0xb2, 0xcf, 0x81, 0xfa, 0x6b, 0x19, 0x78, 0xae, 0x1f, 0x11, 0xeb, 0x9d, 0x30, 0x28, + 0xe6, 0x58, 0x22, 0xf8, 0x65, 0x07, 0x66, 0x71, 0x40, 0xcb, 0xfb, 0xb4, 0x7e, 0xe0, 0xaf, 0xb8, + 0x7e, 0x80, 0x9e, 0x16, 0xd9, 0x1e, 0x6f, 0xdd, 0xaf, 0xa7, 0xbe, 0x75, 0x9f, 0xe7, 0xb3, 0xac, + 0x8e, 0x3c, 0x78, 0xd8, 0xce, 0x03, 0x7a, 0xe4, 0x9b, 0x69, 0xac, 0xd1, 0x62, 0xbe, 0xd4, 0x0d, + 0xf6, 0x37, 0x3c, 0xba, 0x4b, 0x3d, 0xda, 0xae, 0xd3, 0xef, 0x30, 0x8b, 0x79, 0xbd, 0x71, 0x03, + 0x69, 0x30, 0xfe, 0xf1, 0x24, 0xcc, 0xa5, 0x91, 0xb1, 0x7e, 0x51, 0x2e, 0xcd, 0xf1, 0x8c, 0xa6, + 0x3f, 0x98, 0x81, 0x89, 0x1a, 0xad, 0xbb, 0xed, 0xc6, 0x6d, 0xb4, 0x28, 0x12, 0xbd, 0x63, 0x71, + 0xa1, 0x81, 0xc1, 0xad, 0xdd, 0x98, 0xa9, 0xd1, 0xb7, 0x8f, 0x8b, 0x5f, 0x18, 0xec, 0xae, 0x5a, + 0x77, 0x31, 0x5c, 0x50, 0x80, 0x19, 0x37, 0xc2, 0x2a, 0xf0, 0x71, 0x50, 0xab, 0x94, 0x2c, 0xc1, + 0xa4, 0x58, 0xae, 0xae, 0x1a, 0x13, 0x95, 0x47, 0x76, 0x92, 0x05, 0x09, 0xd5, 0xb5, 0x46, 0x42, + 0x6e, 0x42, 0x6e, 0x6b, 0xf1, 0xb6, 0x18, 0x03, 0x99, 0xb3, 0x64, 0x6b, 0xf1, 0x36, 0xaa, 0xc3, + 0xd8, 0x15, 0x63, 0xb2, 0xbb, 0xa8, 0x19, 0xf9, 0x6c, 0x2d, 0xde, 0x26, 0xdf, 0x0b, 0xe7, 0x2a, + 0x8e, 0x2f, 0xaa, 0xe0, 0xbe, 0x1b, 0x0d, 0xf4, 0x58, 0x1c, 0xe9, 0x31, 0x7b, 0x3f, 0x9b, 0x3a, + 0x7b, 0x5f, 0x6c, 0x84, 0x4c, 0x2c, 0xee, 0x18, 0xd2, 0x88, 0xc7, 0x7e, 0x4d, 0xaf, 0x87, 0x7c, + 0x04, 0x53, 0xa8, 0xcc, 0x46, 0x77, 0x16, 0x8c, 0xda, 0x3f, 0xda, 0xa3, 0xe6, 0x4f, 0xa7, 0xd6, + 0xbc, 0xc0, 0xe3, 0x6d, 0xa0, 0x53, 0x0c, 0x46, 0xf8, 0xd7, 0x6e, 0xfd, 0x1a, 0x67, 0x72, 0x17, + 0xa6, 0x85, 0xf8, 0x75, 0x7f, 0x77, 0x73, 0x9f, 0x56, 0xec, 0x23, 0x61, 0x9f, 0x83, 0x37, 0x3a, + 0x21, 0xb3, 0x59, 0xee, 0xae, 0x15, 0xec, 0x53, 0xab, 0x61, 0x6b, 0x82, 0x4a, 0x8c, 0x90, 0x7c, + 0x03, 0xc6, 0x57, 0xdd, 0x3a, 0x93, 0xbc, 0x71, 0x67, 0xe0, 0x26, 0x3b, 0x1f, 0x62, 0xce, 0x4c, + 0x0e, 0x8e, 0x89, 0x53, 0xdf, 0x3e, 0x2e, 0xbe, 0x7d, 0xd6, 0x49, 0xa3, 0x54, 0x60, 0xaa, 0xb5, + 0x91, 0x32, 0xe4, 0xb7, 0xe9, 0x0e, 0x6b, 0x6d, 0x3c, 0x9f, 0x9e, 0x04, 0x0b, 0x8b, 0x3c, 0xf1, + 0x4b, 0xb3, 0xc8, 0x13, 0x30, 0xe2, 0xc1, 0x0c, 0xf6, 0xcf, 0x86, 0xed, 0xfb, 0x87, 0xae, 0xd7, + 0xc0, 0xc4, 0x29, 0xbd, 0xac, 0x81, 0x16, 0x53, 0x3b, 0xff, 0x39, 0xde, 0xf9, 0x1d, 0x85, 0x83, + 0x2a, 0x40, 0x26, 0xd8, 0x93, 0xaf, 0xc1, 0x94, 0x88, 0x5d, 0xb0, 0x76, 0xbb, 0x84, 0xab, 0x72, + 0x42, 0xf3, 0xfb, 0xd4, 0x0b, 0xb9, 0x94, 0x2a, 0x42, 0x21, 0x48, 0x0d, 0x94, 0xd5, 0xda, 0xb5, + 0x75, 0xa5, 0xbf, 0x4a, 0x42, 0x36, 0x60, 0xbc, 0x82, 0x59, 0x9d, 0xd1, 0x37, 0x4d, 0xd8, 0x85, + 0x87, 0x09, 0xc1, 0xa2, 0x12, 0xae, 0x8b, 0x11, 0x09, 0xa0, 0xd1, 0xd3, 0x4d, 0xb7, 0xd5, 0x0d, + 0x11, 0xc9, 0x2d, 0xc8, 0x55, 0x2b, 0x1b, 0xc2, 0x2c, 0x7c, 0x26, 0x8c, 0x10, 0xb2, 0x21, 0xd3, + 0x27, 0xa1, 0xfd, 0x9c, 0xd3, 0xd0, 0x8c, 0xca, 0xab, 0x95, 0x0d, 0xb2, 0x0b, 0x93, 0xd8, 0x01, + 0x2b, 0xd4, 0xe6, 0x7d, 0x3b, 0xdd, 0xa3, 0x6f, 0xaf, 0xa5, 0xf6, 0xed, 0x3c, 0xef, 0xdb, 0x7d, + 0x41, 0xad, 0xe5, 0x83, 0x51, 0xd9, 0x32, 0x91, 0x56, 0xe4, 0xa8, 0x92, 0x59, 0x4c, 0x36, 0x57, + 0xd1, 0x3e, 0x48, 0x88, 0xb4, 0x32, 0xa5, 0x55, 0x98, 0x56, 0xa5, 0xa7, 0xd7, 0x49, 0x92, 0x0f, + 0xf9, 0x3c, 0x0c, 0xdd, 0x3f, 0x08, 0x6c, 0x61, 0x00, 0x2e, 0xfb, 0x91, 0x81, 0x64, 0xf3, 0x51, + 0x0b, 0xe9, 0x1e, 0x68, 0x31, 0xe7, 0x90, 0x86, 0x0d, 0xc5, 0x8a, 0xed, 0x35, 0x0e, 0x6d, 0x0f, + 0x1d, 0x84, 0x67, 0x35, 0x16, 0x4a, 0x09, 0x1f, 0x8a, 0x7d, 0x01, 0x88, 0x79, 0x0d, 0xab, 0x2c, + 0xc8, 0x77, 0xc1, 0x45, 0xdf, 0xd9, 0x6b, 0xdb, 0x41, 0xd7, 0xa3, 0x96, 0xdd, 0xdc, 0x73, 0x3d, + 0x27, 0xd8, 0x6f, 0x59, 0x7e, 0xd7, 0x09, 0xe8, 0xfc, 0x9c, 0x96, 0xd1, 0xba, 0x26, 0xf1, 0x4a, + 0x12, 0xad, 0xc6, 0xb0, 0xcc, 0x0b, 0x7e, 0x7a, 0x01, 0xf9, 0x12, 0x4c, 0xaa, 0x5b, 0xb2, 0x3f, + 0x7f, 0xee, 0x52, 0xee, 0xca, 0x54, 0x78, 0xf1, 0x88, 0x6f, 0xe0, 0x32, 0x12, 0xb4, 0x72, 0x42, + 0xf8, 0x7a, 0x24, 0x68, 0x85, 0x57, 0x98, 0x23, 0x92, 0x14, 0x66, 0xcd, 0x19, 0x31, 0x63, 0x45, + 0x2f, 0xaf, 0xdd, 0x2e, 0x99, 0xa3, 0x1b, 0xd5, 0x07, 0xb5, 0xa6, 0x1b, 0x18, 0xff, 0x45, 0x06, + 0x37, 0x71, 0xf2, 0x1a, 0x06, 0x92, 0x0a, 0x5f, 0xcf, 0x50, 0x7f, 0x6b, 0x77, 0x62, 0x69, 0x04, + 0x38, 0x0a, 0x79, 0x1d, 0x46, 0x6e, 0xdb, 0x75, 0x19, 0xc4, 0x46, 0x20, 0xef, 0x22, 0x44, 0x55, + 0xf6, 0x72, 0x1c, 0x26, 0x5f, 0xf2, 0xc9, 0x5d, 0x8a, 0x92, 0xa5, 0x97, 0x4b, 0xf2, 0xb9, 0x1e, + 0xe5, 0x4b, 0xb1, 0x28, 0x94, 0x6c, 0xea, 0x31, 0xab, 0xf8, 0x54, 0x0e, 0xc6, 0x9f, 0x66, 0xa2, + 0x5d, 0x89, 0xbc, 0x0a, 0x43, 0xe6, 0x46, 0xf8, 0xfd, 0xdc, 0xe9, 0x37, 0xf6, 0xf9, 0x88, 0x40, + 0xbe, 0x04, 0xe7, 0x14, 0x3e, 0x09, 0x13, 0xfd, 0x57, 0xd0, 0x27, 0x55, 0xf9, 0x92, 0x74, 0x3b, + 0xfd, 0x74, 0x1e, 0x28, 0x4c, 0x47, 0x05, 0x15, 0xda, 0x76, 0x38, 0x6f, 0xa5, 0xb1, 0x2a, 0xef, + 0x06, 0x22, 0xc4, 0x1b, 0x9b, 0xc6, 0x81, 0xbb, 0xa4, 0x1a, 0xbf, 0x95, 0xd1, 0x76, 0x9b, 0x30, + 0xbb, 0x74, 0xe6, 0x94, 0xec, 0xd2, 0x6f, 0x01, 0x94, 0xba, 0x81, 0xbb, 0xdc, 0xf6, 0xdc, 0x26, + 0xd7, 0xa2, 0x88, 0x4c, 0x1a, 0xa8, 0x1b, 0xa6, 0x08, 0xd6, 0x3c, 0xe7, 0x42, 0xe4, 0x54, 0x6f, + 0x86, 0xdc, 0xc7, 0xf5, 0x66, 0x30, 0x7e, 0x3f, 0xa3, 0xad, 0x51, 0x26, 0x25, 0x8a, 0xa9, 0xa8, + 0x5a, 0x8c, 0x75, 0x9c, 0x87, 0x96, 0xdf, 0x74, 0xb5, 0x70, 0x15, 0x02, 0x8d, 0xfc, 0xbb, 0x19, + 0x38, 0xcf, 0xdd, 0x02, 0xd6, 0xbb, 0xad, 0x1d, 0xea, 0x3d, 0xb0, 0x9b, 0x4e, 0x23, 0x0a, 0xd3, + 0x17, 0x99, 0x0f, 0x2a, 0xd5, 0xa4, 0xe3, 0xf3, 0x8b, 0x2a, 0x77, 0x53, 0xb0, 0xda, 0x58, 0x68, + 0x3d, 0x0c, 0x4b, 0xd5, 0x8b, 0x6a, 0x3a, 0xbd, 0xf1, 0xeb, 0x19, 0x78, 0xf1, 0xd4, 0x5a, 0xc8, + 0x75, 0x18, 0x95, 0x29, 0x4c, 0x32, 0xd8, 0xf1, 0x68, 0x67, 0x9b, 0x4c, 0x5f, 0x22, 0xb1, 0xc8, + 0x97, 0xe1, 0x9c, 0xca, 0x6a, 0xd3, 0xb3, 0x1d, 0x35, 0x51, 0x48, 0xca, 0x57, 0x07, 0x0c, 0x25, + 0x2e, 0xad, 0xa5, 0x33, 0x31, 0xfe, 0xbf, 0x8c, 0x92, 0x6f, 0xfe, 0x29, 0x95, 0xe1, 0x6f, 0x69, + 0x32, 0xbc, 0x0c, 0x52, 0x1a, 0xb6, 0x8a, 0x95, 0xa5, 0xde, 0xbb, 0xa6, 0x15, 0x7b, 0x71, 0x04, + 0xfc, 0x48, 0x16, 0xc6, 0xb7, 0x7c, 0xea, 0xf1, 0x87, 0xdc, 0xef, 0xac, 0x50, 0x8d, 0x61, 0xbb, + 0x06, 0x0a, 0xa6, 0xf7, 0xc7, 0x19, 0x54, 0xf0, 0xab, 0x14, 0xac, 0x37, 0x94, 0x1c, 0x93, 0xd8, + 0x1b, 0x98, 0x5d, 0x12, 0xa1, 0x3c, 0xb4, 0xd8, 0xaa, 0x9e, 0x6e, 0x16, 0x73, 0x0e, 0xaf, 0x92, + 0x2f, 0xc0, 0xf0, 0x16, 0xaa, 0x2b, 0xf5, 0x20, 0x1b, 0x21, 0x7f, 0x2c, 0xe4, 0x9b, 0x74, 0xd7, + 0xd7, 0xe3, 0xce, 0x71, 0x42, 0x52, 0x83, 0xd1, 0xb2, 0x47, 0x31, 0x7b, 0xfc, 0xd0, 0xe0, 0x2e, + 0xe2, 0x75, 0x4e, 0x12, 0x77, 0x11, 0x17, 0x9c, 0x8c, 0x9f, 0xcb, 0x02, 0x89, 0xda, 0x88, 0xa9, + 0xd2, 0xfc, 0xa7, 0x76, 0xd0, 0xdf, 0xd7, 0x06, 0xfd, 0xf9, 0xc4, 0xa0, 0xf3, 0xe6, 0x0d, 0x34, + 0xf6, 0xbf, 0x93, 0x81, 0xf3, 0xe9, 0x84, 0xe4, 0x25, 0x18, 0xb9, 0xbf, 0xb9, 0x21, 0xe3, 0xb4, + 0x88, 0xa6, 0xb8, 0x1d, 0xd4, 0x15, 0x98, 0xa2, 0x88, 0xbc, 0x01, 0x23, 0x1f, 0x98, 0x65, 0x76, + 0x0e, 0x29, 0xc9, 0x38, 0xbe, 0xee, 0x59, 0x75, 0xfd, 0x28, 0x12, 0x48, 0xea, 0xd8, 0xe6, 0x9e, + 0xd8, 0xd8, 0xfe, 0x64, 0x16, 0xa6, 0x4b, 0xf5, 0x3a, 0xf5, 0x7d, 0x11, 0x68, 0xfe, 0xa9, 0x1d, + 0xd8, 0xf4, 0x08, 0x2c, 0x5a, 0xdb, 0x06, 0x1a, 0xd5, 0xdf, 0xcd, 0xc0, 0x39, 0x49, 0xf5, 0xd0, + 0xa1, 0x87, 0x9b, 0xfb, 0x1e, 0xf5, 0xf7, 0xdd, 0x66, 0x63, 0xe0, 0x8c, 0x3f, 0x4c, 0xd0, 0xc3, + 0xe0, 0xf0, 0xea, 0xab, 0xfe, 0x2e, 0x42, 0x34, 0x41, 0x8f, 0x07, 0x90, 0xbf, 0x0e, 0xa3, 0xa5, + 0x4e, 0xc7, 0x73, 0x1f, 0xf2, 0x65, 0x2f, 0x22, 0x4b, 0xda, 0x1c, 0xa4, 0x79, 0xd8, 0x73, 0x10, + 0xfb, 0x8c, 0x0a, 0x6d, 0xf3, 0x50, 0x7e, 0x93, 0xfc, 0x33, 0x1a, 0xb4, 0xad, 0xca, 0xe2, 0x58, + 0x6e, 0xd4, 0x80, 0x6c, 0x78, 0x6e, 0xcb, 0x0d, 0x68, 0x83, 0xb7, 0x07, 0x03, 0x13, 0x9c, 0x1a, + 0x52, 0x6b, 0xd3, 0x09, 0x9a, 0x5a, 0x48, 0xad, 0x80, 0x01, 0x4c, 0x0e, 0x37, 0xfe, 0x9f, 0x61, + 0x98, 0x50, 0x7b, 0x87, 0x18, 0x3c, 0x8d, 0x87, 0xeb, 0xa9, 0xd1, 0x31, 0x6c, 0x84, 0x98, 0xa2, + 0x24, 0x0a, 0x2d, 0x93, 0x3d, 0x35, 0xb4, 0xcc, 0x36, 0x4c, 0x6e, 0x78, 0x2e, 0x86, 0xc0, 0xc4, + 0xd7, 0x4a, 0xb1, 0x15, 0xce, 0x2a, 0xf7, 0x4e, 0x36, 0x90, 0xf8, 0x1e, 0x8a, 0x92, 0x7d, 0x47, + 0x60, 0x63, 0x72, 0x4b, 0x4d, 0xeb, 0xa2, 0xf1, 0xe1, 0xa6, 0x16, 0xb6, 0x2f, 0xe2, 0xd8, 0x86, + 0xa6, 0x16, 0x0c, 0xa2, 0x9b, 0x5a, 0x30, 0x88, 0xba, 0xd6, 0x86, 0x9f, 0xd4, 0x5a, 0x23, 0x3f, + 0x97, 0x81, 0xf1, 0x52, 0xbb, 0x2d, 0x42, 0xd6, 0x9c, 0xe2, 0xad, 0xff, 0x65, 0x61, 0x6d, 0xf1, + 0xf6, 0xc7, 0xb2, 0xb6, 0x40, 0xb9, 0xc5, 0x47, 0x49, 0x35, 0xaa, 0x50, 0xbd, 0xad, 0x29, 0xdf, + 0x41, 0xde, 0x86, 0x42, 0x38, 0xc9, 0xab, 0xed, 0x06, 0x7d, 0x44, 0x79, 0x1a, 0xc4, 0x49, 0x11, + 0x57, 0x5b, 0x95, 0x4c, 0xe3, 0x88, 0x64, 0x13, 0xc0, 0x0e, 0x67, 0x57, 0x2c, 0x9f, 0x6b, 0x72, + 0xfa, 0x09, 0xe9, 0x19, 0x7f, 0xe3, 0x83, 0x96, 0x2a, 0x3d, 0x47, 0x7c, 0x48, 0x0b, 0xa6, 0x79, + 0x32, 0xd5, 0x5a, 0x60, 0x7b, 0x01, 0xa6, 0xa2, 0x80, 0x53, 0xc7, 0xe1, 0x55, 0xa1, 0x3f, 0x7b, + 0x56, 0xa4, 0x68, 0xf5, 0x19, 0xad, 0x95, 0x92, 0x97, 0x22, 0xce, 0x9b, 0x47, 0x31, 0x37, 0x2f, + 0x24, 0xbf, 0x97, 0x4f, 0xfa, 0x9f, 0xcc, 0xc0, 0x79, 0x75, 0xd2, 0xd7, 0xba, 0x3b, 0x22, 0x74, + 0x28, 0xb9, 0x06, 0x63, 0x62, 0x4e, 0x86, 0x97, 0xa8, 0x64, 0x46, 0x8d, 0x08, 0x85, 0x2c, 0xb3, + 0x69, 0xc8, 0x78, 0x08, 0xa9, 0x7b, 0x36, 0xb6, 0x4f, 0xb1, 0xa2, 0x28, 0x51, 0xb7, 0x87, 0xbf, + 0xf5, 0xf9, 0xc9, 0x20, 0xc6, 0x7b, 0x30, 0xa3, 0x8f, 0x44, 0x8d, 0x06, 0xe4, 0x2a, 0x8c, 0xca, + 0xe1, 0xcb, 0xa4, 0x0f, 0x9f, 0x2c, 0x37, 0xb6, 0x81, 0x24, 0xe8, 0x7d, 0x34, 0x8b, 0x62, 0xf7, + 0x53, 0x6e, 0xb6, 0x27, 0x1f, 0x25, 0x13, 0x88, 0x4b, 0xb3, 0xe2, 0xfb, 0xc6, 0x35, 0xb7, 0x04, + 0x0c, 0xa3, 0xfa, 0xa7, 0x53, 0x30, 0x9b, 0xb2, 0xe7, 0x9e, 0x22, 0x13, 0x15, 0xf5, 0x0d, 0x62, + 0x2c, 0x0c, 0xf6, 0x21, 0xb7, 0x85, 0xf7, 0x60, 0xf8, 0xd4, 0xed, 0x80, 0x3b, 0xa5, 0xc4, 0x76, + 0x01, 0x4e, 0xf6, 0x89, 0xc8, 0x45, 0x6a, 0x3c, 0x9e, 0xe1, 0x27, 0x16, 0x8f, 0x67, 0x09, 0x26, + 0x45, 0xab, 0xc4, 0x76, 0xa5, 0x18, 0x47, 0xcb, 0x0c, 0x31, 0x89, 0x6d, 0x4b, 0x27, 0xe1, 0x3c, + 0x7c, 0xb7, 0xf9, 0x90, 0x0a, 0x1e, 0xa3, 0x2a, 0x0f, 0x2c, 0x48, 0xe5, 0xa1, 0x90, 0x90, 0xff, + 0x18, 0x13, 0x39, 0x22, 0x44, 0xdd, 0xb3, 0xf2, 0xfd, 0xf6, 0xac, 0xc6, 0x93, 0xd9, 0xb3, 0x9e, + 0x97, 0xdf, 0x98, 0xbe, 0x77, 0xa5, 0x7c, 0x16, 0xf9, 0x95, 0x0c, 0xcc, 0xf0, 0xa0, 0x30, 0xea, + 0xc7, 0xf6, 0x0d, 0xf4, 0x51, 0x7f, 0x32, 0x1f, 0xfb, 0x9c, 0xc8, 0x0d, 0x94, 0xfe, 0xad, 0xc9, + 0x8f, 0x22, 0xdf, 0x05, 0x10, 0xae, 0x28, 0x1e, 0x4a, 0x76, 0x7c, 0xf1, 0xb9, 0x94, 0x5d, 0x20, + 0x44, 0x8a, 0x52, 0x78, 0x04, 0x21, 0x9d, 0x96, 0xbe, 0x33, 0x84, 0x92, 0xef, 0x85, 0x39, 0xb6, + 0x5e, 0x42, 0x88, 0x08, 0x61, 0x35, 0x3f, 0x8e, 0xb5, 0x7c, 0xa6, 0xb7, 0x4c, 0x74, 0x2d, 0x8d, + 0x8c, 0x07, 0x1e, 0x8e, 0x32, 0xa9, 0x07, 0x6a, 0xb4, 0x8b, 0xd4, 0x8a, 0x30, 0x32, 0x1c, 0x7e, + 0x3d, 0x4f, 0xb3, 0xd1, 0x63, 0x7f, 0xbb, 0x28, 0xd7, 0x02, 0xdf, 0xdf, 0x7c, 0xdd, 0x47, 0x19, + 0x41, 0xe4, 0x03, 0x20, 0x61, 0x34, 0x15, 0x0e, 0xa3, 0x32, 0x05, 0x07, 0x57, 0x37, 0x47, 0x51, + 0x59, 0x3c, 0x59, 0xac, 0x4e, 0x92, 0x24, 0x31, 0xa1, 0x30, 0x27, 0x1a, 0xcd, 0xa0, 0x32, 0xcb, + 0xa2, 0x3f, 0x3f, 0xa5, 0x05, 0x08, 0x8b, 0x4a, 0xa2, 0x94, 0xeb, 0x4a, 0xaa, 0x46, 0x4d, 0xe5, + 0x94, 0xc6, 0x8e, 0xdc, 0x82, 0x31, 0x74, 0x14, 0x5e, 0x91, 0xc6, 0x5e, 0xc2, 0xf0, 0x04, 0x5d, + 0x8a, 0xad, 0x7d, 0xdd, 0x64, 0x2b, 0x42, 0x65, 0xd7, 0x81, 0x8a, 0x77, 0x64, 0x76, 0xdb, 0xa8, + 0x14, 0x16, 0xfa, 0x8e, 0x86, 0x77, 0x64, 0x79, 0x5d, 0xdd, 0x93, 0x1c, 0x91, 0xc8, 0xd7, 0x60, + 0x7c, 0xcd, 0x7e, 0x14, 0xe6, 0x99, 0x9a, 0x19, 0x3c, 0x9b, 0x55, 0xcb, 0x7e, 0x14, 0x26, 0x99, + 0x8a, 0x67, 0xb3, 0x52, 0x58, 0x92, 0xaf, 0x00, 0x28, 0x9a, 0x6a, 0x72, 0x6a, 0x05, 0x2f, 0xca, + 0xb0, 0x77, 0xa9, 0x1a, 0x6c, 0xe4, 0xaf, 0x30, 0x8c, 0x49, 0x0e, 0x73, 0x9f, 0x9c, 0xe4, 0x70, + 0xee, 0x93, 0x93, 0x1c, 0x16, 0x76, 0xe0, 0x62, 0xcf, 0xa5, 0x93, 0x12, 0xf4, 0xf8, 0xba, 0x1e, + 0xf4, 0xf8, 0x62, 0xaf, 0x23, 0xd6, 0xd7, 0x33, 0xad, 0xcc, 0x16, 0xe6, 0x7a, 0x4b, 0x27, 0xdf, + 0xca, 0xc6, 0x8e, 0x5c, 0x71, 0xb1, 0xe0, 0x59, 0xbe, 0x7a, 0xc9, 0x24, 0x59, 0x4c, 0xc1, 0xcd, + 0x0f, 0x65, 0x25, 0x2e, 0x3c, 0x3b, 0x94, 0xd5, 0x43, 0x1d, 0x8f, 0xe7, 0xc7, 0x3d, 0x7d, 0xdf, + 0x81, 0x29, 0x9e, 0x35, 0xf7, 0x1e, 0x3d, 0x3a, 0x74, 0xbd, 0x06, 0xcf, 0x5f, 0x24, 0x64, 0xf0, + 0x44, 0xca, 0xfb, 0x18, 0x2e, 0xa9, 0x48, 0xdf, 0xd3, 0x61, 0xac, 0xfd, 0x62, 0xea, 0x2e, 0xc6, + 0x10, 0xfa, 0xb9, 0xa5, 0x92, 0x37, 0x43, 0x41, 0x8d, 0x7a, 0x6a, 0xbe, 0x15, 0x4f, 0x02, 0x53, + 0xe4, 0x35, 0xea, 0x19, 0xff, 0x22, 0x07, 0x84, 0xd7, 0x54, 0xb6, 0x3b, 0x36, 0x7a, 0x66, 0x3b, + 0x18, 0x6b, 0xa9, 0x20, 0x70, 0xec, 0x9d, 0x26, 0x55, 0x03, 0x95, 0x09, 0xe3, 0xda, 0xb0, 0xcc, + 0x8a, 0x5f, 0x74, 0x12, 0x84, 0x3d, 0xb6, 0xba, 0xec, 0xe3, 0x6c, 0x75, 0x5f, 0x83, 0x67, 0x4b, + 0x1d, 0x4c, 0xbf, 0x2d, 0x6b, 0xb9, 0xed, 0x7a, 0x72, 0x93, 0xd2, 0x7c, 0xfe, 0xec, 0x10, 0x2d, + 0xf1, 0xa5, 0xfd, 0x58, 0x28, 0x72, 0x0a, 0x9b, 0x97, 0x9d, 0x40, 0x8d, 0x21, 0x21, 0xe5, 0x94, + 0x0e, 0x96, 0xa4, 0xc8, 0x29, 0x9c, 0x44, 0xf2, 0x70, 0x3c, 0x29, 0xa7, 0x60, 0xb6, 0xb2, 0x88, + 0x87, 0xe3, 0xd1, 0x1e, 0xb2, 0x4e, 0x48, 0x42, 0xde, 0x81, 0xf1, 0x52, 0x37, 0x70, 0x05, 0x63, + 0x61, 0x15, 0x1e, 0xd9, 0x6f, 0x8b, 0x4f, 0xd1, 0xae, 0x3e, 0x11, 0xba, 0xf1, 0x27, 0x39, 0xb8, + 0x98, 0x1c, 0x5e, 0x51, 0x1a, 0xae, 0x8f, 0xcc, 0x29, 0xeb, 0x23, 0x6d, 0x36, 0x64, 0xa3, 0x4c, + 0x13, 0x4f, 0x62, 0x36, 0xf0, 0x2c, 0xde, 0x1f, 0x73, 0x36, 0xd4, 0x60, 0x5c, 0x3d, 0xef, 0x86, + 0x3e, 0xee, 0x79, 0xa7, 0x72, 0x61, 0x97, 0x7a, 0x1e, 0x3a, 0x63, 0x38, 0x7a, 0x3a, 0x8a, 0x47, + 0xcd, 0xe0, 0x18, 0xe4, 0xdf, 0x81, 0x4b, 0x7c, 0x4f, 0x8a, 0x37, 0x76, 0xe9, 0x48, 0x72, 0x14, + 0x03, 0xb7, 0x78, 0x72, 0x5c, 0xbc, 0xc6, 0x55, 0x25, 0x56, 0xa2, 0xdb, 0xac, 0x9d, 0x23, 0x4b, + 0x7e, 0x99, 0x52, 0xc9, 0xa9, 0xbc, 0x8d, 0x32, 0x5c, 0x14, 0xa5, 0x91, 0xd3, 0xb6, 0x2c, 0x64, + 0x83, 0x7c, 0x10, 0x69, 0xbb, 0x70, 0x90, 0x63, 0x8a, 0x2c, 0x2c, 0xc7, 0xfc, 0xdf, 0x4a, 0x6e, + 0xe6, 0x37, 0xd2, 0x7c, 0x6e, 0x78, 0xd4, 0x6e, 0x0e, 0xd6, 0xdd, 0x6d, 0xa4, 0x4e, 0x2d, 0x9b, + 0xaa, 0x53, 0x93, 0x4a, 0x99, 0x5c, 0xaa, 0x52, 0xa6, 0x02, 0xd3, 0xb5, 0xee, 0x8e, 0xac, 0x3b, + 0xee, 0xaf, 0xe9, 0x77, 0x77, 0xd2, 0x7a, 0x25, 0x4e, 0x62, 0xfc, 0x68, 0x16, 0x26, 0x36, 0x9a, + 0xdd, 0x3d, 0xa7, 0x5d, 0xb1, 0x03, 0xfb, 0xa9, 0x55, 0xf3, 0xbd, 0xa5, 0xa9, 0xf9, 0x42, 0xd7, + 0xb2, 0xb0, 0x61, 0x03, 0xe9, 0xf8, 0x7e, 0x36, 0x03, 0xd3, 0x11, 0x09, 0x3f, 0xac, 0x57, 0x60, + 0x88, 0xfd, 0x10, 0x97, 0xdf, 0x4b, 0x09, 0xc6, 0x3c, 0xcd, 0x64, 0xf8, 0x97, 0x50, 0xbc, 0xe9, + 0x39, 0xdc, 0x90, 0xc3, 0xc2, 0x67, 0x61, 0x2c, 0x62, 0x7b, 0x96, 0xf4, 0x92, 0xbf, 0x91, 0x81, + 0x42, 0xbc, 0x25, 0xe4, 0x1e, 0x8c, 0x32, 0x4e, 0x0e, 0x95, 0xf7, 0xf2, 0x97, 0x7b, 0xb4, 0xf9, + 0x9a, 0x40, 0xe3, 0x9f, 0x87, 0x9d, 0x4f, 0x39, 0xc4, 0x94, 0x1c, 0x16, 0x4c, 0x98, 0x50, 0xb1, + 0x52, 0xbe, 0xee, 0x75, 0x5d, 0x42, 0x39, 0x9f, 0xde, 0x0f, 0x5a, 0x52, 0x4c, 0xed, 0xab, 0x85, + 0xf0, 0x71, 0x59, 0x9b, 0x5c, 0xa9, 0xab, 0x0a, 0x27, 0xcd, 0x62, 0x94, 0xaf, 0x40, 0x9d, 0x67, + 0x29, 0x13, 0x3a, 0xc4, 0x23, 0xaf, 0xc3, 0x08, 0xaf, 0x4f, 0x4d, 0xe8, 0xd6, 0x41, 0x88, 0x2a, + 0x27, 0x73, 0x1c, 0xe3, 0x6f, 0xe7, 0xe0, 0x7c, 0xf4, 0x79, 0x5b, 0x9d, 0x86, 0x1d, 0xd0, 0x0d, + 0xdb, 0xb3, 0x5b, 0xfe, 0x29, 0x2b, 0xe0, 0x4a, 0xe2, 0xd3, 0x30, 0x95, 0x96, 0xfc, 0x34, 0xe5, + 0x83, 0x8c, 0xd8, 0x07, 0xa1, 0x0e, 0x94, 0x7f, 0x90, 0xfc, 0x0c, 0x72, 0x0f, 0x72, 0x35, 0x1a, + 0x88, 0xbd, 0xf7, 0x72, 0xa2, 0x57, 0xd5, 0xef, 0xba, 0x56, 0xa3, 0x01, 0x1f, 0x44, 0x1e, 0x17, + 0x4a, 0x0b, 0xce, 0xc7, 0xb8, 0x90, 0x6d, 0x18, 0x59, 0x7e, 0xd4, 0xa1, 0xf5, 0x40, 0x24, 0x47, + 0xbd, 0xda, 0x9f, 0x1f, 0xc7, 0x55, 0x72, 0xa3, 0x52, 0x04, 0xa8, 0x9d, 0xc5, 0x51, 0x16, 0x6e, + 0x41, 0x5e, 0x56, 0x7e, 0x96, 0x99, 0xbb, 0xf0, 0x16, 0x8c, 0x2b, 0x95, 0x9c, 0x69, 0xd2, 0xff, + 0x22, 0xdb, 0x57, 0xdd, 0xa6, 0xcc, 0xa7, 0xba, 0x9c, 0x90, 0x15, 0x95, 0x6c, 0x54, 0x5c, 0x56, + 0xb4, 0x0e, 0x44, 0x51, 0x1f, 0xa1, 0xb1, 0x0a, 0xd3, 0xb5, 0x03, 0xa7, 0x13, 0x05, 0x8a, 0xd5, + 0x4e, 0x64, 0xcc, 0x78, 0x23, 0x2e, 0xee, 0xf1, 0x13, 0x39, 0x4e, 0x67, 0xfc, 0x79, 0x06, 0x46, + 0xd8, 0x5f, 0x0f, 0x6e, 0x3d, 0xa5, 0x5b, 0xe6, 0x4d, 0x6d, 0xcb, 0x9c, 0x51, 0x62, 0xb5, 0xe3, + 0xc6, 0x71, 0xeb, 0x94, 0xcd, 0xf2, 0x58, 0x0c, 0x10, 0x47, 0x26, 0x77, 0x60, 0x54, 0x98, 0x14, + 0x09, 0xdb, 0x6f, 0x35, 0xf8, 0xbb, 0x34, 0x36, 0x0a, 0x6f, 0xf8, 0x6e, 0x27, 0xae, 0x12, 0x91, + 0xd4, 0x4c, 0xae, 0x97, 0x21, 0x7b, 0xb5, 0x7c, 0xe9, 0x2e, 0x3a, 0xeb, 0xf1, 0xd0, 0xe5, 0xfe, + 0xd2, 0x05, 0xc1, 0xa9, 0x97, 0x6f, 0x7d, 0x49, 0xbc, 0x86, 0xe4, 0xfa, 0x31, 0x39, 0x2f, 0x93, + 0x14, 0xa7, 0x3e, 0x94, 0xb4, 0xe0, 0x7c, 0xad, 0xb6, 0x82, 0xe6, 0x87, 0x1b, 0xae, 0x17, 0xdc, + 0x76, 0xbd, 0x43, 0x1b, 0x6d, 0x8b, 0x51, 0xc3, 0xa7, 0xd8, 0x20, 0xa4, 0x19, 0x85, 0xbd, 0x9a, + 0x6a, 0x14, 0xd6, 0xc7, 0x4e, 0xc1, 0x68, 0xc3, 0x85, 0x5a, 0x6d, 0x85, 0x07, 0x0e, 0xff, 0x8b, + 0xa8, 0xef, 0x37, 0x32, 0x30, 0x53, 0xab, 0xad, 0xc4, 0xaa, 0x5a, 0x95, 0x11, 0xcb, 0x33, 0x7a, + 0x9e, 0xef, 0xd4, 0x8e, 0xc0, 0x51, 0xc8, 0x70, 0x09, 0xaf, 0xae, 0x05, 0xa7, 0xe4, 0x4c, 0xc8, + 0x46, 0x18, 0x23, 0x3d, 0xab, 0xf9, 0x03, 0xf4, 0x68, 0x28, 0x6a, 0xb8, 0x85, 0x37, 0x1d, 0x2b, + 0xd5, 0x35, 0xdc, 0x0c, 0x62, 0xfc, 0x37, 0xe7, 0x79, 0x14, 0x76, 0x39, 0x5b, 0xde, 0x85, 0x09, + 0x41, 0x8f, 0x46, 0xf3, 0xc2, 0x26, 0xe4, 0x22, 0xdb, 0x20, 0x77, 0x39, 0x9c, 0x47, 0xe7, 0xfd, + 0xf6, 0x71, 0x71, 0x88, 0x75, 0x8d, 0xa9, 0xa1, 0x93, 0xfb, 0x30, 0xb9, 0x66, 0x3f, 0x52, 0xd4, + 0x19, 0xdc, 0x25, 0xea, 0x2a, 0xdb, 0x55, 0x5a, 0xf6, 0xa3, 0x01, 0x8c, 0xee, 0x74, 0x7a, 0x72, + 0x00, 0x53, 0x7a, 0x9b, 0xc4, 0x0c, 0x4c, 0x8e, 0xd8, 0x8d, 0xd4, 0x11, 0xbb, 0xd8, 0x71, 0xbd, + 0xc0, 0xda, 0x0d, 0xc9, 0xb5, 0x8c, 0x03, 0x31, 0xd6, 0xe4, 0x5d, 0x98, 0x51, 0x42, 0x80, 0xde, + 0x76, 0xbd, 0x96, 0x2d, 0x2f, 0x5c, 0xa8, 0xe3, 0x47, 0x5b, 0xa2, 0x5d, 0x04, 0x9b, 0x49, 0x4c, + 0xf2, 0xa5, 0x34, 0x37, 0xb3, 0xe1, 0xc8, 0xf2, 0x30, 0xc5, 0xcd, 0xac, 0x97, 0xe5, 0x61, 0xd2, + 0xe1, 0x6c, 0xaf, 0x9f, 0x65, 0x72, 0x9e, 0xb7, 0x7e, 0x20, 0xcb, 0xe3, 0x70, 0xe4, 0x7a, 0x58, + 0x20, 0x2f, 0x42, 0x6e, 0x69, 0xe3, 0x36, 0xbe, 0x4c, 0x49, 0x23, 0xaa, 0xf6, 0xbe, 0xdd, 0xae, + 0xe3, 0x45, 0x48, 0x78, 0x03, 0xa8, 0x07, 0xe5, 0xd2, 0xc6, 0x6d, 0x62, 0xc3, 0x2c, 0xe6, 0x79, + 0x0b, 0xbe, 0x78, 0xe3, 0x86, 0x32, 0x54, 0x79, 0xfc, 0xb4, 0xeb, 0xe2, 0xd3, 0x8a, 0x98, 0x25, + 0x2e, 0xb0, 0x1e, 0xdd, 0xb8, 0x91, 0x3a, 0x20, 0xe1, 0x87, 0xa5, 0xf1, 0x62, 0x07, 0xd6, 0x9a, + 0xfd, 0x28, 0x72, 0xe2, 0xf0, 0x85, 0xc3, 0xee, 0xf3, 0x72, 0x6a, 0x45, 0x0e, 0x20, 0xda, 0x81, + 0xa5, 0x13, 0xb1, 0x7b, 0x6c, 0x34, 0xc1, 0x7c, 0xe1, 0xea, 0xb4, 0x20, 0xd5, 0x75, 0xd2, 0xab, + 0x5b, 0xbd, 0x8c, 0x29, 0xe8, 0x64, 0x2b, 0xbc, 0x8d, 0xf3, 0xdb, 0xac, 0xc8, 0x8c, 0x7c, 0x5d, + 0xbd, 0x8d, 0x73, 0x25, 0x99, 0xd6, 0xac, 0xe9, 0x50, 0x85, 0xc3, 0xbd, 0x5a, 0x4c, 0x9d, 0x4b, + 0xf2, 0x92, 0x3f, 0x71, 0xf6, 0x4b, 0x3e, 0x85, 0xa1, 0x55, 0xb7, 0x7e, 0x20, 0x82, 0xf3, 0x7d, + 0xc0, 0x76, 0x61, 0x3d, 0x8d, 0xfe, 0xe3, 0x5a, 0x5c, 0x23, 0x7b, 0xb2, 0xce, 0x3e, 0x95, 0xcd, + 0x02, 0xd1, 0x27, 0xc2, 0x8a, 0x77, 0x2e, 0xbc, 0xe5, 0x2a, 0x65, 0x5c, 0x1e, 0xe5, 0x93, 0x46, + 0x76, 0xad, 0xa9, 0x93, 0x13, 0x0a, 0x85, 0x0a, 0xf5, 0x0f, 0x02, 0xb7, 0x53, 0x6e, 0x3a, 0x9d, + 0x1d, 0xd7, 0xf6, 0x64, 0x28, 0xe7, 0x81, 0xf7, 0xe4, 0x06, 0xa7, 0xb7, 0xea, 0x92, 0x81, 0x99, + 0x60, 0x49, 0xbe, 0x04, 0x53, 0x6c, 0x72, 0x2f, 0x3f, 0x0a, 0x68, 0x9b, 0x8f, 0xfc, 0x0c, 0x4a, + 0x74, 0x73, 0x4a, 0xee, 0x92, 0xb0, 0x90, 0xcf, 0x29, 0x5c, 0xec, 0x34, 0x24, 0xd0, 0x02, 0x1b, + 0x6a, 0xac, 0x48, 0x03, 0xe6, 0xd7, 0xec, 0x47, 0x4a, 0x0e, 0x66, 0x65, 0x92, 0x12, 0x9c, 0x60, + 0x57, 0x4e, 0x8e, 0x8b, 0x2f, 0xb3, 0x09, 0x16, 0x45, 0x17, 0xef, 0x31, 0x5f, 0x7b, 0x72, 0x22, + 0xdf, 0x80, 0x0b, 0xa2, 0x59, 0x15, 0xcc, 0x1b, 0xe6, 0x7a, 0x47, 0xb5, 0x7d, 0x1b, 0xfd, 0xb7, + 0x66, 0x7b, 0x74, 0xd8, 0xf5, 0xf4, 0x2d, 0x51, 0x76, 0x58, 0x43, 0xf2, 0xb1, 0x7c, 0xce, 0xc8, + 0xec, 0x55, 0x03, 0xf9, 0x08, 0xa6, 0xf8, 0x73, 0xdc, 0x8a, 0xeb, 0x07, 0xa8, 0xac, 0x99, 0x3b, + 0x9b, 0x5b, 0x02, 0x7f, 0xe3, 0xe3, 0x8e, 0x3c, 0x31, 0xe5, 0x4e, 0x8c, 0x33, 0x79, 0x1b, 0xc6, + 0x37, 0x9c, 0x36, 0x0f, 0x3d, 0x5a, 0xdd, 0x40, 0xb5, 0xb2, 0x38, 0x81, 0x3a, 0x4e, 0xdb, 0x92, + 0x1a, 0x93, 0x4e, 0xb8, 0x5d, 0xa8, 0xd8, 0x64, 0x1b, 0xc6, 0x6b, 0xb5, 0x95, 0xdb, 0x0e, 0x93, + 0x4b, 0x3a, 0x47, 0xf3, 0xe7, 0x7b, 0x7c, 0xe5, 0x4b, 0xa9, 0x5f, 0x39, 0xe9, 0xfb, 0xfb, 0xd6, + 0xae, 0xd3, 0xa4, 0x56, 0xdd, 0xed, 0x1c, 0x99, 0x2a, 0xa7, 0x14, 0x53, 0xfd, 0x0b, 0x4f, 0xd8, + 0x54, 0xbf, 0x0a, 0xd3, 0x8a, 0xf1, 0x2c, 0x1a, 0xce, 0xce, 0x47, 0xf1, 0xaa, 0x54, 0xd3, 0xfc, + 0xb8, 0x6b, 0x6a, 0x9c, 0x4e, 0xda, 0xe8, 0x5f, 0x3c, 0xab, 0x8d, 0xbe, 0x03, 0x33, 0x7c, 0x30, + 0xc4, 0x3c, 0xc0, 0x91, 0x5e, 0xe8, 0xd1, 0x87, 0x57, 0x53, 0xfb, 0x70, 0x56, 0x8c, 0xb4, 0x9c, + 0x64, 0xf8, 0xfc, 0x9c, 0xe4, 0x4a, 0x76, 0x81, 0x08, 0xa0, 0x1d, 0xd8, 0x3b, 0xb6, 0x4f, 0xb1, + 0xae, 0x67, 0x7b, 0xd4, 0xf5, 0x72, 0x6a, 0x5d, 0x53, 0xb2, 0xae, 0x1d, 0x5e, 0x4d, 0x0a, 0x47, + 0xd2, 0x96, 0xf5, 0xc8, 0xf9, 0x85, 0x1d, 0xfb, 0x9c, 0xa6, 0xe3, 0x4e, 0x22, 0xf0, 0xd0, 0x4f, + 0xf1, 0x49, 0x1b, 0xef, 0xf7, 0x14, 0xce, 0xe4, 0x11, 0x9c, 0x4f, 0x7e, 0x05, 0xd6, 0xf9, 0x3c, + 0xd6, 0xf9, 0xbc, 0x56, 0x67, 0x1c, 0x89, 0xcf, 0x1b, 0xbd, 0x59, 0xf1, 0x5a, 0x7b, 0xf0, 0x27, + 0x3f, 0x94, 0x81, 0x0b, 0x6b, 0xb7, 0x4b, 0x98, 0x4d, 0xd4, 0xe1, 0x91, 0xe8, 0x42, 0x97, 0xde, + 0x17, 0xc4, 0x3b, 0x48, 0xfc, 0x6d, 0x46, 0x4a, 0x1c, 0xb8, 0x55, 0x30, 0xd1, 0xfd, 0xa5, 0xd6, + 0xae, 0xcd, 0x93, 0x94, 0x0a, 0x16, 0x29, 0x7e, 0xbf, 0xdf, 0xfc, 0xa3, 0x62, 0xc6, 0xec, 0x55, + 0x15, 0x69, 0xc2, 0x82, 0xde, 0x2d, 0xd2, 0x8b, 0x62, 0x9f, 0x36, 0x9b, 0xf3, 0x45, 0x9c, 0xd1, + 0xaf, 0x9f, 0x1c, 0x17, 0xaf, 0x24, 0x7a, 0x37, 0xf4, 0xcc, 0x60, 0x98, 0x4a, 0x83, 0xfb, 0xf0, + 0x23, 0xad, 0x14, 0xa1, 0x7b, 0xfe, 0x92, 0x16, 0xfb, 0x27, 0x51, 0xbe, 0xf4, 0x8a, 0x90, 0x48, + 0x9e, 0x67, 0xeb, 0xbd, 0xa7, 0x80, 0x68, 0x26, 0x39, 0xdf, 0x1d, 0xca, 0x4f, 0x16, 0xa6, 0x52, + 0x5c, 0x16, 0x8c, 0xdf, 0xce, 0xc6, 0x0e, 0x46, 0x52, 0x85, 0x51, 0x31, 0xdf, 0x7b, 0x5e, 0x32, + 0x9e, 0x4f, 0x9d, 0xd5, 0xa3, 0x62, 0xe9, 0x98, 0x92, 0x9e, 0x1c, 0x32, 0x56, 0xd8, 0x68, 0x71, + 0xe3, 0xfd, 0x0a, 0x3f, 0xf7, 0x10, 0xa4, 0x9d, 0xf0, 0x95, 0xb3, 0x3b, 0xe2, 0xe9, 0x7e, 0x9e, + 0x78, 0xd4, 0xcb, 0xda, 0xc8, 0x01, 0x4f, 0x25, 0x95, 0x0b, 0xbd, 0xb9, 0xf4, 0xbc, 0x51, 0x4f, + 0xac, 0x42, 0x56, 0x8b, 0xf1, 0x5b, 0x19, 0x98, 0xd4, 0x4e, 0x56, 0x72, 0x4b, 0x71, 0x55, 0x8c, + 0xbc, 0xf7, 0x35, 0x1c, 0xdc, 0x6c, 0xe3, 0x4e, 0x8c, 0xb7, 0x84, 0xdf, 0x41, 0xb6, 0x37, 0x1d, + 0x2e, 0xb6, 0xb8, 0xe7, 0x6a, 0x7f, 0xfd, 0x70, 0x98, 0x07, 0x73, 0xa8, 0x47, 0x1e, 0xcc, 0xbf, + 0x57, 0x84, 0x29, 0xfd, 0x46, 0x4c, 0x5e, 0x87, 0x11, 0xd4, 0xcd, 0x4b, 0xf5, 0x0a, 0xaa, 0x85, + 0x50, 0x7d, 0xaf, 0x39, 0xa3, 0x70, 0x1c, 0xf2, 0x0a, 0x40, 0x68, 0x00, 0x2e, 0x5f, 0xa6, 0x86, + 0x4f, 0x8e, 0x8b, 0x99, 0x37, 0x4c, 0xa5, 0x80, 0x7c, 0x15, 0x60, 0xdd, 0x6d, 0xd0, 0x30, 0xb9, + 0x71, 0x1f, 0xeb, 0x8b, 0x57, 0x13, 0x69, 0x56, 0xce, 0xb5, 0xdd, 0x06, 0x4d, 0xe6, 0x54, 0x51, + 0x38, 0x92, 0xcf, 0xc3, 0xb0, 0xd9, 0x6d, 0x52, 0xf9, 0x82, 0x31, 0x2e, 0x4f, 0xb8, 0x6e, 0x93, + 0x46, 0x7a, 0x02, 0xaf, 0x1b, 0x37, 0x2c, 0x64, 0x00, 0xf2, 0x3e, 0x4f, 0xbf, 0x22, 0x62, 0x84, + 0x0e, 0x47, 0x6f, 0x75, 0x8a, 0xe4, 0x93, 0x88, 0x12, 0xaa, 0x90, 0x90, 0xfb, 0x30, 0xaa, 0x3e, + 0x32, 0x29, 0x3e, 0xef, 0xea, 0x43, 0xa4, 0xa2, 0x74, 0x10, 0x59, 0x91, 0xe3, 0xef, 0x4f, 0x92, + 0x0b, 0x79, 0x07, 0xc6, 0x18, 0x7b, 0xb6, 0x73, 0xf8, 0xe2, 0x56, 0x83, 0x2f, 0x72, 0xca, 0x07, + 0xb1, 0xdd, 0x47, 0x8b, 0xe4, 0x19, 0x12, 0x90, 0x2f, 0x61, 0x1e, 0x5b, 0xd1, 0xd5, 0x7d, 0xad, + 0x72, 0x2e, 0x27, 0xba, 0x1a, 0x13, 0xdb, 0x26, 0x7a, 0x3a, 0xe2, 0x47, 0xf6, 0xc2, 0x90, 0x6b, + 0x83, 0xa4, 0xcc, 0x79, 0x2d, 0x51, 0xc1, 0xbc, 0x8c, 0x22, 0x96, 0x4c, 0x52, 0xad, 0xf1, 0x25, + 0x1d, 0x28, 0x44, 0x42, 0xa5, 0xa8, 0x0b, 0xfa, 0xd5, 0xf5, 0x46, 0xa2, 0x2e, 0x75, 0x00, 0x13, + 0xd5, 0x25, 0xb8, 0x93, 0x06, 0x4c, 0xc9, 0x03, 0x4a, 0xd4, 0x37, 0xde, 0xaf, 0xbe, 0x57, 0x12, + 0xf5, 0xcd, 0x36, 0x76, 0x92, 0xf5, 0xc4, 0x78, 0x92, 0x77, 0x60, 0x52, 0x42, 0x78, 0xca, 0xe8, + 0x89, 0x28, 0xe7, 0x6e, 0x63, 0x27, 0x91, 0x28, 0x5a, 0x47, 0x56, 0xa9, 0xf9, 0xec, 0x98, 0xd4, + 0xa8, 0xe3, 0xb3, 0x42, 0x47, 0x26, 0x1f, 0xc2, 0x78, 0xb5, 0xc5, 0x1a, 0xe2, 0xb6, 0xed, 0x80, + 0x0a, 0x7f, 0x48, 0x69, 0x61, 0xa4, 0x94, 0x28, 0x53, 0x95, 0x27, 0xc3, 0x8e, 0x8a, 0xb4, 0x64, + 0xd8, 0x11, 0x98, 0x75, 0x1e, 0x7f, 0x55, 0x14, 0x73, 0x58, 0xfa, 0x4a, 0x3e, 0x9f, 0x62, 0xe5, + 0xa3, 0xb0, 0x17, 0xf1, 0x20, 0x19, 0x54, 0xbe, 0xea, 0xc5, 0x62, 0xf1, 0xaa, 0x3c, 0xc9, 0xbb, + 0x30, 0x2e, 0xb2, 0x89, 0x95, 0xcc, 0x75, 0x7f, 0xbe, 0x80, 0x8d, 0xc7, 0x08, 0x0f, 0x32, 0xf1, + 0x98, 0x65, 0x7b, 0x31, 0x73, 0xd6, 0x08, 0x9f, 0x7c, 0x11, 0xe6, 0xb6, 0x9d, 0x76, 0xc3, 0x3d, + 0xf4, 0xc5, 0x31, 0x25, 0x36, 0xba, 0x99, 0xc8, 0x99, 0xec, 0x90, 0x97, 0x87, 0xb2, 0x60, 0x62, + 0xe3, 0x4b, 0xe5, 0x40, 0xbe, 0x27, 0xc1, 0x99, 0xcf, 0x20, 0xd2, 0x6f, 0x06, 0x2d, 0x26, 0x66, + 0x50, 0xb2, 0xfa, 0xf8, 0x74, 0x4a, 0xad, 0x86, 0xb8, 0x40, 0xf4, 0xf3, 0xfd, 0xae, 0xeb, 0xb4, + 0xe7, 0x67, 0x71, 0x2f, 0x7c, 0x36, 0x1e, 0x53, 0x01, 0xf1, 0x44, 0x52, 0x71, 0xe3, 0xe4, 0xb8, + 0xf8, 0x42, 0x5c, 0xe6, 0xff, 0xc8, 0xd5, 0x9e, 0x4b, 0x52, 0x58, 0x93, 0x0f, 0x61, 0x82, 0xfd, + 0x1f, 0x2a, 0x25, 0xe6, 0x34, 0xbb, 0x50, 0x05, 0x53, 0xd4, 0x83, 0x63, 0x84, 0xe9, 0xce, 0x52, + 0xf4, 0x15, 0x1a, 0x2b, 0xf2, 0x16, 0x00, 0x13, 0x9b, 0xc4, 0x76, 0x7c, 0x2e, 0x0a, 0x7d, 0x8c, + 0x52, 0x57, 0x72, 0x23, 0x8e, 0x90, 0xc9, 0x3b, 0x30, 0xce, 0x7e, 0xd5, 0xba, 0x0d, 0x97, 0xad, + 0x8d, 0xf3, 0x48, 0xcb, 0x5d, 0x53, 0x19, 0xad, 0xcf, 0xe1, 0x9a, 0x6b, 0x6a, 0x84, 0x4e, 0x56, + 0x60, 0x1a, 0x43, 0x54, 0x8b, 0xe0, 0xa8, 0x0e, 0xf5, 0xe7, 0x2f, 0x28, 0xd6, 0x10, 0xac, 0xc8, + 0x72, 0xc2, 0x32, 0xf5, 0x2e, 0x13, 0x23, 0x23, 0x3e, 0xcc, 0x26, 0x9f, 0x93, 0xfd, 0xf9, 0x79, + 0xec, 0x24, 0x29, 0xc1, 0x27, 0x31, 0xf8, 0x7e, 0xcc, 0x46, 0x44, 0xd9, 0xb8, 0xe4, 0xa3, 0x92, + 0x5a, 0x61, 0x1a, 0x77, 0x62, 0x02, 0xb9, 0x53, 0xde, 0x88, 0xc7, 0x70, 0xbe, 0x88, 0x2d, 0xc0, + 0x61, 0xde, 0xab, 0x47, 0x59, 0xc4, 0x53, 0xe2, 0x38, 0xa7, 0x50, 0x93, 0xef, 0x86, 0x73, 0x72, + 0x07, 0x11, 0x45, 0x62, 0x5e, 0x2f, 0x9c, 0x71, 0x27, 0x6e, 0xec, 0x84, 0x55, 0x27, 0xa6, 0x74, + 0x7a, 0x15, 0xc4, 0x86, 0x71, 0x1c, 0x56, 0x51, 0xe3, 0xb3, 0xfd, 0x6a, 0xbc, 0x92, 0xa8, 0xf1, + 0x3c, 0x4e, 0x94, 0x64, 0x65, 0x2a, 0x4f, 0xb2, 0x04, 0x93, 0x62, 0x1d, 0x89, 0xd9, 0xf6, 0x1c, + 0xf6, 0x16, 0x2a, 0xb1, 0xe4, 0x0a, 0x4c, 0x4c, 0x38, 0x9d, 0x44, 0xdd, 0x91, 0xf9, 0x63, 0xd2, + 0xf3, 0xda, 0x8e, 0x1c, 0x7f, 0x43, 0xd2, 0x91, 0xd9, 0x8e, 0x14, 0x49, 0x31, 0xcb, 0x8f, 0x3a, + 0x9e, 0x50, 0x51, 0xbd, 0x10, 0x65, 0x45, 0x52, 0x84, 0x1f, 0x8b, 0x86, 0x18, 0xea, 0x96, 0x90, + 0xc6, 0x81, 0x6c, 0xc1, 0x6c, 0x78, 0x6a, 0x2b, 0x8c, 0x8b, 0x51, 0x94, 0xe0, 0xe8, 0xa8, 0x4f, + 0xe7, 0x9b, 0x46, 0x4f, 0x6c, 0xb8, 0xa0, 0x9d, 0xd3, 0x0a, 0xeb, 0x4b, 0xc8, 0x1a, 0xb3, 0xd6, + 0xeb, 0x87, 0x7c, 0x3a, 0xfb, 0x5e, 0x7c, 0xc8, 0x47, 0xb0, 0x10, 0x3f, 0x9b, 0x95, 0x5a, 0x5e, + 0xc4, 0x5a, 0x5e, 0x3b, 0x39, 0x2e, 0x5e, 0x4e, 0x1c, 0xef, 0xe9, 0x15, 0xf5, 0xe1, 0x46, 0xbe, + 0x0a, 0xf3, 0xfa, 0xf9, 0xac, 0xd4, 0x64, 0x60, 0x4d, 0xb8, 0x74, 0xc2, 0x83, 0x3d, 0xbd, 0x86, + 0x9e, 0x3c, 0x48, 0x00, 0xc5, 0xd4, 0xd9, 0xad, 0x54, 0xf3, 0x52, 0xd4, 0xa0, 0xc4, 0x2a, 0x49, + 0xaf, 0xee, 0x34, 0x96, 0xe4, 0x10, 0x5e, 0x48, 0x3b, 0x26, 0x94, 0x4a, 0x5f, 0x0e, 0x95, 0xc0, + 0x9f, 0x4a, 0x3f, 0x72, 0xd2, 0x6b, 0x3e, 0x85, 0x2d, 0xf9, 0x12, 0x9c, 0x53, 0xd6, 0x97, 0x52, + 0xdf, 0x2b, 0x58, 0x1f, 0xba, 0x82, 0xab, 0x0b, 0x33, 0xbd, 0x96, 0x74, 0x1e, 0xa4, 0x05, 0xb3, + 0xb2, 0xe1, 0xa8, 0x6d, 0x17, 0x47, 0xcf, 0x65, 0x6d, 0x57, 0x4d, 0x62, 0x2c, 0x5d, 0x12, 0xbb, + 0xea, 0x7c, 0x63, 0xc7, 0xea, 0x44, 0x84, 0xea, 0x4c, 0x4f, 0xe1, 0x4b, 0x56, 0x60, 0xa4, 0xb6, + 0x51, 0xbd, 0x7d, 0x7b, 0x79, 0xfe, 0x55, 0xac, 0x41, 0xfa, 0x8d, 0x71, 0xa0, 0x76, 0x69, 0x12, + 0xe6, 0x8a, 0x1d, 0x67, 0x77, 0x57, 0x7b, 0xb0, 0xe2, 0xa8, 0xe4, 0x7b, 0xd0, 0x50, 0x90, 0xed, + 0xa8, 0x25, 0xdf, 0x77, 0xf6, 0x30, 0xea, 0xb4, 0x3f, 0xff, 0x9a, 0xf6, 0xde, 0x2f, 0x23, 0x72, + 0x97, 0x31, 0x61, 0x59, 0x02, 0x9d, 0x4b, 0x9b, 0xec, 0xfe, 0x2f, 0x76, 0x6e, 0xcb, 0x8e, 0x58, + 0xa9, 0x9b, 0x78, 0xb2, 0x22, 0xd6, 0x6f, 0x7b, 0x4e, 0x60, 0xed, 0x77, 0xb5, 0xe6, 0xcf, 0x7f, + 0x4a, 0x8b, 0xc0, 0xcc, 0xd3, 0xb8, 0x29, 0xbd, 0xf6, 0xb2, 0xa8, 0xf0, 0x39, 0x7e, 0x5b, 0xee, + 0xd1, 0x73, 0x33, 0x7b, 0x31, 0x3a, 0x9f, 0xfc, 0x60, 0x06, 0xce, 0x6f, 0xbb, 0xde, 0x41, 0xd3, + 0xb5, 0x1b, 0xb2, 0x55, 0x62, 0x0f, 0x7f, 0xbd, 0xdf, 0x1e, 0xfe, 0x99, 0xc4, 0x1e, 0x6e, 0x1c, + 0x0a, 0x36, 0x56, 0x18, 0xd0, 0x3c, 0xb1, 0x9f, 0xf7, 0xa8, 0x8a, 0x7c, 0x0f, 0x5c, 0x4a, 0x2f, + 0x51, 0x26, 0xe5, 0x1b, 0x38, 0x29, 0x6f, 0x9c, 0x1c, 0x17, 0xdf, 0xe8, 0x55, 0x53, 0xfa, 0x04, + 0x3d, 0x95, 0xf5, 0xdd, 0xa1, 0xfc, 0x95, 0xc2, 0xd5, 0xbb, 0x43, 0xf9, 0xab, 0x85, 0xd7, 0xcc, + 0xe7, 0x6a, 0xa5, 0xb5, 0xd5, 0x6a, 0x43, 0x1e, 0xae, 0x32, 0xe6, 0x3a, 0xa7, 0x31, 0x2f, 0xf7, + 0x2b, 0x8d, 0x38, 0x1a, 0x7f, 0x33, 0x03, 0xc5, 0x53, 0x26, 0x09, 0x3b, 0xcf, 0xa2, 0x91, 0xa8, + 0xd1, 0x40, 0x8d, 0xdc, 0x1e, 0x8d, 0x9f, 0xa5, 0x9b, 0x8d, 0xe8, 0x24, 0xe8, 0x74, 0x28, 0xd2, + 0x85, 0x28, 0xbe, 0xa7, 0xc9, 0x34, 0x21, 0x12, 0xcb, 0x58, 0x85, 0x42, 0x7c, 0xf2, 0x90, 0xcf, + 0xc1, 0xa4, 0x9a, 0xac, 0x40, 0xaa, 0x12, 0x78, 0xa0, 0x11, 0x6f, 0x4f, 0x3b, 0x10, 0x35, 0x44, + 0xe3, 0x17, 0x33, 0x30, 0x9b, 0xb2, 0xc2, 0xc8, 0x65, 0x18, 0xc2, 0x6c, 0x62, 0x8a, 0xd5, 0x50, + 0x2c, 0x8b, 0x18, 0x96, 0x93, 0x4f, 0xc3, 0x68, 0x65, 0xbd, 0x56, 0x2b, 0xad, 0x4b, 0x65, 0x04, + 0x3f, 0x88, 0xdb, 0xbe, 0xe5, 0xdb, 0xba, 0xb1, 0x81, 0x40, 0x23, 0x6f, 0xc0, 0x48, 0x75, 0x03, + 0x09, 0xb8, 0xed, 0x2b, 0xb6, 0xd7, 0xe9, 0xc4, 0xf1, 0x05, 0x92, 0xf1, 0xe3, 0x19, 0x20, 0xc9, + 0xed, 0x82, 0xdc, 0x80, 0x71, 0x75, 0x53, 0xe2, 0xed, 0xc5, 0x17, 0x58, 0x65, 0xe1, 0x98, 0x2a, + 0x0e, 0xa9, 0xc0, 0x30, 0xe6, 0x81, 0x0d, 0xad, 0x1c, 0x52, 0x97, 0xc5, 0x85, 0xc4, 0xb2, 0x18, + 0xc6, 0x2c, 0xb3, 0x26, 0x27, 0x36, 0x7e, 0x37, 0x03, 0x24, 0xdd, 0x76, 0x71, 0x20, 0x2b, 0xab, + 0x37, 0x95, 0xd8, 0x05, 0x6a, 0xbe, 0xa0, 0x30, 0xd9, 0x9b, 0xaa, 0x06, 0x88, 0xa2, 0x1c, 0x5c, + 0xd6, 0xd4, 0x4e, 0xbd, 0x1d, 0x5e, 0xaf, 0xc2, 0xf0, 0x03, 0xea, 0xed, 0x48, 0xb3, 0x6e, 0x34, + 0x05, 0x7d, 0xc8, 0x00, 0xaa, 0x1a, 0x06, 0x31, 0x8c, 0x3f, 0xc9, 0xc0, 0x5c, 0xda, 0x1d, 0xe5, + 0x14, 0xbf, 0x54, 0x23, 0xe6, 0x52, 0x8b, 0x16, 0x56, 0xdc, 0x4e, 0x34, 0x74, 0xa4, 0x2d, 0xc2, + 0x30, 0x6b, 0xac, 0x1c, 0x61, 0x54, 0x83, 0xb1, 0xde, 0xf0, 0x4d, 0x0e, 0x67, 0x08, 0x3c, 0x46, + 0xdf, 0x10, 0x86, 0x77, 0x44, 0x04, 0x9c, 0xdd, 0x26, 0x87, 0x33, 0x84, 0x35, 0xb7, 0x41, 0xa5, + 0x7a, 0x08, 0x11, 0x5a, 0x0c, 0x60, 0x72, 0x38, 0xb9, 0x0c, 0xa3, 0xf7, 0xdb, 0xab, 0xd4, 0x7e, + 0x28, 0x73, 0x56, 0xa0, 0x45, 0x98, 0xdb, 0xb6, 0x9a, 0x0c, 0x66, 0xca, 0x42, 0xe3, 0x67, 0x33, + 0x30, 0x93, 0xb8, 0x1e, 0x9d, 0xee, 0x7a, 0xdb, 0xdf, 0x07, 0x6e, 0x90, 0xf6, 0xf1, 0xcf, 0x1f, + 0x4a, 0xff, 0x7c, 0xe3, 0xbf, 0x1b, 0x81, 0x0b, 0x3d, 0xb4, 0x55, 0x91, 0x8f, 0x6e, 0xe6, 0x54, + 0x1f, 0xdd, 0x2f, 0xc3, 0x64, 0xb9, 0x69, 0x3b, 0x2d, 0x7f, 0xd3, 0x8d, 0xbe, 0x38, 0x72, 0xf5, + 0xc1, 0x32, 0xe1, 0x07, 0x11, 0xfa, 0x84, 0x5c, 0xac, 0x23, 0x85, 0x15, 0xb8, 0x49, 0x61, 0x59, + 0x63, 0x96, 0xf0, 0x92, 0xcd, 0xfd, 0x25, 0xf1, 0x92, 0xd5, 0xfd, 0xb6, 0x86, 0x9e, 0xa8, 0xdf, + 0x56, 0xba, 0xcd, 0xf7, 0xf0, 0xe3, 0x78, 0x00, 0x94, 0x61, 0x92, 0x9b, 0xc4, 0x95, 0x7c, 0x3e, + 0x48, 0x23, 0x09, 0x33, 0x3a, 0xdb, 0x4f, 0x8e, 0x85, 0x46, 0x43, 0x56, 0x74, 0x1f, 0xa3, 0x51, + 0x7c, 0x33, 0xbe, 0xdc, 0xdb, 0x87, 0x48, 0xb3, 0x15, 0xd1, 0x7c, 0x89, 0xbe, 0x01, 0x73, 0x69, + 0xd7, 0xdd, 0xf9, 0xbc, 0x66, 0x6d, 0xdb, 0xd3, 0x4a, 0x7b, 0xf0, 0x4b, 0xf3, 0x41, 0xea, 0xa5, + 0x59, 0xfa, 0x7e, 0x8f, 0x69, 0x21, 0x9d, 0x7b, 0xac, 0x05, 0x8e, 0xdb, 0xdf, 0x43, 0xdc, 0xf8, + 0x32, 0x3c, 0xdf, 0x97, 0x9c, 0xbc, 0xad, 0xc5, 0x18, 0x7a, 0x35, 0x19, 0x63, 0xe8, 0xdb, 0xc7, + 0xc5, 0x19, 0xcd, 0x6f, 0x73, 0x2d, 0x54, 0xf8, 0x1b, 0x3f, 0x9b, 0xd5, 0x3d, 0x8e, 0xff, 0x32, + 0x2e, 0xd4, 0xab, 0x30, 0xbc, 0xbd, 0x4f, 0x3d, 0x79, 0x3c, 0xe0, 0x87, 0x1c, 0x32, 0x80, 0xfa, + 0x21, 0x88, 0x41, 0x6e, 0xc3, 0xd4, 0x06, 0x9f, 0xb8, 0x72, 0x36, 0x0e, 0x45, 0x3a, 0x97, 0x8e, + 0xd0, 0x0c, 0xa6, 0x4c, 0xc7, 0x18, 0x95, 0x71, 0x27, 0xd6, 0xe9, 0x22, 0x42, 0x12, 0xf7, 0x8c, + 0xe2, 0x02, 0xc4, 0x54, 0xe4, 0x0b, 0x16, 0x6d, 0xb6, 0x66, 0x0c, 0x6a, 0xec, 0xc2, 0x0b, 0x7d, + 0x19, 0xb1, 0x73, 0x1b, 0x3a, 0xe1, 0xaf, 0x98, 0xe5, 0x75, 0x5f, 0x52, 0x53, 0xa1, 0x33, 0xbe, + 0x01, 0x13, 0x6a, 0x2f, 0xe3, 0x11, 0xc4, 0x7e, 0x8b, 0x59, 0xc1, 0x8f, 0x20, 0x06, 0x30, 0x39, + 0x3c, 0x7a, 0xcb, 0xc9, 0xa6, 0xbf, 0xe5, 0x44, 0xc3, 0x9f, 0x3b, 0x6d, 0xf8, 0x59, 0xe5, 0xb8, + 0xc3, 0x29, 0x95, 0xe3, 0x6f, 0xb5, 0x72, 0x0c, 0x81, 0x64, 0x72, 0xf8, 0x13, 0xad, 0xfc, 0x9f, + 0xc8, 0x24, 0x67, 0xe8, 0x78, 0x25, 0x97, 0x7b, 0x26, 0xca, 0x54, 0x96, 0xb6, 0x7a, 0x23, 0xcc, + 0x48, 0xa6, 0xc8, 0x9e, 0x26, 0x53, 0x9c, 0x65, 0x22, 0xa2, 0xdc, 0xcb, 0x87, 0x74, 0x28, 0x92, + 0x03, 0xed, 0x84, 0xb5, 0x8b, 0xc4, 0x32, 0xbe, 0x99, 0x81, 0x73, 0xa9, 0x3a, 0x73, 0x56, 0x2b, + 0x57, 0xce, 0x2b, 0xeb, 0x30, 0xae, 0x99, 0xe7, 0x18, 0x67, 0x89, 0x7f, 0x31, 0x78, 0x5b, 0x8c, + 0x17, 0x61, 0x2c, 0x7c, 0xb1, 0x25, 0x73, 0x72, 0xe8, 0xd0, 0x2e, 0x52, 0x3e, 0xfc, 0xd5, 0x00, + 0xd8, 0x17, 0x3c, 0x51, 0xd3, 0x6a, 0xe3, 0x9f, 0x64, 0x79, 0x02, 0xdc, 0xa7, 0x36, 0x94, 0x6d, + 0xba, 0x3d, 0x34, 0x6b, 0x52, 0xef, 0x00, 0xb6, 0x64, 0x19, 0x46, 0x6a, 0x81, 0x1d, 0x74, 0x65, + 0xd8, 0x8e, 0x59, 0x95, 0x0c, 0x0b, 0x1e, 0x2c, 0x46, 0x81, 0x1b, 0x7c, 0x84, 0x68, 0x5a, 0x02, + 0x84, 0x28, 0x66, 0xd5, 0x7f, 0x90, 0x81, 0x09, 0x95, 0x98, 0x7c, 0x08, 0x53, 0x32, 0x40, 0x27, + 0x0f, 0x66, 0x22, 0x9e, 0x97, 0xa5, 0x29, 0x98, 0x0c, 0xd0, 0xa9, 0x06, 0x3f, 0xd1, 0xf0, 0xd5, + 0xad, 0xba, 0xa3, 0x22, 0x93, 0x06, 0x90, 0xd6, 0xae, 0x6d, 0x1d, 0x52, 0xfb, 0x80, 0xfa, 0x81, + 0xc5, 0x4d, 0x76, 0xc4, 0x2b, 0xb4, 0x64, 0xbf, 0x76, 0xbb, 0xc4, 0xad, 0x75, 0xd8, 0x48, 0x88, + 0x48, 0xab, 0x09, 0x1a, 0xf5, 0x69, 0xad, 0xb5, 0x6b, 0x6f, 0xf3, 0x42, 0x4e, 0x67, 0xfc, 0xe9, + 0x08, 0x9f, 0x6e, 0x22, 0x9e, 0xef, 0x0e, 0x4c, 0xdd, 0xaf, 0x56, 0xca, 0x8a, 0xa2, 0x5d, 0x4f, + 0x07, 0xb5, 0xfc, 0x28, 0xa0, 0x5e, 0xdb, 0x6e, 0xca, 0xfb, 0x6e, 0x74, 0x04, 0xb9, 0x4e, 0xa3, + 0x9e, 0xae, 0x84, 0x8f, 0x71, 0x64, 0x75, 0xf0, 0x9b, 0x75, 0x58, 0x47, 0x76, 0xc0, 0x3a, 0x7c, + 0xbb, 0xd5, 0xec, 0x51, 0x87, 0xce, 0x91, 0xec, 0xe3, 0xd5, 0x77, 0xbf, 0xbb, 0xa3, 0xd4, 0x92, + 0xeb, 0x5f, 0xcb, 0x4b, 0xa2, 0x96, 0x67, 0x85, 0x5a, 0x25, 0xb5, 0x9e, 0x04, 0xd7, 0x68, 0x9f, + 0x18, 0x3a, 0x75, 0x9f, 0xf8, 0xeb, 0x19, 0x18, 0xe1, 0xe2, 0xab, 0x98, 0xc6, 0x3d, 0x04, 0xe4, + 0xed, 0x27, 0x23, 0x20, 0x17, 0xf0, 0x9c, 0xd0, 0x26, 0x34, 0x2f, 0x23, 0x95, 0xd8, 0xba, 0x90, + 0xde, 0x00, 0xf8, 0x64, 0xc6, 0x4b, 0x4e, 0x5f, 0x16, 0xa4, 0x1a, 0x85, 0xd2, 0x18, 0x3d, 0xd5, + 0x5b, 0x5b, 0x86, 0x1f, 0x19, 0x15, 0xa1, 0x34, 0xf4, 0x00, 0x1a, 0xab, 0x30, 0x26, 0x02, 0x74, + 0x2c, 0x1d, 0x89, 0x87, 0xf1, 0x82, 0x66, 0xda, 0xd4, 0x58, 0x3a, 0x8a, 0x44, 0x73, 0x11, 0xe2, + 0xc3, 0xda, 0x39, 0xd2, 0xf2, 0x09, 0x4b, 0x44, 0x72, 0x9f, 0xe7, 0xd9, 0xe4, 0x11, 0x8f, 0xf5, + 0x14, 0x07, 0x21, 0x5c, 0x84, 0xfe, 0x92, 0x5e, 0xfe, 0x29, 0x01, 0x8e, 0x23, 0x1e, 0x64, 0x15, + 0x0a, 0x68, 0x0e, 0x47, 0x1b, 0x7c, 0xd5, 0x54, 0x2b, 0x3c, 0x08, 0x84, 0x30, 0x69, 0x0e, 0x78, + 0x99, 0x58, 0x6e, 0x31, 0xff, 0xcb, 0x04, 0xa5, 0xf1, 0x33, 0x59, 0x28, 0xc4, 0x67, 0x1f, 0x79, + 0x07, 0xc6, 0xc3, 0x88, 0xd3, 0xa1, 0x07, 0x38, 0x3e, 0x90, 0x45, 0x21, 0xaa, 0xf5, 0xec, 0x8c, + 0x0a, 0x3a, 0x59, 0x84, 0x3c, 0x5b, 0xc4, 0xf1, 0x4c, 0xc6, 0x5d, 0x01, 0x53, 0x3d, 0xb2, 0x24, + 0x1e, 0xa9, 0xc1, 0x2c, 0x5b, 0x34, 0x35, 0xa7, 0xbd, 0xd7, 0xa4, 0xab, 0xee, 0x9e, 0xdb, 0x0d, + 0xa2, 0x64, 0x85, 0xfc, 0x02, 0x63, 0xb7, 0x9a, 0x5a, 0xb1, 0x9e, 0xaa, 0x30, 0x85, 0x5a, 0xc9, + 0xb3, 0x3e, 0x34, 0x40, 0x9e, 0x75, 0x65, 0x67, 0xfd, 0xa3, 0x2c, 0x8c, 0x2b, 0xd3, 0x8f, 0x5c, + 0x85, 0x7c, 0xd5, 0x5f, 0x75, 0xeb, 0x07, 0x61, 0x28, 0xc9, 0xc9, 0x93, 0xe3, 0xe2, 0x98, 0xe3, + 0x5b, 0x4d, 0x04, 0x9a, 0x61, 0x31, 0x59, 0x82, 0x49, 0xfe, 0x97, 0x4c, 0x1c, 0x92, 0x8d, 0x74, + 0x6b, 0x1c, 0x59, 0xa6, 0x0c, 0x51, 0x37, 0x5b, 0x8d, 0x84, 0x7c, 0x05, 0x80, 0x03, 0x30, 0xf8, + 0x40, 0x6e, 0xf0, 0xb0, 0x09, 0xa2, 0x82, 0x94, 0xb0, 0x03, 0x0a, 0x43, 0xf2, 0x35, 0x1e, 0xd0, + 0x5a, 0x2e, 0x97, 0xa1, 0xc1, 0xe3, 0x3e, 0x30, 0xfe, 0x56, 0x7a, 0xf8, 0x19, 0x95, 0xa5, 0xc8, + 0xf5, 0xb3, 0x60, 0xd2, 0xba, 0xfb, 0x90, 0x7a, 0x47, 0xa5, 0x00, 0x11, 0x15, 0x0c, 0xe3, 0x7f, + 0xc9, 0x28, 0x8b, 0x8c, 0xac, 0x63, 0xae, 0x6e, 0x3e, 0x81, 0x84, 0x49, 0x59, 0x78, 0xc5, 0x90, + 0x70, 0x93, 0xee, 0x2e, 0x3d, 0x2b, 0xac, 0xdb, 0x66, 0xc3, 0x69, 0x18, 0xcb, 0xe1, 0xcd, 0x81, + 0xe4, 0x0b, 0x30, 0x84, 0x5d, 0x97, 0x3d, 0xb5, 0x69, 0xf2, 0x94, 0x1f, 0x62, 0x7d, 0x86, 0x0d, + 0x41, 0x4a, 0xf2, 0x69, 0xe1, 0xb8, 0xcd, 0x3b, 0x7f, 0x4a, 0x39, 0xaa, 0xd9, 0x77, 0x84, 0xc7, + 0x7b, 0x14, 0x81, 0x48, 0x99, 0x3d, 0x7f, 0x33, 0x0b, 0x85, 0xf8, 0xd2, 0x26, 0xef, 0xc3, 0x84, + 0x3c, 0x7e, 0x57, 0x6c, 0x91, 0xf5, 0x62, 0x42, 0x64, 0x9d, 0x90, 0x67, 0xf0, 0xbe, 0xad, 0x9a, + 0xa0, 0x99, 0x1a, 0x01, 0x93, 0x85, 0x36, 0x45, 0x44, 0x40, 0x65, 0x51, 0x05, 0x6e, 0xd0, 0x89, + 0xc5, 0x51, 0x96, 0x68, 0xe4, 0x4d, 0xc8, 0xad, 0xdd, 0x2e, 0x09, 0x07, 0xbf, 0x42, 0xfc, 0x90, + 0xe6, 0x96, 0xb2, 0xba, 0xdd, 0x2e, 0xc3, 0x27, 0xab, 0x4a, 0xc8, 0xf1, 0x11, 0xcd, 0xdc, 0x50, + 0x82, 0xc3, 0xc6, 0x9d, 0x1e, 0x7b, 0xfc, 0xee, 0x50, 0x3e, 0x57, 0x18, 0x12, 0x41, 0x74, 0xff, + 0xfb, 0x1c, 0x8c, 0x85, 0xf5, 0x13, 0xa2, 0xba, 0x4d, 0x73, 0x17, 0x69, 0x72, 0x11, 0xf2, 0x52, + 0xba, 0x13, 0x7e, 0x7e, 0xa3, 0xbe, 0x90, 0xec, 0xe6, 0x41, 0x8a, 0x71, 0x7c, 0x57, 0x30, 0xe5, + 0x4f, 0x72, 0x03, 0x42, 0x19, 0xad, 0x97, 0x30, 0x37, 0xc4, 0x06, 0xcc, 0x0c, 0xd1, 0xc8, 0x14, + 0x64, 0x1d, 0x1e, 0x98, 0x6d, 0xcc, 0xcc, 0x3a, 0x0d, 0xf2, 0x3e, 0xe4, 0xed, 0x46, 0x83, 0x36, + 0x2c, 0x5b, 0xda, 0x66, 0xf5, 0x9b, 0x34, 0x79, 0xc6, 0x8d, 0x9f, 0x19, 0x48, 0x55, 0x0a, 0x48, + 0x09, 0xc6, 0x9a, 0x36, 0xb7, 0xf6, 0x6c, 0x0c, 0x70, 0x00, 0x45, 0x1c, 0xf2, 0x8c, 0x6c, 0xcb, + 0xa7, 0x0d, 0xf2, 0x2a, 0x0c, 0xb1, 0xd1, 0x14, 0x27, 0x8e, 0x14, 0x2a, 0xd9, 0x60, 0xf2, 0x0e, + 0x5b, 0x79, 0xc6, 0x44, 0x04, 0xf2, 0x32, 0xe4, 0xba, 0x8b, 0xbb, 0xe2, 0x2c, 0x29, 0x44, 0xe1, + 0xff, 0x43, 0x34, 0x56, 0x4c, 0x6e, 0x42, 0xfe, 0x50, 0x8f, 0x1c, 0x7f, 0x2e, 0x36, 0x8c, 0x21, + 0x7e, 0x88, 0x48, 0x5e, 0x85, 0x9c, 0xef, 0xbb, 0xc2, 0xa0, 0x69, 0x36, 0xb4, 0x32, 0xbd, 0x1f, + 0x8e, 0x1a, 0xe3, 0xee, 0xfb, 0xee, 0x52, 0x1e, 0x46, 0xf8, 0x01, 0x63, 0xbc, 0x00, 0x10, 0x7d, + 0x63, 0xd2, 0x6f, 0xd3, 0xf8, 0x0a, 0x8c, 0x85, 0xdf, 0x46, 0x9e, 0x07, 0x38, 0xa0, 0x47, 0xd6, + 0xbe, 0xdd, 0x6e, 0x34, 0xb9, 0x74, 0x3a, 0x61, 0x8e, 0x1d, 0xd0, 0xa3, 0x15, 0x04, 0x90, 0x0b, + 0x30, 0xda, 0x61, 0xc3, 0x2f, 0xe6, 0xf8, 0x84, 0x39, 0xd2, 0xe9, 0xee, 0xb0, 0xa9, 0x3c, 0x0f, + 0xa3, 0xa8, 0x67, 0x15, 0x2b, 0x72, 0xd2, 0x94, 0x3f, 0x8d, 0x3f, 0xcb, 0x61, 0x7a, 0x25, 0xa5, + 0x41, 0xe4, 0x25, 0x98, 0xac, 0x7b, 0x14, 0xcf, 0x32, 0x9b, 0x49, 0x68, 0xa2, 0x9e, 0x89, 0x08, + 0x58, 0x6d, 0x90, 0xcb, 0x30, 0xdd, 0xe9, 0xee, 0x34, 0x9d, 0x3a, 0xab, 0xcd, 0xaa, 0xef, 0x88, + 0x7c, 0x10, 0x13, 0xe6, 0x24, 0x07, 0xdf, 0xa3, 0x47, 0xe5, 0x1d, 0x8c, 0x3c, 0x58, 0x50, 0x03, + 0x47, 0x07, 0x61, 0xe2, 0x7b, 0x73, 0x5a, 0x81, 0xa3, 0x6d, 0xe6, 0x79, 0x18, 0xb1, 0xed, 0xbd, + 0xae, 0xc3, 0x23, 0x84, 0x4d, 0x98, 0xe2, 0x17, 0xf9, 0x14, 0xcc, 0x44, 0xb1, 0xcc, 0x65, 0x33, + 0x86, 0xb1, 0x19, 0x85, 0xb0, 0xa0, 0xcc, 0xe1, 0xe4, 0x0d, 0x20, 0x6a, 0x7d, 0xee, 0xce, 0x47, + 0xb4, 0xce, 0xe7, 0xe4, 0x84, 0x39, 0xa3, 0x94, 0xdc, 0xc7, 0x02, 0xf2, 0x22, 0x4c, 0x78, 0xd4, + 0x47, 0xe9, 0x10, 0xbb, 0x0d, 0xb3, 0x0f, 0x9a, 0xe3, 0x12, 0xc6, 0xfa, 0xee, 0x0a, 0x14, 0x94, + 0xee, 0xc0, 0xd8, 0xdc, 0x3c, 0x19, 0x82, 0x39, 0x15, 0xc1, 0xcd, 0x4e, 0xb5, 0x41, 0xbe, 0x08, + 0x0b, 0x0a, 0x26, 0x4f, 0x84, 0x68, 0xd1, 0xa6, 0xb3, 0xe7, 0xec, 0x34, 0xa9, 0x98, 0x6f, 0xc9, + 0x59, 0x1d, 0x5e, 0x21, 0xcd, 0xf9, 0x88, 0x9a, 0xa7, 0x48, 0x5c, 0x16, 0xb4, 0x64, 0x15, 0xe6, + 0x62, 0x9c, 0x69, 0xc3, 0xea, 0x76, 0x7a, 0x86, 0xe4, 0x8b, 0x78, 0x12, 0x9d, 0x27, 0x6d, 0x6c, + 0x75, 0x8c, 0x6f, 0xc0, 0x84, 0x3a, 0x27, 0x59, 0x27, 0xa8, 0x72, 0x89, 0x98, 0x7d, 0xe3, 0x21, + 0xac, 0xca, 0xee, 0x85, 0x53, 0x11, 0x4a, 0x10, 0xe6, 0xf8, 0x37, 0x27, 0x43, 0x28, 0x0e, 0xe1, + 0x8b, 0x30, 0xd1, 0x70, 0xfc, 0x4e, 0xd3, 0x3e, 0xb2, 0xa2, 0x0c, 0xdf, 0xe6, 0xb8, 0x80, 0xa1, + 0xe2, 0x67, 0x09, 0x66, 0x12, 0xfb, 0xa0, 0x22, 0x69, 0xf0, 0x7d, 0xbd, 0xbf, 0xa4, 0x61, 0xb4, + 0x61, 0x42, 0x3d, 0xd7, 0x4e, 0x49, 0x5c, 0x72, 0x1e, 0xc3, 0xf0, 0xf0, 0x4d, 0x7f, 0xe4, 0xe4, + 0xb8, 0x98, 0x75, 0x1a, 0x18, 0x7c, 0xe7, 0x0a, 0xe4, 0xa5, 0xc4, 0x26, 0x04, 0x25, 0x7c, 0x4c, + 0x90, 0x4f, 0x93, 0x66, 0x58, 0x6a, 0xbc, 0x0a, 0xa3, 0xe2, 0xe8, 0xea, 0xff, 0x84, 0x60, 0xfc, + 0x70, 0x16, 0xa6, 0x4d, 0xca, 0x36, 0x56, 0xca, 0xb3, 0x15, 0x3d, 0xb5, 0x57, 0xf4, 0xf4, 0x60, + 0xae, 0x5a, 0xdb, 0xfa, 0xe4, 0x09, 0xfa, 0xd5, 0x0c, 0xcc, 0xa6, 0xe0, 0x7e, 0xac, 0x3c, 0xb9, + 0xb7, 0x60, 0xac, 0xe2, 0xd8, 0xcd, 0x52, 0xa3, 0x11, 0xc6, 0xe4, 0x41, 0x39, 0x1f, 0x93, 0x69, + 0xd9, 0x0c, 0xaa, 0x0a, 0x31, 0x21, 0x2a, 0x79, 0x4d, 0x4c, 0x8a, 0x28, 0xcb, 0x3c, 0x4e, 0x8a, + 0x6f, 0x1f, 0x17, 0x81, 0x7f, 0xd3, 0x66, 0x38, 0x45, 0x30, 0xc0, 0x32, 0x07, 0x46, 0x7e, 0x55, + 0x4f, 0xed, 0xd0, 0xa5, 0x07, 0x58, 0x8e, 0x37, 0x6f, 0xa0, 0x54, 0x41, 0x3f, 0x91, 0x85, 0xf3, + 0xe9, 0x84, 0x1f, 0x37, 0xe5, 0x31, 0x26, 0x69, 0x52, 0x82, 0xc2, 0x63, 0xca, 0x63, 0x9e, 0xd1, + 0x09, 0xf1, 0x23, 0x04, 0xb2, 0x0b, 0x93, 0xab, 0xb6, 0x1f, 0xac, 0x50, 0xdb, 0x0b, 0x76, 0xa8, + 0x1d, 0x0c, 0x20, 0xc9, 0x4b, 0x6b, 0x8a, 0x79, 0x14, 0x26, 0xf6, 0x25, 0x65, 0x4c, 0xd6, 0xd6, + 0xd9, 0x86, 0x13, 0x65, 0x68, 0x80, 0x89, 0xf2, 0x75, 0x98, 0xae, 0xd1, 0x96, 0xdd, 0xd9, 0x77, + 0x3d, 0x19, 0x2f, 0xe1, 0x1a, 0x4c, 0x86, 0xa0, 0xd4, 0xd9, 0xa2, 0x17, 0x6b, 0xf8, 0x4a, 0x47, + 0x44, 0x5b, 0x89, 0x5e, 0x6c, 0xfc, 0xad, 0x2c, 0x5c, 0x28, 0xd5, 0x85, 0x69, 0xa8, 0x28, 0x90, + 0x16, 0xec, 0x9f, 0x70, 0xdd, 0xe4, 0x3a, 0x8c, 0xad, 0xd9, 0x8f, 0x56, 0xa9, 0xed, 0x53, 0x5f, + 0x24, 0x9c, 0xe4, 0x62, 0xaf, 0xfd, 0x28, 0x7a, 0xfc, 0x31, 0x23, 0x1c, 0x55, 0x8d, 0x30, 0xf4, + 0x98, 0x6a, 0x04, 0x03, 0x46, 0x56, 0xdc, 0x66, 0x43, 0x9c, 0xf5, 0xe2, 0xc5, 0x79, 0x1f, 0x21, + 0xa6, 0x28, 0x31, 0xfe, 0x24, 0x03, 0x53, 0xe1, 0x17, 0xe3, 0x27, 0x7c, 0xe2, 0x5d, 0x72, 0x19, + 0x46, 0xb1, 0xa2, 0x30, 0x33, 0x3e, 0x1e, 0x1a, 0x4d, 0x8a, 0x69, 0x03, 0x1b, 0xa6, 0x2c, 0x54, + 0x7b, 0x62, 0xf8, 0xf1, 0x7a, 0xc2, 0xf8, 0xfb, 0xf8, 0x98, 0xad, 0xb6, 0x92, 0x9d, 0x44, 0xca, + 0x87, 0x64, 0x06, 0xfc, 0x90, 0xec, 0x13, 0x1b, 0x92, 0x5c, 0xcf, 0x21, 0xf9, 0x91, 0x2c, 0x8c, + 0x87, 0x1f, 0xfb, 0x1d, 0x96, 0x99, 0x20, 0x6c, 0xd7, 0x40, 0x31, 0x8e, 0x6a, 0xca, 0x5e, 0x21, + 0x42, 0x09, 0x7d, 0x01, 0x46, 0xc4, 0x62, 0xca, 0xc4, 0x2c, 0xb9, 0x63, 0xa3, 0xbb, 0x34, 0x25, + 0x58, 0x8f, 0xe0, 0x80, 0xfa, 0xa6, 0xa0, 0xc3, 0x20, 0x52, 0xdb, 0x74, 0x47, 0xd8, 0x36, 0x3c, + 0xb5, 0x67, 0x54, 0x7a, 0x10, 0xa9, 0xa8, 0x61, 0x03, 0x9d, 0x4e, 0xff, 0x2c, 0x0f, 0x85, 0x38, + 0xc9, 0xe9, 0xb9, 0x1f, 0x36, 0xba, 0x3b, 0xfc, 0xaa, 0xc2, 0x73, 0x3f, 0x74, 0xba, 0x3b, 0x26, + 0x83, 0xa1, 0xe9, 0x93, 0xe7, 0x3c, 0xc4, 0x56, 0x4f, 0x08, 0xd3, 0x27, 0xcf, 0x79, 0xa8, 0x99, + 0x3e, 0x79, 0xce, 0x43, 0x54, 0x24, 0xac, 0xd6, 0x30, 0xc0, 0x02, 0xde, 0x53, 0x84, 0x22, 0xa1, + 0xe9, 0xc7, 0xf3, 0xb8, 0x49, 0x34, 0x76, 0x54, 0x2e, 0x51, 0xdb, 0x13, 0x79, 0x0a, 0xc4, 0x76, + 0x86, 0x47, 0xe5, 0x0e, 0x82, 0xad, 0x80, 0xc1, 0x4d, 0x15, 0x89, 0x34, 0x81, 0x28, 0x3f, 0xe5, + 0x02, 0x3e, 0xfd, 0x6e, 0x2d, 0xad, 0x30, 0xe7, 0x54, 0xd6, 0x96, 0xba, 0x9a, 0x53, 0xf8, 0x3e, + 0x49, 0xed, 0xef, 0x86, 0x08, 0xbe, 0x8a, 0x0a, 0xa4, 0xfc, 0xa9, 0xcc, 0x64, 0x60, 0x18, 0xe0, + 0xc1, 0x59, 0x43, 0x35, 0x52, 0xc4, 0x84, 0xbc, 0x07, 0xe3, 0x6a, 0xd8, 0x0c, 0x1e, 0xdc, 0xe1, + 0x39, 0x1e, 0x4f, 0xb3, 0x47, 0xe6, 0x5f, 0x95, 0x80, 0xec, 0xc0, 0x85, 0xb2, 0xdb, 0xf6, 0xbb, + 0x2d, 0x19, 0xb9, 0x33, 0x8a, 0x17, 0x0e, 0x38, 0x14, 0xe8, 0x83, 0x5f, 0x17, 0x28, 0x22, 0x4a, + 0x83, 0x74, 0x93, 0xd1, 0x2f, 0x20, 0xbd, 0x18, 0x91, 0x4d, 0x18, 0x47, 0x0d, 0xaa, 0x30, 0x79, + 0x1c, 0xd7, 0xb7, 0x8d, 0xa8, 0xa4, 0xc2, 0x16, 0x06, 0x8f, 0x1a, 0x67, 0xb7, 0x9a, 0xd2, 0x4b, + 0x43, 0xd5, 0x04, 0x2b, 0xc8, 0xe4, 0x2b, 0x30, 0xc5, 0xaf, 0x68, 0xdb, 0x74, 0x87, 0xcf, 0x9d, + 0x09, 0x4d, 0x13, 0xa1, 0x17, 0xf2, 0xc7, 0x7c, 0xa1, 0xb7, 0x3e, 0xa4, 0x3b, 0x7c, 0xec, 0x35, + 0x1f, 0x29, 0x0d, 0x9f, 0x6c, 0xc1, 0xec, 0x8a, 0xed, 0x73, 0xa0, 0x12, 0xff, 0x60, 0x12, 0x35, + 0xb4, 0x68, 0xbb, 0xbe, 0x6f, 0xfb, 0x52, 0x11, 0x9e, 0x1a, 0xef, 0x20, 0x8d, 0x9e, 0xfc, 0x70, + 0x06, 0xe6, 0x35, 0x3d, 0xb9, 0xb0, 0x33, 0x6b, 0xd1, 0x76, 0x80, 0xce, 0x50, 0x53, 0x8b, 0x45, + 0x29, 0x94, 0xf6, 0x40, 0xe3, 0x43, 0x12, 0x53, 0xc5, 0x7b, 0x51, 0xb9, 0x6a, 0x14, 0xde, 0x8b, + 0x87, 0x58, 0xa8, 0xb8, 0xa6, 0xa7, 0xf5, 0x85, 0x1a, 0x5b, 0xd7, 0x12, 0xcd, 0xb8, 0x15, 0xef, + 0x6f, 0xa1, 0xe8, 0xca, 0x84, 0x8a, 0xae, 0x39, 0x18, 0xc6, 0x5e, 0x95, 0x51, 0xb4, 0xf0, 0x87, + 0xf1, 0x69, 0x75, 0x1f, 0x12, 0x62, 0x61, 0xdf, 0x7d, 0xc8, 0xf8, 0x1f, 0x47, 0x60, 0x3a, 0x36, + 0x2d, 0xc4, 0x3d, 0x35, 0x93, 0xb8, 0xa7, 0xd6, 0x00, 0xb8, 0xaa, 0x77, 0x40, 0x9d, 0xac, 0x74, + 0xc4, 0x1c, 0x17, 0x6e, 0xd4, 0xe1, 0x9a, 0x52, 0xd8, 0x30, 0xa6, 0x7c, 0xc5, 0x0e, 0xa8, 0x23, + 0x0f, 0x99, 0xf2, 0x45, 0xaf, 0x30, 0x8d, 0xd8, 0x90, 0x22, 0x0c, 0x63, 0xfc, 0x5c, 0xd5, 0x0f, + 0xd6, 0x61, 0x00, 0x93, 0xc3, 0xc9, 0x4b, 0x30, 0xc2, 0x84, 0xa8, 0x6a, 0x45, 0x6c, 0x82, 0x78, + 0xb6, 0x30, 0x29, 0x8b, 0x49, 0x2c, 0xa2, 0x88, 0xdc, 0x82, 0x09, 0xfe, 0x97, 0x08, 0xb3, 0x33, + 0xa2, 0x1b, 0x3f, 0x5a, 0x4e, 0x43, 0x46, 0xda, 0xd1, 0xf0, 0xd8, 0xed, 0xa2, 0xd6, 0x45, 0xb5, + 0x4e, 0xb5, 0x22, 0x02, 0xae, 0xe3, 0xed, 0xc2, 0xe7, 0x40, 0x56, 0x45, 0x84, 0xc0, 0x64, 0x19, + 0xe1, 0x8d, 0x92, 0xc7, 0x3b, 0x25, 0xca, 0x32, 0xdc, 0x0b, 0xc5, 0x14, 0x25, 0xe4, 0x2a, 0x7f, + 0x89, 0x41, 0xb1, 0x90, 0xe7, 0xad, 0xc4, 0x77, 0x0b, 0x54, 0x4c, 0xa0, 0x6c, 0x18, 0x16, 0xb3, + 0xca, 0xd9, 0xdf, 0xcb, 0x2d, 0xdb, 0x69, 0x8a, 0x6d, 0x05, 0x2b, 0x47, 0x5c, 0xca, 0xa0, 0x66, + 0x84, 0x40, 0xde, 0x81, 0x29, 0xf6, 0xa3, 0xec, 0xb6, 0x5a, 0x6e, 0x1b, 0xd9, 0x8f, 0x47, 0x81, + 0xf4, 0x90, 0xa4, 0x8e, 0x45, 0xbc, 0x96, 0x18, 0x2e, 0x3b, 0x4f, 0xf0, 0x95, 0xb7, 0xcb, 0xdf, + 0x88, 0x26, 0xa2, 0xf3, 0x04, 0x49, 0x7d, 0x0e, 0x37, 0x55, 0x24, 0xf2, 0x16, 0x4c, 0xb2, 0x9f, + 0x77, 0x9c, 0x87, 0x94, 0x57, 0x38, 0x19, 0x99, 0x37, 0x20, 0xd5, 0x1e, 0x2b, 0xe1, 0xf5, 0xe9, + 0x98, 0xe4, 0x03, 0x38, 0x87, 0x9c, 0xea, 0x6e, 0x87, 0x36, 0x4a, 0xbb, 0xbb, 0x4e, 0xd3, 0xe1, + 0xd6, 0x68, 0x3c, 0xa0, 0x0c, 0xea, 0xe0, 0x79, 0xc5, 0x88, 0x61, 0xd9, 0x11, 0x8a, 0x99, 0x4e, + 0x49, 0xb6, 0xa1, 0x50, 0xee, 0xfa, 0x81, 0xdb, 0x2a, 0x05, 0x81, 0xe7, 0xec, 0x74, 0x03, 0xea, + 0xcf, 0x4f, 0x6b, 0x61, 0x57, 0xd8, 0xe2, 0x08, 0x0b, 0xb9, 0x3e, 0xa8, 0x8e, 0x14, 0x96, 0x1d, + 0x92, 0x98, 0x09, 0x26, 0xc6, 0x3f, 0xcf, 0xc0, 0xa4, 0x46, 0x4a, 0xde, 0x84, 0x89, 0xdb, 0x9e, + 0x43, 0xdb, 0x8d, 0xe6, 0x91, 0x72, 0x51, 0xc5, 0x5b, 0xcc, 0xae, 0x80, 0xf3, 0x56, 0x6b, 0x68, + 0xa1, 0x9e, 0x27, 0x9b, 0x6a, 0x2a, 0x7a, 0x9d, 0xbb, 0x63, 0x8b, 0x09, 0x9a, 0x8b, 0xe2, 0x40, + 0xe1, 0x04, 0x15, 0xb3, 0x53, 0x41, 0x21, 0xef, 0xc2, 0x08, 0x7f, 0x0f, 0x16, 0x76, 0x8b, 0x17, + 0xd3, 0x9a, 0xc9, 0x5d, 0xff, 0x71, 0x22, 0xa2, 0xd1, 0x8f, 0x6f, 0x0a, 0x22, 0xe3, 0xe7, 0x32, + 0x40, 0x92, 0xa8, 0xa7, 0xe8, 0xbd, 0x4e, 0x35, 0x26, 0xfa, 0x42, 0xb8, 0x1a, 0x73, 0x9a, 0xce, + 0x9c, 0xd5, 0xc4, 0x0b, 0x78, 0xc7, 0x8b, 0x55, 0xa7, 0x2a, 0xe2, 0x78, 0xb1, 0xf1, 0x43, 0x59, + 0x80, 0x08, 0x9b, 0x7c, 0x8e, 0xa7, 0x29, 0xfb, 0xa0, 0x6b, 0x37, 0x9d, 0x5d, 0x47, 0x8f, 0xdb, + 0x8b, 0x4c, 0xbe, 0x2e, 0x4b, 0x4c, 0x1d, 0x91, 0xbc, 0x0f, 0xd3, 0xb5, 0x0d, 0x9d, 0x56, 0x31, + 0x8b, 0xf7, 0x3b, 0x56, 0x8c, 0x3c, 0x8e, 0x8d, 0xf6, 0xc9, 0xea, 0x68, 0x70, 0xfb, 0x64, 0x3e, + 0x10, 0xa2, 0x84, 0x6d, 0x2c, 0xb5, 0x0d, 0x61, 0xf9, 0xdf, 0x08, 0x5f, 0x35, 0xf1, 0xeb, 0xfc, + 0x8e, 0xd5, 0x11, 0x2e, 0x01, 0x6c, 0x9f, 0xd0, 0xf0, 0xa2, 0x8e, 0x1c, 0xee, 0xe1, 0xde, 0xff, + 0xf3, 0xa8, 0xf6, 0x6b, 0xb9, 0x01, 0x15, 0xda, 0x8e, 0xa7, 0xf6, 0xde, 0x13, 0x19, 0x13, 0x0c, + 0x6b, 0x5e, 0xcb, 0x5a, 0xeb, 0x84, 0xc1, 0xcc, 0xcd, 0xe8, 0x92, 0xc2, 0xcd, 0x0a, 0x52, 0x6c, + 0x6c, 0xfe, 0x6e, 0x06, 0xce, 0xa5, 0xd2, 0x92, 0x6b, 0x00, 0x91, 0x4e, 0x49, 0xf4, 0x12, 0xee, + 0x98, 0x51, 0xf4, 0x23, 0x53, 0xc1, 0x20, 0x5f, 0x8e, 0x6b, 0x83, 0x4e, 0x3f, 0x08, 0x17, 0x64, + 0xd0, 0x41, 0x5d, 0x1b, 0x94, 0xa2, 0x03, 0x32, 0x7e, 0x35, 0x07, 0x33, 0x4a, 0x70, 0x25, 0xfe, + 0xad, 0xa7, 0xd8, 0x8b, 0x1f, 0xc0, 0x04, 0x6b, 0x8d, 0x53, 0x17, 0x6e, 0x37, 0xdc, 0xf0, 0xe5, + 0xb5, 0x84, 0xdf, 0xa9, 0xe0, 0x76, 0x4d, 0x45, 0xe6, 0xa1, 0x40, 0x71, 0xeb, 0xc4, 0x07, 0x89, + 0x7a, 0xd2, 0xe5, 0x46, 0x63, 0x4e, 0x7c, 0x98, 0xac, 0x1c, 0xb5, 0xed, 0x56, 0x58, 0x1b, 0x37, + 0x80, 0xf9, 0x54, 0xcf, 0xda, 0x34, 0x6c, 0x5e, 0x5d, 0xe4, 0xa1, 0xc5, 0xcb, 0x52, 0x82, 0x03, + 0x68, 0x54, 0x0b, 0xef, 0xc3, 0x4c, 0xe2, 0xa3, 0xcf, 0x14, 0x95, 0x74, 0x1b, 0x48, 0xf2, 0x3b, + 0x52, 0x38, 0x7c, 0x4a, 0x8f, 0x79, 0x7b, 0x2e, 0x7c, 0xbc, 0x6e, 0xb5, 0xec, 0x76, 0x83, 0x9b, + 0xd3, 0x2c, 0xaa, 0x31, 0x4b, 0x7f, 0x3e, 0xab, 0xfa, 0xfe, 0x3e, 0xed, 0xab, 0xee, 0x0b, 0xda, + 0x6d, 0xf8, 0x85, 0x5e, 0x63, 0x3a, 0x90, 0xd6, 0xe1, 0x5b, 0x39, 0xb8, 0xd0, 0x83, 0x92, 0x1c, + 0xc5, 0x27, 0x11, 0xd7, 0x42, 0xdc, 0xe8, 0x5f, 0xe1, 0x93, 0x98, 0x4a, 0xe4, 0x73, 0x3c, 0xfa, + 0x47, 0xdd, 0x6d, 0xef, 0x3a, 0x7b, 0xe2, 0xfe, 0x8d, 0x6a, 0xfc, 0x83, 0x10, 0x1a, 0x0f, 0xfb, + 0xc1, 0xa1, 0xe4, 0x7d, 0x18, 0x46, 0xc7, 0xef, 0x58, 0x78, 0x47, 0x86, 0x81, 0x70, 0x25, 0x40, + 0x29, 0xfb, 0xa9, 0x05, 0x28, 0x65, 0x00, 0xf2, 0x59, 0xc8, 0x95, 0xb6, 0x6b, 0x62, 0x5c, 0xa6, + 0x54, 0xf2, 0xed, 0x5a, 0x94, 0x5c, 0xc5, 0xd6, 0xb2, 0xa0, 0x30, 0x0a, 0x46, 0x78, 0xa7, 0xbc, + 0x21, 0x46, 0x45, 0x25, 0xbc, 0x53, 0xde, 0x88, 0x08, 0xf7, 0xea, 0x5a, 0xb0, 0xac, 0x3b, 0xe5, + 0x8d, 0x4f, 0x6e, 0xda, 0xff, 0x7b, 0x59, 0x1e, 0xb2, 0x84, 0x37, 0xec, 0x7d, 0x98, 0xd0, 0x62, + 0x92, 0x67, 0x22, 0x79, 0x2c, 0x8c, 0x1f, 0x1f, 0xb3, 0x18, 0xd2, 0x08, 0x64, 0x9a, 0x22, 0xf6, + 0x1b, 0x25, 0x5e, 0xd5, 0xd8, 0x26, 0xe4, 0x80, 0x32, 0x71, 0x3c, 0x4d, 0x51, 0x48, 0x42, 0x6e, + 0x42, 0x7e, 0x93, 0xb6, 0xed, 0x76, 0x10, 0x2a, 0x44, 0xd1, 0xb8, 0x38, 0x40, 0x98, 0x2e, 0x35, + 0x84, 0x88, 0x68, 0x08, 0xdb, 0xdd, 0xf1, 0xeb, 0x9e, 0x83, 0xa1, 0x8d, 0xc2, 0xb3, 0x98, 0x1b, + 0xc2, 0x2a, 0x25, 0x3a, 0x83, 0x18, 0x91, 0xf1, 0xf3, 0x19, 0x18, 0x15, 0x03, 0xc9, 0xd3, 0xcb, + 0xed, 0x45, 0x67, 0x89, 0x70, 0x1e, 0xd8, 0x73, 0xe2, 0xce, 0x03, 0x7b, 0x3c, 0x7e, 0xd0, 0x98, + 0x70, 0xac, 0x0b, 0x9f, 0x06, 0x71, 0x36, 0x4a, 0xb7, 0x4f, 0x3d, 0x7b, 0x58, 0x88, 0x3a, 0xa8, + 0x43, 0x96, 0xf1, 0xb7, 0xc5, 0x97, 0xdd, 0x29, 0x6f, 0x90, 0x45, 0xc8, 0xaf, 0xba, 0x3c, 0x14, + 0x96, 0x9a, 0x2b, 0xb8, 0x29, 0x60, 0x6a, 0x07, 0x49, 0x3c, 0xf6, 0x7d, 0x1b, 0x9e, 0x2b, 0xee, + 0x32, 0xca, 0xf7, 0x75, 0x38, 0x30, 0xf6, 0x7d, 0x21, 0xea, 0xc0, 0xdf, 0x47, 0x53, 0x36, 0x89, + 0x07, 0x37, 0x31, 0x7f, 0xcb, 0x5d, 0xd5, 0xd1, 0x4d, 0x14, 0xc9, 0x9d, 0x62, 0xa1, 0xd7, 0x4e, + 0xf1, 0xe0, 0xa6, 0x99, 0x42, 0x85, 0xef, 0x6a, 0x11, 0xb8, 0x46, 0xbd, 0x87, 0x4f, 0xf1, 0x2e, + 0x9d, 0xfe, 0xae, 0x16, 0x6f, 0xde, 0x40, 0x9b, 0xf4, 0x1f, 0x64, 0xe1, 0x7c, 0x3a, 0xa1, 0xda, + 0x96, 0x4c, 0x9f, 0xb6, 0x5c, 0x81, 0xfc, 0x8a, 0xeb, 0x07, 0x8a, 0x91, 0x20, 0xaa, 0xff, 0xf7, + 0x05, 0xcc, 0x0c, 0x4b, 0xd9, 0x9d, 0x9b, 0xfd, 0x1d, 0x2e, 0x4f, 0xe4, 0x87, 0x81, 0x3a, 0xd8, + 0x9d, 0x9b, 0x17, 0x91, 0x3b, 0x90, 0x37, 0x85, 0xa3, 0x55, 0xac, 0x6b, 0x24, 0x38, 0x94, 0xa6, + 0x88, 0x27, 0x20, 0x5a, 0x68, 0x78, 0x01, 0x23, 0x25, 0x18, 0x15, 0xa3, 0x1f, 0x7b, 0x3a, 0x4e, + 0x99, 0x32, 0x7a, 0xb6, 0x06, 0x49, 0xc7, 0x76, 0x14, 0x7c, 0x04, 0xac, 0x56, 0xa4, 0xcf, 0x14, + 0xee, 0x28, 0xfc, 0x91, 0x50, 0xb7, 0xc7, 0x0c, 0x11, 0x8d, 0x1f, 0xce, 0x02, 0x48, 0xad, 0xcd, + 0x53, 0x3b, 0xc3, 0x3e, 0xab, 0xcd, 0x30, 0xc5, 0xde, 0x68, 0xf0, 0x74, 0xc8, 0xf7, 0xd1, 0x9c, + 0x67, 0xf0, 0x64, 0xc8, 0x45, 0x18, 0xde, 0x8c, 0x14, 0x5a, 0xc2, 0x25, 0x05, 0xd5, 0xd1, 0x1c, + 0x6e, 0xec, 0xc0, 0xdc, 0x1d, 0x1a, 0x44, 0xea, 0x2d, 0xf9, 0xf4, 0xd8, 0x9f, 0xed, 0xeb, 0x30, + 0x26, 0xf0, 0xc3, 0xfd, 0x8b, 0xeb, 0x62, 0x44, 0xec, 0x1b, 0xd4, 0xc5, 0x48, 0x04, 0xb6, 0x1b, + 0x55, 0x68, 0x93, 0x06, 0xf4, 0x93, 0xad, 0xa6, 0x06, 0x84, 0x37, 0x05, 0x5b, 0x36, 0x58, 0x0d, + 0xa7, 0xf6, 0xcf, 0x03, 0x38, 0x17, 0x7e, 0xfb, 0x93, 0xe4, 0x7b, 0x9d, 0x5d, 0x29, 0x45, 0xa2, + 0x83, 0x88, 0x63, 0x1f, 0xdb, 0x93, 0x47, 0xb0, 0x20, 0x09, 0xb6, 0x9d, 0xd0, 0x70, 0x72, 0x20, + 0x5a, 0xf2, 0x0e, 0x8c, 0x2b, 0x34, 0x22, 0x50, 0x3f, 0xaa, 0xa9, 0x0f, 0x9d, 0x60, 0xdf, 0xf2, + 0x39, 0x5c, 0x55, 0x53, 0x2b, 0xe8, 0xc6, 0x97, 0xe0, 0xd9, 0xd0, 0x6d, 0x28, 0xa5, 0xea, 0x18, + 0xf3, 0xcc, 0xd9, 0x98, 0xaf, 0x47, 0xcd, 0xaa, 0xb6, 0x43, 0xcf, 0x68, 0xc9, 0x9b, 0xa8, 0xcd, + 0x12, 0x8d, 0x79, 0x2e, 0xe1, 0x6b, 0xad, 0xb8, 0x54, 0x1b, 0x6f, 0x2b, 0x1f, 0x9b, 0xc2, 0x50, + 0x23, 0xce, 0xc4, 0x89, 0x7f, 0x38, 0x0b, 0xd3, 0xf7, 0xab, 0x95, 0x72, 0x68, 0x7d, 0xf4, 0x1d, + 0x96, 0xac, 0x59, 0x6b, 0x5b, 0xef, 0xfd, 0xc6, 0xd8, 0x82, 0xd9, 0x58, 0x37, 0xa0, 0xe8, 0xf0, + 0x1e, 0x77, 0x38, 0x09, 0xc1, 0x52, 0x6c, 0x38, 0x9f, 0xc6, 0xfe, 0xc1, 0x4d, 0x33, 0x86, 0x6d, + 0xfc, 0x97, 0x10, 0xe3, 0x2b, 0xb6, 0xb0, 0xd7, 0x61, 0xac, 0xea, 0xfb, 0x5d, 0xea, 0x6d, 0x99, + 0xab, 0xaa, 0xaa, 0xc0, 0x41, 0xa0, 0xd5, 0xf5, 0x9a, 0x66, 0x84, 0x40, 0xae, 0x42, 0x5e, 0x04, + 0x49, 0x97, 0x7b, 0x02, 0x6a, 0x6d, 0xc3, 0x18, 0xeb, 0x66, 0x58, 0x4c, 0xde, 0x84, 0x09, 0xfe, + 0x37, 0x9f, 0x6d, 0xa2, 0xc3, 0x51, 0x39, 0x28, 0xd0, 0xf9, 0xec, 0x34, 0x35, 0x34, 0xf2, 0x1a, + 0xe4, 0x4a, 0x65, 0x53, 0xa8, 0x83, 0x84, 0xdc, 0xe8, 0x59, 0x5c, 0x67, 0xa7, 0x5d, 0x22, 0xca, + 0x26, 0x93, 0xfe, 0x64, 0xb0, 0x09, 0xa1, 0xc9, 0xc6, 0x19, 0x20, 0xb5, 0x4d, 0xb1, 0xc3, 0x0c, + 0x61, 0xe4, 0x3a, 0x8c, 0x56, 0xb8, 0xc9, 0x9c, 0xd0, 0x63, 0xf3, 0x4c, 0x84, 0x1c, 0xa4, 0x05, + 0x57, 0xe0, 0x20, 0x72, 0x55, 0x66, 0x68, 0xcb, 0x47, 0x7e, 0x2b, 0x3d, 0xd2, 0xb0, 0xbd, 0x0e, + 0x23, 0x22, 0x94, 0xf8, 0x98, 0x92, 0xbb, 0x25, 0x1e, 0x42, 0x5c, 0xe0, 0x24, 0x1d, 0x58, 0xe1, + 0x49, 0x3a, 0xb0, 0xee, 0xc0, 0x85, 0x3b, 0xa8, 0xbd, 0xd1, 0x03, 0x62, 0x6d, 0x99, 0x55, 0xa1, + 0x0f, 0xc7, 0x67, 0x20, 0xae, 0xe0, 0x89, 0xc7, 0xd4, 0xb2, 0xba, 0x9e, 0x9a, 0x58, 0xb7, 0x17, + 0x23, 0xf2, 0x45, 0x98, 0x4b, 0x2b, 0x12, 0x5a, 0x73, 0x0c, 0xfd, 0x94, 0x5e, 0x81, 0x1a, 0xfa, + 0x29, 0x8d, 0x03, 0x59, 0x85, 0x02, 0x87, 0x97, 0x1a, 0x2d, 0xa7, 0xcd, 0x35, 0xff, 0x5c, 0xab, + 0x8e, 0x8e, 0x24, 0x82, 0xab, 0xcd, 0x0a, 0xf9, 0x0b, 0x80, 0xe6, 0x7a, 0x14, 0xa3, 0x24, 0x3f, + 0x95, 0x61, 0xb7, 0x39, 0x1e, 0x78, 0x7b, 0xcb, 0x5c, 0xf5, 0x45, 0xd8, 0xc0, 0xf3, 0x91, 0x57, + 0x51, 0x2d, 0xf0, 0x9c, 0xf6, 0x9e, 0x70, 0x2b, 0xda, 0x14, 0x6e, 0x45, 0xef, 0x7c, 0x2c, 0xb7, + 0x22, 0xce, 0xca, 0x3f, 0x39, 0x2e, 0x4e, 0x78, 0xa2, 0x4e, 0x5c, 0x45, 0xda, 0x17, 0xb0, 0xae, + 0x43, 0xdf, 0xda, 0xad, 0x36, 0x0f, 0xfb, 0x4b, 0x1b, 0xbc, 0x91, 0xd3, 0xb8, 0x83, 0x63, 0xd7, + 0x61, 0x4e, 0x10, 0xab, 0x1b, 0x22, 0x24, 0x1a, 0x9a, 0xca, 0x81, 0x5d, 0x3c, 0xa5, 0xeb, 0x0a, + 0xf7, 0xc6, 0x2d, 0x44, 0x17, 0x4f, 0xe9, 0xe7, 0x62, 0xe1, 0x34, 0x52, 0x27, 0x8f, 0x46, 0x42, + 0xae, 0xc3, 0xc8, 0x9a, 0xfd, 0xa8, 0xb4, 0x47, 0x45, 0xe6, 0xcd, 0x49, 0xb9, 0xfd, 0x21, 0x70, + 0x29, 0xff, 0x87, 0xdc, 0xd7, 0xe1, 0x19, 0x53, 0xa0, 0x91, 0xef, 0xcb, 0xc0, 0x79, 0xbe, 0x8c, + 0x65, 0x2b, 0x6b, 0x34, 0x08, 0x58, 0x3f, 0x88, 0xf8, 0x81, 0x97, 0x22, 0x83, 0xed, 0x74, 0x3c, + 0xf4, 0xbc, 0x37, 0xc4, 0xce, 0x10, 0x76, 0x9c, 0x2f, 0x4a, 0xb5, 0x40, 0xcc, 0xa9, 0xf4, 0x64, + 0x13, 0xc6, 0xd7, 0x6e, 0x97, 0xc2, 0x6a, 0x79, 0x74, 0xf6, 0x62, 0xda, 0xee, 0xa8, 0xa0, 0xa5, + 0x79, 0x1a, 0xa8, 0x6c, 0x84, 0x77, 0xc0, 0x67, 0x65, 0x7f, 0x90, 0x37, 0x54, 0x57, 0xd4, 0x1c, + 0x4a, 0xcf, 0xa3, 0x2d, 0xfb, 0x91, 0x65, 0xef, 0x51, 0xed, 0x95, 0x5c, 0x68, 0xaf, 0x7f, 0x36, + 0x03, 0x17, 0x7b, 0x36, 0x99, 0xdc, 0x82, 0x0b, 0x36, 0x77, 0xb0, 0xb6, 0xf6, 0x83, 0xa0, 0xe3, + 0x5b, 0xf2, 0x8a, 0x21, 0x9c, 0x57, 0xcd, 0x73, 0xa2, 0x78, 0x85, 0x95, 0xca, 0x5b, 0x87, 0x4f, + 0xde, 0x87, 0xe7, 0x9c, 0xb6, 0x4f, 0xeb, 0x5d, 0x8f, 0x5a, 0x92, 0x41, 0xdd, 0x69, 0x78, 0x96, + 0x67, 0xb7, 0xf7, 0xa4, 0x27, 0xae, 0x79, 0x51, 0xe2, 0x08, 0x27, 0xee, 0xb2, 0xd3, 0xf0, 0x4c, + 0x44, 0x30, 0xfe, 0x79, 0x06, 0xe6, 0x7b, 0x75, 0x09, 0x99, 0x87, 0x51, 0xaa, 0xe4, 0x69, 0xc9, + 0x9b, 0xf2, 0x27, 0x79, 0x16, 0xa2, 0x9d, 0x5e, 0x9c, 0xfe, 0xf9, 0xba, 0xc8, 0x99, 0x81, 0xa6, + 0xed, 0xea, 0xbe, 0x2e, 0x0c, 0x94, 0x27, 0xea, 0xea, 0xee, 0xfe, 0x3c, 0x40, 0xb4, 0x9d, 0x73, + 0xc5, 0x84, 0x39, 0x66, 0xd7, 0x3d, 0xbe, 0xf2, 0xc8, 0x79, 0x18, 0xe1, 0xdb, 0xa5, 0xf0, 0x7f, + 0x10, 0xbf, 0xd8, 0xb9, 0x2d, 0x3a, 0x19, 0xf7, 0xf9, 0xdc, 0xd2, 0x84, 0xd6, 0xd9, 0x23, 0x2d, + 0x1c, 0x1c, 0xe3, 0xa7, 0x27, 0xb9, 0x08, 0x51, 0xea, 0x06, 0xfb, 0x52, 0xe8, 0x58, 0x4c, 0xf3, + 0x17, 0xe3, 0xb6, 0x94, 0x8a, 0x5d, 0xb6, 0xee, 0x25, 0x26, 0xdf, 0x7e, 0xb2, 0xa9, 0x6f, 0x3f, + 0xaf, 0xc3, 0x58, 0x79, 0x9f, 0xd6, 0x0f, 0x42, 0x27, 0x9c, 0xbc, 0x50, 0xae, 0x33, 0x20, 0x0f, + 0x89, 0x1e, 0x21, 0x90, 0xeb, 0x00, 0xe8, 0xa6, 0xca, 0x25, 0x52, 0x25, 0xad, 0x09, 0x7a, 0xb5, + 0x0a, 0xf3, 0x14, 0x05, 0x05, 0xd9, 0xd7, 0xcc, 0xdb, 0xaa, 0x3d, 0x0b, 0x67, 0xef, 0x7b, 0xbb, + 0x02, 0x3d, 0x42, 0x60, 0xcd, 0x53, 0xf6, 0x15, 0x71, 0x0a, 0x16, 0x12, 0x9b, 0x8f, 0x8a, 0x44, + 0xae, 0xc1, 0xd8, 0x86, 0x74, 0x24, 0xc0, 0x43, 0x70, 0x02, 0x29, 0x20, 0x72, 0x3a, 0x98, 0xcf, + 0x98, 0x11, 0x0a, 0xf9, 0x2c, 0x8c, 0x96, 0xa9, 0x17, 0x6c, 0x6e, 0xae, 0xa2, 0xd1, 0x09, 0xcf, + 0xfe, 0x91, 0xc7, 0x4c, 0x0d, 0x41, 0xd0, 0xfc, 0xf6, 0x71, 0x71, 0x32, 0x70, 0x5a, 0x34, 0x8c, + 0x6a, 0x6e, 0x4a, 0x6c, 0xb2, 0x04, 0x05, 0xfe, 0x2c, 0x1e, 0xdd, 0x3d, 0xf0, 0x64, 0xcc, 0xf3, + 0x73, 0x5a, 0xbc, 0xa1, 0x1f, 0xd2, 0x9d, 0x30, 0x4f, 0x45, 0x02, 0x9f, 0x2c, 0xcb, 0xf4, 0x2e, + 0x6a, 0x33, 0x21, 0x52, 0x86, 0xc5, 0x77, 0x0c, 0xd6, 0xda, 0x24, 0x05, 0x29, 0xc1, 0x64, 0xd9, + 0x6d, 0x75, 0xec, 0xc0, 0xc1, 0x3c, 0x98, 0x47, 0xe2, 0x10, 0x44, 0x85, 0x5e, 0x5d, 0x2d, 0xd0, + 0x4e, 0x54, 0xb5, 0x80, 0xdc, 0x86, 0x29, 0xd3, 0xed, 0xb2, 0x61, 0x92, 0xb7, 0x70, 0x7e, 0xce, + 0xa1, 0x69, 0x88, 0xc7, 0x4a, 0xd8, 0xb1, 0x2c, 0xae, 0xdc, 0x5a, 0x04, 0x58, 0x8d, 0x8a, 0xac, + 0xa7, 0x3c, 0x87, 0xa8, 0x87, 0x9b, 0x9a, 0xad, 0x22, 0xc1, 0x2c, 0xe5, 0x25, 0xe5, 0x26, 0x8c, + 0xd7, 0x6a, 0xf7, 0x37, 0xa9, 0x1f, 0xdc, 0x6e, 0xba, 0x87, 0x78, 0xb6, 0xe5, 0x45, 0x72, 0x35, + 0xdf, 0xb5, 0x02, 0xea, 0x07, 0xd6, 0x6e, 0xd3, 0x3d, 0x34, 0x55, 0x2c, 0xf2, 0x55, 0xd6, 0x1f, + 0x8a, 0x24, 0x28, 0x62, 0xdd, 0xf6, 0x13, 0x56, 0xf1, 0x04, 0x89, 0x16, 0x0d, 0x13, 0x59, 0xf5, + 0xce, 0x52, 0xd0, 0xd1, 0xa7, 0xcc, 0x73, 0x1f, 0x1d, 0x95, 0x1a, 0x0d, 0x8f, 0xfa, 0xbe, 0x38, + 0x84, 0xb8, 0x4f, 0x19, 0x2a, 0x1b, 0x6c, 0x5e, 0xa0, 0xf9, 0x94, 0x29, 0x04, 0xe4, 0x47, 0x33, + 0x70, 0x4e, 0xf5, 0x36, 0xc1, 0xe5, 0x82, 0x66, 0x2e, 0xfc, 0x48, 0x7a, 0xe3, 0x9a, 0x3c, 0x84, + 0xaf, 0x29, 0x68, 0xd7, 0x1e, 0xde, 0xb8, 0x56, 0x8a, 0x7e, 0xd6, 0x24, 0x11, 0xc6, 0xed, 0x2b, + 0xa6, 0xf2, 0xd3, 0x72, 0x13, 0xcd, 0xd9, 0x29, 0xc4, 0xa4, 0xcc, 0x24, 0x35, 0x36, 0xa3, 0xd0, + 0x70, 0xaa, 0xba, 0x81, 0x67, 0x9a, 0xd0, 0xa8, 0x8a, 0xf9, 0xc7, 0x4d, 0xac, 0x9c, 0x8e, 0x2e, + 0x90, 0x29, 0x34, 0xa4, 0x0a, 0xd3, 0x1c, 0xc0, 0xb6, 0x05, 0x9e, 0xe6, 0x69, 0x36, 0x4a, 0x34, + 0x21, 0xd8, 0xe0, 0x5b, 0x3f, 0xa6, 0x7a, 0x52, 0x83, 0xb3, 0xc6, 0xe8, 0xc8, 0xfb, 0x30, 0x85, + 0x31, 0xf4, 0xa3, 0xf5, 0x3a, 0x87, 0xab, 0x18, 0x63, 0xcc, 0x8a, 0x92, 0x98, 0xe7, 0xdd, 0x84, + 0xef, 0xef, 0x47, 0x2b, 0xfa, 0x7d, 0x98, 0x42, 0x5b, 0x9d, 0x88, 0xc1, 0xb9, 0x88, 0x81, 0x28, + 0x89, 0x33, 0x08, 0x9a, 0x7e, 0xc4, 0xe0, 0x67, 0x32, 0x70, 0x91, 0x55, 0x94, 0x3e, 0x42, 0xe7, + 0x3f, 0xce, 0x08, 0x61, 0xd4, 0xcd, 0x9e, 0x3c, 0x55, 0x71, 0xd4, 0xf7, 0xf7, 0xd3, 0x38, 0xe0, + 0x47, 0xb1, 0x8f, 0x4f, 0xff, 0xa8, 0x0b, 0x1f, 0xfb, 0xa3, 0x7a, 0xf2, 0x54, 0x3f, 0x2a, 0x68, + 0xfa, 0x69, 0x1c, 0xf0, 0x5a, 0x5b, 0x2b, 0xad, 0xad, 0x46, 0x77, 0xb3, 0xef, 0x2c, 0xb7, 0x15, + 0xad, 0x6d, 0x7d, 0xdc, 0x56, 0xb6, 0xb8, 0x17, 0xb5, 0xd2, 0x0d, 0xf2, 0x5a, 0xab, 0x81, 0xe3, + 0xd7, 0xda, 0x18, 0x8d, 0x19, 0xc3, 0x36, 0x7e, 0x19, 0x62, 0x7c, 0x85, 0xa9, 0xaa, 0x01, 0x23, + 0xfc, 0xd6, 0x2a, 0x3a, 0x19, 0x6d, 0x16, 0xf8, 0x9d, 0xd6, 0x14, 0x25, 0xe4, 0x22, 0xe4, 0x6a, + 0xb5, 0xfb, 0xa2, 0x93, 0xd1, 0x60, 0xd5, 0xf7, 0x5d, 0x93, 0xc1, 0xd8, 0x08, 0xa1, 0x15, 0xaa, + 0x92, 0x93, 0x80, 0x9d, 0x77, 0x26, 0x42, 0x59, 0x7f, 0xcb, 0x3b, 0xe4, 0x50, 0xd4, 0xdf, 0xe2, + 0x0e, 0x19, 0xdd, 0x1c, 0xcb, 0x30, 0x5f, 0xf2, 0x7d, 0xea, 0xb1, 0x09, 0x21, 0x8c, 0x1b, 0x3d, + 0x71, 0xcf, 0x11, 0x07, 0x3b, 0x56, 0x6a, 0xd7, 0x7d, 0xb3, 0x27, 0x22, 0xb9, 0x02, 0xf9, 0x52, + 0xb7, 0xe1, 0xd0, 0x76, 0x5d, 0x0b, 0xcb, 0x66, 0x0b, 0x98, 0x19, 0x96, 0x92, 0x0f, 0xe0, 0x5c, + 0x2c, 0x02, 0xa3, 0xe8, 0x81, 0xd1, 0x68, 0xef, 0x95, 0xf7, 0xb0, 0xc8, 0x20, 0x83, 0x77, 0x49, + 0x3a, 0x25, 0x29, 0x41, 0x61, 0x19, 0xdd, 0xb4, 0x2a, 0x94, 0xbf, 0x0d, 0xb9, 0x1e, 0xf7, 0xcf, + 0xe3, 0xb7, 0x66, 0x11, 0x67, 0xb2, 0x11, 0x16, 0x9a, 0x09, 0x74, 0x72, 0x0f, 0x66, 0xe3, 0x30, + 0x76, 0x82, 0xf3, 0x0b, 0x32, 0xee, 0x37, 0x09, 0x2e, 0x78, 0x86, 0xa7, 0x51, 0x91, 0x1d, 0x98, + 0x89, 0x0c, 0x92, 0xf4, 0x6b, 0xb3, 0xb4, 0x73, 0x0e, 0xcb, 0xe5, 0xd5, 0xf9, 0x59, 0x31, 0x19, + 0x67, 0x23, 0xe3, 0xa6, 0xf0, 0xfa, 0x6c, 0x26, 0xd9, 0x91, 0x06, 0x4c, 0xd5, 0x9c, 0xbd, 0xb6, + 0xd3, 0xde, 0xbb, 0x47, 0x8f, 0x36, 0x6c, 0xc7, 0x13, 0x16, 0xa7, 0xd2, 0x9e, 0xbc, 0xe4, 0x1f, + 0xb5, 0x5a, 0x34, 0xf0, 0x70, 0x23, 0x64, 0xe5, 0xe8, 0x83, 0xce, 0xae, 0x43, 0x0b, 0x3e, 0xa7, + 0x43, 0xb7, 0xcd, 0x8e, 0xed, 0x68, 0x42, 0x80, 0xce, 0x53, 0x53, 0x5d, 0x4c, 0x0c, 0xa8, 0xba, + 0x68, 0xc2, 0xcc, 0x72, 0xbb, 0xee, 0x1d, 0xe1, 0x13, 0x9d, 0xfc, 0xb8, 0xc9, 0x53, 0x3e, 0xee, + 0x65, 0xf1, 0x71, 0xcf, 0xd9, 0x72, 0x86, 0xa5, 0x7d, 0x5e, 0x92, 0x31, 0xa9, 0xc1, 0x0c, 0x5e, + 0x1c, 0xaa, 0x95, 0x8d, 0x6a, 0xdb, 0x09, 0x1c, 0x3b, 0xa0, 0x0d, 0x21, 0x5c, 0x84, 0x99, 0x5c, + 0xf8, 0x15, 0xd5, 0x69, 0x74, 0x2c, 0x47, 0xa2, 0xa8, 0x4c, 0x13, 0xf4, 0xfd, 0xee, 0x89, 0xd3, + 0x7f, 0x41, 0xf7, 0xc4, 0x2a, 0x4c, 0xc7, 0x43, 0x39, 0x14, 0xa2, 0x73, 0xd8, 0xc7, 0x22, 0x76, + 0x9c, 0xbb, 0x5d, 0x14, 0x26, 0xb5, 0xe4, 0xa9, 0xb1, 0x20, 0x0e, 0xb1, 0x2b, 0xe7, 0x8c, 0x76, + 0xe5, 0xd4, 0x76, 0xa5, 0x33, 0x5c, 0x39, 0xc9, 0x06, 0xc0, 0x6d, 0xd7, 0xab, 0xd3, 0x12, 0xfa, + 0x47, 0x13, 0x2d, 0xdf, 0x15, 0x63, 0x1a, 0x15, 0xf2, 0xf5, 0xb3, 0xcb, 0x7e, 0x5b, 0x71, 0x37, + 0x77, 0x85, 0x87, 0xf1, 0x63, 0x59, 0x98, 0xef, 0xf5, 0x39, 0x7d, 0xae, 0x7b, 0x9f, 0x82, 0xe4, + 0x0a, 0x17, 0xd7, 0xbe, 0x02, 0x8d, 0xaf, 0xf3, 0x45, 0x48, 0x5f, 0xc8, 0xe2, 0x1a, 0x38, 0x1b, + 0x27, 0xd8, 0xf2, 0x9a, 0xe4, 0x16, 0x8c, 0x2b, 0x1f, 0x8f, 0x7b, 0x69, 0xaf, 0xa6, 0x9a, 0xb0, + 0x1b, 0xfe, 0xcd, 0xae, 0x89, 0x7c, 0xdf, 0x92, 0xd7, 0x44, 0xfe, 0x8b, 0x14, 0xb8, 0x8b, 0xf8, + 0x08, 0xb7, 0x02, 0xf0, 0x7d, 0x97, 0x10, 0xc0, 0x7d, 0x9b, 0x6f, 0x81, 0x26, 0xfe, 0x6d, 0xfc, + 0xe6, 0x04, 0x3f, 0x91, 0xd5, 0x5b, 0x62, 0x2f, 0xfb, 0xe0, 0xd8, 0xed, 0x31, 0x7b, 0x96, 0xdb, + 0x63, 0xee, 0xf4, 0xdb, 0xe3, 0xd0, 0x69, 0xb7, 0xc7, 0xd8, 0xf5, 0x6e, 0xf8, 0xcc, 0xd7, 0xbb, + 0x91, 0x33, 0x5d, 0xef, 0x46, 0xcf, 0x74, 0xbd, 0xd3, 0x6e, 0xaa, 0xf9, 0xd3, 0x6e, 0xaa, 0x7f, + 0x75, 0x19, 0x7c, 0x5a, 0x2f, 0x83, 0x69, 0x22, 0xde, 0x99, 0x2e, 0x83, 0x3f, 0xd2, 0xf3, 0x2e, + 0x57, 0xf8, 0x38, 0x42, 0xf9, 0x4b, 0x03, 0xdc, 0xe5, 0x06, 0xbd, 0xc9, 0xcd, 0x3c, 0x99, 0x9b, + 0x1c, 0x79, 0x62, 0x37, 0xb9, 0xd9, 0xc7, 0xbd, 0xc9, 0xcd, 0x3d, 0xc9, 0x9b, 0xdc, 0xb9, 0xbf, + 0x8c, 0x37, 0xb9, 0xf3, 0xff, 0x76, 0x6e, 0x72, 0x7f, 0x0d, 0x0a, 0x71, 0xe1, 0xf2, 0xf4, 0xa8, + 0xc7, 0x4f, 0x2c, 0xe4, 0x24, 0x13, 0x7d, 0xe3, 0xc2, 0x1d, 0xb9, 0x0e, 0xb0, 0xe1, 0x39, 0x0f, + 0xed, 0x80, 0xde, 0x93, 0xd6, 0x6f, 0x22, 0x62, 0x37, 0x87, 0xb2, 0x91, 0x37, 0x15, 0x94, 0xf0, + 0x5e, 0x93, 0x4d, 0xbb, 0xd7, 0x18, 0x3f, 0x9a, 0x85, 0x19, 0x1e, 0xb7, 0xed, 0xe9, 0x7f, 0x84, + 0x7d, 0x4f, 0xbb, 0xad, 0x3e, 0x17, 0xe5, 0x08, 0x50, 0x5b, 0xd7, 0xe7, 0x19, 0xf6, 0x2b, 0x70, + 0x2e, 0xd1, 0x15, 0x78, 0x63, 0xad, 0xc8, 0x88, 0x79, 0x89, 0x3b, 0xeb, 0x7c, 0x7a, 0x25, 0x0f, + 0x6e, 0x9a, 0x09, 0x0a, 0xe3, 0xcf, 0x86, 0x12, 0xfc, 0xc5, 0x83, 0xac, 0xfa, 0xc4, 0x9a, 0x39, + 0xdb, 0x13, 0x6b, 0x76, 0xb0, 0x27, 0xd6, 0x98, 0x50, 0x91, 0x1b, 0x44, 0xa8, 0xf8, 0x00, 0x26, + 0x37, 0xa9, 0xdd, 0xf2, 0x37, 0x5d, 0x91, 0x70, 0x8a, 0xfb, 0x5a, 0xc8, 0x80, 0x78, 0xac, 0x4c, + 0x5e, 0xb8, 0x42, 0x9b, 0xd1, 0x80, 0x11, 0xb0, 0x63, 0x90, 0x67, 0xa0, 0x32, 0x75, 0x0e, 0xea, + 0x2d, 0x7a, 0xb8, 0xcf, 0x2d, 0xba, 0x06, 0x13, 0x82, 0x2e, 0x0a, 0xf5, 0x1c, 0x5d, 0xf7, 0x58, + 0x11, 0xc2, 0x65, 0xed, 0x61, 0x36, 0xfc, 0xb0, 0x76, 0x7e, 0xd3, 0xd3, 0x98, 0xb0, 0x2e, 0x58, + 0x6e, 0x37, 0x3a, 0xae, 0xd3, 0xc6, 0x2e, 0x18, 0x8d, 0xba, 0x80, 0x0a, 0x30, 0xef, 0x02, 0x05, + 0x89, 0xbc, 0x03, 0x53, 0xa5, 0x8d, 0xaa, 0x4a, 0x96, 0x8f, 0x5e, 0x79, 0xed, 0x8e, 0x63, 0x69, + 0xa4, 0x31, 0xdc, 0x7e, 0x37, 0x9f, 0xb1, 0xbf, 0x98, 0x9b, 0x8f, 0xf1, 0x4f, 0x27, 0xe5, 0xf2, + 0xfe, 0x64, 0x1f, 0x48, 0xf4, 0x27, 0x8f, 0xdc, 0x19, 0x9f, 0x3c, 0x86, 0x4e, 0x13, 0x24, 0x35, + 0xf9, 0x76, 0xf8, 0x4c, 0xf2, 0xed, 0xc8, 0x63, 0x3f, 0x5f, 0x8c, 0x9e, 0x51, 0x62, 0x8d, 0xad, + 0xb5, 0xfc, 0x20, 0x6b, 0x2d, 0x55, 0xca, 0x1d, 0x7b, 0x7c, 0x29, 0x17, 0xce, 0x2c, 0xe5, 0xd6, + 0x22, 0xdf, 0xe5, 0xf1, 0x53, 0x5d, 0x42, 0x9e, 0x17, 0x5a, 0x81, 0x99, 0xf4, 0x28, 0x7c, 0xa1, + 0x17, 0xf3, 0x77, 0x94, 0xe8, 0xfc, 0xb5, 0x74, 0xd1, 0xb9, 0xff, 0x79, 0x73, 0x26, 0xe1, 0xf9, + 0x47, 0x9f, 0xac, 0xf0, 0xfc, 0x64, 0x1f, 0x42, 0xfe, 0x4a, 0x7c, 0xfe, 0x2b, 0xf1, 0x79, 0x30, + 0xf1, 0x99, 0xdc, 0x07, 0x62, 0x77, 0x83, 0x7d, 0xda, 0x0e, 0x9c, 0x3a, 0x46, 0xa5, 0x65, 0x43, + 0x8c, 0xaf, 0x32, 0x62, 0xbd, 0x26, 0x4b, 0xd5, 0xf5, 0xaa, 0x95, 0xa2, 0x9f, 0xb7, 0x87, 0xeb, + 0x75, 0xdb, 0xf6, 0xda, 0xa8, 0xc7, 0xba, 0x0e, 0xa3, 0x32, 0xae, 0x69, 0x26, 0x52, 0x51, 0x27, + 0x03, 0x9a, 0x4a, 0x2c, 0xb2, 0x08, 0x79, 0x49, 0xac, 0x26, 0xda, 0x39, 0x14, 0x30, 0x2d, 0x64, + 0xa4, 0x80, 0x19, 0xff, 0xd1, 0x90, 0x3c, 0x13, 0xd8, 0x27, 0x6c, 0xd8, 0x9e, 0xdd, 0xc2, 0x1c, + 0x7c, 0xe1, 0x92, 0x55, 0x6e, 0x03, 0xb1, 0x55, 0x1e, 0xf3, 0x15, 0xd0, 0x49, 0x3e, 0x56, 0x60, + 0xda, 0x28, 0xcd, 0x71, 0x6e, 0x80, 0x34, 0xc7, 0x6f, 0x69, 0x39, 0x82, 0x87, 0xa2, 0xa4, 0x94, + 0x6c, 0x9f, 0xec, 0x9f, 0x1d, 0xf8, 0x96, 0x9a, 0xcc, 0x77, 0x38, 0x0a, 0x13, 0x86, 0x94, 0x7d, + 0xd2, 0xf8, 0x86, 0xd7, 0x9b, 0x91, 0xb3, 0x84, 0x7c, 0x1e, 0xfd, 0xb7, 0x1a, 0xf2, 0x79, 0x19, + 0x40, 0x9c, 0xdd, 0x91, 0xbd, 0xc3, 0x2b, 0xb8, 0x9d, 0x08, 0xbb, 0xe7, 0x20, 0x68, 0xf6, 0xc8, + 0x09, 0xa2, 0x10, 0x1a, 0xbf, 0x4f, 0x60, 0xa6, 0x56, 0xbb, 0x5f, 0x71, 0xec, 0xbd, 0xb6, 0xeb, + 0x07, 0x4e, 0xbd, 0xda, 0xde, 0x75, 0x99, 0x6c, 0x1f, 0x9e, 0x2f, 0x4a, 0xb0, 0xde, 0xe8, 0x6c, + 0x09, 0x8b, 0xd9, 0xdd, 0x71, 0xd9, 0xf3, 0xa4, 0xc2, 0x95, 0xdf, 0x1d, 0x29, 0x03, 0x98, 0x1c, + 0xce, 0xc4, 0xe7, 0x5a, 0x17, 0x43, 0x65, 0x08, 0x23, 0x14, 0x14, 0x9f, 0x7d, 0x0e, 0x32, 0x65, + 0x19, 0xa1, 0xc9, 0x09, 0x2b, 0xae, 0x53, 0x17, 0xb4, 0xc0, 0xd1, 0x51, 0x31, 0x5f, 0x8d, 0x42, + 0xba, 0xc1, 0x7d, 0xb8, 0x83, 0x70, 0xd5, 0xc4, 0x2e, 0xb1, 0x06, 0x8e, 0xe0, 0x9c, 0xe6, 0x44, + 0x3d, 0xe8, 0xeb, 0xcc, 0x6b, 0x42, 0x5c, 0x37, 0x30, 0x66, 0x47, 0xca, 0x13, 0x8d, 0x9a, 0x54, + 0x2f, 0xb5, 0x06, 0x76, 0x40, 0x3e, 0x9f, 0x5a, 0x12, 0xae, 0xee, 0x71, 0x2d, 0x78, 0xb7, 0xb2, + 0x69, 0xf0, 0xf4, 0x81, 0xbd, 0xaa, 0xb6, 0x52, 0xb6, 0x82, 0xfe, 0x35, 0x91, 0x7f, 0x94, 0x81, + 0x0b, 0x1a, 0x46, 0xb8, 0xff, 0xf9, 0x61, 0x7c, 0x91, 0xd4, 0x79, 0xfd, 0xd1, 0x93, 0x99, 0xd7, + 0x2f, 0xe9, 0x6d, 0x89, 0x76, 0x68, 0xb5, 0x0d, 0xbd, 0xbe, 0x90, 0x3c, 0x84, 0x19, 0x2c, 0x92, + 0x2f, 0x45, 0x6c, 0xce, 0x8a, 0x07, 0xa6, 0xb9, 0xe8, 0xb3, 0x79, 0x60, 0x00, 0x4c, 0x01, 0xbf, + 0xf8, 0xad, 0xe3, 0xe2, 0xa4, 0x86, 0x2e, 0xc3, 0x61, 0x5b, 0xd1, 0x73, 0x93, 0xd3, 0xde, 0x75, + 0xb5, 0xfc, 0xfe, 0xf1, 0x2a, 0xc8, 0x7f, 0x9d, 0xe1, 0xef, 0x13, 0xbc, 0x19, 0xb7, 0x3d, 0xb7, + 0x15, 0x96, 0x4b, 0x5b, 0xcd, 0x1e, 0xdd, 0xd6, 0x7c, 0x32, 0xdd, 0xf6, 0x0a, 0x7e, 0x32, 0xdf, + 0x13, 0xac, 0x5d, 0xcf, 0x6d, 0x45, 0x9f, 0xaf, 0x76, 0x5c, 0xcf, 0x8f, 0x24, 0xdf, 0x9f, 0x81, + 0x8b, 0x9a, 0x9a, 0x54, 0xcd, 0x4d, 0x22, 0xc2, 0x2f, 0xcc, 0x86, 0x81, 0x59, 0xa2, 0xa2, 0xa5, + 0x6b, 0x62, 0xfe, 0x5f, 0xc6, 0x2f, 0x50, 0xe2, 0x80, 0x32, 0x24, 0xab, 0xc5, 0xb1, 0x94, 0x4f, + 0xe8, 0x5d, 0x0b, 0x71, 0x60, 0x06, 0xcd, 0x76, 0x34, 0x9b, 0xe2, 0xb9, 0xde, 0x36, 0xc5, 0x61, + 0xd6, 0x21, 0xcc, 0x48, 0xd0, 0xdb, 0xb0, 0x38, 0xc9, 0x95, 0x7c, 0x0f, 0x5c, 0x4c, 0x00, 0xc3, + 0xd5, 0x76, 0xae, 0xe7, 0x6a, 0xfb, 0xd4, 0xc9, 0x71, 0xf1, 0xd5, 0xb4, 0xda, 0xd2, 0x56, 0x5a, + 0xef, 0x1a, 0x88, 0x0d, 0x10, 0x15, 0x0a, 0x79, 0x26, 0x7d, 0x82, 0x7e, 0x4a, 0xcc, 0x0f, 0x05, + 0x9f, 0xed, 0xe5, 0xca, 0x37, 0xa8, 0x47, 0x5e, 0x84, 0x44, 0x28, 0x4c, 0x28, 0xd9, 0x18, 0x8e, + 0x84, 0xf5, 0x48, 0x8f, 0x4a, 0xbe, 0x75, 0x5c, 0xd4, 0xb0, 0xd9, 0x0d, 0x4b, 0x4d, 0xf3, 0xa0, + 0x89, 0x8f, 0x2a, 0x22, 0xf9, 0x8d, 0x0c, 0xcc, 0x31, 0x40, 0x34, 0xa9, 0x44, 0xa3, 0xe6, 0xfb, + 0xcd, 0xfa, 0xfd, 0x27, 0x33, 0xeb, 0x5f, 0xc4, 0x6f, 0x54, 0x67, 0x7d, 0xa2, 0x4b, 0x52, 0x3f, + 0x0e, 0x67, 0xbb, 0x66, 0x21, 0xa6, 0xcd, 0xf6, 0x8b, 0x03, 0xcc, 0x76, 0x3e, 0x00, 0xa7, 0xcf, + 0xf6, 0x9e, 0xb5, 0x90, 0x4d, 0x98, 0x10, 0x97, 0x2b, 0xde, 0x61, 0x2f, 0x68, 0x71, 0xa1, 0xd5, + 0x22, 0x7e, 0xe3, 0x15, 0xc9, 0x2a, 0x12, 0x2d, 0xd4, 0xb8, 0x90, 0x36, 0xcc, 0xf2, 0xdf, 0xba, + 0xb2, 0xab, 0xd8, 0x53, 0xd9, 0x75, 0x45, 0xb4, 0xe8, 0x92, 0xe0, 0x1f, 0xd3, 0x79, 0xa9, 0xf1, + 0x9c, 0x52, 0x18, 0x93, 0x0e, 0x10, 0x0d, 0xcc, 0x17, 0xed, 0xa5, 0xfe, 0x2a, 0xae, 0x57, 0x45, + 0x9d, 0xc5, 0x78, 0x9d, 0xf1, 0x95, 0x9b, 0xc2, 0x9b, 0xd8, 0x30, 0x2d, 0xa0, 0xee, 0x01, 0xe5, + 0x3b, 0xfc, 0x8b, 0x5a, 0x44, 0xad, 0x58, 0x29, 0xbf, 0x95, 0xc9, 0x9a, 0x30, 0xe2, 0x59, 0x6c, + 0x43, 0x8f, 0xf3, 0x23, 0xf7, 0x61, 0xa6, 0xd4, 0xe9, 0x34, 0x1d, 0xda, 0xc0, 0x56, 0x9a, 0x5d, + 0xd6, 0x26, 0x23, 0xca, 0xf7, 0x66, 0xf3, 0x42, 0x71, 0x55, 0xf4, 0xba, 0xb1, 0xed, 0x26, 0x41, + 0x6b, 0xfc, 0x48, 0x26, 0xf1, 0xd1, 0xe4, 0x75, 0x18, 0xc3, 0x1f, 0x4a, 0x90, 0x16, 0xd4, 0x19, + 0xf1, 0x4f, 0x44, 0x6d, 0x54, 0x84, 0xc0, 0x84, 0x25, 0x35, 0x50, 0x63, 0x8e, 0x0b, 0x4b, 0x42, + 0x51, 0x11, 0xa9, 0x26, 0x8a, 0xd2, 0xd7, 0x23, 0x17, 0x09, 0x5d, 0xe8, 0xeb, 0x21, 0x3c, 0x3c, + 0x8c, 0x7f, 0x90, 0xd5, 0xa7, 0x1d, 0xb9, 0xa2, 0xc8, 0xed, 0x4a, 0xa8, 0x48, 0x29, 0xb7, 0x2b, + 0xd2, 0xfa, 0xdf, 0xcd, 0xc0, 0xec, 0x7d, 0x25, 0x51, 0xe8, 0xa6, 0x8b, 0xe3, 0xd2, 0x3f, 0x75, + 0xe6, 0x93, 0x4a, 0x01, 0xa8, 0x66, 0x28, 0x65, 0x33, 0x05, 0xa7, 0x8c, 0x99, 0xf6, 0x3d, 0xe8, + 0x3d, 0x87, 0x1f, 0xa6, 0x64, 0x62, 0xe4, 0xe8, 0x1c, 0x7e, 0xc6, 0xd4, 0x15, 0xc6, 0x4f, 0x64, + 0x61, 0x5c, 0x59, 0x31, 0xe4, 0x33, 0x30, 0xa1, 0x56, 0xab, 0x2a, 0x1c, 0xd5, 0xaf, 0x34, 0x35, + 0x2c, 0xd4, 0x38, 0x52, 0xbb, 0xa5, 0x69, 0x1c, 0xd9, 0xba, 0x40, 0xe8, 0x19, 0x6f, 0x42, 0xef, + 0xa7, 0xdc, 0x84, 0x70, 0x96, 0x2b, 0x1a, 0xa3, 0xbe, 0xf7, 0xa1, 0x77, 0x92, 0xf7, 0x21, 0x54, + 0x5e, 0x29, 0xf4, 0xbd, 0x6f, 0x45, 0xc6, 0x4f, 0x67, 0xa0, 0x10, 0x5f, 0xd3, 0x9f, 0x48, 0xaf, + 0x9c, 0xe1, 0x75, 0xe9, 0xc7, 0xb3, 0x61, 0xe6, 0x16, 0xe9, 0x42, 0xfc, 0xb4, 0x9a, 0x29, 0xbe, + 0xab, 0x3d, 0xfc, 0x3c, 0xab, 0x47, 0xc3, 0x53, 0x83, 0x6f, 0xa4, 0x87, 0xc0, 0x1c, 0xfa, 0xe6, + 0x2f, 0x15, 0x9f, 0x31, 0x3e, 0x84, 0xb9, 0x78, 0x77, 0xe0, 0xe3, 0x4f, 0x09, 0xa6, 0x75, 0x78, + 0x3c, 0xef, 0x53, 0x9c, 0xca, 0x8c, 0xe3, 0x1b, 0x7f, 0x98, 0x8d, 0xf3, 0x16, 0x26, 0x8b, 0x6c, + 0x8f, 0x52, 0x0d, 0x71, 0xc4, 0x1e, 0xc5, 0x41, 0xa6, 0x2c, 0x3b, 0x4b, 0xbe, 0xb5, 0xd0, 0x11, + 0x36, 0x97, 0xee, 0x08, 0x4b, 0x6e, 0xc5, 0xac, 0xb4, 0x95, 0xa8, 0x4d, 0x87, 0x74, 0xc7, 0x8a, + 0x2c, 0xb5, 0x63, 0xc6, 0xd9, 0x65, 0x98, 0xd3, 0x42, 0x90, 0x4b, 0xfa, 0xe1, 0x48, 0xd7, 0x1f, + 0x60, 0x01, 0x27, 0x4e, 0x45, 0x26, 0x2b, 0x30, 0xca, 0x3e, 0x73, 0xcd, 0xee, 0x88, 0x37, 0x1d, + 0x12, 0xba, 0xc5, 0x37, 0xc3, 0xfb, 0xa1, 0xe2, 0x19, 0xdf, 0xa4, 0x4c, 0x42, 0x50, 0x27, 0x96, + 0x40, 0x34, 0xfe, 0x65, 0x86, 0xad, 0xff, 0xfa, 0xc1, 0x77, 0x58, 0xd2, 0x36, 0xd6, 0xa4, 0x3e, + 0x16, 0xb5, 0x7f, 0x9c, 0xe5, 0xb9, 0x78, 0xc4, 0xf4, 0x79, 0x0b, 0x46, 0x36, 0x6d, 0x6f, 0x4f, + 0xa4, 0xcc, 0xd6, 0xb9, 0xf0, 0x82, 0x28, 0xa6, 0x54, 0x80, 0xbf, 0x4d, 0x41, 0xa0, 0xaa, 0xce, + 0xb2, 0x03, 0xa9, 0xce, 0x94, 0x77, 0x81, 0xdc, 0x13, 0x7b, 0x17, 0xf8, 0xae, 0x30, 0xed, 0x4e, + 0x29, 0x18, 0x20, 0xc2, 0xf5, 0xa5, 0x78, 0x96, 0xab, 0x44, 0x2c, 0xf2, 0x88, 0x1d, 0xb9, 0xa5, + 0xe6, 0xcd, 0x52, 0x7c, 0x4b, 0x4f, 0xc9, 0x90, 0x65, 0xfc, 0x71, 0x8e, 0xf7, 0xb1, 0xe8, 0xa8, + 0xcb, 0x9a, 0xdf, 0x39, 0xae, 0x93, 0x98, 0x9e, 0x92, 0x7b, 0xa0, 0x5f, 0x86, 0x21, 0x36, 0x37, + 0x45, 0x6f, 0x22, 0x1e, 0x9b, 0xbf, 0x2a, 0x1e, 0x2b, 0x67, 0x6b, 0x19, 0xcf, 0x24, 0x35, 0x21, + 0x22, 0x1e, 0x5b, 0xea, 0x5a, 0x46, 0x0c, 0x72, 0x05, 0x86, 0xd6, 0xdd, 0x86, 0x8c, 0xa4, 0x3e, + 0x87, 0xd1, 0x47, 0xb4, 0x8c, 0xab, 0xf3, 0x19, 0x13, 0x31, 0x58, 0x5b, 0xc3, 0xfc, 0x13, 0x6a, + 0x5b, 0x5b, 0xbb, 0x76, 0x32, 0xd1, 0x9d, 0x92, 0xf4, 0x66, 0x19, 0xa6, 0xb6, 0x9d, 0x76, 0xc3, + 0x3d, 0xf4, 0x2b, 0xd4, 0x3f, 0x08, 0xdc, 0x8e, 0xb0, 0x37, 0x46, 0xed, 0xfe, 0x21, 0x2f, 0xb1, + 0x1a, 0xbc, 0x48, 0x7d, 0x96, 0xd1, 0x89, 0xc8, 0x12, 0x4c, 0x6a, 0x11, 0x5c, 0xc5, 0xe3, 0x2a, + 0x6a, 0x43, 0xf5, 0xf8, 0xaf, 0xaa, 0x36, 0x54, 0x23, 0x61, 0xe7, 0xb9, 0xf8, 0x7e, 0xe5, 0x89, + 0x35, 0xf1, 0xed, 0x02, 0x87, 0xdc, 0x84, 0x3c, 0x0f, 0xf3, 0x51, 0xad, 0xa8, 0xcf, 0x64, 0x3e, + 0xc2, 0x62, 0x61, 0x72, 0x24, 0xa2, 0x12, 0xd6, 0xe1, 0xd3, 0x50, 0x10, 0x5b, 0x52, 0x94, 0xab, + 0xfd, 0x39, 0x18, 0x2a, 0x57, 0x2b, 0xa6, 0xba, 0x8d, 0xd4, 0x9d, 0x86, 0x67, 0x22, 0x14, 0xbd, + 0xfa, 0xd6, 0x69, 0x70, 0xe8, 0x7a, 0x07, 0x26, 0xf5, 0x03, 0xcf, 0xe1, 0xf9, 0x34, 0x71, 0x21, + 0x7e, 0x86, 0xbc, 0x03, 0xc3, 0x68, 0xf8, 0x1a, 0x3b, 0x19, 0xe2, 0x75, 0x2c, 0x4d, 0x8a, 0x09, + 0x3c, 0x8c, 0x56, 0xb4, 0x26, 0x27, 0x22, 0x6f, 0xc1, 0x50, 0x85, 0xb6, 0x8f, 0x62, 0xa9, 0xfe, + 0x12, 0xc4, 0xe1, 0x86, 0xd0, 0xa0, 0xed, 0x23, 0x13, 0x49, 0x8c, 0x9f, 0xce, 0xc2, 0xb9, 0x94, + 0xcf, 0x7a, 0xf0, 0x99, 0xa7, 0x74, 0x57, 0x5c, 0xd2, 0x76, 0x45, 0xf9, 0x3e, 0xde, 0xb3, 0xe3, + 0x53, 0x37, 0xc9, 0x5f, 0xc8, 0xc0, 0x05, 0x7d, 0x82, 0x0a, 0x4b, 0xf7, 0x07, 0x37, 0xc9, 0xdb, + 0x30, 0xb2, 0x42, 0xed, 0x06, 0x95, 0x79, 0xbd, 0xce, 0x85, 0x01, 0xf9, 0x78, 0x0c, 0x03, 0x5e, + 0xc8, 0xd9, 0x46, 0x1e, 0xaf, 0x1c, 0x4a, 0x2a, 0xe2, 0xe3, 0xb8, 0xf8, 0x6e, 0xc8, 0x78, 0x22, + 0x69, 0x55, 0xf5, 0xb1, 0x32, 0xf9, 0x56, 0x06, 0x9e, 0xed, 0x43, 0xc3, 0x06, 0x8e, 0x0d, 0xbd, + 0x3a, 0x70, 0x78, 0xa2, 0x22, 0x94, 0xbc, 0x07, 0xd3, 0x9b, 0x42, 0xfc, 0x97, 0xc3, 0x91, 0x8d, + 0xd6, 0x8b, 0xbc, 0x19, 0x58, 0x72, 0x5c, 0xe2, 0xc8, 0x5a, 0xa0, 0x9b, 0x5c, 0xdf, 0x40, 0x37, + 0x6a, 0xdc, 0x98, 0xa1, 0x41, 0xe3, 0xc6, 0x7c, 0x08, 0x73, 0x7a, 0xdb, 0x44, 0xf8, 0xde, 0x28, + 0x6a, 0x4e, 0xa6, 0x77, 0xd4, 0x9c, 0xbe, 0x41, 0x42, 0x8d, 0x9f, 0xc8, 0x40, 0x41, 0xe7, 0xfd, + 0xb8, 0xe3, 0xf9, 0xae, 0x36, 0x9e, 0xcf, 0xa6, 0x8f, 0x67, 0xef, 0x81, 0xfc, 0xbf, 0x33, 0xf1, + 0xc6, 0x0e, 0x34, 0x82, 0x06, 0x8c, 0x54, 0xdc, 0x96, 0xed, 0xb4, 0xd5, 0xd4, 0xff, 0x0d, 0x84, + 0x98, 0xa2, 0x64, 0xb0, 0x20, 0x43, 0x97, 0x60, 0x78, 0xdd, 0x6d, 0x97, 0x2a, 0xc2, 0xa4, 0x18, + 0xf9, 0xb4, 0xdd, 0xb6, 0x65, 0x37, 0x4c, 0x5e, 0x40, 0x56, 0x01, 0x6a, 0x75, 0x8f, 0xd2, 0x76, + 0xcd, 0xf9, 0x6e, 0x1a, 0x93, 0x34, 0x58, 0x0f, 0x35, 0xbb, 0xb8, 0xb1, 0xf0, 0xa7, 0x53, 0x44, + 0xb4, 0x7c, 0xe7, 0xbb, 0xd5, 0xfd, 0x56, 0xa1, 0xc7, 0x75, 0x25, 0xe2, 0xb0, 0xc5, 0xc6, 0xe1, + 0xc6, 0x27, 0xb1, 0xae, 0x52, 0xab, 0xc2, 0x1e, 0xbe, 0x91, 0x3a, 0x1c, 0x7f, 0x90, 0x81, 0x67, + 0xfb, 0xd0, 0x3c, 0x81, 0x51, 0xf9, 0x8b, 0xee, 0x70, 0x0a, 0x10, 0x11, 0x61, 0x26, 0x65, 0xa7, + 0x11, 0xf0, 0x5c, 0x7d, 0x93, 0x22, 0x93, 0x32, 0x03, 0x68, 0x99, 0x94, 0x19, 0x80, 0x9d, 0xa5, + 0x2b, 0xd4, 0xd9, 0xdb, 0xe7, 0xe6, 0x61, 0x93, 0x7c, 0x6f, 0xd8, 0x47, 0x88, 0x7a, 0x96, 0x72, + 0x1c, 0xe3, 0x5f, 0x0d, 0xc3, 0x45, 0x93, 0xee, 0x39, 0xec, 0x5e, 0xb2, 0xe5, 0x3b, 0xed, 0x3d, + 0x2d, 0xee, 0x8e, 0x11, 0x5b, 0xb9, 0x22, 0x49, 0x05, 0x83, 0x84, 0x33, 0xf1, 0x2a, 0xe4, 0x99, + 0x18, 0xa2, 0x2c, 0x5e, 0x7c, 0xe3, 0x62, 0xc2, 0x8a, 0x08, 0xec, 0x2c, 0x8b, 0xc9, 0x6b, 0x42, + 0x4c, 0x52, 0xd2, 0x08, 0x31, 0x31, 0xe9, 0xdb, 0xc7, 0x45, 0xa8, 0x1d, 0xf9, 0x01, 0xc5, 0x2b, + 0xb2, 0x10, 0x95, 0xc2, 0xbb, 0xcc, 0x50, 0x8f, 0xbb, 0xcc, 0x1a, 0xcc, 0x95, 0x1a, 0xfc, 0x74, + 0xb4, 0x9b, 0x1b, 0x9e, 0xd3, 0xae, 0x3b, 0x1d, 0xbb, 0x29, 0xef, 0xe7, 0xd8, 0xcb, 0x76, 0x58, + 0x6e, 0x75, 0x42, 0x04, 0x33, 0x95, 0x8c, 0x35, 0xa3, 0xb2, 0x5e, 0xc3, 0xf0, 0x34, 0xe2, 0xf9, + 0x12, 0x9b, 0xd1, 0x68, 0xfb, 0xd8, 0x0a, 0xdf, 0x0c, 0x8b, 0xf1, 0x16, 0x85, 0x06, 0x01, 0x9b, + 0xab, 0xb5, 0xc8, 0xa5, 0x9a, 0x67, 0x39, 0xe0, 0x86, 0x05, 0x41, 0xd3, 0x47, 0x53, 0x4c, 0x0d, + 0x2f, 0xa2, 0xab, 0xd5, 0x56, 0x18, 0x5d, 0x3e, 0x41, 0xe7, 0xfb, 0xfb, 0x2a, 0x1d, 0xc7, 0x23, + 0xd7, 0xd9, 0x54, 0x68, 0xb9, 0x01, 0xc5, 0x29, 0x3c, 0x16, 0xdd, 0xb9, 0x3c, 0x84, 0xf2, 0x3b, + 0x97, 0x82, 0x42, 0xde, 0x81, 0xd9, 0xe5, 0xf2, 0xa2, 0x54, 0x3a, 0x57, 0xdc, 0x7a, 0x17, 0x0d, + 0x01, 0x00, 0xeb, 0xc3, 0x31, 0xa4, 0xf5, 0x45, 0xb6, 0x9b, 0xa4, 0xa1, 0x91, 0xcb, 0x30, 0x5a, + 0xad, 0xf0, 0xbe, 0x1f, 0x57, 0x53, 0x79, 0x09, 0xcb, 0x2c, 0x59, 0x48, 0xee, 0x47, 0x97, 0x82, + 0x89, 0x53, 0xa5, 0xf7, 0x8b, 0x03, 0x5c, 0x08, 0xde, 0x82, 0xc9, 0x25, 0x37, 0xa8, 0xb6, 0xfd, + 0xc0, 0x6e, 0xd7, 0x69, 0xb5, 0xa2, 0xc6, 0xd5, 0xde, 0x71, 0x03, 0xcb, 0x11, 0x25, 0xec, 0xcb, + 0x75, 0x4c, 0xf2, 0x39, 0x24, 0xbd, 0x43, 0xdb, 0xd4, 0x8b, 0xe2, 0x69, 0x0f, 0xf3, 0xbe, 0x65, + 0xa4, 0x7b, 0x61, 0x89, 0xa9, 0x23, 0x8a, 0x34, 0x63, 0x3c, 0x39, 0x68, 0xd9, 0x6d, 0x50, 0x9f, + 0xef, 0x16, 0xdf, 0x41, 0x69, 0xc6, 0x94, 0xb6, 0xf5, 0xd9, 0x41, 0xff, 0x7d, 0x4c, 0x33, 0x96, + 0xc0, 0x25, 0x9f, 0x83, 0x61, 0xfc, 0x29, 0xa4, 0xdb, 0xd9, 0x14, 0xb6, 0x91, 0x64, 0x5b, 0x67, + 0x98, 0x26, 0x27, 0x20, 0x55, 0x18, 0x15, 0x17, 0xab, 0xb3, 0x24, 0xcb, 0x11, 0x37, 0x34, 0x3e, + 0x33, 0x04, 0xbd, 0xd1, 0x80, 0x09, 0xb5, 0x42, 0xb6, 0x22, 0x56, 0x6c, 0x7f, 0x9f, 0x36, 0xd8, + 0x2f, 0x91, 0xe7, 0x0e, 0x57, 0xc4, 0x3e, 0x42, 0x2d, 0xf6, 0x1d, 0xa6, 0x82, 0xc2, 0xce, 0xd4, + 0xaa, 0xbf, 0xe5, 0x8b, 0x4f, 0x11, 0xaa, 0x16, 0x07, 0xd5, 0x76, 0x0d, 0x53, 0x14, 0x19, 0xdf, + 0x05, 0x73, 0xeb, 0xdd, 0x66, 0xd3, 0xde, 0x69, 0x52, 0x99, 0x07, 0x05, 0x13, 0x8e, 0x2f, 0xc1, + 0x70, 0x4d, 0x49, 0x61, 0x1e, 0xe6, 0xa2, 0x54, 0x70, 0xd0, 0x08, 0x36, 0x83, 0xa1, 0x82, 0x62, + 0xc9, 0xcb, 0x39, 0xa9, 0xf1, 0x7b, 0x19, 0x98, 0x93, 0xe6, 0x02, 0x9e, 0x5d, 0x3f, 0x08, 0xf3, + 0xd8, 0x5f, 0xd6, 0xe6, 0x1a, 0x4e, 0xd8, 0xd8, 0x34, 0xe2, 0xb3, 0xee, 0xae, 0xfc, 0x08, 0x5d, + 0x60, 0x49, 0xfb, 0xe0, 0xd3, 0x3e, 0x86, 0xbc, 0x03, 0xe3, 0xe2, 0x78, 0x54, 0x02, 0x5c, 0x62, + 0x14, 0x31, 0x71, 0xdd, 0x8b, 0x1b, 0xaf, 0xa8, 0xe8, 0x28, 0x8b, 0xe9, 0x4d, 0x79, 0x5c, 0x19, + 0x20, 0x5d, 0x16, 0xd3, 0xeb, 0xe8, 0x33, 0x75, 0x7f, 0x7b, 0x3c, 0xde, 0xb7, 0x62, 0xee, 0xde, + 0x52, 0x43, 0xda, 0x65, 0xa2, 0x9b, 0x71, 0x14, 0xd2, 0x4e, 0xbd, 0x19, 0x87, 0xa8, 0xe1, 0x98, + 0x64, 0x4f, 0x19, 0x93, 0xf7, 0xe4, 0x98, 0xe4, 0x7a, 0x4f, 0x8c, 0xd9, 0x3e, 0xe3, 0x50, 0x8b, + 0x56, 0xc8, 0xd0, 0x40, 0x6a, 0x95, 0x67, 0x30, 0x76, 0x3f, 0x27, 0x89, 0xef, 0xa2, 0x82, 0x93, + 0xaa, 0xab, 0x19, 0x1e, 0x9c, 0xe9, 0x29, 0x5b, 0xf3, 0xe7, 0x61, 0xa2, 0x14, 0x04, 0x76, 0x7d, + 0x9f, 0x36, 0x2a, 0x6c, 0x7b, 0x52, 0xa2, 0x6f, 0xd9, 0x02, 0xae, 0xbe, 0xb1, 0xa9, 0xb8, 0x3c, + 0x9a, 0xac, 0xed, 0x0b, 0x63, 0xda, 0x30, 0x9a, 0x2c, 0x83, 0xe8, 0xd1, 0x64, 0x19, 0x84, 0x5c, + 0x87, 0xd1, 0x6a, 0xfb, 0xa1, 0xc3, 0xfa, 0x84, 0x07, 0xe0, 0x42, 0xdd, 0x94, 0xc3, 0x41, 0xea, + 0xe6, 0x2a, 0xb0, 0xc8, 0x5b, 0xca, 0xa5, 0x66, 0x2c, 0x52, 0x60, 0x70, 0x95, 0x57, 0x18, 0x61, + 0x47, 0xbd, 0xb0, 0x84, 0xb7, 0x9c, 0x5b, 0x30, 0x2a, 0x35, 0x99, 0x10, 0x29, 0x2d, 0x04, 0x65, + 0x32, 0x60, 0x85, 0x44, 0xc6, 0x9c, 0xe4, 0x4a, 0xbe, 0xbe, 0x71, 0x25, 0x27, 0xb9, 0x92, 0xaf, + 0x4f, 0xcb, 0x49, 0xae, 0x64, 0xee, 0x0b, 0x95, 0x40, 0x13, 0xa7, 0x2a, 0x81, 0x1e, 0xc0, 0xc4, + 0x86, 0xed, 0x05, 0x0e, 0x93, 0x51, 0xda, 0x81, 0x3f, 0x3f, 0xa9, 0xe9, 0x4d, 0x95, 0xa2, 0xa5, + 0x17, 0x64, 0x5e, 0xec, 0x8e, 0x82, 0xaf, 0x27, 0x70, 0x8e, 0xe0, 0xe9, 0xa6, 0xb4, 0x53, 0x8f, + 0x63, 0x4a, 0x8b, 0x9d, 0x8a, 0xba, 0xb2, 0xe9, 0x48, 0x23, 0x83, 0x97, 0x96, 0x98, 0xc2, 0x2c, + 0x44, 0x24, 0x5f, 0x86, 0x09, 0xf6, 0xf7, 0x86, 0xdb, 0x74, 0xea, 0x0e, 0xf5, 0xe7, 0x0b, 0xd8, + 0xb8, 0x17, 0x52, 0x57, 0x3f, 0x22, 0x1d, 0xd5, 0x68, 0xc0, 0x17, 0x30, 0x32, 0x8e, 0x2b, 0xc1, + 0x35, 0x6e, 0xe4, 0x7d, 0x98, 0x60, 0xb3, 0x6f, 0xc7, 0xf6, 0xb9, 0x68, 0x3a, 0x13, 0x19, 0x43, + 0x37, 0x04, 0x3c, 0x11, 0xd0, 0x59, 0x25, 0x60, 0xc7, 0x7c, 0xa9, 0xc3, 0x37, 0x48, 0xa2, 0xcc, + 0xf6, 0x4e, 0x62, 0x73, 0x94, 0x68, 0xe4, 0x0b, 0x30, 0x51, 0xea, 0x74, 0xa2, 0x1d, 0x67, 0x56, + 0x51, 0x84, 0x75, 0x3a, 0x56, 0xea, 0xae, 0xa3, 0x51, 0xc4, 0x37, 0xe6, 0xb9, 0x33, 0x6d, 0xcc, + 0xe4, 0x8d, 0x50, 0x5a, 0x3f, 0x17, 0x69, 0x75, 0xc5, 0xc5, 0x51, 0x13, 0xfd, 0xb9, 0xe0, 0x5e, + 0x86, 0x49, 0xae, 0xe6, 0x94, 0xd2, 0xcc, 0xf9, 0xc4, 0xea, 0x49, 0x11, 0x6a, 0x74, 0x1a, 0xb2, + 0x0c, 0x53, 0xdc, 0xdb, 0xbb, 0x29, 0x22, 0x6d, 0xcf, 0x5f, 0xc0, 0x55, 0x8b, 0x5c, 0xb8, 0x93, + 0x78, 0x13, 0x13, 0xb0, 0xd8, 0x1a, 0x97, 0x18, 0x91, 0xf1, 0x27, 0x19, 0xb8, 0xd0, 0x63, 0xc4, + 0xc3, 0x38, 0xcc, 0x99, 0xfe, 0x71, 0x98, 0xd9, 0xce, 0xa1, 0x6b, 0x45, 0xb0, 0xfd, 0x42, 0xca, + 0x52, 0xc7, 0x4b, 0xca, 0x5b, 0x2e, 0x10, 0x91, 0xe3, 0x48, 0x54, 0x7d, 0xd7, 0x45, 0xd5, 0x6c, + 0x2e, 0x79, 0x08, 0x09, 0x3c, 0xfe, 0x51, 0x4b, 0xc6, 0xc9, 0x71, 0xf1, 0x05, 0x91, 0x42, 0x29, + 0x1c, 0xd6, 0x8f, 0x5c, 0x6d, 0x05, 0xa7, 0xb0, 0x36, 0x8e, 0x33, 0x30, 0xae, 0xac, 0x43, 0x72, + 0x49, 0xf1, 0x42, 0x2e, 0xf0, 0x24, 0x5c, 0x0a, 0x87, 0x2c, 0x3f, 0x89, 0x70, 0x51, 0x65, 0x4f, + 0x57, 0x40, 0xaf, 0x31, 0x51, 0x48, 0x89, 0x55, 0xdd, 0xd2, 0xb4, 0xc5, 0x26, 0x96, 0x63, 0x3a, + 0x7f, 0xdb, 0x0f, 0x4a, 0xf5, 0xc0, 0x79, 0x48, 0x07, 0x38, 0x74, 0xa2, 0x74, 0xfe, 0xb6, 0x1f, + 0x58, 0x36, 0x92, 0x25, 0xd2, 0xf9, 0x87, 0x0c, 0x8d, 0x1f, 0xc8, 0x00, 0x6c, 0x55, 0xcb, 0x18, + 0x6c, 0xfe, 0x71, 0x85, 0x82, 0xf4, 0x00, 0xbe, 0x92, 0x7b, 0x1f, 0x71, 0xe0, 0x7f, 0xca, 0xc0, + 0x94, 0x8e, 0x46, 0xde, 0x83, 0xe9, 0x5a, 0xdd, 0x73, 0x9b, 0xcd, 0x1d, 0xbb, 0x7e, 0xb0, 0xea, + 0xb4, 0x29, 0x0f, 0x9d, 0x3a, 0xcc, 0xcf, 0x22, 0x3f, 0x2c, 0xb2, 0x9a, 0xac, 0xcc, 0x8c, 0x23, + 0x93, 0x1f, 0xcc, 0xc0, 0x64, 0x6d, 0xdf, 0x3d, 0x0c, 0xa3, 0x9d, 0x8a, 0x01, 0xf9, 0x0a, 0x5b, + 0xdb, 0xfe, 0xbe, 0x7b, 0x18, 0x65, 0xf0, 0xd4, 0x6c, 0x45, 0xdf, 0x1d, 0xec, 0x19, 0xbf, 0xee, + 0xe2, 0x4d, 0x26, 0xf0, 0xaf, 0x69, 0x95, 0x98, 0x7a, 0x9d, 0xc6, 0x9f, 0x67, 0x60, 0x1c, 0xef, + 0x3c, 0xcd, 0x26, 0xca, 0x5c, 0xdf, 0x49, 0xe9, 0x20, 0xc3, 0x76, 0xf5, 0x19, 0xd8, 0x37, 0x61, + 0x3a, 0x86, 0x46, 0x0c, 0x18, 0xa9, 0x61, 0x80, 0x01, 0x55, 0x41, 0xc1, 0x43, 0x0e, 0x98, 0xa2, + 0xc4, 0x58, 0x56, 0xc8, 0x1e, 0xdc, 0xc0, 0x67, 0xdd, 0x45, 0x00, 0x47, 0x82, 0xe4, 0xcd, 0x86, + 0xc4, 0xbf, 0xe4, 0xc1, 0x0d, 0x53, 0xc1, 0x32, 0xd6, 0x61, 0xa4, 0xe6, 0x7a, 0xc1, 0xd2, 0x11, + 0xbf, 0x4c, 0x54, 0xa8, 0x5f, 0x57, 0xdf, 0x6d, 0x1d, 0x7c, 0x2b, 0xa9, 0x9b, 0xa2, 0x88, 0x14, + 0x61, 0xf8, 0xb6, 0x43, 0x9b, 0x0d, 0xd5, 0x9e, 0x77, 0x97, 0x01, 0x4c, 0x0e, 0x67, 0x17, 0xae, + 0xf3, 0x51, 0x4e, 0x96, 0xc8, 0x70, 0xf8, 0x71, 0xd7, 0x4d, 0x59, 0xeb, 0xdf, 0x17, 0xc3, 0x3c, + 0x08, 0xc9, 0x9a, 0xfa, 0x74, 0xf5, 0x3f, 0xc8, 0xc0, 0x42, 0x6f, 0x12, 0xd5, 0x16, 0x39, 0xd3, + 0xc7, 0x16, 0xf9, 0x95, 0xf8, 0x3b, 0x23, 0xa2, 0x89, 0x77, 0xc6, 0xe8, 0x75, 0xb1, 0x82, 0xa6, + 0xe0, 0x75, 0x2a, 0x13, 0xb1, 0x5c, 0xea, 0xf3, 0xcd, 0x88, 0xc8, 0x87, 0x39, 0x40, 0x1a, 0x53, + 0xd0, 0x1a, 0xbf, 0x35, 0x04, 0x17, 0x7b, 0x52, 0x90, 0x15, 0x25, 0xbd, 0xd3, 0x54, 0x98, 0x58, + 0xa6, 0x27, 0xfe, 0x35, 0xfc, 0x17, 0xad, 0xfd, 0xe2, 0xde, 0x6e, 0xf7, 0xc3, 0xb4, 0x3e, 0x59, + 0xe4, 0xf5, 0xa9, 0x53, 0x79, 0x71, 0x74, 0x64, 0x06, 0xc9, 0x0c, 0x3f, 0xe8, 0x17, 0x49, 0x03, + 0xdb, 0x69, 0xfa, 0xea, 0xb2, 0x6b, 0x70, 0x90, 0x29, 0xcb, 0x22, 0x03, 0xf1, 0xa1, 0x74, 0x03, + 0x71, 0xe3, 0x5f, 0x65, 0x60, 0x2c, 0xfc, 0x6c, 0xb2, 0x00, 0xe7, 0x37, 0xcd, 0x52, 0x79, 0xd9, + 0xda, 0xfc, 0x70, 0x63, 0xd9, 0xda, 0x5a, 0xaf, 0x6d, 0x2c, 0x97, 0xab, 0xb7, 0xab, 0xcb, 0x95, + 0xc2, 0x33, 0x64, 0x06, 0x26, 0xb7, 0xd6, 0xef, 0xad, 0xdf, 0xdf, 0x5e, 0xb7, 0x96, 0x4d, 0xf3, + 0xbe, 0x59, 0xc8, 0x90, 0x49, 0x18, 0x33, 0x97, 0x4a, 0x65, 0x6b, 0xfd, 0x7e, 0x65, 0xb9, 0x90, + 0x25, 0x05, 0x98, 0x28, 0xdf, 0x5f, 0x5f, 0x5f, 0x2e, 0x6f, 0x56, 0x1f, 0x54, 0x37, 0x3f, 0x2c, + 0xe4, 0x08, 0x81, 0x29, 0x44, 0xd8, 0x30, 0xab, 0xeb, 0xe5, 0xea, 0x46, 0x69, 0xb5, 0x30, 0xc4, + 0x60, 0x0c, 0x5f, 0x81, 0x0d, 0x87, 0x8c, 0xee, 0x6d, 0x2d, 0x2d, 0x17, 0x46, 0x18, 0x0a, 0xfb, + 0x4b, 0x41, 0x19, 0x65, 0xd5, 0x23, 0x4a, 0xa5, 0xb4, 0x59, 0x5a, 0x2a, 0xd5, 0x96, 0x0b, 0x79, + 0x72, 0x01, 0x66, 0x35, 0x90, 0xb5, 0x7a, 0xff, 0x4e, 0x75, 0xbd, 0x30, 0x46, 0xe6, 0xa0, 0x10, + 0xc2, 0x2a, 0x4b, 0xd6, 0x56, 0x6d, 0xd9, 0x2c, 0x40, 0x1c, 0xba, 0x5e, 0x5a, 0x5b, 0x2e, 0x8c, + 0x1b, 0xef, 0x72, 0x3f, 0x44, 0xde, 0xd5, 0xe4, 0x3c, 0x90, 0xda, 0x66, 0x69, 0x73, 0xab, 0x16, + 0x6b, 0xfc, 0x38, 0x8c, 0xd6, 0xb6, 0xca, 0xe5, 0xe5, 0x5a, 0xad, 0x90, 0x21, 0x00, 0x23, 0xb7, + 0x4b, 0xd5, 0xd5, 0xe5, 0x4a, 0x21, 0x6b, 0xfc, 0x54, 0x06, 0x66, 0xa4, 0x04, 0x28, 0x1f, 0x8d, + 0x1e, 0x73, 0x2d, 0xbe, 0xa7, 0x5d, 0x6c, 0xa5, 0x93, 0x58, 0xac, 0x92, 0x3e, 0xcb, 0xf0, 0x17, + 0x32, 0x70, 0x2e, 0x15, 0x9b, 0x7c, 0x08, 0x05, 0xf9, 0x05, 0x6b, 0x76, 0x50, 0xdf, 0x8f, 0xf6, + 0xb1, 0x17, 0x62, 0xb5, 0xc4, 0xd0, 0xb8, 0x5a, 0x33, 0x4a, 0x38, 0x9d, 0x60, 0x33, 0x78, 0x3a, + 0x04, 0xe3, 0x9b, 0x19, 0xb8, 0xd0, 0xa3, 0x1a, 0x52, 0x86, 0x91, 0x30, 0x31, 0x4e, 0x1f, 0x83, + 0xb7, 0xb9, 0x6f, 0x1d, 0x17, 0x05, 0x22, 0x66, 0xe8, 0xc5, 0xbf, 0xcc, 0x91, 0x30, 0xd3, 0x0d, + 0xa6, 0x9b, 0xe1, 0xdd, 0x77, 0x31, 0xd6, 0xf3, 0xa2, 0xa6, 0xd2, 0x76, 0x6d, 0x69, 0x5c, 0xf4, + 0x5d, 0xce, 0x3e, 0xf4, 0x31, 0xdf, 0x8c, 0xf1, 0xb3, 0x19, 0x26, 0xdc, 0xc5, 0x11, 0x99, 0xcc, + 0x5b, 0xf2, 0xfd, 0x6e, 0x8b, 0x9a, 0x6e, 0x93, 0x96, 0xcc, 0x75, 0x71, 0x6c, 0xa0, 0xb4, 0x6a, + 0x63, 0x01, 0x5e, 0x2b, 0x2c, 0xdb, 0x6b, 0x6b, 0xaf, 0xd5, 0x2a, 0x0d, 0x79, 0x0b, 0x60, 0xf9, + 0x51, 0x40, 0xbd, 0xb6, 0xdd, 0x0c, 0x63, 0xc4, 0xf0, 0xc8, 0x56, 0x02, 0xaa, 0xcb, 0xdb, 0x0a, + 0xb2, 0xf1, 0xd7, 0x33, 0x30, 0x21, 0x2e, 0x4d, 0xa5, 0x26, 0xf5, 0x82, 0xc7, 0x9b, 0x5e, 0x6f, + 0x69, 0xd3, 0x2b, 0xf4, 0xef, 0x50, 0xf8, 0xb3, 0xe2, 0xd4, 0x99, 0xf5, 0xcf, 0x32, 0x50, 0x88, + 0x23, 0x92, 0xf7, 0x20, 0x5f, 0xa3, 0x0f, 0xa9, 0xe7, 0x04, 0x47, 0x62, 0xa3, 0x94, 0x29, 0x04, + 0x39, 0x8e, 0x28, 0xe3, 0xf3, 0xc1, 0x17, 0xbf, 0xcc, 0x90, 0x66, 0xd0, 0xfd, 0x5e, 0x51, 0x7b, + 0xe4, 0x9e, 0x94, 0xda, 0xc3, 0xf8, 0xdf, 0xb3, 0x70, 0xe1, 0x0e, 0x0d, 0xd4, 0x36, 0x85, 0xe6, + 0x05, 0x9f, 0x1e, 0xac, 0x5d, 0x4a, 0x4b, 0xe6, 0x61, 0x14, 0x8b, 0xe4, 0xf8, 0x9a, 0xf2, 0x27, + 0x59, 0x0a, 0xe7, 0x75, 0x4e, 0xcb, 0x51, 0xd6, 0xa3, 0xee, 0x6b, 0x4a, 0xd6, 0xa2, 0x70, 0x5a, + 0x5f, 0x86, 0x29, 0x0c, 0xcb, 0xdf, 0x65, 0xcb, 0x81, 0x36, 0x84, 0xfa, 0x27, 0x6f, 0xc6, 0xa0, + 0xe4, 0x35, 0x28, 0x30, 0x48, 0xa9, 0x7e, 0xd0, 0x76, 0x0f, 0x9b, 0xb4, 0xb1, 0x47, 0x1b, 0x78, + 0xac, 0xe7, 0xcd, 0x04, 0x5c, 0xf2, 0xdc, 0x6a, 0xf3, 0xab, 0x1b, 0x6d, 0xa0, 0x8e, 0x46, 0xf0, + 0x8c, 0xa0, 0x0b, 0x6f, 0xc1, 0xf8, 0xc7, 0xcc, 0x40, 0x66, 0xfc, 0xaf, 0x19, 0x98, 0xc3, 0xc6, + 0x29, 0x15, 0xcb, 0xec, 0xb0, 0xb2, 0xb7, 0x94, 0xa4, 0x3c, 0x36, 0x03, 0xe9, 0x4b, 0x21, 0xec, + 0xc5, 0x48, 0x27, 0x94, 0x1d, 0x40, 0x27, 0x54, 0x3b, 0x4b, 0x26, 0xfc, 0x01, 0x55, 0x5a, 0x77, + 0x87, 0xf2, 0xb9, 0xc2, 0x50, 0x34, 0xe4, 0xc6, 0x0f, 0x66, 0x61, 0xd4, 0xa4, 0x98, 0x22, 0x9c, + 0x5c, 0x86, 0xd1, 0x75, 0x37, 0xa0, 0xfe, 0x9a, 0x96, 0x0f, 0xbe, 0xcd, 0x40, 0x56, 0xab, 0x61, + 0xca, 0x42, 0x36, 0xe1, 0x37, 0x3c, 0xb7, 0xd1, 0xad, 0x07, 0xea, 0x84, 0xef, 0x70, 0x90, 0x29, + 0xcb, 0xc8, 0xeb, 0x30, 0x26, 0x38, 0x87, 0x8f, 0xba, 0x68, 0xbb, 0xec, 0xd1, 0x30, 0xc5, 0x7c, + 0x84, 0x80, 0x32, 0x2d, 0x17, 0x30, 0x86, 0x14, 0x99, 0x36, 0x21, 0x33, 0x48, 0x51, 0x7d, 0xb8, + 0x8f, 0xa8, 0xfe, 0x69, 0x18, 0x29, 0xf9, 0x3e, 0x0d, 0x64, 0x14, 0x85, 0x89, 0x30, 0x6c, 0x9c, + 0x4f, 0x03, 0xce, 0xd8, 0xc6, 0x72, 0x53, 0xe0, 0x19, 0xff, 0x32, 0x0b, 0xc3, 0xf8, 0x27, 0x3e, + 0x99, 0x7a, 0xf5, 0x7d, 0xed, 0xc9, 0xd4, 0xab, 0xef, 0x9b, 0x08, 0x25, 0x37, 0x50, 0x53, 0x21, + 0xf3, 0x47, 0x89, 0xd6, 0xa3, 0x0a, 0xbe, 0x11, 0x81, 0x4d, 0x15, 0x27, 0x7c, 0xe1, 0xcf, 0xa5, + 0xc6, 0x4e, 0x39, 0x0f, 0xd9, 0xfb, 0x35, 0xd1, 0x62, 0x8c, 0xc8, 0xe5, 0xfa, 0x66, 0xf6, 0x7e, + 0x0d, 0x7b, 0x63, 0xa5, 0xb4, 0xf8, 0xe6, 0x2d, 0xd1, 0x50, 0xde, 0x1b, 0xfb, 0xf6, 0xe2, 0x9b, + 0xb7, 0x4c, 0x51, 0xc2, 0xfa, 0x17, 0xbf, 0x19, 0x1f, 0x5e, 0xb9, 0xcf, 0x3f, 0xf6, 0x2f, 0xb6, + 0x0d, 0x1f, 0x59, 0xcd, 0x08, 0x81, 0x2c, 0xc2, 0xb8, 0x88, 0x35, 0x81, 0xf8, 0x4a, 0x2c, 0x08, + 0x11, 0x8b, 0x82, 0x53, 0xa8, 0x48, 0xfc, 0x09, 0x4e, 0x0c, 0x90, 0xcc, 0x72, 0x2b, 0x9e, 0xe0, + 0xe4, 0x10, 0xfa, 0xa6, 0x82, 0xc2, 0x3e, 0x89, 0xbf, 0xe1, 0x45, 0xbe, 0xfc, 0x53, 0x4a, 0xd0, + 0x02, 0x4c, 0xb3, 0x10, 0x22, 0x18, 0xbf, 0x92, 0x85, 0xfc, 0x46, 0xb3, 0xbb, 0xe7, 0xb4, 0x1f, + 0xdc, 0x20, 0x04, 0xf0, 0x1a, 0x27, 0xf3, 0x70, 0xb0, 0xbf, 0xc9, 0x45, 0xc8, 0xcb, 0x9b, 0x9b, + 0xdc, 0x90, 0x7c, 0x71, 0x6b, 0x9b, 0x07, 0x39, 0xee, 0x22, 0xf4, 0x9a, 0xfc, 0x49, 0x6e, 0x40, + 0x78, 0xff, 0xea, 0x75, 0x51, 0x1b, 0x62, 0x8b, 0xc5, 0x0c, 0xd1, 0xc8, 0x1b, 0x80, 0x87, 0x84, + 0xb8, 0x3c, 0x48, 0x85, 0x36, 0xff, 0x34, 0x21, 0xa7, 0x70, 0x12, 0x44, 0x23, 0x37, 0x41, 0x4c, + 0x4c, 0x91, 0x4d, 0xfd, 0x9c, 0x4e, 0xc0, 0xf3, 0x53, 0x4a, 0x12, 0x81, 0x4a, 0xde, 0x81, 0xf1, + 0xba, 0x47, 0xf1, 0xd5, 0xd1, 0x6e, 0x46, 0x49, 0xd2, 0x55, 0xca, 0x72, 0x54, 0xfe, 0xe0, 0x86, + 0xa9, 0xa2, 0x1b, 0xff, 0x5b, 0x1e, 0x26, 0xd4, 0xef, 0x21, 0x26, 0xcc, 0xfa, 0x4d, 0x76, 0x77, + 0x17, 0xc6, 0x66, 0x1d, 0x2c, 0x14, 0xc7, 0xe9, 0x25, 0xfd, 0x83, 0x18, 0x1e, 0xb7, 0x3c, 0x93, + 0x41, 0x32, 0x56, 0x9e, 0x31, 0x67, 0xfc, 0x08, 0xcc, 0xf1, 0x48, 0x09, 0xf2, 0x6e, 0xc7, 0xdf, + 0xa3, 0x6d, 0x47, 0xbe, 0xb7, 0xbc, 0xa4, 0x31, 0xba, 0x2f, 0x0a, 0x13, 0xbc, 0x42, 0x32, 0xf2, + 0x26, 0x8c, 0xb8, 0x1d, 0xda, 0xb6, 0x1d, 0x71, 0xc6, 0x3d, 0x1b, 0x63, 0x40, 0xdb, 0xa5, 0xaa, + 0x42, 0x28, 0x90, 0xc9, 0x75, 0x18, 0x72, 0x0f, 0xc2, 0xf1, 0xba, 0xa8, 0x13, 0x1d, 0x04, 0xb6, + 0x42, 0x82, 0x88, 0x8c, 0xe0, 0x23, 0xbb, 0xb5, 0x2b, 0x46, 0x4c, 0x27, 0xb8, 0x6b, 0xb7, 0x76, + 0x55, 0x02, 0x86, 0x48, 0xde, 0x07, 0xe8, 0xd8, 0x7b, 0xd4, 0xb3, 0x1a, 0xdd, 0xe0, 0x48, 0x8c, + 0xdb, 0x0b, 0x1a, 0xd9, 0x06, 0x2b, 0xae, 0x74, 0x83, 0x23, 0x85, 0x76, 0xac, 0x23, 0x81, 0xa4, + 0x04, 0xd0, 0xb2, 0x83, 0x80, 0x7a, 0x2d, 0x57, 0x58, 0xfb, 0x45, 0x41, 0x10, 0x39, 0x83, 0xb5, + 0xb0, 0x58, 0xe1, 0xa0, 0x10, 0xe1, 0x47, 0x3b, 0x9e, 0x2d, 0x72, 0xda, 0xc7, 0x3e, 0xda, 0xf1, + 0xb4, 0x56, 0x32, 0x44, 0xf2, 0x39, 0x18, 0x6d, 0x38, 0x7e, 0xdd, 0xf5, 0x1a, 0x22, 0x7a, 0xca, + 0x73, 0x1a, 0x4d, 0x85, 0x97, 0x29, 0x64, 0x12, 0x9d, 0x7d, 0xad, 0x08, 0x82, 0xba, 0xee, 0x1e, + 0xa2, 0x9a, 0x3f, 0xfe, 0xb5, 0xb5, 0xb0, 0x58, 0xfd, 0xda, 0x88, 0x88, 0x0d, 0xe5, 0x9e, 0x13, + 0x34, 0xed, 0x1d, 0xf1, 0xce, 0xad, 0x0f, 0xe5, 0x1d, 0x2c, 0x52, 0x87, 0x92, 0x23, 0x93, 0xb7, + 0x20, 0x4f, 0xdb, 0x81, 0x67, 0x5b, 0x4e, 0x43, 0x38, 0x55, 0xea, 0x1f, 0xcd, 0x0e, 0x60, 0xbb, + 0x5a, 0x51, 0x3f, 0x1a, 0xf1, 0xab, 0x0d, 0xd6, 0x3f, 0x7e, 0xdd, 0x69, 0x09, 0x5f, 0x48, 0xbd, + 0x7f, 0x6a, 0xe5, 0xea, 0x9a, 0xda, 0x3f, 0x0c, 0x91, 0xbc, 0x07, 0xa3, 0x6c, 0xfd, 0x36, 0xdc, + 0x3d, 0x11, 0x90, 0xc2, 0xd0, 0xfb, 0x87, 0x97, 0x25, 0xa6, 0xab, 0x24, 0x62, 0x0b, 0xd9, 0x3e, + 0xf4, 0x2d, 0xa7, 0x2e, 0x82, 0x4c, 0xe8, 0xcb, 0xb1, 0xb4, 0x5d, 0xab, 0x96, 0x15, 0xb2, 0x61, + 0xfb, 0xd0, 0xaf, 0xd6, 0xc9, 0x22, 0x0c, 0x63, 0x8a, 0x0a, 0x11, 0x08, 0x53, 0xa7, 0xc1, 0xe4, + 0x14, 0x2a, 0x0d, 0xa2, 0xb2, 0x81, 0x6c, 0xf9, 0xe8, 0x5e, 0x22, 0x12, 0x45, 0xe8, 0x7d, 0xb2, + 0x56, 0x43, 0x9f, 0x13, 0xf5, 0x13, 0x05, 0x3a, 0xfb, 0xc4, 0x36, 0x0d, 0x2c, 0xe7, 0xeb, 0x22, + 0xd5, 0x83, 0x5e, 0xdd, 0x3a, 0x0d, 0xaa, 0x1f, 0xa8, 0xd5, 0xb5, 0x69, 0x50, 0xfd, 0x3a, 0x79, + 0x01, 0x20, 0x7a, 0xfa, 0xe7, 0x0f, 0x35, 0xa6, 0x02, 0xf9, 0xfc, 0xd0, 0xff, 0xf5, 0x4b, 0xc5, + 0xcc, 0x12, 0xfc, 0x1b, 0xf6, 0xbe, 0xad, 0xc7, 0x91, 0xe3, 0x3a, 0x78, 0x9b, 0xe4, 0xcc, 0x70, + 0x0e, 0xe7, 0xd2, 0x53, 0x3b, 0xbb, 0x33, 0x9a, 0xbd, 0x69, 0x5b, 0xbb, 0xeb, 0x5d, 0xca, 0x92, + 0xb5, 0xab, 0x4f, 0x96, 0x64, 0x5b, 0x96, 0x7b, 0x38, 0x3d, 0x43, 0xee, 0xf2, 0xe6, 0x6e, 0x72, + 0xd6, 0xeb, 0xb5, 0xdd, 0xee, 0x25, 0x7b, 0x66, 0xda, 0xe2, 0x90, 0x34, 0x9b, 0xd4, 0x7a, 0x8c, + 0x0f, 0xf8, 0x6c, 0x7c, 0x80, 0x0d, 0x7c, 0x5f, 0x12, 0x27, 0x4e, 0x82, 0x08, 0x7e, 0xf1, 0x43, + 0x84, 0x20, 0x0f, 0xf9, 0x01, 0x41, 0x9c, 0x17, 0xbf, 0x19, 0x30, 0x0c, 0x18, 0xc8, 0x9b, 0x13, + 0x08, 0x89, 0x80, 0x04, 0xc8, 0xe5, 0x2d, 0x48, 0x1e, 0x0c, 0x04, 0x08, 0xea, 0x54, 0x55, 0x77, + 0xf5, 0x85, 0xdc, 0x59, 0x4b, 0x4a, 0x62, 0xc0, 0x4f, 0x33, 0x3c, 0x75, 0xea, 0x74, 0x5d, 0x4f, + 0x9d, 0x3a, 0x75, 0x2e, 0x90, 0x17, 0x61, 0x75, 0xb4, 0x2a, 0x3c, 0x33, 0x95, 0x59, 0x90, 0x5b, + 0xa0, 0x1e, 0x38, 0x5c, 0x55, 0xd8, 0x39, 0x72, 0xfa, 0x7d, 0xb7, 0xc7, 0xd9, 0xf4, 0xaa, 0x80, + 0x97, 0x18, 0x98, 0x51, 0xd6, 0xde, 0x84, 0xf5, 0xb4, 0x55, 0x42, 0xae, 0xc2, 0x92, 0x1c, 0x41, + 0x88, 0x13, 0x29, 0x38, 0x43, 0x4f, 0xc4, 0x10, 0xe2, 0x04, 0x7e, 0xa4, 0xc0, 0xc5, 0x59, 0x3c, + 0x87, 0x6c, 0x41, 0x7e, 0x38, 0xf2, 0x06, 0x28, 0xdb, 0xf2, 0x14, 0x0d, 0xe2, 0x37, 0x66, 0x5f, + 0x40, 0x21, 0x6c, 0xec, 0x1c, 0x72, 0xaf, 0x10, 0x73, 0x11, 0x21, 0x2d, 0xe7, 0xd0, 0x27, 0xcf, + 0xc3, 0x5a, 0xd7, 0x3d, 0x70, 0x26, 0xbd, 0xb1, 0xed, 0x77, 0x8e, 0xdc, 0x2e, 0xfa, 0x6d, 0xa1, + 0xb5, 0x9f, 0xa9, 0xf2, 0x02, 0x4b, 0xc0, 0x13, 0x2d, 0x9e, 0x9b, 0xd2, 0xe2, 0xbb, 0xb9, 0xbc, + 0xa2, 0x66, 0x4c, 0x34, 0xaf, 0xd2, 0xbe, 0x95, 0x81, 0xcd, 0x69, 0x9b, 0x8c, 0xbc, 0x91, 0x36, + 0x06, 0xec, 0xb5, 0x43, 0x86, 0xcb, 0xaf, 0x1d, 0xd2, 0xd7, 0xc8, 0x1d, 0x08, 0xbc, 0xae, 0x9e, + 0x14, 0x41, 0x41, 0xc0, 0x68, 0x9d, 0xa1, 0xe3, 0xfb, 0x8f, 0x29, 0x1f, 0xc9, 0x4a, 0x51, 0x78, + 0x39, 0x4c, 0xae, 0x23, 0x60, 0xe4, 0x55, 0x80, 0x4e, 0x6f, 0xe0, 0xbb, 0x68, 0x54, 0xc0, 0x05, + 0x14, 0x66, 0x4b, 0x1e, 0x40, 0xe5, 0x57, 0x64, 0x84, 0x96, 0x06, 0x5d, 0x97, 0x4f, 0xa0, 0x03, + 0x1b, 0x53, 0xb8, 0x2a, 0x9d, 0x9e, 0x30, 0xa5, 0xbd, 0x48, 0x90, 0x35, 0x09, 0x12, 0xdb, 0xc7, + 0x47, 0x3c, 0x33, 0x6d, 0x8d, 0x9c, 0x00, 0x49, 0xb2, 0x4e, 0x4a, 0x9d, 0x5b, 0x44, 0x4f, 0x46, + 0x01, 0x75, 0x06, 0x69, 0x8f, 0x7a, 0xe4, 0x0a, 0x14, 0x44, 0x02, 0x4c, 0x7a, 0x01, 0x60, 0xc4, + 0x81, 0x83, 0xee, 0xb9, 0xb8, 0x78, 0x30, 0xcc, 0x2a, 0xfa, 0xd6, 0x71, 0xd1, 0x62, 0x11, 0x21, + 0xad, 0x93, 0xa1, 0xe8, 0xdd, 0x45, 0xb1, 0xbe, 0xa3, 0x07, 0x1a, 0x2f, 0xfd, 0x43, 0x45, 0x4c, + 0x7f, 0xf2, 0x44, 0x78, 0x52, 0xfb, 0x08, 0xa0, 0x6b, 0x13, 0x6f, 0x18, 0xfe, 0x4f, 0x45, 0x1d, + 0xb1, 0xeb, 0xb8, 0xa8, 0xc3, 0x7f, 0x92, 0x1b, 0xb0, 0x3a, 0x62, 0xc6, 0xaf, 0xe3, 0x01, 0x1f, + 0x4f, 0x96, 0x6c, 0x64, 0x99, 0x81, 0x5b, 0x03, 0x1c, 0x53, 0xde, 0xae, 0xbb, 0xc1, 0x80, 0x49, + 0x07, 0x24, 0x79, 0x11, 0x16, 0xe9, 0x01, 0x89, 0xe1, 0x79, 0x62, 0x3e, 0x15, 0x88, 0x87, 0xe2, + 0x86, 0x99, 0xff, 0x1a, 0xff, 0x9f, 0xd3, 0x7a, 0x27, 0x23, 0x88, 0xc9, 0xc7, 0x33, 0xd9, 0x80, + 0x85, 0xc1, 0xe8, 0x50, 0xea, 0xda, 0xfc, 0x60, 0x74, 0x48, 0xfb, 0x75, 0x13, 0x54, 0xe6, 0xe2, + 0xc3, 0x42, 0x2d, 0xf8, 0x27, 0x7d, 0x76, 0x7f, 0xcf, 0x9b, 0x2b, 0x0c, 0x8e, 0x59, 0xfe, 0x4f, + 0xfa, 0x1d, 0x8a, 0xe9, 0xfb, 0x03, 0x5b, 0x8e, 0xca, 0xc5, 0xbb, 0xbd, 0xe2, 0xfb, 0x83, 0x30, + 0x3c, 0x57, 0x97, 0x6c, 0xc3, 0x32, 0xa5, 0x13, 0xc4, 0x06, 0xe3, 0xd2, 0xc3, 0xa5, 0xa4, 0xf4, + 0x70, 0xd2, 0xef, 0x88, 0x26, 0x9a, 0x4b, 0xbe, 0xf4, 0x8b, 0xdc, 0x03, 0x55, 0x12, 0xb3, 0xd0, + 0xe7, 0x33, 0x66, 0x88, 0x1d, 0x92, 0x91, 0xc4, 0xb3, 0x4a, 0xff, 0x60, 0x60, 0xae, 0x76, 0xa2, + 0x00, 0x3e, 0x34, 0x3f, 0x54, 0x04, 0x2f, 0x4d, 0xa9, 0x44, 0x34, 0x58, 0x3e, 0x72, 0x7c, 0xdb, + 0xf7, 0x8f, 0x99, 0x61, 0x19, 0x8f, 0x46, 0x5c, 0x38, 0x72, 0x7c, 0xcb, 0x3f, 0x16, 0xd9, 0x4e, + 0xce, 0x51, 0x9c, 0x81, 0x33, 0x19, 0x1f, 0xd9, 0xb2, 0xd0, 0xc8, 0x46, 0xec, 0xec, 0x91, 0xe3, + 0x37, 0x68, 0x99, 0x44, 0x9b, 0x5c, 0x83, 0x15, 0xa4, 0xdb, 0xf1, 0x04, 0x61, 0x0c, 0x97, 0x61, + 0x2e, 0x51, 0xc2, 0x1d, 0x8f, 0x51, 0xe6, 0x2d, 0xfc, 0xc7, 0x0c, 0x9c, 0x4f, 0x1f, 0x1d, 0x5c, + 0x9e, 0x74, 0x4c, 0xd1, 0xb1, 0x8f, 0xb7, 0x6d, 0x91, 0x42, 0x58, 0xa8, 0x93, 0xb4, 0xc9, 0xc9, + 0xa4, 0x4e, 0x4e, 0x11, 0xd6, 0x90, 0x10, 0x17, 0x4f, 0x7b, 0x9e, 0x3f, 0xe6, 0x11, 0x3c, 0xcc, + 0x55, 0x5a, 0xc0, 0xf8, 0x79, 0x95, 0x82, 0xc9, 0x75, 0x58, 0x11, 0x1c, 0x79, 0xf0, 0xb8, 0x4f, + 0x3f, 0xcc, 0xd8, 0xf1, 0x32, 0x87, 0x36, 0x10, 0x48, 0xce, 0xc1, 0xbc, 0x33, 0x1c, 0xd2, 0x4f, + 0x32, 0x2e, 0x3c, 0xe7, 0x0c, 0x87, 0x2c, 0x23, 0x0f, 0xba, 0x31, 0xda, 0x07, 0x68, 0x5a, 0xc4, + 0xed, 0x18, 0xcd, 0x25, 0x04, 0x32, 0x73, 0x23, 0x9f, 0xee, 0x7b, 0x5a, 0x57, 0xa0, 0x2c, 0x20, + 0x0a, 0x38, 0xc3, 0x00, 0xe1, 0x19, 0xc8, 0x8b, 0x47, 0x6e, 0xe6, 0x8d, 0x61, 0x2e, 0x38, 0xfc, + 0x81, 0xfb, 0x15, 0xd8, 0xe8, 0x7a, 0x3e, 0x2e, 0x5e, 0xd6, 0xa5, 0xe1, 0x90, 0x3b, 0x4e, 0xb2, + 0xc8, 0xbe, 0xe6, 0x3a, 0x2f, 0xa6, 0x23, 0xa9, 0x0f, 0x87, 0xcc, 0x7d, 0x92, 0x8f, 0xf5, 0x6b, + 0xb0, 0xca, 0xc5, 0x34, 0x7e, 0x44, 0x62, 0x5b, 0xf8, 0x06, 0xa6, 0xf7, 0x27, 0x9e, 0x03, 0x09, + 0x38, 0xa8, 0xd2, 0x15, 0x35, 0xff, 0x46, 0x81, 0x73, 0xa9, 0x72, 0x1e, 0xf9, 0x2a, 0x30, 0x3f, + 0xb1, 0xf1, 0xc0, 0x1e, 0xb9, 0x1d, 0x6f, 0xe8, 0x61, 0xe0, 0x0d, 0xa6, 0x07, 0xbd, 0x33, 0x4b, + 0x42, 0x44, 0x9f, 0xb3, 0xd6, 0xc0, 0x0c, 0x2a, 0x31, 0x05, 0x8d, 0x3a, 0x8a, 0x81, 0xb7, 0x1e, + 0xc2, 0xb9, 0x54, 0xd4, 0x14, 0xc5, 0xc9, 0xc7, 0xa3, 0x19, 0xa8, 0xc5, 0xcb, 0x56, 0xac, 0xd3, + 0x92, 0x42, 0x85, 0x77, 0xef, 0xc7, 0x41, 0xf7, 0x62, 0x12, 0x21, 0x31, 0xe2, 0xfb, 0x3a, 0xed, + 0x52, 0x23, 0x2a, 0x4d, 0xdf, 0xda, 0x0f, 0xe1, 0x1c, 0x5f, 0x7c, 0x87, 0x23, 0x67, 0x78, 0x14, + 0x92, 0x63, 0x0d, 0xfd, 0x58, 0x1a, 0x39, 0xb6, 0x2a, 0xf7, 0x28, 0x7e, 0x40, 0xf5, 0xac, 0x93, + 0x04, 0xf2, 0x3e, 0x7c, 0x3b, 0x23, 0xb6, 0x7a, 0x4a, 0x73, 0x52, 0x96, 0xb5, 0x92, 0xb6, 0xac, + 0x4f, 0xbf, 0xa7, 0xea, 0x40, 0x64, 0x66, 0xc5, 0x54, 0xa5, 0xdc, 0x0a, 0x4b, 0x08, 0xf7, 0xbc, + 0x21, 0x12, 0x6b, 0xb0, 0x58, 0x06, 0xd0, 0xb5, 0x4e, 0x1c, 0x44, 0x2e, 0xc0, 0x62, 0x90, 0x64, + 0x9b, 0x1f, 0x1c, 0x79, 0x06, 0xa8, 0x74, 0xc9, 0xb3, 0xb0, 0xc4, 0xe4, 0xf8, 0xc8, 0x9e, 0x03, + 0x84, 0xe9, 0x74, 0xe3, 0x89, 0x31, 0x50, 0xe0, 0xd9, 0x27, 0x8d, 0x21, 0xb9, 0x0f, 0xe7, 0xd1, + 0x16, 0xc4, 0x1f, 0x04, 0xd3, 0x60, 0x77, 0x9c, 0xce, 0x91, 0xcb, 0x57, 0xad, 0x96, 0x3a, 0x19, + 0xc3, 0xa1, 0x65, 0x35, 0xa4, 0x79, 0x18, 0x0e, 0x2d, 0x7f, 0x20, 0x7e, 0x97, 0x68, 0x75, 0xde, + 0x86, 0x2e, 0x5c, 0x98, 0x51, 0x53, 0x62, 0x1c, 0x8a, 0xcc, 0x38, 0x6e, 0x82, 0x7a, 0xe0, 0x76, + 0xa9, 0x4c, 0xec, 0x76, 0xb1, 0x69, 0x6f, 0xdf, 0x61, 0x69, 0xe5, 0xcd, 0x95, 0x00, 0x6e, 0xf9, + 0x83, 0xfd, 0x3b, 0xfc, 0x2b, 0xc7, 0xe2, 0xc8, 0x93, 0xef, 0x22, 0xe4, 0x45, 0x38, 0x1b, 0x0b, + 0x6a, 0x12, 0x7a, 0xc9, 0x9b, 0x6b, 0xb4, 0x28, 0x1a, 0x02, 0xeb, 0x2a, 0x2c, 0x89, 0x55, 0x31, + 0x0a, 0x9c, 0xe7, 0xcc, 0x02, 0x87, 0xd1, 0x5d, 0xc7, 0x3f, 0x37, 0x11, 0x9d, 0x4a, 0xbd, 0xc6, + 0x9c, 0x42, 0x96, 0x26, 0x2f, 0x00, 0x09, 0xe4, 0xf6, 0x80, 0x51, 0xf0, 0x0f, 0xae, 0x89, 0x92, + 0x60, 0x87, 0xf3, 0xcf, 0xfe, 0x65, 0x06, 0xce, 0xa6, 0xdc, 0x7f, 0xe8, 0x25, 0xc0, 0xeb, 0x8f, + 0xdd, 0x43, 0x76, 0x85, 0x90, 0x3b, 0xb9, 0x2a, 0xc1, 0xb9, 0x52, 0x6b, 0x9e, 0xa5, 0x4d, 0xe7, + 0xdf, 0xe2, 0xbf, 0x28, 0xf3, 0x70, 0x46, 0x42, 0x5f, 0x43, 0xff, 0x25, 0x15, 0x58, 0xc3, 0x5c, + 0x10, 0xbe, 0x37, 0xc0, 0x94, 0x12, 0x28, 0x84, 0xe4, 0x22, 0x37, 0x24, 0x6c, 0x45, 0x53, 0x42, + 0xa2, 0x52, 0x88, 0xa9, 0x0e, 0x63, 0x10, 0xf2, 0x69, 0xd8, 0x92, 0xce, 0x1a, 0x3b, 0xb6, 0xf3, + 0xd0, 0x3c, 0xde, 0xdc, 0x70, 0x82, 0x53, 0x67, 0x27, 0xb2, 0x07, 0xb7, 0xe1, 0x32, 0x4e, 0xa2, + 0xd7, 0x1d, 0xda, 0x89, 0xe4, 0x21, 0xd8, 0x55, 0x16, 0x6d, 0x7f, 0x8b, 0x62, 0x55, 0xba, 0xc3, + 0x58, 0x1e, 0x11, 0xda, 0x6b, 0x3e, 0x7c, 0x0f, 0xe1, 0x5c, 0x6a, 0x8b, 0xe9, 0x01, 0x83, 0xd6, + 0x57, 0xa1, 0x6c, 0xb4, 0x40, 0x7f, 0x53, 0xe1, 0xe8, 0x2a, 0x2c, 0x3d, 0x72, 0x9d, 0x91, 0x3b, + 0xe2, 0x27, 0x37, 0x5f, 0x12, 0x0c, 0x26, 0x1f, 0xdc, 0xdd, 0xe8, 0xd4, 0x70, 0x45, 0x13, 0xa9, + 0xc1, 0x59, 0x76, 0x02, 0x7a, 0xc7, 0x28, 0x0c, 0x72, 0xe5, 0x94, 0x12, 0x11, 0x87, 0xb0, 0x0a, + 0x1e, 0x4d, 0x15, 0xc4, 0x62, 0xb5, 0xcd, 0xb5, 0xc3, 0x38, 0x88, 0xee, 0xe8, 0xf3, 0xe9, 0xd8, + 0x64, 0x1b, 0x0a, 0x8c, 0x38, 0xbb, 0x16, 0xb0, 0x57, 0x85, 0xab, 0x33, 0xbf, 0x50, 0x42, 0xa3, + 0x64, 0x3f, 0xf8, 0x9f, 0x9e, 0xd7, 0xf8, 0x80, 0x6b, 0x1f, 0xcb, 0x8f, 0x26, 0xe6, 0x12, 0x02, + 0xf9, 0x63, 0x89, 0xf6, 0x57, 0x8a, 0xe8, 0x6a, 0xe4, 0x46, 0x4d, 0x97, 0x96, 0xef, 0xf6, 0xc5, + 0xc3, 0xd1, 0xa2, 0xc9, 0x7f, 0x3d, 0xe5, 0x52, 0x27, 0xaf, 0xc2, 0x12, 0x25, 0x7b, 0x38, 0xe9, + 0xb3, 0x25, 0x97, 0x8d, 0x04, 0xf3, 0xa9, 0xb1, 0x22, 0x3a, 0x6d, 0xe5, 0x33, 0x66, 0xe1, 0x38, + 0xfc, 0x49, 0xa5, 0x65, 0xff, 0x78, 0x3c, 0x94, 0x17, 0xaa, 0xd0, 0x2e, 0x5a, 0xb5, 0x56, 0x93, + 0x57, 0xc9, 0x53, 0x9c, 0x50, 0x5a, 0xde, 0x9e, 0x67, 0xfa, 0x45, 0xed, 0x79, 0x28, 0x48, 0xb4, + 0x69, 0x67, 0x98, 0xbb, 0x8d, 0xe8, 0x0c, 0xfb, 0xc5, 0x27, 0xfb, 0x11, 0xe4, 0x05, 0x49, 0x7a, + 0x2d, 0x38, 0x1a, 0xf8, 0x62, 0x93, 0xe3, 0xff, 0x14, 0x46, 0x47, 0x19, 0x3b, 0x39, 0x67, 0xe2, + 0xff, 0x78, 0x96, 0x8c, 0x1d, 0x7a, 0x1f, 0xe8, 0xf9, 0xf6, 0x10, 0xcd, 0xb6, 0x02, 0xe1, 0x99, + 0xc2, 0x5b, 0x3d, 0x9f, 0x19, 0x73, 0xf1, 0x6f, 0xfc, 0x79, 0x70, 0x08, 0xc7, 0x54, 0x10, 0xd3, + 0x78, 0x66, 0xe4, 0xc8, 0xc8, 0x24, 0x8f, 0x0c, 0x16, 0xa4, 0x85, 0xd7, 0x64, 0x5f, 0x06, 0x84, + 0xe1, 0x91, 0x21, 0x71, 0x86, 0x5c, 0x84, 0x33, 0x48, 0x77, 0xf2, 0x70, 0xf6, 0xd8, 0x89, 0x23, + 0xee, 0xe4, 0x71, 0x3e, 0xf5, 0x6e, 0xb0, 0x42, 0x22, 0x4a, 0x10, 0x2a, 0x3c, 0x33, 0xc1, 0x99, + 0xa7, 0xf6, 0x8d, 0x31, 0xc8, 0xb3, 0x58, 0xc8, 0x12, 0xff, 0x04, 0x8c, 0xf2, 0xc9, 0x77, 0x4e, + 0xf2, 0x12, 0xac, 0x07, 0xc9, 0x28, 0xfd, 0xb7, 0xbc, 0xa1, 0x8d, 0xe9, 0x48, 0x4f, 0xb8, 0x48, + 0x4b, 0x44, 0x99, 0xf5, 0x96, 0x37, 0xdc, 0xc7, 0x12, 0xde, 0xcc, 0x3f, 0xc9, 0x08, 0x4d, 0xc6, + 0xf6, 0x60, 0x30, 0xf6, 0xc7, 0x23, 0x67, 0x18, 0x51, 0xf3, 0x92, 0x63, 0x78, 0x06, 0x9b, 0x74, + 0x07, 0xd3, 0x83, 0x0c, 0x46, 0x22, 0x7c, 0x49, 0xb0, 0xc1, 0x0a, 0x77, 0x3e, 0x11, 0xbd, 0x8a, + 0xe8, 0x14, 0x5b, 0x97, 0x91, 0xe9, 0xbe, 0x92, 0xa8, 0x96, 0xcf, 0x98, 0x1b, 0x8c, 0x66, 0x02, + 0x8b, 0x94, 0x53, 0x78, 0x4d, 0x5c, 0xcf, 0xbb, 0x1d, 0x32, 0x9e, 0x28, 0x55, 0x99, 0x25, 0x91, + 0xcf, 0xc2, 0xa2, 0xd7, 0x95, 0xb3, 0x60, 0xc6, 0x35, 0x8c, 0x95, 0x2e, 0x8b, 0xc4, 0x1d, 0xd2, + 0xa0, 0x5b, 0xc3, 0xe3, 0xd0, 0xed, 0xe5, 0x88, 0x42, 0x5c, 0xdb, 0x16, 0x97, 0xe6, 0x64, 0x35, + 0xb2, 0x02, 0x99, 0x60, 0x21, 0x66, 0xbc, 0x2e, 0xe3, 0x02, 0x61, 0x2c, 0x70, 0x93, 0xff, 0xd2, + 0xfe, 0x37, 0xdc, 0x3c, 0xed, 0x18, 0x51, 0x8e, 0x31, 0x65, 0xc0, 0x17, 0x59, 0x18, 0xce, 0xe8, + 0xb8, 0x5d, 0x05, 0x39, 0x94, 0xb1, 0x27, 0x96, 0x88, 0x80, 0xb5, 0x47, 0x9e, 0xf6, 0x2f, 0x59, + 0x58, 0x89, 0x3e, 0x01, 0x90, 0xe7, 0x21, 0x27, 0x31, 0xca, 0x8d, 0x94, 0x77, 0x02, 0x64, 0x8f, + 0x88, 0x74, 0x2a, 0xc6, 0x48, 0xee, 0xc2, 0x0a, 0x1a, 0x25, 0xa2, 0x84, 0x3c, 0xf6, 0xf8, 0xc3, + 0xd2, 0xec, 0xb7, 0xc1, 0xfc, 0x4f, 0xde, 0xbb, 0x72, 0x06, 0x9f, 0x01, 0x97, 0x68, 0x5d, 0x2a, + 0xa4, 0xd2, 0x42, 0x49, 0xc3, 0x9b, 0x9b, 0xae, 0xe1, 0xe5, 0x5d, 0x99, 0xa2, 0xe1, 0x9d, 0x9b, + 0xa1, 0xe1, 0x0d, 0x6b, 0xca, 0x1a, 0x5e, 0xd4, 0xf3, 0x2f, 0x4c, 0xd3, 0xf3, 0x87, 0x75, 0x98, + 0x9e, 0x3f, 0xd4, 0xd0, 0xe6, 0xa7, 0x6a, 0x68, 0xc3, 0x3a, 0x5c, 0x43, 0x1b, 0xea, 0x4c, 0x17, + 0xa7, 0xea, 0x4c, 0xa5, 0x4a, 0x4c, 0x67, 0x7a, 0x8d, 0x0f, 0xec, 0xc8, 0x79, 0x6c, 0xe3, 0x88, + 0xf3, 0x23, 0x1f, 0x87, 0xcc, 0x74, 0x1e, 0xa3, 0xb5, 0xd1, 0xf6, 0x22, 0x08, 0x13, 0x25, 0xed, + 0x47, 0x31, 0x06, 0x24, 0xe6, 0xfc, 0x3a, 0xac, 0xb0, 0x73, 0x98, 0x87, 0x77, 0x65, 0x07, 0xf1, + 0xb2, 0xb9, 0x2c, 0xa0, 0xec, 0x2a, 0xfd, 0x31, 0x58, 0x0d, 0xd0, 0xf8, 0x6d, 0x12, 0x3d, 0x17, + 0xcd, 0xa0, 0x36, 0x0f, 0xc3, 0x23, 0xd3, 0x1b, 0xf1, 0x40, 0x37, 0x11, 0x7a, 0x2c, 0x0a, 0xca, + 0x0b, 0x40, 0x42, 0xb4, 0xc0, 0x60, 0x33, 0x87, 0xa8, 0x6b, 0x01, 0x6a, 0x60, 0x55, 0xf9, 0xfb, + 0x4a, 0x4c, 0x47, 0xfb, 0x51, 0x35, 0xff, 0x79, 0x08, 0xbe, 0x6e, 0x73, 0x3d, 0x9b, 0xe8, 0x81, + 0x2a, 0x0a, 0x9a, 0x1c, 0xae, 0x1d, 0xc6, 0xef, 0x84, 0x1f, 0x51, 0xab, 0xb4, 0x1f, 0x67, 0x23, + 0xfa, 0x2b, 0xf1, 0x19, 0x2a, 0xdf, 0xf8, 0x03, 0x9b, 0x4f, 0x31, 0x67, 0xbf, 0x57, 0xa7, 0x2c, + 0x53, 0x6e, 0xa2, 0x66, 0x59, 0x0d, 0x13, 0x7c, 0x7f, 0x20, 0x2c, 0xd6, 0x6c, 0x76, 0xd7, 0x61, + 0x12, 0x19, 0x6e, 0x53, 0x41, 0x8e, 0xf1, 0xda, 0xe2, 0x6c, 0x72, 0x42, 0x81, 0x40, 0x77, 0x29, + 0xde, 0x79, 0x82, 0x5f, 0xe2, 0x03, 0x6d, 0x40, 0x75, 0xaf, 0x1f, 0x25, 0x9e, 0x4d, 0xb9, 0xd5, + 0x26, 0x88, 0xe3, 0x28, 0x21, 0x65, 0x75, 0x22, 0xfe, 0x15, 0x64, 0x0d, 0x58, 0x42, 0xed, 0x91, + 0x20, 0x98, 0x4b, 0x79, 0x51, 0x49, 0x76, 0xbe, 0x54, 0xa9, 0x99, 0x05, 0x5a, 0x4f, 0x90, 0x39, + 0x82, 0x67, 0x64, 0x9d, 0x4f, 0xb4, 0x91, 0x73, 0x22, 0x28, 0xf3, 0xcc, 0x11, 0x08, 0x55, 0x43, + 0xd8, 0xd4, 0xf3, 0x4e, 0x14, 0xc0, 0xd1, 0xb4, 0x23, 0xd8, 0x9a, 0x3e, 0x25, 0x33, 0x12, 0x7e, + 0x85, 0xa2, 0x4d, 0x46, 0x16, 0x6d, 0x64, 0x0d, 0x50, 0x36, 0xa2, 0x01, 0xd2, 0xfe, 0x38, 0x0b, + 0xcf, 0x9d, 0x62, 0xba, 0x66, 0x7c, 0xf3, 0x73, 0x51, 0xc1, 0x39, 0x13, 0xb9, 0xb3, 0x53, 0xa2, + 0xfc, 0x4c, 0x38, 0xe9, 0x77, 0xa6, 0x88, 0xcd, 0x5f, 0x85, 0x55, 0xc6, 0xf8, 0x99, 0x95, 0xe9, + 0xc1, 0xa4, 0x77, 0x0a, 0xce, 0x7f, 0x41, 0xb8, 0xc4, 0xc5, 0xaa, 0xe2, 0x61, 0x80, 0xfc, 0xce, + 0x0a, 0x60, 0xa4, 0x05, 0x05, 0x44, 0x3b, 0x70, 0xbc, 0xde, 0xa9, 0x7c, 0xb3, 0x84, 0xc3, 0x9d, + 0x5c, 0x8d, 0x19, 0xc7, 0x53, 0xc0, 0x2e, 0xfe, 0x26, 0x37, 0x60, 0xb5, 0x3f, 0x39, 0xa6, 0x22, + 0x21, 0x5b, 0x0b, 0xdc, 0x98, 0x67, 0xce, 0x5c, 0xee, 0x4f, 0x8e, 0xf5, 0xe1, 0x10, 0xa7, 0x14, + 0xad, 0x7e, 0xd6, 0x28, 0x1e, 0xdb, 0xb5, 0x02, 0x73, 0x1e, 0x31, 0x29, 0x01, 0xb6, 0x6f, 0x39, + 0xee, 0x3a, 0x30, 0x1b, 0x50, 0x9e, 0xf0, 0x8c, 0xfd, 0xd0, 0xfe, 0x3d, 0x23, 0x34, 0x11, 0xd3, + 0xd7, 0xfd, 0x6f, 0xa6, 0x28, 0x65, 0x8a, 0x6e, 0x82, 0x4a, 0x87, 0x3e, 0x64, 0x2a, 0xc1, 0x1c, + 0xad, 0xf4, 0x27, 0xc7, 0xc1, 0xd8, 0xc9, 0x03, 0x3f, 0x2f, 0x0f, 0xfc, 0xab, 0x42, 0x53, 0x91, + 0xca, 0x1e, 0xa6, 0x0f, 0x39, 0x95, 0x98, 0x6e, 0x9c, 0x8e, 0x09, 0xfc, 0x66, 0xde, 0x52, 0xe6, + 0x2d, 0xa6, 0xd4, 0x9e, 0x4b, 0x28, 0xb5, 0x53, 0xf6, 0xde, 0x7c, 0xda, 0xde, 0x4b, 0xa8, 0xd0, + 0x17, 0x52, 0x54, 0xe8, 0xa9, 0x1b, 0x34, 0xff, 0x84, 0x0d, 0xba, 0x28, 0xaf, 0x93, 0x7f, 0x08, + 0x54, 0x4b, 0xd1, 0x2b, 0xd0, 0x43, 0x38, 0x2b, 0xae, 0x40, 0xec, 0xe4, 0x08, 0x5f, 0x46, 0x0a, + 0x77, 0x6e, 0xa5, 0x5d, 0x7e, 0x10, 0x2d, 0xe5, 0x82, 0xb2, 0xc6, 0xaf, 0x3d, 0x61, 0xf9, 0xff, + 0x9c, 0x0b, 0x0f, 0x79, 0x00, 0xe7, 0x31, 0x5d, 0x40, 0x47, 0x7e, 0xd3, 0xb1, 0x47, 0xee, 0x01, + 0x5f, 0x0f, 0x57, 0x13, 0xd7, 0x03, 0xaf, 0x23, 0x35, 0xc7, 0x74, 0x0f, 0xca, 0x67, 0xcc, 0x75, + 0x3f, 0x05, 0x1e, 0xbf, 0x4b, 0xfd, 0x99, 0x02, 0xda, 0x93, 0xc7, 0x0b, 0xaf, 0xbd, 0xf1, 0x01, + 0xa7, 0xd7, 0x5e, 0x69, 0xf4, 0x9e, 0x83, 0xe5, 0x91, 0x7b, 0x30, 0x72, 0xfd, 0xa3, 0x88, 0x6e, + 0x6a, 0x89, 0x03, 0xc5, 0xc0, 0x88, 0x18, 0xa3, 0x4f, 0x75, 0x19, 0x11, 0x95, 0xb4, 0xdd, 0xe0, + 0x8a, 0x9c, 0x3a, 0x0f, 0x74, 0x35, 0xc9, 0x0d, 0x64, 0x3f, 0xee, 0xe6, 0xf2, 0x19, 0x35, 0x6b, + 0xf2, 0x48, 0xa8, 0x07, 0x5e, 0xcf, 0xd5, 0xfe, 0x42, 0x11, 0x12, 0x41, 0xda, 0xe0, 0x91, 0x87, + 0x92, 0x6d, 0x76, 0x36, 0x21, 0x86, 0xa4, 0x55, 0x91, 0xcd, 0x58, 0x79, 0xb4, 0x4d, 0x04, 0x44, + 0xa2, 0x6d, 0x22, 0xe4, 0x03, 0x18, 0x98, 0x72, 0x45, 0xc1, 0xeb, 0xc2, 0xc0, 0x8b, 0xf2, 0xbc, + 0xfd, 0xdb, 0xe4, 0x16, 0x2c, 0x30, 0x9b, 0x2e, 0xd1, 0xdc, 0xd5, 0x48, 0x73, 0xf7, 0x6f, 0x9b, + 0xa2, 0x5c, 0x7b, 0x27, 0x78, 0x71, 0x4c, 0x74, 0x62, 0xff, 0x36, 0x79, 0xf5, 0x74, 0xb6, 0xd6, + 0x79, 0x61, 0x6b, 0x1d, 0xd8, 0x59, 0xbf, 0x16, 0xb1, 0xb3, 0xbe, 0x36, 0x7b, 0xb4, 0xf8, 0x3b, + 0x31, 0x8b, 0x2e, 0x19, 0x46, 0x1d, 0xfb, 0x45, 0x06, 0x2e, 0xcd, 0xac, 0x41, 0x2e, 0x42, 0x5e, + 0x6f, 0x56, 0x5a, 0xe1, 0xfc, 0xd2, 0x3d, 0x23, 0x20, 0x64, 0x0f, 0x16, 0xb7, 0x1d, 0xdf, 0xeb, + 0xd0, 0x65, 0x9c, 0xfa, 0x70, 0x93, 0x20, 0x1b, 0xa0, 0x97, 0xcf, 0x98, 0x61, 0x5d, 0x62, 0xc3, + 0x1a, 0xee, 0x85, 0x48, 0x26, 0xb1, 0x6c, 0x8a, 0x7a, 0x25, 0x41, 0x30, 0x51, 0x8d, 0xf2, 0x99, + 0x04, 0x90, 0x3c, 0x02, 0x62, 0x59, 0xe5, 0x92, 0x3b, 0x1a, 0x73, 0xb5, 0xc3, 0xd8, 0x0b, 0x0c, + 0x77, 0x5f, 0x7a, 0xc2, 0xd8, 0x25, 0xea, 0x95, 0xcf, 0x98, 0x29, 0xd4, 0xe2, 0xdb, 0xfc, 0x6d, + 0x21, 0xef, 0x4c, 0x1f, 0x84, 0xa7, 0x88, 0xdc, 0x7b, 0x13, 0xf2, 0x4d, 0x61, 0x25, 0x22, 0x39, + 0x40, 0x08, 0x8b, 0x10, 0x33, 0x28, 0xd5, 0x7e, 0x4b, 0x11, 0x7a, 0x96, 0x27, 0x0f, 0x96, 0x94, + 0xe8, 0xad, 0x3b, 0x3b, 0xd1, 0x5b, 0xf7, 0x57, 0x4c, 0xf4, 0xa6, 0x79, 0x70, 0xeb, 0xd4, 0x03, + 0x4b, 0x3e, 0x03, 0x2a, 0xe6, 0xc4, 0x72, 0xa4, 0x49, 0x62, 0xfb, 0x6b, 0x2d, 0x08, 0xe5, 0x5e, + 0xe6, 0x89, 0x07, 0xcd, 0xd5, 0x4e, 0xb4, 0xb6, 0xf6, 0xa7, 0x3c, 0x84, 0x7f, 0xa5, 0xdb, 0x8c, + 0x3d, 0x01, 0x7c, 0x50, 0x9f, 0x19, 0x23, 0xb2, 0xd9, 0x9e, 0x93, 0x72, 0x92, 0x26, 0xbf, 0x35, + 0xdd, 0x75, 0x46, 0xda, 0x79, 0x7f, 0x94, 0x85, 0x8b, 0xb3, 0xaa, 0xa7, 0x66, 0x3d, 0x57, 0x9e, + 0x2e, 0xeb, 0xf9, 0x2d, 0xc8, 0x33, 0x58, 0xe0, 0x10, 0x82, 0x73, 0xcb, 0xab, 0xd2, 0xb9, 0x15, + 0xc5, 0xe4, 0x39, 0x98, 0xd7, 0x4b, 0x56, 0x98, 0x88, 0x0f, 0x2d, 0xb7, 0x9d, 0x8e, 0x8f, 0x36, + 0xc1, 0xbc, 0x88, 0x7c, 0x25, 0x99, 0x7b, 0x92, 0x67, 0xe0, 0xbb, 0x20, 0x0d, 0x48, 0x22, 0xbb, + 0x06, 0xb6, 0x37, 0xcc, 0x06, 0xc1, 0x03, 0xac, 0x9b, 0xc9, 0x3c, 0x96, 0x1a, 0xcc, 0x37, 0x47, + 0xae, 0xef, 0x8e, 0x65, 0xab, 0xea, 0x21, 0x42, 0x4c, 0x5e, 0xc2, 0x6d, 0x9e, 0x9d, 0x13, 0x16, + 0xe2, 0x62, 0x5e, 0x0e, 0x3b, 0x84, 0x46, 0xd2, 0x14, 0x6c, 0x4a, 0x28, 0xb4, 0x42, 0xd5, 0x99, + 0xf4, 0x3b, 0x47, 0x6d, 0xb3, 0xca, 0x25, 0x27, 0x56, 0xa1, 0x87, 0x50, 0xda, 0x41, 0xdf, 0x94, + 0x50, 0xb4, 0xef, 0x2a, 0xb0, 0x9e, 0xd6, 0x0f, 0x72, 0x11, 0x72, 0xfd, 0xd4, 0x34, 0x9b, 0x7d, + 0xe6, 0x99, 0x5f, 0xa0, 0x7f, 0xed, 0x83, 0xc1, 0xe8, 0xd8, 0x19, 0xcb, 0xb6, 0xe7, 0x12, 0xd8, + 0x04, 0xfa, 0x63, 0x17, 0xff, 0x27, 0x57, 0xc4, 0x91, 0x93, 0x4d, 0x24, 0xe6, 0xc4, 0x3f, 0x9a, + 0x0e, 0x50, 0xe9, 0x36, 0x1b, 0x43, 0x96, 0xdd, 0xe1, 0x65, 0xc8, 0xd1, 0x66, 0xc5, 0x56, 0x2f, + 0x5d, 0x3f, 0x7a, 0xad, 0xca, 0x91, 0x58, 0xab, 0x7c, 0xe7, 0xb8, 0x67, 0x22, 0xb2, 0x76, 0x1f, + 0x56, 0xa2, 0x18, 0xc4, 0x88, 0x06, 0xf8, 0x2d, 0xdc, 0x51, 0x39, 0xa5, 0xed, 0xc1, 0x80, 0xf9, + 0x3f, 0x6d, 0x3f, 0xf3, 0x8b, 0xf7, 0xae, 0x00, 0xfd, 0xc9, 0xea, 0xa4, 0x05, 0x00, 0xd6, 0xbe, + 0x97, 0x81, 0xf5, 0x30, 0xe4, 0x82, 0xd8, 0x43, 0xbf, 0xb6, 0xfe, 0xbf, 0x7a, 0xc4, 0x3f, 0x55, + 0xc8, 0x8d, 0xc9, 0x0e, 0xce, 0x70, 0x8b, 0xdb, 0x83, 0xcd, 0x69, 0xf8, 0xe4, 0x79, 0x58, 0xc4, + 0x28, 0x5d, 0x43, 0xa7, 0xe3, 0xca, 0x6c, 0xb6, 0x2f, 0x80, 0x66, 0x58, 0xae, 0xfd, 0x4c, 0x81, + 0x2d, 0xee, 0xb5, 0x53, 0x73, 0xbc, 0x3e, 0xbe, 0xdf, 0x74, 0xdc, 0x0f, 0xc7, 0x7f, 0x7d, 0x2f, + 0xc2, 0xc7, 0xae, 0x47, 0x9d, 0xb3, 0x12, 0x5f, 0x9b, 0xde, 0x5b, 0x72, 0x0b, 0x23, 0xcf, 0x71, + 0xfb, 0x86, 0x1c, 0x8b, 0x17, 0xd2, 0xa7, 0x00, 0x39, 0x5e, 0x08, 0x62, 0x68, 0xff, 0x07, 0x2e, + 0xcf, 0xfe, 0x00, 0xf9, 0x32, 0x2c, 0x63, 0x2a, 0xb5, 0xf6, 0xf0, 0x70, 0xe4, 0x74, 0x5d, 0xa1, + 0xd9, 0x13, 0x0a, 0x68, 0xb9, 0x8c, 0x05, 0xd2, 0xe3, 0xf1, 0x2b, 0x0e, 0x31, 0x49, 0x1b, 0xaf, + 0x14, 0x71, 0x8d, 0x93, 0xa9, 0x69, 0xdf, 0x52, 0x80, 0x24, 0x69, 0x90, 0x4f, 0xc2, 0x52, 0xbb, + 0x55, 0xb2, 0xc6, 0xce, 0x68, 0x5c, 0x1e, 0x4c, 0x46, 0x3c, 0x8a, 0x1d, 0x0b, 0x67, 0x30, 0xee, + 0xd8, 0xec, 0xa5, 0xee, 0x68, 0x30, 0x19, 0x99, 0x11, 0x3c, 0x4c, 0xd9, 0xe5, 0xba, 0x6f, 0x75, + 0x9d, 0x93, 0x68, 0xca, 0x2e, 0x0e, 0x8b, 0xa4, 0xec, 0xe2, 0x30, 0xed, 0x5d, 0x05, 0x2e, 0x08, + 0xb3, 0xd5, 0x6e, 0x4a, 0x5b, 0x4a, 0x18, 0xb4, 0x67, 0x24, 0xc2, 0x26, 0xcf, 0x92, 0xd0, 0xd7, + 0x44, 0x5c, 0x2b, 0x6c, 0x20, 0x8a, 0xea, 0xac, 0x2e, 0xf9, 0x1c, 0xe4, 0xac, 0xf1, 0x60, 0x78, + 0x8a, 0xc0, 0x56, 0x6a, 0x30, 0xa3, 0xe3, 0xc1, 0x10, 0x49, 0x60, 0x4d, 0xcd, 0x85, 0x75, 0xb9, + 0x71, 0xa2, 0xc5, 0xa4, 0x06, 0x0b, 0x3c, 0x82, 0x61, 0xcc, 0x22, 0x64, 0x46, 0x9f, 0xb6, 0x57, + 0x45, 0xf4, 0x2c, 0x1e, 0xb6, 0xd7, 0x14, 0x34, 0xb4, 0xdf, 0x51, 0xa0, 0x40, 0x05, 0x1b, 0xbc, + 0x94, 0x7e, 0xd0, 0x25, 0x1d, 0x95, 0x83, 0x85, 0x81, 0x53, 0x40, 0xfe, 0x54, 0xa7, 0xf1, 0x2b, + 0xb0, 0x1a, 0xab, 0x40, 0x34, 0x8c, 0x9b, 0xd2, 0xf3, 0x3a, 0x0e, 0xcb, 0x00, 0xc4, 0x8c, 0x83, + 0x22, 0x30, 0xed, 0xff, 0x29, 0xb0, 0xde, 0x78, 0x6b, 0xec, 0xb0, 0x07, 0x75, 0x73, 0xd2, 0x13, + 0xfb, 0x9d, 0x0a, 0x6b, 0xc2, 0xfe, 0x99, 0xc5, 0x74, 0x60, 0xc2, 0x1a, 0x87, 0x99, 0x41, 0x29, + 0x29, 0x43, 0x9e, 0x9f, 0x2f, 0x3e, 0x8f, 0xb6, 0x7b, 0x59, 0xd2, 0x8d, 0x84, 0x84, 0x39, 0x12, + 0xed, 0x09, 0xb2, 0x30, 0x5e, 0xc7, 0x0c, 0x6a, 0x6b, 0xff, 0xaa, 0xc0, 0xc6, 0x94, 0x3a, 0xe4, + 0x0d, 0x98, 0x43, 0x7f, 0x53, 0x3e, 0x7b, 0x17, 0xa7, 0x7c, 0x62, 0xdc, 0x39, 0xda, 0xbf, 0xcd, + 0x0e, 0xa2, 0x63, 0xfa, 0xc3, 0x64, 0xb5, 0xc8, 0x43, 0x58, 0xd4, 0xbb, 0x5d, 0x7e, 0x3b, 0xcb, + 0x44, 0x6e, 0x67, 0x53, 0xbe, 0xf8, 0x62, 0x80, 0xcf, 0x6e, 0x67, 0xcc, 0xf3, 0xa9, 0xdb, 0xb5, + 0xb9, 0x2f, 0x6d, 0x48, 0x6f, 0xeb, 0x33, 0xb0, 0x12, 0x45, 0x7e, 0x2a, 0xf7, 0xbf, 0x77, 0x14, + 0x50, 0xa3, 0x6d, 0xf8, 0x68, 0xe2, 0x7e, 0xa5, 0x4d, 0xf3, 0x13, 0x16, 0xd5, 0xef, 0x65, 0xe0, + 0x5c, 0xea, 0x08, 0x93, 0x17, 0x60, 0x5e, 0x1f, 0x0e, 0x2b, 0x3b, 0x7c, 0x55, 0x71, 0x09, 0x09, + 0x95, 0xde, 0x91, 0xcb, 0x2b, 0x43, 0x22, 0x2f, 0x43, 0x9e, 0xd9, 0x6d, 0xec, 0x08, 0x86, 0x83, + 0x81, 0x8c, 0xb8, 0x51, 0x49, 0x34, 0xee, 0xad, 0x40, 0x24, 0xbb, 0xb0, 0xc2, 0x43, 0x00, 0x99, + 0xee, 0xa1, 0xfb, 0x8d, 0x20, 0x01, 0x03, 0xe6, 0x88, 0x10, 0x9a, 0x74, 0x7b, 0xc4, 0xca, 0xe4, + 0x20, 0x38, 0xd1, 0x5a, 0xa4, 0x0a, 0x2a, 0xd2, 0x94, 0x29, 0xb1, 0xe0, 0xbb, 0x18, 0x94, 0x89, + 0x35, 0x62, 0x0a, 0xad, 0x44, 0xcd, 0x60, 0xba, 0x74, 0xdf, 0xf7, 0x0e, 0xfb, 0xc7, 0x6e, 0x7f, + 0xfc, 0xd1, 0x4d, 0x57, 0xf8, 0x8d, 0x53, 0x4d, 0xd7, 0x1f, 0xe4, 0xd8, 0x66, 0x8e, 0x57, 0xa3, + 0x12, 0x8d, 0x14, 0x6f, 0x1d, 0x25, 0x1a, 0x7a, 0x3f, 0xe3, 0x41, 0x6e, 0x76, 0x60, 0x81, 0x05, + 0x1f, 0x12, 0x3b, 0xe3, 0x52, 0x6a, 0x13, 0x18, 0xce, 0xfe, 0x6d, 0x26, 0xbe, 0x30, 0xc7, 0x57, + 0xdf, 0x14, 0x55, 0xc9, 0x3e, 0x14, 0x4a, 0x3d, 0xd7, 0xe9, 0x4f, 0x86, 0xad, 0xd3, 0x3d, 0x1a, + 0x6f, 0xf2, 0xbe, 0x2c, 0x75, 0x58, 0x35, 0x7c, 0x6c, 0x46, 0x4e, 0x2e, 0x13, 0x22, 0xad, 0xc0, + 0x17, 0x2e, 0x87, 0x8a, 0xd7, 0x97, 0x66, 0x8c, 0x4f, 0x1c, 0x88, 0xf5, 0xa2, 0x8e, 0x9e, 0xdc, + 0x59, 0xce, 0x86, 0x95, 0xaa, 0xe3, 0x8f, 0x5b, 0x23, 0xa7, 0xef, 0x63, 0xd0, 0xd2, 0x53, 0x04, + 0x75, 0xbb, 0x20, 0x12, 0x72, 0xa3, 0xca, 0x74, 0x1c, 0x54, 0x65, 0x0a, 0xd9, 0x28, 0x39, 0x2a, + 0x2f, 0xed, 0x7a, 0x7d, 0xa7, 0xe7, 0x7d, 0x53, 0xb8, 0x0c, 0x33, 0x79, 0xe9, 0x40, 0x00, 0xcd, + 0xb0, 0x5c, 0xfb, 0x52, 0x62, 0xde, 0x58, 0x2b, 0x0b, 0xb0, 0xc0, 0x03, 0x4a, 0xb0, 0x00, 0x0b, + 0x4d, 0xa3, 0xbe, 0x53, 0xa9, 0xef, 0xa9, 0x0a, 0x59, 0x01, 0x68, 0x9a, 0x8d, 0x92, 0x61, 0x59, + 0xf4, 0x77, 0x86, 0xfe, 0xe6, 0xd1, 0x17, 0x76, 0xdb, 0x55, 0x35, 0x2b, 0x05, 0x60, 0xc8, 0x69, + 0x3f, 0x55, 0xe0, 0x7c, 0xfa, 0x54, 0x92, 0x16, 0x60, 0x08, 0x0e, 0x6e, 0x3e, 0xf0, 0xc9, 0x99, + 0xf3, 0x9e, 0x0a, 0x8e, 0x87, 0xf2, 0x18, 0xb3, 0x10, 0x11, 0x19, 0xf1, 0xf6, 0xc5, 0x7c, 0x4e, + 0xbd, 0xae, 0x99, 0xf1, 0xba, 0x5a, 0x09, 0x36, 0xa7, 0xd1, 0x88, 0x76, 0x75, 0x15, 0x0a, 0x7a, + 0xb3, 0x59, 0xad, 0x94, 0xf4, 0x56, 0xa5, 0x51, 0x57, 0x15, 0xb2, 0x08, 0x73, 0x7b, 0x66, 0xa3, + 0xdd, 0x54, 0x33, 0xda, 0xf7, 0x15, 0x58, 0xae, 0x84, 0xf6, 0x80, 0x1f, 0x74, 0xf3, 0x7d, 0x2a, + 0xb2, 0xf9, 0x36, 0x83, 0x60, 0x35, 0xc1, 0x07, 0x4e, 0xb5, 0xf3, 0xde, 0xcf, 0xc0, 0x5a, 0xa2, + 0x0e, 0xb1, 0x60, 0x41, 0xbf, 0x6f, 0x35, 0x2a, 0x3b, 0x25, 0xde, 0xb2, 0x2b, 0xa1, 0x21, 0x1b, + 0xa6, 0x2f, 0x4b, 0x7c, 0x85, 0x39, 0x78, 0x3f, 0xf6, 0xed, 0x81, 0xd7, 0x95, 0x72, 0x19, 0x97, + 0xcf, 0x98, 0x82, 0x12, 0x9e, 0x64, 0xdf, 0x9c, 0x8c, 0x5c, 0x24, 0x9b, 0x89, 0xe8, 0x75, 0x03, + 0x78, 0x92, 0x30, 0x7a, 0xd6, 0x38, 0xb4, 0x3c, 0x49, 0x3a, 0xa4, 0x47, 0xea, 0x30, 0xbf, 0xe7, + 0x8d, 0xcb, 0x93, 0x47, 0x7c, 0xff, 0x5e, 0x0e, 0x93, 0x59, 0x95, 0x27, 0x8f, 0x92, 0x64, 0x51, + 0x65, 0xc9, 0x82, 0x31, 0x45, 0x48, 0x72, 0x2a, 0x71, 0x9f, 0xd4, 0xdc, 0x53, 0xf9, 0xa4, 0x6e, + 0x2f, 0x43, 0x81, 0xdf, 0xa1, 0xf0, 0x7a, 0xf2, 0x63, 0x05, 0x36, 0xa7, 0x8d, 0x1c, 0xbd, 0x96, + 0x45, 0x63, 0x4f, 0x9c, 0x0f, 0xb2, 0x9d, 0x44, 0x83, 0x4e, 0x08, 0x34, 0xf2, 0x26, 0x14, 0x98, + 0x95, 0x96, 0xf5, 0x72, 0xdb, 0xac, 0xf0, 0xe5, 0x7a, 0xe9, 0x9f, 0xde, 0xbb, 0xb2, 0xc1, 0x0d, + 0xbb, 0xfc, 0x97, 0xed, 0xc9, 0xc8, 0x8b, 0x64, 0x86, 0x90, 0x6b, 0x50, 0x29, 0xda, 0x99, 0x74, + 0x3d, 0x57, 0xdc, 0x21, 0x84, 0x7f, 0x3e, 0x87, 0xc9, 0x67, 0x9a, 0x80, 0x69, 0xdf, 0x51, 0x60, + 0x6b, 0xfa, 0x34, 0xd1, 0x73, 0xb2, 0xc5, 0x8c, 0xdd, 0x84, 0x87, 0x3c, 0x9e, 0x93, 0x81, 0x45, + 0x9c, 0x4c, 0x53, 0x20, 0xd2, 0x4a, 0x5c, 0xc3, 0x25, 0x94, 0x24, 0x72, 0x7a, 0xf3, 0x68, 0x25, + 0x81, 0xa8, 0x3d, 0x80, 0x8d, 0x29, 0x93, 0x4a, 0x3e, 0x9b, 0x9a, 0x43, 0x09, 0x1d, 0xc8, 0xe4, + 0x1c, 0x4a, 0x91, 0x64, 0x7c, 0x12, 0x5c, 0xfb, 0xe7, 0x0c, 0x9c, 0xa7, 0xbb, 0xab, 0xe7, 0xfa, + 0xbe, 0x1e, 0xa6, 0x1b, 0xa6, 0x5c, 0xf1, 0x55, 0x98, 0x3f, 0x7a, 0x3a, 0x55, 0x31, 0x43, 0x27, + 0x04, 0xf0, 0xc4, 0x12, 0x6e, 0x4b, 0xf4, 0x7f, 0x72, 0x15, 0xe4, 0x5c, 0xf5, 0x59, 0x8c, 0x56, + 0x9b, 0xd9, 0x54, 0xcc, 0xc5, 0x61, 0x90, 0x56, 0xfa, 0x35, 0x98, 0x43, 0x7d, 0x0a, 0x3f, 0x3b, + 0x84, 0xcc, 0x9f, 0xde, 0x3a, 0xd4, 0xb6, 0x98, 0xac, 0x02, 0xf9, 0x04, 0x40, 0x98, 0xe8, 0x83, + 0x1f, 0x0e, 0x42, 0xcf, 0x10, 0xe4, 0xfa, 0x30, 0x17, 0x8f, 0x0f, 0x1c, 0x9e, 0x3d, 0xa3, 0x08, + 0x6b, 0x62, 0xc4, 0x87, 0x22, 0xc8, 0x25, 0x7f, 0xc5, 0x5c, 0x65, 0x05, 0x95, 0xa1, 0x08, 0x74, + 0x79, 0x2d, 0x91, 0x6f, 0x1b, 0x63, 0x5d, 0xc7, 0x92, 0x6a, 0x5f, 0x4b, 0x24, 0xd5, 0xce, 0x33, + 0x2c, 0x39, 0x73, 0xb6, 0xf6, 0xf7, 0x19, 0x58, 0xbc, 0x4f, 0xa5, 0x32, 0xd4, 0x35, 0xcc, 0xd6, + 0x5d, 0xdc, 0x81, 0x42, 0x75, 0xe0, 0xf0, 0xe7, 0x22, 0xee, 0xed, 0xc3, 0x5c, 0xf4, 0x7b, 0x03, + 0x47, 0xbc, 0x3c, 0xf9, 0xa6, 0x8c, 0xf4, 0x84, 0xf0, 0x02, 0x77, 0x61, 0x9e, 0x3d, 0xdf, 0x71, + 0x35, 0x9a, 0x90, 0xcb, 0x83, 0x16, 0xbd, 0xc8, 0x8a, 0xa5, 0x17, 0x0e, 0xf6, 0x04, 0x28, 0x0b, + 0x89, 0x3c, 0x64, 0xaf, 0xa4, 0x59, 0x99, 0x3b, 0x9d, 0x66, 0x45, 0x0a, 0x4d, 0x38, 0x7f, 0x9a, + 0xd0, 0x84, 0x5b, 0xaf, 0x43, 0x41, 0x6a, 0xcf, 0x53, 0x89, 0xe9, 0xdf, 0xce, 0xc0, 0x32, 0xf6, + 0x2a, 0xb0, 0xe5, 0xf9, 0xf5, 0xd4, 0x13, 0x7d, 0x2a, 0xa2, 0x27, 0xda, 0x94, 0xe7, 0x8b, 0xf5, + 0x6c, 0x86, 0x82, 0xe8, 0x2e, 0xac, 0x25, 0x10, 0xc9, 0x2b, 0x30, 0x47, 0x9b, 0x2f, 0xee, 0xd5, + 0x6a, 0x7c, 0x05, 0x84, 0x61, 0xac, 0x69, 0xc7, 0x7d, 0x93, 0x61, 0x6b, 0xff, 0xa6, 0xc0, 0x12, + 0xcf, 0x22, 0xd3, 0x3f, 0x18, 0x3c, 0x71, 0x38, 0x6f, 0xc4, 0x87, 0x93, 0x05, 0xcb, 0xe1, 0xc3, + 0xf9, 0x5f, 0x3d, 0x88, 0xaf, 0x47, 0x06, 0x71, 0x23, 0x08, 0x6a, 0x29, 0xba, 0x33, 0x63, 0x0c, + 0x7f, 0x84, 0x61, 0x9e, 0xa3, 0x88, 0xe4, 0x2b, 0xb0, 0x58, 0x77, 0x1f, 0x47, 0xae, 0xa7, 0x37, + 0xa6, 0x10, 0x7d, 0x31, 0x40, 0x64, 0x7b, 0x0a, 0x4f, 0xf6, 0xbe, 0xfb, 0xd8, 0x4e, 0xbc, 0x1c, + 0x86, 0x24, 0xe9, 0x0d, 0x35, 0x5a, 0xed, 0x69, 0x96, 0x3e, 0x77, 0x3d, 0xc6, 0xf8, 0x4f, 0xdf, + 0xcd, 0x02, 0x84, 0x5e, 0x9b, 0x74, 0x03, 0x46, 0x8c, 0x26, 0x84, 0x66, 0x1f, 0x41, 0xf2, 0x1a, + 0x17, 0xb6, 0x14, 0x37, 0xb8, 0x06, 0x3a, 0x33, 0x3d, 0xe8, 0x28, 0xea, 0xa2, 0x4b, 0xdc, 0x4d, + 0xb0, 0xeb, 0xf6, 0x1c, 0xc6, 0xdb, 0xb3, 0xdb, 0xd7, 0x30, 0xc6, 0x74, 0x00, 0x9d, 0x92, 0x3d, + 0x1c, 0x9d, 0x09, 0x77, 0x28, 0x42, 0xc2, 0x13, 0x3a, 0xf7, 0x74, 0x9e, 0xd0, 0x4d, 0x58, 0xf4, + 0xfa, 0x6f, 0xbb, 0xfd, 0xf1, 0x60, 0x74, 0x82, 0x6a, 0xf7, 0x50, 0x9f, 0x47, 0x87, 0xa0, 0x22, + 0xca, 0xd8, 0x3c, 0xe0, 0x99, 0x1b, 0xe0, 0xcb, 0xd3, 0x10, 0x00, 0x03, 0x4f, 0xee, 0x39, 0x75, + 0xfe, 0x6e, 0x2e, 0x3f, 0xaf, 0x2e, 0xdc, 0xcd, 0xe5, 0xf3, 0xea, 0xe2, 0xdd, 0x5c, 0x7e, 0x51, + 0x05, 0x53, 0x7a, 0x33, 0x0b, 0xde, 0xc4, 0xa4, 0x67, 0xac, 0xe8, 0x13, 0x95, 0xf6, 0xcb, 0x0c, + 0x90, 0x64, 0x33, 0xc8, 0xa7, 0xa0, 0xc0, 0x18, 0xac, 0x3d, 0xf2, 0xbf, 0xce, 0x1d, 0x41, 0x58, + 0x14, 0x2d, 0x09, 0x2c, 0x47, 0xd1, 0x62, 0x60, 0xd3, 0xff, 0x7a, 0x8f, 0x7c, 0x19, 0xce, 0xe2, + 0xf0, 0x0e, 0xdd, 0x91, 0x37, 0xe8, 0xda, 0x18, 0xf2, 0xd8, 0xe9, 0xf1, 0x4c, 0x9f, 0x2f, 0x60, + 0x4a, 0xea, 0x64, 0xf1, 0x94, 0x69, 0x40, 0xe7, 0xcc, 0x26, 0x62, 0x36, 0x19, 0x22, 0x69, 0x81, + 0x2a, 0xd7, 0x3f, 0x98, 0xf4, 0x7a, 0x7c, 0x66, 0x8b, 0xf4, 0x46, 0x1f, 0x2f, 0x9b, 0x42, 0x78, + 0x25, 0x24, 0xbc, 0x3b, 0xe9, 0xf5, 0xc8, 0xab, 0x00, 0x83, 0xbe, 0x7d, 0xec, 0xf9, 0x3e, 0x7b, + 0xcc, 0x09, 0xfc, 0xc8, 0x43, 0xa8, 0x3c, 0x19, 0x83, 0x7e, 0x8d, 0x01, 0xc9, 0xff, 0x02, 0x0c, + 0xbe, 0x81, 0x51, 0x69, 0x98, 0x35, 0x12, 0x4f, 0xc6, 0x23, 0x80, 0x51, 0xb7, 0xf5, 0x43, 0xd7, + 0xf2, 0xbe, 0x29, 0x9c, 0x70, 0xbe, 0x08, 0x6b, 0xdc, 0x5e, 0xfa, 0xbe, 0x37, 0x3e, 0xe2, 0x57, + 0x89, 0x0f, 0x72, 0x0f, 0x91, 0xee, 0x12, 0x7f, 0x9d, 0x03, 0xd0, 0xef, 0x5b, 0x22, 0xe0, 0xdb, + 0x2d, 0x98, 0xa3, 0x17, 0x24, 0xa1, 0x68, 0x41, 0x35, 0x35, 0xd2, 0x95, 0xd5, 0xd4, 0x88, 0x41, + 0x77, 0xa3, 0x89, 0xee, 0x0e, 0x42, 0xc9, 0x82, 0xbb, 0x91, 0x79, 0x40, 0x44, 0x02, 0x6e, 0x73, + 0x2c, 0x52, 0x05, 0x08, 0x43, 0xb0, 0x71, 0x91, 0x7f, 0x2d, 0x8c, 0x65, 0xc4, 0x0b, 0x78, 0xd2, + 0x8f, 0x30, 0x8c, 0x9b, 0xbc, 0x7c, 0x42, 0x34, 0x72, 0x0f, 0x72, 0x2d, 0x27, 0xf0, 0x92, 0x9e, + 0x12, 0x98, 0xee, 0x59, 0x9e, 0x89, 0x35, 0x0c, 0x4e, 0xb7, 0x32, 0x76, 0x22, 0x09, 0xab, 0x91, + 0x08, 0x31, 0x60, 0x9e, 0x67, 0xd9, 0x9f, 0x12, 0xd0, 0x94, 0x27, 0xd9, 0xe7, 0x61, 0xcc, 0x11, + 0x28, 0xcb, 0x14, 0x3c, 0x9f, 0xfe, 0x1d, 0xc8, 0x5a, 0x56, 0x8d, 0x87, 0x63, 0x59, 0x0e, 0xaf, + 0x5f, 0x96, 0x55, 0x63, 0xef, 0xbe, 0xbe, 0x7f, 0x2c, 0x55, 0xa3, 0xc8, 0xe4, 0xd3, 0x50, 0x90, + 0x84, 0x62, 0x1e, 0xc8, 0x08, 0xc7, 0x40, 0xf2, 0x43, 0x93, 0x99, 0x86, 0x84, 0x4d, 0xaa, 0xa0, + 0xde, 0x9b, 0x3c, 0x72, 0xf5, 0xe1, 0x10, 0x1d, 0x54, 0xdf, 0x76, 0x47, 0x4c, 0x6c, 0xcb, 0x87, + 0x11, 0xc0, 0xd1, 0x7b, 0xa5, 0x2b, 0x4a, 0x65, 0x65, 0x53, 0xbc, 0x26, 0x69, 0xc2, 0x9a, 0xe5, + 0x8e, 0x27, 0x43, 0x66, 0x5f, 0xb3, 0x3b, 0x18, 0xd1, 0xfb, 0x0d, 0x0b, 0x7b, 0x84, 0xc1, 0x92, + 0x7d, 0x5a, 0x28, 0x8c, 0x9a, 0x0e, 0x06, 0xa3, 0xd8, 0x5d, 0x27, 0x59, 0x59, 0x73, 0xe5, 0x29, + 0xa7, 0xa7, 0x6a, 0xf4, 0xd6, 0x84, 0xa7, 0xaa, 0xb8, 0x35, 0x85, 0x77, 0xa5, 0x4f, 0xa4, 0x84, + 0xe6, 0xc3, 0x97, 0x41, 0x29, 0x34, 0x5f, 0x24, 0x20, 0xdf, 0xbb, 0x39, 0x29, 0x3a, 0x2c, 0x9f, + 0x8b, 0x37, 0x00, 0xee, 0x0e, 0xbc, 0x7e, 0xcd, 0x1d, 0x1f, 0x0d, 0xba, 0x52, 0x84, 0xc0, 0xc2, + 0xd7, 0x06, 0x5e, 0xdf, 0x3e, 0x46, 0xf0, 0x2f, 0xdf, 0xbb, 0x22, 0x21, 0x99, 0xd2, 0xff, 0xe4, + 0xe3, 0xb0, 0x48, 0x7f, 0xb5, 0x42, 0x2b, 0x21, 0xa6, 0x93, 0xc5, 0xda, 0x2c, 0x87, 0x4a, 0x88, + 0x40, 0x5e, 0xc7, 0xac, 0x41, 0xde, 0x70, 0x2c, 0x09, 0xaf, 0x22, 0x45, 0x90, 0x37, 0x1c, 0xc7, + 0x03, 0x7e, 0x4b, 0xc8, 0xa4, 0x1c, 0x34, 0x5d, 0x24, 0xfa, 0xe2, 0xc9, 0x89, 0x50, 0xf1, 0xc8, + 0xd7, 0x9a, 0x2d, 0x22, 0x0d, 0xcb, 0x19, 0x9c, 0x63, 0xd5, 0xb0, 0x11, 0x56, 0x79, 0x87, 0xbd, + 0x14, 0x71, 0xa1, 0x96, 0x35, 0xc2, 0x3f, 0xea, 0xda, 0x1d, 0x04, 0x47, 0x1a, 0x11, 0x20, 0x93, + 0x6d, 0x58, 0x65, 0x32, 0x7e, 0x90, 0x30, 0x94, 0x8b, 0xb8, 0xc8, 0xdb, 0xc2, 0x8c, 0xa2, 0xf2, + 0xe7, 0x63, 0x15, 0xc8, 0x2e, 0xcc, 0xe1, 0x5d, 0x93, 0x7b, 0x43, 0x5c, 0x90, 0xd5, 0x04, 0xf1, + 0x7d, 0x84, 0x7c, 0x05, 0x15, 0x04, 0x32, 0x5f, 0x41, 0x54, 0xf2, 0x05, 0x00, 0xa3, 0x3f, 0x1a, + 0xf4, 0x7a, 0x18, 0x0b, 0x3b, 0x8f, 0x57, 0xa9, 0x4b, 0xd1, 0xfd, 0x88, 0x54, 0x42, 0x24, 0x1e, + 0xb7, 0x11, 0x7f, 0xdb, 0xb1, 0x88, 0xd9, 0x12, 0x2d, 0xad, 0x02, 0xf3, 0x6c, 0x33, 0x62, 0x5c, + 0x79, 0x9e, 0x29, 0x47, 0x8a, 0x4a, 0xce, 0xe2, 0xca, 0x73, 0x78, 0x32, 0xae, 0xbc, 0x54, 0x41, + 0xbb, 0x07, 0xeb, 0x69, 0x1d, 0x8b, 0xdc, 0x8e, 0x95, 0xd3, 0xde, 0x8e, 0x7f, 0x98, 0x85, 0x25, + 0xa4, 0x26, 0xb8, 0xb0, 0x0e, 0xcb, 0xd6, 0xe4, 0x51, 0x10, 0x74, 0x4d, 0x70, 0x63, 0x6c, 0x9f, + 0x2f, 0x17, 0xc8, 0x6f, 0x78, 0x91, 0x1a, 0xc4, 0x80, 0x15, 0x71, 0x12, 0xec, 0x09, 0xcf, 0x81, + 0x20, 0xa4, 0xbb, 0x70, 0xa8, 0x48, 0x26, 0x4c, 0x8e, 0x55, 0x0a, 0xcf, 0x83, 0xec, 0xd3, 0x9c, + 0x07, 0xb9, 0x53, 0x9d, 0x07, 0x0f, 0x61, 0x49, 0x7c, 0x0d, 0x39, 0xf9, 0xdc, 0x07, 0xe3, 0xe4, + 0x11, 0x62, 0xa4, 0x1a, 0x70, 0xf4, 0xf9, 0x99, 0x1c, 0x1d, 0x1f, 0x46, 0xc5, 0x2e, 0x1b, 0x22, + 0x2c, 0xc9, 0xd8, 0x31, 0xa3, 0xe8, 0x5e, 0xa9, 0xf9, 0x2b, 0x9c, 0x92, 0xaf, 0xc0, 0x62, 0x75, + 0x20, 0xde, 0xc4, 0xa4, 0xc7, 0x88, 0x9e, 0x00, 0xca, 0xe2, 0x42, 0x80, 0x19, 0x9c, 0x6e, 0xd9, + 0x0f, 0xe3, 0x74, 0x7b, 0x1d, 0x80, 0xbb, 0xa4, 0x84, 0x99, 0x00, 0x71, 0xcb, 0x88, 0xd8, 0x31, + 0xd1, 0x37, 0x11, 0x09, 0x99, 0x72, 0x27, 0x6e, 0x6e, 0xa3, 0x77, 0x3a, 0x83, 0x49, 0x7f, 0x1c, + 0x49, 0x9d, 0x2d, 0x7c, 0x8b, 0x1d, 0x5e, 0x26, 0xb3, 0x87, 0x58, 0xb5, 0x0f, 0x77, 0x42, 0xc8, + 0xe7, 0x03, 0xe3, 0xc7, 0x85, 0x59, 0x23, 0xa4, 0x25, 0x46, 0x68, 0xaa, 0xc9, 0xa3, 0xf6, 0x53, + 0x45, 0xce, 0xa7, 0xf1, 0x2b, 0x4c, 0xf5, 0x6b, 0x00, 0x81, 0x51, 0x82, 0x98, 0x6b, 0x76, 0x5f, + 0x0a, 0xa0, 0xf2, 0x28, 0x87, 0xb8, 0x52, 0x6f, 0xb2, 0x1f, 0x56, 0x6f, 0x5a, 0x50, 0x68, 0xbc, + 0x35, 0x76, 0x42, 0x2b, 0x16, 0xb0, 0x02, 0x49, 0x16, 0x39, 0x53, 0x76, 0xfb, 0x3a, 0x9e, 0x0d, + 0xa1, 0x1c, 0x3c, 0x45, 0x04, 0x96, 0x2a, 0x6a, 0xff, 0xa1, 0xc0, 0xaa, 0x1c, 0x10, 0xe1, 0xa4, + 0xdf, 0x21, 0x9f, 0x65, 0xe1, 0x7d, 0x95, 0xc8, 0x95, 0x45, 0x42, 0xa2, 0x2c, 0xf7, 0xa4, 0xdf, + 0x61, 0x02, 0x90, 0xf3, 0x58, 0x6e, 0x2c, 0xad, 0x48, 0x1e, 0xc1, 0x52, 0x73, 0xd0, 0xeb, 0x51, + 0xb1, 0x66, 0xf4, 0x36, 0xbf, 0x00, 0x50, 0x42, 0xf1, 0xa7, 0x11, 0xd1, 0xa0, 0xed, 0xe7, 0xf8, + 0x3d, 0x77, 0x63, 0x48, 0xf9, 0xbd, 0xc7, 0xeb, 0x85, 0x64, 0xdf, 0x41, 0xd7, 0x40, 0x99, 0x66, + 0x78, 0x36, 0x45, 0xf3, 0x42, 0xc8, 0xad, 0xa4, 0xc5, 0xd8, 0xce, 0x19, 0x67, 0x93, 0xf6, 0x73, + 0x05, 0x48, 0xb2, 0x6b, 0x32, 0xeb, 0x53, 0xfe, 0x1b, 0x44, 0xe1, 0x98, 0x08, 0x99, 0x7b, 0x1a, + 0x11, 0x52, 0xfb, 0x81, 0x02, 0xeb, 0x69, 0xe3, 0x40, 0x4f, 0x10, 0xf9, 0x48, 0x09, 0x0e, 0x34, + 0x3c, 0x41, 0xe4, 0x53, 0x28, 0x7a, 0xac, 0xc5, 0x2a, 0xc5, 0x1b, 0x97, 0x79, 0x9a, 0xc6, 0x15, + 0x7f, 0x57, 0x81, 0xd5, 0x8a, 0x5e, 0xe3, 0x69, 0x44, 0xd8, 0x33, 0xd5, 0x55, 0xb8, 0x54, 0xd1, + 0x6b, 0x76, 0xb3, 0x51, 0xad, 0x94, 0x1e, 0xd8, 0xa9, 0xd1, 0xc1, 0x2f, 0xc1, 0x33, 0x49, 0x94, + 0xf0, 0x39, 0xeb, 0x22, 0x6c, 0x26, 0x8b, 0x45, 0x04, 0xf1, 0xf4, 0xca, 0x22, 0xd8, 0x78, 0xb6, + 0xf8, 0x26, 0xac, 0x8a, 0x68, 0xd9, 0xad, 0xaa, 0x85, 0xf9, 0x38, 0x56, 0xa1, 0xb0, 0x6f, 0x98, + 0x95, 0xdd, 0x07, 0xf6, 0x6e, 0xbb, 0x5a, 0x55, 0xcf, 0x90, 0x65, 0x58, 0xe4, 0x80, 0x92, 0xae, + 0x2a, 0x64, 0x09, 0xf2, 0x95, 0xba, 0x65, 0x94, 0xda, 0xa6, 0xa1, 0x66, 0x8a, 0x6f, 0xc2, 0x4a, + 0x73, 0xe4, 0xbd, 0xed, 0x8c, 0xdd, 0x7b, 0xee, 0x09, 0xbe, 0x46, 0x2d, 0x40, 0xd6, 0xd4, 0xef, + 0xab, 0x67, 0x08, 0xc0, 0x7c, 0xf3, 0x5e, 0xc9, 0xba, 0x7d, 0x5b, 0x55, 0x48, 0x01, 0x16, 0xf6, + 0x4a, 0x4d, 0xfb, 0x5e, 0xcd, 0x52, 0x33, 0xf4, 0x87, 0x7e, 0xdf, 0xc2, 0x1f, 0xd9, 0xe2, 0x4b, + 0xb0, 0x86, 0x52, 0x57, 0xd5, 0xf3, 0xc7, 0x6e, 0xdf, 0x1d, 0x61, 0x1b, 0x96, 0x20, 0x6f, 0xb9, + 0x94, 0x5d, 0x8e, 0x5d, 0xd6, 0x80, 0xda, 0xa4, 0x37, 0xf6, 0x86, 0x3d, 0xf7, 0x1b, 0xaa, 0x52, + 0x7c, 0x1d, 0x56, 0xcd, 0xc1, 0x64, 0xec, 0xf5, 0x0f, 0xad, 0x31, 0xc5, 0x38, 0x3c, 0x21, 0xe7, + 0x60, 0xad, 0x5d, 0xd7, 0x6b, 0xdb, 0x95, 0xbd, 0x76, 0xa3, 0x6d, 0xd9, 0x35, 0xbd, 0x55, 0x2a, + 0xb3, 0xb7, 0xb0, 0x5a, 0xc3, 0x6a, 0xd9, 0xa6, 0x51, 0x32, 0xea, 0x2d, 0x55, 0x29, 0x7e, 0x0f, + 0x15, 0x48, 0x9d, 0x41, 0xbf, 0xbb, 0xeb, 0x74, 0xc6, 0x83, 0x11, 0x36, 0x58, 0x83, 0xcb, 0x96, + 0x51, 0x6a, 0xd4, 0x77, 0xec, 0x5d, 0xbd, 0xd4, 0x6a, 0x98, 0x69, 0xe1, 0xe9, 0xb7, 0xe0, 0x7c, + 0x0a, 0x4e, 0xa3, 0xd5, 0x54, 0x15, 0x72, 0x05, 0x2e, 0xa4, 0x94, 0xdd, 0x37, 0xb6, 0xf5, 0x76, + 0xab, 0x5c, 0x57, 0x33, 0x53, 0x2a, 0x5b, 0x56, 0x43, 0xcd, 0x16, 0xff, 0xbf, 0x02, 0x2b, 0x6d, + 0x9f, 0xdb, 0xd5, 0xb7, 0xd1, 0x8b, 0xf8, 0x59, 0xb8, 0xd8, 0xb6, 0x0c, 0xd3, 0x6e, 0x35, 0xee, + 0x19, 0x75, 0xbb, 0x6d, 0xe9, 0x7b, 0xf1, 0xd6, 0x5c, 0x81, 0x0b, 0x12, 0x86, 0x69, 0x94, 0x1a, + 0xfb, 0x86, 0x69, 0x37, 0x75, 0xcb, 0xba, 0xdf, 0x30, 0x77, 0x54, 0x85, 0x7e, 0x31, 0x05, 0xa1, + 0xb6, 0xab, 0xb3, 0xd6, 0x44, 0xca, 0xea, 0xc6, 0x7d, 0xbd, 0x6a, 0x6f, 0x37, 0x5a, 0x6a, 0xb6, + 0x58, 0xa3, 0x42, 0x0c, 0x06, 0x89, 0x66, 0xe6, 0x93, 0x79, 0xc8, 0xd5, 0x1b, 0x75, 0x23, 0xfe, + 0x82, 0xba, 0x04, 0x79, 0xbd, 0xd9, 0x34, 0x1b, 0xfb, 0xb8, 0xc4, 0x00, 0xe6, 0x77, 0x8c, 0x3a, + 0x6d, 0x59, 0x96, 0x96, 0x34, 0xcd, 0x46, 0xad, 0xd1, 0x32, 0x76, 0xd4, 0x5c, 0xd1, 0x14, 0xfc, + 0x45, 0x10, 0xed, 0x0c, 0xd8, 0x73, 0xe5, 0x8e, 0xb1, 0xab, 0xb7, 0xab, 0x2d, 0x3e, 0x45, 0x0f, + 0x6c, 0xd3, 0xf8, 0x7c, 0xdb, 0xb0, 0x5a, 0x96, 0xaa, 0x10, 0x15, 0x96, 0xea, 0x86, 0xb1, 0x63, + 0xd9, 0xa6, 0xb1, 0x5f, 0x31, 0xee, 0xab, 0x19, 0x4a, 0x93, 0xfd, 0x4f, 0xbf, 0x50, 0x7c, 0x57, + 0x01, 0xc2, 0x02, 0x6c, 0x8b, 0xac, 0x4d, 0xb8, 0x62, 0x2e, 0xc3, 0x56, 0x99, 0x4e, 0x35, 0x76, + 0xad, 0xd6, 0xd8, 0x89, 0x0f, 0xd9, 0x79, 0x20, 0xb1, 0xf2, 0xc6, 0xee, 0xae, 0xaa, 0x90, 0x0b, + 0x70, 0x36, 0x06, 0xdf, 0x31, 0x1b, 0x4d, 0x35, 0xb3, 0x95, 0xc9, 0x2b, 0x64, 0x23, 0x51, 0x78, + 0xcf, 0x30, 0x9a, 0x6a, 0x96, 0x4e, 0x51, 0xac, 0x40, 0x6c, 0x09, 0x56, 0x3d, 0x57, 0xfc, 0x8e, + 0x02, 0xe7, 0x59, 0x33, 0xc5, 0xfe, 0x0a, 0x9a, 0x7a, 0x11, 0x36, 0x79, 0xda, 0x80, 0xb4, 0x86, + 0xae, 0x83, 0x1a, 0x29, 0x65, 0xcd, 0x3c, 0x07, 0x6b, 0x11, 0x28, 0xb6, 0x23, 0x43, 0xb9, 0x47, + 0x04, 0xbc, 0x6d, 0x58, 0x2d, 0xdb, 0xd8, 0xdd, 0x6d, 0x98, 0x2d, 0xd6, 0x90, 0x6c, 0x51, 0x83, + 0xb5, 0x92, 0x3b, 0x1a, 0xd3, 0xfb, 0x65, 0xdf, 0xf7, 0x06, 0x7d, 0x6c, 0xc2, 0x32, 0x2c, 0x1a, + 0x5f, 0x68, 0x19, 0x75, 0xab, 0xd2, 0xa8, 0xab, 0x67, 0x8a, 0x17, 0x63, 0x38, 0x62, 0x1f, 0x5b, + 0x56, 0x59, 0x3d, 0x53, 0x74, 0x60, 0x59, 0x58, 0x97, 0xb3, 0x55, 0x71, 0x19, 0xb6, 0xc4, 0x5a, + 0x43, 0x8e, 0x12, 0xef, 0xc2, 0x26, 0xac, 0x27, 0xcb, 0x8d, 0x96, 0xaa, 0xd0, 0x59, 0x88, 0x95, + 0x50, 0x78, 0xa6, 0xf8, 0x7f, 0x15, 0x58, 0x0e, 0x5e, 0x86, 0x50, 0x17, 0x7d, 0x05, 0x2e, 0xd4, + 0x76, 0x75, 0x7b, 0xc7, 0xd8, 0xaf, 0x94, 0x0c, 0xfb, 0x5e, 0xa5, 0xbe, 0x13, 0xfb, 0xc8, 0x33, + 0x70, 0x2e, 0x05, 0x01, 0xbf, 0xb2, 0x09, 0xeb, 0xf1, 0xa2, 0x16, 0xdd, 0xaa, 0x19, 0x3a, 0xf4, + 0xf1, 0x92, 0x60, 0x9f, 0x66, 0x8b, 0xfb, 0xb0, 0x62, 0xe9, 0xb5, 0xea, 0xee, 0x60, 0xd4, 0x71, + 0xf5, 0xc9, 0xf8, 0xa8, 0x4f, 0x2e, 0xc0, 0xc6, 0x6e, 0xc3, 0x2c, 0x19, 0x36, 0xa2, 0xc4, 0x5a, + 0x70, 0x16, 0x56, 0xe5, 0xc2, 0x07, 0x06, 0x5d, 0xbe, 0x04, 0x56, 0x64, 0x60, 0xbd, 0xa1, 0x66, + 0x8a, 0x5f, 0x82, 0xa5, 0x48, 0xf2, 0xc6, 0x0d, 0x38, 0x2b, 0xff, 0x6e, 0xba, 0xfd, 0xae, 0xd7, + 0x3f, 0x54, 0xcf, 0xc4, 0x0b, 0xcc, 0x49, 0xbf, 0x4f, 0x0b, 0x70, 0x3f, 0xcb, 0x05, 0x2d, 0x77, + 0x74, 0xec, 0xf5, 0x9d, 0xb1, 0xdb, 0x55, 0x33, 0xc5, 0x17, 0x61, 0x39, 0x12, 0x32, 0x9e, 0x4e, + 0x5c, 0xb5, 0xc1, 0x19, 0x70, 0xcd, 0xd8, 0xa9, 0xb4, 0x6b, 0xea, 0x1c, 0xdd, 0xc9, 0xe5, 0xca, + 0x5e, 0x59, 0x85, 0xe2, 0xf7, 0x15, 0x7a, 0x99, 0xc2, 0x44, 0x50, 0xb5, 0x5d, 0x5d, 0x4c, 0x35, + 0x5d, 0x66, 0x2c, 0x11, 0x85, 0x61, 0x59, 0xcc, 0x70, 0xe0, 0x22, 0x6c, 0xf2, 0x1f, 0xb6, 0x5e, + 0xdf, 0xb1, 0xcb, 0xba, 0xb9, 0x73, 0x5f, 0x37, 0xe9, 0xda, 0x7b, 0xa0, 0x66, 0x70, 0x43, 0x49, + 0x10, 0xbb, 0xd5, 0x68, 0x97, 0xca, 0x6a, 0x96, 0xae, 0xdf, 0x08, 0xbc, 0x59, 0xa9, 0xab, 0x39, + 0xdc, 0x9e, 0x09, 0x6c, 0x24, 0x4b, 0xcb, 0xe7, 0x8a, 0xef, 0x2b, 0xb0, 0x61, 0x79, 0x87, 0x7d, + 0x67, 0x3c, 0x19, 0xb9, 0x7a, 0xef, 0x70, 0x30, 0xf2, 0xc6, 0x47, 0xc7, 0xd6, 0xc4, 0x1b, 0xbb, + 0xe4, 0x16, 0x5c, 0xb7, 0x2a, 0x7b, 0x75, 0xbd, 0x45, 0xb7, 0x97, 0x5e, 0xdd, 0x6b, 0x98, 0x95, + 0x56, 0xb9, 0x66, 0x5b, 0xed, 0x4a, 0x62, 0xe5, 0x5d, 0x83, 0x67, 0xa7, 0xa3, 0x56, 0x8d, 0x3d, + 0xbd, 0xf4, 0x40, 0x55, 0x66, 0x13, 0xdc, 0xd6, 0xab, 0x7a, 0xbd, 0x64, 0xec, 0xd8, 0xfb, 0xb7, + 0xd5, 0x0c, 0xb9, 0x0e, 0x57, 0xa7, 0xa3, 0xee, 0x56, 0x9a, 0x16, 0x45, 0xcb, 0xce, 0xfe, 0x6e, + 0xd9, 0xaa, 0x51, 0xac, 0x5c, 0xf1, 0x07, 0x0a, 0x6c, 0x4e, 0x0b, 0x01, 0x46, 0x6e, 0x80, 0x66, + 0xd4, 0x5b, 0xa6, 0x5e, 0xd9, 0xb1, 0x4b, 0xa6, 0xb1, 0x63, 0xd4, 0x5b, 0x15, 0xbd, 0x6a, 0xd9, + 0x56, 0xa3, 0x4d, 0x57, 0x53, 0x68, 0xdf, 0xf1, 0x1c, 0x5c, 0x99, 0x81, 0xd7, 0xa8, 0xec, 0x94, + 0x54, 0x85, 0xdc, 0x86, 0x17, 0x66, 0x20, 0x59, 0x0f, 0xac, 0x96, 0x51, 0x93, 0x4b, 0xd4, 0x4c, + 0xb1, 0x04, 0x5b, 0xd3, 0x63, 0x04, 0x51, 0x36, 0x1d, 0x1d, 0xe9, 0x3c, 0xe4, 0x76, 0xe8, 0xc9, + 0x10, 0xc9, 0x57, 0x52, 0xf4, 0x40, 0x8d, 0xc7, 0xcf, 0x48, 0x18, 0xe2, 0x98, 0xed, 0x7a, 0x9d, + 0x1d, 0x23, 0xab, 0x50, 0x68, 0xb4, 0xca, 0x86, 0xc9, 0x33, 0xbe, 0x60, 0x8a, 0x97, 0x76, 0x9d, + 0x6e, 0x9c, 0x86, 0x59, 0xf9, 0x22, 0x9e, 0x27, 0x9b, 0xb0, 0x6e, 0x55, 0xf5, 0xd2, 0x3d, 0xbb, + 0xde, 0x68, 0xd9, 0x95, 0xba, 0x5d, 0x2a, 0xeb, 0xf5, 0xba, 0x51, 0x55, 0x01, 0x07, 0x73, 0x9a, + 0x03, 0x29, 0xf9, 0x38, 0xdc, 0x6c, 0xdc, 0x6b, 0xe9, 0x76, 0xb3, 0xda, 0xde, 0xab, 0xd4, 0x6d, + 0xeb, 0x41, 0xbd, 0x24, 0x64, 0x9f, 0x52, 0x92, 0xe5, 0xde, 0x84, 0x6b, 0x33, 0xb1, 0xc3, 0xdc, + 0x2c, 0x37, 0x40, 0x9b, 0x89, 0xc9, 0x3b, 0x52, 0xfc, 0x99, 0x02, 0x17, 0x66, 0x3c, 0x94, 0x93, + 0x17, 0xe0, 0x56, 0xd9, 0xd0, 0x77, 0xaa, 0x86, 0x65, 0x21, 0xa3, 0xa0, 0xd3, 0xc0, 0x0c, 0x76, + 0x52, 0x19, 0xea, 0x2d, 0xb8, 0x3e, 0x1b, 0x3d, 0x3c, 0x9a, 0x6f, 0xc2, 0xb5, 0xd9, 0xa8, 0xfc, + 0xa8, 0xce, 0x90, 0x22, 0xdc, 0x98, 0x8d, 0x19, 0x1c, 0xf1, 0xd9, 0xe2, 0x6f, 0x2b, 0x70, 0x3e, + 0x5d, 0x5b, 0x45, 0xdb, 0x56, 0xa9, 0x5b, 0x2d, 0xbd, 0x5a, 0xb5, 0x9b, 0xba, 0xa9, 0xd7, 0x6c, + 0xa3, 0x6e, 0x36, 0xaa, 0xd5, 0xb4, 0xa3, 0xed, 0x1a, 0x3c, 0x3b, 0x1d, 0xd5, 0x2a, 0x99, 0x95, + 0x26, 0xe5, 0xde, 0x1a, 0x5c, 0x9e, 0x8e, 0x65, 0x54, 0x4a, 0x86, 0x9a, 0xd9, 0x7e, 0xe3, 0x27, + 0x7f, 0x77, 0xf9, 0xcc, 0x4f, 0xde, 0xbf, 0xac, 0xfc, 0xfc, 0xfd, 0xcb, 0xca, 0xdf, 0xbe, 0x7f, + 0x59, 0xf9, 0xe2, 0xf3, 0xa7, 0x4b, 0x6b, 0x86, 0x97, 0x92, 0x47, 0xf3, 0x78, 0x0d, 0x7b, 0xf9, + 0x3f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xf0, 0xe6, 0xfe, 0x0d, 0xe2, 0xc1, 0x01, 0x00, } func (this *PluginSpecV1) Equal(that interface{}) bool { @@ -24302,6 +24432,30 @@ func (this *PluginSpecV1_Msteams) Equal(that interface{}) bool { } return true } +func (this *PluginSpecV1_NetIq) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PluginSpecV1_NetIq) + if !ok { + that2, ok := that.(PluginSpecV1_NetIq) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.NetIq.Equal(that1.NetIq) { + return false + } + return true +} func (this *PluginSlackAccessSettings) Equal(that interface{}) bool { if that == nil { return this == nil @@ -25249,6 +25403,39 @@ func (this *PluginMSTeamsSettings) Equal(that interface{}) bool { } return true } +func (this *PluginNetIQSettings) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PluginNetIQSettings) + if !ok { + that2, ok := that.(PluginNetIQSettings) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.OauthIssuerEndpoint != that1.OauthIssuerEndpoint { + return false + } + if this.ApiEndpoint != that1.ApiEndpoint { + return false + } + if this.InsecureSkipVerify != that1.InsecureSkipVerify { + return false + } + if !bytes.Equal(this.XXX_unrecognized, that1.XXX_unrecognized) { + return false + } + return true +} func (this *PluginStaticCredentialsRef) Equal(that interface{}) bool { if that == nil { return this == nil @@ -45098,6 +45285,29 @@ func (m *PluginSpecV1_Msteams) MarshalToSizedBuffer(dAtA []byte) (int, error) { } return len(dAtA) - i, nil } +func (m *PluginSpecV1_NetIq) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginSpecV1_NetIq) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.NetIq != nil { + { + size, err := m.NetIq.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x9a + } + return len(dAtA) - i, nil +} func (m *PluginSlackAccessSettings) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -46522,6 +46732,57 @@ func (m *PluginMSTeamsSettings) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PluginNetIQSettings) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginNetIQSettings) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginNetIQSettings) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.InsecureSkipVerify { + i-- + if m.InsecureSkipVerify { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.ApiEndpoint) > 0 { + i -= len(m.ApiEndpoint) + copy(dAtA[i:], m.ApiEndpoint) + i = encodeVarintTypes(dAtA, i, uint64(len(m.ApiEndpoint))) + i-- + dAtA[i] = 0x12 + } + if len(m.OauthIssuerEndpoint) > 0 { + i -= len(m.OauthIssuerEndpoint) + copy(dAtA[i:], m.OauthIssuerEndpoint) + i = encodeVarintTypes(dAtA, i, uint64(len(m.OauthIssuerEndpoint))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *PluginBootstrapCredentialsV1) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -46743,12 +47004,12 @@ func (m *PluginStatusV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x32 } - n363, err363 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastSyncTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastSyncTime):]) - if err363 != nil { - return 0, err363 + n364, err364 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastSyncTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastSyncTime):]) + if err364 != nil { + return 0, err364 } - i -= n363 - i = encodeVarintTypes(dAtA, i, uint64(n363)) + i -= n364 + i = encodeVarintTypes(dAtA, i, uint64(n364)) i-- dAtA[i] = 0x1a if len(m.ErrorMessage) > 0 { @@ -46850,6 +47111,74 @@ func (m *PluginStatusV1_AwsIc) MarshalToSizedBuffer(dAtA []byte) (int, error) { } return len(dAtA) - i, nil } +func (m *PluginStatusV1_NetIq) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginStatusV1_NetIq) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.NetIq != nil { + { + size, err := m.NetIq.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + return len(dAtA) - i, nil +} +func (m *PluginNetIQStatusV1) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginNetIQStatusV1) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginNetIQStatusV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.ImportedResources != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ImportedResources)) + i-- + dAtA[i] = 0x20 + } + if m.ImportedRoles != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ImportedRoles)) + i-- + dAtA[i] = 0x18 + } + if m.ImportedGroups != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ImportedGroups)) + i-- + dAtA[i] = 0x10 + } + if m.ImportedUsers != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ImportedUsers)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *PluginGitlabStatusV1) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -47109,22 +47438,22 @@ func (m *PluginOktaStatusDetailsAppGroupSync) MarshalToSizedBuffer(dAtA []byte) dAtA[i] = 0x28 } if m.LastFailed != nil { - n373, err373 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) - if err373 != nil { - return 0, err373 + n375, err375 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) + if err375 != nil { + return 0, err375 } - i -= n373 - i = encodeVarintTypes(dAtA, i, uint64(n373)) + i -= n375 + i = encodeVarintTypes(dAtA, i, uint64(n375)) i-- dAtA[i] = 0x22 } if m.LastSuccessful != nil { - n374, err374 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) - if err374 != nil { - return 0, err374 + n376, err376 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) + if err376 != nil { + return 0, err376 } - i -= n374 - i = encodeVarintTypes(dAtA, i, uint64(n374)) + i -= n376 + i = encodeVarintTypes(dAtA, i, uint64(n376)) i-- dAtA[i] = 0x1a } @@ -47183,22 +47512,22 @@ func (m *PluginOktaStatusDetailsUsersSync) MarshalToSizedBuffer(dAtA []byte) (in dAtA[i] = 0x28 } if m.LastFailed != nil { - n375, err375 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) - if err375 != nil { - return 0, err375 + n377, err377 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) + if err377 != nil { + return 0, err377 } - i -= n375 - i = encodeVarintTypes(dAtA, i, uint64(n375)) + i -= n377 + i = encodeVarintTypes(dAtA, i, uint64(n377)) i-- dAtA[i] = 0x22 } if m.LastSuccessful != nil { - n376, err376 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) - if err376 != nil { - return 0, err376 + n378, err378 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) + if err378 != nil { + return 0, err378 } - i -= n376 - i = encodeVarintTypes(dAtA, i, uint64(n376)) + i -= n378 + i = encodeVarintTypes(dAtA, i, uint64(n378)) i-- dAtA[i] = 0x1a } @@ -47317,22 +47646,22 @@ func (m *PluginOktaStatusDetailsAccessListsSync) MarshalToSizedBuffer(dAtA []byt } } if m.LastFailed != nil { - n377, err377 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) - if err377 != nil { - return 0, err377 + n379, err379 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastFailed, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastFailed):]) + if err379 != nil { + return 0, err379 } - i -= n377 - i = encodeVarintTypes(dAtA, i, uint64(n377)) + i -= n379 + i = encodeVarintTypes(dAtA, i, uint64(n379)) i-- dAtA[i] = 0x22 } if m.LastSuccessful != nil { - n378, err378 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) - if err378 != nil { - return 0, err378 + n380, err380 := github_com_gogo_protobuf_types.StdTimeMarshalTo(*m.LastSuccessful, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(*m.LastSuccessful):]) + if err380 != nil { + return 0, err380 } - i -= n378 - i = encodeVarintTypes(dAtA, i, uint64(n378)) + i -= n380 + i = encodeVarintTypes(dAtA, i, uint64(n380)) i-- dAtA[i] = 0x1a } @@ -47498,12 +47827,12 @@ func (m *PluginOAuth2AccessTokenCredentials) MarshalToSizedBuffer(dAtA []byte) ( i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - n383, err383 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) - if err383 != nil { - return 0, err383 + n385, err385 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Expires, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Expires):]) + if err385 != nil { + return 0, err385 } - i -= n383 - i = encodeVarintTypes(dAtA, i, uint64(n383)) + i -= n385 + i = encodeVarintTypes(dAtA, i, uint64(n385)) i-- dAtA[i] = 0x1a if len(m.RefreshToken) > 0 { @@ -48445,20 +48774,20 @@ func (m *ScheduledAgentUpgradeWindow) MarshalToSizedBuffer(dAtA []byte) (int, er i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } - n398, err398 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Stop, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Stop):]) - if err398 != nil { - return 0, err398 + n400, err400 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Stop, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Stop):]) + if err400 != nil { + return 0, err400 } - i -= n398 - i = encodeVarintTypes(dAtA, i, uint64(n398)) + i -= n400 + i = encodeVarintTypes(dAtA, i, uint64(n400)) i-- dAtA[i] = 0x12 - n399, err399 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Start, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Start):]) - if err399 != nil { - return 0, err399 + n401, err401 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Start, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Start):]) + if err401 != nil { + return 0, err401 } - i -= n399 - i = encodeVarintTypes(dAtA, i, uint64(n399)) + i -= n401 + i = encodeVarintTypes(dAtA, i, uint64(n401)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -48885,12 +49214,12 @@ func (m *OktaAssignmentSpecV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x30 } - n406, err406 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastTransition, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastTransition):]) - if err406 != nil { - return 0, err406 + n408, err408 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.LastTransition, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.LastTransition):]) + if err408 != nil { + return 0, err408 } - i -= n406 - i = encodeVarintTypes(dAtA, i, uint64(n406)) + i -= n408 + i = encodeVarintTypes(dAtA, i, uint64(n408)) i-- dAtA[i] = 0x2a if m.Status != 0 { @@ -48898,12 +49227,12 @@ func (m *OktaAssignmentSpecV1) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x20 } - n407, err407 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CleanupTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CleanupTime):]) - if err407 != nil { - return 0, err407 + n409, err409 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CleanupTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CleanupTime):]) + if err409 != nil { + return 0, err409 } - i -= n407 - i = encodeVarintTypes(dAtA, i, uint64(n407)) + i -= n409 + i = encodeVarintTypes(dAtA, i, uint64(n409)) i-- dAtA[i] = 0x1a if len(m.Targets) > 0 { @@ -50427,12 +50756,12 @@ func (m *AccessGraphSync) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - n432, err432 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.PollInterval, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.PollInterval):]) - if err432 != nil { - return 0, err432 + n434, err434 := github_com_gogo_protobuf_types.StdDurationMarshalTo(m.PollInterval, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdDuration(m.PollInterval):]) + if err434 != nil { + return 0, err434 } - i -= n432 - i = encodeVarintTypes(dAtA, i, uint64(n432)) + i -= n434 + i = encodeVarintTypes(dAtA, i, uint64(n434)) i-- dAtA[i] = 0x12 if len(m.AWS) > 0 { @@ -59450,6 +59779,18 @@ func (m *PluginSpecV1_Msteams) Size() (n int) { } return n } +func (m *PluginSpecV1_NetIq) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NetIq != nil { + l = m.NetIq.Size() + n += 2 + l + sovTypes(uint64(l)) + } + return n +} func (m *PluginSlackAccessSettings) Size() (n int) { if m == nil { return 0 @@ -60130,6 +60471,29 @@ func (m *PluginMSTeamsSettings) Size() (n int) { return n } +func (m *PluginNetIQSettings) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OauthIssuerEndpoint) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.ApiEndpoint) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.InsecureSkipVerify { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *PluginBootstrapCredentialsV1) Size() (n int) { if m == nil { return 0 @@ -60297,6 +60661,42 @@ func (m *PluginStatusV1_AwsIc) Size() (n int) { } return n } +func (m *PluginStatusV1_NetIq) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.NetIq != nil { + l = m.NetIq.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} +func (m *PluginNetIQStatusV1) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ImportedUsers != 0 { + n += 1 + sovTypes(uint64(m.ImportedUsers)) + } + if m.ImportedGroups != 0 { + n += 1 + sovTypes(uint64(m.ImportedGroups)) + } + if m.ImportedRoles != 0 { + n += 1 + sovTypes(uint64(m.ImportedRoles)) + } + if m.ImportedResources != 0 { + n += 1 + sovTypes(uint64(m.ImportedResources)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *PluginGitlabStatusV1) Size() (n int) { if m == nil { return 0 @@ -120051,6 +120451,41 @@ func (m *PluginSpecV1) Unmarshal(dAtA []byte) error { } m.Settings = &PluginSpecV1_Msteams{v} iNdEx = postIndex + case 19: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NetIq", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &PluginNetIQSettings{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Settings = &PluginSpecV1_NetIq{v} + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -123977,6 +124412,141 @@ func (m *PluginMSTeamsSettings) Unmarshal(dAtA []byte) error { } return nil } +func (m *PluginNetIQSettings) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginNetIQSettings: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginNetIQSettings: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OauthIssuerEndpoint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OauthIssuerEndpoint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ApiEndpoint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ApiEndpoint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InsecureSkipVerify", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.InsecureSkipVerify = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PluginBootstrapCredentialsV1) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -124648,6 +125218,168 @@ func (m *PluginStatusV1) Unmarshal(dAtA []byte) error { } m.Details = &PluginStatusV1_AwsIc{v} iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NetIq", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &PluginNetIQStatusV1{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Details = &PluginStatusV1_NetIq{v} + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginNetIQStatusV1) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginNetIQStatusV1: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginNetIQStatusV1: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ImportedUsers", wireType) + } + m.ImportedUsers = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ImportedUsers |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ImportedGroups", wireType) + } + m.ImportedGroups = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ImportedGroups |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ImportedRoles", wireType) + } + m.ImportedRoles = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ImportedRoles |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ImportedResources", wireType) + } + m.ImportedResources = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ImportedResources |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/assets/aws/Makefile b/assets/aws/Makefile index a13720c8310e3..3ba53240deaa4 100644 --- a/assets/aws/Makefile +++ b/assets/aws/Makefile @@ -2,7 +2,7 @@ # This must be a _released_ version of Teleport, i.e. one which has binaries # available for download on https://goteleport.com/download # Unreleased versions will fail to build. -TELEPORT_VERSION ?= 17.1.0 +TELEPORT_VERSION ?= 17.1.1 # Teleport UID is the UID of a non-privileged 'teleport' user TELEPORT_UID ?= 1007 diff --git a/buf-legacy.yaml b/buf-legacy.yaml index 5dcbbf314a2a4..f50c9f7b20e5b 100644 --- a/buf-legacy.yaml +++ b/buf-legacy.yaml @@ -35,7 +35,3 @@ lint: - RPC_REQUEST_RESPONSE_UNIQUE - RPC_REQUEST_STANDARD_NAME - RPC_RESPONSE_STANDARD_NAME - -breaking: - use: - - "buf-legacy.yaml should not be used for buf breaking" diff --git a/build.assets/versions.mk b/build.assets/versions.mk index 15a01e3006f58..94e9e3a12831e 100644 --- a/build.assets/versions.mk +++ b/build.assets/versions.mk @@ -17,7 +17,7 @@ LIBPCSCLITE_VERSION ?= 1.9.9-teleport DEVTOOLSET ?= devtoolset-12 # Protogen related versions. -BUF_VERSION ?= v1.42.0 +BUF_VERSION ?= v1.48.0 # Keep in sync with api/proto/buf.yaml (and buf.lock). GOGO_PROTO_TAG ?= v1.3.2 NODE_GRPC_TOOLS_VERSION ?= 1.12.4 diff --git a/constants.go b/constants.go index 1c7ecf3226a96..63ba08b791c46 100644 --- a/constants.go +++ b/constants.go @@ -21,6 +21,8 @@ package teleport import ( "strings" "time" + + "github.com/gravitational/trace" ) // WebAPIVersion is a current webapi version @@ -823,9 +825,15 @@ const ( UsageWindowsDesktopOnly = "usage:windows_desktop" ) +// ErrNodeIsAmbiguous serves as an identifying error string indicating that +// the proxy subsystem found multiple nodes matching the specified hostname. +var ErrNodeIsAmbiguous = &trace.NotFoundError{Message: "ambiguous host could match multiple nodes"} + const ( // NodeIsAmbiguous serves as an identifying error string indicating that // the proxy subsystem found multiple nodes matching the specified hostname. + // TODO(tross) DELETE IN v20.0.0 + // Deprecated: Prefer using ErrNodeIsAmbiguous NodeIsAmbiguous = "err-node-is-ambiguous" // MaxLeases serves as an identifying error string indicating that the diff --git a/docs/cspell.json b/docs/cspell.json index 08c89c4305a08..c369da521ab43 100644 --- a/docs/cspell.json +++ b/docs/cspell.json @@ -2,6 +2,14 @@ "language": "en", "version": "0.2", "words": [ + "aada", + "abee", + "fffc", + "fabfc", + "microservices", + "configmaps", + "genrsa", + "displayname", "AADUSER", "ABCDEFGHIJKL", "ADFS", diff --git a/docs/img/connect-your-client/webui-db-sessions/connect-dialog-custom.png b/docs/img/connect-your-client/webui-db-sessions/connect-dialog-custom.png new file mode 100644 index 0000000000000..1ed7f0e494230 Binary files /dev/null and b/docs/img/connect-your-client/webui-db-sessions/connect-dialog-custom.png differ diff --git a/docs/img/connect-your-client/webui-db-sessions/connect-dialog.png b/docs/img/connect-your-client/webui-db-sessions/connect-dialog.png new file mode 100644 index 0000000000000..f1614f0a2826e Binary files /dev/null and b/docs/img/connect-your-client/webui-db-sessions/connect-dialog.png differ diff --git a/docs/img/connect-your-client/webui-db-sessions/resources-connect-dialog.png b/docs/img/connect-your-client/webui-db-sessions/resources-connect-dialog.png new file mode 100644 index 0000000000000..51137d8769469 Binary files /dev/null and b/docs/img/connect-your-client/webui-db-sessions/resources-connect-dialog.png differ diff --git a/docs/img/connect-your-client/webui-db-sessions/resources-list.png b/docs/img/connect-your-client/webui-db-sessions/resources-list.png new file mode 100644 index 0000000000000..447fe1a42a13a Binary files /dev/null and b/docs/img/connect-your-client/webui-db-sessions/resources-list.png differ diff --git a/docs/img/connect-your-client/webui-db-sessions/session-terminal.png b/docs/img/connect-your-client/webui-db-sessions/session-terminal.png new file mode 100644 index 0000000000000..c062ec00e2ace Binary files /dev/null and b/docs/img/connect-your-client/webui-db-sessions/session-terminal.png differ diff --git a/docs/pages/connect-your-client/web-ui.mdx b/docs/pages/connect-your-client/web-ui.mdx index be05318f09d57..9bce88e3eac52 100644 --- a/docs/pages/connect-your-client/web-ui.mdx +++ b/docs/pages/connect-your-client/web-ui.mdx @@ -65,3 +65,57 @@ After you save and exit the editor, `tctl` will update the resource: cluster networking configuration has been updated ``` +## Starting a database session + +Starting from version `17.1`, users can establish database sessions using the +Teleport Web UI. Currently, it is supported in PostgreSQL databases. + +To start a new session, locate your database in the resources list and click +"Connect". + +![Resources list](../../img/connect-your-client/webui-db-sessions/resources-list.png) + +For supported databases, the dialog will present the option to start +the session in your browser. + +![Resources list database connect dialog](../../img/connect-your-client/webui-db-sessions/resources-connect-dialog.png) + +After clicking on the "Connect in the browser" button, a new tab will open with +a form. Teleport will pre-fill this form based on your permissions, but you can +adjust the options as needed. + +![New database session connect dialog](../../img/connect-your-client/webui-db-sessions/connect-dialog.png) + +If your user has wildcard permissions (*), you can type custom values into the +form fields. This allows flexibility in selecting specific databases or +credentials. + +![New database session connect dialog with custom values](../../img/connect-your-client/webui-db-sessions/connect-dialog-custom.png) + +Once you've filled in the session details, click the "Connect" button. Your +session will start, and a terminal interface will appear in the browser. + +The browser-based terminal allows you to execute queries and interact with your +database. Follow the on-screen instructions to see available commands and +limitations. + +![Database session terminal](../../img/connect-your-client/webui-db-sessions/session-terminal.png) + + + While the terminal interface provided in the Teleport Web UI is designed to + resemble popular database CLIs such as `psql`, it is a custom implementation + with some differences and limitations: + - **Feature Set:** Not all features available in `psql` are implemented. + For instance, scripting capabilities, query cancellation, or informational + commands like `\d` or `\dt` are currently unsupported. + - **Error Handling:** Error messages and diagnostics might differ from what + users are accustomed to in `psql`. + + These distinctions are designed to maintain a lightweight and secure interface + directly in your browser. For more complex operations, you may prefer + accessing your database from your terminal using `tsh` and your preferred + tool. + + Future updates may expand functionality or address feedback based on user + needs and supported databases. + diff --git a/docs/pages/enroll-resources/application-access/getting-started.mdx b/docs/pages/enroll-resources/application-access/getting-started.mdx index 28a23fad24da2..3fe1756f69c93 100644 --- a/docs/pages/enroll-resources/application-access/getting-started.mdx +++ b/docs/pages/enroll-resources/application-access/getting-started.mdx @@ -1,6 +1,6 @@ --- -title: Getting Started with Teleport Application Access -description: Getting started with Teleport application access. +title: Protect a Web Application with Teleport +description: Provides instructions to set up the Teleport Application Service and enable secure access to a web application. videoBanner: cvW4b96aPL0 --- @@ -20,6 +20,21 @@ At a high level, configuring access for applications involves the following step - Install and configure Teleport on the application host. - Add a user to verify access to the application. +## How it works + +In the setup we demonstrate in this guide, the Teleport Application Service +joins your Teleport cluster with a secure token. You configure the Application +Service to protect a web application using a configuration file. After the +Application Service joins the cluster, the Teleport Proxy Service routes +requests from end users to the Teleport Application Service, and responses from +the Application Serve back to end users. + +The Application Service authenticates user requests by validating a JSON web +token (JWT) in the request against a CA maintained by the Teleport Auth Service. +The requesting user's roles are encoded in the JWT, allowing the Application +Service to determine whether the user has permissions to make a request to a +Teleport-protected application. + ## Prerequisites For this tutorial, verify your environment meets the following requirements: @@ -179,7 +194,7 @@ $ helm install teleport-kube-agent teleport/teleport-kube-agent \ - Change `apps[0].name` and `apps[0].uri` if you're configuring access to a different web application. -Make sure that the Teleport agent pod is running. You should see one +Make sure that the Teleport Agent pod is running. You should see one `teleport-kube-agent` pod with a single ready container: ```code @@ -203,8 +218,9 @@ To assign to the `access` role to a new local user named `alice`, run the follow $ tctl users add --roles=access alice ``` -The command generates an invitation URL for the new user. You can use the URL to choose -a password, set up a second factor for authentication, and sign in to the Teleport Web UI. +The command generates an invitation URL for the new user. You can use the URL to +choose a password, set up multi-factor authentication, and sign in to the +Teleport Web UI. ## Step 5/5. Access the application @@ -225,5 +241,5 @@ Learn more about protecting applications with Teleport in the following topics: - [Connecting applications](./guides/connecting-apps.mdx). - Integrating with [JWT tokens](./jwt/introduction.mdx). - Accessing applications with [RESTful APIs](./guides/api-access.mdx). -- Setting configuration options AND running CLI commands in the [Application Access reference](../../reference/agent-services/application-access.mdx). +- Setting configuration options AND running CLI commands in the [Application Service reference](../../reference/agent-services/application-access.mdx). - Using the Let's Encrypt [ACME protocol](https://letsencrypt.org/how-it-works/). diff --git a/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx b/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx index 26ed6d6c3fbc9..816ae2484d96c 100644 --- a/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx +++ b/docs/pages/enroll-resources/application-access/guides/connecting-apps.mdx @@ -132,10 +132,9 @@ Teleport, you must configure these yourself: Service domain, e.g., `*.teleport.example.com`, with the domain name of the Teleport Proxy Service. -1. Ensure that your system provisionings TLS certificates for - Teleport-registered applications. The method to use depends on how you - originally set up TLS for your self-hosted Teleport deployment, and is - outside the scope of this guide. +1. Ensure that your system provisions TLS certificates for Teleport-registered + applications. The method to use depends on how you originally set up TLS for + your self-hosted Teleport deployment, and is outside the scope of this guide. In general, the same system that provisions TLS certificates signed for the web address of the Proxy Service (e.g., `teleport.example.com`) must also diff --git a/docs/pages/enroll-resources/application-access/guides/dynamodb.mdx b/docs/pages/enroll-resources/application-access/guides/dynamodb.mdx index 58d846981d619..681752478ecb5 100644 --- a/docs/pages/enroll-resources/application-access/guides/dynamodb.mdx +++ b/docs/pages/enroll-resources/application-access/guides/dynamodb.mdx @@ -22,15 +22,15 @@ This guide will help you to: - +## How it works The Teleport Application Service enables secure access to DynamoDB via its [integration](../cloud-apis/aws-console.mdx) with the AWS management console and API. This is an alternative to accessing DynamoDB through the Teleport Database -service, as described in our [Database Access with AWS -DynamoDB](../../database-access/enroll-aws-databases/aws-dynamodb.mdx) guide. +service, as described in our [Protect Amazon DynamoDB with +Teleport](../../database-access/enroll-aws-databases/aws-dynamodb.mdx) guide. + The Application Service's integration with AWS is not designed specifically for DynamoDB, while the Database Service has a purpose-built DynamoDB integration. As a result, we recommend using the Database Service to enable secure access to @@ -40,7 +40,6 @@ It is worth noting that the Database Service will allow you to connect with GUI clients, whereas the Application Service does not. On the other hand, a single Application Service configuration can access DynamoDB across regions, while database resources must be configured for each region with DynamoDB databases. - ## Prerequisites @@ -173,6 +172,6 @@ $ tsh apps logout aws ``` ## Next steps -- More information on [AWS Management and API with Teleport Application Access](../../application-access/cloud-apis/aws-console.mdx). +- More information on [protecting AWS Console with Teleport](../../application-access/cloud-apis/aws-console.mdx). - Learn more about [AWS service endpoints](https://docs.aws.amazon.com/general/latest/gr/rande.html). diff --git a/docs/pages/enroll-resources/auto-discovery/kubernetes-applications/get-started.mdx b/docs/pages/enroll-resources/auto-discovery/kubernetes-applications/get-started.mdx index fd9a5d9fa8c19..62f4d807c3f35 100644 --- a/docs/pages/enroll-resources/auto-discovery/kubernetes-applications/get-started.mdx +++ b/docs/pages/enroll-resources/auto-discovery/kubernetes-applications/get-started.mdx @@ -11,6 +11,14 @@ setup step. In this guide, we show you how to enable Kubernetes application auto-discovery. +## How it works + +The Teleport Discovery Service queries the API server of the Kubernetes cluster +in which you want to detect applications, maintaining dynamic `app` resources to +match the Kubernetes services that it detects within the cluster. The Teleport +Application Service queries the Teleport Auth Service to fetch `app` resources, +and proxies applications based the dynamically generated configuration. + ## Prerequisites (!docs/pages/includes/edition-prereqs-tabs.mdx!) @@ -26,7 +34,7 @@ In this guide, we show you how to enable Kubernetes application auto-discovery. ## Step 1/2. Create a join token -Create a join token for a new Teleport agent that will run the Teleport +Create a join token for a new Teleport Agent that will run the Teleport Kubernetes Service, Application Service, and Discovery Service: ```code @@ -40,15 +48,15 @@ Teleport applications created from discovered Kubernetes services. ## Step 2/2. Deploy the agent -If you want to install a new Teleport agent in your Kubernetes cluster, you can -use the `teleport-kube-agent` Helm chart. If you already have a Teleport agent +If you want to install a new Teleport Agent in your Kubernetes cluster, you can +use the `teleport-kube-agent` Helm chart. If you already have a Teleport Agent installed, you can upgrade it to enable the Kubernetes Application Discovery by adding the `kube`, `app`, and `discovery` to roles as shown below. -Deploy a new Teleport agent running your configured services by installing the +Deploy a new Teleport Agent running your configured services by installing the `teleport-kube-agent` Helm chart: ```code diff --git a/docs/pages/enroll-resources/database-access/enroll-aws-databases/postgres-redshift.mdx b/docs/pages/enroll-resources/database-access/enroll-aws-databases/postgres-redshift.mdx index 77e487d14bb3b..87be741c8513d 100644 --- a/docs/pages/enroll-resources/database-access/enroll-aws-databases/postgres-redshift.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-aws-databases/postgres-redshift.mdx @@ -205,6 +205,8 @@ $ tsh db connect --db-user=role/example-iam-role --db-name=dev my-redshift +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + To log out of the database and remove credentials: ```code diff --git a/docs/pages/enroll-resources/database-access/enroll-aws-databases/rds.mdx b/docs/pages/enroll-resources/database-access/enroll-aws-databases/rds.mdx index 4837cb6e7a4e4..a07c4b6e4c73d 100644 --- a/docs/pages/enroll-resources/database-access/enroll-aws-databases/rds.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-aws-databases/rds.mdx @@ -295,6 +295,8 @@ Retrieve credentials for the database and connect to it as the `alice` user: $ tsh db connect --db-user=alice --db-name=postgres rds-example ``` +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + The appropriate database command-line client (`psql`, `mysql`, `mariadb`) should be available in `PATH` in order to be able to connect. diff --git a/docs/pages/enroll-resources/database-access/enroll-aws-databases/redshift-serverless.mdx b/docs/pages/enroll-resources/database-access/enroll-aws-databases/redshift-serverless.mdx index 8de82a3035a91..7b01cb3a2a959 100644 --- a/docs/pages/enroll-resources/database-access/enroll-aws-databases/redshift-serverless.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-aws-databases/redshift-serverless.mdx @@ -235,6 +235,8 @@ Type "help" for help. dev=> ``` +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + To log out of the database and remove credentials: ```code diff --git a/docs/pages/enroll-resources/database-access/enroll-azure-databases/azure-postgres-mysql.mdx b/docs/pages/enroll-resources/database-access/enroll-azure-databases/azure-postgres-mysql.mdx index b639ab2a0673a..e18afa60ca7e9 100644 --- a/docs/pages/enroll-resources/database-access/enroll-azure-databases/azure-postgres-mysql.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-azure-databases/azure-postgres-mysql.mdx @@ -428,6 +428,8 @@ $ tsh db connect --db-user=teleport --db-name=postgres azure-db +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + The appropriate database command-line client (`psql`, `mysql`) should be available in the `PATH` of the machine you're running `tsh db connect` from. diff --git a/docs/pages/enroll-resources/database-access/enroll-google-cloud-databases/postgres-cloudsql.mdx b/docs/pages/enroll-resources/database-access/enroll-google-cloud-databases/postgres-cloudsql.mdx index 15a3d9ece0f22..05f58d2e21788 100644 --- a/docs/pages/enroll-resources/database-access/enroll-google-cloud-databases/postgres-cloudsql.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-google-cloud-databases/postgres-cloudsql.mdx @@ -149,6 +149,8 @@ Retrieve credentials for the "cloudsql" example database and connect to it: $ tsh db connect --db-user=cloudsql-user@.iam --db-name=postgres cloudsql ``` +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + To log out of the database and remove credentials: ```code diff --git a/docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/postgres-self-hosted.mdx b/docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/postgres-self-hosted.mdx index 1cbb3d8a0f427..02acd22cd3fdc 100644 --- a/docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/postgres-self-hosted.mdx +++ b/docs/pages/enroll-resources/database-access/enroll-self-hosted-databases/postgres-self-hosted.mdx @@ -142,6 +142,8 @@ To retrieve credentials for a database and connect to it: $ tsh db connect --db-user=postgres --db-name=postgres example-postgres ``` +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + To log out of the database and remove credentials: ```code diff --git a/docs/pages/enroll-resources/database-access/rbac.mdx b/docs/pages/enroll-resources/database-access/rbac.mdx index 38a63801be474..d383ab0d0b8d9 100644 --- a/docs/pages/enroll-resources/database-access/rbac.mdx +++ b/docs/pages/enroll-resources/database-access/rbac.mdx @@ -264,6 +264,35 @@ spec: version: v1 ``` +### Disabling the default import rule + +Teleport expects at least one import rule to be defined. If it is missing, the Teleport Auth Service will create a default import rule on startup. + +If you don't want to import any database objects, create a rule that matches no databases. In the example below, the list of matching label values is empty, so no database will ever match this selector. + +```yaml +kind: db_object_import_rule +metadata: + name: import_no_objects +spec: + database_labels: + - {} + mappings: + - {} +version: v1 +``` + +Create the custom rule and remove the default one: + +{/* spell-checker: disable */} +```code +$ tctl create -f import_no_objects.yaml +rule "import_no_objects" has been created +$ tctl rm db_object_import_rule/import_all_objects +Rule "import_all_objects" has been deleted +``` +{/* spell-checker: enable */} + ### Database admin user A database admin user is responsible for granting permissions to end users. You diff --git a/docs/pages/includes/database-access/auto-user-provisioning/connect.mdx b/docs/pages/includes/database-access/auto-user-provisioning/connect.mdx index 2d55518cc26ec..891efcc664187 100644 --- a/docs/pages/includes/database-access/auto-user-provisioning/connect.mdx +++ b/docs/pages/includes/database-access/auto-user-provisioning/connect.mdx @@ -2,6 +2,8 @@ Now, log into your Teleport cluster and connect to the database: +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + ```code $ tsh login --proxy=teleport.example.com $ tsh db connect --db-name example diff --git a/docs/pages/includes/database-access/pg-access-webui.mdx b/docs/pages/includes/database-access/pg-access-webui.mdx new file mode 100644 index 0000000000000..5f6f7cddb4b33 --- /dev/null +++ b/docs/pages/includes/database-access/pg-access-webui.mdx @@ -0,0 +1,3 @@ + + Starting from version `17.1`, you can now [access your PostgreSQL databases using the Web UI.](../../connect-your-client/web-ui.mdx#starting-a-database-session) + diff --git a/docs/pages/includes/database-access/rds-proxy.mdx b/docs/pages/includes/database-access/rds-proxy.mdx index 348708e348aa9..dccbc48e02bc9 100644 --- a/docs/pages/includes/database-access/rds-proxy.mdx +++ b/docs/pages/includes/database-access/rds-proxy.mdx @@ -184,6 +184,8 @@ Retrieve credentials for the database and connect to it as the `alice` user: $ tsh db connect --db-user=alice --db-name=dev rds-proxy ``` +(!docs/pages/includes/database-access/pg-access-webui.mdx!) + To log out of the database and remove credentials: ```code diff --git a/docs/pages/reference/resources.mdx b/docs/pages/reference/resources.mdx index 7705f6456d4c9..55bc6c6e5e117 100644 --- a/docs/pages/reference/resources.mdx +++ b/docs/pages/reference/resources.mdx @@ -126,7 +126,7 @@ When no `kubernetes_resource` is set: {/* This table is cursed. Our current docs engine doesn't support HTML tables (due to SSR and the rehydration process). We have dto do everything inlined in markdown. Some HTML character codes are used to render specific chars like {} -or to avoid line breaks in the middle fo the YAML. Whitespaces before br tags +or to avoid line breaks in the middle fo the YAML. Spaces before br tags are required.*/} | Allow rule | Role v5 | Role v6 | Role v7 | diff --git a/docs/pages/reference/signature-algorithms.mdx b/docs/pages/reference/signature-algorithms.mdx index 8b96acfe67be5..c41186f3d7bc3 100644 --- a/docs/pages/reference/signature-algorithms.mdx +++ b/docs/pages/reference/signature-algorithms.mdx @@ -192,8 +192,8 @@ in each suite. Try it and let us know! We aim to balance security, performance, and compatibility with the chosen signature algorithm suites. -It is okay to continue using the `legacy` suite for the forseeable future and we -expect it may be required for some user's environments. +It is okay to continue using the `legacy` suite for the foreseeable future and we +expect it may be required for some users' environments. ### How did you choose these algorithms? diff --git a/docs/pages/reference/terraform-provider/data-sources/data-sources.mdx b/docs/pages/reference/terraform-provider/data-sources/data-sources.mdx index 92e37199d2dd6..0e6dfabb1b4d4 100644 --- a/docs/pages/reference/terraform-provider/data-sources/data-sources.mdx +++ b/docs/pages/reference/terraform-provider/data-sources/data-sources.mdx @@ -34,3 +34,4 @@ The Teleport Terraform provider supports the following data-sources: - [`teleport_trusted_cluster`](./trusted_cluster.mdx) - [`teleport_trusted_device`](./trusted_device.mdx) - [`teleport_user`](./user.mdx) + - [`teleport_workload_identity`](./workload_identity.mdx) diff --git a/docs/pages/reference/terraform-provider/data-sources/workload_identity.mdx b/docs/pages/reference/terraform-provider/data-sources/workload_identity.mdx new file mode 100644 index 0000000000000..2298d5363d77c --- /dev/null +++ b/docs/pages/reference/terraform-provider/data-sources/workload_identity.mdx @@ -0,0 +1,69 @@ +--- +title: Reference for the teleport_workload_identity Terraform data-source +sidebar_label: workload_identity +description: This page describes the supported values of the teleport_workload_identity data-source of the Teleport Terraform provider. +--- + +{/*Auto-generated file. Do not edit.*/} +{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} + + + + + +{/* schema generated by tfplugindocs */} +## Schema + +### Optional + +- `metadata` (Attributes) Common metadata that all resources share. (see [below for nested schema](#nested-schema-for-metadata)) +- `spec` (Attributes) The configured properties of the WorkloadIdentity (see [below for nested schema](#nested-schema-for-spec)) +- `sub_kind` (String) Differentiates variations of the same kind. All resources should contain one, even if it is never populated. +- `version` (String) The version of the resource being represented. + +### Nested Schema for `metadata` + +Optional: + +- `description` (String) description is object description. +- `expires` (String) expires is a global expiry time header can be set on any resource in the system. +- `labels` (Map of String) labels is a set of labels. +- `name` (String) name is an object name. + + +### Nested Schema for `spec` + +Optional: + +- `rules` (Attributes) The rules which are evaluated before the WorkloadIdentity can be issued. (see [below for nested schema](#nested-schema-for-specrules)) +- `spiffe` (Attributes) Configuration pertaining to the issuance of SPIFFE-compatible workload identity credentials. (see [below for nested schema](#nested-schema-for-specspiffe)) + +### Nested Schema for `spec.rules` + +Optional: + +- `allow` (Attributes List) A list of rules used to determine if a WorkloadIdentity can be issued. If none are provided, it will be considered a pass. If any are provided, then at least one must pass for the rules to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallow)) + +### Nested Schema for `spec.rules.allow` + +Optional: + +- `conditions` (Attributes List) The conditions that must be met for this rule to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallowconditions)) + +### Nested Schema for `spec.rules.allow.conditions` + +Optional: + +- `attribute` (String) The name of the attribute to evaluate the condition against. +- `equals` (String) An exact string that the attribute must match. + + + + +### Nested Schema for `spec.spiffe` + +Optional: + +- `hint` (String) A freeform text field which is provided to workloads along with a credential produced by this WorkloadIdentity. This can be used to provide additional context that can be used to select between multiple credentials. +- `id` (String) The path of the SPIFFE ID that will be issued to the workload. This should be prefixed with a forward-slash ("/"). This field supports templating using attributes. + diff --git a/docs/pages/reference/terraform-provider/resources/resources.mdx b/docs/pages/reference/terraform-provider/resources/resources.mdx index 51d7bb8d2e3b3..e962f85c38abb 100644 --- a/docs/pages/reference/terraform-provider/resources/resources.mdx +++ b/docs/pages/reference/terraform-provider/resources/resources.mdx @@ -36,3 +36,4 @@ The Teleport Terraform provider supports the following resources: - [`teleport_trusted_cluster`](./trusted_cluster.mdx) - [`teleport_trusted_device`](./trusted_device.mdx) - [`teleport_user`](./user.mdx) + - [`teleport_workload_identity`](./workload_identity.mdx) diff --git a/docs/pages/reference/terraform-provider/resources/workload_identity.mdx b/docs/pages/reference/terraform-provider/resources/workload_identity.mdx new file mode 100644 index 0000000000000..a9d3da4bc7a73 --- /dev/null +++ b/docs/pages/reference/terraform-provider/resources/workload_identity.mdx @@ -0,0 +1,94 @@ +--- +title: Reference for the teleport_workload_identity Terraform resource +sidebar_label: workload_identity +description: This page describes the supported values of the teleport_workload_identity resource of the Teleport Terraform provider. +--- + +{/*Auto-generated file. Do not edit.*/} +{/*To regenerate, navigate to integrations/terraform and run `make docs`.*/} + + + +## Example Usage + +```hcl +resource "teleport_workload_identity" "example" { + version = "v1" + metadata = { + name = "example" + } + spec = { + rules = { + allow = [ + { + conditions = [{ + attribute = "user.name" + equals = "noah" + }] + } + ] + } + spiffe = { + id = "/my/spiffe/id/path" + hint = "my-hint" + } + } +} +``` + +{/* schema generated by tfplugindocs */} +## Schema + +### Optional + +- `metadata` (Attributes) Common metadata that all resources share. (see [below for nested schema](#nested-schema-for-metadata)) +- `spec` (Attributes) The configured properties of the WorkloadIdentity (see [below for nested schema](#nested-schema-for-spec)) +- `sub_kind` (String) Differentiates variations of the same kind. All resources should contain one, even if it is never populated. +- `version` (String) The version of the resource being represented. + +### Nested Schema for `metadata` + +Optional: + +- `description` (String) description is object description. +- `expires` (String) expires is a global expiry time header can be set on any resource in the system. +- `labels` (Map of String) labels is a set of labels. +- `name` (String) name is an object name. + + +### Nested Schema for `spec` + +Optional: + +- `rules` (Attributes) The rules which are evaluated before the WorkloadIdentity can be issued. (see [below for nested schema](#nested-schema-for-specrules)) +- `spiffe` (Attributes) Configuration pertaining to the issuance of SPIFFE-compatible workload identity credentials. (see [below for nested schema](#nested-schema-for-specspiffe)) + +### Nested Schema for `spec.rules` + +Optional: + +- `allow` (Attributes List) A list of rules used to determine if a WorkloadIdentity can be issued. If none are provided, it will be considered a pass. If any are provided, then at least one must pass for the rules to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallow)) + +### Nested Schema for `spec.rules.allow` + +Optional: + +- `conditions` (Attributes List) The conditions that must be met for this rule to be considered passed. (see [below for nested schema](#nested-schema-for-specrulesallowconditions)) + +### Nested Schema for `spec.rules.allow.conditions` + +Optional: + +- `attribute` (String) The name of the attribute to evaluate the condition against. +- `equals` (String) An exact string that the attribute must match. + + + + +### Nested Schema for `spec.spiffe` + +Optional: + +- `hint` (String) A freeform text field which is provided to workloads along with a credential produced by this WorkloadIdentity. This can be used to provide additional context that can be used to select between multiple credentials. +- `id` (String) The path of the SPIFFE ID that will be issued to the workload. This should be prefixed with a forward-slash ("/"). This field supports templating using attributes. + diff --git a/e b/e index ffbb6c77ab986..1ac55fb740b1f 160000 --- a/e +++ b/e @@ -1 +1 @@ -Subproject commit ffbb6c77ab986eae88ed8681c4b67b0e82820eae +Subproject commit 1ac55fb740b1f79d44a1457d004bfb0b422b4007 diff --git a/examples/aws/terraform/AMIS.md b/examples/aws/terraform/AMIS.md index c9006e85440da..7d865426baf67 100644 --- a/examples/aws/terraform/AMIS.md +++ b/examples/aws/terraform/AMIS.md @@ -6,116 +6,116 @@ This list is updated when new AMI versions are released. ### OSS ``` -# ap-northeast-1 v17.1.0 arm64 OSS: ami-05d48ab4187b69aad -# ap-northeast-1 v17.1.0 x86_64 OSS: ami-0771bb7ea243be53e -# ap-northeast-2 v17.1.0 arm64 OSS: ami-07184d83509a4de9f -# ap-northeast-2 v17.1.0 x86_64 OSS: ami-0f77764082d35f51f -# ap-northeast-3 v17.1.0 arm64 OSS: ami-030b6b0910f582924 -# ap-northeast-3 v17.1.0 x86_64 OSS: ami-0fea7130c366b6660 -# ap-south-1 v17.1.0 arm64 OSS: ami-00536811675fb7ca5 -# ap-south-1 v17.1.0 x86_64 OSS: ami-004c201af536d8c4c -# ap-southeast-1 v17.1.0 arm64 OSS: ami-0512146122ffad85e -# ap-southeast-1 v17.1.0 x86_64 OSS: ami-0a06cfa6a7088c06a -# ap-southeast-2 v17.1.0 arm64 OSS: ami-04ee7db250ee72884 -# ap-southeast-2 v17.1.0 x86_64 OSS: ami-02827e89f41e222c2 -# ca-central-1 v17.1.0 arm64 OSS: ami-0bea774e474572c9a -# ca-central-1 v17.1.0 x86_64 OSS: ami-09b1350d81173ca9f -# eu-central-1 v17.1.0 arm64 OSS: ami-006b6efbc199ba1b7 -# eu-central-1 v17.1.0 x86_64 OSS: ami-0d350bffc56ed6a7e -# eu-north-1 v17.1.0 arm64 OSS: ami-025c9c63e6681a10c -# eu-north-1 v17.1.0 x86_64 OSS: ami-0f757ccc0186db97b -# eu-west-1 v17.1.0 arm64 OSS: ami-0a628413a28dc743e -# eu-west-1 v17.1.0 x86_64 OSS: ami-0c44493ee0f75b08f -# eu-west-2 v17.1.0 arm64 OSS: ami-074beb9d44ee7f8b0 -# eu-west-2 v17.1.0 x86_64 OSS: ami-0526b4f61f6c8ac19 -# eu-west-3 v17.1.0 arm64 OSS: ami-09f0631b07f10f700 -# eu-west-3 v17.1.0 x86_64 OSS: ami-0a3c6bbf9ed4b06fb -# sa-east-1 v17.1.0 arm64 OSS: ami-08e90ce1a60c5d9d7 -# sa-east-1 v17.1.0 x86_64 OSS: ami-0714cd595e4739862 -# us-east-1 v17.1.0 arm64 OSS: ami-060da265f62727bf6 -# us-east-1 v17.1.0 x86_64 OSS: ami-0a481eea172b4293d -# us-east-2 v17.1.0 arm64 OSS: ami-04efea40fcbc97719 -# us-east-2 v17.1.0 x86_64 OSS: ami-0cc8d9116cc499a3c -# us-west-1 v17.1.0 arm64 OSS: ami-063e9e5c822a37abb -# us-west-1 v17.1.0 x86_64 OSS: ami-0f423d0d5bd921fa3 -# us-west-2 v17.1.0 arm64 OSS: ami-073a4498a5bdb3d9f -# us-west-2 v17.1.0 x86_64 OSS: ami-0f091942faaef349a +# ap-northeast-1 v17.1.1 arm64 OSS: ami-0a5f537784eefe27d +# ap-northeast-1 v17.1.1 x86_64 OSS: ami-0fa7217a33b990ade +# ap-northeast-2 v17.1.1 arm64 OSS: ami-07743f3160d7a84d5 +# ap-northeast-2 v17.1.1 x86_64 OSS: ami-09494d6d9a40ba545 +# ap-northeast-3 v17.1.1 arm64 OSS: ami-0796da20b071a04b3 +# ap-northeast-3 v17.1.1 x86_64 OSS: ami-01261fded996c0ef0 +# ap-south-1 v17.1.1 arm64 OSS: ami-0e27bda4740337a18 +# ap-south-1 v17.1.1 x86_64 OSS: ami-0880e06edeb92ecd8 +# ap-southeast-1 v17.1.1 arm64 OSS: ami-07af7f495d88a376f +# ap-southeast-1 v17.1.1 x86_64 OSS: ami-01e50574d67633cce +# ap-southeast-2 v17.1.1 arm64 OSS: ami-037afbc1ff2499bfe +# ap-southeast-2 v17.1.1 x86_64 OSS: ami-0e9edd4ef1b3e31d6 +# ca-central-1 v17.1.1 arm64 OSS: ami-0073a58172aa80af8 +# ca-central-1 v17.1.1 x86_64 OSS: ami-0fce23a5eb19a02db +# eu-central-1 v17.1.1 arm64 OSS: ami-0d5907f1b2a21211f +# eu-central-1 v17.1.1 x86_64 OSS: ami-0ba02341b6b92f1ec +# eu-north-1 v17.1.1 arm64 OSS: ami-0ea705245cecc65c2 +# eu-north-1 v17.1.1 x86_64 OSS: ami-0c3fa661a640c192d +# eu-west-1 v17.1.1 arm64 OSS: ami-01b5104f6f8cd57f3 +# eu-west-1 v17.1.1 x86_64 OSS: ami-0b48b0e504ca31eea +# eu-west-2 v17.1.1 arm64 OSS: ami-076c147bd8e15b442 +# eu-west-2 v17.1.1 x86_64 OSS: ami-09a03b3aacde88e2c +# eu-west-3 v17.1.1 arm64 OSS: ami-0dce47e1114501cb8 +# eu-west-3 v17.1.1 x86_64 OSS: ami-0e6c59fe3f5dc2d10 +# sa-east-1 v17.1.1 arm64 OSS: ami-0f690494a46ee109b +# sa-east-1 v17.1.1 x86_64 OSS: ami-037d098fadee1e2c6 +# us-east-1 v17.1.1 arm64 OSS: ami-07740b1bf08cf934f +# us-east-1 v17.1.1 x86_64 OSS: ami-041cfef0d1d4a87c5 +# us-east-2 v17.1.1 arm64 OSS: ami-031fe3ad6e1dceca7 +# us-east-2 v17.1.1 x86_64 OSS: ami-0536a571102911485 +# us-west-1 v17.1.1 arm64 OSS: ami-0835e194313e390c3 +# us-west-1 v17.1.1 x86_64 OSS: ami-0578b1ed1a3ac9b43 +# us-west-2 v17.1.1 arm64 OSS: ami-09edc5fe54a15763d +# us-west-2 v17.1.1 x86_64 OSS: ami-0cb483d633378e707 ``` ### Enterprise ``` -# ap-northeast-1 v17.1.0 arm64 Enterprise: ami-0054beb624b93a3d0 -# ap-northeast-1 v17.1.0 x86_64 Enterprise: ami-0dbef8379e4c2c225 -# ap-northeast-2 v17.1.0 arm64 Enterprise: ami-0c38f0f52cd32a5ed -# ap-northeast-2 v17.1.0 x86_64 Enterprise: ami-049e5fbf9f1d9fce8 -# ap-northeast-3 v17.1.0 arm64 Enterprise: ami-00656bf0363c42865 -# ap-northeast-3 v17.1.0 x86_64 Enterprise: ami-001609c2cb7449fbc -# ap-south-1 v17.1.0 arm64 Enterprise: ami-036ece94f64bf3ea7 -# ap-south-1 v17.1.0 x86_64 Enterprise: ami-0b42050e95f926aeb -# ap-southeast-1 v17.1.0 arm64 Enterprise: ami-06a26bb15bd9ca42a -# ap-southeast-1 v17.1.0 x86_64 Enterprise: ami-0c5cf93801310fc9c -# ap-southeast-2 v17.1.0 arm64 Enterprise: ami-0a3bc5db7482b39e8 -# ap-southeast-2 v17.1.0 x86_64 Enterprise: ami-063a7f0c4ce5b1db2 -# ca-central-1 v17.1.0 arm64 Enterprise: ami-080d8bd9ad1ab8fc7 -# ca-central-1 v17.1.0 x86_64 Enterprise: ami-00a89e0f143218b4f -# eu-central-1 v17.1.0 arm64 Enterprise: ami-0c24ed4801d5d8930 -# eu-central-1 v17.1.0 x86_64 Enterprise: ami-08e2317992e40cae6 -# eu-north-1 v17.1.0 arm64 Enterprise: ami-0272e7fe996421cb3 -# eu-north-1 v17.1.0 x86_64 Enterprise: ami-0f324a587f30af7a9 -# eu-west-1 v17.1.0 arm64 Enterprise: ami-0a016a18b345679c8 -# eu-west-1 v17.1.0 x86_64 Enterprise: ami-092241ead9afd9dfe -# eu-west-2 v17.1.0 arm64 Enterprise: ami-098ca4be33a079de5 -# eu-west-2 v17.1.0 x86_64 Enterprise: ami-05d03222fd3f32735 -# eu-west-3 v17.1.0 arm64 Enterprise: ami-05f4a7124ca6c2c66 -# eu-west-3 v17.1.0 x86_64 Enterprise: ami-0bf3fff32d23ef3c1 -# sa-east-1 v17.1.0 arm64 Enterprise: ami-0610008b54140b89b -# sa-east-1 v17.1.0 x86_64 Enterprise: ami-00da41d2bf0698b3f -# us-east-1 v17.1.0 arm64 Enterprise: ami-0bf51a258f80e2ec2 -# us-east-1 v17.1.0 x86_64 Enterprise: ami-0b1da60eb131922ab -# us-east-2 v17.1.0 arm64 Enterprise: ami-0a4367cf4cb92be24 -# us-east-2 v17.1.0 x86_64 Enterprise: ami-0c4bc58b0d9ef0c61 -# us-west-1 v17.1.0 arm64 Enterprise: ami-0660af60a0aba46c1 -# us-west-1 v17.1.0 x86_64 Enterprise: ami-05c3f83de44830858 -# us-west-2 v17.1.0 arm64 Enterprise: ami-0f2da6ca41d40371a -# us-west-2 v17.1.0 x86_64 Enterprise: ami-0797199b139ee8a16 +# ap-northeast-1 v17.1.1 arm64 Enterprise: ami-06ae3535ed979aee1 +# ap-northeast-1 v17.1.1 x86_64 Enterprise: ami-07a429464b7ee8c39 +# ap-northeast-2 v17.1.1 arm64 Enterprise: ami-038083abbd8409558 +# ap-northeast-2 v17.1.1 x86_64 Enterprise: ami-09c60722ea157e47f +# ap-northeast-3 v17.1.1 arm64 Enterprise: ami-0462fb982418429a6 +# ap-northeast-3 v17.1.1 x86_64 Enterprise: ami-0edf80412e2acfd7d +# ap-south-1 v17.1.1 arm64 Enterprise: ami-00ee7e18b4dce5b38 +# ap-south-1 v17.1.1 x86_64 Enterprise: ami-0c79727a649925e90 +# ap-southeast-1 v17.1.1 arm64 Enterprise: ami-0d20a3b57c85d3181 +# ap-southeast-1 v17.1.1 x86_64 Enterprise: ami-0fbcb24884a208cb8 +# ap-southeast-2 v17.1.1 arm64 Enterprise: ami-0c0f6083586a83757 +# ap-southeast-2 v17.1.1 x86_64 Enterprise: ami-0b4a4c53dd6a3c041 +# ca-central-1 v17.1.1 arm64 Enterprise: ami-060427412a5b319db +# ca-central-1 v17.1.1 x86_64 Enterprise: ami-08c8208ba96f752d3 +# eu-central-1 v17.1.1 arm64 Enterprise: ami-09c856532e84903a4 +# eu-central-1 v17.1.1 x86_64 Enterprise: ami-04d917c8c4579daf3 +# eu-north-1 v17.1.1 arm64 Enterprise: ami-04626a94f7050e050 +# eu-north-1 v17.1.1 x86_64 Enterprise: ami-02037040a4dec671c +# eu-west-1 v17.1.1 arm64 Enterprise: ami-00b9b4e5b3a88e7e2 +# eu-west-1 v17.1.1 x86_64 Enterprise: ami-071ebf6045a75b052 +# eu-west-2 v17.1.1 arm64 Enterprise: ami-0a236e67285cdb0b1 +# eu-west-2 v17.1.1 x86_64 Enterprise: ami-0c5a3e844c5b0ec71 +# eu-west-3 v17.1.1 arm64 Enterprise: ami-0140989d590989f0d +# eu-west-3 v17.1.1 x86_64 Enterprise: ami-073047ac3039425ed +# sa-east-1 v17.1.1 arm64 Enterprise: ami-05e5977088a7c2f0d +# sa-east-1 v17.1.1 x86_64 Enterprise: ami-00c165883d2b5aaf3 +# us-east-1 v17.1.1 arm64 Enterprise: ami-034f43fd05ada7b8b +# us-east-1 v17.1.1 x86_64 Enterprise: ami-02082755b0ae57bee +# us-east-2 v17.1.1 arm64 Enterprise: ami-0a1f6bc02c3d3bf34 +# us-east-2 v17.1.1 x86_64 Enterprise: ami-0adca974f282e5cff +# us-west-1 v17.1.1 arm64 Enterprise: ami-05d3f25c97a11b669 +# us-west-1 v17.1.1 x86_64 Enterprise: ami-080171387a0b1e9f9 +# us-west-2 v17.1.1 arm64 Enterprise: ami-0cdaf82f5bb71e653 +# us-west-2 v17.1.1 x86_64 Enterprise: ami-07518e397993ac08b ``` ### Enterprise FIPS ``` -# ap-northeast-1 v17.1.0 arm64 Enterprise FIPS: ami-006e277130d6697b8 -# ap-northeast-1 v17.1.0 x86_64 Enterprise FIPS: ami-0d2097cc785d5ddd1 -# ap-northeast-2 v17.1.0 arm64 Enterprise FIPS: ami-05d7526f2fa772bae -# ap-northeast-2 v17.1.0 x86_64 Enterprise FIPS: ami-0b95d703d0fb35264 -# ap-northeast-3 v17.1.0 arm64 Enterprise FIPS: ami-058a1688e3746346f -# ap-northeast-3 v17.1.0 x86_64 Enterprise FIPS: ami-0a3609711beac9b12 -# ap-south-1 v17.1.0 arm64 Enterprise FIPS: ami-04fd535409f9546b2 -# ap-south-1 v17.1.0 x86_64 Enterprise FIPS: ami-0c8eb1f599b03ba3d -# ap-southeast-1 v17.1.0 arm64 Enterprise FIPS: ami-0859705827146286a -# ap-southeast-1 v17.1.0 x86_64 Enterprise FIPS: ami-08ce8518812498f8e -# ap-southeast-2 v17.1.0 arm64 Enterprise FIPS: ami-099243139967a52ef -# ap-southeast-2 v17.1.0 x86_64 Enterprise FIPS: ami-04e9d6967cf82c029 -# ca-central-1 v17.1.0 arm64 Enterprise FIPS: ami-0724d756ac222374c -# ca-central-1 v17.1.0 x86_64 Enterprise FIPS: ami-0ba9b501211abdfa3 -# eu-central-1 v17.1.0 arm64 Enterprise FIPS: ami-0db5328407fdf56cb -# eu-central-1 v17.1.0 x86_64 Enterprise FIPS: ami-0c811a9693f2ddb6e -# eu-north-1 v17.1.0 arm64 Enterprise FIPS: ami-0e70137a138a7c919 -# eu-north-1 v17.1.0 x86_64 Enterprise FIPS: ami-01ed85ddc0cdbafb4 -# eu-west-1 v17.1.0 arm64 Enterprise FIPS: ami-04678f3cda0b28ae8 -# eu-west-1 v17.1.0 x86_64 Enterprise FIPS: ami-0f2ccfb2586e70f99 -# eu-west-2 v17.1.0 arm64 Enterprise FIPS: ami-0e89768c72aa20b1a -# eu-west-2 v17.1.0 x86_64 Enterprise FIPS: ami-0fb819f8af7d2c478 -# eu-west-3 v17.1.0 arm64 Enterprise FIPS: ami-0e6824016a67d2446 -# eu-west-3 v17.1.0 x86_64 Enterprise FIPS: ami-010efc79993d1ea33 -# sa-east-1 v17.1.0 arm64 Enterprise FIPS: ami-0658ae24643ca38e6 -# sa-east-1 v17.1.0 x86_64 Enterprise FIPS: ami-0d14d90a5352b3771 -# us-east-1 v17.1.0 arm64 Enterprise FIPS: ami-08d29a6b64f3344be -# us-east-1 v17.1.0 x86_64 Enterprise FIPS: ami-0430151efc1689906 -# us-east-2 v17.1.0 arm64 Enterprise FIPS: ami-0da38d632101bf3d1 -# us-east-2 v17.1.0 x86_64 Enterprise FIPS: ami-09340caeb2a02f47d -# us-west-1 v17.1.0 arm64 Enterprise FIPS: ami-0456b2b106888013e -# us-west-1 v17.1.0 x86_64 Enterprise FIPS: ami-0b58799c4f10967c2 -# us-west-2 v17.1.0 arm64 Enterprise FIPS: ami-06b404ae4fed6d673 -# us-west-2 v17.1.0 x86_64 Enterprise FIPS: ami-084c64cf7ead63339 +# ap-northeast-1 v17.1.1 arm64 Enterprise FIPS: ami-095a897c8b13edec7 +# ap-northeast-1 v17.1.1 x86_64 Enterprise FIPS: ami-0a03bc36f642d0795 +# ap-northeast-2 v17.1.1 arm64 Enterprise FIPS: ami-083c2cc73df99c551 +# ap-northeast-2 v17.1.1 x86_64 Enterprise FIPS: ami-038b56cef84d98b26 +# ap-northeast-3 v17.1.1 arm64 Enterprise FIPS: ami-0fd3ed262911c079f +# ap-northeast-3 v17.1.1 x86_64 Enterprise FIPS: ami-03a2e04456b18a65c +# ap-south-1 v17.1.1 arm64 Enterprise FIPS: ami-04e4f5f215d81edc9 +# ap-south-1 v17.1.1 x86_64 Enterprise FIPS: ami-0e81f5bd20bfab210 +# ap-southeast-1 v17.1.1 arm64 Enterprise FIPS: ami-0d6848c15b2f79a03 +# ap-southeast-1 v17.1.1 x86_64 Enterprise FIPS: ami-08c4fc849b2afcc78 +# ap-southeast-2 v17.1.1 arm64 Enterprise FIPS: ami-0321bc57c7f7201b0 +# ap-southeast-2 v17.1.1 x86_64 Enterprise FIPS: ami-058396ee5c2e518bf +# ca-central-1 v17.1.1 arm64 Enterprise FIPS: ami-09f7184cefdb18036 +# ca-central-1 v17.1.1 x86_64 Enterprise FIPS: ami-0b85b4c0019b40956 +# eu-central-1 v17.1.1 arm64 Enterprise FIPS: ami-08fbb4c1ed81bd076 +# eu-central-1 v17.1.1 x86_64 Enterprise FIPS: ami-00c06e92f6992d8c3 +# eu-north-1 v17.1.1 arm64 Enterprise FIPS: ami-0845f4478f4cd5f63 +# eu-north-1 v17.1.1 x86_64 Enterprise FIPS: ami-0b50b04da77f287b1 +# eu-west-1 v17.1.1 arm64 Enterprise FIPS: ami-0689ff77e620de869 +# eu-west-1 v17.1.1 x86_64 Enterprise FIPS: ami-05aa391af6f47f95a +# eu-west-2 v17.1.1 arm64 Enterprise FIPS: ami-090188b6f91c6d7e4 +# eu-west-2 v17.1.1 x86_64 Enterprise FIPS: ami-0c9534dcfaa711757 +# eu-west-3 v17.1.1 arm64 Enterprise FIPS: ami-00af1fadbb5b101cb +# eu-west-3 v17.1.1 x86_64 Enterprise FIPS: ami-0b0a4d9ead7ec1cf1 +# sa-east-1 v17.1.1 arm64 Enterprise FIPS: ami-018f08eeb957e774f +# sa-east-1 v17.1.1 x86_64 Enterprise FIPS: ami-0c4b47928c2097626 +# us-east-1 v17.1.1 arm64 Enterprise FIPS: ami-0fd7d05acc2acee36 +# us-east-1 v17.1.1 x86_64 Enterprise FIPS: ami-0e2c9f308efa1ede7 +# us-east-2 v17.1.1 arm64 Enterprise FIPS: ami-0d6114bd3d19c6291 +# us-east-2 v17.1.1 x86_64 Enterprise FIPS: ami-0463c72427ad61436 +# us-west-1 v17.1.1 arm64 Enterprise FIPS: ami-0c550565b653d7cd6 +# us-west-1 v17.1.1 x86_64 Enterprise FIPS: ami-051ee46c716df5ef6 +# us-west-2 v17.1.1 arm64 Enterprise FIPS: ami-04c32562ed8325ff7 +# us-west-2 v17.1.1 x86_64 Enterprise FIPS: ami-0825c6a88c93a01c7 ``` diff --git a/examples/aws/terraform/ha-autoscale-cluster/README.md b/examples/aws/terraform/ha-autoscale-cluster/README.md index 3aea34e392677..579c13a201c1a 100644 --- a/examples/aws/terraform/ha-autoscale-cluster/README.md +++ b/examples/aws/terraform/ha-autoscale-cluster/README.md @@ -46,7 +46,7 @@ export TF_VAR_cluster_name="teleport.example.com" # OSS: aws ec2 describe-images --owners 146628656107 --filters 'Name=name,Values=teleport-oss-*' # Enterprise: aws ec2 describe-images --owners 146628656107 --filters 'Name=name,Values=teleport-ent-*' # FIPS 140-2 images are also available for Enterprise customers, look for '-fips' on the end of the AMI's name -export TF_VAR_ami_name="teleport-ent-17.1.0-arm64" +export TF_VAR_ami_name="teleport-ent-17.1.1-arm64" # Instance types used for authentication server auto scaling group # This should match to the AMI instance architecture type, ARM or x86 diff --git a/examples/aws/terraform/starter-cluster/README.md b/examples/aws/terraform/starter-cluster/README.md index be6ef3107f3f3..a7461d5981d86 100644 --- a/examples/aws/terraform/starter-cluster/README.md +++ b/examples/aws/terraform/starter-cluster/README.md @@ -98,7 +98,7 @@ TF_VAR_license_path ?= "/path/to/license" # OSS: aws ec2 describe-images --owners 146628656107 --filters 'Name=name,Values=teleport-oss-*' # Enterprise: aws ec2 describe-images --owners 146628656107 --filters 'Name=name,Values=teleport-ent-*' # FIPS 140-2 images are also available for Enterprise customers, look for '-fips' on the end of the AMI's name -TF_VAR_ami_name ?= "teleport-ent-17.1.0-arm64" +TF_VAR_ami_name ?= "teleport-ent-17.1.1-arm64" # Route 53 hosted zone to use, must be a root zone registered in AWS, e.g. example.com TF_VAR_route53_zone ?= "example.com" diff --git a/examples/chart/tbot/.lint/full.yaml b/examples/chart/tbot/.lint/full.yaml index 706b3d207ee5c..9d076782b506e 100644 --- a/examples/chart/tbot/.lint/full.yaml +++ b/examples/chart/tbot/.lint/full.yaml @@ -1,7 +1,7 @@ clusterName: "test.teleport.sh" teleportAuthAddress: "my-auth:3024" defaultOutput: - enabled: false + enabled: true token: "my-token" joinMethod: "modified-join-method" diff --git a/examples/chart/tbot/templates/_config.tpl b/examples/chart/tbot/templates/_config.tpl index 344b25e403fc5..d8c9aff491862 100644 --- a/examples/chart/tbot/templates/_config.tpl +++ b/examples/chart/tbot/templates/_config.tpl @@ -40,10 +40,10 @@ outputs: name: {{ include "tbot.defaultOutputName" . }} {{- end }} {{- if .Values.outputs }} -{{- toYaml .Values.outputs | nindent 6}} +{{- toYaml .Values.outputs | nindent 2}} {{- end }} {{- end }} {{- if .Values.services }} -services: {{- toYaml .Values.services | nindent 6}} +services: {{- toYaml .Values.services | nindent 2}} {{- end }} {{- end -}} diff --git a/examples/chart/tbot/tests/__snapshot__/config_test.yaml.snap b/examples/chart/tbot/tests/__snapshot__/config_test.yaml.snap index a1e58c58b4643..2dbfb81532f58 100644 --- a/examples/chart/tbot/tests/__snapshot__/config_test.yaml.snap +++ b/examples/chart/tbot/tests/__snapshot__/config_test.yaml.snap @@ -35,6 +35,10 @@ should match the snapshot (full): join_method: modified-join-method token: my-token outputs: + - destination: + name: RELEASE-NAME-tbot-out + type: kubernetes_secret + type: identity - app_name: foo destination: path: /bar diff --git a/examples/chart/tbot/tests/__snapshot__/deployment_test.yaml.snap b/examples/chart/tbot/tests/__snapshot__/deployment_test.yaml.snap index d615816877e63..1c2be632d2ae5 100644 --- a/examples/chart/tbot/tests/__snapshot__/deployment_test.yaml.snap +++ b/examples/chart/tbot/tests/__snapshot__/deployment_test.yaml.snap @@ -22,7 +22,7 @@ should match the snapshot (full): template: metadata: annotations: - checksum/config: 094cdbfc4e4fe3824a33426d8eea4e9e8a4b2711823d4fbb4102e11caa7f62c0 + checksum/config: 010d3421120a26bed12d1b9df8443e0eeafa362e88bd830e4a81688d13689483 test-key: test-annotation-pod labels: app.kubernetes.io/component: tbot diff --git a/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go b/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go index 73e0be8af1866..f2e88f23d89c8 100644 --- a/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/access_graph_service.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/access_graph_service.proto @@ -1554,6 +1554,183 @@ func (*AzureEventsStreamResponse) Descriptor() ([]byte, []int) { return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{23} } +// NetIQEventsStreamRequest is a request to send commands to the NetIQ importer +type NetIQEventsStreamRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Operation: + // + // *NetIQEventsStreamRequest_Sync + // *NetIQEventsStreamRequest_Upsert + // *NetIQEventsStreamRequest_Delete + Operation isNetIQEventsStreamRequest_Operation `protobuf_oneof:"operation"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQEventsStreamRequest) Reset() { + *x = NetIQEventsStreamRequest{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQEventsStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQEventsStreamRequest) ProtoMessage() {} + +func (x *NetIQEventsStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24] + 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 NetIQEventsStreamRequest.ProtoReflect.Descriptor instead. +func (*NetIQEventsStreamRequest) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{24} +} + +func (x *NetIQEventsStreamRequest) GetOperation() isNetIQEventsStreamRequest_Operation { + if x != nil { + return x.Operation + } + return nil +} + +func (x *NetIQEventsStreamRequest) GetSync() *NetIQSyncOperation { + if x != nil { + if x, ok := x.Operation.(*NetIQEventsStreamRequest_Sync); ok { + return x.Sync + } + } + return nil +} + +func (x *NetIQEventsStreamRequest) GetUpsert() *NetIQResourceList { + if x != nil { + if x, ok := x.Operation.(*NetIQEventsStreamRequest_Upsert); ok { + return x.Upsert + } + } + return nil +} + +func (x *NetIQEventsStreamRequest) GetDelete() *NetIQResourceList { + if x != nil { + if x, ok := x.Operation.(*NetIQEventsStreamRequest_Delete); ok { + return x.Delete + } + } + return nil +} + +type isNetIQEventsStreamRequest_Operation interface { + isNetIQEventsStreamRequest_Operation() +} + +type NetIQEventsStreamRequest_Sync struct { + // sync is a command to sync the access graph with the NetIQ state. + Sync *NetIQSyncOperation `protobuf:"bytes,1,opt,name=sync,proto3,oneof"` +} + +type NetIQEventsStreamRequest_Upsert struct { + // upsert is a command to put a resource into the access graph or update it. + Upsert *NetIQResourceList `protobuf:"bytes,2,opt,name=upsert,proto3,oneof"` +} + +type NetIQEventsStreamRequest_Delete struct { + // delete is a command to delete a resource from the access graph when it's deleted. + Delete *NetIQResourceList `protobuf:"bytes,3,opt,name=delete,proto3,oneof"` +} + +func (*NetIQEventsStreamRequest_Sync) isNetIQEventsStreamRequest_Operation() {} + +func (*NetIQEventsStreamRequest_Upsert) isNetIQEventsStreamRequest_Operation() {} + +func (*NetIQEventsStreamRequest_Delete) isNetIQEventsStreamRequest_Operation() {} + +// NetIQSyncOperation is a command that Teleport sends to the access graph service +// at the end of the sync process. +type NetIQSyncOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQSyncOperation) Reset() { + *x = NetIQSyncOperation{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQSyncOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQSyncOperation) ProtoMessage() {} + +func (x *NetIQSyncOperation) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[25] + 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 NetIQSyncOperation.ProtoReflect.Descriptor instead. +func (*NetIQSyncOperation) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{25} +} + +// NetIQEventsStreamResponse is a response from NetIQEventsStream +type NetIQEventsStreamResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQEventsStreamResponse) Reset() { + *x = NetIQEventsStreamResponse{} + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQEventsStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQEventsStreamResponse) ProtoMessage() {} + +func (x *NetIQEventsStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[26] + 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 NetIQEventsStreamResponse.ProtoReflect.Descriptor instead. +func (*NetIQEventsStreamResponse) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP(), []int{26} +} + var File_accessgraph_v1alpha_access_graph_service_proto protoreflect.FileDescriptor var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ @@ -1573,25 +1750,54 @@ var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x61, 0x63, 0x63, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0x24, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x6f, 0x64, - 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x64, 0x67, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x64, - 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, 0x74, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x69, - 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xaa, - 0x03, 0x0a, 0x13, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x2f, 0x6e, 0x65, 0x74, 0x69, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x23, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x24, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x71, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x6f, + 0x64, 0x65, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x64, 0x67, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, + 0x64, 0x67, 0x65, 0x52, 0x05, 0x65, 0x64, 0x67, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x22, 0x25, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, + 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, + 0xaa, 0x03, 0x0a, 0x13, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, + 0x63, 0x12, 0x3b, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, + 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x5b, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x73, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6f, + 0x0a, 0x1b, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac, 0x03, 0x0a, + 0x15, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4f, @@ -1617,202 +1823,201 @@ var file_accessgraph_v1alpha_access_graph_service_proto_rawDesc = []byte{ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xac, 0x03, 0x0a, 0x15, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x53, + 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x6f, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, + 0x58, 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, + 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, + 0x5f, 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, + 0x43, 0x61, 0x50, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, + 0x73, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x11, + 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x70, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x50, 0x65, + 0x6d, 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x16, 0x41, 0x57, 0x53, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, - 0x3b, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, + 0x3e, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, + 0x3e, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, + 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x19, 0x0a, 0x17, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x19, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x04, 0x73, 0x79, 0x6e, + 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, + 0x74, 0x6c, 0x61, 0x62, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x73, + 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x5b, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x73, 0x5f, - 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, - 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x12, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x6f, 0x0a, 0x1b, - 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, - 0x69, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x73, 0x48, 0x00, 0x52, 0x18, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x41, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x42, 0x0b, 0x0a, - 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x79, - 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x5b, 0x0a, 0x16, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, - 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, - 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x6f, 0x0a, 0x0a, 0x41, 0x75, 0x64, 0x69, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x58, - 0x0a, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x64, 0x48, 0x00, 0x52, 0x11, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, - 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x22, 0x54, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, - 0x70, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, - 0x61, 0x50, 0x65, 0x6d, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6c, 0x75, 0x73, - 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x0a, 0x11, 0x52, - 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1e, 0x0a, 0x0b, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x5f, 0x70, 0x65, 0x6d, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x43, 0x61, 0x50, 0x65, 0x6d, - 0x22, 0x14, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xe2, 0x01, 0x0a, 0x16, 0x41, 0x57, 0x53, 0x45, 0x76, + 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, + 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1c, 0x0a, 0x1a, + 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x45, + 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, + 0x61, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, + 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, + 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, + 0x6e, 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x45, 0x6e, 0x74, 0x72, 0x61, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x3b, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x3e, - 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x3e, - 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x41, - 0x57, 0x53, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, - 0x19, 0x0a, 0x17, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xee, 0x01, 0x0a, 0x19, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, - 0x6c, 0x61, 0x62, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x41, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, - 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x41, 0x0a, 0x06, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, + 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, + 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x14, 0x0a, 0x12, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, + 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, + 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x14, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x4e, 0x65, 0x74, 0x49, 0x51, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x9b, 0x09, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, + 0x72, 0x61, 0x70, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x05, 0x51, + 0x75, 0x65, 0x72, 0x79, 0x12, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x47, + 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x65, 0x74, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, - 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, - 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1c, 0x0a, 0x1a, 0x47, - 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x45, 0x6e, - 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, - 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, - 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, - 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, - 0x74, 0x72, 0x61, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0xea, 0x01, 0x0a, 0x18, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x3d, 0x0a, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, - 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x73, 0x79, 0x6e, 0x63, 0x12, - 0x40, 0x0a, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, 0x73, 0x65, 0x72, - 0x74, 0x12, 0x40, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x14, 0x0a, 0x12, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4f, 0x70, 0x65, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1b, 0x0a, 0x19, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0xa3, 0x08, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4e, 0x0a, 0x05, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x12, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x07, 0x47, 0x65, - 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x46, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x65, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x12, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, - 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x63, 0x63, + 0x61, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x65, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x12, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x6d, 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x12, 0x2a, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x6d, 0x0a, 0x0e, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x12, 0x2a, 0x2e, 0x61, 0x63, 0x63, 0x65, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x56, 0x32, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x12, 0x24, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x5d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x12, 0x26, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, - 0x0a, 0x0f, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, - 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x5d, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x12, 0x26, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, - 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x79, - 0x0a, 0x12, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, - 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, 0x61, - 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x45, 0x6e, 0x74, - 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x43, 0x41, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x6e, 0x0a, 0x0f, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x12, 0x2b, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x57, 0x53, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, + 0x79, 0x0a, 0x12, 0x47, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x47, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x45, 0x6e, + 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, - 0x70, 0x68, 0x61, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x61, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, - 0x01, 0x12, 0x76, 0x0a, 0x11, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, + 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x41, 0x7a, 0x75, 0x72, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x57, 0x5a, 0x55, 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, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, - 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x11, 0x4e, 0x65, + 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, + 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, + 0x30, 0x01, 0x42, 0x57, 0x5a, 0x55, 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, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -1827,7 +2032,7 @@ func file_accessgraph_v1alpha_access_graph_service_proto_rawDescGZIP() []byte { return file_accessgraph_v1alpha_access_graph_service_proto_rawDescData } -var file_accessgraph_v1alpha_access_graph_service_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_accessgraph_v1alpha_access_graph_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_accessgraph_v1alpha_access_graph_service_proto_goTypes = []any{ (*QueryRequest)(nil), // 0: accessgraph.v1alpha.QueryRequest (*QueryResponse)(nil), // 1: accessgraph.v1alpha.QueryResponse @@ -1853,72 +2058,81 @@ var file_accessgraph_v1alpha_access_graph_service_proto_goTypes = []any{ (*AzureEventsStreamRequest)(nil), // 21: accessgraph.v1alpha.AzureEventsStreamRequest (*AzureSyncOperation)(nil), // 22: accessgraph.v1alpha.AzureSyncOperation (*AzureEventsStreamResponse)(nil), // 23: accessgraph.v1alpha.AzureEventsStreamResponse - (*Node)(nil), // 24: accessgraph.v1alpha.Node - (*Edge)(nil), // 25: accessgraph.v1alpha.Edge - (*ResourceList)(nil), // 26: accessgraph.v1alpha.ResourceList - (*ResourceHeaderList)(nil), // 27: accessgraph.v1alpha.ResourceHeaderList - (*AccessListsMembers)(nil), // 28: accessgraph.v1alpha.AccessListsMembers - (*ExcludeAccessListsMembers)(nil), // 29: accessgraph.v1alpha.ExcludeAccessListsMembers - (*AccessPathChanged)(nil), // 30: accessgraph.v1alpha.AccessPathChanged - (*AWSResourceList)(nil), // 31: accessgraph.v1alpha.AWSResourceList - (*GitlabSyncOperation)(nil), // 32: accessgraph.v1alpha.GitlabSyncOperation - (*GitlabResourceList)(nil), // 33: accessgraph.v1alpha.GitlabResourceList - (*EntraSyncOperation)(nil), // 34: accessgraph.v1alpha.EntraSyncOperation - (*EntraResourceList)(nil), // 35: accessgraph.v1alpha.EntraResourceList - (*AzureResourceList)(nil), // 36: accessgraph.v1alpha.AzureResourceList + (*NetIQEventsStreamRequest)(nil), // 24: accessgraph.v1alpha.NetIQEventsStreamRequest + (*NetIQSyncOperation)(nil), // 25: accessgraph.v1alpha.NetIQSyncOperation + (*NetIQEventsStreamResponse)(nil), // 26: accessgraph.v1alpha.NetIQEventsStreamResponse + (*Node)(nil), // 27: accessgraph.v1alpha.Node + (*Edge)(nil), // 28: accessgraph.v1alpha.Edge + (*ResourceList)(nil), // 29: accessgraph.v1alpha.ResourceList + (*ResourceHeaderList)(nil), // 30: accessgraph.v1alpha.ResourceHeaderList + (*AccessListsMembers)(nil), // 31: accessgraph.v1alpha.AccessListsMembers + (*ExcludeAccessListsMembers)(nil), // 32: accessgraph.v1alpha.ExcludeAccessListsMembers + (*AccessPathChanged)(nil), // 33: accessgraph.v1alpha.AccessPathChanged + (*AWSResourceList)(nil), // 34: accessgraph.v1alpha.AWSResourceList + (*GitlabSyncOperation)(nil), // 35: accessgraph.v1alpha.GitlabSyncOperation + (*GitlabResourceList)(nil), // 36: accessgraph.v1alpha.GitlabResourceList + (*EntraSyncOperation)(nil), // 37: accessgraph.v1alpha.EntraSyncOperation + (*EntraResourceList)(nil), // 38: accessgraph.v1alpha.EntraResourceList + (*AzureResourceList)(nil), // 39: accessgraph.v1alpha.AzureResourceList + (*NetIQResourceList)(nil), // 40: accessgraph.v1alpha.NetIQResourceList } var file_accessgraph_v1alpha_access_graph_service_proto_depIdxs = []int32{ - 24, // 0: accessgraph.v1alpha.QueryResponse.nodes:type_name -> accessgraph.v1alpha.Node - 25, // 1: accessgraph.v1alpha.QueryResponse.edges:type_name -> accessgraph.v1alpha.Edge + 27, // 0: accessgraph.v1alpha.QueryResponse.nodes:type_name -> accessgraph.v1alpha.Node + 28, // 1: accessgraph.v1alpha.QueryResponse.edges:type_name -> accessgraph.v1alpha.Edge 6, // 2: accessgraph.v1alpha.EventsStreamRequest.sync:type_name -> accessgraph.v1alpha.SyncOperation - 26, // 3: accessgraph.v1alpha.EventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.ResourceList - 27, // 4: accessgraph.v1alpha.EventsStreamRequest.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList - 28, // 5: accessgraph.v1alpha.EventsStreamRequest.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers - 29, // 6: accessgraph.v1alpha.EventsStreamRequest.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers + 29, // 3: accessgraph.v1alpha.EventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.ResourceList + 30, // 4: accessgraph.v1alpha.EventsStreamRequest.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList + 31, // 5: accessgraph.v1alpha.EventsStreamRequest.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers + 32, // 6: accessgraph.v1alpha.EventsStreamRequest.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers 6, // 7: accessgraph.v1alpha.EventsStreamV2Request.sync:type_name -> accessgraph.v1alpha.SyncOperation - 26, // 8: accessgraph.v1alpha.EventsStreamV2Request.upsert:type_name -> accessgraph.v1alpha.ResourceList - 27, // 9: accessgraph.v1alpha.EventsStreamV2Request.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList - 28, // 10: accessgraph.v1alpha.EventsStreamV2Request.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers - 29, // 11: accessgraph.v1alpha.EventsStreamV2Request.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers + 29, // 8: accessgraph.v1alpha.EventsStreamV2Request.upsert:type_name -> accessgraph.v1alpha.ResourceList + 30, // 9: accessgraph.v1alpha.EventsStreamV2Request.delete:type_name -> accessgraph.v1alpha.ResourceHeaderList + 31, // 10: accessgraph.v1alpha.EventsStreamV2Request.access_lists_members:type_name -> accessgraph.v1alpha.AccessListsMembers + 32, // 11: accessgraph.v1alpha.EventsStreamV2Request.exclude_access_list_members:type_name -> accessgraph.v1alpha.ExcludeAccessListsMembers 9, // 12: accessgraph.v1alpha.EventsStreamV2Response.event:type_name -> accessgraph.v1alpha.AuditEvent - 30, // 13: accessgraph.v1alpha.AuditEvent.access_path_changed:type_name -> accessgraph.v1alpha.AccessPathChanged + 33, // 13: accessgraph.v1alpha.AuditEvent.access_path_changed:type_name -> accessgraph.v1alpha.AccessPathChanged 15, // 14: accessgraph.v1alpha.AWSEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.AWSSyncOperation - 31, // 15: accessgraph.v1alpha.AWSEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AWSResourceList - 31, // 16: accessgraph.v1alpha.AWSEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AWSResourceList - 32, // 17: accessgraph.v1alpha.GitlabEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.GitlabSyncOperation - 33, // 18: accessgraph.v1alpha.GitlabEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.GitlabResourceList - 33, // 19: accessgraph.v1alpha.GitlabEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.GitlabResourceList - 34, // 20: accessgraph.v1alpha.EntraEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.EntraSyncOperation - 35, // 21: accessgraph.v1alpha.EntraEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.EntraResourceList - 35, // 22: accessgraph.v1alpha.EntraEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.EntraResourceList + 34, // 15: accessgraph.v1alpha.AWSEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AWSResourceList + 34, // 16: accessgraph.v1alpha.AWSEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AWSResourceList + 35, // 17: accessgraph.v1alpha.GitlabEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.GitlabSyncOperation + 36, // 18: accessgraph.v1alpha.GitlabEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.GitlabResourceList + 36, // 19: accessgraph.v1alpha.GitlabEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.GitlabResourceList + 37, // 20: accessgraph.v1alpha.EntraEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.EntraSyncOperation + 38, // 21: accessgraph.v1alpha.EntraEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.EntraResourceList + 38, // 22: accessgraph.v1alpha.EntraEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.EntraResourceList 22, // 23: accessgraph.v1alpha.AzureEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.AzureSyncOperation - 36, // 24: accessgraph.v1alpha.AzureEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AzureResourceList - 36, // 25: accessgraph.v1alpha.AzureEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AzureResourceList - 0, // 26: accessgraph.v1alpha.AccessGraphService.Query:input_type -> accessgraph.v1alpha.QueryRequest - 2, // 27: accessgraph.v1alpha.AccessGraphService.GetFile:input_type -> accessgraph.v1alpha.GetFileRequest - 4, // 28: accessgraph.v1alpha.AccessGraphService.EventsStream:input_type -> accessgraph.v1alpha.EventsStreamRequest - 5, // 29: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:input_type -> accessgraph.v1alpha.EventsStreamV2Request - 10, // 30: accessgraph.v1alpha.AccessGraphService.Register:input_type -> accessgraph.v1alpha.RegisterRequest - 12, // 31: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:input_type -> accessgraph.v1alpha.ReplaceCAsRequest - 14, // 32: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:input_type -> accessgraph.v1alpha.AWSEventsStreamRequest - 17, // 33: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:input_type -> accessgraph.v1alpha.GitlabEventsStreamRequest - 19, // 34: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:input_type -> accessgraph.v1alpha.EntraEventsStreamRequest - 21, // 35: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:input_type -> accessgraph.v1alpha.AzureEventsStreamRequest - 1, // 36: accessgraph.v1alpha.AccessGraphService.Query:output_type -> accessgraph.v1alpha.QueryResponse - 3, // 37: accessgraph.v1alpha.AccessGraphService.GetFile:output_type -> accessgraph.v1alpha.GetFileResponse - 7, // 38: accessgraph.v1alpha.AccessGraphService.EventsStream:output_type -> accessgraph.v1alpha.EventsStreamResponse - 8, // 39: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:output_type -> accessgraph.v1alpha.EventsStreamV2Response - 11, // 40: accessgraph.v1alpha.AccessGraphService.Register:output_type -> accessgraph.v1alpha.RegisterResponse - 13, // 41: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:output_type -> accessgraph.v1alpha.ReplaceCAsResponse - 16, // 42: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:output_type -> accessgraph.v1alpha.AWSEventsStreamResponse - 18, // 43: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:output_type -> accessgraph.v1alpha.GitlabEventsStreamResponse - 20, // 44: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:output_type -> accessgraph.v1alpha.EntraEventsStreamResponse - 23, // 45: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:output_type -> accessgraph.v1alpha.AzureEventsStreamResponse - 36, // [36:46] is the sub-list for method output_type - 26, // [26:36] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 39, // 24: accessgraph.v1alpha.AzureEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.AzureResourceList + 39, // 25: accessgraph.v1alpha.AzureEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.AzureResourceList + 25, // 26: accessgraph.v1alpha.NetIQEventsStreamRequest.sync:type_name -> accessgraph.v1alpha.NetIQSyncOperation + 40, // 27: accessgraph.v1alpha.NetIQEventsStreamRequest.upsert:type_name -> accessgraph.v1alpha.NetIQResourceList + 40, // 28: accessgraph.v1alpha.NetIQEventsStreamRequest.delete:type_name -> accessgraph.v1alpha.NetIQResourceList + 0, // 29: accessgraph.v1alpha.AccessGraphService.Query:input_type -> accessgraph.v1alpha.QueryRequest + 2, // 30: accessgraph.v1alpha.AccessGraphService.GetFile:input_type -> accessgraph.v1alpha.GetFileRequest + 4, // 31: accessgraph.v1alpha.AccessGraphService.EventsStream:input_type -> accessgraph.v1alpha.EventsStreamRequest + 5, // 32: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:input_type -> accessgraph.v1alpha.EventsStreamV2Request + 10, // 33: accessgraph.v1alpha.AccessGraphService.Register:input_type -> accessgraph.v1alpha.RegisterRequest + 12, // 34: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:input_type -> accessgraph.v1alpha.ReplaceCAsRequest + 14, // 35: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:input_type -> accessgraph.v1alpha.AWSEventsStreamRequest + 17, // 36: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:input_type -> accessgraph.v1alpha.GitlabEventsStreamRequest + 19, // 37: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:input_type -> accessgraph.v1alpha.EntraEventsStreamRequest + 21, // 38: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:input_type -> accessgraph.v1alpha.AzureEventsStreamRequest + 24, // 39: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:input_type -> accessgraph.v1alpha.NetIQEventsStreamRequest + 1, // 40: accessgraph.v1alpha.AccessGraphService.Query:output_type -> accessgraph.v1alpha.QueryResponse + 3, // 41: accessgraph.v1alpha.AccessGraphService.GetFile:output_type -> accessgraph.v1alpha.GetFileResponse + 7, // 42: accessgraph.v1alpha.AccessGraphService.EventsStream:output_type -> accessgraph.v1alpha.EventsStreamResponse + 8, // 43: accessgraph.v1alpha.AccessGraphService.EventsStreamV2:output_type -> accessgraph.v1alpha.EventsStreamV2Response + 11, // 44: accessgraph.v1alpha.AccessGraphService.Register:output_type -> accessgraph.v1alpha.RegisterResponse + 13, // 45: accessgraph.v1alpha.AccessGraphService.ReplaceCAs:output_type -> accessgraph.v1alpha.ReplaceCAsResponse + 16, // 46: accessgraph.v1alpha.AccessGraphService.AWSEventsStream:output_type -> accessgraph.v1alpha.AWSEventsStreamResponse + 18, // 47: accessgraph.v1alpha.AccessGraphService.GitlabEventsStream:output_type -> accessgraph.v1alpha.GitlabEventsStreamResponse + 20, // 48: accessgraph.v1alpha.AccessGraphService.EntraEventsStream:output_type -> accessgraph.v1alpha.EntraEventsStreamResponse + 23, // 49: accessgraph.v1alpha.AccessGraphService.AzureEventsStream:output_type -> accessgraph.v1alpha.AzureEventsStreamResponse + 26, // 50: accessgraph.v1alpha.AccessGraphService.NetIQEventsStream:output_type -> accessgraph.v1alpha.NetIQEventsStreamResponse + 40, // [40:51] is the sub-list for method output_type + 29, // [29:40] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_accessgraph_v1alpha_access_graph_service_proto_init() } @@ -1932,6 +2146,7 @@ func file_accessgraph_v1alpha_access_graph_service_proto_init() { file_accessgraph_v1alpha_events_proto_init() file_accessgraph_v1alpha_gitlab_proto_init() file_accessgraph_v1alpha_graph_proto_init() + file_accessgraph_v1alpha_netiq_proto_init() file_accessgraph_v1alpha_resources_proto_init() file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[4].OneofWrappers = []any{ (*EventsStreamRequest_Sync)(nil), @@ -1973,13 +2188,18 @@ func file_accessgraph_v1alpha_access_graph_service_proto_init() { (*AzureEventsStreamRequest_Upsert)(nil), (*AzureEventsStreamRequest_Delete)(nil), } + file_accessgraph_v1alpha_access_graph_service_proto_msgTypes[24].OneofWrappers = []any{ + (*NetIQEventsStreamRequest_Sync)(nil), + (*NetIQEventsStreamRequest_Upsert)(nil), + (*NetIQEventsStreamRequest_Delete)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_accessgraph_v1alpha_access_graph_service_proto_rawDesc, NumEnums: 0, - NumMessages: 24, + NumMessages: 27, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go b/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go index 7bc14a2bb03e0..db84b95c72f89 100644 --- a/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/access_graph_service_grpc.pb.go @@ -46,6 +46,7 @@ const ( AccessGraphService_GitlabEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/GitlabEventsStream" AccessGraphService_EntraEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/EntraEventsStream" AccessGraphService_AzureEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/AzureEventsStream" + AccessGraphService_NetIQEventsStream_FullMethodName = "/accessgraph.v1alpha.AccessGraphService/NetIQEventsStream" ) // AccessGraphServiceClient is the client API for AccessGraphService service. @@ -95,6 +96,8 @@ type AccessGraphServiceClient interface { EntraEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[EntraEventsStreamRequest, EntraEventsStreamResponse], error) // AzureEventsStream is a stream of commands to the Azure importer AzureEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[AzureEventsStreamRequest, AzureEventsStreamResponse], error) + // NetIQEventsStream is a stream of commands to the NetIQ importer. + NetIQEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[NetIQEventsStreamRequest, NetIQEventsStreamResponse], error) } type accessGraphServiceClient struct { @@ -223,6 +226,19 @@ func (c *accessGraphServiceClient) AzureEventsStream(ctx context.Context, opts . // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type AccessGraphService_AzureEventsStreamClient = grpc.BidiStreamingClient[AzureEventsStreamRequest, AzureEventsStreamResponse] +func (c *accessGraphServiceClient) NetIQEventsStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[NetIQEventsStreamRequest, NetIQEventsStreamResponse], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &AccessGraphService_ServiceDesc.Streams[6], AccessGraphService_NetIQEventsStream_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[NetIQEventsStreamRequest, NetIQEventsStreamResponse]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type AccessGraphService_NetIQEventsStreamClient = grpc.BidiStreamingClient[NetIQEventsStreamRequest, NetIQEventsStreamResponse] + // AccessGraphServiceServer is the server API for AccessGraphService service. // All implementations must embed UnimplementedAccessGraphServiceServer // for forward compatibility. @@ -270,6 +286,8 @@ type AccessGraphServiceServer interface { EntraEventsStream(grpc.BidiStreamingServer[EntraEventsStreamRequest, EntraEventsStreamResponse]) error // AzureEventsStream is a stream of commands to the Azure importer AzureEventsStream(grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse]) error + // NetIQEventsStream is a stream of commands to the NetIQ importer. + NetIQEventsStream(grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse]) error mustEmbedUnimplementedAccessGraphServiceServer() } @@ -310,6 +328,9 @@ func (UnimplementedAccessGraphServiceServer) EntraEventsStream(grpc.BidiStreamin func (UnimplementedAccessGraphServiceServer) AzureEventsStream(grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse]) error { return status.Errorf(codes.Unimplemented, "method AzureEventsStream not implemented") } +func (UnimplementedAccessGraphServiceServer) NetIQEventsStream(grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse]) error { + return status.Errorf(codes.Unimplemented, "method NetIQEventsStream not implemented") +} func (UnimplementedAccessGraphServiceServer) mustEmbedUnimplementedAccessGraphServiceServer() {} func (UnimplementedAccessGraphServiceServer) testEmbeddedByValue() {} @@ -445,6 +466,13 @@ func _AccessGraphService_AzureEventsStream_Handler(srv interface{}, stream grpc. // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type AccessGraphService_AzureEventsStreamServer = grpc.BidiStreamingServer[AzureEventsStreamRequest, AzureEventsStreamResponse] +func _AccessGraphService_NetIQEventsStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(AccessGraphServiceServer).NetIQEventsStream(&grpc.GenericServerStream[NetIQEventsStreamRequest, NetIQEventsStreamResponse]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type AccessGraphService_NetIQEventsStreamServer = grpc.BidiStreamingServer[NetIQEventsStreamRequest, NetIQEventsStreamResponse] + // AccessGraphService_ServiceDesc is the grpc.ServiceDesc for AccessGraphService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -504,6 +532,12 @@ var AccessGraphService_ServiceDesc = grpc.ServiceDesc{ ServerStreams: true, ClientStreams: true, }, + { + StreamName: "NetIQEventsStream", + Handler: _AccessGraphService_NetIQEventsStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, }, Metadata: "accessgraph/v1alpha/access_graph_service.proto", } diff --git a/gen/proto/go/accessgraph/v1alpha/aws.pb.go b/gen/proto/go/accessgraph/v1alpha/aws.pb.go index cad4fa81e9895..3a4f1065253e3 100644 --- a/gen/proto/go/accessgraph/v1alpha/aws.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/aws.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/aws.proto diff --git a/gen/proto/go/accessgraph/v1alpha/azure.pb.go b/gen/proto/go/accessgraph/v1alpha/azure.pb.go index e2f78bee99f2a..b7ea6443a8964 100644 --- a/gen/proto/go/accessgraph/v1alpha/azure.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/azure.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/azure.proto diff --git a/gen/proto/go/accessgraph/v1alpha/entra.pb.go b/gen/proto/go/accessgraph/v1alpha/entra.pb.go index d40698a29a134..5617e3154135c 100644 --- a/gen/proto/go/accessgraph/v1alpha/entra.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/entra.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/entra.proto diff --git a/gen/proto/go/accessgraph/v1alpha/events.pb.go b/gen/proto/go/accessgraph/v1alpha/events.pb.go index bc7569f3fb422..fd30d09ff450b 100644 --- a/gen/proto/go/accessgraph/v1alpha/events.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/events.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/events.proto diff --git a/gen/proto/go/accessgraph/v1alpha/gitlab.pb.go b/gen/proto/go/accessgraph/v1alpha/gitlab.pb.go index 7806c7a9b599e..23b3e914240dc 100644 --- a/gen/proto/go/accessgraph/v1alpha/gitlab.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/gitlab.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/gitlab.proto diff --git a/gen/proto/go/accessgraph/v1alpha/graph.pb.go b/gen/proto/go/accessgraph/v1alpha/graph.pb.go index 14834899a5610..066df973254e9 100644 --- a/gen/proto/go/accessgraph/v1alpha/graph.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/graph.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/graph.proto diff --git a/gen/proto/go/accessgraph/v1alpha/netiq.pb.go b/gen/proto/go/accessgraph/v1alpha/netiq.pb.go new file mode 100644 index 0000000000000..e39260c159875 --- /dev/null +++ b/gen/proto/go/accessgraph/v1alpha/netiq.pb.go @@ -0,0 +1,1328 @@ +// +// 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 . + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.1 +// protoc (unknown) +// source: accessgraph/v1alpha/netiq.proto + +package accessgraphv1alpha + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// RoleRecipientType is the type of the recipient. +type RoleRecipientType int32 + +const ( + // ROLE_RECIPIENT_TYPE_UNSPECIFIED is a unspecified role recipient type. + RoleRecipientType_ROLE_RECIPIENT_TYPE_UNSPECIFIED RoleRecipientType = 0 + // ROLE_RECIPIENT_TYPE_USER represents a user being member of a role. + RoleRecipientType_ROLE_RECIPIENT_TYPE_USER RoleRecipientType = 1 + // ROLE_RECIPIENT_TYPE_GROUP represents a group being member of a role. + RoleRecipientType_ROLE_RECIPIENT_TYPE_GROUP RoleRecipientType = 2 +) + +// Enum value maps for RoleRecipientType. +var ( + RoleRecipientType_name = map[int32]string{ + 0: "ROLE_RECIPIENT_TYPE_UNSPECIFIED", + 1: "ROLE_RECIPIENT_TYPE_USER", + 2: "ROLE_RECIPIENT_TYPE_GROUP", + } + RoleRecipientType_value = map[string]int32{ + "ROLE_RECIPIENT_TYPE_UNSPECIFIED": 0, + "ROLE_RECIPIENT_TYPE_USER": 1, + "ROLE_RECIPIENT_TYPE_GROUP": 2, + } +) + +func (x RoleRecipientType) Enum() *RoleRecipientType { + p := new(RoleRecipientType) + *p = x + return p +} + +func (x RoleRecipientType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RoleRecipientType) Descriptor() protoreflect.EnumDescriptor { + return file_accessgraph_v1alpha_netiq_proto_enumTypes[0].Descriptor() +} + +func (RoleRecipientType) Type() protoreflect.EnumType { + return &file_accessgraph_v1alpha_netiq_proto_enumTypes[0] +} + +func (x RoleRecipientType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RoleRecipientType.Descriptor instead. +func (RoleRecipientType) EnumDescriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{0} +} + +// NetIQResourceList is a request that contains resources to be sync. +type NetIQResourceList struct { + state protoimpl.MessageState `protogen:"open.v1"` + // resources is a list of NetIQ resources to sync. + Resources []*NetIQObject `protobuf:"bytes,1,rep,name=resources,proto3" json:"resources,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQResourceList) Reset() { + *x = NetIQResourceList{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQResourceList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQResourceList) ProtoMessage() {} + +func (x *NetIQResourceList) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[0] + 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 NetIQResourceList.ProtoReflect.Descriptor instead. +func (*NetIQResourceList) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{0} +} + +func (x *NetIQResourceList) GetResources() []*NetIQObject { + if x != nil { + return x.Resources + } + return nil +} + +// NetIQObject represents a NetIQ resource +type NetIQObject struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Object: + // + // *NetIQObject_Group + // *NetIQObject_GroupMember + // *NetIQObject_Resource + // *NetIQObject_Role + // *NetIQObject_ParentRoleRef + // *NetIQObject_User + // *NetIQObject_ResourceRoleRef + // *NetIQObject_RoleMemberRef + Object isNetIQObject_Object `protobuf_oneof:"object"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQObject) Reset() { + *x = NetIQObject{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQObject) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQObject) ProtoMessage() {} + +func (x *NetIQObject) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[1] + 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 NetIQObject.ProtoReflect.Descriptor instead. +func (*NetIQObject) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{1} +} + +func (x *NetIQObject) GetObject() isNetIQObject_Object { + if x != nil { + return x.Object + } + return nil +} + +func (x *NetIQObject) GetGroup() *NetIQGroup { + if x != nil { + if x, ok := x.Object.(*NetIQObject_Group); ok { + return x.Group + } + } + return nil +} + +func (x *NetIQObject) GetGroupMember() *NetIQGroupMember { + if x != nil { + if x, ok := x.Object.(*NetIQObject_GroupMember); ok { + return x.GroupMember + } + } + return nil +} + +func (x *NetIQObject) GetResource() *NetIQResource { + if x != nil { + if x, ok := x.Object.(*NetIQObject_Resource); ok { + return x.Resource + } + } + return nil +} + +func (x *NetIQObject) GetRole() *NetIQRole { + if x != nil { + if x, ok := x.Object.(*NetIQObject_Role); ok { + return x.Role + } + } + return nil +} + +func (x *NetIQObject) GetParentRoleRef() *NetIQRoleRef { + if x != nil { + if x, ok := x.Object.(*NetIQObject_ParentRoleRef); ok { + return x.ParentRoleRef + } + } + return nil +} + +func (x *NetIQObject) GetUser() *NetIQUser { + if x != nil { + if x, ok := x.Object.(*NetIQObject_User); ok { + return x.User + } + } + return nil +} + +func (x *NetIQObject) GetResourceRoleRef() *NetIQResourceAssignmentRef { + if x != nil { + if x, ok := x.Object.(*NetIQObject_ResourceRoleRef); ok { + return x.ResourceRoleRef + } + } + return nil +} + +func (x *NetIQObject) GetRoleMemberRef() *NetIQMemberAssignmentRef { + if x != nil { + if x, ok := x.Object.(*NetIQObject_RoleMemberRef); ok { + return x.RoleMemberRef + } + } + return nil +} + +type isNetIQObject_Object interface { + isNetIQObject_Object() +} + +type NetIQObject_Group struct { + // group represents a NetIQ group in an organization. + Group *NetIQGroup `protobuf:"bytes,1,opt,name=group,proto3,oneof"` +} + +type NetIQObject_GroupMember struct { + // group_member represents a NetIQ group member. + GroupMember *NetIQGroupMember `protobuf:"bytes,2,opt,name=group_member,json=groupMember,proto3,oneof"` +} + +type NetIQObject_Resource struct { + // resource represents a NetIQ resource. + Resource *NetIQResource `protobuf:"bytes,3,opt,name=resource,proto3,oneof"` +} + +type NetIQObject_Role struct { + // role represents a role with certain access levels to a resource. + Role *NetIQRole `protobuf:"bytes,4,opt,name=role,proto3,oneof"` +} + +type NetIQObject_ParentRoleRef struct { + // parent_role_ref represents a parent relationship between roles. + ParentRoleRef *NetIQRoleRef `protobuf:"bytes,5,opt,name=parent_role_ref,json=parentRoleRef,proto3,oneof"` +} + +type NetIQObject_User struct { + // user represents a NetIQ user. + User *NetIQUser `protobuf:"bytes,6,opt,name=user,proto3,oneof"` +} + +type NetIQObject_ResourceRoleRef struct { + // resource_role_ref represents a resource assignment to a role. + ResourceRoleRef *NetIQResourceAssignmentRef `protobuf:"bytes,7,opt,name=resource_role_ref,json=resourceRoleRef,proto3,oneof"` +} + +type NetIQObject_RoleMemberRef struct { + // role_member_ref represents a member being member of a role. + RoleMemberRef *NetIQMemberAssignmentRef `protobuf:"bytes,8,opt,name=role_member_ref,json=roleMemberRef,proto3,oneof"` +} + +func (*NetIQObject_Group) isNetIQObject_Object() {} + +func (*NetIQObject_GroupMember) isNetIQObject_Object() {} + +func (*NetIQObject_Resource) isNetIQObject_Object() {} + +func (*NetIQObject_Role) isNetIQObject_Object() {} + +func (*NetIQObject_ParentRoleRef) isNetIQObject_Object() {} + +func (*NetIQObject_User) isNetIQObject_Object() {} + +func (*NetIQObject_ResourceRoleRef) isNetIQObject_Object() {} + +func (*NetIQObject_RoleMemberRef) isNetIQObject_Object() {} + +// NetIQGroup represents a NetIQ group +type NetIQGroup struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name is the group name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // id is the universal identifier for the group. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // description is the group description. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQGroup) Reset() { + *x = NetIQGroup{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQGroup) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQGroup) ProtoMessage() {} + +func (x *NetIQGroup) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[2] + 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 NetIQGroup.ProtoReflect.Descriptor instead. +func (*NetIQGroup) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{2} +} + +func (x *NetIQGroup) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQGroup) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *NetIQGroup) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +// NetIQGroupMember represents a NetIQ group member +type NetIQGroupMember struct { + state protoimpl.MessageState `protogen:"open.v1"` + // group_id is the group id. + GroupId string `protobuf:"bytes,1,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + // user_id is the universal identifier for the user. + UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + // is_group_assignment is a flag that determines whether the member is a group assignment. + IsGroupAssignment bool `protobuf:"varint,3,opt,name=is_group_assignment,json=isGroupAssignment,proto3" json:"is_group_assignment,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQGroupMember) Reset() { + *x = NetIQGroupMember{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQGroupMember) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQGroupMember) ProtoMessage() {} + +func (x *NetIQGroupMember) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[3] + 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 NetIQGroupMember.ProtoReflect.Descriptor instead. +func (*NetIQGroupMember) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{3} +} + +func (x *NetIQGroupMember) GetGroupId() string { + if x != nil { + return x.GroupId + } + return "" +} + +func (x *NetIQGroupMember) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *NetIQGroupMember) GetIsGroupAssignment() bool { + if x != nil { + return x.IsGroupAssignment + } + return false +} + +// NetIQResource represents a NetIQ resource +type NetIQResource struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name is the resource name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // id is the universal identifier for the resource. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // description is the project description. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // categories is the list of categories the resource belongs to. + Categories []*NetIQCategory `protobuf:"bytes,4,rep,name=categories,proto3" json:"categories,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQResource) Reset() { + *x = NetIQResource{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQResource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQResource) ProtoMessage() {} + +func (x *NetIQResource) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[4] + 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 NetIQResource.ProtoReflect.Descriptor instead. +func (*NetIQResource) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{4} +} + +func (x *NetIQResource) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQResource) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *NetIQResource) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *NetIQResource) GetCategories() []*NetIQCategory { + if x != nil { + return x.Categories + } + return nil +} + +// NetIQCategory is a resource category. +type NetIQCategory struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name is the resource name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // id is the universal identifier for the category. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQCategory) Reset() { + *x = NetIQCategory{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQCategory) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQCategory) ProtoMessage() {} + +func (x *NetIQCategory) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[5] + 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 NetIQCategory.ProtoReflect.Descriptor instead. +func (*NetIQCategory) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{5} +} + +func (x *NetIQCategory) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQCategory) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +// NetIQRole represents a NetIQ role +type NetIQRole struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name is the resource name. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // id is the universal identifier for the role. + Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` + // description is the project description. + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + // categories is the list of categories the resource belongs to. + Categories []*NetIQCategory `protobuf:"bytes,4,rep,name=categories,proto3" json:"categories,omitempty"` + Level *NetIQRole_RoleLevel `protobuf:"bytes,5,opt,name=level,proto3" json:"level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQRole) Reset() { + *x = NetIQRole{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQRole) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQRole) ProtoMessage() {} + +func (x *NetIQRole) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[6] + 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 NetIQRole.ProtoReflect.Descriptor instead. +func (*NetIQRole) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{6} +} + +func (x *NetIQRole) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQRole) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *NetIQRole) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *NetIQRole) GetCategories() []*NetIQCategory { + if x != nil { + return x.Categories + } + return nil +} + +func (x *NetIQRole) GetLevel() *NetIQRole_RoleLevel { + if x != nil { + return x.Level + } + return nil +} + +// NetIQRoleRef represents a NetIQ Role reference. +type NetIQRoleRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // child_role_id is the group id of a role that is a child role of parent_role_id. + ChildRoleId string `protobuf:"bytes,1,opt,name=child_role_id,json=childRoleId,proto3" json:"child_role_id,omitempty"` + // parent_role_id is the universal identifier for the role that is parent to child_role_id. + ParentRoleId string `protobuf:"bytes,2,opt,name=parent_role_id,json=parentRoleId,proto3" json:"parent_role_id,omitempty"` + // level is the level of the role. + Level int32 `protobuf:"varint,3,opt,name=level,proto3" json:"level,omitempty"` + // request_description is the description of the request. + RequestDescription string `protobuf:"bytes,4,opt,name=request_description,json=requestDescription,proto3" json:"request_description,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQRoleRef) Reset() { + *x = NetIQRoleRef{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQRoleRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQRoleRef) ProtoMessage() {} + +func (x *NetIQRoleRef) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[7] + 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 NetIQRoleRef.ProtoReflect.Descriptor instead. +func (*NetIQRoleRef) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{7} +} + +func (x *NetIQRoleRef) GetChildRoleId() string { + if x != nil { + return x.ChildRoleId + } + return "" +} + +func (x *NetIQRoleRef) GetParentRoleId() string { + if x != nil { + return x.ParentRoleId + } + return "" +} + +func (x *NetIQRoleRef) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *NetIQRoleRef) GetRequestDescription() string { + if x != nil { + return x.RequestDescription + } + return "" +} + +// NetIQUser represents a NetIQ user. +type NetIQUser struct { + state protoimpl.MessageState `protogen:"open.v1"` + // id is the id of the user. + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // email is the user's email. + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + // name is the user's name. + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // is_disabled indicates if a user is disabled. + IsDisabled bool `protobuf:"varint,4,opt,name=is_disabled,json=isDisabled,proto3" json:"is_disabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQUser) Reset() { + *x = NetIQUser{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQUser) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQUser) ProtoMessage() {} + +func (x *NetIQUser) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[8] + 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 NetIQUser.ProtoReflect.Descriptor instead. +func (*NetIQUser) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{8} +} + +func (x *NetIQUser) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *NetIQUser) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + +func (x *NetIQUser) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQUser) GetIsDisabled() bool { + if x != nil { + return x.IsDisabled + } + return false +} + +// NetIQResourceAssignmentRef represents a NetIQ resource assignment reference. +type NetIQResourceAssignmentRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // role_id is the group id of a role that is assigned to resource_id. + RoleId string `protobuf:"bytes,1,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty"` + // resource_id is the universal identifier for the resource that is assigned to role_id. + ResourceId string `protobuf:"bytes,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"` + // mapping_description is the description of the mapping. + MappingDescription string `protobuf:"bytes,4,opt,name=mapping_description,json=mappingDescription,proto3" json:"mapping_description,omitempty"` + // status_code is the status code of the role assignment. + StatusCode uint32 `protobuf:"varint,5,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQResourceAssignmentRef) Reset() { + *x = NetIQResourceAssignmentRef{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQResourceAssignmentRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQResourceAssignmentRef) ProtoMessage() {} + +func (x *NetIQResourceAssignmentRef) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[9] + 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 NetIQResourceAssignmentRef.ProtoReflect.Descriptor instead. +func (*NetIQResourceAssignmentRef) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{9} +} + +func (x *NetIQResourceAssignmentRef) GetRoleId() string { + if x != nil { + return x.RoleId + } + return "" +} + +func (x *NetIQResourceAssignmentRef) GetResourceId() string { + if x != nil { + return x.ResourceId + } + return "" +} + +func (x *NetIQResourceAssignmentRef) GetMappingDescription() string { + if x != nil { + return x.MappingDescription + } + return "" +} + +func (x *NetIQResourceAssignmentRef) GetStatusCode() uint32 { + if x != nil { + return x.StatusCode + } + return 0 +} + +// NetIQMemberAssignmentRef represents a NetIQ resource assignment reference. +type NetIQMemberAssignmentRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // role_id is the group id of a role that user_id is member of. + RoleId string `protobuf:"bytes,1,opt,name=role_id,json=roleId,proto3" json:"role_id,omitempty"` + // dn is the universal identifier for the user that is member of role_id. + Dn string `protobuf:"bytes,2,opt,name=dn,proto3" json:"dn,omitempty"` + // recipient_type identifies the recipient provenance. + RecipientType RoleRecipientType `protobuf:"varint,3,opt,name=recipient_type,json=recipientType,proto3,enum=accessgraph.v1alpha.RoleRecipientType" json:"recipient_type,omitempty"` + // recipient_type_subcontainer is the sub container of the recipient type. + RecipientTypeSubcontainer string `protobuf:"bytes,4,opt,name=recipient_type_subcontainer,json=recipientTypeSubcontainer,proto3" json:"recipient_type_subcontainer,omitempty"` + // status_code is the status code of the role assignment. + StatusCode uint32 `protobuf:"varint,5,opt,name=status_code,json=statusCode,proto3" json:"status_code,omitempty"` + // StatusDstatus_displayisplay is the display of the status. + StatusDisplay string `protobuf:"bytes,6,opt,name=status_display,json=statusDisplay,proto3" json:"status_display,omitempty"` + // effective_date is the effective date of the role assignment. + EffectiveDate *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=effective_date,json=effectiveDate,proto3" json:"effective_date,omitempty"` + // expiry_date is the expiry date of the role assignment. + ExpiryDate *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=expiry_date,json=expiryDate,proto3" json:"expiry_date,omitempty"` + // description is the description of the role assignment. + Description string `protobuf:"bytes,9,opt,name=description,proto3" json:"description,omitempty"` + // grant is a flag that determines whether the role assignment is granted. + Grant bool `protobuf:"varint,10,opt,name=grant,proto3" json:"grant,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQMemberAssignmentRef) Reset() { + *x = NetIQMemberAssignmentRef{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQMemberAssignmentRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQMemberAssignmentRef) ProtoMessage() {} + +func (x *NetIQMemberAssignmentRef) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[10] + 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 NetIQMemberAssignmentRef.ProtoReflect.Descriptor instead. +func (*NetIQMemberAssignmentRef) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{10} +} + +func (x *NetIQMemberAssignmentRef) GetRoleId() string { + if x != nil { + return x.RoleId + } + return "" +} + +func (x *NetIQMemberAssignmentRef) GetDn() string { + if x != nil { + return x.Dn + } + return "" +} + +func (x *NetIQMemberAssignmentRef) GetRecipientType() RoleRecipientType { + if x != nil { + return x.RecipientType + } + return RoleRecipientType_ROLE_RECIPIENT_TYPE_UNSPECIFIED +} + +func (x *NetIQMemberAssignmentRef) GetRecipientTypeSubcontainer() string { + if x != nil { + return x.RecipientTypeSubcontainer + } + return "" +} + +func (x *NetIQMemberAssignmentRef) GetStatusCode() uint32 { + if x != nil { + return x.StatusCode + } + return 0 +} + +func (x *NetIQMemberAssignmentRef) GetStatusDisplay() string { + if x != nil { + return x.StatusDisplay + } + return "" +} + +func (x *NetIQMemberAssignmentRef) GetEffectiveDate() *timestamppb.Timestamp { + if x != nil { + return x.EffectiveDate + } + return nil +} + +func (x *NetIQMemberAssignmentRef) GetExpiryDate() *timestamppb.Timestamp { + if x != nil { + return x.ExpiryDate + } + return nil +} + +func (x *NetIQMemberAssignmentRef) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *NetIQMemberAssignmentRef) GetGrant() bool { + if x != nil { + return x.Grant + } + return false +} + +// RoleLevel represents the role level. +type NetIQRole_RoleLevel struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name is the name of the role level. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // level is the level of the role level. + Level int32 `protobuf:"varint,2,opt,name=level,proto3" json:"level,omitempty"` + // cn is the common name. + Cn string `protobuf:"bytes,3,opt,name=cn,proto3" json:"cn,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NetIQRole_RoleLevel) Reset() { + *x = NetIQRole_RoleLevel{} + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NetIQRole_RoleLevel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NetIQRole_RoleLevel) ProtoMessage() {} + +func (x *NetIQRole_RoleLevel) ProtoReflect() protoreflect.Message { + mi := &file_accessgraph_v1alpha_netiq_proto_msgTypes[11] + 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 NetIQRole_RoleLevel.ProtoReflect.Descriptor instead. +func (*NetIQRole_RoleLevel) Descriptor() ([]byte, []int) { + return file_accessgraph_v1alpha_netiq_proto_rawDescGZIP(), []int{6, 0} +} + +func (x *NetIQRole_RoleLevel) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NetIQRole_RoleLevel) GetLevel() int32 { + if x != nil { + return x.Level + } + return 0 +} + +func (x *NetIQRole_RoleLevel) GetCn() string { + if x != nil { + return x.Cn + } + return "" +} + +var File_accessgraph_v1alpha_netiq_proto protoreflect.FileDescriptor + +var file_accessgraph_v1alpha_netiq_proto_rawDesc = []byte{ + 0x0a, 0x1f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2f, 0x6e, 0x65, 0x74, 0x69, 0x71, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x13, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, + 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x53, 0x0a, 0x11, 0x4e, 0x65, 0x74, 0x49, 0x51, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x09, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x20, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, + 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0xcf, 0x04, 0x0a, + 0x0b, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x37, 0x0a, 0x05, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x48, 0x00, 0x52, 0x05, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x4a, 0x0a, 0x0c, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x6d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, + 0x65, 0x72, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x12, 0x40, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x6f, 0x6c, + 0x65, 0x48, 0x00, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x0f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x6f, + 0x6c, 0x65, 0x52, 0x65, 0x66, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, + 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x66, 0x12, 0x34, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, + 0x55, 0x73, 0x65, 0x72, 0x48, 0x00, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x5d, 0x0a, 0x11, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x72, 0x65, + 0x66, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, + 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x66, 0x12, 0x57, 0x0a, 0x0f, 0x72, + 0x6f, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x66, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x6f, 0x6c, 0x65, 0x4d, 0x65, 0x6d, 0x62, 0x65, + 0x72, 0x52, 0x65, 0x66, 0x42, 0x08, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x52, + 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x76, 0x0a, 0x10, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x49, + 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x69, 0x73, + 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x99, 0x01, 0x0a, 0x0d, 0x4e, + 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, + 0x49, 0x51, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x22, 0x33, 0x0a, 0x0d, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x43, + 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x9c, 0x02, 0x0a, 0x09, + 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x42, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x43, + 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x52, 0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x2e, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x6f, + 0x6c, 0x65, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x1a, 0x45, 0x0a, 0x09, 0x52, 0x6f, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x63, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x63, 0x6e, 0x22, 0x9f, 0x01, 0x0a, 0x0c, 0x4e, + 0x65, 0x74, 0x49, 0x51, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x66, 0x12, 0x22, 0x0a, 0x0d, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, + 0x24, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, + 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x2f, 0x0a, 0x13, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x09, + 0x4e, 0x65, 0x74, 0x49, 0x51, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, + 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x22, 0xa8, 0x01, 0x0a, 0x1a, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x66, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2f, 0x0a, + 0x13, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x22, + 0xd2, 0x03, 0x0a, 0x18, 0x4e, 0x65, 0x74, 0x49, 0x51, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x41, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x12, 0x17, 0x0a, 0x07, + 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x6f, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x64, 0x6e, 0x12, 0x4d, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, + 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2e, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x3e, 0x0a, 0x1b, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x73, 0x75, 0x62, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x72, 0x65, 0x63, 0x69, 0x70, + 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x53, 0x75, 0x62, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x41, 0x0a, 0x0e, + 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x07, + 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, 0x0d, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x61, 0x74, 0x65, 0x12, + 0x3b, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x44, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x2a, 0x75, 0x0a, 0x11, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x63, 0x69, + 0x70, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x4f, 0x4c, + 0x45, 0x5f, 0x52, 0x45, 0x43, 0x49, 0x50, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1c, + 0x0a, 0x18, 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x49, 0x50, 0x49, 0x45, 0x4e, 0x54, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, + 0x52, 0x4f, 0x4c, 0x45, 0x5f, 0x52, 0x45, 0x43, 0x49, 0x50, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x02, 0x42, 0x57, 0x5a, 0x55, 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, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x67, 0x72, 0x61, 0x70, 0x68, 0x76, 0x31, 0x61, + 0x6c, 0x70, 0x68, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_accessgraph_v1alpha_netiq_proto_rawDescOnce sync.Once + file_accessgraph_v1alpha_netiq_proto_rawDescData = file_accessgraph_v1alpha_netiq_proto_rawDesc +) + +func file_accessgraph_v1alpha_netiq_proto_rawDescGZIP() []byte { + file_accessgraph_v1alpha_netiq_proto_rawDescOnce.Do(func() { + file_accessgraph_v1alpha_netiq_proto_rawDescData = protoimpl.X.CompressGZIP(file_accessgraph_v1alpha_netiq_proto_rawDescData) + }) + return file_accessgraph_v1alpha_netiq_proto_rawDescData +} + +var file_accessgraph_v1alpha_netiq_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_accessgraph_v1alpha_netiq_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_accessgraph_v1alpha_netiq_proto_goTypes = []any{ + (RoleRecipientType)(0), // 0: accessgraph.v1alpha.RoleRecipientType + (*NetIQResourceList)(nil), // 1: accessgraph.v1alpha.NetIQResourceList + (*NetIQObject)(nil), // 2: accessgraph.v1alpha.NetIQObject + (*NetIQGroup)(nil), // 3: accessgraph.v1alpha.NetIQGroup + (*NetIQGroupMember)(nil), // 4: accessgraph.v1alpha.NetIQGroupMember + (*NetIQResource)(nil), // 5: accessgraph.v1alpha.NetIQResource + (*NetIQCategory)(nil), // 6: accessgraph.v1alpha.NetIQCategory + (*NetIQRole)(nil), // 7: accessgraph.v1alpha.NetIQRole + (*NetIQRoleRef)(nil), // 8: accessgraph.v1alpha.NetIQRoleRef + (*NetIQUser)(nil), // 9: accessgraph.v1alpha.NetIQUser + (*NetIQResourceAssignmentRef)(nil), // 10: accessgraph.v1alpha.NetIQResourceAssignmentRef + (*NetIQMemberAssignmentRef)(nil), // 11: accessgraph.v1alpha.NetIQMemberAssignmentRef + (*NetIQRole_RoleLevel)(nil), // 12: accessgraph.v1alpha.NetIQRole.RoleLevel + (*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp +} +var file_accessgraph_v1alpha_netiq_proto_depIdxs = []int32{ + 2, // 0: accessgraph.v1alpha.NetIQResourceList.resources:type_name -> accessgraph.v1alpha.NetIQObject + 3, // 1: accessgraph.v1alpha.NetIQObject.group:type_name -> accessgraph.v1alpha.NetIQGroup + 4, // 2: accessgraph.v1alpha.NetIQObject.group_member:type_name -> accessgraph.v1alpha.NetIQGroupMember + 5, // 3: accessgraph.v1alpha.NetIQObject.resource:type_name -> accessgraph.v1alpha.NetIQResource + 7, // 4: accessgraph.v1alpha.NetIQObject.role:type_name -> accessgraph.v1alpha.NetIQRole + 8, // 5: accessgraph.v1alpha.NetIQObject.parent_role_ref:type_name -> accessgraph.v1alpha.NetIQRoleRef + 9, // 6: accessgraph.v1alpha.NetIQObject.user:type_name -> accessgraph.v1alpha.NetIQUser + 10, // 7: accessgraph.v1alpha.NetIQObject.resource_role_ref:type_name -> accessgraph.v1alpha.NetIQResourceAssignmentRef + 11, // 8: accessgraph.v1alpha.NetIQObject.role_member_ref:type_name -> accessgraph.v1alpha.NetIQMemberAssignmentRef + 6, // 9: accessgraph.v1alpha.NetIQResource.categories:type_name -> accessgraph.v1alpha.NetIQCategory + 6, // 10: accessgraph.v1alpha.NetIQRole.categories:type_name -> accessgraph.v1alpha.NetIQCategory + 12, // 11: accessgraph.v1alpha.NetIQRole.level:type_name -> accessgraph.v1alpha.NetIQRole.RoleLevel + 0, // 12: accessgraph.v1alpha.NetIQMemberAssignmentRef.recipient_type:type_name -> accessgraph.v1alpha.RoleRecipientType + 13, // 13: accessgraph.v1alpha.NetIQMemberAssignmentRef.effective_date:type_name -> google.protobuf.Timestamp + 13, // 14: accessgraph.v1alpha.NetIQMemberAssignmentRef.expiry_date:type_name -> google.protobuf.Timestamp + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_accessgraph_v1alpha_netiq_proto_init() } +func file_accessgraph_v1alpha_netiq_proto_init() { + if File_accessgraph_v1alpha_netiq_proto != nil { + return + } + file_accessgraph_v1alpha_netiq_proto_msgTypes[1].OneofWrappers = []any{ + (*NetIQObject_Group)(nil), + (*NetIQObject_GroupMember)(nil), + (*NetIQObject_Resource)(nil), + (*NetIQObject_Role)(nil), + (*NetIQObject_ParentRoleRef)(nil), + (*NetIQObject_User)(nil), + (*NetIQObject_ResourceRoleRef)(nil), + (*NetIQObject_RoleMemberRef)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_accessgraph_v1alpha_netiq_proto_rawDesc, + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_accessgraph_v1alpha_netiq_proto_goTypes, + DependencyIndexes: file_accessgraph_v1alpha_netiq_proto_depIdxs, + EnumInfos: file_accessgraph_v1alpha_netiq_proto_enumTypes, + MessageInfos: file_accessgraph_v1alpha_netiq_proto_msgTypes, + }.Build() + File_accessgraph_v1alpha_netiq_proto = out.File + file_accessgraph_v1alpha_netiq_proto_rawDesc = nil + file_accessgraph_v1alpha_netiq_proto_goTypes = nil + file_accessgraph_v1alpha_netiq_proto_depIdxs = nil +} diff --git a/gen/proto/go/accessgraph/v1alpha/resources.pb.go b/gen/proto/go/accessgraph/v1alpha/resources.pb.go index 0e9776bc509d9..fe7e9a261e694 100644 --- a/gen/proto/go/accessgraph/v1alpha/resources.pb.go +++ b/gen/proto/go/accessgraph/v1alpha/resources.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: accessgraph/v1alpha/resources.proto diff --git a/gen/proto/go/prehog/v1/teleport.pb.go b/gen/proto/go/prehog/v1/teleport.pb.go index 9603c82dabfe7..7dfca32709ee9 100644 --- a/gen/proto/go/prehog/v1/teleport.pb.go +++ b/gen/proto/go/prehog/v1/teleport.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: prehog/v1/teleport.proto diff --git a/gen/proto/go/prehog/v1alpha/connect.pb.go b/gen/proto/go/prehog/v1alpha/connect.pb.go index 95f74db0e4a67..a86322f17adbc 100644 --- a/gen/proto/go/prehog/v1alpha/connect.pb.go +++ b/gen/proto/go/prehog/v1alpha/connect.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: prehog/v1alpha/connect.proto diff --git a/gen/proto/go/prehog/v1alpha/tbot.pb.go b/gen/proto/go/prehog/v1alpha/tbot.pb.go index 4855721797d81..654c1f2645217 100644 --- a/gen/proto/go/prehog/v1alpha/tbot.pb.go +++ b/gen/proto/go/prehog/v1alpha/tbot.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: prehog/v1alpha/tbot.proto diff --git a/gen/proto/go/prehog/v1alpha/teleport.pb.go b/gen/proto/go/prehog/v1alpha/teleport.pb.go index 66c02fa515281..e67592e2b7984 100644 --- a/gen/proto/go/prehog/v1alpha/teleport.pb.go +++ b/gen/proto/go/prehog/v1alpha/teleport.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: prehog/v1alpha/teleport.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/access_request.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/access_request.pb.go index dd1ac1691363e..df21c55cc973e 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/access_request.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/access_request.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/access_request.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/app.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/app.pb.go index 322b8a085b6a1..222ee783e19c0 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/app.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/app.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/app.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/auth_settings.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/auth_settings.pb.go index 4be23b9de07f0..cadcb84907e9f 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/auth_settings.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/auth_settings.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/auth_settings.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go index ee91a32cb84d9..51dbd7b580553 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/cluster.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/cluster.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/database.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/database.pb.go index ea2412225ab7a..8ce033e5c9c93 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/database.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/database.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/database.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/gateway.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/gateway.pb.go index 0dc296f5e76cc..f2bc2e5b6c174 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/gateway.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/gateway.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/gateway.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/kube.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/kube.pb.go index 1cb3f9100031d..056780e54a086 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/kube.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/kube.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/kube.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/label.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/label.pb.go index c04c7a2cb6bda..115728588ead1 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/label.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/label.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/label.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/server.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/server.pb.go index 2c499f8dd9316..2d26b10c2ebf4 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/server.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/server.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/server.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go index f2ff4bcaced0d..6a60ee36d074d 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/service.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/service.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go index 8cce353289d5a..d4c27c8f47fcd 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/tshd_events_service.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/tshd_events_service.proto diff --git a/gen/proto/go/teleport/lib/teleterm/v1/usage_events.pb.go b/gen/proto/go/teleport/lib/teleterm/v1/usage_events.pb.go index 7cd8fa552bba2..8b6bab199aaf1 100644 --- a/gen/proto/go/teleport/lib/teleterm/v1/usage_events.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/v1/usage_events.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/v1/usage_events.proto diff --git a/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go b/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go index 9f5907015d443..285b72529c17b 100644 --- a/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go +++ b/gen/proto/go/teleport/lib/teleterm/vnet/v1/vnet_service.pb.go @@ -16,7 +16,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/teleterm/vnet/v1/vnet_service.proto diff --git a/gen/proto/go/teleport/quicpeering/v1alpha/dial.pb.go b/gen/proto/go/teleport/quicpeering/v1alpha/dial.pb.go index 6844da6249b34..1e6fed8a15dc1 100644 --- a/gen/proto/go/teleport/quicpeering/v1alpha/dial.pb.go +++ b/gen/proto/go/teleport/quicpeering/v1alpha/dial.pb.go @@ -16,7 +16,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/quicpeering/v1alpha/dial.proto diff --git a/gen/proto/ts/google/protobuf/descriptor_pb.ts b/gen/proto/ts/google/protobuf/descriptor_pb.ts index 391723fe0e258..c0f84db4647ad 100644 --- a/gen/proto/ts/google/protobuf/descriptor_pb.ts +++ b/gen/proto/ts/google/protobuf/descriptor_pb.ts @@ -1036,12 +1036,13 @@ export interface MessageOptions { */ export interface FieldOptions { /** + * NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. * The ctype option instructs the C++ code generator to use a different * representation of the field than it normally would. See the specific * options below. This option is only implemented to support use of * [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - * type "bytes" in the open source release -- sorry, we'll try to include - * other types in a future version! + * type "bytes" in the open source release. + * TODO: make ctype actually deprecated. * * @generated from protobuf field: optional google.protobuf.FieldOptions.CType ctype = 1; */ @@ -1261,8 +1262,6 @@ export enum FieldOptions_JSType { } /** * If set to RETENTION_SOURCE, the option will be omitted from the binary. - * Note: as of January 2023, support for this is in progress and does not yet - * have an effect (b/264593489). * * @generated from protobuf enum google.protobuf.FieldOptions.OptionRetention */ @@ -1283,8 +1282,7 @@ export enum FieldOptions_OptionRetention { /** * This indicates the types of entities that the field may apply to when used * as an option. If it is unset, then the field may be freely used as an - * option on any kind of entity. Note: as of January 2023, support for this is - * in progress and does not yet have an effect (b/264593489). + * option on any kind of entity. * * @generated from protobuf enum google.protobuf.FieldOptions.OptionTargetType */ @@ -2071,7 +2069,7 @@ export enum Edition { EDITION_2024 = 1001, /** * Placeholder editions for testing feature resolution. These should not be - * used or relyed on outside of tests. + * used or relied on outside of tests. * * @generated from protobuf enum value: EDITION_1_TEST_ONLY = 1; */ diff --git a/go.mod b/go.mod index eb16212086763..8c464ff082e65 100644 --- a/go.mod +++ b/go.mod @@ -214,7 +214,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 google.golang.org/grpc v1.68.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 - google.golang.org/protobuf v1.36.0 + google.golang.org/protobuf v1.36.1 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/dnaeon/go-vcr.v3 v3.2.0 gopkg.in/ini.v1 v1.67.0 diff --git a/go.sum b/go.sum index 82132a3ee7268..354d9459e95f9 100644 --- a/go.sum +++ b/go.sum @@ -3096,8 +3096,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= diff --git a/integration/helpers/trustedclusters.go b/integration/helpers/trustedclusters.go index 1b3f43b61507c..cfc68f571ce5d 100644 --- a/integration/helpers/trustedclusters.go +++ b/integration/helpers/trustedclusters.go @@ -61,7 +61,66 @@ func TryCreateTrustedCluster(t *testing.T, authServer *auth.Server, trustedClust ctx := context.TODO() for i := 0; i < 10; i++ { log.Debugf("Will create trusted cluster %v, attempt %v.", trustedCluster, i) - _, err := authServer.UpsertTrustedCluster(ctx, trustedCluster) + _, err := authServer.CreateTrustedCluster(ctx, trustedCluster) + if err == nil { + return + } + if trace.IsConnectionProblem(err) { + log.Debugf("Retrying on connection problem: %v.", err) + time.Sleep(500 * time.Millisecond) + continue + } + if trace.IsAccessDenied(err) { + log.Debugf("Retrying on access denied: %v.", err) + time.Sleep(500 * time.Millisecond) + continue + } + require.FailNow(t, "Terminating on unexpected problem", "%v.", err) + } + require.FailNow(t, "Timeout creating trusted cluster") +} + +// TryUpdateTrustedCluster performs several attempts to update a trusted cluster, +// retries on connection problems and access denied errors to let caches +// propagate and services to start +func TryUpdateTrustedCluster(t *testing.T, authServer *auth.Server, trustedCluster types.TrustedCluster) { + t.Helper() + ctx := context.TODO() + for i := 0; i < 10; i++ { + log.Debugf("Will create trusted cluster %v, attempt %v.", trustedCluster, i) + _, err := authServer.UpdateTrustedCluster(ctx, trustedCluster) + if err == nil { + return + } + if trace.IsConnectionProblem(err) { + log.Debugf("Retrying on connection problem: %v.", err) + time.Sleep(500 * time.Millisecond) + continue + } + if trace.IsAccessDenied(err) { + log.Debugf("Retrying on access denied: %v.", err) + time.Sleep(500 * time.Millisecond) + continue + } + require.FailNow(t, "Terminating on unexpected problem", "%v.", err) + } + require.FailNow(t, "Timeout creating trusted cluster") +} + +// TryUpdateTrustedCluster performs several attempts to upsert a trusted cluster, +// retries on connection problems and access denied errors to let caches +// propagate and services to start +func TryUpsertTrustedCluster(t *testing.T, authServer *auth.Server, trustedCluster types.TrustedCluster, skipNameValidation bool) { + t.Helper() + ctx := context.TODO() + for i := 0; i < 10; i++ { + log.Debugf("Will create trusted cluster %v, attempt %v.", trustedCluster, i) + var err error + if skipNameValidation { + _, err = authServer.UpsertTrustedCluster(ctx, trustedCluster) + } else { + _, err = authServer.UpsertTrustedClusterV2(ctx, trustedCluster) + } if err == nil { return } diff --git a/integration/integration_test.go b/integration/integration_test.go index cbc138b498f4f..9dcb2332b44e6 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -196,6 +196,8 @@ func TestIntegrations(t *testing.T) { t.Run("TrustedDisabledClusters", suite.bind(testDisabledTrustedClusters)) t.Run("TrustedClustersRoleMapChanges", suite.bind(testTrustedClustersRoleMapChanges)) t.Run("TrustedClustersWithLabels", suite.bind(testTrustedClustersWithLabels)) + t.Run("TrustedClustersSkipNameValidation", suite.bind(testTrustedClustersSkipNameValidation)) + t.Run("CreateAndUpdateTrustedClusters", suite.bind(testCreateAndUpdateTrustedClusters)) t.Run("TrustedTunnelNode", suite.bind(testTrustedTunnelNode)) t.Run("TwoClustersProxy", suite.bind(testTwoClustersProxy)) t.Run("TwoClustersTunnel", suite.bind(testTwoClustersTunnel)) @@ -809,9 +811,7 @@ func testUUIDBasedProxy(t *testing.T, suite *integrationTestSuite) { // attempting to run a command by hostname should generate NodeIsAmbiguous error. _, err = runCommand(t, teleportSvr, []string{"echo", "Hello there!"}, helpers.ClientConfig{Login: suite.Me.Username, Cluster: helpers.Site, Host: Host}, 1) require.Error(t, err) - if !strings.Contains(err.Error(), teleport.NodeIsAmbiguous) { - require.FailNowf(t, "Expected %s, got %s", teleport.NodeIsAmbiguous, err.Error()) - } + require.ErrorContains(t, err, "ambiguous") // attempting to run a command by uuid should succeed. _, err = runCommand(t, teleportSvr, []string{"echo", "Hello there!"}, helpers.ClientConfig{Login: suite.Me.Username, Cluster: helpers.Site, Host: uuid1}, 1) @@ -2746,17 +2746,14 @@ func testMapRoles(t *testing.T, suite *integrationTestSuite) { {Remote: mainDevs, Local: []string{auxDevs}}, }) - // modify trusted cluster resource name so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") - require.NoError(t, main.Start()) require.NoError(t, aux.Start()) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) // try and upsert a trusted cluster - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) sshPort, _, _ := aux.StartNodeAndProxy(t, "aux-node") @@ -2906,6 +2903,9 @@ type trustedClusterTest struct { // useLabels turns on trusted cluster labels and // verifies RBAC useLabels bool + // skipNameValidation uses the deprecated UpsertTrustedCluster and skips + // cluster name validation. + skipNameValidation bool } // TestTrustedClusters tests remote clusters scenarios @@ -2942,6 +2942,15 @@ func testTrustedClustersWithLabels(t *testing.T, suite *integrationTestSuite) { trustedClusters(t, suite, trustedClusterTest{multiplex: false, useLabels: true}) } +// TestTrustedClustersSkipNameValidation tests remote clusters scenarios +// skipping name validation. +func testTrustedClustersSkipNameValidation(t *testing.T, suite *integrationTestSuite) { + tr := utils.NewTracer(utils.ThisFunction()).Start() + defer tr.Stop() + + trustedClusters(t, suite, trustedClusterTest{skipNameValidation: true}) +} + // TestJumpTrustedClusters tests remote clusters scenarios // using trusted clusters feature using jumphost connection func testJumpTrustedClusters(t *testing.T, suite *integrationTestSuite) { @@ -2969,6 +2978,15 @@ func testMultiplexingTrustedClusters(t *testing.T, suite *integrationTestSuite) trustedClusters(t, suite, trustedClusterTest{multiplex: true}) } +// TestCreateAndUpdateTrustedClusters tests the basic create and update +// operations for a trusted cluster. +func testCreateAndUpdateTrustedClusters(t *testing.T, suite *integrationTestSuite) { + tr := utils.NewTracer(utils.ThisFunction()).Start() + defer tr.Stop() + + createAndUpdateTrustedClusters(t, suite, trustedClusterTest{}) +} + func standardPortsOrMuxSetup(t *testing.T, mux bool, fds *[]*servicecfg.FileDescriptor) *helpers.InstanceListeners { if mux { return helpers.WebReverseTunnelMuxPortSetup(t, fds) @@ -2976,6 +2994,116 @@ func standardPortsOrMuxSetup(t *testing.T, mux bool, fds *[]*servicecfg.FileDesc return helpers.StandardListenerSetup(t, fds) } +func createAndUpdateTrustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClusterTest) { + ctx := context.Background() + username := suite.Me.Username + + clusterMain := "cluster-main" + clusterAux := "cluster-aux" + mainCfg := helpers.InstanceConfig{ + ClusterName: clusterMain, + HostID: helpers.HostID, + NodeName: Host, + Priv: suite.Priv, + Pub: suite.Pub, + Log: suite.Log, + } + mainCfg.Listeners = standardPortsOrMuxSetup(t, test.multiplex, &mainCfg.Fds) + main := helpers.NewInstance(t, mainCfg) + aux := suite.newNamedTeleportInstance(t, clusterAux) + + // main cluster has a local user and belongs to role "main-devs" and "main-admins" + mainDevs := "main-devs" + mainRole, err := types.NewRole(mainDevs, types.RoleSpecV6{ + Allow: types.RoleConditions{ + Logins: []string{username}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + }, + }) + require.NoError(t, err) + + mainAdmins := "main-admins" + adminsRole, err := types.NewRole(mainAdmins, types.RoleSpecV6{ + Allow: types.RoleConditions{ + Logins: []string{"superuser"}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + }, + }) + require.NoError(t, err) + + main.AddUserWithRole(username, mainRole, adminsRole) + + // for role mapping test we turn on Web API on the main cluster + // as it's used + makeConfig := func(instance *helpers.TeleInstance, enableSSH bool) (*testing.T, *servicecfg.Config) { + tconf := suite.defaultServiceConfig() + tconf.Proxy.DisableWebService = false + tconf.Proxy.DisableWebInterface = true + tconf.SSH.Enabled = enableSSH + tconf, err := instance.GenerateConfig(t, nil, tconf) + require.NoError(t, err) + + tconf.CachePolicy.Enabled = false + return t, tconf + } + lib.SetInsecureDevMode(true) + defer lib.SetInsecureDevMode(false) + + require.NoError(t, main.CreateWithConf(makeConfig(main, false))) + require.NoError(t, aux.CreateWithConf(makeConfig(aux, true))) + + // auxiliary cluster has only a role aux-devs + // connect aux cluster to main cluster + // using trusted clusters, so remote user will be allowed to assume + // role specified by mapping remote role "devs" to local role "local-devs" + auxDevs := "aux-devs" + auxRole, err := types.NewRole(auxDevs, types.RoleSpecV6{ + Allow: types.RoleConditions{ + Logins: []string{username}, + NodeLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + }, + }) + require.NoError(t, err) + _, err = aux.Process.GetAuthServer().UpsertRole(ctx, auxRole) + require.NoError(t, err) + + trustedClusterToken := "trusted-cluster-token" + tokenResource, err := types.NewProvisionToken(trustedClusterToken, []types.SystemRole{types.RoleTrustedCluster}, time.Time{}) + require.NoError(t, err) + err = main.Process.GetAuthServer().UpsertToken(ctx, tokenResource) + require.NoError(t, err) + + trustedCluster := main.AsTrustedCluster(trustedClusterToken, types.RoleMap{ + {Remote: mainDevs, Local: []string{auxDevs}}, + }) + + require.NoError(t, main.Start()) + require.NoError(t, aux.Start()) + + require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) + + // Note that the trusted cluster resource name must match the cluster name. + // Modify the trusted cluster resource name and expect the create to fail. + trustedCluster.SetName(main.Secrets.SiteName + "-cluster") + _, err = aux.Process.GetAuthServer().CreateTrustedCluster(ctx, trustedCluster) + require.ErrorContains(t, err, "trusted cluster resource name must be the same as the remote cluster name", "expected failure due to tc name mismatch") + + // Modify the trusted cluster resource name back to what it was originally. + // Try and create a trusted cluster + trustedCluster.SetName(main.Secrets.SiteName) + helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + + // Update the trusted cluster resource with new role mappings. + trustedCluster.SetRoleMap(types.RoleMap{ + {Remote: mainAdmins, Local: []string{auxDevs}}, + }) + helpers.TryUpdateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + + // stop clusters and remaining nodes + require.NoError(t, main.StopAll()) + require.NoError(t, aux.StopAll()) +} + func trustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClusterTest) { ctx := context.Background() username := suite.Me.Username @@ -3079,17 +3207,25 @@ func trustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClus {Remote: mainOps, Local: []string{auxDevs}}, }) - // modify trusted cluster resource name, so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") - require.NoError(t, main.Start()) require.NoError(t, aux.Start()) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) + // Note that the trusted cluster resource name must match the cluster name. + // Modify the trusted cluster resource name and expect the upsert to fail. + trustedCluster.SetName(main.Secrets.SiteName + "-cluster") + + _, err = aux.Process.GetAuthServer().UpsertTrustedClusterV2(ctx, trustedCluster) + require.ErrorContains(t, err, "trusted cluster resource name must be the same as the remote cluster name", "expected failure due to tc name mismatch") + + if !test.skipNameValidation { + // Modify the trusted cluster resource name back to what it was originally. + trustedCluster.SetName(main.Secrets.SiteName) + } + // try and upsert a trusted cluster - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) sshPort, _, _ := aux.StartNodeAndProxy(t, "aux-node") @@ -3176,7 +3312,7 @@ func trustedClusters(t *testing.T, suite *integrationTestSuite, test trustedClus require.Error(t, err, "expected tunnel to close and SSH client to start failing") // recreating the trusted cluster should re-establish connection - _, err = aux.Process.GetAuthServer().UpsertTrustedCluster(ctx, trustedCluster) + _, err = aux.Process.GetAuthServer().UpsertTrustedClusterV2(ctx, trustedCluster) require.NoError(t, err) // check that remote cluster has been re-provisioned @@ -3322,9 +3458,6 @@ func trustedDisabledCluster(t *testing.T, suite *integrationTestSuite, test trus {Remote: mainOps, Local: []string{auxDevs}}, }) - // modify trusted cluster resource name, so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") // disable cluster trustedCluster.SetEnabled(false) @@ -3334,11 +3467,11 @@ func trustedDisabledCluster(t *testing.T, suite *integrationTestSuite, test trus require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) // try and upsert a trusted cluster while disabled - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) // try to enable disabled cluster trustedCluster.SetEnabled(true) - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) helpers.CheckTrustedClustersCanConnect(ctx, t, helpers.TrustedClusterSetup{ @@ -3462,16 +3595,12 @@ func trustedClustersRoleMapChanges(t *testing.T, suite *integrationTestSuite, te {Remote: mainOps, Local: []string{auxDevs}}, }) - // modify trusted cluster resource name, so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") - require.NoError(t, main.Start()) require.NoError(t, aux.Start()) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) // change role mapping to ensure updating works @@ -3479,7 +3608,7 @@ func trustedClustersRoleMapChanges(t *testing.T, suite *integrationTestSuite, te {Remote: mainDevs, Local: []string{auxDevs}}, }) - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) helpers.CheckTrustedClustersCanConnect(ctx, t, helpers.TrustedClusterSetup{ @@ -3492,7 +3621,7 @@ func trustedClustersRoleMapChanges(t *testing.T, suite *integrationTestSuite, te // disable the enabled trusted cluster and ensure it no longer works trustedCluster.SetEnabled(false) - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, test.skipNameValidation) // Wait for both cluster to no longer see each other via reverse tunnels. require.Eventually(t, helpers.WaitForClusters(main.Tunnel, 0), 10*time.Second, 1*time.Second, @@ -3563,17 +3692,14 @@ func testTrustedTunnelNode(t *testing.T, suite *integrationTestSuite) { {Remote: mainDevs, Local: []string{auxDevs}}, }) - // modify trusted cluster resource name, so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") - require.NoError(t, main.Start()) require.NoError(t, aux.Start()) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) // try and upsert a trusted cluster - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) // Create a Teleport instance with a node that dials back to the aux cluster. @@ -3747,17 +3873,14 @@ func testTrustedClusterAgentless(t *testing.T, suite *integrationTestSuite) { {Remote: devsRoleName, Local: []string{devsRoleName}}, }) - // modify trusted cluster resource name, so it would not - // match the cluster name to check that it does not matter - trustedCluster.SetName(main.Secrets.SiteName + "-cluster") - require.NoError(t, main.Start()) require.NoError(t, leaf.Start()) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) // try and upsert a trusted cluster - helpers.TryCreateTrustedCluster(t, leaf.Process.GetAuthServer(), trustedCluster) + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, leaf.Process.GetAuthServer(), trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, main.Process.GetAuthServer(), clusterAux, 1) // Wait for both cluster to see each other via reverse tunnels. @@ -5585,7 +5708,8 @@ func testRotateTrustedClusters(t *testing.T, suite *integrationTestSuite) { lib.SetInsecureDevMode(true) defer lib.SetInsecureDevMode(false) - helpers.TryCreateTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster) + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, aux.Process.GetAuthServer(), trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, svc.GetAuthServer(), aux.Secrets.SiteName, 1) // capture credentials before reload has started to simulate old client @@ -7484,7 +7608,9 @@ func createTrustedClusterPair(t *testing.T, suite *integrationTestSuite, extraSe t.Cleanup(func() { leaf.StopAll() }) require.NoError(t, services.CheckAndSetDefaults(trustedCluster)) - helpers.TryCreateTrustedCluster(t, leaf.Process.GetAuthServer(), trustedCluster) + + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, leaf.Process.GetAuthServer(), trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, root.Process.GetAuthServer(), leafName, 1) _, _, rootProxySSHPort := root.StartNodeAndProxy(t, "root-zero") diff --git a/integration/kube_integration_test.go b/integration/kube_integration_test.go index c9fd5ff21efdb..2127486ff7a7f 100644 --- a/integration/kube_integration_test.go +++ b/integration/kube_integration_test.go @@ -695,7 +695,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) { var upsertSuccess bool for i := 0; i < 10; i++ { log.Debugf("Will create trusted cluster %v, attempt %v", trustedCluster, i) - _, err = aux.Process.GetAuthServer().UpsertTrustedCluster(ctx, trustedCluster) + _, err = aux.Process.GetAuthServer().UpsertTrustedClusterV2(ctx, trustedCluster) if err != nil { if trace.IsConnectionProblem(err) { log.Debugf("retrying on connection problem: %v", err) @@ -971,7 +971,7 @@ func testKubeTrustedClustersSNI(t *testing.T, suite *KubeSuite) { var upsertSuccess bool for i := 0; i < 10; i++ { log.Debugf("Will create trusted cluster %v, attempt %v", trustedCluster, i) - _, err = aux.Process.GetAuthServer().UpsertTrustedCluster(ctx, trustedCluster) + _, err = aux.Process.GetAuthServer().UpsertTrustedClusterV2(ctx, trustedCluster) if err != nil { if trace.IsConnectionProblem(err) { log.Debugf("retrying on connection problem: %v", err) diff --git a/integration/proxy/proxy_helpers.go b/integration/proxy/proxy_helpers.go index e0e3c7b587224..9de514caf73e1 100644 --- a/integration/proxy/proxy_helpers.go +++ b/integration/proxy/proxy_helpers.go @@ -184,7 +184,8 @@ func newSuite(t *testing.T, opts ...proxySuiteOptionsFunc) *Suite { } if options.trustedCluster != nil { - helpers.TryCreateTrustedCluster(t, suite.leaf.Process.GetAuthServer(), options.trustedCluster) + const skipNameValidation = false + helpers.TryUpsertTrustedCluster(t, suite.leaf.Process.GetAuthServer(), options.trustedCluster, skipNameValidation) helpers.WaitForTunnelConnections(t, suite.root.Process.GetAuthServer(), suite.leaf.Secrets.SiteName, 1) } diff --git a/integrations/access/slack/bot.go b/integrations/access/slack/bot.go index dff6c17bbad27..9c58093cb9897 100644 --- a/integrations/access/slack/bot.go +++ b/integrations/access/slack/bot.go @@ -291,6 +291,7 @@ func (b Bot) slackAccessListReminderMsgSection(accessList *accesslist.AccessList if b.webProxyURL != nil { reqURL := *b.webProxyURL reqURL.Path = lib.BuildURLPath("web", "accesslists", accessList.Metadata.Name) + reqURL.Fragment = "review" link = fmt.Sprintf("*Link*: %s", reqURL.String()) } diff --git a/integrations/event-handler/go.mod b/integrations/event-handler/go.mod index 56ac4bd95bd73..c5f1c71cee047 100644 --- a/integrations/event-handler/go.mod +++ b/integrations/event-handler/go.mod @@ -17,7 +17,7 @@ require ( github.com/stretchr/testify v1.10.0 golang.org/x/net v0.33.0 golang.org/x/time v0.8.0 - google.golang.org/protobuf v1.36.0 + google.golang.org/protobuf v1.36.1 ) require ( diff --git a/integrations/event-handler/go.sum b/integrations/event-handler/go.sum index 2b0f134829fcd..7965768d49fdb 100644 --- a/integrations/event-handler/go.sum +++ b/integrations/event-handler/go.sum @@ -2337,8 +2337,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integrations/terraform/Makefile b/integrations/terraform/Makefile index 0d1c0ed65e6d6..572a07d4d45dc 100644 --- a/integrations/terraform/Makefile +++ b/integrations/terraform/Makefile @@ -115,10 +115,18 @@ endif --terraform_out=config=protoc-gen-terraform-statichostuser.yaml:./tfschema \ teleport/userprovisioning/v2/statichostuser.proto + @protoc \ + -I=../../api/proto \ + -I=$(PROTOBUF_MOD_PATH) \ + --plugin=$(PROTOC_GEN_TERRAFORM) \ + --terraform_out=config=protoc-gen-terraform-workloadidentity.yaml:./tfschema \ + teleport/workloadidentity/v1/resource.proto + mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1/loginrule_terraform.go ./tfschema/loginrule/v1/ mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1/accesslist_terraform.go ./tfschema/accesslist/v1/ mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/accessmonitoringrules/v1/access_monitoring_rules_terraform.go ./tfschema/accessmonitoringrules/v1/ mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2/statichostuser_terraform.go ./tfschema/userprovisioning/v2/ + mv ./tfschema/github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1/resource_terraform.go ./tfschema/workloadidentity/v1/ mv ./tfschema/github.com/gravitational/teleport/api/types/device_terraform.go ./tfschema/devicetrust/v1/ rm -r ./tfschema/github.com/ @go run ./gen/main.go diff --git a/integrations/terraform/examples/resources/teleport_workload_identity/resource.tf b/integrations/terraform/examples/resources/teleport_workload_identity/resource.tf new file mode 100644 index 0000000000000..e48ab1e5d0dd2 --- /dev/null +++ b/integrations/terraform/examples/resources/teleport_workload_identity/resource.tf @@ -0,0 +1,22 @@ +resource "teleport_workload_identity" "example" { + version = "v1" + metadata = { + name = "example" + } + spec = { + rules = { + allow = [ + { + conditions = [{ + attribute = "user.name" + equals = "noah" + }] + } + ] + } + spiffe = { + id = "/my/spiffe/id/path" + hint = "my-hint" + } + } +} \ No newline at end of file diff --git a/integrations/terraform/gen/main.go b/integrations/terraform/gen/main.go index 3053e7b56098a..ca639ac758ac2 100644 --- a/integrations/terraform/gen/main.go +++ b/integrations/terraform/gen/main.go @@ -519,6 +519,31 @@ var ( ExtraImports: []string{"apitypes \"github.com/gravitational/teleport/api/types\""}, ForceSetKind: "apitypes.KindStaticHostUser", } + + workloadIdentity = payload{ + Name: "WorkloadIdentity", + TypeName: "WorkloadIdentity", + VarName: "workloadIdentity", + GetMethod: "GetWorkloadIdentity", + CreateMethod: "CreateWorkloadIdentity", + UpsertMethodArity: 2, + UpdateMethod: "UpsertWorkloadIdentity", + DeleteMethod: "DeleteWorkloadIdentity", + ID: "workloadIdentity.Metadata.Name", + Kind: "workload_identity", + HasStaticID: false, + ProtoPackage: "workloadidentityv1", + ProtoPackagePath: "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1", + SchemaPackage: "schemav1", + SchemaPackagePath: "github.com/gravitational/teleport/integrations/terraform/tfschema/workloadidentity/v1", + TerraformResourceType: "teleport_workload_identity", + // Since [RFD 153](https://github.com/gravitational/teleport/blob/master/rfd/0153-resource-guidelines.md) + // resources are plain structs + IsPlainStruct: true, + // As 153-style resources don't have CheckAndSetDefaults, we must set the Kind manually. + // We import the package containing kinds, then use ForceSetKind. + ForceSetKind: `"workload_identity"`, + } ) func main() { @@ -570,6 +595,8 @@ func genTFSchema() { generateDataSource(accessMonitoringRule, pluralDataSource) generateResource(staticHostUser, pluralResource) generateDataSource(staticHostUser, pluralDataSource) + generateResource(workloadIdentity, pluralResource) + generateDataSource(workloadIdentity, pluralDataSource) } func generateResource(p payload, tpl string) { diff --git a/integrations/terraform/go.mod b/integrations/terraform/go.mod index e6e5624117945..23f3eb75782e1 100644 --- a/integrations/terraform/go.mod +++ b/integrations/terraform/go.mod @@ -24,7 +24,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.10.0 google.golang.org/grpc v1.68.0 - google.golang.org/protobuf v1.36.0 + google.golang.org/protobuf v1.36.1 ) require ( diff --git a/integrations/terraform/go.sum b/integrations/terraform/go.sum index e2d3ece037acc..860c97ee36879 100644 --- a/integrations/terraform/go.sum +++ b/integrations/terraform/go.sum @@ -2700,8 +2700,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml b/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml new file mode 100644 index 0000000000000..016f3209037ba --- /dev/null +++ b/integrations/terraform/protoc-gen-terraform-workloadidentity.yaml @@ -0,0 +1,68 @@ +--- +target_package_name: "v1" +default_package_name: "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" +duration_custom_type: Duration +use_state_for_unknown_by_default: true + +# Top-level type names to export +types: + - "WorkloadIdentity" + +# These import paths were not being automatically picked up by +# protoc-gen-terraform without these overrides +import_path_overrides: + "types": "github.com/gravitational/teleport/api/types" + "wrappers": "github.com/gravitational/teleport/api/types/wrappers" + "durationpb": "google.golang.org/protobuf/types/known/durationpb" + "timestamppb": "google.golang.org/protobuf/types/known/timestamppb" + "structpb": "google.golang.org/protobuf/types/known/structpb" + "v1": "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + "v11": "github.com/gravitational/teleport/api/gen/proto/go/teleport/label/v1" + "github_com_gravitational_teleport_integrations_terraform_tfschema": "github.com/gravitational/teleport/integrations/terraform/tfschema" + + +# id field is required for integration tests. It is not used by provider. +# We have to add it manually (might be removed in the future versions). +injected_fields: + WorkloadIdentity: + - name: id + type: github.com/hashicorp/terraform-plugin-framework/types.StringType + computed: true + plan_modifiers: + - "github.com/hashicorp/terraform-plugin-framework/tfsdk.UseStateForUnknown()" + +# These fields will be excluded +exclude_fields: + # Metadata (we id resources by name on our side) + - "WorkloadIdentity.metadata.id" + +# These fields will be marked as Computed: true +computed_fields: + # Metadata + - "WorkloadIdentity.metadata.namespace" + - "WorkloadIdentity.kind" + +# These fields will be marked as Required: true +required_fields: [] + + +plan_modifiers: + # Force to recreate resource if it's name changes + Metadata.name: + - "github.com/hashicorp/terraform-plugin-framework/tfsdk.RequiresReplace()" + +# This must be defined for the generator to be happy, but in reality all time +# fields are overridden (because the protobuf timestamps contain locks and the +# linter gets mad if we use raw structs instead of pointers). +time_type: + type: "PlaceholderType" +duration_type: + type: "PlaceholderType" + +validators: + # Expires must be in the future + Metadata.expires: + - github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture() + +custom_types: + "WorkloadIdentity.metadata.expires": Timestamp \ No newline at end of file diff --git a/integrations/terraform/provider/data_source_teleport_workload_identity.go b/integrations/terraform/provider/data_source_teleport_workload_identity.go new file mode 100755 index 0000000000000..1b1d15fb99dcd --- /dev/null +++ b/integrations/terraform/provider/data_source_teleport_workload_identity.go @@ -0,0 +1,82 @@ +// Code generated by _gen/main.go DO NOT EDIT +/* +Copyright 2015-2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package provider + +import ( + "context" + + + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/workloadidentity/v1" +) + +// dataSourceTeleportWorkloadIdentityType is the data source metadata type +type dataSourceTeleportWorkloadIdentityType struct{} + +// dataSourceTeleportWorkloadIdentity is the resource +type dataSourceTeleportWorkloadIdentity struct { + p Provider +} + +// GetSchema returns the data source schema +func (r dataSourceTeleportWorkloadIdentityType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaWorkloadIdentity(ctx) +} + +// NewDataSource creates the empty data source +func (r dataSourceTeleportWorkloadIdentityType) NewDataSource(_ context.Context, p tfsdk.Provider) (tfsdk.DataSource, diag.Diagnostics) { + return dataSourceTeleportWorkloadIdentity{ + p: *(p.(*Provider)), + }, nil +} + +// Read reads teleport WorkloadIdentity +func (r dataSourceTeleportWorkloadIdentity) Read(ctx context.Context, req tfsdk.ReadDataSourceRequest, resp *tfsdk.ReadDataSourceResponse) { + var id types.String + diags := req.Config.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + workloadIdentityI, err := r.p.Client.GetWorkloadIdentity(ctx, id.Value) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + + var state types.Object + workloadIdentity := workloadIdentityI + + diags = schemav1.CopyWorkloadIdentityToTerraform(ctx, workloadIdentity, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} diff --git a/integrations/terraform/provider/provider.go b/integrations/terraform/provider/provider.go index ec2648df1b274..13b20d20c434f 100644 --- a/integrations/terraform/provider/provider.go +++ b/integrations/terraform/provider/provider.go @@ -504,6 +504,7 @@ func (p *Provider) GetResources(_ context.Context) (map[string]tfsdk.ResourceTyp "teleport_installer": resourceTeleportInstallerType{}, "teleport_access_monitoring_rule": resourceTeleportAccessMonitoringRuleType{}, "teleport_static_host_user": resourceTeleportStaticHostUserType{}, + "teleport_workload_identity": resourceTeleportWorkloadIdentityType{}, }, nil } @@ -531,6 +532,7 @@ func (p *Provider) GetDataSources(_ context.Context) (map[string]tfsdk.DataSourc "teleport_installer": dataSourceTeleportInstallerType{}, "teleport_access_monitoring_rule": dataSourceTeleportAccessMonitoringRuleType{}, "teleport_static_host_user": dataSourceTeleportStaticHostUserType{}, + "teleport_workload_identity": dataSourceTeleportWorkloadIdentityType{}, }, nil } diff --git a/integrations/terraform/provider/resource_teleport_workload_identity.go b/integrations/terraform/provider/resource_teleport_workload_identity.go new file mode 100755 index 0000000000000..e5c59e0993b44 --- /dev/null +++ b/integrations/terraform/provider/resource_teleport_workload_identity.go @@ -0,0 +1,317 @@ +// Code generated by _gen/main.go DO NOT EDIT +/* +Copyright 2015-2024 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package provider + +import ( + "context" + "fmt" + + workloadidentityv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" + + "github.com/gravitational/teleport/integrations/lib/backoff" + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jonboulle/clockwork" + + schemav1 "github.com/gravitational/teleport/integrations/terraform/tfschema/workloadidentity/v1" +) + +// resourceTeleportWorkloadIdentityType is the resource metadata type +type resourceTeleportWorkloadIdentityType struct{} + +// resourceTeleportWorkloadIdentity is the resource +type resourceTeleportWorkloadIdentity struct { + p Provider +} + +// GetSchema returns the resource schema +func (r resourceTeleportWorkloadIdentityType) GetSchema(ctx context.Context) (tfsdk.Schema, diag.Diagnostics) { + return schemav1.GenSchemaWorkloadIdentity(ctx) +} + +// NewResource creates the empty resource +func (r resourceTeleportWorkloadIdentityType) NewResource(_ context.Context, p tfsdk.Provider) (tfsdk.Resource, diag.Diagnostics) { + return resourceTeleportWorkloadIdentity{ + p: *(p.(*Provider)), + }, nil +} + +// Create creates the WorkloadIdentity +func (r resourceTeleportWorkloadIdentity) Create(ctx context.Context, req tfsdk.CreateResourceRequest, resp *tfsdk.CreateResourceResponse) { + var err error + if !r.p.IsConfigured(resp.Diagnostics) { + return + } + + var plan types.Object + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + workloadIdentity := &workloadidentityv1.WorkloadIdentity{} + diags = schemav1.CopyWorkloadIdentityFromTerraform(ctx, plan, workloadIdentity) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + + workloadIdentityResource := workloadIdentity + + workloadIdentityResource.Kind = "workload_identity" + + id := workloadIdentityResource.Metadata.Name + + _, err = r.p.Client.GetWorkloadIdentity(ctx, id) + if !trace.IsNotFound(err) { + if err == nil { + existErr := fmt.Sprintf("WorkloadIdentity exists in Teleport. Either remove it (tctl rm workload_identity/%v)"+ + " or import it to the existing state (terraform import teleport_workload_identity.%v %v)", id, id, id) + + resp.Diagnostics.Append(diagFromErr("WorkloadIdentity exists in Teleport", trace.Errorf(existErr))) + return + } + + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + + _, err = r.p.Client.CreateWorkloadIdentity(ctx, workloadIdentityResource) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error creating WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + var workloadIdentityI *workloadidentityv1.WorkloadIdentity + tries := 0 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + workloadIdentityI, err = r.p.Client.GetWorkloadIdentity(ctx, id) + if trace.IsNotFound(err) { + if bErr := backoff.Do(ctx); bErr != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(bErr), "workload_identity")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading WorkloadIdentity (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "workload_identity") + } + continue + } + break + } + + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + + workloadIdentityResource = workloadIdentityI + + workloadIdentity = workloadIdentityResource + + diags = schemav1.CopyWorkloadIdentityToTerraform(ctx, workloadIdentity, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + plan.Attrs["id"] = types.String{Value: workloadIdentity.Metadata.Name} + + diags = resp.State.Set(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read reads teleport WorkloadIdentity +func (r resourceTeleportWorkloadIdentity) Read(ctx context.Context, req tfsdk.ReadResourceRequest, resp *tfsdk.ReadResourceResponse) { + var state types.Object + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + var id types.String + diags = req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + workloadIdentityI, err := r.p.Client.GetWorkloadIdentity(ctx, id.Value) + if trace.IsNotFound(err) { + resp.State.RemoveResource(ctx) + return + } + + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + workloadIdentity := workloadIdentityI + diags = schemav1.CopyWorkloadIdentityToTerraform(ctx, workloadIdentity, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Update updates teleport WorkloadIdentity +func (r resourceTeleportWorkloadIdentity) Update(ctx context.Context, req tfsdk.UpdateResourceRequest, resp *tfsdk.UpdateResourceResponse) { + if !r.p.IsConfigured(resp.Diagnostics) { + return + } + + var plan types.Object + diags := req.Plan.Get(ctx, &plan) + + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + workloadIdentity := &workloadidentityv1.WorkloadIdentity{} + diags = schemav1.CopyWorkloadIdentityFromTerraform(ctx, plan, workloadIdentity) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + workloadIdentityResource := workloadIdentity + + + + name := workloadIdentityResource.Metadata.Name + + workloadIdentityBefore, err := r.p.Client.GetWorkloadIdentity(ctx, name) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", err, "workload_identity")) + return + } + + _, err = r.p.Client.UpsertWorkloadIdentity(ctx, workloadIdentityResource) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error updating WorkloadIdentity", err, "workload_identity")) + return + } + var workloadIdentityI *workloadidentityv1.WorkloadIdentity + + tries := 0 + backoff := backoff.NewDecorr(r.p.RetryConfig.Base, r.p.RetryConfig.Cap, clockwork.NewRealClock()) + for { + tries = tries + 1 + workloadIdentityI, err = r.p.Client.GetWorkloadIdentity(ctx, name) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", err, "workload_identity")) + return + } + if workloadIdentityBefore.GetMetadata().Revision != workloadIdentityI.GetMetadata().Revision || false { + break + } + + if err := backoff.Do(ctx); err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + if tries >= r.p.RetryConfig.MaxTries { + diagMessage := fmt.Sprintf("Error reading WorkloadIdentity (tried %d times) - state outdated, please import resource", tries) + resp.Diagnostics.AddError(diagMessage, "workload_identity") + return + } + } + + workloadIdentityResource = workloadIdentityI + + diags = schemav1.CopyWorkloadIdentityToTerraform(ctx, workloadIdentity, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete deletes Teleport WorkloadIdentity +func (r resourceTeleportWorkloadIdentity) Delete(ctx context.Context, req tfsdk.DeleteResourceRequest, resp *tfsdk.DeleteResourceResponse) { + var id types.String + diags := req.State.GetAttribute(ctx, path.Root("metadata").AtName("name"), &id) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + err := r.p.Client.DeleteWorkloadIdentity(ctx, id.Value) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error deleting WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + + resp.State.RemoveResource(ctx) +} + +// ImportState imports WorkloadIdentity state +func (r resourceTeleportWorkloadIdentity) ImportState(ctx context.Context, req tfsdk.ImportResourceStateRequest, resp *tfsdk.ImportResourceStateResponse) { + workloadIdentity, err := r.p.Client.GetWorkloadIdentity(ctx, req.ID) + if err != nil { + resp.Diagnostics.Append(diagFromWrappedErr("Error reading WorkloadIdentity", trace.Wrap(err), "workload_identity")) + return + } + + workloadIdentityResource := workloadIdentity + + + var state types.Object + + diags := resp.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + diags = schemav1.CopyWorkloadIdentityToTerraform(ctx, workloadIdentityResource, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + id := workloadIdentity.Metadata.Name + + state.Attrs["id"] = types.String{Value: id} + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} diff --git a/integrations/terraform/testlib/fixtures/workload_identity_0_create.tf b/integrations/terraform/testlib/fixtures/workload_identity_0_create.tf new file mode 100644 index 0000000000000..b5d0ebe8aae08 --- /dev/null +++ b/integrations/terraform/testlib/fixtures/workload_identity_0_create.tf @@ -0,0 +1,21 @@ +resource "teleport_workload_identity" "test" { + version = "v1" + metadata = { + name = "test" + } + spec = { + rules = { + allow = [ + { + conditions = [{ + attribute = "user.name" + equals = "foo" + }] + } + ] + } + spiffe = { + id = "/test" + } + } +} \ No newline at end of file diff --git a/integrations/terraform/testlib/fixtures/workload_identity_1_update.tf b/integrations/terraform/testlib/fixtures/workload_identity_1_update.tf new file mode 100644 index 0000000000000..cced0a4f8ecdd --- /dev/null +++ b/integrations/terraform/testlib/fixtures/workload_identity_1_update.tf @@ -0,0 +1,21 @@ +resource "teleport_workload_identity" "test" { + version = "v1" + metadata = { + name = "test" + } + spec = { + rules = { + allow = [ + { + conditions = [{ + attribute = "user.name" + equals = "foo" + }] + } + ] + } + spiffe = { + id = "/test/updated" + } + } +} \ No newline at end of file diff --git a/integrations/terraform/testlib/workload_identity_test.go b/integrations/terraform/testlib/workload_identity_test.go new file mode 100644 index 0000000000000..1e6d84cf6feb9 --- /dev/null +++ b/integrations/terraform/testlib/workload_identity_test.go @@ -0,0 +1,143 @@ +// Copyright 2024 Gravitational, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testlib + +import ( + "context" + "fmt" + "time" + + "github.com/gravitational/trace" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/stretchr/testify/require" + + v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + workloadidentityv1pb "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" + "github.com/gravitational/teleport/api/types" +) + +func (s *TerraformSuiteOSS) TestWorkloadIdentity() { + t := s.T() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + checkDestroyed := func(state *terraform.State) error { + _, err := s.client.GetWorkloadIdentity(ctx, "test") + if trace.IsNotFound(err) { + return nil + } + return trace.Errorf("expected not found, actual: %v", err) + } + + name := "teleport_workload_identity.test" + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + CheckDestroy: checkDestroyed, + IsUnitTest: true, + Steps: []resource.TestStep{ + { + Config: s.getFixture("workload_identity_0_create.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "workload_identity"), + resource.TestCheckResourceAttr(name, "spec.spiffe.id", "/test"), + resource.TestCheckResourceAttr(name, "spec.rules.allow.0.conditions.0.attribute", "user.name"), + resource.TestCheckResourceAttr(name, "spec.rules.allow.0.conditions.0.equals", "foo"), + ), + }, + { + Config: s.getFixture("workload_identity_0_create.tf"), + PlanOnly: true, + }, + { + Config: s.getFixture("workload_identity_1_update.tf"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(name, "kind", "workload_identity"), + resource.TestCheckResourceAttr(name, "spec.spiffe.id", "/test/updated"), + resource.TestCheckResourceAttr(name, "spec.rules.allow.0.conditions.0.attribute", "user.name"), + resource.TestCheckResourceAttr(name, "spec.rules.allow.0.conditions.0.equals", "foo"), + ), + }, + { + Config: s.getFixture("workload_identity_1_update.tf"), + PlanOnly: true, + }, + }, + }) +} + +func (s *TerraformSuiteOSS) TestImportWorkloadIdentity() { + t := s.T() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + r := "teleport_workload_identity" + id := "test_import" + name := r + "." + id + + shu := &workloadidentityv1pb.WorkloadIdentity{ + Metadata: &v1.Metadata{ + Name: id, + }, + Kind: types.KindWorkloadIdentity, + Version: types.V1, + Spec: &workloadidentityv1pb.WorkloadIdentitySpec{ + Rules: &workloadidentityv1pb.WorkloadIdentityRules{ + Allow: []*workloadidentityv1pb.WorkloadIdentityRule{ + { + Conditions: []*workloadidentityv1pb.WorkloadIdentityCondition{ + { + Attribute: "user.name", + Equals: "foo", + }, + }, + }, + }, + }, + Spiffe: &workloadidentityv1pb.WorkloadIdentitySPIFFE{ + Id: "/test", + }, + }, + } + shu, err := s.client.CreateWorkloadIdentity(ctx, shu) + require.NoError(t, err) + + require.Eventually(t, func() bool { + _, err := s.client.GetWorkloadIdentity(ctx, shu.GetMetadata().Name) + return err == nil + }, 5*time.Second, time.Second) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: s.terraformProviders, + IsUnitTest: true, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf("%s\nresource %q %q { }", s.terraformConfig, r, id), + ResourceName: name, + ImportState: true, + ImportStateId: id, + ImportStateCheck: func(state []*terraform.InstanceState) error { + require.Equal(t, types.KindWorkloadIdentity, state[0].Attributes["kind"]) + require.Equal(t, "/test", state[0].Attributes["spec.spiffe.id"]) + require.Equal(t, "user.name", state[0].Attributes["spec.rules.allow.0.conditions.0.attribute"]) + require.Equal(t, "foo", state[0].Attributes["spec.rules.allow.0.conditions.0.equals"]) + + return nil + }, + }, + }, + }) +} diff --git a/integrations/terraform/tfschema/workloadidentity/v1/custom_types.go b/integrations/terraform/tfschema/workloadidentity/v1/custom_types.go new file mode 100644 index 0000000000000..eb615d5b1888b --- /dev/null +++ b/integrations/terraform/tfschema/workloadidentity/v1/custom_types.go @@ -0,0 +1,25 @@ +// 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 v1 + +import "github.com/gravitational/teleport/integrations/terraform/tfschema/resource153" + +var ( + GenSchemaTimestamp = resource153.GenSchemaTimestamp + CopyToTimestamp = resource153.CopyToTimestamp + CopyFromTimestamp = resource153.CopyFromTimestamp +) diff --git a/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go b/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go new file mode 100644 index 0000000000000..f6510d28f7294 --- /dev/null +++ b/integrations/terraform/tfschema/workloadidentity/v1/resource_terraform.go @@ -0,0 +1,1177 @@ +/* +Copyright 2015-2022 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: teleport/workloadidentity/v1/resource.proto + +package v1 + +import ( + context "context" + fmt "fmt" + math "math" + + proto "github.com/gogo/protobuf/proto" + _ "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + github_com_gravitational_teleport_api_gen_proto_go_teleport_header_v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1" + github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/workloadidentity/v1" + github_com_gravitational_teleport_integrations_terraform_tfschema "github.com/gravitational/teleport/integrations/terraform/tfschema" + github_com_hashicorp_terraform_plugin_framework_attr "github.com/hashicorp/terraform-plugin-framework/attr" + github_com_hashicorp_terraform_plugin_framework_diag "github.com/hashicorp/terraform-plugin-framework/diag" + github_com_hashicorp_terraform_plugin_framework_tfsdk "github.com/hashicorp/terraform-plugin-framework/tfsdk" + github_com_hashicorp_terraform_plugin_framework_types "github.com/hashicorp/terraform-plugin-framework/types" + github_com_hashicorp_terraform_plugin_go_tftypes "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// GenSchemaWorkloadIdentity returns tfsdk.Schema definition for WorkloadIdentity +func GenSchemaWorkloadIdentity(ctx context.Context) (github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema, github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics) { + return github_com_hashicorp_terraform_plugin_framework_tfsdk.Schema{Attributes: map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "id": { + Computed: true, + Optional: false, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Required: false, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "kind": { + Computed: true, + Description: "The kind of resource represented.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "metadata": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "description": { + Description: "description is object description.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "expires": GenSchemaTimestamp(ctx, github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + Description: "expires is a global expiry time header can be set on any resource in the system.", + Optional: true, + Validators: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributeValidator{github_com_gravitational_teleport_integrations_terraform_tfschema.MustTimeBeInFuture()}, + }), + "labels": { + Description: "labels is a set of labels.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.MapType{ElemType: github_com_hashicorp_terraform_plugin_framework_types.StringType}, + }, + "name": { + Description: "name is an object name.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.RequiresReplace()}, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "namespace": { + Computed: true, + Description: "namespace is object namespace. The field should be called \"namespace\" when it returns in Teleport 2.4.", + Optional: true, + PlanModifiers: []github_com_hashicorp_terraform_plugin_framework_tfsdk.AttributePlanModifier{github_com_hashicorp_terraform_plugin_framework_tfsdk.UseStateForUnknown()}, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "revision": { + Description: "revision is an opaque identifier which tracks the versions of a resource over time. Clients should ignore and not alter its value but must return the revision in any updates of a resource.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Common metadata that all resources share.", + Optional: true, + }, + "spec": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "rules": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"allow": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{"conditions": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.ListNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "attribute": { + Description: "The name of the attribute to evaluate the condition against.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "equals": { + Description: "An exact string that the attribute must match.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "The conditions that must be met for this rule to be considered passed.", + Optional: true, + }}), + Description: "A list of rules used to determine if a WorkloadIdentity can be issued. If none are provided, it will be considered a pass. If any are provided, then at least one must pass for the rules to be considered passed.", + Optional: true, + }}), + Description: "The rules which are evaluated before the WorkloadIdentity can be issued.", + Optional: true, + }, + "spiffe": { + Attributes: github_com_hashicorp_terraform_plugin_framework_tfsdk.SingleNestedAttributes(map[string]github_com_hashicorp_terraform_plugin_framework_tfsdk.Attribute{ + "hint": { + Description: "A freeform text field which is provided to workloads along with a credential produced by this WorkloadIdentity. This can be used to provide additional context that can be used to select between multiple credentials.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "id": { + Description: "The path of the SPIFFE ID that will be issued to the workload. This should be prefixed with a forward-slash (\"/\"). This field supports templating using attributes.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }), + Description: "Configuration pertaining to the issuance of SPIFFE-compatible workload identity credentials.", + Optional: true, + }, + }), + Description: "The configured properties of the WorkloadIdentity", + Optional: true, + }, + "sub_kind": { + Description: "Differentiates variations of the same kind. All resources should contain one, even if it is never populated.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + "version": { + Description: "The version of the resource being represented.", + Optional: true, + Type: github_com_hashicorp_terraform_plugin_framework_types.StringType, + }, + }}, nil +} + +// CopyWorkloadIdentityFromTerraform copies contents of the source Terraform object into a target struct +func CopyWorkloadIdentityFromTerraform(_ context.Context, tf github_com_hashicorp_terraform_plugin_framework_types.Object, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentity) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { + var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics + { + a, ok := tf.Attrs["kind"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Kind = t + } + } + } + { + a, ok := tf.Attrs["sub_kind"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.sub_kind"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.sub_kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.SubKind = t + } + } + } + { + a, ok := tf.Attrs["version"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.version"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.version", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Version = t + } + } + } + { + a, ok := tf.Attrs["metadata"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Metadata = nil + if !v.Null && !v.Unknown { + tf := v + obj.Metadata = &github_com_gravitational_teleport_api_gen_proto_go_teleport_header_v1.Metadata{} + obj := obj.Metadata + { + a, ok := tf.Attrs["name"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.name"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Name = t + } + } + } + { + a, ok := tf.Attrs["namespace"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.namespace"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.namespace", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Namespace = t + } + } + } + { + a, ok := tf.Attrs["description"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.description"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.description", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Description = t + } + } + } + { + a, ok := tf.Attrs["labels"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.labels"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.labels", "github.com/hashicorp/terraform-plugin-framework/types.Map"}) + } else { + obj.Labels = make(map[string]string, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.labels", "github_com_hashicorp_terraform_plugin_framework_types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Labels[k] = t + } + } + } + } + } + } + { + a, ok := tf.Attrs["expires"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.expires"}) + } + CopyFromTimestamp(diags, a, &obj.Expires) + } + { + a, ok := tf.Attrs["revision"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.metadata.revision"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.metadata.revision", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Revision = t + } + } + } + } + } + } + } + { + a, ok := tf.Attrs["spec"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Spec = nil + if !v.Null && !v.Unknown { + tf := v + obj.Spec = &github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentitySpec{} + obj := obj.Spec + { + a, ok := tf.Attrs["rules"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.rules"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Rules = nil + if !v.Null && !v.Unknown { + tf := v + obj.Rules = &github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityRules{} + obj := obj.Rules + { + a, ok := tf.Attrs["allow"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.rules.allow"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Allow = make([]*github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityRule, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow", "github_com_hashicorp_terraform_plugin_framework_types.Object"}) + } else { + var t *github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityRule + if !v.Null && !v.Unknown { + tf := v + t = &github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityRule{} + obj := t + { + a, ok := tf.Attrs["conditions"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions", "github.com/hashicorp/terraform-plugin-framework/types.List"}) + } else { + obj.Conditions = make([]*github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityCondition, len(v.Elems)) + if !v.Null && !v.Unknown { + for k, a := range v.Elems { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions", "github_com_hashicorp_terraform_plugin_framework_types.Object"}) + } else { + var t *github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityCondition + if !v.Null && !v.Unknown { + tf := v + t = &github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentityCondition{} + obj := t + { + a, ok := tf.Attrs["attribute"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions.attribute"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions.attribute", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Attribute = t + } + } + } + { + a, ok := tf.Attrs["equals"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions.equals"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions.equals", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Equals = t + } + } + } + } + obj.Conditions[k] = t + } + } + } + } + } + } + } + obj.Allow[k] = t + } + } + } + } + } + } + } + } + } + } + { + a, ok := tf.Attrs["spiffe"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.spiffe"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.spiffe", "github.com/hashicorp/terraform-plugin-framework/types.Object"}) + } else { + obj.Spiffe = nil + if !v.Null && !v.Unknown { + tf := v + obj.Spiffe = &github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentitySPIFFE{} + obj := obj.Spiffe + { + a, ok := tf.Attrs["id"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.spiffe.id"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.spiffe.id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Id = t + } + } + } + { + a, ok := tf.Attrs["hint"] + if !ok { + diags.Append(attrReadMissingDiag{"WorkloadIdentity.spec.spiffe.hint"}) + } else { + v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrReadConversionFailureDiag{"WorkloadIdentity.spec.spiffe.hint", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } else { + var t string + if !v.Null && !v.Unknown { + t = string(v.Value) + } + obj.Hint = t + } + } + } + } + } + } + } + } + } + } + } + return diags +} + +// CopyWorkloadIdentityToTerraform copies contents of the source Terraform object into a target struct +func CopyWorkloadIdentityToTerraform(ctx context.Context, obj *github_com_gravitational_teleport_api_gen_proto_go_teleport_workloadidentity_v1.WorkloadIdentity, tf *github_com_hashicorp_terraform_plugin_framework_types.Object) github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics { + var diags github_com_hashicorp_terraform_plugin_framework_diag.Diagnostics + tf.Null = false + tf.Unknown = false + if tf.Attrs == nil { + tf.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value) + } + { + t, ok := tf.AttrTypes["kind"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.kind"}) + } else { + v, ok := tf.Attrs["kind"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Kind) == "" + } + v.Value = string(obj.Kind) + v.Unknown = false + tf.Attrs["kind"] = v + } + } + { + t, ok := tf.AttrTypes["sub_kind"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.sub_kind"}) + } else { + v, ok := tf.Attrs["sub_kind"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.sub_kind", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.sub_kind", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.SubKind) == "" + } + v.Value = string(obj.SubKind) + v.Unknown = false + tf.Attrs["sub_kind"] = v + } + } + { + t, ok := tf.AttrTypes["version"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.version"}) + } else { + v, ok := tf.Attrs["version"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.version", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.version", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Version) == "" + } + v.Value = string(obj.Version) + v.Unknown = false + tf.Attrs["version"] = v + } + } + { + a, ok := tf.AttrTypes["metadata"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["metadata"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if obj.Metadata == nil { + v.Null = true + } else { + obj := obj.Metadata + tf := &v + { + t, ok := tf.AttrTypes["name"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.name"}) + } else { + v, ok := tf.Attrs["name"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.metadata.name", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.name", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Name) == "" + } + v.Value = string(obj.Name) + v.Unknown = false + tf.Attrs["name"] = v + } + } + { + t, ok := tf.AttrTypes["namespace"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.namespace"}) + } else { + v, ok := tf.Attrs["namespace"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.metadata.namespace", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.namespace", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Namespace) == "" + } + v.Value = string(obj.Namespace) + v.Unknown = false + tf.Attrs["namespace"] = v + } + } + { + t, ok := tf.AttrTypes["description"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.description"}) + } else { + v, ok := tf.Attrs["description"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.metadata.description", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.description", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Description) == "" + } + v.Value = string(obj.Description) + v.Unknown = false + tf.Attrs["description"] = v + } + } + { + a, ok := tf.AttrTypes["labels"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.labels"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.MapType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.labels", "github.com/hashicorp/terraform-plugin-framework/types.MapType"}) + } else { + c, ok := tf.Attrs["labels"].(github_com_hashicorp_terraform_plugin_framework_types.Map) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.Map{ + + ElemType: o.ElemType, + Elems: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Labels)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Labels)) + } + } + if obj.Labels != nil { + t := o.ElemType + for k, a := range obj.Labels { + v, ok := tf.Attrs["labels"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.metadata.labels", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.labels", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = false + } + v.Value = string(a) + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Labels) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["labels"] = c + } + } + } + { + t, ok := tf.AttrTypes["expires"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.expires"}) + } else { + v := CopyToTimestamp(diags, obj.Expires, t, tf.Attrs["expires"]) + tf.Attrs["expires"] = v + } + } + { + t, ok := tf.AttrTypes["revision"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.metadata.revision"}) + } else { + v, ok := tf.Attrs["revision"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.metadata.revision", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.metadata.revision", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Revision) == "" + } + v.Value = string(obj.Revision) + v.Unknown = false + tf.Attrs["revision"] = v + } + } + } + v.Unknown = false + tf.Attrs["metadata"] = v + } + } + } + { + a, ok := tf.AttrTypes["spec"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["spec"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if obj.Spec == nil { + v.Null = true + } else { + obj := obj.Spec + tf := &v + { + a, ok := tf.AttrTypes["rules"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.rules"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.rules", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["rules"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if obj.Rules == nil { + v.Null = true + } else { + obj := obj.Rules + tf := &v + { + a, ok := tf.AttrTypes["allow"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.rules.allow"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.rules.allow", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["allow"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow)) + } + } + if obj.Allow != nil { + o := o.ElemType.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if len(obj.Allow) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Allow)) + } + for k, a := range obj.Allow { + v, ok := tf.Attrs["allow"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if a == nil { + v.Null = true + } else { + obj := a + tf := &v + { + a, ok := tf.AttrTypes["conditions"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ListType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions", "github.com/hashicorp/terraform-plugin-framework/types.ListType"}) + } else { + c, ok := tf.Attrs["conditions"].(github_com_hashicorp_terraform_plugin_framework_types.List) + if !ok { + c = github_com_hashicorp_terraform_plugin_framework_types.List{ + + ElemType: o.ElemType, + Elems: make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Conditions)), + Null: true, + } + } else { + if c.Elems == nil { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Conditions)) + } + } + if obj.Conditions != nil { + o := o.ElemType.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if len(obj.Conditions) != len(c.Elems) { + c.Elems = make([]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(obj.Conditions)) + } + for k, a := range obj.Conditions { + v, ok := tf.Attrs["conditions"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if a == nil { + v.Null = true + } else { + obj := a + tf := &v + { + t, ok := tf.AttrTypes["attribute"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions.attribute"}) + } else { + v, ok := tf.Attrs["attribute"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.spec.rules.allow.conditions.attribute", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions.attribute", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Attribute) == "" + } + v.Value = string(obj.Attribute) + v.Unknown = false + tf.Attrs["attribute"] = v + } + } + { + t, ok := tf.AttrTypes["equals"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.rules.allow.conditions.equals"}) + } else { + v, ok := tf.Attrs["equals"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.spec.rules.allow.conditions.equals", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.rules.allow.conditions.equals", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Equals) == "" + } + v.Value = string(obj.Equals) + v.Unknown = false + tf.Attrs["equals"] = v + } + } + } + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Conditions) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["conditions"] = c + } + } + } + } + v.Unknown = false + c.Elems[k] = v + } + if len(obj.Allow) > 0 { + c.Null = false + } + } + c.Unknown = false + tf.Attrs["allow"] = c + } + } + } + } + v.Unknown = false + tf.Attrs["rules"] = v + } + } + } + { + a, ok := tf.AttrTypes["spiffe"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.spiffe"}) + } else { + o, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.ObjectType) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.spiffe", "github.com/hashicorp/terraform-plugin-framework/types.ObjectType"}) + } else { + v, ok := tf.Attrs["spiffe"].(github_com_hashicorp_terraform_plugin_framework_types.Object) + if !ok { + v = github_com_hashicorp_terraform_plugin_framework_types.Object{ + + AttrTypes: o.AttrTypes, + Attrs: make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(o.AttrTypes)), + } + } else { + if v.Attrs == nil { + v.Attrs = make(map[string]github_com_hashicorp_terraform_plugin_framework_attr.Value, len(tf.AttrTypes)) + } + } + if obj.Spiffe == nil { + v.Null = true + } else { + obj := obj.Spiffe + tf := &v + { + t, ok := tf.AttrTypes["id"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.spiffe.id"}) + } else { + v, ok := tf.Attrs["id"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.spec.spiffe.id", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.spiffe.id", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Id) == "" + } + v.Value = string(obj.Id) + v.Unknown = false + tf.Attrs["id"] = v + } + } + { + t, ok := tf.AttrTypes["hint"] + if !ok { + diags.Append(attrWriteMissingDiag{"WorkloadIdentity.spec.spiffe.hint"}) + } else { + v, ok := tf.Attrs["hint"].(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil)) + if err != nil { + diags.Append(attrWriteGeneralError{"WorkloadIdentity.spec.spiffe.hint", err}) + } + v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String) + if !ok { + diags.Append(attrWriteConversionFailureDiag{"WorkloadIdentity.spec.spiffe.hint", "github.com/hashicorp/terraform-plugin-framework/types.String"}) + } + v.Null = string(obj.Hint) == "" + } + v.Value = string(obj.Hint) + v.Unknown = false + tf.Attrs["hint"] = v + } + } + } + v.Unknown = false + tf.Attrs["spiffe"] = v + } + } + } + } + v.Unknown = false + tf.Attrs["spec"] = v + } + } + } + return diags +} + +// attrReadMissingDiag represents diagnostic message on an attribute missing in the source object +type attrReadMissingDiag struct { + Path string +} + +func (d attrReadMissingDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrReadMissingDiag) Summary() string { + return "Error reading from Terraform object" +} + +func (d attrReadMissingDiag) Detail() string { + return fmt.Sprintf("A value for %v is missing in the source Terraform object Attrs", d.Path) +} + +func (d attrReadMissingDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrReadConversionFailureDiag represents diagnostic message on a failed type conversion on read +type attrReadConversionFailureDiag struct { + Path string + Type string +} + +func (d attrReadConversionFailureDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrReadConversionFailureDiag) Summary() string { + return "Error reading from Terraform object" +} + +func (d attrReadConversionFailureDiag) Detail() string { + return fmt.Sprintf("A value for %v can not be converted to %v", d.Path, d.Type) +} + +func (d attrReadConversionFailureDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteMissingDiag represents diagnostic message on an attribute missing in the target object +type attrWriteMissingDiag struct { + Path string +} + +func (d attrWriteMissingDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteMissingDiag) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteMissingDiag) Detail() string { + return fmt.Sprintf("A value for %v is missing in the source Terraform object AttrTypes", d.Path) +} + +func (d attrWriteMissingDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteConversionFailureDiag represents diagnostic message on a failed type conversion on write +type attrWriteConversionFailureDiag struct { + Path string + Type string +} + +func (d attrWriteConversionFailureDiag) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteConversionFailureDiag) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteConversionFailureDiag) Detail() string { + return fmt.Sprintf("A value for %v can not be converted to %v", d.Path, d.Type) +} + +func (d attrWriteConversionFailureDiag) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} + +// attrWriteGeneralError represents diagnostic message on a generic error on write +type attrWriteGeneralError struct { + Path string + Err error +} + +func (d attrWriteGeneralError) Severity() github_com_hashicorp_terraform_plugin_framework_diag.Severity { + return github_com_hashicorp_terraform_plugin_framework_diag.SeverityError +} + +func (d attrWriteGeneralError) Summary() string { + return "Error writing to Terraform object" +} + +func (d attrWriteGeneralError) Detail() string { + return fmt.Sprintf("%s: %s", d.Path, d.Err.Error()) +} + +func (d attrWriteGeneralError) Equal(o github_com_hashicorp_terraform_plugin_framework_diag.Diagnostic) bool { + return (d.Severity() == o.Severity()) && (d.Summary() == o.Summary()) && (d.Detail() == o.Detail()) +} diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 4a88c5e083603..7d15e272af2c2 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -652,7 +652,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) { // Add in a login hook for generating state during user login. as.ulsGenerator, err = userloginstate.NewGenerator(userloginstate.GeneratorConfig{ - Log: log, + Log: as.logger, AccessLists: &as, Access: &as, UsageEvents: &as, diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index 8f535a1727588..b9e9eb0a5aa8b 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -1262,7 +1262,7 @@ func TestTrustedClusterCRUDEventEmitted(t *testing.T) { // test create event for switch case: when tc exists but enabled is false tc.SetEnabled(false) - _, err = s.a.UpsertTrustedCluster(ctx, tc) + _, err = s.a.UpsertTrustedClusterV2(ctx, tc) require.NoError(t, err) require.Equal(t, events.TrustedClusterCreateEvent, s.mockEmitter.LastEvent().GetType()) createEvt := s.mockEmitter.LastEvent().(*apievents.TrustedClusterCreate) @@ -1272,7 +1272,7 @@ func TestTrustedClusterCRUDEventEmitted(t *testing.T) { // test create event for switch case: when tc exists but enabled is true tc.SetEnabled(true) - _, err = s.a.UpsertTrustedCluster(ctx, tc) + _, err = s.a.UpsertTrustedClusterV2(ctx, tc) require.NoError(t, err) require.Equal(t, events.TrustedClusterCreateEvent, s.mockEmitter.LastEvent().GetType()) createEvt = s.mockEmitter.LastEvent().(*apievents.TrustedClusterCreate) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index 4e463f6d7b8b1..40e94526e472a 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -196,30 +196,14 @@ func (a *ServerWithRoles) actionWithExtendedContext(kind, verb string, extendCon // actionForKindSession is a special checker that grants access to session // recordings. It can allow access to a specific recording based on the // `where` section of the user's access rule for kind `session`. -func (a *ServerWithRoles) actionForKindSession(ctx context.Context, sid session.ID) (types.SessionKind, error) { - sessionEnd, err := a.findSessionEndEvent(ctx, sid) - - extendContext := func(ctx *services.Context) error { - ctx.Session = sessionEnd +func (a *ServerWithRoles) actionForKindSession(ctx context.Context, sid session.ID) error { + extendContext := func(servicesCtx *services.Context) error { + sessionEnd, err := a.findSessionEndEvent(ctx, sid) + servicesCtx.Session = sessionEnd return trace.Wrap(err) } - var sessionKind types.SessionKind - switch e := sessionEnd.(type) { - case *apievents.SessionEnd: - sessionKind = types.SSHSessionKind - if e.KubernetesCluster != "" { - sessionKind = types.KubernetesSessionKind - } - case *apievents.DatabaseSessionEnd: - sessionKind = types.DatabaseSessionKind - case *apievents.AppSessionEnd: - sessionKind = types.AppSessionKind - case *apievents.WindowsDesktopSessionEnd: - sessionKind = types.WindowsDesktopSessionKind - } - - return sessionKind, trace.Wrap(a.actionWithExtendedContext(types.KindSession, types.VerbRead, extendContext)) + return trace.Wrap(a.actionWithExtendedContext(types.KindSession, types.VerbRead, extendContext)) } // localServerAction returns an access denied error if the role is not one of the builtin server roles. @@ -1648,22 +1632,23 @@ func (a *ServerWithRoles) GetSSHTargets(ctx context.Context, req *proto.GetSSHTa return nil, trace.Wrap(err) } - lreq := proto.ListResourcesRequest{ - ResourceType: types.KindNode, + lreq := &proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + SortBy: types.SortBy{Field: types.ResourceMetadataName}, UseSearchAsRoles: true, } var servers []*types.ServerV2 for { - // note that we're calling ServerWithRoles.ListResources here rather than some internal method. This method + // note that we're calling ServerWithRoles.ListUnifiedResources here rather than some internal method. This method // delegates all RBAC filtering to ListResources, and then performs additional filtering on top of that. - lrsp, err := a.ListResources(ctx, lreq) + lrsp, err := a.ListUnifiedResources(ctx, lreq) if err != nil { return nil, trace.Wrap(err) } for _, rsc := range lrsp.Resources { - srv, ok := rsc.(*types.ServerV2) - if !ok { + srv := rsc.GetNode() + if srv == nil { log.Warnf("Unexpected resource type %T, expected *types.ServerV2 (skipping)", rsc) continue } @@ -1687,6 +1672,92 @@ func (a *ServerWithRoles) GetSSHTargets(ctx context.Context, req *proto.GetSSHTa }, nil } +// ResolveSSHTarget gets a server that would match an equivalent ssh dial request. +func (a *ServerWithRoles) ResolveSSHTarget(ctx context.Context, req *proto.ResolveSSHTargetRequest) (*proto.ResolveSSHTargetResponse, error) { + // try to detect case-insensitive routing setting, but default to false if we can't load + // networking config (equivalent to proxy routing behavior). + var routeToMostRecent bool + if cfg, err := a.authServer.GetReadOnlyClusterNetworkingConfig(ctx); err == nil { + routeToMostRecent = cfg.GetRoutingStrategy() == types.RoutingStrategy_MOST_RECENT + } + + var servers []*types.ServerV2 + switch { + case req.Host != "": + if len(req.Labels) > 0 || req.PredicateExpression != "" || len(req.SearchKeywords) > 0 { + a.authServer.logger.WarnContext(ctx, "ssh target resolution request contained both host and a resource matcher - ignoring resource matcher") + } + + resp, err := a.GetSSHTargets(ctx, &proto.GetSSHTargetsRequest{ + Host: req.Host, + Port: req.Port, + }) + if err != nil { + return nil, trace.Wrap(err) + } + + servers = resp.Servers + case len(req.Labels) > 0 || req.PredicateExpression != "" || len(req.SearchKeywords) > 0: + lreq := &proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + SortBy: types.SortBy{Field: types.ResourceMetadataName}, + Labels: req.Labels, + PredicateExpression: req.PredicateExpression, + SearchKeywords: req.SearchKeywords, + } + for { + // note that we're calling ServerWithRoles.ListUnifiedResources here rather than some internal method. This method + // delegates all RBAC filtering to ListResources, and then performs additional filtering on top of that. + lrsp, err := a.ListUnifiedResources(ctx, lreq) + if err != nil { + return nil, trace.Wrap(err) + } + + for _, rsc := range lrsp.Resources { + srv := rsc.GetNode() + if srv == nil { + log.Warnf("Unexpected resource type %T, expected *types.ServerV2 (skipping)", rsc) + continue + } + + servers = append(servers, srv) + } + + // If the routing strategy doesn't permit ambiguous matches, then abort + // early if more than one server has been found already + if !routeToMostRecent && len(servers) > 1 { + break + } + + if lrsp.NextKey == "" || len(lrsp.Resources) == 0 { + break + } + + lreq.StartKey = lrsp.NextKey + + } + default: + return nil, trace.BadParameter("request did not contain any host information or resource matcher") + } + + switch len(servers) { + case 1: + return &proto.ResolveSSHTargetResponse{Server: servers[0]}, nil + case 0: + return nil, trace.NotFound("no matching hosts") + default: + if !routeToMostRecent { + return nil, trace.Wrap(teleport.ErrNodeIsAmbiguous) + } + + // Return the most recent version of the resource. + server := slices.MaxFunc(servers, func(a, b *types.ServerV2) int { + return a.Expiry().Compare(b.Expiry()) + }) + return &proto.ResolveSSHTargetResponse{Server: server}, nil + } +} + // ListResources returns a paginated list of resources filtered by user access. func (a *ServerWithRoles) ListResources(ctx context.Context, req proto.ListResourcesRequest) (*types.ListResourcesResponse, error) { // Check if auth server has a license for this resource type but only return an @@ -6034,29 +6105,25 @@ func (a *ServerWithRoles) ReplaceRemoteLocks(ctx context.Context, clusterName st // channel if one is encountered. Otherwise the event channel is closed when the stream ends. // The event channel is not closed on error to prevent race conditions in downstream select statements. func (a *ServerWithRoles) StreamSessionEvents(ctx context.Context, sessionID session.ID, startIndex int64) (chan apievents.AuditEvent, chan error) { - createErrorChannel := func(err error) (chan apievents.AuditEvent, chan error) { - e := make(chan error, 1) - e <- trace.Wrap(err) - return nil, e - } - err := a.localServerAction() isTeleportServer := err == nil - var sessionType types.SessionKind - if !isTeleportServer { - var err error - sessionType, err = a.actionForKindSession(ctx, sessionID) - if err != nil { - c, e := make(chan apievents.AuditEvent), make(chan error, 1) - e <- trace.Wrap(err) - return c, e - } + // StreamSessionEvents can be called internally, and when that + // happens we don't want to emit an event or check for permissions. + if isTeleportServer { + return a.alog.StreamSessionEvents(ctx, sessionID, startIndex) } - // StreamSessionEvents can be called internally, and when that happens we don't want to emit an event. - shouldEmitAuditEvent := !isTeleportServer - if shouldEmitAuditEvent { + if err := a.actionForKindSession(ctx, sessionID); err != nil { + c, e := make(chan apievents.AuditEvent), make(chan error, 1) + e <- trace.Wrap(err) + return c, e + } + + // We can only determine the session type after the streaming started. For + // this reason, we delay the emit audit event until the first event or if + // the streaming returns an error. + cb := func(evt apievents.AuditEvent, _ error) { if err := a.authServer.emitter.EmitAuditEvent(a.authServer.closeCtx, &apievents.SessionRecordingAccess{ Metadata: apievents.Metadata{ Type: events.SessionRecordingAccessEvent, @@ -6064,14 +6131,34 @@ func (a *ServerWithRoles) StreamSessionEvents(ctx context.Context, sessionID ses }, SessionID: sessionID.String(), UserMetadata: a.context.Identity.GetIdentity().GetUserMetadata(), - SessionType: string(sessionType), + SessionType: string(sessionTypeFromStartEvent(evt)), Format: metadata.SessionRecordingFormatFromContext(ctx), }); err != nil { - return createErrorChannel(err) + log.WithError(err).Errorf("Failed to emit stream session event audit event") } } - return a.alog.StreamSessionEvents(ctx, sessionID, startIndex) + return a.alog.StreamSessionEvents(events.ContextWithSessionStartCallback(ctx, cb), sessionID, startIndex) +} + +// sessionTypeFromStartEvent determines the session type given the session start +// event. +func sessionTypeFromStartEvent(sessionStart apievents.AuditEvent) types.SessionKind { + switch e := sessionStart.(type) { + case *apievents.SessionStart: + if e.KubernetesCluster != "" { + return types.KubernetesSessionKind + } + return types.SSHSessionKind + case *apievents.DatabaseSessionStart: + return types.DatabaseSessionKind + case *apievents.AppSessionStart: + return types.AppSessionKind + case *apievents.WindowsDesktopSessionStart: + return types.WindowsDesktopSessionKind + default: + return types.UnknownSessionKind + } } // CreateApp creates a new application resource. diff --git a/lib/auth/auth_with_roles_test.go b/lib/auth/auth_with_roles_test.go index 1576986648191..f6ad5315cd6fb 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -2267,7 +2267,29 @@ func TestStreamSessionEvents(t *testing.T) { func TestStreamSessionEvents_SessionType(t *testing.T) { t.Parallel() - srv := newTestTLSServer(t) + authServerConfig := TestAuthServerConfig{ + Dir: t.TempDir(), + Clock: clockwork.NewFakeClockAt(time.Now().Round(time.Second).UTC()), + } + require.NoError(t, authServerConfig.CheckAndSetDefaults()) + + uploader := eventstest.NewMemoryUploader() + localLog, err := events.NewAuditLog(events.AuditLogConfig{ + DataDir: authServerConfig.Dir, + ServerID: authServerConfig.ClusterName, + Clock: authServerConfig.Clock, + UploadHandler: uploader, + }) + require.NoError(t, err) + authServerConfig.AuditLog = localLog + + as, err := NewTestAuthServer(authServerConfig) + require.NoError(t, err) + + srv, err := as.NewTestTLSServer() + require.NoError(t, err) + t.Cleanup(func() { srv.Close() }) + ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) @@ -2278,22 +2300,29 @@ func TestStreamSessionEvents_SessionType(t *testing.T) { identity := TestUser(user.GetName()) clt, err := srv.NewClient(identity) require.NoError(t, err) - sessionID := "44c6cea8-362f-11ea-83aa-125400432324" + sessionID := session.NewID() - // Emitting a session end event will cause the listing to correctly locate - // the recording (even if there might not be a recording file to stream). - require.NoError(t, srv.Auth().EmitAuditEvent(ctx, &apievents.DatabaseSessionEnd{ + streamer, err := events.NewProtoStreamer(events.ProtoStreamerConfig{ + Uploader: uploader, + }) + require.NoError(t, err) + stream, err := streamer.CreateAuditStream(ctx, sessionID) + require.NoError(t, err) + // The event is not required to pass through the auth server, we only need + // the upload to be present. + require.NoError(t, stream.RecordEvent(ctx, eventstest.PrepareEvent(&apievents.DatabaseSessionStart{ Metadata: apievents.Metadata{ - Type: events.DatabaseSessionEndEvent, - Code: events.DatabaseSessionEndCode, + Type: events.DatabaseSessionStartEvent, + Code: events.DatabaseSessionStartCode, }, SessionMetadata: apievents.SessionMetadata{ - SessionID: sessionID, + SessionID: sessionID.String(), }, - })) + }))) + require.NoError(t, stream.Complete(ctx)) accessedFormat := teleport.PTY - clt.StreamSessionEvents(metadata.WithSessionRecordingFormatContext(ctx, accessedFormat), session.ID(sessionID), 0) + clt.StreamSessionEvents(metadata.WithSessionRecordingFormatContext(ctx, accessedFormat), sessionID, 0) // Perform the listing an eventually loop to ensure the event is emitted. var searchEvents []apievents.AuditEvent diff --git a/lib/auth/authclient/clt.go b/lib/auth/authclient/clt.go index 4217b12a5991e..09e4caff54d29 100644 --- a/lib/auth/authclient/clt.go +++ b/lib/auth/authclient/clt.go @@ -1875,6 +1875,9 @@ type ClientI interface { // but may result in confusing behavior if it is used outside of those contexts. GetSSHTargets(ctx context.Context, req *proto.GetSSHTargetsRequest) (*proto.GetSSHTargetsResponse, error) + // ResolveSSHTarget returns the server that would be resolved in an equivalent ssh dial request. + ResolveSSHTarget(ctx context.Context, req *proto.ResolveSSHTargetRequest) (*proto.ResolveSSHTargetResponse, error) + // PerformMFACeremony retrieves an MFA challenge from the server with the given challenge extensions // and prompts the user to answer the challenge with the given promptOpts, and ultimately returning // an MFA challenge response for the user. diff --git a/lib/auth/bot.go b/lib/auth/bot.go index d2ce2518abb50..104518ea7687e 100644 --- a/lib/auth/bot.go +++ b/lib/auth/bot.go @@ -26,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" "github.com/gravitational/teleport/api/client/proto" @@ -42,6 +41,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/sshutils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // legacyValidateGenerationLabel validates and updates a generation label. @@ -121,7 +121,10 @@ func (a *Server) legacyValidateGenerationLabel(ctx context.Context, username str // The current generations must match to continue: if currentIdentityGeneration != currentUserGeneration { if err := a.tryLockBotDueToGenerationMismatch(ctx, user.GetName()); err != nil { - log.WithError(err).Warnf("Failed to lock bot %q when a generation mismatch was detected", user.GetName()) + a.logger.WarnContext(ctx, "Failed to lock bot when a generation mismatch was detected", + "error", err, + "bot", user.GetName(), + ) } return trace.AccessDenied( @@ -248,7 +251,7 @@ func (a *Server) tryLockBotDueToGenerationMismatch(ctx context.Context, username }, UserMetadata: userMetadata, }); err != nil { - log.WithError(err).Warn("Failed to emit renewable cert generation mismatch event") + a.logger.WarnContext(ctx, "Failed to emit renewable cert generation mismatch event", "error", err) } return nil @@ -348,11 +351,11 @@ func (a *Server) updateBotInstance( authRecord.Generation = 1 } - log.WithFields(logrus.Fields{ - "bot_name": botName, - "invalid_instance_id": botInstanceID, - "new_instance_id": instanceID.String(), - }).Info("bot has no valid instance ID, a new instance will be generated") + a.logger.InfoContext(ctx, "bot has no valid instance ID, a new instance will be generated", + "bot_name", botName, + "invalid_instance_id", botInstanceID, + "new_instance_id", logutils.StringerAttr(instanceID), + ) expires := a.GetClock().Now().Add(req.ttl + machineidv1.ExpiryMargin) @@ -371,14 +374,14 @@ func (a *Server) updateBotInstance( return nil } - l := log.WithFields(logrus.Fields{ - "bot_name": botName, - "bot_instance_id": botInstanceID, - }) + log := a.logger.With( + "bot_name", botName, + "bot_instance_id", botInstanceID, + ) if currentIdentityGeneration == 0 { // Nothing to do. - l.Warn("bot attempted to fetch certificates without providing a current identity generation, this is not allowed") + log.WarnContext(ctx, "bot attempted to fetch certificates without providing a current identity generation, this is not allowed") return trace.AccessDenied("a current identity generation must be provided") } else if currentIdentityGeneration > 0 && currentIdentityGeneration != instanceGeneration { @@ -386,7 +389,7 @@ func (a *Server) updateBotInstance( // renewable (i.e. token) identities. if req.renewable { if err := a.tryLockBotDueToGenerationMismatch(ctx, username); err != nil { - l.WithError(err).Warn("Failed to lock bot when a generation mismatch was detected") + log.WarnContext(ctx, "Failed to lock bot when a generation mismatch was detected", "error", err) } return trace.AccessDenied( @@ -398,12 +401,13 @@ func (a *Server) updateBotInstance( // We'll still log the check failure, but won't deny access. This // log data will help make an informed decision about reliability of // the generation counter for all join methods in the future. - l.WithFields(logrus.Fields{ - "bot_instance_generation": instanceGeneration, - "bot_identity_generation": currentIdentityGeneration, - "bot_join_method": authRecord.JoinMethod, - }).Warn("Bot generation counter mismatch detected. This check is not enforced for this join method, " + - "but may indicate multiple uses of a bot identity and possibly a compromised certificate.") + const msg = "Bot generation counter mismatch detected. This check is not enforced for this join method, " + + "but may indicate multiple uses of a bot identity and possibly a compromised certificate." + log.WarnContext(ctx, msg, + "bot_instance_generation", instanceGeneration, + "bot_identity_generation", currentIdentityGeneration, + "bot_join_method", authRecord.JoinMethod, + ) } } @@ -419,7 +423,7 @@ func (a *Server) updateBotInstance( // setting this for other methods will break compatibility. if req.renewable { if err := a.commitLegacyGenerationCounterToBotUser(ctx, username, uint64(newGeneration)); err != nil { - l.WithError(err).Warn("unable to commit legacy generation counter to bot user") + log.WarnContext(ctx, "unable to commit legacy generation counter to bot user", "error", err) } } @@ -442,7 +446,7 @@ func (a *Server) updateBotInstance( // An initial auth record should have been added during initial join, // but if not, add it now. if bi.Status.InitialAuthentication == nil { - l.Warn("bot instance is missing its initial authentication record, a new one will be added") + log.WarnContext(ctx, "bot instance is missing its initial authentication record, a new one will be added") bi.Status.InitialAuthentication = authRecord } @@ -500,13 +504,16 @@ func (a *Server) generateInitialBotCerts( // permissions to read user data. userState, err := a.GetUserOrLoginState(ctx, username) if err != nil { - log.WithError(err).Debugf("Could not impersonate user %v. The user could not be fetched from local store.", username) + a.logger.DebugContext(ctx, "Could not impersonate user - the user could not be fetched from local store", + "error", err, + "user", username, + ) return nil, "", trace.AccessDenied("access denied") } // Do not allow SSO users to be impersonated. if userState.GetUserType() == types.UserTypeSSO { - log.Warningf("Tried to issue a renewable cert for externally managed user %v, this is not supported.", username) + a.logger.WarnContext(ctx, "Tried to issue a renewable cert for externally managed user, this is not supported", "user", username) return nil, "", trace.AccessDenied("access denied") } diff --git a/lib/auth/github.go b/lib/auth/github.go index a447f9dca3594..64a147f584a7a 100644 --- a/lib/auth/github.go +++ b/lib/auth/github.go @@ -167,8 +167,7 @@ func (a *Server) CreateGithubAuthRequest(ctx context.Context, req types.GithubAu config := newGithubOAuth2Config(connector) req.RedirectURL = config.AuthCodeURL(req.StateToken) - log.WithFields(logrus.Fields{teleport.ComponentKey: "github"}).Debugf( - "Redirect URL: %v.", req.RedirectURL) + a.logger.DebugContext(ctx, "Creating github auth request", "redirect_url", req.RedirectURL) req.SetExpiry(a.GetClock().Now().UTC().Add(defaults.GithubAuthRequestTTL)) err = a.Services.CreateGithubAuthRequest(ctx, req) if err != nil { @@ -197,7 +196,7 @@ func (a *Server) upsertGithubConnector(ctx context.Context, connector types.Gith }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - log.WithError(err).Warn("Failed to emit GitHub connector create event.") + a.logger.WarnContext(ctx, "Failed to emit GitHub connector create event", "error", err) } return upserted, nil @@ -224,7 +223,7 @@ func (a *Server) createGithubConnector(ctx context.Context, connector types.Gith }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - log.WithError(err).Warn("Failed to emit GitHub connector create event.") + a.logger.WarnContext(ctx, "Failed to emit GitHub connector create event", "error", err) } return created, nil @@ -251,7 +250,7 @@ func (a *Server) updateGithubConnector(ctx context.Context, connector types.Gith }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - log.WithError(err).Warn("Failed to emit GitHub connector update event.") + a.logger.WarnContext(ctx, "Failed to emit GitHub connector update event", "error", err) } return updated, nil @@ -407,7 +406,7 @@ func (a *Server) deleteGithubConnector(ctx context.Context, connectorName string }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - log.WithError(err).Warn("Failed to emit GitHub connector delete event.") + a.logger.WarnContext(ctx, "Failed to emit GitHub connector delete event", "error", err) } return nil @@ -433,10 +432,10 @@ type githubManager interface { // ValidateGithubAuthCallback validates Github auth callback redirect func (a *Server) ValidateGithubAuthCallback(ctx context.Context, q url.Values) (*authclient.GithubAuthResponse, error) { diagCtx := NewSSODiagContext(types.KindGithub, a) - return validateGithubAuthCallbackHelper(ctx, a, diagCtx, q, a.emitter) + return validateGithubAuthCallbackHelper(ctx, a, diagCtx, q, a.emitter, a.logger) } -func validateGithubAuthCallbackHelper(ctx context.Context, m githubManager, diagCtx *SSODiagContext, q url.Values, emitter apievents.Emitter) (*authclient.GithubAuthResponse, error) { +func validateGithubAuthCallbackHelper(ctx context.Context, m githubManager, diagCtx *SSODiagContext, q url.Values, emitter apievents.Emitter, logger *slog.Logger) (*authclient.GithubAuthResponse, error) { event := &apievents.UserLogin{ Metadata: apievents.Metadata{ Type: events.UserLoginEvent, @@ -456,7 +455,7 @@ func validateGithubAuthCallbackHelper(ctx context.Context, m githubManager, diag attributes, err := apievents.EncodeMapStrings(claims.OrganizationToTeams) if err != nil { event.Status.UserMessage = fmt.Sprintf("Failed to encode identity attributes: %v", err.Error()) - log.WithError(err).Debug("Failed to encode identity attributes.") + logger.DebugContext(ctx, "Failed to encode identity attributes", "error", err) } else { event.IdentityAttributes = attributes } @@ -472,7 +471,7 @@ func validateGithubAuthCallbackHelper(ctx context.Context, m githubManager, diag event.Status.UserMessage = err.Error() if err := emitter.EmitAuditEvent(ctx, event); err != nil { - log.WithError(err).Warn("Failed to emit GitHub login failed event.") + logger.WarnContext(ctx, "Failed to emit GitHub login failed event", "error", err) } return nil, trace.Wrap(err) } @@ -484,7 +483,7 @@ func validateGithubAuthCallbackHelper(ctx context.Context, m githubManager, diag event.User = auth.Username if err := emitter.EmitAuditEvent(ctx, event); err != nil { - log.WithError(err).Warn("Failed to emit GitHub login event.") + logger.WarnContext(ctx, "Failed to emit GitHub login event", "error", err) } return auth, nil @@ -602,6 +601,16 @@ func (a *Server) validateGithubAuthCallback(ctx context.Context, diagCtx *SSODia if err != nil { return nil, trace.Wrap(err, "Failed to query GitHub API for user claims.") } + + logger.DebugContext(ctx, "Retrieved GitHub claims", + slog.Group("claims", + slog.String("user_name", claims.Username), + slog.String("user_id", claims.UserID), + slog.Any("organization_to_teams", claims.Teams), + slog.Any("roles", claims.OrganizationToTeams), + ), + ) + diagCtx.Info.GithubClaims = claims // Calculate (figure out name, roles, traits, session TTL) of user and @@ -945,9 +954,12 @@ func (a *Server) calculateGithubUser(ctx context.Context, diagCtx *SSODiagContex } func (a *Server) createGithubUser(ctx context.Context, p *CreateUserParams, dryRun bool) (types.User, error) { - log.WithFields(logrus.Fields{teleport.ComponentKey: "github"}).Debugf( - "Generating dynamic GitHub identity %v/%v with roles: %v. Dry run: %v.", - p.ConnectorName, p.Username, p.Roles, dryRun) + a.logger.DebugContext(ctx, "Generating dynamic GitHub identity", + "connector_name", p.ConnectorName, + "user_name", p.Username, + "role", p.Roles, + "dry_run", dryRun, + ) expires := a.GetClock().Now().UTC().Add(p.SessionTTL) @@ -1125,15 +1137,12 @@ func populateGithubClaims(user *GithubUserResponse, teams []GithubTeamResponse) return nil, trace.AccessDenied( "list of user teams is empty, did you grant access?") } - claims := &types.GithubClaims{ + return &types.GithubClaims{ Username: user.Login, OrganizationToTeams: orgToTeams, Teams: teamList, UserID: user.getIDStr(), - } - log.WithFields(logrus.Fields{teleport.ComponentKey: "github"}).Debugf( - "Claims: %#v.", claims) - return claims, nil + }, nil } // githubAPIClient is a tiny wrapper around some of Github APIs @@ -1223,11 +1232,11 @@ func (c *githubAPIClient) getTeams(ctx context.Context) ([]GithubTeamResponse, e // of pages, print an error when it does happen, and return the results up // to that point. if count > MaxPages { - warningMessage := "Truncating list of teams used to populate claims: " + + const warningMessage = "Truncating list of teams used to populate claims: " + "hit maximum number pages that can be fetched from GitHub." // Print warning to Teleport logs as well as the Audit Log. - log.Warn(warningMessage) + c.authServer.logger.WarnContext(ctx, warningMessage) if err := c.authServer.emitter.EmitAuditEvent(c.authServer.closeCtx, &apievents.UserLogin{ Metadata: apievents.Metadata{ Type: events.UserLoginEvent, @@ -1240,7 +1249,7 @@ func (c *githubAPIClient) getTeams(ctx context.Context) ([]GithubTeamResponse, e }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - log.WithError(err).Warn("Failed to emit GitHub login failure event.") + c.authServer.logger.WarnContext(ctx, "Failed to emit GitHub login failure event", "error", err) } return result, nil } diff --git a/lib/auth/github_test.go b/lib/auth/github_test.go index 56d33fcf91711..862f3ce2d03c0 100644 --- a/lib/auth/github_test.go +++ b/lib/auth/github_test.go @@ -188,6 +188,7 @@ func TestValidateGithubAuthCallbackEventsEmitted(t *testing.T) { clientAddr := &net.TCPAddr{IP: net.IPv4(10, 255, 0, 0)} ctx := authz.ContextWithClientSrcAddr(context.Background(), clientAddr) tt := setupGithubContext(ctx, t) + logger := utils.NewSlogLoggerForTests() auth := &authclient.GithubAuthResponse{ Username: "test-name", @@ -220,7 +221,7 @@ func TestValidateGithubAuthCallbackEventsEmitted(t *testing.T) { diagCtx.Info.AppliedLoginRules = []string{"login-rule"} return auth, nil } - _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter) + _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter, logger) require.Equal(t, events.UserLoginEvent, tt.mockEmitter.LastEvent().GetType()) require.Equal(t, events.UserSSOLoginCode, tt.mockEmitter.LastEvent().GetCode()) loginEvt := tt.mockEmitter.LastEvent().(*apievents.UserLogin) @@ -235,7 +236,7 @@ func TestValidateGithubAuthCallbackEventsEmitted(t *testing.T) { diagCtx.Info.GithubClaims = claims return auth, trace.BadParameter("") } - _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter) + _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter, logger) require.Equal(t, events.UserLoginEvent, tt.mockEmitter.LastEvent().GetType()) require.Equal(t, events.UserSSOLoginFailureCode, tt.mockEmitter.LastEvent().GetCode()) loginEvt = tt.mockEmitter.LastEvent().(*apievents.UserLogin) @@ -248,7 +249,7 @@ func TestValidateGithubAuthCallbackEventsEmitted(t *testing.T) { diagCtx.Info.GithubClaims = claims return auth, nil } - _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter) + _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter, logger) require.Equal(t, events.UserLoginEvent, tt.mockEmitter.LastEvent().GetType()) require.Equal(t, events.UserSSOTestFlowLoginCode, tt.mockEmitter.LastEvent().GetCode()) loginEvt = tt.mockEmitter.LastEvent().(*apievents.UserLogin) @@ -262,7 +263,7 @@ func TestValidateGithubAuthCallbackEventsEmitted(t *testing.T) { diagCtx.Info.GithubClaims = claims return auth, trace.BadParameter("") } - _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter) + _, _ = validateGithubAuthCallbackHelper(ctx, m, diagCtx, nil, tt.a.emitter, logger) require.Equal(t, events.UserLoginEvent, tt.mockEmitter.LastEvent().GetType()) require.Equal(t, events.UserSSOTestFlowLoginFailureCode, tt.mockEmitter.LastEvent().GetCode()) loginEvt = tt.mockEmitter.LastEvent().(*apievents.UserLogin) diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index c7c8900f5c82a..d5dfc1f553f2b 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "os" "strconv" @@ -34,7 +35,6 @@ import ( "github.com/gravitational/trace" "github.com/gravitational/trace/trail" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" collectortracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -123,6 +123,7 @@ import ( "github.com/gravitational/teleport/lib/srv/server/installer" usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) var ( @@ -179,7 +180,7 @@ var ( type GRPCServer struct { authpb.UnimplementedAuthServiceServer auditlogpb.UnimplementedAuditLogServiceServer - *logrus.Entry + logger *slog.Logger APIConfig server *grpc.Server @@ -256,11 +257,11 @@ func (g *GRPCServer) SendKeepAlives(stream authpb.AuthService_SendKeepAlivesServ } keepAlive, err := stream.Recv() if errors.Is(err, io.EOF) { - g.Logger.Debug("Connection closed.") + g.logger.DebugContext(stream.Context(), "Connection closed") return nil } if err != nil { - g.Logger.Debugf("Failed to receive heartbeat: %v", err) + g.logger.DebugContext(stream.Context(), "Failed to receive heartbeat", "error", err) return trace.Wrap(err) } err = auth.KeepAliveServer(stream.Context(), *keepAlive) @@ -268,7 +269,10 @@ func (g *GRPCServer) SendKeepAlives(stream authpb.AuthService_SendKeepAlivesServ return trace.Wrap(err) } if firstIteration { - g.Logger.Debugf("Got %s heartbeat connection from %v.", keepAlive.GetType(), auth.User.GetName()) + g.logger.DebugContext(stream.Context(), "Got heartbeat connection", + "heartbeat_type", keepAlive.GetType(), + "identity", auth.User.GetName(), + ) heartbeatConnectionsReceived.Inc() metric, ok := connectedResourceGauges[keepAlive.GetType()] @@ -276,7 +280,7 @@ func (g *GRPCServer) SendKeepAlives(stream authpb.AuthService_SendKeepAlivesServ metric.Inc() defer metric.Dec() } else { - g.Logger.Warnf("missing connected resources gauge for keep alive %s (this is a bug)", keepAlive.GetType()) + g.logger.WarnContext(stream.Context(), "missing connected resources gauge for keep alive (this is a bug)", "heartbeat_type", keepAlive.GetType()) } firstIteration = false @@ -308,7 +312,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre var eventStream apievents.Stream var sessionID session.ID - g.Debugf("CreateAuditStream connection from %v.", auth.User.GetName()) + g.logger.DebugContext(stream.Context(), "CreateAuditStream connection", "identity", auth.User.GetName()) streamStart := time.Now() processed := int64(0) counter := 0 @@ -319,7 +323,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre return case statusUpdate := <-eventStream.Status(): if err := stream.Send(&statusUpdate); err != nil { - g.WithError(err).Debugf("Failed to send status update.") + g.logger.DebugContext(stream.Context(), "Failed to send status update", "error", err) } } } @@ -328,10 +332,10 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre closeStream := func(eventStream apievents.Stream) { if err := eventStream.Close(auth.CloseContext()); err != nil { if auth.CloseContext().Err() == nil { - g.WithError(err).Warn("Failed to flush close the stream.") + g.logger.WarnContext(stream.Context(), "Failed to flush close the stream", "error", err) } } else { - g.Debugf("Flushed and closed the stream.") + g.logger.DebugContext(stream.Context(), "Flushed and closed the stream") } } @@ -342,7 +346,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre } if err != nil { if stream.Context().Err() == nil { - g.WithError(err).Debug("Failed to receive stream request.") + g.logger.DebugContext(stream.Context(), "Failed to receive stream request", "error", err) } return trace.Wrap(err) } @@ -355,11 +359,11 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre // Log the reason why audit stream creation failed. This will // surface things like AWS/GCP/MinIO credential/configuration // errors. - g.Errorf("Failed to create audit stream: %q.", err) + g.logger.ErrorContext(stream.Context(), "Failed to create audit stream", "error", err) return trace.Wrap(err) } sessionID = session.ID(create.SessionID) - g.Debugf("Created stream for session %v", sessionID) + g.logger.DebugContext(stream.Context(), "Created stream for session", "session_id", sessionID) go forwardEvents(eventStream) defer closeStream(eventStream) } else if resume := request.GetResumeStream(); resume != nil { @@ -370,7 +374,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre if err != nil { return trace.Wrap(err) } - g.Debugf("Resumed stream for session %v", resume.SessionID) + g.logger.DebugContext(stream.Context(), "Resumed stream for session", "session_id", resume.SessionID) go forwardEvents(eventStream) defer closeStream(eventStream) } else if complete := request.GetCompleteStream(); complete != nil { @@ -408,7 +412,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre return trace.Wrap(err) } } - g.Debugf("Completed stream for session %v", sessionID) + g.logger.DebugContext(stream.Context(), "Completed stream for session", "session_id", sessionID) return nil } else if flushAndClose := request.GetFlushAndCloseStream(); flushAndClose != nil { if eventStream == nil { @@ -422,7 +426,7 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre } event, err := apievents.FromOneOf(*oneof) if err != nil { - g.WithError(err).Debug("Failed to decode event.") + g.logger.DebugContext(stream.Context(), "Failed to decode event", "error", err) return trace.Wrap(err) } // Currently only api/client.auditStreamer calls with an event @@ -451,8 +455,15 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre if err != nil { switch { case events.IsPermanentEmitError(err): - g.WithError(err).WithField("event", event). - Error("Failed to EmitAuditEvent due to a permanent error. Event wil be omitted.") + g.logger.ErrorContext(stream.Context(), "Failed to EmitAuditEvent due to a permanent error, event wil be omitted", + slog.Any("error", err), + slog.Group("event", + slog.String("type", event.GetType()), + slog.String("code", event.GetCode()), + slog.String("id", event.GetID()), + slog.Int64("index", event.GetIndex()), + ), + ) continue default: return trace.Wrap(err) @@ -465,15 +476,18 @@ func (g *GRPCServer) CreateAuditStream(stream authpb.AuthService_CreateAuditStre if counter%logInterval == 0 { if seconds > 0 { kbytes := float64(processed) / 1000 - g.Debugf("Processed %v events, tx rate kbytes %v/second.", counter, kbytes/float64(seconds)) + g.logger.DebugContext(stream.Context(), "Processed events", "event_count", counter, "tx_rate", kbytes/float64(seconds)) } } diff := time.Since(start) if diff > 100*time.Millisecond { - g.Warningf("RecordEvent(%v) took longer than 100ms: %v", event.GetType(), time.Since(event.GetTime())) + g.logger.WarnContext(stream.Context(), "RecordEvent took longer than 100ms", + "event_type", event.GetType(), + "duration", time.Since(event.GetTime()), + ) } } else { - g.Errorf("Rejecting unsupported stream request: %v.", request) + g.logger.ErrorContext(stream.Context(), "Rejecting unsupported stream request", "request", request) return trace.BadParameter("unsupported stream request") } } @@ -569,7 +583,7 @@ func (g *GRPCServer) GenerateUserCerts(ctx context.Context, req *authpb.UserCert return nil, trace.Wrap(err) } if err := validateUserCertsRequest(auth, req); err != nil { - g.Entry.Debugf("Validation of user certs request failed: %v", err) + g.logger.DebugContext(ctx, "Validation of user certs request failed", "error", err) return nil, trace.Wrap(err) } @@ -645,7 +659,7 @@ func (g *GRPCServer) generateUserSingleUseCerts(ctx context.Context, actx *grpcC actx, *req) if err != nil { - g.Entry.Warningf("Failed to generate single-use cert: %v", err) + g.logger.WarnContext(ctx, "Failed to generate single-use cert", "error", err) return nil, trace.Wrap(err) } @@ -806,7 +820,10 @@ func (g *GRPCServer) GetInstances(filter *types.InstanceFilter, stream authpb.Au for instances.Next() { instance, ok := instances.Item().(*types.InstanceV1) if !ok { - log.Warnf("Skipping unexpected instance type %T, expected %T.", instances.Item(), instance) + g.logger.WarnContext(stream.Context(), "Skipping unexpected instance type", + "instance_type", logutils.TypeAttr(instances.Item()), + "expected_instance_type", logutils.TypeAttr(instance), + ) continue } if err := stream.Send(instance); err != nil { @@ -904,7 +921,10 @@ func (g *GRPCServer) GetCurrentUserRoles(_ *emptypb.Empty, stream authpb.AuthSer for _, role := range roles { v6, ok := role.(*types.RoleV6) if !ok { - log.Warnf("expected type RoleV6, got %T for role %q", role, role.GetName()) + g.logger.WarnContext(stream.Context(), "expected type RoleV6, got unexpected for role type", + "role_type", logutils.TypeAttr(role), + "role", role.GetName(), + ) return trace.Errorf("encountered unexpected role type") } if err := stream.Send(v6); err != nil { @@ -2097,7 +2117,10 @@ func (g *GRPCServer) ListRoles(ctx context.Context, req *authpb.ListRolesRequest for _, role := range rsp.Roles { downgraded, err := maybeDowngradeRole(ctx, role) if err != nil { - log.Warnf("Failed to downgrade role %q, this is a bug and may result in spurious access denied errors. err=%q", role.GetName(), err) + g.logger.WarnContext(ctx, "Failed to downgrade role, this is a bug and may result in spurious access denied errors", + "role", role.GetName(), + "error", err, + ) continue } downgradedRoles = append(downgradedRoles, downgraded) @@ -2132,11 +2155,14 @@ func (g *GRPCServer) CreateRole(ctx context.Context, req *authpb.CreateRoleReque return nil, trace.Wrap(err) } - g.Debugf("%q role upserted", req.Role.GetName()) + g.logger.DebugContext(ctx, "role upserted", "role_name", req.Role.GetName()) v6, ok := created.(*types.RoleV6) if !ok { - log.Warnf("expected type RoleV6, got %T for role %q", created, created.GetName()) + g.logger.WarnContext(ctx, "expected type RoleV6, got unexpected type", + "role_type", logutils.TypeAttr(created), + "role", created.GetName(), + ) return nil, trace.BadParameter("encountered unexpected role type") } @@ -2168,11 +2194,14 @@ func (g *GRPCServer) UpdateRole(ctx context.Context, req *authpb.UpdateRoleReque return nil, trace.Wrap(err) } - g.Debugf("%q role upserted", req.Role.GetName()) + g.logger.DebugContext(ctx, "role upserted", "role", req.Role.GetName()) v6, ok := updated.(*types.RoleV6) if !ok { - log.Warnf("expected type RoleV6, got %T for role %q", updated, updated.GetName()) + g.logger.WarnContext(ctx, "expected type RoleV6, got unexpected type", + "role_type", logutils.TypeAttr(updated), + "role", updated.GetName(), + ) return nil, trace.BadParameter("encountered unexpected role type") } @@ -2204,11 +2233,14 @@ func (g *GRPCServer) UpsertRoleV2(ctx context.Context, req *authpb.UpsertRoleReq return nil, trace.Wrap(err) } - g.Debugf("%q role upserted", req.Role.GetName()) + g.logger.DebugContext(ctx, "role upserted", "role", req.Role.GetName()) v6, ok := upserted.(*types.RoleV6) if !ok { - log.Warnf("expected type RoleV6, got %T for role %q", upserted, upserted.GetName()) + g.logger.WarnContext(ctx, "expected type RoleV6, got unexpected type", + "role_type", logutils.TypeAttr(upserted), + "role", upserted.GetName(), + ) return nil, trace.BadParameter("encountered unexpected role type") } @@ -2231,7 +2263,7 @@ func (g *GRPCServer) DeleteRole(ctx context.Context, req *authpb.DeleteRoleReque return nil, trace.Wrap(err) } - g.Debugf("%q role deleted", req.GetName()) + g.logger.DebugContext(ctx, "role deleted", "role", req.GetName()) return &emptypb.Empty{}, nil } @@ -2907,7 +2939,10 @@ func (g *GRPCServer) GetServerInfos(_ *emptypb.Empty, stream authpb.AuthService_ for infos.Next() { si, ok := infos.Item().(*types.ServerInfoV1) if !ok { - log.Warnf("Skipping unexpected instance type %T, expected %T.", infos.Item(), si) + g.logger.WarnContext(stream.Context(), "expected type ServerInfoV1, got unexpected type", + "server_info_type", logutils.TypeAttr(infos.Item()), + "server_info_name", infos.Item().GetName(), + ) } if err := stream.Send(si); err != nil { infos.Done() @@ -3014,6 +3049,8 @@ func (g *GRPCServer) GetTrustedClusters(ctx context.Context, _ *emptypb.Empty) ( } // UpsertTrustedCluster upserts a Trusted Cluster. +// +// Deprecated: Use UpsertTrustedClusterV2 instead. func (g *GRPCServer) UpsertTrustedCluster(ctx context.Context, cluster *types.TrustedClusterV2) (*types.TrustedClusterV2, error) { auth, err := g.authenticate(ctx) if err != nil { @@ -3836,7 +3873,7 @@ func (g *GRPCServer) UpsertWindowsDesktopService(ctx context.Context, service *t // the closest thing we have to a public IP for the service. clientAddr, err := authz.ClientSrcAddrFromContext(ctx) if err != nil { - g.Logger.WithError(err).Warn("error getting client address from context") + g.logger.WarnContext(ctx, "error getting client address from context", "error", err) return nil, status.Errorf(codes.FailedPrecondition, "client address not found in request context") } service.Spec.Addr = utils.ReplaceLocalhost(service.GetAddr(), clientAddr.String()) @@ -4200,6 +4237,21 @@ func (g *GRPCServer) GetSSHTargets(ctx context.Context, req *authpb.GetSSHTarget return rsp, nil } +// ResolveSSHTarget gets a server that would match an equivalent ssh dial request. +func (g *GRPCServer) ResolveSSHTarget(ctx context.Context, req *authpb.ResolveSSHTargetRequest) (*authpb.ResolveSSHTargetResponse, error) { + auth, err := g.authenticate(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + rsp, err := auth.ServerWithRoles.ResolveSSHTarget(ctx, req) + if err != nil { + return nil, trace.Wrap(err) + } + + return rsp, nil +} + // CreateSessionTracker creates a tracker resource for an active session. func (g *GRPCServer) CreateSessionTracker(ctx context.Context, req *authpb.CreateSessionTrackerRequest) (*types.SessionTrackerV1, error) { auth, err := g.authenticate(ctx) @@ -4208,7 +4260,7 @@ func (g *GRPCServer) CreateSessionTracker(ctx context.Context, req *authpb.Creat } if req.SessionTracker == nil { - g.Errorf("Missing SessionTracker in CreateSessionTrackerRequest. This can be caused by an outdated Teleport node running against your cluster.") + g.logger.ErrorContext(ctx, "Missing SessionTracker in CreateSessionTrackerRequest, this can be caused by an outdated Teleport node running against your cluster") return nil, trace.BadParameter("missing SessionTracker from CreateSessionTrackerRequest") } @@ -5063,7 +5115,13 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { if err := cfg.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - log.Debugf("gRPC(SERVER): keep alive %v count: %v.", cfg.KeepAlivePeriod, cfg.KeepAliveCount) + + logger := slog.With(teleport.ComponentKey, teleport.Component(teleport.ComponentAuth, teleport.ComponentGRPC)) + + logger.DebugContext(context.Background(), "creating gRPC server", + "keep_alive_period", cfg.KeepAlivePeriod, + "keep_alive_count", cfg.KeepAliveCount, + ) // httplib.TLSCreds are explicitly used instead of credentials.NewTLS because the latter // modifies the tls.Config.NextProtos which causes problems due to multiplexing on the auth @@ -5104,6 +5162,7 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { Emitter: cfg.Emitter, Reporter: cfg.AuthServer.Services.UsageReporter, Clock: cfg.AuthServer.GetClock(), + Logger: cfg.AuthServer.logger.With(teleport.ComponentKey, "users.service"), }) if err != nil { return nil, trace.Wrap(err) @@ -5118,6 +5177,7 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { Emitter: cfg.Emitter, Reporter: cfg.AuthServer.Services.UsageReporter, Clock: cfg.AuthServer.GetClock(), + Logger: cfg.AuthServer.logger.With(teleport.ComponentKey, "presence.service"), }) if err != nil { return nil, trace.Wrap(err) @@ -5225,20 +5285,18 @@ func NewGRPCServer(cfg GRPCServerConfig) (*GRPCServer, error) { authServer := &GRPCServer{ APIConfig: cfg.APIConfig, - Entry: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.Component(teleport.ComponentAuth, teleport.ComponentGRPC), - }), - server: server, + logger: logger, + server: server, } if en := os.Getenv("TELEPORT_UNSTABLE_CREATEAUDITSTREAM_INFLIGHT_LIMIT"); en != "" { inflightLimit, err := strconv.ParseInt(en, 10, 64) if err != nil { - log.Error("Failed to parse the TELEPORT_UNSTABLE_CREATEAUDITSTREAM_INFLIGHT_LIMIT envvar, limit will not be enforced.") + logger.ErrorContext(context.Background(), "Failed to parse the TELEPORT_UNSTABLE_CREATEAUDITSTREAM_INFLIGHT_LIMIT envvar, limit will not be enforced") inflightLimit = -1 } if inflightLimit == 0 { - log.Warn("TELEPORT_UNSTABLE_CREATEAUDITSTREAM_INFLIGHT_LIMIT is set to 0, no CreateAuditStream RPCs will be allowed.") + logger.WarnContext(context.Background(), "TELEPORT_UNSTABLE_CREATEAUDITSTREAM_INFLIGHT_LIMIT is set to 0, no CreateAuditStream RPCs will be allowed") } metrics.RegisterPrometheusCollectors( createAuditStreamAcceptedTotalMetric, diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index 8a91f952e001e..c92e521e386c0 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -2988,6 +2988,69 @@ func TestGetSSHTargets(t *testing.T) { require.ElementsMatch(t, []string{rsp.Servers[0].GetHostname(), rsp.Servers[1].GetHostname()}, []string{"foo", "Foo"}) } +func TestResolveSSHTarget(t *testing.T) { + t.Parallel() + ctx := context.Background() + srv := newTestTLSServer(t) + + clt, err := srv.NewClient(TestAdmin()) + require.NoError(t, err) + + upper, err := types.NewServerWithLabels(uuid.New().String(), types.KindNode, types.ServerSpecV2{ + Hostname: "Foo", + UseTunnel: true, + }, nil) + require.NoError(t, err) + upper.SetExpiry(time.Now().Add(time.Hour)) + + lower, err := types.NewServerWithLabels(uuid.New().String(), types.KindNode, types.ServerSpecV2{ + Hostname: "foo", + UseTunnel: true, + }, nil) + require.NoError(t, err) + + other, err := types.NewServerWithLabels(uuid.New().String(), types.KindNode, types.ServerSpecV2{ + Hostname: "bar", + UseTunnel: true, + }, nil) + require.NoError(t, err) + + for _, node := range []types.Server{upper, lower, other} { + _, err = clt.UpsertNode(ctx, node) + require.NoError(t, err) + } + + rsp, err := clt.ResolveSSHTarget(ctx, &proto.ResolveSSHTargetRequest{ + Host: "foo", + Port: "0", + }) + require.NoError(t, err) + require.Equal(t, "foo", rsp.Server.GetHostname()) + + cnc := types.DefaultClusterNetworkingConfig() + cnc.SetCaseInsensitiveRouting(true) + _, err = clt.UpsertClusterNetworkingConfig(ctx, cnc) + require.NoError(t, err) + + rsp, err = clt.ResolveSSHTarget(ctx, &proto.ResolveSSHTargetRequest{ + Host: "foo", + Port: "0", + }) + require.Error(t, err) + require.Nil(t, rsp) + + cnc.SetRoutingStrategy(types.RoutingStrategy_MOST_RECENT) + _, err = clt.UpsertClusterNetworkingConfig(ctx, cnc) + require.NoError(t, err) + + rsp, err = clt.ResolveSSHTarget(ctx, &proto.ResolveSSHTargetRequest{ + Host: "foo", + Port: "0", + }) + require.NoError(t, err) + require.Equal(t, "Foo", rsp.Server.GetHostname()) +} + func TestNodesCRUD(t *testing.T) { t.Parallel() ctx := context.Background() diff --git a/lib/auth/init.go b/lib/auth/init.go index 215dd4aaae512..3e0c0fbe1a970 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -71,11 +71,13 @@ import ( "github.com/gravitational/teleport/lib/tlsca" usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentAuth, -}) +var ( + log = logrus.WithField(teleport.ComponentKey, teleport.ComponentAuth) + logger = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentAuth) +) // VersionStorage local storage for saving the version. type VersionStorage interface { @@ -401,7 +403,7 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { // on initial startup. if len(cfg.BootstrapResources) > 0 { if firstStart { - log.Infof("Applying %v bootstrap resources (first initialization)", len(cfg.BootstrapResources)) + asrv.logger.InfoContext(ctx, "Applying bootstrap resources (first initialization)", "resource_count", len(cfg.BootstrapResources)) if err := checkResourceConsistency(ctx, asrv.keyStore, domainName, cfg.BootstrapResources...); err != nil { return trace.Wrap(err, "refusing to bootstrap backend") } @@ -409,13 +411,13 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { return trace.Wrap(err, "backend bootstrap failed") } } else { - log.Warnf("Ignoring %v bootstrap resources (previously initialized)", len(cfg.BootstrapResources)) + asrv.logger.WarnContext(ctx, "Ignoring bootstrap resources (previously initialized)", "resource_count", len(cfg.BootstrapResources)) } } // if apply-on-startup resources are supplied, apply them if len(cfg.ApplyOnStartupResources) > 0 { - log.Infof("Applying %v resources (apply-on-startup)", len(cfg.ApplyOnStartupResources)) + asrv.logger.InfoContext(ctx, "Applying resources (apply-on-startup)", "resource_count", len(cfg.ApplyOnStartupResources)) if err := applyResources(ctx, asrv.Services, cfg.ApplyOnStartupResources); err != nil { return trace.Wrap(err, "applying resources failed") @@ -432,7 +434,7 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { if _, err := asrv.UpsertRole(ctx, role); err != nil { return trace.Wrap(err) } - log.Infof("Created role: %v.", role) + asrv.logger.InfoContext(ctx, "Created role", "role", role.GetName()) } for i := range cfg.Authorities { ca := cfg.Authorities[i] @@ -450,14 +452,17 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { return trace.Wrap(err) } } else { - log.Infof("Created trusted certificate authority: %q, type: %q.", ca.GetName(), ca.GetType()) + asrv.logger.InfoContext(ctx, "Created trusted certificate authority", + "ca_name", ca.GetName(), + "ca_type", ca.GetType(), + ) } } for _, tunnel := range cfg.ReverseTunnels { if err := asrv.UpsertReverseTunnel(ctx, tunnel); err != nil { return trace.Wrap(err) } - log.Infof("Created reverse tunnel: %v.", tunnel) + asrv.logger.InfoContext(ctx, "Created reverse tunnel", "tunnel", tunnel.GetName()) } g, gctx := errgroup.WithContext(ctx) @@ -494,14 +499,14 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { g.Go(func() error { _, span := cfg.Tracer.Start(gctx, "auth/SetStaticTokens") defer span.End() - log.Infof("Updating cluster configuration: %v.", cfg.StaticTokens) + asrv.logger.InfoContext(ctx, "Updating cluster configuration", "static_tokens", cfg.StaticTokens) return trace.Wrap(asrv.SetStaticTokens(cfg.StaticTokens)) }) g.Go(func() error { _, span := cfg.Tracer.Start(gctx, "auth/SetClusterNamespace") defer span.End() - log.Infof("Creating namespace: %q.", apidefaults.Namespace) + asrv.logger.InfoContext(ctx, "Creating namespace", "namespace", apidefaults.Namespace) return trace.Wrap(asrv.UpsertNamespace(types.DefaultNamespace())) }) @@ -530,18 +535,18 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { return trace.Wrap(err) } if cn.GetClusterName() != cfg.ClusterName.GetClusterName() { - msg := "Cannot rename cluster: continuing with current cluster name. Teleport " + + const msg = "Cannot rename cluster: continuing with current cluster name. Teleport " + "clusters can not be renamed once they are created. You are seeing this " + "message for one of two reasons. Either you have not set \"cluster_name\" in " + "Teleport configuration and changed the hostname of the auth server or you " + "are trying to change the value of \"cluster_name\"." - log.WithFields(logrus.Fields{ - "current_cluster_name": cn.GetClusterName(), - "configured_cluster_name": cfg.ClusterName.GetClusterName(), - }).Error(msg) + asrv.logger.ErrorContext(ctx, msg, + "current_cluster_name", cn.GetClusterName(), + "configured_cluster_name", cfg.ClusterName.GetClusterName(), + ) } - log.Debugf("Cluster configuration: %v.", cn.GetClusterName()) + asrv.logger.DebugContext(ctx, "Cluster configuration", "cluster_name", cn.GetClusterName()) return nil }) @@ -563,10 +568,10 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { } if lib.IsInsecureDevMode() { - warningMessage := "Starting teleport in insecure mode. This is " + + const warningMessage = "Starting teleport in insecure mode. This is " + "dangerous! Sensitive information will be logged to console and " + "certificates will not be verified. Proceed with caution!" - log.Warn(warningMessage) + asrv.logger.WarnContext(ctx, warningMessage) } span.AddEvent("migrating legacy resources") @@ -593,18 +598,18 @@ func initCluster(ctx context.Context, cfg InitConfig, asrv *Server) error { span.AddEvent("creating preset database object import rules") if err := createPresetDatabaseObjectImportRule(ctx, asrv); err != nil { // merely raise a warning; this is not a fatal error. - log.WithError(err).Warn("error creating preset database object import rules") + asrv.logger.WarnContext(ctx, "error creating preset database object import rules", "error", err) } span.AddEvent("completed creating database object import rules") } else { - log.Info("skipping preset role and user creation") + asrv.logger.InfoContext(ctx, "skipping preset role and user creation") } if !cfg.SkipPeriodicOperations { - log.Infof("Auth server is running periodic operations.") + asrv.logger.InfoContext(ctx, "Auth server is running periodic operations") go asrv.runPeriodicOperations() } else { - log.Infof("Auth server is skipping periodic operations.") + asrv.logger.InfoContext(ctx, "Auth server is skipping periodic operations") } return nil @@ -650,7 +655,7 @@ func initializeAuthorities(ctx context.Context, asrv *Server, cfg *InitConfig) e // Key deletion is best-effort, log a warning if it fails and carry on. // We don't want to prevent a CA rotation, which may be necessary in // some cases where this would fail. - log.Warnf("An attempt to clean up unused HSM or KMS CA keys has failed unexpectedly: %v", err) + asrv.logger.WarnContext(ctx, "An attempt to clean up unused HSM or KMS CA keys has failed unexpectedly", "error", err) } return nil } @@ -662,7 +667,7 @@ func initializeAuthority(ctx context.Context, asrv *Server, caID types.CertAuthI return nil, nil, trace.Wrap(err) } - log.Infof("First start: generating %s certificate authority.", caID.Type) + asrv.logger.InfoContext(ctx, "First start: generating certificate authority", "ca_type", caID.Type) if ca, err = generateAuthority(ctx, asrv, caID); err != nil { return nil, nil, trace.Wrap(err) } @@ -705,28 +710,34 @@ func initializeAuthority(ctx context.Context, asrv *Server, caID types.CertAuthI return nil, nil, trace.Wrap(err) } } else { - log.Warnf("This Auth Service is configured to use %s but the %s CA contains only %s. "+ - "No new certificates can be signed with the existing keys. "+ - "You must perform a CA rotation to generate new keys, or adjust your configuration to use the existing keys.", - usableKeysResult.PreferredKeyType, - caID.Type, - strings.Join(usableKeysResult.CAKeyTypes, " and ")) + const msg = "This Auth Service is configured to use key types that the CA does not contain. " + + "No new certificates can be signed with the existing keys. " + + "You must perform a CA rotation to generate new keys, or adjust your configuration to use the existing keys." + asrv.logger.WarnContext(ctx, msg, + "configured_key_type", usableKeysResult.PreferredKeyType, + "ca_type", caID.Type, + "available_key_types", usableKeysResult.CAKeyTypes, + ) } } else if !usableKeysResult.CAHasPreferredKeyType { - log.Warnf("This Auth Service is configured to use %s but the %s CA contains only %s. "+ - "New certificates will continue to be signed with raw software keys but you must perform a CA rotation to begin using %s.", - usableKeysResult.PreferredKeyType, - caID.Type, - strings.Join(usableKeysResult.CAKeyTypes, " and "), - usableKeysResult.PreferredKeyType) + const msg = "This Auth Service is configured to use key types that the CA does not contain. " + + "New certificates will continue to be signed with raw software keys but you must perform a CA rotation to begin using the new key type." + asrv.logger.WarnContext(ctx, msg, + "configured_key_type", usableKeysResult.PreferredKeyType, + "ca_type", caID.Type, + "available_key_types", usableKeysResult.CAKeyTypes, + ) } allKeyTypes := ca.AllKeyTypes() numKeyTypes := len(allKeyTypes) if numKeyTypes > 1 { - log.Warnf("%s CA contains a combination of %s and %s keys. If you are attempting to"+ - " configure HSM or KMS key storage, make sure it is configured on all auth servers in"+ - " this cluster and then perform a CA rotation: https://goteleport.com/docs/management/operations/ca-rotation/", - caID.Type, strings.Join(allKeyTypes[:numKeyTypes-1], ", "), allKeyTypes[numKeyTypes-1]) + const msg = "CA contains a combination of key typess. If you are attempting to" + + " configure HSM or KMS key storage, make sure it is configured on all auth servers in" + + " this cluster and then perform a CA rotation: https://goteleport.com/docs/management/operations/ca-rotation/" + asrv.logger.WarnContext(ctx, msg, + "ca_type", caID.Type, + "key_types", []string{strings.Join(allKeyTypes[:numKeyTypes-1], ", "), allKeyTypes[numKeyTypes-1]}, + ) } for _, keySet := range []types.CAKeySet{ca.GetActiveKeys(), ca.GetAdditionalTrustedKeys()} { @@ -785,7 +796,7 @@ func initializeAuthPreference(ctx context.Context, asrv *Server, newAuthPref typ return trace.Wrap(err) } - shouldReplace, err := shouldInitReplaceResourceWithOrigin(storedAuthPref, newAuthPref) + shouldReplace, err := shouldInitReplaceResourceWithOrigin(ctx, storedAuthPref, newAuthPref, asrv.logger) if err != nil { return trace.Wrap(err) } @@ -830,7 +841,7 @@ func initializeAuthPreference(ctx context.Context, asrv *Server, newAuthPref typ } if storedAuthPref == nil { - log.Infof("Creating cluster auth preference: %v.", newAuthPref) + asrv.logger.InfoContext(ctx, "Creating cluster auth preference", "auth_preference", newAuthPref) _, err := asrv.CreateAuthPreference(ctx, newAuthPref) if trace.IsAlreadyExists(err) { continue @@ -861,7 +872,7 @@ func initializeClusterNetworkingConfig(ctx context.Context, asrv *Server, newNet return trace.Wrap(err) } - shouldReplace, err := shouldInitReplaceResourceWithOrigin(storedNetConfig, newNetConfig) + shouldReplace, err := shouldInitReplaceResourceWithOrigin(ctx, storedNetConfig, newNetConfig, asrv.logger) if err != nil { return trace.Wrap(err) } @@ -871,7 +882,7 @@ func initializeClusterNetworkingConfig(ctx context.Context, asrv *Server, newNet } if storedNetConfig == nil { - log.Infof("Creating cluster networking configuration: %v.", newNetConfig) + asrv.logger.InfoContext(ctx, "Creating cluster networking configuration", "networking_confg", newNetConfig) _, err = asrv.CreateClusterNetworkingConfig(ctx, newNetConfig) if trace.IsAlreadyExists(err) { continue @@ -880,7 +891,7 @@ func initializeClusterNetworkingConfig(ctx context.Context, asrv *Server, newNet return trace.Wrap(err) } - log.Infof("Updating cluster networking configuration: %v.", newNetConfig) + asrv.logger.InfoContext(ctx, "Updating cluster networking configuration", "networking_config", newNetConfig) newNetConfig.SetRevision(storedNetConfig.GetRevision()) _, err = asrv.UpdateClusterNetworkingConfig(ctx, newNetConfig) if trace.IsCompareFailed(err) { @@ -901,7 +912,7 @@ func initializeSessionRecordingConfig(ctx context.Context, asrv *Server, newRecC return trace.Wrap(err) } - shouldReplace, err := shouldInitReplaceResourceWithOrigin(storedRecConfig, newRecConfig) + shouldReplace, err := shouldInitReplaceResourceWithOrigin(ctx, storedRecConfig, newRecConfig, asrv.logger) if err != nil { return trace.Wrap(err) } @@ -911,7 +922,7 @@ func initializeSessionRecordingConfig(ctx context.Context, asrv *Server, newRecC } if storedRecConfig == nil { - log.Infof("Creating session recording config: %v.", newRecConfig) + asrv.logger.InfoContext(ctx, "Creating session recording config", "recording_config", newRecConfig) _, err := asrv.CreateSessionRecordingConfig(ctx, newRecConfig) if trace.IsAlreadyExists(err) { continue @@ -920,7 +931,7 @@ func initializeSessionRecordingConfig(ctx context.Context, asrv *Server, newRecC return trace.Wrap(err) } - log.Infof("Updating session recording config: %v.", newRecConfig) + asrv.logger.InfoContext(ctx, "Updating session recording config", "recording_config", newRecConfig) newRecConfig.SetRevision(storedRecConfig.GetRevision()) _, err = asrv.UpdateSessionRecordingConfig(ctx, newRecConfig) if trace.IsCompareFailed(err) { @@ -949,7 +960,7 @@ func initializeAccessGraphSettings(ctx context.Context, asrv *Server) error { return trace.Wrap(err) } - log.Infof("Creating access graph settings: %v.", stored) + asrv.logger.InfoContext(ctx, "Creating access graph settings", "settings", stored) _, err = asrv.CreateAccessGraphSettings(ctx, stored) if trace.IsAlreadyExists(err) { return nil @@ -962,7 +973,7 @@ func initializeAccessGraphSettings(ctx context.Context, asrv *Server) error { // resource should be used to replace the stored resource during auth server // initialization. Dynamically configured resources must not be overwritten // when the corresponding file config is left unspecified (i.e., by defaults). -func shouldInitReplaceResourceWithOrigin(stored, candidate types.ResourceWithOrigin) (bool, error) { +func shouldInitReplaceResourceWithOrigin(ctx context.Context, stored, candidate types.ResourceWithOrigin, logger *slog.Logger) (bool, error) { if candidate == nil || (candidate.Origin() != types.OriginDefaults && candidate.Origin() != types.OriginConfigFile) { return false, trace.BadParameter("candidate origin must be either defaults or config-file (this is a bug)") } @@ -978,7 +989,7 @@ func shouldInitReplaceResourceWithOrigin(stored, candidate types.ResourceWithOri if candidate.Origin() == types.OriginConfigFile { // Log a warning when about to overwrite a dynamically configured resource. if stored.Origin() == types.OriginDynamic { - log.Warnf("Stored %v resource that was configured dynamically is about to be discarded in favor of explicit file configuration.", stored.GetKind()) + logger.WarnContext(ctx, "Stored resource that was configured dynamically is about to be discarded in favor of explicit file configuration", "resource", stored.GetKind()) } return true, nil } @@ -991,15 +1002,15 @@ func shouldInitReplaceResourceWithOrigin(stored, candidate types.ResourceWithOri // migrationStart marks the migration as active. // It should be called when a migration starts. -func migrationStart(ctx context.Context, migrationName string) { - log.Debugf("Migrations: %q migration started.", migrationName) +func migrationStart(ctx context.Context, migrationName string, logger *slog.Logger) { + logger.DebugContext(ctx, "Migration started", "migration_name", migrationName) migrations.WithLabelValues(migrationName).Set(1) } // migrationEnd marks the migration as inactive. // It should be called when a migration ends. -func migrationEnd(ctx context.Context, migrationName string) { - log.Debugf("Migrations: %q migration ended.", migrationName) +func migrationEnd(ctx context.Context, migrationName string, logger *slog.Logger) { + logger.DebugContext(ctx, "Migration ended", "migration_name", migrationName) migrations.WithLabelValues(migrationName).Set(0) } @@ -1080,7 +1091,7 @@ func createPresetRoles(ctx context.Context, rm PresetRoleManager) error { return trace.Wrap(err) } - role, err := services.AddRoleDefaults(currentRole) + role, err := services.AddRoleDefaults(gctx, currentRole) if trace.IsAlreadyExists(err) { return nil } @@ -1340,8 +1351,8 @@ func CertAuthorityInfo(ca types.CertAuthority) string { // where the presence of remote cluster was identified only by presence // of host certificate authority with cluster name not equal local cluster name func migrateRemoteClusters(ctx context.Context, asrv *Server) error { - migrationStart(ctx, "remote_clusters") - defer migrationEnd(ctx, "remote_clusters") + migrationStart(ctx, "remote_clusters", asrv.logger) + defer migrationEnd(ctx, "remote_clusters", asrv.logger) clusterName, err := asrv.Services.GetClusterName() if err != nil { @@ -1355,13 +1366,13 @@ func migrateRemoteClusters(ctx context.Context, asrv *Server) error { // forward and forward agent allowed for _, certAuthority := range certAuthorities { if certAuthority.GetName() == clusterName.GetClusterName() { - log.Debugf("Migrations: skipping local cluster cert authority %q.", certAuthority.GetName()) + asrv.logger.DebugContext(ctx, "Migrations: skipping local cluster cert authority", "cert_authority", certAuthority.GetName()) continue } // remote cluster already exists _, err = asrv.Services.GetRemoteCluster(ctx, certAuthority.GetName()) if err == nil { - log.Debugf("Migrations: remote cluster already exists for cert authority %q.", certAuthority.GetName()) + asrv.logger.DebugContext(ctx, "Migrations: remote cluster already exists for cert authority", "cert_authority", certAuthority.GetName()) continue } if !trace.IsNotFound(err) { @@ -1370,7 +1381,7 @@ func migrateRemoteClusters(ctx context.Context, asrv *Server) error { // the cert authority is associated with trusted cluster _, err = asrv.Services.GetTrustedCluster(ctx, certAuthority.GetName()) if err == nil { - log.Debugf("Migrations: trusted cluster resource exists for cert authority %q.", certAuthority.GetName()) + asrv.logger.DebugContext(ctx, "Migrations: trusted cluster resource exists for cert authority", "cert_authority", certAuthority.GetName()) continue } if !trace.IsNotFound(err) { @@ -1386,7 +1397,7 @@ func migrateRemoteClusters(ctx context.Context, asrv *Server) error { return trace.Wrap(err) } } - log.Infof("Migrations: added remote cluster resource for cert authority %q.", certAuthority.GetName()) + asrv.logger.InfoContext(ctx, "Migrations: added remote cluster resource for cert authority", "cert_authority", certAuthority.GetName()) } return nil diff --git a/lib/auth/join.go b/lib/auth/join.go index 53880bf9955e2..00d4f8847f1e9 100644 --- a/lib/auth/join.go +++ b/lib/auth/join.go @@ -22,13 +22,12 @@ import ( "context" "crypto/rand" "encoding/base64" - "fmt" + "log/slog" "net" "slices" "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "google.golang.org/grpc/peer" "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" @@ -60,7 +59,11 @@ func (a *Server) checkTokenJoinRequestCommon(ctx context.Context, req *types.Reg // make sure the token is valid provisionToken, err := a.ValidateToken(ctx, req.Token) if err != nil { - log.Warningf("%q can not join the cluster with role %s, token error: %v", req.NodeName, req.Role, err) + a.logger.WarnContext(ctx, "cannot join the cluster with invalid token", + "node_name", req.NodeName, + "role", req.Role, + "error", err, + ) msg := "the token is not valid" // default to most generic message if strings.Contains(err.Error(), TokenExpiredOrNotFound) { // propagate ExpiredOrNotFound message so that clients can attempt @@ -80,17 +83,22 @@ func (a *Server) checkTokenJoinRequestCommon(ctx context.Context, req *types.Reg } } if !hasLocalServiceRole { - msg := fmt.Sprintf("%q [%v] cannot requisition instance certs (token contains no local service roles)", req.NodeName, req.HostID) - log.Warn(msg) - return nil, trace.AccessDenied(msg) + a.logger.WarnContext(ctx, "cannot requisition instance certs (token contains no local service roles)", + "node_name", req.NodeName, + "host_id", req.HostID, + ) + return nil, trace.AccessDenied("%s [%v] cannot requisition instance certs (token contains no local service roles)", req.NodeName, req.HostID) } } // make sure the caller is requesting a role allowed by the token if !provisionToken.GetRoles().Include(req.Role) && req.Role != types.RoleInstance { - msg := fmt.Sprintf("node %q [%v] can not join the cluster, the token does not allow %q role", req.NodeName, req.HostID, req.Role) - log.Warn(msg) - return nil, trace.BadParameter(msg) + a.logger.WarnContext(ctx, "token does not allow role to join the cluster", + "node_name", req.NodeName, + "host_id", req.HostID, + "role", req.Role, + ) + return nil, trace.BadParameter("node %q [%v] can not join the cluster, the token does not allow %q role", req.NodeName, req.HostID, req.Role) } return provisionToken, nil @@ -121,17 +129,20 @@ func setRemoteAddrFromContext(ctx context.Context, req *types.RegisterUsingToken // handleJoinFailure logs and audits the failure of a join. It is intentionally // designed to handle potential nullness of the input parameters. func (a *Server) handleJoinFailure( + ctx context.Context, origErr error, pt types.ProvisionToken, attributeSource joinAttributeSourcer, req *types.RegisterUsingTokenRequest, ) { - fields := logrus.Fields{} + attrs := []slog.Attr{slog.Any("error", origErr)} if req != nil { - fields["role"] = req.Role - fields["host_id"] = req.HostID - fields["node_name"] = req.NodeName - fields["remote_addr"] = req.RemoteAddr + attrs = append(attrs, []slog.Attr{ + slog.String("role", string(req.Role)), + slog.String("host_id", req.HostID), + slog.String("node_name", req.NodeName), + slog.String("remote_addr", req.RemoteAddr), + }...) } // Fetch and encode attributes if they are available. @@ -140,21 +151,21 @@ func (a *Server) handleJoinFailure( var err error attributes, err := attributeSource.JoinAuditAttributes() if err != nil { - log.WithError(err).Warn("Unable to fetch join attributes from join method") + a.logger.WarnContext(ctx, "Unable to fetch join attributes from join method", "error", err) } - fields["attributes"] = attributes + attrs = append(attrs, slog.Any("attributes", attributes)) attributesProto, err = apievents.EncodeMap(attributes) if err != nil { - log.WithError(err).Warn("Unable to encode join attributes for audit event") + a.logger.WarnContext(ctx, "Unable to encode join attributes for audit event", "error", err) } } // Add log fields from token if available. if pt != nil { - fields["join_method"] = string(pt.GetJoinMethod()) - fields["token_name"] = pt.GetSafeName() + attrs = append(attrs, slog.String("join_method", string(pt.GetJoinMethod()))) + attrs = append(attrs, slog.String("token_name", pt.GetSafeName())) } - log.WithError(origErr).WithFields(fields).Warn("Failure to join cluster occurred") + a.logger.LogAttrs(ctx, slog.LevelWarn, "Failure to join cluster occurred", attrs...) var evt apievents.AuditEvent status := apievents.Status{ @@ -201,7 +212,7 @@ func (a *Server) handleJoinFailure( evt = instanceJoinEvent } if err := a.emitter.EmitAuditEvent(a.closeCtx, evt); err != nil { - log.WithError(err).Warn("Failed to emit failed join event") + a.logger.WarnContext(ctx, "Failed to emit failed join event", "error", err) } } @@ -222,7 +233,7 @@ func (a *Server) RegisterUsingToken(ctx context.Context, req *types.RegisterUsin defer func() { // Emit a log message and audit event on join failure. if err != nil { - a.handleJoinFailure(err, provisionToken, joinAttributeSrc, req) + a.handleJoinFailure(ctx, err, provisionToken, joinAttributeSrc, req) } }() @@ -398,16 +409,16 @@ func (a *Server) generateCertsBot( if joinAttributeSrc != nil { attributes, err := joinAttributeSrc.JoinAuditAttributes() if err != nil { - log.WithError(err).Warn("Unable to fetch join attributes from join method.") + a.logger.WarnContext(ctx, "Unable to fetch join attributes from join method", "error", err) } joinEvent.Attributes, err = apievents.EncodeMap(attributes) if err != nil { - log.WithError(err).Warn("Unable to encode join attributes for audit event.") + a.logger.WarnContext(ctx, "Unable to encode join attributes for audit event", "error", err) } auth.Metadata, err = structpb.NewStruct(attributes) if err != nil { - log.WithError(err).Warn("Unable to encode struct value for join metadata.") + a.logger.WarnContext(ctx, "Unable to encode struct value for join metadata", "error", err) } } @@ -432,16 +443,20 @@ func (a *Server) generateCertsBot( if shouldDeleteToken { // delete ephemeral bot join tokens so they can't be re-used if err := a.DeleteToken(ctx, provisionToken.GetName()); err != nil { - log.WithError(err).Warnf("Could not delete bot provision token %q after generating certs", - provisionToken.GetSafeName(), + a.logger.WarnContext(ctx, "Could not delete bot provision token after generating certs", + "provision_token", provisionToken.GetSafeName(), + "error", err, ) } } // Emit audit event for bot join. - log.Infof("Bot %q (instance: %s) has joined the cluster.", botName, botInstanceID) + a.logger.InfoContext(ctx, "Bot has joined the cluster", + "bot_name", botName, + "bot_instance", botInstanceID, + ) if err := a.emitter.EmitAuditEvent(ctx, joinEvent); err != nil { - log.WithError(err).Warn("Failed to emit bot join event.") + a.logger.WarnContext(ctx, "Failed to emit bot join event", "error", err) } return certs, nil } @@ -464,7 +479,7 @@ func (a *Server) generateCerts( if r.IsLocalService() { systemRoles = append(systemRoles, r) } else { - log.Warnf("Omitting non-service system role from instance cert: %q", r) + a.logger.WarnContext(ctx, "Omitting non-service system role from instance cert", "system_role", string(r)) } } } @@ -488,9 +503,18 @@ func (a *Server) generateCerts( // Emit audit event if req.Role == types.RoleInstance { - log.Infof("Instance %q [%v] has joined the cluster. role=%s, systemRoles=%+v", req.NodeName, req.HostID, req.Role, systemRoles) + a.logger.InfoContext(ctx, "Instance has joined the cluster", + "node_name", req.NodeName, + "host_id", req.HostID, + "role", req.Role, + "system_roles", systemRoles, + ) } else { - log.Infof("Instance %q [%v] has joined the cluster. role=%s", req.NodeName, req.HostID, req.Role) + a.logger.InfoContext(ctx, "Instance has joined the cluster", + "node_name", req.NodeName, + "host_id", req.HostID, + "role", req.Role, + ) } joinEvent := &apievents.InstanceJoin{ Metadata: apievents.Metadata{ @@ -513,15 +537,15 @@ func (a *Server) generateCerts( if joinAttributeSrc != nil { attributes, err := joinAttributeSrc.JoinAuditAttributes() if err != nil { - log.WithError(err).Warn("Unable to fetch join attributes from join method.") + a.logger.WarnContext(ctx, "Unable to fetch join attributes from join method", "error", err) } joinEvent.Attributes, err = apievents.EncodeMap(attributes) if err != nil { - log.WithError(err).Warn("Unable to encode join attributes for audit event.") + a.logger.WarnContext(ctx, "Unable to encode join attributes for audit event", "error", err) } } if err := a.emitter.EmitAuditEvent(ctx, joinEvent); err != nil { - log.WithError(err).Warn("Failed to emit instance join event.") + a.logger.WarnContext(ctx, "Failed to emit instance join event", "error", err) } return certs, nil } diff --git a/lib/auth/join_azure.go b/lib/auth/join_azure.go index 721a53ff2d7fa..70ae17918b7fa 100644 --- a/lib/auth/join_azure.go +++ b/lib/auth/join_azure.go @@ -366,9 +366,7 @@ func (a *Server) RegisterUsingAzureMethodWithOpts( defer func() { // Emit a log message and audit event on join failure. if err != nil { - a.handleJoinFailure( - err, provisionToken, nil, joinRequest, - ) + a.handleJoinFailure(ctx, err, provisionToken, nil, joinRequest) } }() diff --git a/lib/auth/join_gcp.go b/lib/auth/join_gcp.go index a6cf1db4ccd7e..9cfecca822637 100644 --- a/lib/auth/join_gcp.go +++ b/lib/auth/join_gcp.go @@ -24,7 +24,6 @@ import ( "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/gcp" @@ -50,17 +49,18 @@ func (a *Server) checkGCPJoinRequest(ctx context.Context, req *types.RegisterUsi claims, err := a.gcpIDTokenValidator.Validate(ctx, req.IDToken) if err != nil { - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).WithError(err).Warn("Unable to validate GCP IDToken") + a.logger.WarnContext(ctx, "Unable to validate GCP IDToken", + "error", err, + "claims", claims, + "token", pt.GetName(), + ) return nil, trace.Wrap(err) } - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).Info("GCP VM trying to join cluster") + a.logger.InfoContext(ctx, "GCP VM trying to join cluster", + "claims", claims, + "token", pt.GetName(), + ) if err := checkGCPAllowRules(token, claims); err != nil { return nil, trace.Wrap(err) diff --git a/lib/auth/join_github.go b/lib/auth/join_github.go index 226f1c501c6b0..87d9e0aaa3ea4 100644 --- a/lib/auth/join_github.go +++ b/lib/auth/join_github.go @@ -24,7 +24,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/githubactions" @@ -87,10 +86,10 @@ func (a *Server) checkGitHubJoinRequest(ctx context.Context, req *types.Register } } - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).Info("Github actions run trying to join cluster") + a.logger.InfoContext(ctx, "Github actions run trying to join cluster", + "claims", claims, + "token", pt.GetName(), + ) return claims, trace.Wrap(checkGithubAllowRules(token, claims)) } diff --git a/lib/auth/join_gitlab.go b/lib/auth/join_gitlab.go index e20b9f8f343d8..0296c9ad3ed24 100644 --- a/lib/auth/join_gitlab.go +++ b/lib/auth/join_gitlab.go @@ -24,7 +24,6 @@ import ( "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/gitlab" @@ -57,10 +56,10 @@ func (a *Server) checkGitLabJoinRequest(ctx context.Context, req *types.Register return nil, trace.Wrap(err) } - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).Info("GitLab CI run trying to join cluster") + a.logger.InfoContext(ctx, "GitLab CI run trying to join cluster", + "claims", claims, + "token", pt.GetName(), + ) return claims, trace.Wrap(checkGitLabAllowRules(token, claims)) } diff --git a/lib/auth/join_iam.go b/lib/auth/join_iam.go index ba2209105c7c0..5ca3f4af1877d 100644 --- a/lib/auth/join_iam.go +++ b/lib/auth/join_iam.go @@ -344,9 +344,7 @@ func (a *Server) RegisterUsingIAMMethodWithOpts( defer func() { // Emit a log message and audit event on join failure. if err != nil { - a.handleJoinFailure( - err, provisionToken, nil, joinRequest, - ) + a.handleJoinFailure(ctx, err, provisionToken, nil, joinRequest) } }() diff --git a/lib/auth/join_kubernetes.go b/lib/auth/join_kubernetes.go index d5bbc6586d831..317f6cc7dfd3e 100644 --- a/lib/auth/join_kubernetes.go +++ b/lib/auth/join_kubernetes.go @@ -24,7 +24,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" kubetoken "github.com/gravitational/teleport/lib/kube/token" @@ -82,10 +81,10 @@ func (a *Server) checkKubernetesJoinRequest(ctx context.Context, req *types.Regi ) } - log.WithFields(logrus.Fields{ - "validated_identity": result, - "token": token.GetName(), - }).Info("Kubernetes workload trying to join cluster") + a.logger.InfoContext(ctx, "Kubernetes workload trying to join cluster", + "validated_identity", result, + "token", token.GetName(), + ) return result, trace.Wrap(checkKubernetesAllowRules(token, result)) } diff --git a/lib/auth/join_spacelift.go b/lib/auth/join_spacelift.go index 30fecf5424abd..67b84de5f0e38 100644 --- a/lib/auth/join_spacelift.go +++ b/lib/auth/join_spacelift.go @@ -23,7 +23,6 @@ import ( "fmt" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/modules" @@ -64,10 +63,10 @@ func (a *Server) checkSpaceliftJoinRequest(ctx context.Context, req *types.Regis return nil, trace.Wrap(err) } - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).Info("Spacelift run trying to join cluster") + a.logger.InfoContext(ctx, "Spacelift run trying to join cluster", + "claims", claims, + "token", pt.GetName(), + ) return claims, trace.Wrap(checkSpaceliftAllowRules(token, claims)) } diff --git a/lib/auth/join_terraformcloud.go b/lib/auth/join_terraformcloud.go index 9302004858608..827319733a39a 100644 --- a/lib/auth/join_terraformcloud.go +++ b/lib/auth/join_terraformcloud.go @@ -23,7 +23,6 @@ import ( "fmt" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/modules" @@ -75,10 +74,10 @@ func (a *Server) checkTerraformCloudJoinRequest(ctx context.Context, req *types. return nil, trace.Wrap(err) } - log.WithFields(logrus.Fields{ - "claims": claims, - "token": pt.GetName(), - }).Info("Terraform Cloud run trying to join cluster") + a.logger.InfoContext(ctx, "Terraform Cloud run trying to join cluster", + "claims", claims, + "token", pt.GetName(), + ) return claims, trace.Wrap(checkTerraformCloudAllowRules(token, claims)) } diff --git a/lib/auth/join_tpm.go b/lib/auth/join_tpm.go index 05bf9e3c35a54..12463e8ecd811 100644 --- a/lib/auth/join_tpm.go +++ b/lib/auth/join_tpm.go @@ -43,9 +43,7 @@ func (a *Server) RegisterUsingTPMMethod( defer func() { // Emit a log message and audit event on join failure. if err != nil { - a.handleJoinFailure( - err, provisionToken, attributeSrc, initReq.JoinRequest, - ) + a.handleJoinFailure(ctx, err, provisionToken, attributeSrc, initReq.JoinRequest) } }() diff --git a/lib/auth/middleware.go b/lib/auth/middleware.go index 8e21c071eb4a5..4d5b913f9db56 100644 --- a/lib/auth/middleware.go +++ b/lib/auth/middleware.go @@ -24,6 +24,7 @@ import ( "crypto/x509" "encoding/json" "fmt" + "log/slog" "net" "net/http" "os" @@ -36,7 +37,6 @@ import ( "github.com/gravitational/trace" grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus" "github.com/prometheus/client_golang/prometheus" - "github.com/sirupsen/logrus" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "golang.org/x/net/http2" "google.golang.org/grpc" @@ -57,6 +57,7 @@ import ( "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) const ( @@ -139,7 +140,7 @@ type TLSServer struct { // cfg is TLS server configuration used for auth server cfg TLSServerConfig // log is TLS server logging entry - log *logrus.Entry + log *slog.Logger // mux is a listener that multiplexes HTTP/2 and HTTP/1.1 // on different listeners mux *multiplexer.TLSListener @@ -215,9 +216,7 @@ func NewTLSServer(ctx context.Context, cfg TLSServerConfig) (*TLSServer, error) return authz.ContextWithConn(ctx, c) }, }, - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: cfg.Component, - }), + log: slog.With(teleport.ComponentKey, cfg.Component), } tlsConfig := cfg.TLS.Clone() @@ -306,7 +305,7 @@ func (t *TLSServer) Serve() error { errC := make(chan error, 2) go func() { err := t.mux.Serve() - t.log.WithError(err).Warningf("Mux serve failed.") + t.log.WarnContext(context.Background(), "Mux serve failed", "error", err) }() go func() { errC <- t.httpServer.Serve(t.mux.HTTP()) @@ -372,7 +371,9 @@ func getCustomRate(endpoint string) *limiter.RateSet { rates := limiter.NewRateSet() // This limit means: 1 request per minute with bursts up to 10 requests. if err := rates.Add(time.Minute, 1, 10); err != nil { - log.WithError(err).Debugf("Failed to define a custom rate for rpc method %q, using default rate", endpoint) + logger.DebugContext(context.Background(), "Failed to define a custom rate for rpc method, using default rate", + "error", err, + "rpc_method", endpoint) return nil } return rates @@ -383,7 +384,10 @@ func getCustomRate(endpoint string) *limiter.RateSet { const burst = defaults.LimiterBurst rates := limiter.NewRateSet() if err := rates.Add(period, average, burst); err != nil { - log.WithError(err).Debugf("Failed to define a custom rate for rpc method %q, using default rate", endpoint) + logger.DebugContext(context.Background(), "Failed to define a custom rate for rpc method, using default rate", + "error", err, + "rpc_method", endpoint, + ) return nil } return rates @@ -406,24 +410,29 @@ func (a *Middleware) ValidateClientVersion(ctx context.Context, info IdentityInf ua := metadata.UserAgentFromContext(ctx) - logger := log.WithFields(logrus.Fields{"user_agent": ua, "identity": info.IdentityGetter.GetIdentity().Username, "version": clientVersionString, "addr": info.Conn.RemoteAddr().String()}) + logger := slog.With( + "user_agent", ua, + "identity", info.IdentityGetter.GetIdentity().Username, + "version", clientVersionString, + "addr", logutils.StringerAttr(info.Conn.RemoteAddr()), + ) clientVersion, err := semver.NewVersion(clientVersionString) if err != nil { - logger.WithError(err).Warn("Failed to determine client version") + logger.WarnContext(ctx, "Failed to determine client version", "error", err) a.displayRejectedClientAlert(ctx, clientVersionString, info.Conn.RemoteAddr(), ua, info.IdentityGetter) if err := info.Conn.Close(); err != nil { - logger.WithError(err).Warn("Failed to close client connection") + logger.WarnContext(ctx, "Failed to close client connection", "error", err) } return trace.AccessDenied("client version is unsupported") } if clientVersion.LessThan(*a.OldestSupportedVersion) { - logger.Info("Terminating connection of client using unsupported version") + logger.InfoContext(ctx, "Terminating connection of client using unsupported version") a.displayRejectedClientAlert(ctx, clientVersionString, info.Conn.RemoteAddr(), ua, info.IdentityGetter) if err := info.Conn.Close(); err != nil { - logger.WithError(err).Warn("Failed to close client connection") + logger.WarnContext(ctx, "Failed to close client connection", "error", err) } return trace.AccessDenied("client version is unsupported") @@ -486,12 +495,12 @@ func (a *Middleware) displayRejectedClientAlert(ctx context.Context, clientVersi types.WithAlertLabel(types.AlertVerbPermit, fmt.Sprintf("%s:%s", types.KindToken, types.VerbCreate)), ) if err != nil { - log.WithError(err).Warn("failed to create rejected-unsupported-connection alert") + logger.WarnContext(ctx, "failed to create rejected-unsupported-connection alert", "error", err) return } if err := a.AlertCreator(ctx, alert); err != nil { - log.WithError(err).Warn("failed to persist rejected-unsupported-connection alert") + logger.WarnContext(ctx, "failed to persist rejected-unsupported-connection alert", "error", err) return } } @@ -656,7 +665,7 @@ func (a *Middleware) GetUser(connState tls.ConnectionState) (authz.IdentityGette if certClusterName == "" { certClusterName, err = tlsca.ClusterName(clientCert.Issuer) if err != nil { - log.Warnf("Failed to parse client certificate %v.", err) + logger.WarnContext(context.Background(), "Failed to parse client certificate", "error", err) return nil, trace.AccessDenied("access denied: invalid client certificate") } identity.TeleportCluster = certClusterName @@ -667,8 +676,11 @@ func (a *Middleware) GetUser(connState tls.ConnectionState) (authz.IdentityGette // against auth server. Later on we can extend more // advanced cert usage, but for now this is the safest option. if len(identity.Usage) != 0 && !slices.Equal(a.AcceptedUsage, identity.Usage) { - log.Warningf("Restricted certificate of user %q with usage %v rejected while accessing the auth endpoint with acceptable usage %v.", - identity.Username, identity.Usage, a.AcceptedUsage) + logger.WarnContext(context.Background(), "Restricted certificate rejected while accessing the auth endpoint", + "user", identity.Username, + "cert_usage", identity.Usage, + "acceptable_usage", a.AcceptedUsage, + ) return nil, trace.AccessDenied("access denied: invalid client certificate") } @@ -734,7 +746,7 @@ func extractAdditionalSystemRoles(roles []string) types.SystemRoles { if err != nil { // ignore unknown system roles rather than rejecting them, since new unknown system // roles may be present on certs if we rolled back from a newer version. - log.Warnf("Ignoring unknown system role: %q", role) + logger.WarnContext(context.Background(), "Ignoring unknown system role", "unknown_role", role) continue } systemRoles = append(systemRoles, systemRole) diff --git a/lib/auth/presence/presencev1/service.go b/lib/auth/presence/presencev1/service.go index c83e36fc453e3..3eb28af2e740e 100644 --- a/lib/auth/presence/presencev1/service.go +++ b/lib/auth/presence/presencev1/service.go @@ -20,10 +20,10 @@ package presencev1 import ( "context" + "log/slog" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" "github.com/gravitational/teleport" @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/lib/services" usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // Backend is the subset of the backend resources that the Service modifies. @@ -65,7 +66,7 @@ type ServiceConfig struct { AuthServer AuthServer Backend Backend Cache Cache - Logger logrus.FieldLogger + Logger *slog.Logger Emitter apievents.Emitter Reporter usagereporter.UsageReporter Clock clockwork.Clock @@ -79,7 +80,7 @@ type Service struct { authServer AuthServer backend Backend cache Cache - logger logrus.FieldLogger + logger *slog.Logger emitter apievents.Emitter reporter usagereporter.UsageReporter clock clockwork.Clock @@ -103,7 +104,7 @@ func NewService(cfg ServiceConfig) (*Service, error) { } if cfg.Logger == nil { - cfg.Logger = logrus.WithField(teleport.ComponentKey, "presence.service") + cfg.Logger = slog.With(teleport.ComponentKey, "presence.service") } if cfg.Clock == nil { cfg.Clock = clockwork.NewRealClock() @@ -149,7 +150,11 @@ func (s *Service) GetRemoteCluster( v3, ok := rc.(*types.RemoteClusterV3) if !ok { - s.logger.Warnf("expected type RemoteClusterV3, got %T for %q", rc, rc.GetName()) + s.logger.WarnContext(ctx, "unexpected remote cluster type", + "got_type", logutils.TypeAttr(rc), + "expected_type", "RemoteClusterV3", + "remote_cluster", rc.GetName(), + ) return nil, trace.BadParameter("encountered unexpected remote cluster type") } @@ -180,7 +185,11 @@ func (s *Service) ListRemoteClusters( for _, rc := range page { v3, ok := rc.(*types.RemoteClusterV3) if !ok { - s.logger.Warnf("expected type RemoteClusterV3, got %T for %q", rc, rc.GetName()) + s.logger.WarnContext(ctx, "unexpected remote cluster type", + "got_type", logutils.TypeAttr(rc), + "expected_type", "RemoteClusterV3", + "remote_cluster", rc.GetName(), + ) continue } concretePage = append(concretePage, v3) @@ -234,7 +243,11 @@ func (s *Service) UpdateRemoteCluster( } v3, ok := rc.(*types.RemoteClusterV3) if !ok { - s.logger.Warnf("expected type RemoteClusterV3, got %T for user %q", rc, rc.GetName()) + s.logger.WarnContext(ctx, "unexpected remote cluster type", + "got_type", logutils.TypeAttr(rc), + "expected_type", "RemoteClusterV3", + "remote_cluster", rc.GetName(), + ) return nil, trace.BadParameter("encountered unexpected remote cluster type") } return v3, nil @@ -271,7 +284,11 @@ func (s *Service) UpdateRemoteCluster( } v3, ok := rc.(*types.RemoteClusterV3) if !ok { - s.logger.Warnf("expected type RemoteClusterV3, got %T for user %q", rc, rc.GetName()) + s.logger.WarnContext(ctx, "unexpected remote cluster type", + "got_type", logutils.TypeAttr(rc), + "expected_type", "RemoteClusterV3", + "remote_cluster", rc.GetName(), + ) return nil, trace.BadParameter("encountered unexpected remote cluster type") } @@ -330,7 +347,11 @@ func (s *Service) ListReverseTunnels( for _, rc := range page { v3, ok := rc.(*types.ReverseTunnelV2) if !ok { - s.logger.Warnf("expected type ReverseTunnelV2, got %T for %q", rc, rc.GetName()) + s.logger.WarnContext(ctx, "unexpected reverse tunnel type", + "got_type", logutils.TypeAttr(rc), + "expected_type", "ReverseTunnelV2", + "reverse_tunnel", rc.GetName(), + ) continue } concretePage = append(concretePage, v3) diff --git a/lib/auth/rotate.go b/lib/auth/rotate.go index 5110909d53654..5f7d708f71551 100644 --- a/lib/auth/rotate.go +++ b/lib/auth/rotate.go @@ -165,9 +165,14 @@ func (a *Server) RotateCertAuthority(ctx context.Context, req types.RotateReques rotation := rotated.GetRotation() switch rotation.State { case types.RotationStateInProgress: - log.WithFields(logrus.Fields{"type": req.Type}).Infof("Updated rotation state, set current phase to: %q.", rotation.Phase) + a.logger.InfoContext(ctx, "Updated rotation state", + "current_phase", rotation.Phase, + "ca_type", req.Type, + ) case types.RotationStateStandby: - log.WithFields(logrus.Fields{"type": req.Type}).Infof("Updated and completed rotation.") + a.logger.InfoContext(ctx, "Updated and completed rotation", + "ca_type", req.Type, + ) } return nil diff --git a/lib/auth/sessions.go b/lib/auth/sessions.go index 9947279aad248..7f202bd9110b3 100644 --- a/lib/auth/sessions.go +++ b/lib/auth/sessions.go @@ -25,7 +25,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -154,7 +153,7 @@ func (a *Server) augmentSessionForDeviceTrust( }) switch { case err != nil: - log.WithError(err).Warn("Failed to create DeviceWebToken for user") + a.logger.WarnContext(ctx, "Failed to create DeviceWebToken for user", "error", err) case webToken != nil: // May be nil even if err==nil. session.SetDeviceWebToken(&types.DeviceWebToken{ Id: webToken.Id, @@ -210,7 +209,7 @@ func (a *Server) newWebSession( } if req.LoginIP == "" { // TODO(antonam): consider turning this into error after all use cases are covered (before v14.0 testplan) - log.Debug("Creating new web session without login IP specified.") + a.logger.DebugContext(ctx, "Creating new web session without login IP specified") } clusterName, err := a.GetClusterName() @@ -351,17 +350,15 @@ func (a *Server) newWebSession( if tdr, err := a.calculateTrustedDeviceMode(ctx, func() ([]types.Role, error) { return checker.Roles(), nil }); err != nil { - log. - WithError(err). - Warn("Failed to calculate trusted device mode for session") + a.logger.WarnContext(ctx, "Failed to calculate trusted device mode for session", "error", err) } else { sess.SetTrustedDeviceRequirement(tdr) if tdr != types.TrustedDeviceRequirement_TRUSTED_DEVICE_REQUIREMENT_UNSPECIFIED { - log.WithFields(logrus.Fields{ - "user": req.User, - "trusted_device_requirement": tdr, - }).Debug("Calculated trusted device requirement for session") + a.logger.DebugContext(ctx, "Calculated trusted device requirement for session", + "user", req.User, + "trusted_device_requirement", tdr, + ) } } @@ -597,7 +594,7 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR if err = a.UpsertAppSession(ctx, session); err != nil { return nil, trace.Wrap(err) } - log.Debugf("Generated application web session for %v with TTL %v.", req.User, req.SessionTTL) + a.logger.DebugContext(ctx, "Generated application web session", "user", req.User, "ttl", req.SessionTTL) UserLoginCount.Inc() // Extract the identity of the user from the certificate, this will include metadata from any actively assumed access requests. @@ -643,7 +640,7 @@ func (a *Server) CreateAppSessionFromReq(ctx context.Context, req NewAppSessionR }, }) if err != nil { - log.WithError(err).Warn("Failed to emit app session start event") + a.logger.WarnContext(ctx, "Failed to emit app session start event", "error", err) } return session, nil @@ -784,7 +781,7 @@ func (a *Server) CreateSnowflakeSession(ctx context.Context, req types.CreateSno if err = a.UpsertSnowflakeSession(ctx, session); err != nil { return nil, trace.Wrap(err) } - log.Debugf("Generated Snowflake web session for %v with TTL %v.", req.Username, ttl) + a.logger.DebugContext(ctx, "Generated Snowflake web session", "user", req.Username, "ttl", ttl) return session, nil } @@ -808,7 +805,7 @@ func (a *Server) CreateSAMLIdPSession(ctx context.Context, req types.CreateSAMLI if err = a.UpsertSAMLIdPSession(ctx, session); err != nil { return nil, trace.Wrap(err) } - log.Debugf("Generated SAML IdP web session for %v.", req.Username) + a.logger.DebugContext(ctx, "Generated SAML IdP web session", "user", req.Username) return session, nil } diff --git a/lib/auth/touchid/api.go b/lib/auth/touchid/api.go index 7769b6dd5d2f7..0d96a61f05297 100644 --- a/lib/auth/touchid/api.go +++ b/lib/auth/touchid/api.go @@ -20,6 +20,7 @@ package touchid import ( "bytes" + "context" "crypto/ecdsa" "crypto/sha256" "encoding/base64" @@ -38,10 +39,11 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/protocol/webauthncose" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" + "github.com/gravitational/teleport" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" "github.com/gravitational/teleport/lib/darwin" + logutils "github.com/gravitational/teleport/lib/utils/log" ) var ( @@ -52,6 +54,8 @@ var ( PromptPlatformMessage = "Using platform authenticator, follow the OS prompt" // PromptWriter is the writer used for prompt messages. PromptWriter io.Writer = os.Stderr + + logger = logutils.NewPackageLogger(teleport.ComponentKey, "TouchID") ) func promptPlatform() { @@ -167,7 +171,7 @@ func IsAvailable() bool { var err error cachedDiag, err = Diag() if err != nil { - log.WithError(err).Warn("Touch ID self-diagnostics failed") + logger.WarnContext(context.Background(), "self-diagnostics failed", "error", err) return false } } @@ -356,7 +360,7 @@ func HasCredentials(rpid, user string) bool { } creds, err := native.FindCredentials(rpid, user) if err != nil { - log.WithError(err).Debug("Touch ID: Could not find credentials") + logger.DebugContext(context.Background(), "Could not find credentials", "error", err) return false } return len(creds) > 0 @@ -494,7 +498,7 @@ func Login(origin, user string, assertion *wantypes.CredentialAssertion, picker if err != nil { return nil, "", trace.Wrap(err) } - log.Debugf("Touch ID: using credential %q", cred.CredentialID) + logger.DebugContext(context.Background(), "using credential", "credential_id", cred.CredentialID) attData, err := makeAttestationData(protocol.AssertCeremony, origin, rpID, assertion.Response.Challenge, nil /* cred */) if err != nil { @@ -609,7 +613,7 @@ func ListCredentials() ([]CredentialInfo, error) { info := &infos[i] key, err := darwin.ECDSAPublicKeyFromRaw(info.publicKeyRaw) if err != nil { - log.Warnf("Failed to convert public key: %v", err) + logger.WarnContext(context.Background(), "Failed to convert public key", "error", err) } info.PublicKey = key // this is OK, even if it's nil info.publicKeyRaw = nil diff --git a/lib/auth/touchid/api_darwin.go b/lib/auth/touchid/api_darwin.go index a7ac71653a863..723660e831c50 100644 --- a/lib/auth/touchid/api_darwin.go +++ b/lib/auth/touchid/api_darwin.go @@ -33,6 +33,7 @@ package touchid import "C" import ( + "context" "encoding/base64" "fmt" "runtime/cgo" @@ -42,7 +43,8 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" + + logutils "github.com/gravitational/teleport/lib/utils/log" ) const ( @@ -110,7 +112,7 @@ func (touchIDImpl) Diag() (*DiagResult, error) { laErrorDomain := C.GoString(resC.la_error_domain) laErrorDescription := C.GoString(resC.la_error_description) if !passedLA && laErrorDescription != "" { - log.Debugf("Touch ID: LAError description: %v", laErrorDescription) + logger.DebugContext(context.Background(), "Received non-empty LAError description", "description", laErrorDescription) } isAvailable := signed && entitled && passedLA && passedEnclave @@ -141,7 +143,7 @@ func runGoFuncHandle(handle C.uintptr_t) { val := cgo.Handle(handle).Value() fn, ok := val.(func()) if !ok { - log.Warnf("Touch ID: received unexpected function handle: %T", val) + logger.WarnContext(context.Background(), "received unexpected function handle", "handle", logutils.TypeAttr(val)) return } fn() @@ -304,6 +306,8 @@ func readCredentialInfos(find func(**C.CredentialInfo) C.int) ([]CredentialInfo, var infosC *C.CredentialInfo defer func() { C.free(unsafe.Pointer(infosC)) }() + ctx := context.Background() + res := find(&infosC) if res < 0 { return nil, int(res) @@ -338,21 +342,30 @@ func readCredentialInfos(find func(**C.CredentialInfo) C.int) ([]CredentialInfo, // user@rpid parsedLabel, err := parseLabel(label) if err != nil { - log.Debugf("Skipping credential %q: %v", credentialID, err) + logger.DebugContext(ctx, "Skipping credential", + "credential_id", credentialID, + "error", err, + ) continue } // user handle userHandle, err := base64.RawURLEncoding.DecodeString(appTag) if err != nil { - log.Debugf("Skipping credential %q: unexpected application tag: %q", credentialID, appTag) + logger.DebugContext(ctx, "Skipping credential, unexpected application tag", + "credential_id", credentialID, + "app_tag", appTag, + ) continue } // ECDSA public key pubKeyRaw, err := base64.StdEncoding.DecodeString(pubKeyB64) if err != nil { - log.WithError(err).Warnf("Failed to decode public key for credential %q", credentialID) + logger.WarnContext(ctx, "Failed to decode public key for credential", + "credential_id", credentialID, + "error", err, + ) // Do not return or break out of the loop, it needs to run in order to // deallocate the structs within. } @@ -361,7 +374,11 @@ func readCredentialInfos(find func(**C.CredentialInfo) C.int) ([]CredentialInfo, const iso8601Format = "2006-01-02T15:04:05Z0700" createTime, err := time.Parse(iso8601Format, creationDate) if err != nil { - log.WithError(err).Warnf("Failed to parse creation time %q for credential %q", creationDate, credentialID) + logger.WarnContext(ctx, "Failed to parse creation time for credential", + "creation_time", creationDate, + "credential_id", credentialID, + "error", err, + ) } infos = append(infos, CredentialInfo{ diff --git a/lib/auth/trust/trustv1/service.go b/lib/auth/trust/trustv1/service.go index 91f99a4819be9..345bb8419940d 100644 --- a/lib/auth/trust/trustv1/service.go +++ b/lib/auth/trust/trustv1/service.go @@ -23,10 +23,8 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" - "github.com/gravitational/teleport" trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/authz" @@ -44,6 +42,13 @@ type authServer interface { // RotateCertAuthority starts or restarts certificate authority rotation process. RotateCertAuthority(ctx context.Context, req types.RotateRequest) error + + // UpsertTrustedClusterV2 upserts a Trusted Cluster. + UpsertTrustedClusterV2(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) + // CreateTrustedCluster creates a Trusted Cluster. + CreateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) + // UpdateTrustedCluster updates a Trusted Cluster. + UpdateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) } // ServiceConfig holds configuration options for @@ -52,7 +57,6 @@ type ServiceConfig struct { Authorizer authz.Authorizer Cache services.AuthorityGetter Backend services.TrustInternal - Logger *logrus.Entry AuthServer authServer } @@ -63,7 +67,6 @@ type Service struct { cache services.AuthorityGetter backend services.TrustInternal authServer authServer - logger *logrus.Entry } // NewService returns a new trust gRPC service. @@ -77,12 +80,9 @@ func NewService(cfg *ServiceConfig) (*Service, error) { return nil, trace.BadParameter("authorizer is required") case cfg.AuthServer == nil: return nil, trace.BadParameter("authServer is required") - case cfg.Logger == nil: - cfg.Logger = logrus.WithField(teleport.ComponentKey, "trust.service") } return &Service{ - logger: cfg.Logger, authorizer: cfg.Authorizer, cache: cfg.Cache, backend: cfg.Backend, diff --git a/lib/auth/trust/trustv1/service_test.go b/lib/auth/trust/trustv1/service_test.go index 152c2558c22b3..23ae66a5149b5 100644 --- a/lib/auth/trust/trustv1/service_test.go +++ b/lib/auth/trust/trustv1/service_test.go @@ -100,6 +100,18 @@ func (f *fakeAuthServer) RotateCertAuthority(ctx context.Context, req types.Rota return f.rotateCertAuthorityData[string(req.Type)] } +func (f *fakeAuthServer) UpsertTrustedClusterV2(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) { + return tc, nil +} + +func (f *fakeAuthServer) CreateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) { + return tc, nil +} + +func (f *fakeAuthServer) UpdateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) { + return tc, nil +} + type fakeChecker struct { services.AccessChecker allow map[check]bool diff --git a/lib/auth/trust/trustv1/trustedcluster.go b/lib/auth/trust/trustv1/trustedcluster.go new file mode 100644 index 0000000000000..48f57a43ba0ec --- /dev/null +++ b/lib/auth/trust/trustv1/trustedcluster.go @@ -0,0 +1,126 @@ +/* + * 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 trustv1 + +import ( + "context" + + "github.com/gravitational/trace" + + trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/modules" + "github.com/gravitational/teleport/lib/services" +) + +// UpsertTrustedCluster upserts a Trusted Cluster. +func (s *Service) UpsertTrustedCluster(ctx context.Context, req *trustpb.UpsertTrustedClusterRequest) (*types.TrustedClusterV2, error) { + // Don't allow a Cloud tenant to be a leaf cluster. + if modules.GetModules().Features().Cloud { + return nil, trace.NotImplemented("cloud tenants cannot be leaf clusters") + } + + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.CheckAccessToKind(types.KindTrustedCluster, types.VerbCreate, types.VerbUpdate); err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil { + return nil, trace.Wrap(err) + } + + if err = services.ValidateTrustedCluster(req.GetTrustedCluster()); err != nil { + return nil, trace.Wrap(err) + } + tc, err := s.authServer.UpsertTrustedClusterV2(ctx, req.GetTrustedCluster()) + if err != nil { + return nil, trace.Wrap(err) + } + trustedClusterV2, ok := tc.(*types.TrustedClusterV2) + if !ok { + return nil, trace.Errorf("encountered unexpected Trusted Cluster type: %T", tc) + } + return trustedClusterV2, nil +} + +// CreateTrustedCluster creates a Trusted Cluster. +func (s *Service) CreateTrustedCluster(ctx context.Context, req *trustpb.CreateTrustedClusterRequest) (*types.TrustedClusterV2, error) { + // Don't allow a Cloud tenant to be a leaf cluster. + if modules.GetModules().Features().Cloud { + return nil, trace.NotImplemented("cloud tenants cannot be leaf clusters") + } + + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.CheckAccessToKind(types.KindTrustedCluster, types.VerbCreate); err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil { + return nil, trace.Wrap(err) + } + + if err = services.ValidateTrustedCluster(req.GetTrustedCluster()); err != nil { + return nil, trace.Wrap(err) + } + tc, err := s.authServer.CreateTrustedCluster(ctx, req.GetTrustedCluster()) + if err != nil { + return nil, trace.Wrap(err) + } + trustedClusterV2, ok := tc.(*types.TrustedClusterV2) + if !ok { + return nil, trace.Errorf("encountered unexpected Trusted Cluster type: %T", tc) + } + return trustedClusterV2, nil +} + +// UpdateTrustedCluster updates a Trusted Cluster. +func (s *Service) UpdateTrustedCluster(ctx context.Context, req *trustpb.UpdateTrustedClusterRequest) (*types.TrustedClusterV2, error) { + // Don't allow a Cloud tenant to be a leaf cluster. + if modules.GetModules().Features().Cloud { + return nil, trace.NotImplemented("cloud tenants cannot be leaf clusters") + } + + authCtx, err := s.authorizer.Authorize(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.CheckAccessToKind(types.KindTrustedCluster, types.VerbUpdate); err != nil { + return nil, trace.Wrap(err) + } + if err := authCtx.AuthorizeAdminActionAllowReusedMFA(); err != nil { + return nil, trace.Wrap(err) + } + + if err = services.ValidateTrustedCluster(req.GetTrustedCluster()); err != nil { + return nil, trace.Wrap(err) + } + tc, err := s.authServer.UpdateTrustedCluster(ctx, req.GetTrustedCluster()) + if err != nil { + return nil, trace.Wrap(err) + } + trustedClusterV2, ok := tc.(*types.TrustedClusterV2) + if !ok { + return nil, trace.Errorf("encountered unexpected Trusted Cluster type: %T", tc) + } + return trustedClusterV2, nil +} diff --git a/lib/auth/trust/trustv1/trustedcluster_test.go b/lib/auth/trust/trustv1/trustedcluster_test.go new file mode 100644 index 0000000000000..d4aea850fedc4 --- /dev/null +++ b/lib/auth/trust/trustv1/trustedcluster_test.go @@ -0,0 +1,281 @@ +/* + * 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 trustv1 + +import ( + "context" + "testing" + + "github.com/gravitational/trace" + "github.com/stretchr/testify/require" + + "github.com/gravitational/teleport" + trustpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/trust/v1" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/modules" + "github.com/gravitational/teleport/lib/services/local" +) + +// TestCloudProhibited verifies that Trusted Clusters cannot be created or updated +// in a Cloud hosted environment. +// Tests cannot be run in parallel because it relies on environment variables. +func TestCloudProhibited(t *testing.T) { + ctx := context.Background() + p := newTestPack(t) + + trust := local.NewCAService(p.mem) + cfg := &ServiceConfig{ + Cache: trust, + Backend: trust, + Authorizer: &fakeAuthorizer{}, + AuthServer: &fakeAuthServer{}, + } + + service, err := NewService(cfg) + require.NoError(t, err) + + modules.SetTestModules(t, &modules.TestModules{ + TestFeatures: modules.Features{Cloud: true}, + }) + + tc, err := types.NewTrustedCluster("test", types.TrustedClusterSpecV2{ + RoleMap: []types.RoleMapping{ + {Remote: teleport.PresetAccessRoleName, Local: []string{teleport.PresetAccessRoleName}}, + }, + }) + require.NoError(t, err, "creating trusted cluster resource") + + trustedClusterV2, ok := tc.(*types.TrustedClusterV2) + require.True(t, ok) + + t.Run("Cloud prohibits being a leaf cluster (UpsertTrustedCluster)", func(t *testing.T) { + _, err = service.UpsertTrustedCluster(ctx, &trustpb.UpsertTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsNotImplemented(err), "UpsertTrustedClusterV2 returned an unexpected error, got = %v (%T), want trace.NotImplementedError", err, err) + }) + + t.Run("Cloud prohibits being a leaf cluster (CreateTrustedCluster)", func(t *testing.T) { + _, err = service.CreateTrustedCluster(ctx, &trustpb.CreateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsNotImplemented(err), "CreateTrustedCluster returned an unexpected error, got = %v (%T), want trace.NotImplementedError", err, err) + }) + + t.Run("Cloud prohibits being a leaf cluster (UpdateTrustedCluster)", func(t *testing.T) { + _, err = service.UpdateTrustedCluster(ctx, &trustpb.UpdateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsNotImplemented(err), "UpdateTrustedCluster returned an unexpected error, got = %v (%T), want trace.NotImplementedError", err, err) + }) +} + +func TestTrustedClusterRBAC(t *testing.T) { + t.Parallel() + ctx := context.Background() + p := newTestPack(t) + + tc, err := types.NewTrustedCluster("test", types.TrustedClusterSpecV2{ + RoleMap: []types.RoleMapping{ + {Remote: teleport.PresetAccessRoleName, Local: []string{teleport.PresetAccessRoleName}}, + }, + }) + require.NoError(t, err, "creating trusted cluster resource") + + trustedClusterV2, ok := tc.(*types.TrustedClusterV2) + require.True(t, ok) + + tests := []struct { + desc string + f func(t *testing.T, service *Service) + authorizer fakeAuthorizer + expectChecks []check + }{ + { + desc: "upsert no access", + f: func(t *testing.T, service *Service) { + _, err := service.UpsertTrustedCluster(ctx, &trustpb.UpsertTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %v", err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{}, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + { + desc: "upsert no create access", + f: func(t *testing.T, service *Service) { + _, err := service.UpsertTrustedCluster(ctx, &trustpb.UpsertTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %v", err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{ + {types.KindTrustedCluster, types.VerbCreate}: false, + {types.KindTrustedCluster, types.VerbUpdate}: true, + }, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + { + desc: "upsert no update access", + f: func(t *testing.T, service *Service) { + _, err := service.UpsertTrustedCluster(ctx, &trustpb.UpsertTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %v", err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{ + {types.KindTrustedCluster, types.VerbCreate}: true, + {types.KindTrustedCluster, types.VerbUpdate}: false, + }, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + { + desc: "upsert ok", + f: func(t *testing.T, service *Service) { + _, err := service.UpsertTrustedCluster(ctx, &trustpb.UpsertTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.NoError(t, err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{ + {types.KindTrustedCluster, types.VerbCreate}: true, + {types.KindTrustedCluster, types.VerbUpdate}: true, + }, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + { + desc: "create no access", + f: func(t *testing.T, service *Service) { + _, err := service.CreateTrustedCluster(ctx, &trustpb.CreateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %v", err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{}, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + }, + }, + { + desc: "create ok", + f: func(t *testing.T, service *Service) { + _, err := service.CreateTrustedCluster(ctx, &trustpb.CreateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.NoError(t, err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{ + {types.KindTrustedCluster, types.VerbCreate}: true, + }, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbCreate}, + }, + }, + { + desc: "update no access", + f: func(t *testing.T, service *Service) { + _, err := service.UpdateTrustedCluster(ctx, &trustpb.UpdateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.True(t, trace.IsAccessDenied(err), "expected AccessDenied error, got %v", err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{}, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + { + desc: "update ok", + f: func(t *testing.T, service *Service) { + _, err := service.UpdateTrustedCluster(ctx, &trustpb.UpdateTrustedClusterRequest{ + TrustedCluster: trustedClusterV2, + }) + require.NoError(t, err) + }, + authorizer: fakeAuthorizer{ + checker: &fakeChecker{ + allow: map[check]bool{ + {types.KindTrustedCluster, types.VerbUpdate}: true, + }, + }, + }, + expectChecks: []check{ + {types.KindTrustedCluster, types.VerbUpdate}, + }, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + trust := local.NewCAService(p.mem) + cfg := &ServiceConfig{ + Cache: trust, + Backend: trust, + Authorizer: &test.authorizer, + AuthServer: &fakeAuthServer{}, + } + + service, err := NewService(cfg) + require.NoError(t, err) + test.f(t, service) + require.ElementsMatch(t, test.expectChecks, test.authorizer.checker.checks) + }) + } +} diff --git a/lib/auth/trustedcluster.go b/lib/auth/trustedcluster.go index 784d6aad010dc..e86008679d31e 100644 --- a/lib/auth/trustedcluster.go +++ b/lib/auth/trustedcluster.go @@ -30,6 +30,7 @@ import ( "github.com/gravitational/trace" "github.com/gravitational/teleport" + "github.com/gravitational/teleport/api/client/webclient" tracehttp "github.com/gravitational/teleport/api/observability/tracing/http" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" @@ -45,7 +46,53 @@ import ( ) // UpsertTrustedCluster creates or toggles a Trusted Cluster relationship. +// Deprecated: UpsertTrustedClusterV2 should be preferred instead. func (a *Server) UpsertTrustedCluster(ctx context.Context, tc types.TrustedCluster) (newTrustedCluster types.TrustedCluster, returnErr error) { + const validateNameFalse = false + upserted, err := a.upsertTrustedCluster(ctx, tc, validateNameFalse) + return upserted, trace.Wrap(err) +} + +// UpsertTrustedClusterV2 creates or toggles a Trusted Cluster relationship. +// The trusted cluster resource name must match the cluster name. +func (a *Server) UpsertTrustedClusterV2(ctx context.Context, tc types.TrustedCluster) (newTrustedCluster types.TrustedCluster, returnErr error) { + const validateNameTrue = true + upserted, err := a.upsertTrustedCluster(ctx, tc, validateNameTrue) + return upserted, trace.Wrap(err) +} + +// CreateTrustedCluster creates a Trusted Cluster relationship. +func (a *Server) CreateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (newTrustedCluster types.TrustedCluster, returnErr error) { + // verify that trusted cluster role map does not reference non-existent roles + if err := a.checkLocalRoles(ctx, tc.GetRoleMap()); err != nil { + return nil, trace.Wrap(err) + } + + const validateNameTrue = true + created, err := a.createTrustedCluster(ctx, tc, validateNameTrue) + return created, trace.Wrap(err) +} + +// UpdateTrustedCluster updates a Trusted Cluster relationship. +func (a *Server) UpdateTrustedCluster(ctx context.Context, tc types.TrustedCluster) (newTrustedCluster types.TrustedCluster, returnErr error) { + // verify that trusted cluster role map does not reference non-existent roles + if err := a.checkLocalRoles(ctx, tc.GetRoleMap()); err != nil { + return nil, trace.Wrap(err) + } + + existingCluster, err := a.GetTrustedCluster(ctx, tc.GetName()) + if err != nil { + return nil, trace.Wrap(err) + } + + updated, err := a.updateTrustedCluster(ctx, tc, existingCluster) + return updated, trace.Wrap(err) +} + +// upsertTrustedCluster upserts the trusted cluster. +// If validateName is true, the trusted cluster resource name must be validated +// before the trusted cluster is created. +func (a *Server) upsertTrustedCluster(ctx context.Context, tc types.TrustedCluster, validateName bool) (types.TrustedCluster, error) { // verify that trusted cluster role map does not reference non-existent roles if err := a.checkLocalRoles(ctx, tc.GetRoleMap()); err != nil { return nil, trace.Wrap(err) @@ -67,7 +114,7 @@ func (a *Server) UpsertTrustedCluster(ctx context.Context, tc types.TrustedClust // if there is no existing cluster, switch to the create case if existingCluster == nil { - return a.createTrustedCluster(ctx, tc) + return a.createTrustedCluster(ctx, tc, validateName) } if err := existingCluster.CanChangeStateTo(tc); err != nil { @@ -103,8 +150,11 @@ func (a *Server) UpsertTrustedCluster(ctx context.Context, tc types.TrustedClust return tc, nil } -func (a *Server) createTrustedCluster(ctx context.Context, tc types.TrustedCluster) (types.TrustedCluster, error) { - remoteCAs, err := a.establishTrust(ctx, tc) +// createTrustedCluster creates the trusted cluster. +// If validateName is true, the trusted cluster resource name must be validated +// before the trusted cluster is created. +func (a *Server) createTrustedCluster(ctx context.Context, tc types.TrustedCluster, validateName bool) (types.TrustedCluster, error) { + remoteCAs, err := a.establishTrust(ctx, tc, validateName) if err != nil { return nil, trace.Wrap(err) } @@ -130,6 +180,38 @@ func (a *Server) createTrustedCluster(ctx context.Context, tc types.TrustedClust return tc, nil } +// updateTrustedCluster updates the trusted cluster. +func (a *Server) updateTrustedCluster(ctx context.Context, tc types.TrustedCluster, existingCluster types.TrustedCluster) (types.TrustedCluster, error) { + if err := existingCluster.CanChangeStateTo(tc); err != nil { + return nil, trace.Wrap(err) + } + + // always load all current CAs. even if we aren't changing them as part of + // this function, Services.UpdateTrustedCluster will only correctly activate/deactivate + // CAs that are explicitly passed to it. note that we pass in the existing cluster state + // since where CAs are stored depends on the current state of the trusted cluster. + cas, err := a.getCAsForTrustedCluster(ctx, existingCluster) + if err != nil { + return nil, trace.Wrap(err) + } + + // propagate any role map changes to cas + configureCAsForTrustedCluster(tc, cas) + + revision, err := a.Services.UpdateTrustedCluster(ctx, tc, cas) + if err != nil { + return nil, trace.Wrap(err) + } + + tc.SetRevision(revision) + + if err := a.onTrustedClusterWrite(ctx, tc); err != nil { + return nil, trace.Wrap(err) + } + + return tc, nil +} + // configureCAsForTrustedCluster modifies remote CAs for use as trusted cluster CAs. func configureCAsForTrustedCluster(tc types.TrustedCluster, cas []types.CertAuthority) { // modify the remote CAs for use as tc cas. @@ -267,7 +349,7 @@ func (a *Server) DeleteTrustedCluster(ctx context.Context, name string) error { return nil } -func (a *Server) establishTrust(ctx context.Context, trustedCluster types.TrustedCluster) ([]types.CertAuthority, error) { +func (a *Server) establishTrust(ctx context.Context, trustedCluster types.TrustedCluster, validateName bool) ([]types.CertAuthority, error) { var localCertAuthorities []types.CertAuthority domainName, err := a.GetDomainName() @@ -286,6 +368,14 @@ func (a *Server) establishTrust(ctx context.Context, trustedCluster types.Truste } } + // Validate cluster names before establishing trust to avoid unnecessarily + // creating a remote_cluster resource on the root cluster. + if validateName { + if err := a.validateTrustedClusterName(ctx, trustedCluster); err != nil { + return nil, trace.Wrap(err) + } + } + // create a request to validate a trusted cluster (token and local certificate authorities) validateRequest := authclient.ValidateTrustedClusterRequest{ Token: trustedCluster.GetToken(), @@ -322,9 +412,10 @@ func (a *Server) establishTrust(ctx context.Context, trustedCluster types.Truste if remoteClusterName == domainName { return nil, trace.BadParameter("remote cluster name can not be the same as local cluster name") } - // TODO(klizhentas) in 2.5.0 prohibit adding trusted cluster resource name - // different from cluster name (we had no way of checking this before x509, - // because SSH CA was a public key, not a cert with metadata) + if validateName && trustedCluster.GetName() != remoteClusterName { + return nil, trace.BadParameter("trusted cluster resource name must be the same as the remote cluster name. got: %q", + trustedCluster.GetName()) + } } } @@ -586,7 +677,6 @@ func (a *Server) sendValidateRequestToProxy(host string, validateRequest *authcl if err != nil { return nil, trace.Wrap(err) } - validateRequestRaw, err := validateRequest.ToRaw() if err != nil { return nil, trace.Wrap(err) @@ -611,6 +701,24 @@ func (a *Server) sendValidateRequestToProxy(host string, validateRequest *authcl return validateResponse, nil } +// validateTrustedClusterName validates that the trusted cluster resource name +// matches the cluster name. +func (a *Server) validateTrustedClusterName(ctx context.Context, trustedCluster types.TrustedCluster) error { + resp, err := webclient.Find(&webclient.Config{ + Context: ctx, + ProxyAddr: trustedCluster.GetProxyAddress(), + Insecure: lib.IsInsecureDevMode(), + }) + if err != nil { + return trace.Wrap(err) + } + if trustedCluster.GetName() != resp.ClusterName { + return trace.BadParameter("trusted cluster resource name must be the same as the remote cluster name. got: %q", + trustedCluster.GetName()) + } + return nil +} + // createReverseTunnel will create a services.ReverseTunnel givenin the // services.TrustedCluster resource. func (a *Server) createReverseTunnel(ctx context.Context, t types.TrustedCluster) error { diff --git a/lib/auth/trustedcluster_test.go b/lib/auth/trustedcluster_test.go index c65287c5064ff..aca02a7dc4943 100644 --- a/lib/auth/trustedcluster_test.go +++ b/lib/auth/trustedcluster_test.go @@ -453,17 +453,23 @@ func TestUpsertTrustedCluster(t *testing.T) { err = a.SetStaticTokens(tks) require.NoError(t, err) - trustedCluster, err := types.NewTrustedCluster("trustedcluster", - types.TrustedClusterSpecV2{ - Enabled: true, - RoleMap: []types.RoleMapping{ - { - Local: []string{"someRole"}, - Remote: "someRole", - }, + role, err := types.NewRole("test-role", types.RoleSpecV6{}) + require.NoError(t, err) + _, err = a.UpsertRole(ctx, role) + require.NoError(t, err) + + trustedClusterSpec := types.TrustedClusterSpecV2{ + Enabled: true, + RoleMap: []types.RoleMapping{ + { + Local: []string{"test-role"}, + Remote: "someRole", }, - ProxyAddress: "localhost", - }) + }, + ProxyAddress: "localhost", + } + + trustedCluster, err := types.NewTrustedCluster("trustedcluster", trustedClusterSpec) require.NoError(t, err) ca := suite.NewTestCA(types.UserCA, "trustedcluster") @@ -489,7 +495,7 @@ func TestUpsertTrustedCluster(t *testing.T) { ProxyAddress: "localhost", }) require.NoError(t, err) - _, err = a.UpsertTrustedCluster(ctx, trustedCluster) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) require.ErrorContains(t, err, "someNewRole") }) t.Run("Change role map of existing enabled trusted cluster", func(t *testing.T) { @@ -505,7 +511,7 @@ func TestUpsertTrustedCluster(t *testing.T) { ProxyAddress: "localhost", }) require.NoError(t, err) - _, err = a.UpsertTrustedCluster(ctx, trustedCluster) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) require.NoError(t, err) }) t.Run("Disable existing trusted cluster", func(t *testing.T) { @@ -521,7 +527,7 @@ func TestUpsertTrustedCluster(t *testing.T) { ProxyAddress: "localhost", }) require.NoError(t, err) - _, err = a.UpsertTrustedCluster(ctx, trustedCluster) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) require.NoError(t, err) }) t.Run("Change role map of existing disabled trusted cluster", func(t *testing.T) { @@ -537,7 +543,7 @@ func TestUpsertTrustedCluster(t *testing.T) { ProxyAddress: "localhost", }) require.NoError(t, err) - _, err = a.UpsertTrustedCluster(ctx, trustedCluster) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) require.NoError(t, err) }) t.Run("Enable existing trusted cluster", func(t *testing.T) { @@ -553,23 +559,177 @@ func TestUpsertTrustedCluster(t *testing.T) { ProxyAddress: "localhost", }) require.NoError(t, err) - _, err = a.UpsertTrustedCluster(ctx, trustedCluster) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) require.NoError(t, err) }) - t.Run("Cloud prohibits being a leaf cluster", func(t *testing.T) { - modules.SetTestModules(t, &modules.TestModules{ - TestFeatures: modules.Features{Cloud: true}, - }) + t.Run("Upsert unmodified trusted cluster", func(t *testing.T) { + trustedCluster, err := types.NewTrustedCluster("trustedcluster", trustedClusterSpec) + require.NoError(t, err) + _, err = a.UpsertTrustedClusterV2(ctx, trustedCluster) + require.NoError(t, err) + }) +} + +func TestUpdateTrustedCluster(t *testing.T) { + ctx := context.Background() + testAuth, err := NewTestAuthServer(TestAuthServerConfig{ + ClusterName: "localcluster", + Dir: t.TempDir(), + }) + require.NoError(t, err) + a := testAuth.AuthServer + + const validToken = "validtoken" + tks, err := types.NewStaticTokens(types.StaticTokensSpecV2{ + StaticTokens: []types.ProvisionTokenV1{{ + Roles: []types.SystemRole{types.RoleTrustedCluster}, + Token: validToken, + }}, + }) + require.NoError(t, err) + + err = a.SetStaticTokens(tks) + require.NoError(t, err) - tc, err := types.NewTrustedCluster("test", types.TrustedClusterSpecV2{ - RoleMap: []types.RoleMapping{ - {Remote: teleport.PresetAccessRoleName, Local: []string{teleport.PresetAccessRoleName}}, + role, err := types.NewRole("test-role", types.RoleSpecV6{}) + require.NoError(t, err) + _, err = a.UpsertRole(ctx, role) + require.NoError(t, err) + + trustedClusterSpec := types.TrustedClusterSpecV2{ + Enabled: true, + RoleMap: []types.RoleMapping{ + { + Local: []string{"test-role"}, + Remote: "someRole", }, - }) - require.NoError(t, err, "creating trusted cluster resource") + }, + ProxyAddress: "localhost", + } - server := ServerWithRoles{authServer: a} - _, err = server.UpsertTrustedCluster(ctx, tc) - require.True(t, trace.IsNotImplemented(err), "UpsertTrustedCluster returned an unexpected error, got = %v (%T), want trace.NotImplementedError", err, err) + testClusterName := "trustedcluster" + trustedCluster, err := types.NewTrustedCluster(testClusterName, trustedClusterSpec) + require.NoError(t, err) + + ca := suite.NewTestCA(types.UserCA, testClusterName) + + configureCAsForTrustedCluster(trustedCluster, []types.CertAuthority{ca}) + + _, err = a.Services.CreateTrustedCluster(ctx, trustedCluster, []types.CertAuthority{ca}) + require.NoError(t, err) + + err = a.createReverseTunnel(ctx, trustedCluster) + require.NoError(t, err) + + t.Run("Invalid role change", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, + types.TrustedClusterSpecV2{ + Enabled: true, + RoleMap: []types.RoleMapping{ + { + Local: []string{"someNewRole"}, + Remote: "someRole", + }, + }, + ProxyAddress: "localhost", + }) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.ErrorContains(t, err, "someNewRole") + }) + t.Run("Change role map of existing enabled trusted cluster", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, + types.TrustedClusterSpecV2{ + Enabled: true, + RoleMap: []types.RoleMapping{ + { + Local: []string{constants.DefaultImplicitRole}, + Remote: "someRole", + }, + }, + ProxyAddress: "localhost", + }) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.NoError(t, err) + }) + t.Run("Disable existing trusted cluster", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, + types.TrustedClusterSpecV2{ + Enabled: false, + RoleMap: []types.RoleMapping{ + { + Local: []string{constants.DefaultImplicitRole}, + Remote: "someRole", + }, + }, + ProxyAddress: "localhost", + }) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.NoError(t, err) + }) + t.Run("Change role map of existing disabled trusted cluster", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, + types.TrustedClusterSpecV2{ + Enabled: false, + RoleMap: []types.RoleMapping{ + { + Local: []string{constants.DefaultImplicitRole}, + Remote: "someOtherRole", + }, + }, + ProxyAddress: "localhost", + }) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.NoError(t, err) + }) + t.Run("Enable existing trusted cluster", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, + types.TrustedClusterSpecV2{ + Enabled: true, + RoleMap: []types.RoleMapping{ + { + Local: []string{constants.DefaultImplicitRole}, + Remote: "someOtherRole", + }, + }, + ProxyAddress: "localhost", + }) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.NoError(t, err) + }) + t.Run("Update unmodified trusted cluster", func(t *testing.T) { + existing, err := a.GetTrustedCluster(ctx, testClusterName) + require.NoError(t, err) + trustedCluster, err := types.NewTrustedCluster(testClusterName, trustedClusterSpec) + require.NoError(t, err) + trustedCluster.SetRevision(existing.GetRevision()) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.NoError(t, err) + }) + + t.Run("Invalid revision", func(t *testing.T) { + trustedCluster, err := types.NewTrustedCluster(testClusterName, trustedClusterSpec) + require.NoError(t, err) + _, err = a.UpdateTrustedCluster(ctx, trustedCluster) + require.Error(t, err) }) } diff --git a/lib/auth/userloginstate/generator.go b/lib/auth/userloginstate/generator.go index f9c72ac1a5f07..1eddc9c81ea53 100644 --- a/lib/auth/userloginstate/generator.go +++ b/lib/auth/userloginstate/generator.go @@ -21,10 +21,10 @@ package userloginstate import ( "context" "fmt" + "log/slog" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" usageeventsv1 "github.com/gravitational/teleport/api/gen/proto/go/usageevents/v1" @@ -49,7 +49,7 @@ type AccessListsAndLockGetter interface { // GeneratorConfig is the configuration for the user login state generator. type GeneratorConfig struct { // Log is a logger to use for the generator. - Log *logrus.Entry + Log *slog.Logger // AccessLists is a service for retrieving access lists and locks from the backend. AccessLists AccessListsAndLockGetter @@ -107,7 +107,7 @@ func (g *GeneratorConfig) CheckAndSetDefaults() error { // Generator will generate a user login state from a user. type Generator struct { - log *logrus.Entry + log *slog.Logger accessLists AccessListsAndLockGetter access services.Access usageEvents UsageEventsClient @@ -191,7 +191,7 @@ func (g *Generator) Generate(ctx context.Context, user types.User, ulsService se if g.usageEvents != nil { // Emit the usage event metadata. if err := g.emitUsageEvent(ctx, user, uls, inheritedRoles, inheritedTraits); err != nil { - g.log.WithError(err).Debug("Error emitting usage event during user login state generation, skipping") + g.log.DebugContext(ctx, "Error emitting usage event during user login state generation, skipping", "error", err) } } @@ -245,7 +245,7 @@ func (g *Generator) handleAccessListMembership(ctx context.Context, user types.U if err != nil || membershipKind == accesslists.MembershipOrOwnershipTypeNone { // Log any error. if err != nil { - g.log.WithError(err).Warn("checking access list membership") + g.log.WarnContext(ctx, "checking access list membership", "error", err) } return inheritedRoles, inheritedTraits, nil } @@ -290,7 +290,7 @@ func (g *Generator) handleAccessListOwnership(ctx context.Context, user types.Us if err != nil || ownershipType == accesslists.MembershipOrOwnershipTypeNone { // Log any error. if err != nil { - g.log.WithError(err).Warn("checking access list ownership") + g.log.WarnContext(ctx, "checking access list ownership", "error", err) } return inheritedRoles, inheritedTraits, nil } @@ -497,6 +497,6 @@ func (g *Generator) emitSkippedAccessListEvent(ctx context.Context, accessListNa UserMessage: "access list skipped because it references non-existent role(s)", }, }); err != nil { - g.log.WithError(err).Warn("Failed to emit access list skipped warning audit event.") + g.log.WarnContext(ctx, "Failed to emit access list skipped warning audit event", "error", err) } } diff --git a/lib/auth/userloginstate/generator_test.go b/lib/auth/userloginstate/generator_test.go index 1154dec233de3..a263297c416c9 100644 --- a/lib/auth/userloginstate/generator_test.go +++ b/lib/auth/userloginstate/generator_test.go @@ -26,7 +26,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/client/proto" @@ -42,6 +41,7 @@ import ( "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" + "github.com/gravitational/teleport/lib/utils" ) const ownerUser = "owner" @@ -729,7 +729,6 @@ func initGeneratorSvc(t *testing.T) (*Generator, *svc) { ulsService, err := local.NewUserLoginStateService(mem) require.NoError(t, err) - log := logrus.WithField("test", "logger") svc := &svc{ AccessLists: accessListsSvc, Access: accessSvc, @@ -739,7 +738,7 @@ func initGeneratorSvc(t *testing.T) (*Generator, *svc) { emitter := &eventstest.MockRecorderEmitter{} generator, err := NewGenerator(GeneratorConfig{ - Log: log, + Log: utils.NewSlogLoggerForTests(), AccessLists: svc, Access: svc, UsageEvents: svc, diff --git a/lib/auth/userloginstate/userloginstatev1/service.go b/lib/auth/userloginstate/userloginstatev1/service.go index 1b4bbb43cc2a1..fc51ac2b299c6 100644 --- a/lib/auth/userloginstate/userloginstatev1/service.go +++ b/lib/auth/userloginstate/userloginstatev1/service.go @@ -23,10 +23,8 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" - "github.com/gravitational/teleport" userloginstatev1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userloginstate/v1" "github.com/gravitational/teleport/api/types" conv "github.com/gravitational/teleport/api/types/userloginstate/convert/v1" @@ -36,8 +34,6 @@ import ( // ServiceConfig is the service config for the Access Lists gRPC service. type ServiceConfig struct { - // Logger is the logger to use. - Logger logrus.FieldLogger // Authorizer is the authorizer to use. Authorizer authz.Authorizer @@ -58,10 +54,6 @@ func (c *ServiceConfig) checkAndSetDefaults() error { return trace.BadParameter("user login states service is missing") } - if c.Logger == nil { - c.Logger = logrus.WithField(teleport.ComponentKey, "user_login_state_crud_service") - } - if c.Clock == nil { c.Clock = clockwork.NewRealClock() } @@ -72,7 +64,6 @@ func (c *ServiceConfig) checkAndSetDefaults() error { type Service struct { userloginstatev1.UnimplementedUserLoginStateServiceServer - log logrus.FieldLogger authorizer authz.Authorizer userLoginStates services.UserLoginStates clock clockwork.Clock @@ -85,7 +76,6 @@ func NewService(cfg ServiceConfig) (*Service, error) { } return &Service{ - log: cfg.Logger, authorizer: cfg.Authorizer, userLoginStates: cfg.UserLoginStates, clock: cfg.Clock, diff --git a/lib/auth/userpreferences/userpreferencesv1/service.go b/lib/auth/userpreferences/userpreferencesv1/service.go index 0a0b8605c5f11..2bf7b1b339979 100644 --- a/lib/auth/userpreferences/userpreferencesv1/service.go +++ b/lib/auth/userpreferences/userpreferencesv1/service.go @@ -22,10 +22,8 @@ import ( "context" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" - "github.com/gravitational/teleport" userpreferences "github.com/gravitational/teleport/api/gen/proto/go/userpreferences/v1" "github.com/gravitational/teleport/lib/authz" "github.com/gravitational/teleport/lib/services" @@ -35,7 +33,6 @@ import ( type ServiceConfig struct { Backend services.UserPreferences Authorizer authz.Authorizer - Logger *logrus.Entry } // Service implements the teleport.userpreferences.v1.UserPreferencesService RPC service. @@ -44,7 +41,6 @@ type Service struct { backend services.UserPreferences authorizer authz.Authorizer - log *logrus.Entry } // NewService returns a new user preferences gRPC service. @@ -54,14 +50,11 @@ func NewService(cfg *ServiceConfig) (*Service, error) { return nil, trace.BadParameter("backend is required") case cfg.Authorizer == nil: return nil, trace.BadParameter("authorizer is required") - case cfg.Logger == nil: - cfg.Logger = logrus.WithField(teleport.ComponentKey, "userpreferences.service") } return &Service{ backend: cfg.Backend, authorizer: cfg.Authorizer, - log: cfg.Logger, }, nil } diff --git a/lib/auth/users/usersv1/service.go b/lib/auth/users/usersv1/service.go index 217a258002392..3a7a3bd630e27 100644 --- a/lib/auth/users/usersv1/service.go +++ b/lib/auth/users/usersv1/service.go @@ -20,10 +20,10 @@ package usersv1 import ( "context" + "log/slog" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" "github.com/gravitational/teleport" @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/services" usagereporter "github.com/gravitational/teleport/lib/usagereporter/teleport" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // Cache is the subset of the cached resources that the Service queries. @@ -69,7 +70,7 @@ type ServiceConfig struct { Authorizer authz.Authorizer Cache Cache Backend Backend - Logger logrus.FieldLogger + Logger *slog.Logger Emitter apievents.Emitter Reporter usagereporter.UsageReporter Clock clockwork.Clock @@ -82,7 +83,7 @@ type Service struct { authorizer authz.Authorizer cache Cache backend Backend - logger logrus.FieldLogger + logger *slog.Logger emitter apievents.Emitter reporter usagereporter.UsageReporter clock clockwork.Clock @@ -104,7 +105,7 @@ func NewService(cfg ServiceConfig) (*Service, error) { } if cfg.Logger == nil { - cfg.Logger = logrus.WithField(teleport.ComponentKey, "users.service") + cfg.Logger = slog.With(teleport.ComponentKey, "users.service") } if cfg.Clock == nil { cfg.Clock = clockwork.NewRealClock() @@ -171,7 +172,7 @@ func (s *Service) GetUser(ctx context.Context, req *userspb.GetUserRequest) (*us // migrated to that model. if !authz.HasBuiltinRole(*authCtx, string(types.RoleAdmin)) { err := trace.AccessDenied("user %q requested access to user %q with secrets", authCtx.User.GetName(), req.Name) - s.logger.Warn(err) + s.logger.WarnContext(ctx, "use does not have permission to read user with sercrets", "error", err) if err := s.emitter.EmitAuditEvent(ctx, &apievents.UserLogin{ Metadata: apievents.Metadata{ Type: events.UserLoginEvent, @@ -184,7 +185,7 @@ func (s *Service) GetUser(ctx context.Context, req *userspb.GetUserRequest) (*us UserMessage: err.Error(), }, }); err != nil { - s.logger.WithError(err).Warn("Failed to emit local login failure event.") + s.logger.WarnContext(ctx, "Failed to emit local login failure event", "error", err) } return nil, trace.AccessDenied("this request can be only executed by an admin") } @@ -206,7 +207,11 @@ func (s *Service) GetUser(ctx context.Context, req *userspb.GetUserRequest) (*us v2, ok := user.(*types.UserV2) if !ok { - s.logger.Warnf("expected type UserV2, got %T for user %q", user, user.GetName()) + s.logger.WarnContext(ctx, "unexpected user type", + "got_type", logutils.TypeAttr(user), + "expected_type", "UserV2", + "user", user.GetName(), + ) return nil, trace.BadParameter("encountered unexpected user type") } @@ -271,14 +276,18 @@ func (s *Service) CreateUser(ctx context.Context, req *userspb.CreateUserRequest Roles: created.GetRoles(), ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - s.logger.WithError(err).Warn("Failed to emit user create event.") + s.logger.WarnContext(ctx, "Failed to emit user create event", "error", err) } usagereporter.EmitEditorChangeEvent(created.GetName(), nil, created.GetRoles(), s.reporter.AnonymizeAndSubmit) v2, ok := created.(*types.UserV2) if !ok { - s.logger.Warnf("expected type UserV2, got %T for user %q", created, created.GetName()) + s.logger.WarnContext(ctx, "unexpected user type", + "got_type", logutils.TypeAttr(created), + "expected_type", "UserV2", + "user", created.GetName(), + ) return nil, trace.BadParameter("encountered unexpected user type") } @@ -319,7 +328,7 @@ func (s *Service) UpdateUser(ctx context.Context, req *userspb.UpdateUserRequest var omitEditorEvent bool if err != nil { // don't return error here since this call is for event emitting purposes only - s.logger.WithError(err).Warn("Failed getting previous user during update") + s.logger.WarnContext(ctx, "Failed getting previous user during update", "error", err) omitEditorEvent = true } @@ -356,7 +365,7 @@ func (s *Service) UpdateUser(ctx context.Context, req *userspb.UpdateUserRequest Roles: updated.GetRoles(), ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - s.logger.WithError(err).Warn("Failed to emit user update event.") + s.logger.WarnContext(ctx, "Failed to emit user update event", "error", err) } if !omitEditorEvent { @@ -365,7 +374,11 @@ func (s *Service) UpdateUser(ctx context.Context, req *userspb.UpdateUserRequest v2, ok := updated.(*types.UserV2) if !ok { - s.logger.Warnf("expected type UserV2, got %T for user %q", updated, updated.GetName()) + s.logger.WarnContext(ctx, "unexpected user type", + "got_type", logutils.TypeAttr(updated), + "expected_type", "UserV2", + "user", updated.GetName(), + ) return nil, trace.BadParameter("encountered unexpected user type") } @@ -405,7 +418,7 @@ func (s *Service) UpsertUser(ctx context.Context, req *userspb.UpsertUserRequest var omitEditorEvent bool if err != nil { // don't return error here since this call is for event emitting purposes only - s.logger.WithError(err).Warn("Failed getting previous user during update") + s.logger.WarnContext(ctx, "Failed getting previous user during update", "error", err) omitEditorEvent = true } @@ -446,7 +459,7 @@ func (s *Service) UpsertUser(ctx context.Context, req *userspb.UpsertUserRequest Roles: upserted.GetRoles(), ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - s.logger.WithError(err).Warn("Failed to emit user upsert event.") + s.logger.WarnContext(ctx, "Failed to emit user upsert event", "error", err) } if !omitEditorEvent { @@ -455,7 +468,11 @@ func (s *Service) UpsertUser(ctx context.Context, req *userspb.UpsertUserRequest v2, ok := upserted.(*types.UserV2) if !ok { - s.logger.Warnf("expected type UserV2, got %T for user %q", upserted, upserted.GetName()) + s.logger.WarnContext(ctx, "unexpected user type", + "got_type", logutils.TypeAttr(upserted), + "expected_type", "UserV2", + "user", upserted.GetName(), + ) return nil, trace.BadParameter("encountered unexpected user type") } @@ -480,7 +497,7 @@ func (s *Service) DeleteUser(ctx context.Context, req *userspb.DeleteUserRequest var omitEditorEvent bool if err != nil && !trace.IsNotFound(err) { // don't return error here, delete may still succeed - s.logger.WithError(err).Warn("Failed getting previous user during delete operation") + s.logger.WarnContext(ctx, "Failed getting previous user during delete operation", "error", err) prevUser = nil omitEditorEvent = true } @@ -518,7 +535,7 @@ func (s *Service) DeleteUser(ctx context.Context, req *userspb.DeleteUserRequest }, ConnectionMetadata: authz.ConnectionMetadata(ctx), }); err != nil { - s.logger.WithError(err).Warn("Failed to emit user delete event.") + s.logger.WarnContext(ctx, "Failed to emit user delete event", "error", err) } if !omitEditorEvent { @@ -539,7 +556,7 @@ func (s *Service) ListUsers(ctx context.Context, req *userspb.ListUsersRequest) // migrated to that model. if !authz.HasBuiltinRole(*authCtx, string(types.RoleAdmin)) { err := trace.AccessDenied("user %q requested access to all users with secrets", authCtx.User.GetName()) - s.logger.Warn(err) + s.logger.WarnContext(ctx, "use does not have permission to read all users with sercrets", "error", err) if err := s.emitter.EmitAuditEvent(ctx, &apievents.UserLogin{ Metadata: apievents.Metadata{ Type: events.UserLoginEvent, @@ -552,7 +569,7 @@ func (s *Service) ListUsers(ctx context.Context, req *userspb.ListUsersRequest) UserMessage: err.Error(), }, }); err != nil { - s.logger.WithError(err).Warn("Failed to emit local login failure event.") + s.logger.WarnContext(ctx, "Failed to emit local login failure event", "error", err) } return nil, trace.AccessDenied("this request can be only executed by an admin") } diff --git a/lib/auth/webauthn/attestation.go b/lib/auth/webauthn/attestation.go index a382229dce048..fa14c23a21ed1 100644 --- a/lib/auth/webauthn/attestation.go +++ b/lib/auth/webauthn/attestation.go @@ -19,17 +19,22 @@ package webauthn import ( + "context" "crypto/x509" "encoding/pem" + "log/slog" "slices" "github.com/go-webauthn/webauthn/protocol" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" + "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" + logutils "github.com/gravitational/teleport/lib/utils/log" ) +var log = logutils.NewPackageLogger(teleport.ComponentKey, "WebAuthn") + // x5cFormats enumerates all attestation formats that supply an attestation // chain through the "x5c" field. // See https://www.w3.org/TR/webauthn/#sctn-defined-attestation-formats. @@ -138,13 +143,17 @@ func getChainFromX5C(obj protocol.AttestationObject) ([]*x509.Certificate, error // Print out attestation certs if debug is enabled. // This may come in handy for people having trouble with their setups. - if log.IsLevelEnabled(log.DebugLevel) { + ctx := context.Background() + if log.Handler().Enabled(ctx, slog.LevelDebug) { for _, cert := range chain { certPEM := pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, }) - log.Debugf("WebAuthn: got %q attestation certificate:\n\n%s", obj.Format, certPEM) + log.DebugContext(context.Background(), "got attestation certificate", + "format", obj.Format, + "certificate", string(certPEM), + ) } } diff --git a/lib/auth/webauthn/device.go b/lib/auth/webauthn/device.go index a78ec9f7fea4f..700f671b4d264 100644 --- a/lib/auth/webauthn/device.go +++ b/lib/auth/webauthn/device.go @@ -19,6 +19,7 @@ package webauthn import ( + "context" "crypto/ecdsa" "crypto/x509" @@ -26,7 +27,6 @@ import ( "github.com/go-webauthn/webauthn/protocol/webauthncose" wan "github.com/go-webauthn/webauthn/webauthn" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" ) @@ -51,7 +51,7 @@ func deviceToCredential( var err error pubKeyCBOR, err = u2fDERKeyToCBOR(dev.U2F.PubKey) if err != nil { - log.Warnf("WebAuthn: failed to convert U2F device key to CBOR: %v", err) + log.WarnContext(context.Background(), "failed to convert U2F device key to CBOR", "error", err) return wan.Credential{}, false } } diff --git a/lib/auth/webauthn/login.go b/lib/auth/webauthn/login.go index 2ed9f085155a6..9948602beeba6 100644 --- a/lib/auth/webauthn/login.go +++ b/lib/auth/webauthn/login.go @@ -31,7 +31,6 @@ import ( wan "github.com/go-webauthn/webauthn/webauthn" gogotypes "github.com/gogo/protobuf/types" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" mfav1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/mfa/v1" "github.com/gravitational/teleport/api/types" @@ -107,13 +106,14 @@ func (f *loginFlow) begin(ctx context.Context, user string, challengeExtensions continue } - log.Errorf(""+ - "User device %q/%q has unexpected RPID=%q, excluding from allowed credentials. "+ - "RPID changes are not supported by WebAuthn, this is likely to cause permanent authentication problems for your users. "+ - "Consider reverting the change or reset your users so they may register their devices again.", - user, - devices[i].GetName(), - webDev.CredentialRpId) + const msg = "User device has unexpected RPID, excluding from allowed credentials. " + + "RPID changes are not supported by WebAuthn, this is likely to cause permanent authentication problems for your users. " + + "Consider reverting the change or reset your users so they may register their devices again." + log.ErrorContext(ctx, msg, + "user", user, + "device", devices[i].GetName(), + "rpid", webDev.CredentialRpId, + ) // "Cut" device from slice. devices = slices.Delete(devices, i, i+1) @@ -249,7 +249,7 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred origin := parsedResp.Response.CollectedClientData.Origin if err := validateOrigin(origin, f.Webauthn.RPID); err != nil { - log.WithError(err).Debugf("WebAuthn: origin validation failed") + log.DebugContext(ctx, "origin validation failed", "error", err) return nil, trace.Wrap(err) } @@ -330,9 +330,9 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred if (discoverableLogin || uvr == protocol.VerificationRequired) && sd.UserVerification != string(protocol.VerificationRequired) { // This is not a failure yet, but will likely become one. sd.UserVerification = string(protocol.VerificationRequired) - log.Warnf(""+ - "WebAuthn: User verification required by extensions but not by challenge. "+ - "Increased SessionData.UserVerification to %s.", sd.UserVerification) + const msg = "User verification required by extensions but not by challenge. " + + "Increased SessionData.UserVerification." + log.WarnContext(ctx, msg, "user_verification", sd.UserVerification) } sessionData := wantypes.SessionDataToProtocol(sd) @@ -371,8 +371,10 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred return nil, trace.Wrap(err) } if credential.Authenticator.CloneWarning { - log.Warnf( - "WebAuthn: Clone warning detected for user %q / device %q. Device counter may be malfunctioning.", user, dev.GetName()) + log.WarnContext(ctx, "Clone warning detected for device, the device counter may be malfunctioning", + "user", user, + "device", dev.GetName(), + ) } // Update last used timestamp and device counter. @@ -381,7 +383,11 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred } // Retroactively write the credential RPID, now that it cleared authn. if webDev := dev.GetWebauthn(); webDev != nil && webDev.CredentialRpId == "" { - log.Debugf("WebAuthn: Recording RPID=%q in device %q/%q", rpID, user, dev.GetName()) + log.DebugContext(ctx, "Recording RPID in device", + "rpid", rpID, + "user", user, + "device", dev.GetName(), + ) webDev.CredentialRpId = rpID } @@ -395,7 +401,10 @@ func (f *loginFlow) finish(ctx context.Context, user string, resp *wantypes.Cred // passes. if sd.ChallengeExtensions.AllowReuse != mfav1.ChallengeAllowReuse_CHALLENGE_ALLOW_REUSE_YES { if err := f.sessionData.Delete(ctx, user, challenge); err != nil { - log.Warnf("WebAuthn: failed to delete login SessionData for user %v (scope = %s)", user, sd.ChallengeExtensions.Scope) + log.WarnContext(ctx, "failed to delete login SessionData for user", + "user", user, + "scope", sd.ChallengeExtensions.Scope, + ) } } @@ -463,19 +472,19 @@ func updateCredentialAndTimestamps( d.Webauthn.CredentialBackupEligible = &gogotypes.BoolValue{ Value: credential.Flags.BackupEligible, } - log.WithFields(log.Fields{ - "device": dest.GetName(), - "be": credential.Flags.BackupEligible, - }).Debug("Backfilled Webauthn device BE flag") + log.DebugContext(context.Background(), "Backfilled Webauthn device BE flag", + "device", dest.GetName(), + "be", credential.Flags.BackupEligible, + ) } if d.Webauthn.CredentialBackedUp == nil { d.Webauthn.CredentialBackedUp = &gogotypes.BoolValue{ Value: credential.Flags.BackupState, } - log.WithFields(log.Fields{ - "device": dest.GetName(), - "bs": credential.Flags.BackupState, - }).Debug("Backfilled Webauthn device BS flag") + log.DebugContext(context.Background(), "Backfilled Webauthn device BS flag", + "device", dest.GetName(), + "bs", credential.Flags.BackupState, + ) } default: diff --git a/lib/auth/webauthn/register.go b/lib/auth/webauthn/register.go index 50eb3420391eb..9d6a0726af232 100644 --- a/lib/auth/webauthn/register.go +++ b/lib/auth/webauthn/register.go @@ -32,7 +32,6 @@ import ( gogotypes "github.com/gogo/protobuf/types" "github.com/google/uuid" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" @@ -284,7 +283,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t origin := parsedResp.Response.CollectedClientData.Origin if err := validateOrigin(origin, f.Webauthn.RPID); err != nil { - log.WithError(err).Debugf("WebAuthn: origin validation failed") + log.DebugContext(ctx, "origin validation failed", "error", err) return nil, trace.Wrap(err) } @@ -332,7 +331,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t protocolErr.Type == protocol.ErrVerification.Type && passwordless && !parsedResp.Response.AttestationObject.AuthData.Flags.UserVerified() { - log.WithError(err).Debug("WebAuthn: Replacing verification error with PIN message") + log.DebugContext(ctx, "WebAuthn: Replacing verification error with PIN message", "error", err) return nil, trace.BadParameter("authenticator doesn't support passwordless, setting up a PIN may fix this") } @@ -378,7 +377,7 @@ func (f *RegistrationFlow) Finish(ctx context.Context, req RegisterResponse) (*t // Registration complete, remove the registration challenge we just used. if err := f.Identity.DeleteWebauthnSessionData(ctx, req.User, scopeSession); err != nil { - log.Warnf("WebAuthn: failed to delete registration SessionData for user %v", req.User) + log.WarnContext(ctx, "failed to delete registration SessionData for user", "user", req.User, "error", err) } return newDevice, nil diff --git a/lib/auth/webauthncli/api.go b/lib/auth/webauthncli/api.go index 8278c77a03634..5ee0f9e4f7d3c 100644 --- a/lib/auth/webauthncli/api.go +++ b/lib/auth/webauthncli/api.go @@ -24,14 +24,20 @@ import ( "strings" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" oteltrace "go.opentelemetry.io/otel/trace" + "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/observability/tracing" "github.com/gravitational/teleport/lib/auth/touchid" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" wanwin "github.com/gravitational/teleport/lib/auth/webauthnwin" + logutils "github.com/gravitational/teleport/lib/utils/log" +) + +var ( + log = logutils.NewPackageLogger(teleport.ComponentKey, "WebAuthn") + fidoLog = logutils.NewPackageLogger(teleport.ComponentKey, "FIDO2") ) // ErrUsingNonRegisteredDevice is returned from Login when the user attempts to @@ -137,10 +143,10 @@ func Login( switch { case origin == "", assertion == nil: // let downstream handle empty/nil case !strings.HasPrefix(origin, "https://"+assertion.Response.RelyingPartyID): - log.Warnf(""+ - "WebAuthn: origin and RPID mismatch, "+ - "if you are having authentication problems double check your proxy address "+ - "(%q vs %q)", origin, assertion.Response.RelyingPartyID) + log.WarnContext(ctx, "origin and RPID mismatch, if you are having authentication problems double check your proxy address", + "origin", origin, + "rpid", assertion.Response.RelyingPartyID, + ) } var attachment AuthenticatorAttachment @@ -151,7 +157,7 @@ func Login( } if wanwin.IsAvailable() { - log.Debug("WebAuthnWin: Using windows webauthn for credential assertion") + log.DebugContext(ctx, "Using windows webauthn for credential assertion") return wanwin.Login(ctx, origin, assertion, &wanwin.LoginOpts{ AuthenticatorAttachment: wanwin.AuthenticatorAttachment(attachment), }) @@ -159,19 +165,19 @@ func Login( switch attachment { case AttachmentCrossPlatform: - log.Debug("Cross-platform login") + log.DebugContext(ctx, "Cross-platform login") return crossPlatformLogin(ctx, origin, assertion, prompt, opts) case AttachmentPlatform: - log.Debug("Platform login") + log.DebugContext(ctx, "Platform login") return platformLogin(origin, user, assertion, prompt) default: - log.Debug("Attempting platform login") + log.DebugContext(ctx, "Attempting platform login") resp, credentialUser, err := platformLogin(origin, user, assertion, prompt) if !errors.Is(err, &touchid.ErrAttemptFailed{}) { return resp, credentialUser, trace.Wrap(err) } - log.WithError(err).Debug("Platform login failed, falling back to cross-platform") + log.DebugContext(ctx, "Platform login failed, falling back to cross-platform", "error", err) return crossPlatformLogin(ctx, origin, assertion, prompt, opts) } } @@ -180,7 +186,7 @@ func crossPlatformLogin( ctx context.Context, origin string, assertion *wantypes.CredentialAssertion, prompt LoginPrompt, opts *LoginOpts, ) (*proto.MFAAuthenticateResponse, string, error) { - log.Debug("FIDO2: Using libfido2 for assertion") + fidoLog.DebugContext(ctx, "Using libfido2 for assertion") resp, user, err := FIDO2Login(ctx, origin, assertion, prompt, opts) return resp, user, trace.Wrap(err) } @@ -223,11 +229,11 @@ func Register( ctx context.Context, origin string, cc *wantypes.CredentialCreation, prompt RegisterPrompt) (*proto.MFARegisterResponse, error) { if wanwin.IsAvailable() { - log.Debug("WebAuthnWin: Using windows webauthn for credential creation") + log.DebugContext(ctx, "Using windows webauthn for credential creation") return wanwin.Register(ctx, origin, cc) } - log.Debug("FIDO2: Using libfido2 for credential creation") + fidoLog.DebugContext(ctx, "Using libfido2 for credential creation") resp, err := FIDO2Register(ctx, origin, cc, prompt) return resp, trace.Wrap(err) } diff --git a/lib/auth/webauthncli/fido2.go b/lib/auth/webauthncli/fido2.go index a20b714fc2fcb..33a033a26b383 100644 --- a/lib/auth/webauthncli/fido2.go +++ b/lib/auth/webauthncli/fido2.go @@ -29,6 +29,7 @@ import ( "encoding/json" "errors" "fmt" + "log/slog" "sync" "time" @@ -37,7 +38,6 @@ import ( "github.com/go-webauthn/webauthn/protocol/webauthncose" "github.com/gravitational/trace" "github.com/keys-pub/go-libfido2" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" wanpb "github.com/gravitational/teleport/api/types/webauthn" @@ -165,7 +165,11 @@ func fido2Login( // Presence of any allowed credential is interpreted as the user identity // being partially established, aka non-passwordless. passwordless := len(allowedCreds) == 0 - log.Debugf("FIDO2: assertion: passwordless=%v, uv=%v, %v allowed credentials", passwordless, uv, len(allowedCreds)) + fidoLog.DebugContext(ctx, "assertion", + "passwordless", passwordless, + "uv", uv, + "allowed_cred_count", len(allowedCreds), + ) // Prepare challenge data for the device. ccdJSON, err := json.Marshal(&CollectedClientData{ @@ -209,7 +213,11 @@ func fido2Login( deviceCallback := func(dev FIDODevice, info *deviceInfo, pin string) error { actualRPID := rpID if usesAppID(dev, info, ccdHash[:], allowedCreds, rpID, appID) { - log.Debugf("FIDO2: Device %v registered for AppID (%q) instead of RPID", info.path, appID) + fidoLog.DebugContext(ctx, "Device registered for AppID instead of RPID", + "device", info.path, + "app_id", appID, + "rp_id", rpID, + ) actualRPID = appID } @@ -227,7 +235,7 @@ func fido2Login( // Happens inconsistently in some authenticator series (YubiKey 5). // We are relying on the fact that, because the PIN is set, the // authenticator will set the UV bit regardless of it being requested. - log.Debugf("FIDO2: Device %v: retrying assertion without UV", info.path) + fidoLog.DebugContext(ctx, "Retrying assertion without UV", "device", info.path) opts.UV = libfido2.Default assertions, err = devAssertion(dev, info, actualRPID, ccdHash[:], allowedCreds, pin, opts) } @@ -239,7 +247,7 @@ func fido2Login( // touch - this causes another slew of problems with abandoned U2F // goroutines during registration. if !info.fido2 { - log.Debugf("FIDO2: U2F device %v not registered, ignoring it", info.path) + fidoLog.DebugContext(ctx, "U2F device not registered, ignoring it", "device", info.path) err = &nonInteractiveError{err: err} } else { err = ErrUsingNonRegisteredDevice // "Upgrade" error message. @@ -248,7 +256,7 @@ func fido2Login( if err != nil { return trace.Wrap(err) } - log.Debugf("FIDO2: Got %v assertions", len(assertions)) + fidoLog.DebugContext(ctx, "Got assertions", "assertion_count", len(assertions)) // Find assertion for target user, or show the prompt. assertion, err := pickAssertion(assertions, prompt, user, passwordless) @@ -256,9 +264,11 @@ func fido2Login( return trace.Wrap(err) } - log.Debugf( - "FIDO2: Authenticated: credential ID (b64) = %v, user ID (hex) = %x, user name = %q", - base64.RawURLEncoding.EncodeToString(assertion.CredentialID), assertion.User.ID, assertion.User.Name) + fidoLog.DebugContext(ctx, "Authenticated", + "credential_id", base64.RawURLEncoding.EncodeToString(assertion.CredentialID), + "user_id", assertion.User.ID, + "user_name", assertion.User.Name, + ) // Use the first successful assertion. // In practice it is very unlikely we'd hit this twice. @@ -342,13 +352,16 @@ func devAssertion( return nil, trace.Wrap(libfido2.ErrUserPresenceRequired) } - if log.IsLevelEnabled(log.DebugLevel) { + if fidoLog.Enabled(context.Background(), slog.LevelDebug) { credPrefix := hex.EncodeToString(cred) const prefixLen = 10 if len(credPrefix) > prefixLen { credPrefix = credPrefix[:prefixLen] } - log.Debugf("FIDO2: Device %v: Using credential %v...", info.path, credPrefix) + fidoLog.DebugContext(context.Background(), "Using credential", + "device", info.path, + "credential", credPrefix, + ) } allowedCreds = [][]byte{cred} @@ -451,7 +464,7 @@ func fido2Register( if err != nil { return nil, trace.Wrap(err) } - log.Debugf("FIDO2: registration: resident key=%v", rrk) + fidoLog.DebugContext(ctx, "registration", "resident_key", rrk) // Can we create ES256 keys? // TODO(codingllama): Consider supporting other algorithms and respecting @@ -526,12 +539,13 @@ func fido2Register( case err != nil: // Swallow unexpected errors: a double registration is better than // aborting the ceremony. - log.Debugf( - "FIDO2: Device %v: excluded credential assertion failed, letting device through: err=%q", - info.path, err) + fidoLog.DebugContext(ctx, "excluded credential assertion failed, letting device through", + "device", info.path, + "error", err, + ) return nil default: - log.Debugf("FIDO2: Device %v: filtered due to presence of excluded credential", info.path) + fidoLog.DebugContext(ctx, "filtered due to presence of excluded credential", "device", info.path) return errHasExcludedCredential } } @@ -619,7 +633,7 @@ func makeAttStatement(attestation *libfido2.Attestation) (string, map[string]int case none: return format, nil, nil default: - log.Debugf(`FIDO2: Unsupported attestation format %q, using "none"`, format) + fidoLog.DebugContext(context.Background(), `Unsupported attestation format, using "none"`, "attestation_format", format) return none, nil, nil } @@ -686,11 +700,11 @@ func runOnFIDO2Devices( case <-devicesC: receiveCount++ case <-maxWait.C: - log.Debugf("FIDO2: Abandoning device goroutines after %s", fido2DeviceMaxWait) + fidoLog.DebugContext(ctx, "Abandoning device goroutines after exceeding wait time", "max_wait_time", fido2DeviceMaxWait) return } } - log.Debug("FIDO2: Device goroutines exited cleanly") + fidoLog.DebugContext(ctx, "Device goroutines exited cleanly") }() // First "interactive" response wins. @@ -701,7 +715,7 @@ func runOnFIDO2Devices( // Keep going on cancels or non-interactive errors. if errors.Is(err, libfido2.ErrKeepaliveCancel) || errors.Is(err, &nonInteractiveError{}) { - log.Debugf("FIDO2: Got cancel or non-interactive device error: %v", err) + fidoLog.DebugContext(ctx, "Got cancel or non-interactive device error", "error", err) continue } @@ -729,7 +743,10 @@ func startDevices( for i, dev := range fidoDevs { path := openDevs[i].path err := dev.Close() - log.Debugf("FIDO2: Close device %v, err=%v", path, err) + fidoLog.DebugContext(context.Background(), "Close device", + "device", path, + "error", err, + ) } } @@ -747,7 +764,10 @@ func startDevices( // This is largely safe to ignore, as opening is fairly consistent in // other situations and failures are likely from a non-chosen device in // multi-device scenarios. - log.Debugf("FIDO2: Device %v failed to open, skipping: %v", path, err) + fidoLog.DebugContext(context.Background(), "Device failed to open, skipping", + "device", path, + "error", err, + ) continue } @@ -828,7 +848,10 @@ func (l *openedDevices) cancelAll(except FIDODevice) { // Note that U2F devices fail Cancel with "invalid argument". err := d.dev.Cancel() - log.Debugf("FIDO2: Cancel device %v, err=%v", d.path, err) + fidoLog.DebugContext(context.Background(), "Cancel device", + "device", d.path, + "error", err, + ) } } @@ -841,10 +864,14 @@ func handleDevice( firstTouchAck func() error, pinPrompt runPrompt, ) error { + ctx := context.Background() // handleDevice owns the device, thus it has the privilege to shut it down. defer func() { err := dev.Close() - log.Debugf("FIDO2: Close device %v, err=%v", path, err) + fidoLog.DebugContext(ctx, "Close device", + "device", path, + "error", err, + ) }() if err := dev.SetTimeout(fido2DeviceTimeout); err != nil { @@ -862,16 +889,22 @@ func handleDevice( if err != nil { return trace.Wrap(&nonInteractiveError{err: err}) } - log.Debugf("FIDO2: Device %v: info %#v", path, info) + fidoLog.DebugContext(ctx, "Device", + "path", path, + "info", info, + ) } else { - log.Debugf("FIDO2: Device %v: not a FIDO2 device", path) + fidoLog.DebugContext(ctx, "not a FIDO2 device", "device", path) } di := makeDevInfo(path, info, isFIDO2) // Apply initial filters, waiting for confirmation if the filter fails before // relaying the error. if err := filter(dev, di); err != nil { - log.Debugf("FIDO2: Device %v filtered, err=%v", path, err) + fidoLog.DebugContext(ctx, "Device filtered", + "device", path, + "error", err, + ) // If the device is chosen then treat the error as interactive. if touched, _ := waitForTouch(dev); touched { @@ -885,7 +918,11 @@ func handleDevice( // Run the callback. cb := withPINHandler(withRetries(deviceCallback)) requiresPIN, err := cb(dev, di, "" /* pin */) - log.Debugf("FIDO2: Device %v: callback returned, requiresPIN=%v, err=%v", path, requiresPIN, err) + fidoLog.DebugContext(ctx, "callback returned", + "device", path, + "requires_pin", requiresPIN, + "error", err, + ) if err != nil { return trace.Wrap(err) } @@ -932,7 +969,11 @@ func devInfo(path string, dev FIDODevice) (*libfido2.DeviceInfo, error) { } lastErr = err - log.Debugf("FIDO2: Device %v: Info failed, retrying after %s: %v", path, fido2RetryInterval, err) + fidoLog.DebugContext(context.Background(), "Info failed, retrying", + "device", path, + "backoff_duration", fido2RetryInterval, + "error", err, + ) time.Sleep(fido2RetryInterval) } @@ -955,7 +996,7 @@ func withRetries(callback deviceCallbackFunc) deviceCallbackFunc { // ErrOperationDenied happens when fingerprint reading fails (UV=false). if errors.Is(err, libfido2.ErrOperationDenied) { fmt.Println("Gesture validation failed, make sure you use a registered fingerprint") - log.Debug("FIDO2: Retrying libfido2 error 'operation denied'") + fidoLog.DebugContext(context.Background(), "Retrying libfido2 error 'operation denied'") continue } @@ -975,7 +1016,7 @@ func withRetries(callback deviceCallbackFunc) deviceCallbackFunc { "Alternatively, you may unblock your device by using it in the Web UI." return trace.Wrap(err, msg) case 63: // FIDO_ERR_UV_INVALID, 0x3f - log.Debug("FIDO2: Retrying libfido2 error 63") + fidoLog.DebugContext(context.Background(), "Retrying libfido2 error 63") continue default: // Unexpected code. return err @@ -1041,7 +1082,7 @@ func waitForTouch(dev FIDODevice) (touched bool, err error) { touch, err := dev.TouchBegin() if err != nil { // Error logged here as it's mostly ignored by callers. - log.Debugf("FIDO2: Device touch begin error: %v", err) + fidoLog.DebugContext(context.Background(), "Device touch begin error", "error", err) return false, trace.Wrap(err) } defer touch.Stop() @@ -1051,7 +1092,7 @@ func waitForTouch(dev FIDODevice) (touched bool, err error) { touched, err := touch.Status(fido2TouchMaxWait) if err != nil { // Error logged here as it's mostly ignored by callers. - log.Debugf("FIDO2: Device touch status error: %v", err) + fidoLog.DebugContext(context.Background(), "Device touch status error", "error", err) return false, trace.Wrap(err) } if touched { diff --git a/lib/auth/webauthnwin/api.go b/lib/auth/webauthnwin/api.go index 4e8de09029911..5d3cdcefe22e5 100644 --- a/lib/auth/webauthnwin/api.go +++ b/lib/auth/webauthnwin/api.go @@ -27,13 +27,13 @@ import ( "context" "fmt" "io" + "log/slog" "os" "sync" "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/protocol/webauthncose" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" @@ -221,7 +221,7 @@ type CheckSupportResult struct { func IsAvailable() bool { supports := CheckSupport() if supports.HasCompileSupport && !supports.IsAvailable { - log.Warn("Webauthn is not supported on this version of Windows, supported from version 1903") + slog.WarnContext(context.Background(), "Webauthn is not supported on this version of Windows, supported from version 1903") } return supports.IsAvailable diff --git a/lib/auth/webauthnwin/webauthn_windows.go b/lib/auth/webauthnwin/webauthn_windows.go index 681120739aa92..0f07071ba498e 100644 --- a/lib/auth/webauthnwin/webauthn_windows.go +++ b/lib/auth/webauthnwin/webauthn_windows.go @@ -19,17 +19,19 @@ package webauthnwin import ( + "context" "encoding/base64" "errors" "fmt" + "log/slog" "syscall" "unsafe" "github.com/go-webauthn/webauthn/protocol" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "golang.org/x/sys/windows" + "github.com/gravitational/teleport" wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" ) @@ -52,27 +54,26 @@ func newNativeImpl() *nativeImpl { hasCompileSupport: true, } + logger := slog.With(teleport.ComponentKey, "WebAuthnWin") + ctx := context.Background() + // Explicitly loading the module avoids a panic when calling DLL functions if // the DLL is missing. // https://github.com/gravitational/teleport/issues/36851 if err := modWebAuthn.Load(); err != nil { - log. - WithError(err). - Debug("WebAuthnWin: failed to load WebAuthn.dll (it's likely missing)") + logger.DebugContext(ctx, "failed to load WebAuthn.dll (it's likely missing)", "error", err) return n } // Load WebAuthNGetApiVersionNumber explicitly too, it avoids a panic on some // Windows Server 2019 installs. if err := procWebAuthNGetApiVersionNumber.Find(); err != nil { - log. - WithError(err). - Debug("WebAuthnWin: failed to load WebAuthNGetApiVersionNumber") + logger.DebugContext(ctx, "failed to load WebAuthNGetApiVersionNumber", "error", err) return n } v, err := webAuthNGetApiVersionNumber() if err != nil { - log.WithError(err).Debug("WebAuthnWin: failed to check version") + logger.DebugContext(ctx, "failed to check version", "error", err) return n } n.webauthnAPIVersion = v @@ -86,7 +87,7 @@ func newNativeImpl() *nativeImpl { if err != nil { // This should not happen if dll exists, however we are fine with // to proceed without uvPlatform. - log.WithError(err).Debug("WebAuthnWin: failed to check isUVPlatformAuthenticatorAvailable") + logger.DebugContext(ctx, "failed to check isUVPlatformAuthenticatorAvailable", "error", err) } return n diff --git a/lib/client/alpn.go b/lib/client/alpn.go index db58eb374701f..9f88c69f1bdb1 100644 --- a/lib/client/alpn.go +++ b/lib/client/alpn.go @@ -129,7 +129,7 @@ func RunALPNAuthTunnel(ctx context.Context, cfg ALPNAuthTunnelConfig) error { go func() { defer cfg.Listener.Close() if err := lp.Start(ctx); err != nil { - log.WithError(err).Info("ALPN proxy stopped.") + log.InfoContext(ctx, "ALPN proxy stopped", "error", err) } }() diff --git a/lib/client/api.go b/lib/client/api.go index 6cc0caae15286..35b28544978b2 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -40,7 +40,6 @@ import ( "unicode/utf8" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/attribute" oteltrace "go.opentelemetry.io/otel/trace" "golang.org/x/crypto/ssh" @@ -130,9 +129,7 @@ const ( const remoteForwardUnsupportedMessage = "ssh: tcpip-forward request denied by peer" -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentClient, -}) +var log = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentClient) // ForwardedPort specifies local tunnel to remote // destination managed by the client, is equivalent @@ -659,7 +656,7 @@ func RetryWithRelogin(ctx context.Context, tc *TeleportClient, fn func() error, for _, o := range opts { o(opt) } - log.Debugf("Activating relogin on error=%q (type=%T)", fnErr, trace.Unwrap(fnErr)) + log.DebugContext(ctx, "Activating relogin on error", "error", fnErr, "error_type", logutils.TypeAttr(trace.Unwrap(fnErr))) if keys.IsPrivateKeyPolicyError(fnErr) { privateKeyPolicy, err := keys.ParsePrivateKeyPolicyError(fnErr) @@ -680,7 +677,7 @@ func RetryWithRelogin(ctx context.Context, tc *TeleportClient, fn func() error, key, err := tc.Login(ctx) if err != nil { if errors.Is(err, prompt.ErrNotTerminal) { - log.WithError(err).Debugf("Relogin is not available in this environment") + log.DebugContext(ctx, "Relogin is not available in this environment", "error", err) return trace.Wrap(fnErr) } if trace.IsTrustError(err) { @@ -705,7 +702,7 @@ func RetryWithRelogin(ctx context.Context, tc *TeleportClient, fn func() error, // Save profile to record proxy credentials if err := tc.SaveProfile(opt.makeCurrentProfile); err != nil { - log.Warningf("Failed to save profile: %v", err) + log.WarnContext(ctx, "Failed to save profile", "error", err) return trace.Wrap(err) } @@ -906,13 +903,16 @@ func (c *Config) LoadProfile(ps ProfileStore, proxyAddr string) error { c.DynamicForwardedPorts, err = ParseDynamicPortForwardSpec(profile.DynamicForwardedPorts) if err != nil { - log.Warnf("Unable to parse dynamic port forwarding in user profile: %v.", err) + log.WarnContext(context.Background(), "Unable to parse dynamic port forwarding in user profile", "error", err) } if required, ok := client.OverwriteALPNConnUpgradeRequirementByEnv(c.WebProxyAddr); ok { c.TLSRoutingConnUpgradeRequired = required } - log.Infof("ALPN connection upgrade required for %q: %v.", c.WebProxyAddr, c.TLSRoutingConnUpgradeRequired) + log.InfoContext(context.Background(), "ALPN connection upgrade required", + "web_proxy_addr", c.WebProxyAddr, + "upgrade_required", c.TLSRoutingConnUpgradeRequired, + ) return nil } @@ -1247,7 +1247,7 @@ func NewClient(c *Config) (tc *TeleportClient, err error) { if err != nil { return nil, trace.Wrap(err) } - log.Infof("No teleport login given. defaulting to %s", c.Username) + log.InfoContext(context.Background(), "No teleport login given, using default", "default_login", c.Username) } if c.WebProxyAddr == "" { return nil, trace.BadParameter("No proxy address specified, missed --proxy flag?") @@ -1257,7 +1257,7 @@ func NewClient(c *Config) (tc *TeleportClient, err error) { if err != nil { return nil, trace.Wrap(err) } - log.Infof("no host login given. defaulting to %s", c.HostLogin) + log.InfoContext(context.Background(), "no host login given, using default", "default_host_login", c.HostLogin) } c.Namespace = types.ProcessNamespace(c.Namespace) @@ -1426,7 +1426,10 @@ func (tc *TeleportClient) SignersForClusterWithReissue(ctx context.Context, clus signers, err = tc.localAgent.signersForCluster(clusterName) if err != nil { - log.WithError(err).Warnf("Failed to load/reissue certificates for cluster %q.", clusterName) + log.WarnContext(ctx, "Failed to load/reissue certificates for cluster", + "error", err, + "cluster", clusterName, + ) return nil, trace.Wrap(err) } return signers, nil @@ -1489,7 +1492,7 @@ type TargetNode struct { func (tc *TeleportClient) GetTargetNodes(ctx context.Context, clt client.ListUnifiedResourcesClient, options SSHOptions) ([]TargetNode, error) { ctx, span := tc.Tracer.Start( ctx, - "teleportClient/getTargetNodes", + "teleportClient/GetTargetNodes", oteltrace.WithSpanKind(oteltrace.SpanKindClient), ) defer span.End() @@ -1505,7 +1508,11 @@ func (tc *TeleportClient) GetTargetNodes(ctx context.Context, clt client.ListUni // Query for nodes if labels, fuzzy search, or predicate expressions were provided. if len(tc.Labels) > 0 || len(tc.SearchKeywords) > 0 || tc.PredicateExpression != "" { - log.Debugf("Attempting to resolve matching hosts from labels=%v|search=%v|predicate=%v", tc.Labels, tc.SearchKeywords, tc.PredicateExpression) + log.DebugContext(ctx, "Attempting to resolve matching hosts", + "labels", tc.Labels, + "search", tc.SearchKeywords, + "predicate", tc.PredicateExpression, + ) nodes, err := client.GetAllUnifiedResources(ctx, clt, &proto.ListUnifiedResourcesRequest{ Kinds: []string{types.KindNode}, SortBy: types.SortBy{Field: types.ResourceMetadataName}, @@ -1535,7 +1542,7 @@ func (tc *TeleportClient) GetTargetNodes(ctx context.Context, clt client.ListUni return retval, nil } - log.Debugf("Using provided host %s", tc.Host) + log.DebugContext(ctx, "Using provided host", "host", tc.Host) // detect the common error when users use host:port address format _, port, err := net.SplitHostPort(tc.Host) @@ -1553,6 +1560,120 @@ func (tc *TeleportClient) GetTargetNodes(ctx context.Context, clt client.ListUni }, nil } +// GetTargetNode returns a single host matching the target host provided by users. Host resolution +// honors an explicit host, i.e. tsh ssh user@hostname, label based hosts, i.e. tsh ssh user@foo=bar, +// as well as respecting any proxy templates that are specified. +func (tc *TeleportClient) GetTargetNode(ctx context.Context, clt authclient.ClientI, options *SSHOptions) (*TargetNode, error) { + ctx, span := tc.Tracer.Start( + ctx, + "teleportClient/GetTargetNode", + oteltrace.WithSpanKind(oteltrace.SpanKindClient), + ) + defer span.End() + + if options != nil && options.HostAddress != "" { + return &TargetNode{ + Hostname: options.HostAddress, + Addr: options.HostAddress, + }, nil + } + + if len(tc.Labels) == 0 && len(tc.SearchKeywords) == 0 && tc.PredicateExpression == "" { + log.DebugContext(ctx, "Using provided host", "host", tc.Host) + + // detect the common error when users use host:port address format + _, port, err := net.SplitHostPort(tc.Host) + // client has used host:port notation + if err == nil { + return nil, trace.BadParameter("please use ssh subcommand with '--port=%v' flag instead of semicolon", port) + } + + addr := net.JoinHostPort(tc.Host, strconv.Itoa(tc.HostPort)) + return &TargetNode{ + Hostname: tc.Host, + Addr: addr, + }, nil + } + + // Query for nodes if labels, fuzzy search, or predicate expressions were provided. + log.DebugContext(ctx, "Attempting to resolve matching host", + "labels", tc.Labels, + "search", tc.SearchKeywords, + "predicate", tc.PredicateExpression, + ) + resp, err := clt.ResolveSSHTarget(ctx, &proto.ResolveSSHTargetRequest{ + PredicateExpression: tc.PredicateExpression, + SearchKeywords: tc.SearchKeywords, + Labels: tc.Labels, + }) + switch { + //TODO(tross): DELETE IN v20.0.0 + case trace.IsNotImplemented(err): + resources, err := client.GetAllUnifiedResources(ctx, clt, &proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + SortBy: types.SortBy{Field: types.ResourceMetadataName}, + Labels: tc.Labels, + SearchKeywords: tc.SearchKeywords, + PredicateExpression: tc.PredicateExpression, + }) + if err != nil { + return nil, trace.Wrap(err) + } + + switch len(resources) { + case 0: + return nil, trace.NotFound("no matching SSH hosts found for search terms or query expression") + case 1: + node, ok := resources[0].ResourceWithLabels.(*types.ServerV2) + if !ok { + return nil, trace.BadParameter("expected node resource, got %T", resources[0].ResourceWithLabels) + } + return &TargetNode{ + Hostname: node.GetHostname(), + Addr: node.GetName() + ":0", + }, nil + default: + // If routing does not allow choosing the most recent host, then abort with + // an ambiguous host error. + cnc, err := clt.GetClusterNetworkingConfig(ctx) + if err != nil || cnc.GetRoutingStrategy() != types.RoutingStrategy_MOST_RECENT { + return nil, trace.BadParameter("found multiple matching SSH hosts %v", resources[:2]) + } + + // Get the most recent version of the resource. + enrichedResource := slices.MaxFunc(resources, func(a, b *types.EnrichedResource) int { + return a.Expiry().Compare(b.Expiry()) + }) + server, ok := enrichedResource.ResourceWithLabels.(types.Server) + if !ok { + return nil, trace.BadParameter("received unexpected resource type %T", resources[0].ResourceWithLabels) + } + + // Dialing is happening by UUID but a port is still required by + // the Proxy dial request. Zero is an indicator to the Proxy that + // it may chose the appropriate port based on the target server. + return &TargetNode{ + Hostname: server.GetHostname(), + Addr: server.GetName() + ":0", + }, nil + } + case err == nil: + if resp.GetServer() == nil { + return nil, trace.NotFound("no matching SSH hosts found") + } + + // Dialing is happening by UUID but a port is still required by + // the Proxy dial request. Zero is an indicator to the Proxy that + // it may chose the appropriate port based on the target server. + return &TargetNode{ + Hostname: resp.GetServer().GetHostname(), + Addr: resp.GetServer().GetName() + ":0", + }, nil + default: + return nil, trace.Wrap(err) + } +} + // ReissueUserCerts issues new user certs based on params and stores them in // the local key agent (usually on disk in ~/.tsh). func (tc *TeleportClient) ReissueUserCerts(ctx context.Context, cachePolicy CertCachePolicy, params ReissueParams) error { @@ -2065,7 +2186,7 @@ func (tc *TeleportClient) runShellOrCommandOnSingleNode(ctx context.Context, clt go func() { connClosed <- nodeClient.Client.Wait() }() - log.Debugf("Connected to node, no remote command execution was requested, blocking indefinitely.") + log.DebugContext(ctx, "Connected to node, no remote command execution was requested, blocking indefinitely") select { case <-ctx.Done(): // Only return an error if the context was canceled by something other than SIGINT. @@ -2149,11 +2270,11 @@ func (tc *TeleportClient) startPortForwarding(ctx context.Context, nodeClient *N // We log the error here instead of returning it to be consistent with // the other port forwarding methods, which don't stop the session // if forwarding fails. - message := fmt.Sprintf("Failed to bind on remote host to %v: %v.", addr, err) if strings.Contains(err.Error(), remoteForwardUnsupportedMessage) { - message = "Node does not support remote port forwarding (-R)." + log.ErrorContext(ctx, "Node does not support remote port forwarding (-R)") + } else { + log.ErrorContext(ctx, "Failed to bind on remote host", "addr", addr, "error", err) } - log.Error(message) } else { go nodeClient.remoteListenAndForward(ctx, socket, net.JoinHostPort(fp.DestHost, strconv.Itoa(fp.DestPort)), addr) } @@ -2434,19 +2555,11 @@ func (tc *TeleportClient) SFTP(ctx context.Context, source []string, destination defer clt.Close() // Respect any proxy templates and attempt host resolution. - resolvedNodes, err := tc.GetTargetNodes(ctx, clt.AuthClient, SSHOptions{}) + target, err := tc.GetTargetNode(ctx, clt.AuthClient, nil) if err != nil { return trace.Wrap(err) } - switch len(resolvedNodes) { - case 1: - case 0: - return trace.NotFound("no matching hosts found") - default: - return trace.BadParameter("multiple matching hosts found") - } - var cfg *sftp.Config switch { case isDownload: @@ -2469,7 +2582,7 @@ func (tc *TeleportClient) SFTP(ctx context.Context, source []string, destination } } - return trace.Wrap(tc.TransferFiles(ctx, clt, tc.HostLogin, resolvedNodes[0].Addr, cfg)) + return trace.Wrap(tc.TransferFiles(ctx, clt, tc.HostLogin, target.Addr, cfg)) } // TransferFiles copies files between the current machine and the @@ -2548,7 +2661,7 @@ func (tc *TeleportClient) ListNodesWithFilters(ctx context.Context) ([]types.Ser for _, r := range page { srv, ok := r.ResourceWithLabels.(types.Server) if !ok { - log.Warnf("expected types.Server but received unexpected type %T", r) + log.WarnContext(ctx, "expected types.Server but received unexpected type", "resource_type", logutils.TypeAttr(r)) continue } @@ -2944,7 +3057,7 @@ func (tc *TeleportClient) getProxySSHPrincipal() string { proxyPrincipal := tc.Config.HostLogin if len(tc.JumpHosts) > 0 && tc.JumpHosts[0].Username != "" { - log.Debugf("Setting proxy login to jump host's parameter user %q", tc.JumpHosts[0].Username) + log.DebugContext(context.Background(), "Setting proxy login to jump host's parameter user", "user", tc.JumpHosts[0].Username) proxyPrincipal = tc.JumpHosts[0].Username } return proxyPrincipal @@ -3076,7 +3189,7 @@ func (tc *TeleportClient) generateClientConfig(ctx context.Context) (*clientConf authMethods := append([]ssh.AuthMethod{}, tc.Config.AuthMethods...) clusterName := func() string { return tc.SiteName } if len(tc.JumpHosts) > 0 { - log.Debugf("Overriding SSH proxy to JumpHosts's address %q", tc.JumpHosts[0].Addr.String()) + log.DebugContext(ctx, "Overriding SSH proxy to JumpHosts's address", "addr", logutils.StringerAttr(&tc.JumpHosts[0].Addr)) proxyAddr = tc.JumpHosts[0].Addr.Addr if tc.localAgent != nil { @@ -3197,7 +3310,9 @@ func (g *proxyClusterGuesser) hostKeyCallback(hostname string, remote net.Addr, } if clusterName == "" { - log.Debugf("Target SSH server %q does not have a cluster name embedded in their certificate; will use all available client certificates to authenticate", hostname) + log.DebugContext(context.Background(), "Target SSH server does not have a cluster name embedded in their certificate; will use all available client certificates to authenticate", + "target_server", hostname, + ) } if g.nextHostKeyCallback != nil { @@ -3446,7 +3561,7 @@ func (tc *TeleportClient) AttemptDeviceLogin(ctx context.Context, keyRing *KeyRi } if !tc.dtAttemptLoginIgnorePing && pingResp.Auth.DeviceTrust.Disabled { - log.Debug("Device Trust: skipping device authentication, device trust disabled") + log.DebugContext(ctx, "Device Trust: skipping device authentication, device trust disabled") return nil } @@ -3461,20 +3576,20 @@ func (tc *TeleportClient) AttemptDeviceLogin(ctx context.Context, keyRing *KeyRi }) switch { case errors.Is(err, devicetrust.ErrDeviceKeyNotFound): - log.Debug("Device Trust: Skipping device authentication, device key not found") + log.DebugContext(ctx, "Device Trust: Skipping device authentication, device key not found") return nil // err swallowed on purpose case errors.Is(err, devicetrust.ErrPlatformNotSupported): - log.Debug("Device Trust: Skipping device authentication, platform not supported") + log.DebugContext(ctx, "Device Trust: Skipping device authentication, platform not supported") return nil // err swallowed on purpose case trace.IsNotImplemented(err): - log.Debug("Device Trust: Skipping device authentication, not supported by server") + log.DebugContext(ctx, "Device Trust: Skipping device authentication, not supported by server") return nil // err swallowed on purpose case err != nil: - log.WithError(err).Debug("Device Trust: device authentication failed") + log.DebugContext(ctx, "Device Trust: device authentication failed", "error", err) return nil // err swallowed on purpose } - log.Debug("Device Trust: acquired augmented user certificates") + log.DebugContext(ctx, "Device Trust: acquired augmented user certificates") cp := *keyRing cp.Cert = newCerts.SshAuthorizedKey cp.TLSCert = pem.EncodeToMemory(&pem.Block{ @@ -3534,7 +3649,7 @@ func (tc *TeleportClient) DeviceLogin(ctx context.Context, params *dtauthntypes. // Is auto-enroll enabled? pingResp, err := tc.Ping(ctx) if err != nil { - log.WithError(err).Debug("Device Trust: swallowing Ping error for previous Login error") + log.DebugContext(ctx, "Device Trust: swallowing Ping error for previous Login error", "error", err) return nil, trace.Wrap(loginErr) // err swallowed for loginErr } if !tc.dtAutoEnrollIgnorePing && !pingResp.Auth.DeviceTrust.AutoEnroll { @@ -3548,7 +3663,7 @@ func (tc *TeleportClient) DeviceLogin(ctx context.Context, params *dtauthntypes. // Auto-enroll and Login again. if _, err := autoEnroll(ctx, params.DevicesClient); err != nil { - log.WithError(err).Debug("Device Trust: device auto-enroll failed") + log.DebugContext(ctx, "Device Trust: device auto-enroll failed", "error", err) return nil, trace.Wrap(loginErr) // err swallowed for loginErr } newCerts, err = runCeremony(ctx, params) @@ -3588,7 +3703,7 @@ func (tc *TeleportClient) getSSHLoginFunc(pr *webclient.PingResponse) (SSHLoginF // registered, we can try to go with passwordless login even though // auth=local was selected. if tc.canDefaultToPasswordless(pr) { - log.Debug("Trying passwordless login because credentials were found") + log.DebugContext(context.Background(), "Trying passwordless login because credentials were found") return tc.pwdlessLogin, nil } @@ -3630,7 +3745,7 @@ func (tc *TeleportClient) getWebLoginFunc(pr *webclient.PingResponse) (WebLoginF // registered, we can try to go with passwordless login even though // auth=local was selected. if tc.canDefaultToPasswordless(pr) { - log.Debug("Trying passwordless login because credentials were found") + log.DebugContext(context.Background(), "Trying passwordless login because credentials were found") return tc.pwdlessLoginWeb, nil } @@ -3882,9 +3997,9 @@ func (tc *TeleportClient) GetNewLoginKeyRing(ctx context.Context) (keyRing *KeyR defer span.End() if tc.PrivateKeyPolicy.IsHardwareKeyPolicy() { - log.Debugf("Attempting to login with YubiKey private key.") + log.DebugContext(ctx, "Attempting to login with YubiKey private key") if tc.PIVSlot != "" { - log.Debugf("Using PIV slot %q specified by client or server settings.", tc.PIVSlot) + log.DebugContext(ctx, "Using PIV slot specified by client or server settings", "piv_slot", tc.PIVSlot) } priv, err := keys.GetYubiKeyPrivateKey(ctx, tc.PrivateKeyPolicy, tc.PIVSlot, tc.CustomHardwareKeyPrompt) if err != nil { @@ -3896,7 +4011,7 @@ func (tc *TeleportClient) GetNewLoginKeyRing(ctx context.Context) (keyRing *KeyR var sshKey, tlsKey crypto.Signer if tc.GenerateUnifiedKey { - log.Debugf("Attempting to login with a new software private key.") + log.DebugContext(ctx, "Attempting to login with a new software private key") // Using the UserTLS key algorithm for both keys because SSH generally // supports all TLS keys algorithms (RSA2048, ECDSAP256), but TLS does // not support Ed25519 which may be used for SSH. @@ -3906,7 +4021,7 @@ func (tc *TeleportClient) GetNewLoginKeyRing(ctx context.Context) (keyRing *KeyR } sshKey = tlsKey } else { - log.Debugf("Attempting to login with new software private keys.") + log.DebugContext(ctx, "Attempting to login with new software private keys") var err error sshKey, tlsKey, err = cryptosuites.GenerateUserSSHAndTLSKey(ctx, tc.GetCurrentSignatureAlgorithmSuite) if err != nil { @@ -4643,23 +4758,26 @@ func (tc *TeleportClient) EventsChannel() <-chan events.EventFields { // loopbackPool reads trusted CAs if it finds it in a predefined location // and will work only if target proxy address is loopback func loopbackPool(proxyAddr string) *x509.CertPool { + ctx := context.Background() + if !apiutils.IsLoopback(proxyAddr) { - log.Debugf("not using loopback pool for remote proxy addr: %v", proxyAddr) + log.DebugContext(ctx, "not using loopback pool for remote proxy addr", "proxy_addr", proxyAddr) return nil } - log.Debugf("attempting to use loopback pool for local proxy addr: %v", proxyAddr) + log.DebugContext(ctx, "attempting to use loopback pool for local proxy addr", "proxy_addr", proxyAddr) certPool, err := x509.SystemCertPool() if err != nil { - log.Debugf("could not open system cert pool, using empty cert pool instead: %v", err) + log.DebugContext(ctx, "could not open system cert pool, using empty cert pool instead", "error", err) certPool = x509.NewCertPool() } certPath := filepath.Join(defaults.DataDir, defaults.SelfSignedCertPath) - log.Debugf("reading self-signed certs from: %v", certPath) + logger := log.With("cert_path", certPath) + logger.DebugContext(ctx, "reading self-signed certs") pemByte, err := os.ReadFile(certPath) if err != nil { - log.Debugf("could not open any path in: %v", certPath) + logger.DebugContext(ctx, "could not open any path in") return nil } @@ -4671,25 +4789,31 @@ func loopbackPool(proxyAddr string) *x509.CertPool { } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { - log.Debugf("could not parse cert in: %v, err: %v", certPath, err) + logger.DebugContext(ctx, "could not parse cert", "error", err) return nil } certPool.AddCert(cert) } - log.Debugf("using local pool for loopback proxy: %v, err: %v", certPath, err) + logger.DebugContext(ctx, "using local pool for loopback proxy", "error", err) return certPool } // connectToSSHAgent connects to the system SSH agent and returns an agent.Agent. func connectToSSHAgent() agent.ExtendedAgent { + ctx := context.Background() + logger := log.With(teleport.ComponentKey, "KEYAGENT") + socketPath := os.Getenv(teleport.SSHAuthSock) conn, err := agentconn.Dial(socketPath) if err != nil { - log.Warnf("[KEY AGENT] Unable to connect to SSH agent on socket %q: %v", socketPath, err) + logger.WarnContext(ctx, "Unable to connect to SSH agent on socket", + "socket_path", socketPath, + "error", err, + ) return nil } - log.Infof("[KEY AGENT] Connected to the system agent: %q", socketPath) + logger.InfoContext(ctx, "Connected to the system agent", "socket_path", socketPath) return agent.NewClient(conn) } diff --git a/lib/client/api_login_test.go b/lib/client/api_login_test.go index cd39dd3acf0c1..e06e73c6ce648 100644 --- a/lib/client/api_login_test.go +++ b/lib/client/api_login_test.go @@ -36,7 +36,6 @@ import ( "github.com/google/uuid" "github.com/jonboulle/clockwork" "github.com/pquerna/otp/totp" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -64,8 +63,6 @@ import ( func TestTeleportClient_Login_local(t *testing.T) { t.Parallel() - silenceLogger(t) - type webauthnFunc func(ctx context.Context, origin string, assertion *wantypes.CredentialAssertion, prompt wancli.LoginPrompt) (*proto.MFAAuthenticateResponse, error) waitForCancelFn := func(ctx context.Context) (string, error) { @@ -324,8 +321,6 @@ func TestTeleportClient_Login_local(t *testing.T) { } func TestTeleportClient_DeviceLogin(t *testing.T) { - silenceLogger(t) - clock := clockwork.NewFakeClockAt(time.Now()) sa := newStandaloneTeleport(t, clock) username := sa.Username @@ -521,10 +516,6 @@ type standaloneBundle struct { func newStandaloneTeleport(t *testing.T, clock clockwork.Clock) *standaloneBundle { randomAddr := utils.NetAddr{AddrNetwork: "tcp", Addr: "127.0.0.1:0"} - // Silent logger and console. - logger := utils.NewLoggerForTests() - logger.SetLevel(log.PanicLevel) - logger.SetOutput(io.Discard) console := io.Discard staticToken := uuid.New().String() @@ -559,7 +550,7 @@ func newStandaloneTeleport(t *testing.T, clock clockwork.Clock) *standaloneBundl cfg.Hostname = "localhost" cfg.Clock = clock cfg.Console = console - cfg.Log = logger + cfg.Logger = utils.NewSlogLoggerForTests() cfg.SetAuthServerAddress(randomAddr) // must be present cfg.Auth.Preference, err = types.NewAuthPreferenceFromConfigFile(types.AuthPreferenceSpecV2{ Type: constants.Local, @@ -643,7 +634,7 @@ func newStandaloneTeleport(t *testing.T, clock clockwork.Clock) *standaloneBundl cfg.SetToken(staticToken) cfg.Clock = clock cfg.Console = console - cfg.Log = logger + cfg.Logger = utils.NewSlogLoggerForTests() cfg.SetAuthServerAddress(*authAddr) cfg.Auth.Enabled = false cfg.Proxy.Enabled = true @@ -683,17 +674,6 @@ func startAndWait(t *testing.T, cfg *servicecfg.Config, eventName string) *servi return instance } -// silenceLogger silences logger during testing. -func silenceLogger(t *testing.T) { - lvl := log.GetLevel() - t.Cleanup(func() { - log.SetOutput(os.Stderr) - log.SetLevel(lvl) - }) - log.SetOutput(io.Discard) - log.SetLevel(log.PanicLevel) -} - func TestRetryWithRelogin(t *testing.T) { clock := clockwork.NewFakeClockAt(time.Now()) sa := newStandaloneTeleport(t, clock) diff --git a/lib/client/api_test.go b/lib/client/api_test.go index 136d338b01e39..320922e551ef7 100644 --- a/lib/client/api_test.go +++ b/lib/client/api_test.go @@ -27,6 +27,7 @@ import ( "math" "os" "testing" + "time" "github.com/coreos/go-semver/semver" "github.com/google/go-cmp/cmp" @@ -42,6 +43,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/grpc/interceptors" "github.com/gravitational/teleport/api/utils/keys" + "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/cryptosuites" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/modules" @@ -1305,6 +1307,192 @@ func TestGetTargetNodes(t *testing.T) { } } +type fakeGetTargetNodeClient struct { + authclient.ClientI + + nodes []*types.ServerV2 + resolved *types.ServerV2 + resolveErr error + routeToMostRecent bool +} + +func (f fakeGetTargetNodeClient) ListUnifiedResources(ctx context.Context, req *proto.ListUnifiedResourcesRequest) (*proto.ListUnifiedResourcesResponse, error) { + out := make([]*proto.PaginatedResource, 0, len(f.nodes)) + for _, n := range f.nodes { + out = append(out, &proto.PaginatedResource{Resource: &proto.PaginatedResource_Node{Node: n}}) + } + + return &proto.ListUnifiedResourcesResponse{Resources: out}, nil +} + +func (f fakeGetTargetNodeClient) ResolveSSHTarget(ctx context.Context, req *proto.ResolveSSHTargetRequest) (*proto.ResolveSSHTargetResponse, error) { + if f.resolveErr != nil { + return nil, f.resolveErr + } + + return &proto.ResolveSSHTargetResponse{Server: f.resolved}, nil +} + +func (f fakeGetTargetNodeClient) GetClusterNetworkingConfig(ctx context.Context) (types.ClusterNetworkingConfig, error) { + cfg := types.DefaultClusterNetworkingConfig() + if f.routeToMostRecent { + cfg.SetRoutingStrategy(types.RoutingStrategy_MOST_RECENT) + } + + return cfg, nil +} + +func TestGetTargetNode(t *testing.T) { + now := time.Now() + then := now.Add(-5 * time.Hour) + + tests := []struct { + name string + options *SSHOptions + labels map[string]string + search []string + predicate string + host string + port int + clt fakeGetTargetNodeClient + errAssertion require.ErrorAssertionFunc + expected TargetNode + }{ + { + name: "options override", + options: &SSHOptions{ + HostAddress: "test:1234", + }, + host: "llama", + port: 56789, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "test:1234", Addr: "test:1234"}, + }, + { + name: "explicit target", + host: "test", + port: 1234, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "test", Addr: "test:1234"}, + }, + { + name: "resolved labels", + labels: map[string]string{"foo": "bar"}, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "resolved-labels", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "labels"}}}, + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-labels"}}, + }, + }, + { + name: "fallback labels", + labels: map[string]string{"foo": "bar"}, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "labels", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "labels"}}}, + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-labels"}}, + resolveErr: trace.NotImplemented(""), + }, + }, + { + name: "resolved search", + search: []string{"foo", "bar"}, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "resolved-search", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "search"}}}, + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-search"}}, + }, + }, + + { + name: "fallback search", + search: []string{"foo", "bar"}, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "search", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "search"}}}, + resolveErr: trace.NotImplemented(""), + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-search"}}, + }, + }, + { + name: "resolved predicate", + predicate: `resource.spec.hostname == "test"`, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "resolved-predicate", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "predicate"}}}, + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-predicate"}}, + }, + }, + { + name: "fallback predicate", + predicate: `resource.spec.hostname == "test"`, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "predicate", Addr: "abcd:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "predicate"}}}, + resolveErr: trace.NotImplemented(""), + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-predicate"}}, + }, + }, + { + name: "fallback ambiguous hosts", + predicate: `resource.spec.hostname == "test"`, + errAssertion: require.Error, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{ + {Metadata: types.Metadata{Name: "abcd-1"}, Spec: types.ServerSpecV2{Hostname: "predicate"}}, + {Metadata: types.Metadata{Name: "abcd-2"}, Spec: types.ServerSpecV2{Hostname: "predicate"}}, + }, + resolveErr: trace.NotImplemented(""), + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-predicate"}}, + }, + }, + { + name: "fallback and route to recent", + predicate: `resource.spec.hostname == "test"`, + errAssertion: require.NoError, + expected: TargetNode{Hostname: "predicate-now", Addr: "abcd-1:0"}, + clt: fakeGetTargetNodeClient{ + nodes: []*types.ServerV2{ + {Metadata: types.Metadata{Name: "abcd-0", Expires: &then}, Spec: types.ServerSpecV2{Hostname: "predicate-then"}}, + {Metadata: types.Metadata{Name: "abcd-1", Expires: &now}, Spec: types.ServerSpecV2{Hostname: "predicate-now"}}, + {Metadata: types.Metadata{Name: "abcd-2", Expires: &then}, Spec: types.ServerSpecV2{Hostname: "predicate-then-again"}}, + }, + resolveErr: trace.NotImplemented(""), + routeToMostRecent: true, + resolved: &types.ServerV2{Metadata: types.Metadata{Name: "abcd"}, Spec: types.ServerSpecV2{Hostname: "resolved-predicate"}}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + clt := TeleportClient{ + Config: Config{ + Tracer: tracing.NoopTracer(""), + Labels: test.labels, + SearchKeywords: test.search, + PredicateExpression: test.predicate, + Host: test.host, + HostPort: test.port, + }, + } + + match, err := clt.GetTargetNode(context.Background(), test.clt, test.options) + test.errAssertion(t, err) + if match == nil { + match = &TargetNode{} + } + require.EqualValues(t, test.expected, *match) + }) + } +} + func TestNonRetryableError(t *testing.T) { orgError := trace.AccessDenied("do not enter") err := &NonRetryableError{ diff --git a/lib/client/client.go b/lib/client/client.go index f14a5a2df476d..ffa41d5fcbc5f 100644 --- a/lib/client/client.go +++ b/lib/client/client.go @@ -54,6 +54,7 @@ import ( "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/sshutils/sftp" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/utils/socks" ) @@ -217,7 +218,7 @@ func makeDatabaseClientPEM(proto string, cert []byte, pk *keys.PrivateKey) ([]by } else if !trace.IsBadParameter(err) { return nil, trace.Wrap(err) } - log.WithError(err).Warn("MongoDB integration is not supported when logging in with a hardware private key.") + log.WarnContext(context.Background(), "MongoDB integration is not supported when logging in with a hardware private key", "error", err) } return cert, nil } @@ -333,7 +334,11 @@ func NewNodeClient(ctx context.Context, sshConfig *ssh.ClientConfig, conn net.Co // TODO(codingllama): Improve error message below for device trust. // An alternative we have here is querying the cluster to check if device // trust is required, a check similar to `IsMFARequired`. - log.Infof("Access denied to %v connecting to %v: %v", sshConfig.User, nodeName, err) + log.InfoContext(ctx, "Access denied connecting to host", + "login", sshConfig.User, + "target_host", nodeName, + "error", err, + ) return nil, trace.AccessDenied(`access denied to %v connecting to %v`, sshConfig.User, nodeName) } return nil, trace.Wrap(err) @@ -640,7 +645,7 @@ func (c *NodeClient) handleGlobalRequests(ctx context.Context, requestCh <-chan switch r.Type { case teleport.MFAPresenceRequest: if c.OnMFA == nil { - log.Warn("Received MFA presence request, but no callback was provided.") + log.WarnContext(ctx, "Received MFA presence request, but no callback was provided") continue } @@ -651,21 +656,21 @@ func (c *NodeClient) handleGlobalRequests(ctx context.Context, requestCh <-chan var e events.EventFields err := json.Unmarshal(r.Payload, &e) if err != nil { - log.Warnf("Unable to parse event: %v: %v.", string(r.Payload), err) + log.WarnContext(ctx, "Unable to parse event", "event", string(r.Payload), "error", err) continue } // Send event to event channel. err = c.TC.SendEvent(ctx, e) if err != nil { - log.Warnf("Unable to send event %v: %v.", string(r.Payload), err) + log.WarnContext(ctx, "Unable to send event", "event", string(r.Payload), "error", err) continue } default: // This handles keep-alive messages and matches the behavior of OpenSSH. err := r.Reply(false, nil) if err != nil { - log.Warnf("Unable to reply to %v request.", r.Type) + log.WarnContext(ctx, "Unable to reply to request", "request_type", r.Type, "error", err) continue } } @@ -707,7 +712,7 @@ func newClientConn( case <-ctx.Done(): errClose := conn.Close() if errClose != nil { - log.Error(errClose) + log.ErrorContext(ctx, "Failed closing connection", "error", errClose) } // drain the channel resp := <-respCh @@ -732,11 +737,16 @@ type netDialer interface { } func proxyConnection(ctx context.Context, conn net.Conn, remoteAddr string, dialer netDialer) error { + logger := log.With( + "source_addr", logutils.StringerAttr(conn.RemoteAddr()), + "target_addr", remoteAddr, + ) + defer conn.Close() - defer log.Debugf("Finished proxy from %v to %v.", conn.RemoteAddr(), remoteAddr) + defer logger.DebugContext(ctx, "Finished proxy connection") var remoteConn net.Conn - log.Debugf("Attempting to connect proxy from %v to %v.", conn.RemoteAddr(), remoteAddr) + logger.DebugContext(ctx, "Attempting to proxy connection") retry, err := retryutils.NewLinear(retryutils.LinearConfig{ First: 100 * time.Millisecond, @@ -756,7 +766,7 @@ func proxyConnection(ctx context.Context, conn net.Conn, remoteAddr string, dial break } - log.Debugf("Proxy connection attempt %v: %v.", attempt, err) + logger.DebugContext(ctx, "Proxy connection attempt", "attempt", attempt, "error", err) // Wait and attempt to connect again, if the context has closed, exit // right away. select { @@ -806,16 +816,19 @@ func acceptWithContext(ctx context.Context, l net.Listener) (net.Conn, error) { func (c *NodeClient) listenAndForward(ctx context.Context, ln net.Listener, localAddr string, remoteAddr string) { defer ln.Close() - log := log.WithField("localAddr", localAddr).WithField("remoteAddr", remoteAddr) + log := log.With( + "local_addr", localAddr, + "remote_addr", remoteAddr, + ) - log.Infof("Starting port forwarding") + log.InfoContext(ctx, "Starting port forwarding") for ctx.Err() == nil { // Accept connections from the client. conn, err := acceptWithContext(ctx, ln) if err != nil { if ctx.Err() == nil { - log.WithError(err).Errorf("Port forwarding failed.") + log.ErrorContext(ctx, "Port forwarding failed", "error", err) } continue } @@ -824,12 +837,12 @@ func (c *NodeClient) listenAndForward(ctx context.Context, ln net.Listener, loca go func() { // `err` must be a fresh variable, hence `:=` instead of `=`. if err := proxyConnection(ctx, conn, remoteAddr, c.Client); err != nil { - log.WithError(err).Warnf("Failed to proxy connection.") + log.WarnContext(ctx, "Failed to proxy connection", "error", err) } }() } - log.WithError(ctx.Err()).Infof("Shutting down port forwarding.") + log.InfoContext(ctx, "Shutting down port forwarding", "error", ctx.Err()) } // dynamicListenAndForward listens for connections, performs a SOCKS5 @@ -837,9 +850,11 @@ func (c *NodeClient) listenAndForward(ctx context.Context, ln net.Listener, loca func (c *NodeClient) dynamicListenAndForward(ctx context.Context, ln net.Listener, localAddr string) { defer ln.Close() - log := log.WithField("localAddr", localAddr) + log := log.With( + "local_addr", localAddr, + ) - log.Infof("Starting dynamic port forwarding.") + log.InfoContext(ctx, "Starting dynamic port forwarding") for ctx.Err() == nil { // Accept connection from the client. Here the client is typically @@ -847,7 +862,7 @@ func (c *NodeClient) dynamicListenAndForward(ctx context.Context, ln net.Listene conn, err := acceptWithContext(ctx, ln) if err != nil { if ctx.Err() == nil { - log.WithError(err).Errorf("Dynamic port forwarding (SOCKS5) failed.") + log.ErrorContext(ctx, "Dynamic port forwarding (SOCKS5) failed", "error", err) } continue } @@ -856,52 +871,55 @@ func (c *NodeClient) dynamicListenAndForward(ctx context.Context, ln net.Listene // address to proxy. remoteAddr, err := socks.Handshake(conn) if err != nil { - log.WithError(err).Errorf("SOCKS5 handshake failed.") + log.ErrorContext(ctx, "SOCKS5 handshake failed", "error", err) if err = conn.Close(); err != nil { - log.WithError(err).Errorf("Error closing failed proxy connection.") + log.ErrorContext(ctx, "Error closing failed proxy connection", "error", err) } continue } - log.Debugf("SOCKS5 proxy forwarding requests to %v.", remoteAddr) + log.DebugContext(ctx, "SOCKS5 proxy forwarding requests", "remote_addr", remoteAddr) // Proxy the connection to the remote address. go func() { // `err` must be a fresh variable, hence `:=` instead of `=`. if err := proxyConnection(ctx, conn, remoteAddr, c.Client); err != nil { - log.WithError(err).Warnf("Failed to proxy connection.") + log.WarnContext(ctx, "Failed to proxy connection", "error", err) if err = conn.Close(); err != nil { - log.WithError(err).Errorf("Error closing failed proxy connection.") + log.ErrorContext(ctx, "Error closing failed proxy connection", "error", err) } } }() } - log.WithError(ctx.Err()).Infof("Shutting down dynamic port forwarding.") + log.InfoContext(ctx, "Shutting down dynamic port forwarding", "error", ctx.Err()) } // remoteListenAndForward requests a listening socket and forwards all incoming // commands to the local address through the SSH tunnel. func (c *NodeClient) remoteListenAndForward(ctx context.Context, ln net.Listener, localAddr, remoteAddr string) { defer ln.Close() - log := log.WithField("localAddr", localAddr).WithField("remoteAddr", remoteAddr) - log.Infof("Starting remote port forwarding") + log := log.With( + "local_addr", localAddr, + "remote_addr", remoteAddr, + ) + log.InfoContext(ctx, "Starting remote port forwarding") for ctx.Err() == nil { conn, err := acceptWithContext(ctx, ln) if err != nil { if ctx.Err() == nil { - log.WithError(err).Errorf("Remote port forwarding failed.") + log.ErrorContext(ctx, "Remote port forwarding failed", "error", err) } continue } go func() { if err := proxyConnection(ctx, conn, localAddr, &net.Dialer{}); err != nil { - log.WithError(err).Warnf("Failed to proxy connection") + log.WarnContext(ctx, "Failed to proxy connection", "error", err) } }() } - log.WithError(ctx.Err()).Infof("Shutting down remote port forwarding.") + log.InfoContext(ctx, "Shutting down remote port forwarding", "error", ctx.Err()) } // GetRemoteTerminalSize fetches the terminal size of a given SSH session. diff --git a/lib/client/client_store.go b/lib/client/client_store.go index d10b1b47a7b4b..5762f9d7ec8ee 100644 --- a/lib/client/client_store.go +++ b/lib/client/client_store.go @@ -19,13 +19,14 @@ package client import ( + "context" "errors" "fmt" + "log/slog" "net/url" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -42,7 +43,7 @@ import ( // when using `tsh --add-keys-to-agent=only`, Store will be made up of an in-memory // key store and an FS (~/.tsh) profile and trusted certs store. type Store struct { - log *logrus.Entry + log *slog.Logger KeyStore TrustedCertsStore @@ -53,7 +54,7 @@ type Store struct { func NewFSClientStore(dirPath string) *Store { dirPath = profile.FullProfilePath(dirPath) return &Store{ - log: logrus.WithField(teleport.ComponentKey, teleport.ComponentKeyStore), + log: slog.With(teleport.ComponentKey, teleport.ComponentKeyStore), KeyStore: NewFSKeyStore(dirPath), TrustedCertsStore: NewFSTrustedCertsStore(dirPath), ProfileStore: NewFSProfileStore(dirPath), @@ -63,7 +64,7 @@ func NewFSClientStore(dirPath string) *Store { // NewMemClientStore initializes a new in-memory client store. func NewMemClientStore() *Store { return &Store{ - log: logrus.WithField(teleport.ComponentKey, teleport.ComponentKeyStore), + log: slog.With(teleport.ComponentKey, teleport.ComponentKeyStore), KeyStore: NewMemKeyStore(), TrustedCertsStore: NewMemTrustedCertsStore(), ProfileStore: NewMemProfileStore(), @@ -261,7 +262,10 @@ func (s *Store) FullProfileStatus() (*ProfileStatus, []*ProfileStatus, error) { } status, err := s.ReadProfileStatus(profileName) if err != nil { - s.log.WithError(err).Warnf("skipping profile %q due to error", profileName) + s.log.WarnContext(context.Background(), "skipping profile due to error", + "profile_name", profileName, + "error", err, + ) continue } profiles = append(profiles, status) diff --git a/lib/client/cluster_client.go b/lib/client/cluster_client.go index ce0a7d6485a6e..729f8f602863d 100644 --- a/lib/client/cluster_client.go +++ b/lib/client/cluster_client.go @@ -311,7 +311,7 @@ func (c *ClusterClient) SessionSSHConfig(ctx context.Context, user string, targe defer authClient.Close() } - log.Debug("Attempting to issue a single-use user certificate with an MFA check.") + log.DebugContext(ctx, "Attempting to issue a single-use user certificate with an MFA check") keyRing, err = c.performSessionMFACeremony(ctx, mfaClt, ReissueParams{ @@ -325,7 +325,7 @@ func (c *ClusterClient) SessionSSHConfig(ctx context.Context, user string, targe return nil, trace.Wrap(err) } - log.Debug("Issued single-use user certificate after an MFA check.") + log.DebugContext(ctx, "Issued single-use user certificate after an MFA check") am, err := keyRing.AsAuthMethod() if err != nil { return nil, trace.Wrap(ceremonyFailedErr{err}) @@ -561,7 +561,7 @@ func (c *ClusterClient) IssueUserCertsWithMFA(ctx context.Context, params Reissu // MFA is not required, but the user requires a new certificate with the // target included in it for routing. if !mfaRequired { - log.Debug("MFA not required for access.") + log.DebugContext(ctx, "MFA not required for access") keyRing, err := certClient.generateUserCerts(ctx, CertCacheKeep, params) return keyRing, proto.MFARequired_MFA_REQUIRED_NO, trace.Wrap(err) } @@ -572,7 +572,7 @@ func (c *ClusterClient) IssueUserCertsWithMFA(ctx context.Context, params Reissu return nil, proto.MFARequired_MFA_REQUIRED_YES, trace.Wrap(err) } - log.Debug("Issued single-use user certificate after an MFA check.") + log.DebugContext(ctx, "Issued single-use user certificate after an MFA check") return keyRing, proto.MFARequired_MFA_REQUIRED_YES, nil } @@ -648,7 +648,7 @@ func PerformSessionMFACeremony(ctx context.Context, params PerformSessionMFACere // that MFA was not required instead of the error received from the root cluster. if mfaRequiredReq != nil && !params.MFAAgainstRoot { mfaRequiredResp, err := currentClient.IsMFARequired(ctx, mfaRequiredReq) - log.Debugf("MFA requirement acquired from leaf, MFARequired=%s", mfaRequiredResp.GetMFARequired()) + log.DebugContext(ctx, "MFA requirement acquired from leaf", "mfa_required", mfaRequiredResp.GetMFARequired()) switch { case err != nil: return nil, nil, trace.Wrap(MFARequiredUnknown(err)) @@ -686,7 +686,7 @@ func PerformSessionMFACeremony(ctx context.Context, params PerformSessionMFACere certsReq := params.CertsReq certsReq.MFAResponse = mfaResp certsReq.Purpose = proto.UserCertsRequest_CERT_PURPOSE_SINGLE_USE_CERTS - log.Debug("Issuing single-use certificate from unary GenerateUserCerts") + log.DebugContext(ctx, "Issuing single-use certificate from unary GenerateUserCerts") newCerts, err := rootClient.GenerateUserCerts(ctx, *certsReq) if err != nil { return nil, nil, trace.Wrap(err) diff --git a/lib/client/conntest/database/mysql.go b/lib/client/conntest/database/mysql.go index 1c2a7ca2e561b..39d07a811fa17 100644 --- a/lib/client/conntest/database/mysql.go +++ b/lib/client/conntest/database/mysql.go @@ -22,13 +22,13 @@ import ( "context" "errors" "fmt" + "log/slog" "net" "strings" "github.com/go-mysql-org/go-mysql/client" "github.com/go-mysql-org/go-mysql/mysql" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/lib/defaults" ) @@ -73,7 +73,7 @@ func (p *MySQLPinger) Ping(ctx context.Context, params PingParams) error { defer func() { if err := conn.Quit(); err != nil { - logrus.WithError(err).Info("Failed to close connection in MySQLPinger.Ping") + slog.InfoContext(context.Background(), "Failed to close connection in MySQLPinger.Ping", "error", err) } }() diff --git a/lib/client/conntest/database/postgres.go b/lib/client/conntest/database/postgres.go index 6a574c56ce156..a048376aadc8a 100644 --- a/lib/client/conntest/database/postgres.go +++ b/lib/client/conntest/database/postgres.go @@ -22,12 +22,12 @@ import ( "context" "errors" "fmt" + "log/slog" "strings" "github.com/gravitational/trace" "github.com/jackc/pgconn" "github.com/jackc/pgerrcode" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/lib/defaults" ) @@ -65,7 +65,7 @@ func (p *PostgresPinger) Ping(ctx context.Context, params PingParams) error { defer func() { if err := conn.Close(ctx); err != nil { - logrus.WithError(err).Info("failed to close connection in PostgresPinger.Ping") + slog.InfoContext(context.Background(), "failed to close connection in PostgresPinger.Ping", "error", err) } }() diff --git a/lib/client/https_client.go b/lib/client/https_client.go index db980450238b0..66293120843b2 100644 --- a/lib/client/https_client.go +++ b/lib/client/https_client.go @@ -84,7 +84,7 @@ type WebClient struct { // and a the HTTPS failure will be considered final. func (w *WebClient) PostJSONWithFallback(ctx context.Context, endpoint string, val interface{}, allowHTTPFallback bool) (*roundtrip.Response, error) { // First try HTTPS and see how that goes - log.Debugf("Attempting %s", endpoint) + log.DebugContext(ctx, "Attempting request", "endpoint", endpoint) resp, httpsErr := w.Client.PostJSON(ctx, endpoint, val) if httpsErr == nil { // If all went well, then we don't need to do anything else - just return @@ -116,7 +116,7 @@ func (w *WebClient) PostJSONWithFallback(ctx context.Context, endpoint string, v // re-write the endpoint to try HTTP u.Scheme = "http" endpoint = u.String() - log.Warnf("Request for %s/%s falling back to PLAIN HTTP", u.Host, u.Path) + log.WarnContext(ctx, "Request for falling back to PLAIN HTTP", "endpoint", endpoint) return httplib.ConvertResponse(w.Client.PostJSON(ctx, endpoint, val)) } diff --git a/lib/client/interfaces.go b/lib/client/interfaces.go index 23502cb4f561c..b755a98de5970 100644 --- a/lib/client/interfaces.go +++ b/lib/client/interfaces.go @@ -28,6 +28,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "log/slog" "strings" "time" @@ -81,6 +82,14 @@ func (idx KeyRingIndex) Match(matchKeyRing KeyRingIndex) bool { (matchKeyRing.Username == "" || matchKeyRing.Username == idx.Username) } +func (idx KeyRingIndex) LogValue() slog.Value { + return slog.GroupValue( + slog.String("proxy", idx.ProxyHost), + slog.String("cluster", idx.ClusterName), + slog.String("username", idx.Username), + ) +} + // TLSCredential holds a signed TLS certificate and matching private key. type TLSCredential struct { // PrivateKey is the private key of the credential. diff --git a/lib/client/keyagent.go b/lib/client/keyagent.go index 741c1f5b989ec..85e095f14a3c1 100644 --- a/lib/client/keyagent.go +++ b/lib/client/keyagent.go @@ -23,6 +23,7 @@ import ( "crypto/x509" "fmt" "io" + "log/slog" "net" "os" "runtime" @@ -30,7 +31,6 @@ import ( "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" @@ -40,12 +40,13 @@ import ( "github.com/gravitational/teleport/api/utils/sshutils" "github.com/gravitational/teleport/lib/auth/authclient" "github.com/gravitational/teleport/lib/tlsca" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // LocalKeyAgent holds Teleport certificates for a user connected to a cluster. type LocalKeyAgent struct { // log holds the structured logger. - log *logrus.Entry + log *slog.Logger // ExtendedAgent is the teleport agent agent.ExtendedAgent @@ -120,9 +121,7 @@ func NewLocalAgent(conf LocalAgentConfig) (a *LocalKeyAgent, err error) { conf.Agent = keyring } a = &LocalKeyAgent{ - log: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentKeyAgent, - }), + log: slog.With(teleport.ComponentKey, teleport.ComponentKeyAgent), ExtendedAgent: conf.Agent, clientStore: conf.ClientStore, noHosts: make(map[string]bool), @@ -136,10 +135,10 @@ func NewLocalAgent(conf LocalAgentConfig) (a *LocalKeyAgent, err error) { if shouldAddKeysToAgent(conf.KeysOption) { a.systemAgent = connectToSSHAgent() } else { - log.Debug("Skipping connection to the local ssh-agent.") + log.DebugContext(context.Background(), "Skipping connection to the local ssh-agent.") if !agentSupportsSSHCertificates() && agentIsPresent() { - log.Warn(`Certificate was not loaded into agent because the agent at SSH_AUTH_SOCK does not appear + log.WarnContext(context.Background(), `Certificate was not loaded into agent because the agent at SSH_AUTH_SOCK does not appear to support SSH certificates. To force load the certificate into the running agent, use the --add-keys-to-agent=yes flag.`) } @@ -195,13 +194,15 @@ func (a *LocalKeyAgent) LoadKeyRing(keyRing KeyRing) error { return trace.Wrap(err) } - a.log.Infof("Loading SSH key for user %q and cluster %q.", a.username, keyRing.ClusterName) + a.log.InfoContext(context.Background(), "Loading SSH key", "user", a.username, "cluster", keyRing.ClusterName) agents := []agent.ExtendedAgent{a.ExtendedAgent} if a.systemAgent != nil { if canAddToSystemAgent(agentKey) { agents = append(agents, a.systemAgent) } else { - a.log.Infof("Skipping adding key to SSH system agent for non-standard key type %T", agentKey.PrivateKey) + a.log.InfoContext(context.Background(), "Skipping adding key to SSH system agent for non-standard key type", + "key_type", logutils.TypeAttr(agentKey.PrivateKey), + ) } } @@ -249,14 +250,14 @@ func (a *LocalKeyAgent) UnloadKeyRing(keyRing KeyRingIndex) error { // get a list of all keys in the agent keyList, err := agent.List() if err != nil { - a.log.Warnf("Unable to communicate with agent and list keys: %v", err) + a.log.WarnContext(context.Background(), "Unable to communicate with agent and list keys", "error", err) } // remove any teleport keys we currently have loaded in the agent for this user and proxy for _, agentKey := range keyList { if agentKeyIdx, ok := parseTeleportAgentKeyComment(agentKey.Comment); ok && agentKeyIdx.Match(keyRing) { if err = agent.Remove(agentKey); err != nil { - a.log.Warnf("Unable to communicate with agent and remove key: %v", err) + a.log.WarnContext(context.Background(), "Unable to communicate with agent and remove key", "error", err) } } } @@ -278,14 +279,14 @@ func (a *LocalKeyAgent) UnloadKeys() error { // get a list of all keys in the agent keyList, err := agent.List() if err != nil { - a.log.Warnf("Unable to communicate with agent and list keys: %v", err) + a.log.WarnContext(context.Background(), "Unable to communicate with agent and list keys", "error", err) } // remove any teleport keys we currently have loaded in the agent for _, key := range keyList { if isTeleportAgentKey(key) { if err = agent.Remove(key); err != nil { - a.log.Warnf("Unable to communicate with agent and remove key: %v", err) + a.log.WarnContext(context.Background(), "Unable to communicate with agent and remove key", "error", err) } } } @@ -362,13 +363,15 @@ func (a *LocalKeyAgent) HostKeyCallback(addr string, remote net.Addr, hostKey ss }, FIPS: isFIPS(), } - a.log.Debugf("Checking key: %s.", ssh.MarshalAuthorizedKey(hostKey)) + + ctx := context.Background() + a.log.DebugContext(ctx, "Checking key", "host_key", string(ssh.MarshalAuthorizedKey(hostKey))) err = certChecker.CheckHostKey(addr, remote, hostKey) if err != nil { - a.log.Debugf("Host validation failed: %v.", err) + a.log.DebugContext(ctx, "Host validation failed", "error", err) return trace.Wrap(err) } - a.log.Debugf("Validated host %v.", addr) + a.log.DebugContext(ctx, "Validated host", "host_addr", addr) return nil } @@ -377,12 +380,14 @@ func (a *LocalKeyAgent) HostKeyCallback(addr string, remote net.Addr, hostKey ss // reject the server key. func (a *LocalKeyAgent) checkHostCertificateForClusters(clusters ...string) func(key ssh.PublicKey, addr string) bool { return func(key ssh.PublicKey, addr string) bool { + ctx := context.Background() + // Check the local cache (where all Teleport CAs are placed upon login) to // see if any of them match. var keys []ssh.PublicKey trustedCerts, err := a.clientStore.GetTrustedCerts(a.proxyHost) if err != nil { - a.log.Errorf("Failed to get trusted certs: %v.", err) + a.log.ErrorContext(ctx, "Failed to get trusted certs", "error", err) return false } @@ -395,7 +400,7 @@ func (a *LocalKeyAgent) checkHostCertificateForClusters(clusters ...string) func } key, err := sshutils.ParseAuthorizedKeys(cert.AuthorizedKeys) if err != nil { - a.log.Errorf("Failed to parse authorized keys: %v.", err) + a.log.ErrorContext(ctx, "Failed to parse authorized keys", "error", err) return false } keys = append(keys, key...) @@ -418,25 +423,26 @@ func (a *LocalKeyAgent) checkHostCertificateForClusters(clusters ...string) func // ~/.tsh/known_hosts cache and if not found, prompts the user to accept // or reject. func (a *LocalKeyAgent) checkHostKey(addr string, remote net.Addr, key ssh.PublicKey) error { - var err error + ctx := context.Background() + logger := a.log.With("host_addr", addr) // Unless --insecure flag was given, prohibit public keys or host certs // not signed by Teleport. if !a.insecure { - a.log.Debugf("Host %s presented a public key not signed by Teleport. Rejecting due to insecure mode being OFF.", addr) + logger.DebugContext(ctx, "Host presented a public key not signed by Teleport - Rejecting due to insecure mode being OFF") return trace.BadParameter("host %s presented a public key not signed by Teleport", addr) } - a.log.Warnf("Host %s presented a public key not signed by Teleport. Proceeding due to insecure mode being ON.", addr) + logger.WarnContext(ctx, "Host presented a public key not signed by Teleport - Proceeding due to insecure mode being ON") // Check if this exact host is in the local cache. keys, err := a.clientStore.GetTrustedHostKeys(addr) if err != nil { - a.log.WithError(err).Debugf("Failed to retrieve client's trusted host keys.") + logger.DebugContext(ctx, "Failed to retrieve client's trusted host keys", "error", err) } else { for _, trustedHostKey := range keys { if sshutils.KeysEqual(key, trustedHostKey) { - a.log.Debugf("Verified host %s.", addr) + logger.DebugContext(ctx, "Verified host") return nil } } @@ -456,7 +462,7 @@ func (a *LocalKeyAgent) checkHostKey(addr string, remote net.Addr, key ssh.Publi // If the user trusts the key, store the key in the client trusted certs store. err = a.clientStore.AddTrustedHostKeys(a.proxyHost, addr, key) if err != nil { - a.log.Warnf("Failed to save the host key: %v.", err) + logger.WarnContext(ctx, "Failed to save the host key", "error", err) return trace.Wrap(err) } return nil @@ -547,7 +553,7 @@ func (a *LocalKeyAgent) addKeyRing(keyRing *KeyRing) error { } } else { if !keyRing.EqualPrivateKey(storedKeyRing) { - a.log.Debugf("Deleting obsolete stored keyring with index %+v.", storedKeyRing.KeyRingIndex) + a.log.DebugContext(context.Background(), "Deleting obsolete stored keyring", "keyring_index", storedKeyRing.KeyRingIndex) if err := a.clientStore.DeleteKeyRing(storedKeyRing.KeyRingIndex); err != nil { return trace.Wrap(err) } diff --git a/lib/client/keyagent_test.go b/lib/client/keyagent_test.go index bbd2ae2677dc7..4c0c078e82293 100644 --- a/lib/client/keyagent_test.go +++ b/lib/client/keyagent_test.go @@ -812,7 +812,7 @@ func startDebugAgent(t *testing.T) error { conn, err := listener.Accept() if err != nil { if !utils.IsUseOfClosedNetworkError(err) { - log.Warnf("Unexpected response from listener.Accept: %v", err) + log.WarnContext(context.Background(), "Unexpected response from listener.Accept", "error", err) } return } diff --git a/lib/client/keystore.go b/lib/client/keystore.go index 2cba0d5810825..9215922f5c33b 100644 --- a/lib/client/keystore.go +++ b/lib/client/keystore.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" iofs "io/fs" + "log/slog" "os" "path/filepath" "runtime" @@ -31,7 +32,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -95,7 +95,7 @@ type KeyStore interface { // The FS store uses the file layout outlined in `api/utils/keypaths.go`. type FSKeyStore struct { // log holds the structured logger. - log logrus.FieldLogger + log *slog.Logger // KeyDir is the directory where all keys are stored. KeyDir string @@ -111,7 +111,7 @@ type FSKeyStore struct { func NewFSKeyStore(dirPath string) *FSKeyStore { dirPath = profile.FullProfilePath(dirPath) return &FSKeyStore{ - log: logrus.WithField(teleport.ComponentKey, teleport.ComponentKeyStore), + log: slog.With(teleport.ComponentKey, teleport.ComponentKeyStore), KeyDir: dirPath, } } @@ -225,7 +225,7 @@ func (fs *FSKeyStore) AddKeyRing(keyRing *KeyRing) error { if runtime.GOOS == constants.WindowsOS { ppkFile, err := keyRing.SSHPrivateKey.PPKFile() if err != nil { - fs.log.Debugf("Cannot convert private key to PPK-formatted keypair: %v", err) + fs.log.DebugContext(context.Background(), "Cannot convert private key to PPK-formatted keypair", "error", err) } else { if err := fs.writeBytes(ppkFile, fs.ppkFilePath(keyRing.KeyRingIndex)); err != nil { return trace.Wrap(err) @@ -353,7 +353,10 @@ func tryLockFile(ctx context.Context, path string, lockFn func(string) (func() e case err == nil: return func() { if err := unlock(); err != nil { - log.Errorf("failed to unlock TLS credential at %s: %s", path, err) + log.ErrorContext(ctx, "failed to unlock TLS credential", + "credential_path", path, + "error", err, + ) } }, nil case errors.Is(err, utils.ErrUnsuccessfulLockTry): @@ -447,7 +450,7 @@ func (fs *FSKeyStore) DeleteKeyRing(idx KeyRingIndex) error { // And try to delete kube credentials lockfile in case it exists err := utils.RemoveSecure(fs.kubeCredLockfilePath(idx)) if err != nil && !errors.Is(err, iofs.ErrNotExist) { - log.Debugf("Could not remove kube credentials file: %v", err) + log.DebugContext(context.Background(), "Could not remove kube credentials file", "error", err) } // Clear ClusterName to delete the user certs stored for all clusters. diff --git a/lib/client/known_hosts_migrate.go b/lib/client/known_hosts_migrate.go index bd331dd3c8fb4..26fd22a667d2b 100644 --- a/lib/client/known_hosts_migrate.go +++ b/lib/client/known_hosts_migrate.go @@ -20,9 +20,10 @@ package client import ( "bytes" + "context" + "log/slog" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -117,7 +118,7 @@ func canPruneOldHostsEntry(oldEntry *knownHostEntry, newEntries []*knownHostEntr // duplicate entry exists. This may modify order of host keys, but will not // change their content. func pruneOldHostKeys(output []string) []string { - log := logrus.WithField(teleport.ComponentKey, teleport.ComponentMigrate) + log := slog.With(teleport.ComponentKey, teleport.ComponentMigrate) var ( oldEntries = make([]*knownHostEntry, 0) @@ -130,7 +131,10 @@ func pruneOldHostKeys(output []string) []string { parsed, err := parseKnownHost(line) if err != nil { // If the line isn't parseable, pass it through. - log.WithError(err).Debugf("Unable to parse known host on line %d, skipping", i+1) + log.DebugContext(context.Background(), "Unable to parse known host, skipping", + "invalid_line_number", i+1, + "error", err, + ) prunedOutput = append(prunedOutput, line) continue } @@ -153,7 +157,7 @@ func pruneOldHostKeys(output []string) []string { // exists. If not, pass it through. for _, entry := range oldEntries { if canPruneOldHostsEntry(entry, newEntries) { - log.Debugf("Pruning old known_hosts entry for %s.", entry.hosts[0]) + log.DebugContext(context.Background(), "Pruning old known_hosts entry for host", "host", entry.hosts[0]) } else { prunedOutput = append(prunedOutput, entry.raw) } diff --git a/lib/client/kube/kube.go b/lib/client/kube/kube.go index dd26866d0938a..85980291f5d25 100644 --- a/lib/client/kube/kube.go +++ b/lib/client/kube/kube.go @@ -17,17 +17,17 @@ package kube import ( + "context" + "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/tlsca" + logutils "github.com/gravitational/teleport/lib/utils/log" ) -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentKubeClient, -}) +var log = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentKubeClient) // CheckIfCertsAreAllowedToAccessCluster evaluates if the new cert created by the user // to access kubeCluster has at least one kubernetes_user or kubernetes_group @@ -43,7 +43,7 @@ func CheckIfCertsAreAllowedToAccessCluster(k *client.KeyRing, rootCluster, telep return nil } if cred, ok := k.KubeTLSCredentials[kubeCluster]; ok { - log.Debugf("Got TLS cert for Kubernetes cluster %q", kubeCluster) + log.DebugContext(context.Background(), "Got TLS cert for Kubernetes cluster", "kubernetes_cluster", kubeCluster) exist, err := checkIfCertHasKubeGroupsAndUsers(cred.Cert) if err != nil { return trace.Wrap(err) diff --git a/lib/client/kubesession.go b/lib/client/kubesession.go index 5390555369c19..39681989a1abd 100644 --- a/lib/client/kubesession.go +++ b/lib/client/kubesession.go @@ -227,7 +227,7 @@ func (s *KubeSession) pipeInOut(stdout io.Writer, enableEscapeSequences bool, mo handleNonPeerControls(mode, s.term, func() { err := s.stream.ForceTerminate() if err != nil { - log.Debugf("Error sending force termination request: %v", err) + log.DebugContext(context.Background(), "Error sending force termination request", "error", err) fmt.Print("\n\rError while sending force termination request\n\r") } }) diff --git a/lib/client/local_proxy_middleware.go b/lib/client/local_proxy_middleware.go index 781e1ce4fa95b..20b8b9f3e7822 100644 --- a/lib/client/local_proxy_middleware.go +++ b/lib/client/local_proxy_middleware.go @@ -161,7 +161,10 @@ func (c *CertChecker) GetOrIssueCert(ctx context.Context) (tls.Certificate, erro } certTTL := cert.Leaf.NotAfter.Sub(c.clock.Now()).Round(time.Minute) - log.Debugf("Certificate renewed: valid until %s [valid for %v]", cert.Leaf.NotAfter.Format(time.RFC3339), certTTL) + log.DebugContext(ctx, "Certificate renewed", + "valud_until", cert.Leaf.NotAfter.Format(time.RFC3339), + "cert_ttl", certTTL, + ) c.cert = cert return c.cert, nil @@ -209,7 +212,7 @@ func (c *DBCertIssuer) CheckCert(cert *x509.Certificate) error { func (c *DBCertIssuer) IssueCert(ctx context.Context) (tls.Certificate, error) { var accessRequests []string if profile, err := c.Client.ProfileStatus(); err != nil { - log.WithError(err).Warn("unable to load profile, requesting database certs without access requests") + log.WarnContext(ctx, "unable to load profile, requesting database certs without access requests", "error", err) } else { accessRequests = profile.ActiveRequests.AccessRequests } @@ -281,7 +284,7 @@ func (c *AppCertIssuer) CheckCert(cert *x509.Certificate) error { func (c *AppCertIssuer) IssueCert(ctx context.Context) (tls.Certificate, error) { var accessRequests []string if profile, err := c.Client.ProfileStatus(); err != nil { - log.WithError(err).Warn("unable to load profile, requesting app certs without access requests") + log.WarnContext(ctx, "unable to load profile, requesting app certs without access requests", "error", err) } else { accessRequests = profile.ActiveRequests.AccessRequests } @@ -446,7 +449,10 @@ func (r *LocalCertGenerator) ensureValidCA(ctx context.Context) error { } certTTL := time.Until(caTLSCert.Leaf.NotAfter).Round(time.Minute) - log.Debugf("Local CA renewed: valid until %s [valid for %v]", caTLSCert.Leaf.NotAfter.Format(time.RFC3339), certTTL) + log.DebugContext(ctx, "Local CA renewed", + "valid_until", caTLSCert.Leaf.NotAfter.Format(time.RFC3339), + "cert_ttl", certTTL, + ) // Clear cert cache and use CA for hostnames in the CA. r.certsByHost = make(map[string]*tls.Certificate) diff --git a/lib/client/mfa/prompt.go b/lib/client/mfa/prompt.go index c96935c897f18..8adb56a3b262d 100644 --- a/lib/client/mfa/prompt.go +++ b/lib/client/mfa/prompt.go @@ -21,11 +21,11 @@ package mfa import ( "context" "errors" + "log/slog" "strings" "sync" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/mfa" @@ -115,9 +115,7 @@ func HandleMFAPromptGoroutines(ctx context.Context, startGoroutines func(context // Surface error immediately. return nil, trace.Wrap(resp.Err) case err != nil: - log. - WithError(err). - Debug("MFA goroutine failed, continuing so other goroutines have a chance to succeed") + slog.DebugContext(ctx, "MFA goroutine failed, continuing so other goroutines have a chance to succeed", "error", err) errs = append(errs, err) // Continue to give the other authn goroutine a chance to succeed. // If both have failed, this will exit the loop. diff --git a/lib/client/profile.go b/lib/client/profile.go index 985266ee3bc75..10e2754c82354 100644 --- a/lib/client/profile.go +++ b/lib/client/profile.go @@ -19,6 +19,7 @@ package client import ( + "context" "net/url" "os" "path/filepath" @@ -27,7 +28,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/profile" @@ -109,9 +109,6 @@ func (ms *MemProfileStore) SaveProfile(profile *profile.Profile, makecurrent boo // // The FS store uses the file layout outlined in `api/utils/keypaths.go`. type FSProfileStore struct { - // log holds the structured logger. - log logrus.FieldLogger - // Dir is the directory where all keys are stored. Dir string } @@ -120,7 +117,6 @@ type FSProfileStore struct { func NewFSProfileStore(dirPath string) *FSProfileStore { dirPath = profile.FullProfilePath(dirPath) return &FSProfileStore{ - log: logrus.WithField(teleport.ComponentKey, teleport.ComponentKeyStore), Dir: dirPath, } } @@ -434,14 +430,17 @@ func (p *ProfileStatus) virtualPathFromEnv(kind VirtualPathKind, params VirtualP // If we can't resolve any env vars, this will return garbage which we // should at least warn about. As ugly as this is, arguably making every // profile path lookup fallible is even uglier. - log.Debugf("Could not resolve path to virtual profile entry of type %s "+ - "with parameters %+v.", kind, params) + log.DebugContext(context.Background(), "Could not resolve path to virtual profile entry", + "entry_type", kind, + "parameters", params, + ) virtualPathWarnOnce.Do(func() { - log.Errorf("A virtual profile is in use due to an identity file " + + const msg = "A virtual profile is in use due to an identity file " + "(`-i ...`) but this functionality requires additional files on " + "disk and may fail. Consider using a compatible wrapper " + - "application (e.g. Machine ID) for this command.") + "application (e.g. Machine ID) for this command." + log.ErrorContext(context.Background(), msg) }) return "", false diff --git a/lib/client/session.go b/lib/client/session.go index 1c6cc9bea41e3..8d40ee5ba5675 100644 --- a/lib/client/session.go +++ b/lib/client/session.go @@ -151,7 +151,7 @@ func newSession(ctx context.Context, if ns.terminal.IsAttached() { err = ns.terminal.Resize(int16(terminalSize.Width), int16(terminalSize.Height)) if err != nil { - log.Error(err) + log.ErrorContext(ctx, "Failed to resize terminal", "error", err) } } @@ -179,7 +179,7 @@ func newSession(ctx context.Context, if ns.shouldClearOnExit { if err := ns.terminal.Clear(); err != nil { - log.Warnf("Failed to clear screen: %v.", err) + log.WarnContext(ctx, "Failed to clear screen", "error", err) } } ns.terminal.Close() @@ -247,7 +247,7 @@ func (ns *NodeSession) createServerSession(ctx context.Context, chanReqCallback } if err := sess.SetEnvs(ctx, envs); err != nil { - log.Warn(err) + log.WarnContext(ctx, "Failed to set environment variabls", "error", err) } // if agent forwarding was requested (and we have a agent to forward), @@ -256,7 +256,7 @@ func (ns *NodeSession) createServerSession(ctx context.Context, chanReqCallback targetAgent := selectKeyAgent(tc) if targetAgent != nil { - log.Debugf("Forwarding Selected Key Agent") + log.DebugContext(ctx, "Forwarding Selected Key Agent") err = agent.ForwardToAgent(ns.nodeClient.Client.Client, targetAgent) if err != nil { return nil, trace.Wrap(err) @@ -275,13 +275,13 @@ func (ns *NodeSession) createServerSession(ctx context.Context, chanReqCallback func selectKeyAgent(tc *TeleportClient) agent.ExtendedAgent { switch tc.ForwardAgent { case ForwardAgentYes: - log.Debugf("Selecting system key agent.") + log.DebugContext(context.Background(), "Selecting system key agent") return connectToSSHAgent() case ForwardAgentLocal: - log.Debugf("Selecting local Teleport key agent.") + log.DebugContext(context.Background(), "Selecting local Teleport key agent") return tc.localAgent.ExtendedAgent default: - log.Debugf("No Key Agent selected.") + log.DebugContext(context.Background(), "No Key Agent selected") return nil } } @@ -355,7 +355,7 @@ func (ns *NodeSession) allocateTerminal(ctx context.Context, termType string, s if ns.terminal.IsAttached() { realWidth, realHeight, err := ns.terminal.Size() if err != nil { - log.Error(err) + log.ErrorContext(ctx, "Unable to determine terminal size", "error", err) } else { width = int(realWidth) height = int(realHeight) @@ -390,7 +390,7 @@ func (ns *NodeSession) allocateTerminal(ctx context.Context, termType string, s } go func() { if _, err := io.Copy(ns.nodeClient.TC.Stderr, stderr); err != nil { - log.Debugf("Error reading remote STDERR: %v", err) + log.DebugContext(ctx, "Error reading remote STDERR", "error", err) } }() return utils.NewPipeNetConn( @@ -407,7 +407,7 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi lastWidth, lastHeight, err := ns.terminal.Size() if err != nil { - log.Errorf("Unable to get window size: %v", err) + log.ErrorContext(ctx, "Unable to get window size", "error", err) return } @@ -432,7 +432,7 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi currWidth, currHeight, err := ns.terminal.Size() if err != nil { - log.Warnf("Unable to get window size: %v.", err) + log.WarnContext(ctx, "Unable to get window size", "error", err) continue } @@ -443,11 +443,16 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi // Send the "window-change" request over the channel. if err = s.WindowChange(ctx, int(currHeight), int(currWidth)); err != nil { - log.Warnf("Unable to send %v request: %v.", sshutils.WindowChangeRequest, err) + log.WarnContext(ctx, "Unable to send window change request", "error", err) continue } - log.Debugf("Updated window size from (%d, %d) to (%d, %d) due to SIGWINCH.", lastWidth, lastHeight, currWidth, currHeight) + log.DebugContext(ctx, "Updated window size from due to SIGWINCH.", + "original_width", lastWidth, + "original_height", lastHeight, + "current_width", currWidth, + "current_height", currHeight, + ) lastWidth, lastHeight = currWidth, currHeight @@ -460,14 +465,18 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi terminalParams, err := session.UnmarshalTerminalParams(event.GetString(events.TerminalSize)) if err != nil { - log.Warnf("Unable to unmarshal terminal parameters: %v.", err) + log.WarnContext(ctx, "Unable to unmarshal terminal parameters", "error", err) continue } lastSize := terminalParams.Winsize() lastWidth = int16(lastSize.Width) lastHeight = int16(lastSize.Height) - log.Debugf("Received window size %v from node in session %v.", lastSize, event.GetString(events.SessionEventID)) + log.DebugContext(ctx, "Received window size from node in session", + "width", lastSize.Width, + "height", lastSize.Height, + "session_id", event.GetString(events.SessionEventID), + ) // Update size of local terminal with the last size received from remote server. case <-tickerCh.C: @@ -475,7 +484,7 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi // received. currWidth, currHeight, err := ns.terminal.Size() if err != nil { - log.Warnf("Unable to get current terminal size: %v.", err) + log.WarnContext(ctx, "Unable to get current terminal size", "error", err) continue } @@ -488,11 +497,16 @@ func (ns *NodeSession) updateTerminalSize(ctx context.Context, s *tracessh.Sessi // the window. err = ns.terminal.Resize(lastWidth, lastHeight) if err != nil { - log.Warnf("Unable to update terminal size: %v.", err) + log.WarnContext(ctx, "Unable to update terminal size", "error", err) continue } - log.Debugf("Updated window size from (%d, %d) to (%d, %d) due to remote window change.", currWidth, currHeight, lastWidth, lastHeight) + log.DebugContext(ctx, "Updated window size due to remote window change", + "original_width", lastWidth, + "original_height", lastHeight, + "current_width", currWidth, + "current_height", currHeight, + ) case <-ns.closer.C: return } @@ -602,10 +616,10 @@ func (ns *NodeSession) runCommand(ctx context.Context, mode types.SessionPartici // Ctrl-C. case <-ctx.Done(): if err := s.Close(); err != nil { - log.Debugf("Unable to close SSH channel: %v", err) + log.DebugContext(ctx, "Unable to close SSH channel", "error", err) } if err := ns.NodeClient().Client.Close(); err != nil { - log.Debugf("Unable to close SSH client: %v", err) + log.DebugContext(ctx, "Unable to close SSH client", "error", err) } return trace.ConnectionProblem(ctx.Err(), "connection canceled") } @@ -640,7 +654,7 @@ func (ns *NodeSession) watchSignals(shell io.Writer) { case <-ctrlCSignal: _, err := shell.Write([]byte{ctrlCharC}) if err != nil { - log.Error(err.Error()) + log.ErrorContext(context.Background(), "Failed to forward ctrl+c", "error", err) } case <-ns.closer.C: return @@ -656,7 +670,7 @@ func (ns *NodeSession) watchSignals(shell io.Writer) { if _, ok := event.(terminal.StopEvent); ok { _, err := shell.Write([]byte{ctrlCharZ}) if err != nil { - log.Error(err.Error()) + log.ErrorContext(context.Background(), "Failed to forward ctrl+z", "error", err) } } } @@ -698,7 +712,7 @@ func handlePeerControls(term *terminal.Terminal, enableEscapeSequences bool, rem // by tsh. These can be used to force a client disconnect since CTRL-C is merely passed // to the other end and not interpreted as an exit request locally stdin = escape.NewReader(stdin, term.Stderr(), func(err error) { - log.Debugf("escape.NewReader error: %v", err) + log.DebugContext(context.Background(), "escape.NewReader error", "error", err) switch { case errors.Is(err, escape.ErrDisconnect): @@ -713,7 +727,7 @@ func handlePeerControls(term *terminal.Terminal, enableEscapeSequences bool, rem _, err := io.Copy(remoteStdin, stdin) if err != nil { - log.Debugf("Error copying data to remote peer: %v", err) + log.DebugContext(context.Background(), "Error copying data to remote peer", "error", err) fmt.Fprint(term.Stderr(), "\r\nError copying data to remote peer\r\n") forceDisconnect = true } @@ -728,8 +742,8 @@ func (ns *NodeSession) pipeInOut(ctx context.Context, shell io.ReadWriteCloser, go func() { defer ns.closer.Close() _, err := io.Copy(ns.terminal.Stdout(), shell) - if err != nil { - log.Error(err.Error()) + if err != nil && !utils.IsOKNetworkError(err) { + log.ErrorContext(ctx, "Failed copying data to session", "error", err) } }() diff --git a/lib/client/terminal/terminal_common.go b/lib/client/terminal/terminal_common.go index fe51fdc7f6f2b..11e9f00e66b20 100644 --- a/lib/client/terminal/terminal_common.go +++ b/lib/client/terminal/terminal_common.go @@ -23,14 +23,12 @@ import ( "sync" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" + logutils "github.com/gravitational/teleport/lib/utils/log" ) -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentClient, -}) +var log = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentClient) // ResizeEvent is emitted when a terminal window is resized. type ResizeEvent struct{} diff --git a/lib/client/terminal/terminal_unix.go b/lib/client/terminal/terminal_unix.go index 479ddfcfc492d..98da0332a4205 100644 --- a/lib/client/terminal/terminal_unix.go +++ b/lib/client/terminal/terminal_unix.go @@ -22,9 +22,10 @@ package terminal import ( - "bytes" + "context" "fmt" "io" + "log/slog" "os" "os/signal" "sync" @@ -32,9 +33,9 @@ import ( "github.com/gravitational/trace" "github.com/moby/term" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // Terminal is used to configure raw input and output modes for an attached @@ -80,26 +81,6 @@ func New(stdin io.Reader, stdout, stderr io.Writer) (*Terminal, error) { return &term, nil } -// addCRFormatter is a formatter which adds carriage return (CR) to the output of a base formatter. -// This is needed in case the logger output is fed into terminal in raw mode. -type addCRFormatter struct { - BaseFmt logrus.Formatter -} - -func (r addCRFormatter) Format(entry *logrus.Entry) ([]byte, error) { - out, err := r.BaseFmt.Format(entry) - if err != nil { - return nil, err - } - - replaced := bytes.ReplaceAll(out, []byte("\n"), []byte("\r\n")) - return replaced, nil -} - -func newCRFormatter(baseFmt logrus.Formatter) *addCRFormatter { - return &addCRFormatter{BaseFmt: baseFmt} -} - // InitRaw puts the terminal into raw mode. On Unix, no special input handling // is required beyond simply reading from stdin, so `input` has no effect. // Note that some implementations may replace one or more streams (particularly @@ -107,17 +88,18 @@ func newCRFormatter(baseFmt logrus.Formatter) *addCRFormatter { func (t *Terminal) InitRaw(input bool) error { // Put the terminal into raw mode. ts, err := term.SetRawTerminal(0) - fmtNew := newCRFormatter(logrus.StandardLogger().Formatter) - logrus.StandardLogger().Formatter = fmtNew + + originalHandler := slog.Default().Handler() + slog.SetDefault(slog.New(logutils.DiscardHandler{})) if err != nil { - log.Warnf("Could not put terminal into raw mode: %v", err) + log.WarnContext(context.Background(), "Could not put terminal into raw mode", "error", err) } else { // Ensure the terminal is reset on exit. t.closeWait.Add(1) go func() { <-t.closer.C term.RestoreTerminal(0, ts) - logrus.StandardLogger().Formatter = fmtNew.BaseFmt + slog.SetDefault(slog.New(originalHandler)) t.closeWait.Done() }() } diff --git a/lib/client/terminal/terminal_unix_test.go b/lib/client/terminal/terminal_unix_test.go deleted file mode 100644 index fe0fc2d586b3e..0000000000000 --- a/lib/client/terminal/terminal_unix_test.go +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 . - */ - -package terminal - -import ( - "fmt" - "testing" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" -) - -// fixedDummyFmt is dummy formatter which ignores entry argument in Format() call and returns the same value, always. -type fixedDummyFmt struct { - bytes []byte - err error -} - -func (r fixedDummyFmt) Format(entry *logrus.Entry) ([]byte, error) { - return r.bytes, r.err -} - -func Test_addCRFormatter(t *testing.T) { - tests := []struct { - name string - input string - output string - wantErr bool - }{ - { - name: "no newlines", - input: "foo bar baz", - output: "foo bar baz", - }, - { - name: "single newline", - input: "foo bar baz\n", - output: "foo bar baz\r\n", - }, - { - name: "multiple newlines", - input: "foo\nbar\nbaz\n", - output: "foo\r\nbar\r\nbaz\r\n", - }, - { - name: "propagate error", - wantErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - baseFmt := fixedDummyFmt{bytes: []byte(tt.input)} - if tt.wantErr { - baseFmt.err = fmt.Errorf("dummy") - } - - r := newCRFormatter(baseFmt) - actual, err := r.Format(nil) - - if tt.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.output, string(actual)) - } - - }) - } -} diff --git a/lib/client/terminal/terminal_windows.go b/lib/client/terminal/terminal_windows.go index 9a9f71051310a..3c9e51ab9e229 100644 --- a/lib/client/terminal/terminal_windows.go +++ b/lib/client/terminal/terminal_windows.go @@ -19,6 +19,7 @@ package terminal import ( + "context" "fmt" "io" "os" @@ -76,7 +77,10 @@ func initTerminal(input bool) (func(), error) { // Attempt to reset the stdout mode before returning. err = winterm.SetConsoleMode(uintptr(stdoutFd), oldOutMode) if err != nil { - log.Errorf("Failed to reset terminal output mode to %d: %v\n", oldOutMode, err) + log.ErrorContext(context.Background(), "Failed to reset terminal output mode", + "original_output_mode", oldOutMode, + "error", err, + ) } return func() {}, fmt.Errorf("failed to set stdin mode: %w", err) @@ -86,13 +90,19 @@ func initTerminal(input bool) (func(), error) { return func() { err := winterm.SetConsoleMode(uintptr(stdoutFd), oldOutMode) if err != nil { - log.Errorf("Failed to reset terminal output mode to %d: %v\n", oldOutMode, err) + log.ErrorContext(context.Background(), "Failed to reset terminal output mode", + "original_output_mode", oldOutMode, + "error", err, + ) } if input { err = winterm.SetConsoleMode(uintptr(stdinFd), oldInMode) if err != nil { - log.Errorf("Failed to reset terminal input mode to %d: %v\n", oldInMode, err) + log.ErrorContext(context.Background(), "Failed to reset terminal input mode", + "original_input_mode", oldInMode, + "error", err, + ) } } }, nil diff --git a/lib/client/trusted_certs_store.go b/lib/client/trusted_certs_store.go index bb270e5ea1aa3..24dede0c3a9c3 100644 --- a/lib/client/trusted_certs_store.go +++ b/lib/client/trusted_certs_store.go @@ -25,13 +25,13 @@ import ( "encoding/pem" "fmt" iofs "io/fs" + "log/slog" "os" "path/filepath" "strings" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" @@ -161,7 +161,7 @@ func (ms *MemTrustedCertsStore) GetTrustedHostKeys(hostnames ...string) ([]ssh.P // The FS store uses the file layout outlined in `api/utils/keypaths.go`. type FSTrustedCertsStore struct { // log holds the structured logger. - log logrus.FieldLogger + log *slog.Logger // Dir is the directory where all keys are stored. Dir string @@ -171,7 +171,7 @@ type FSTrustedCertsStore struct { func NewFSTrustedCertsStore(dirPath string) *FSTrustedCertsStore { dirPath = profile.FullProfilePath(dirPath) return &FSTrustedCertsStore{ - log: logrus.WithField(teleport.ComponentKey, teleport.ComponentKeyStore), + log: slog.With(teleport.ComponentKey, teleport.ComponentKeyStore), Dir: dirPath, } } @@ -296,7 +296,7 @@ func (fs *FSTrustedCertsStore) saveTrustedCertsInCASDir(proxyHost string, cas [] } // check if cluster name is safe and doesn't contain miscellaneous characters. if strings.Contains(ca.ClusterName, "..") { - fs.log.Warnf("Skipped unsafe cluster name: %q", ca.ClusterName) + fs.log.WarnContext(context.Background(), "Skipped unsafe cluster name", "cluster_name", ca.ClusterName) continue } // Create CA files in cas dir for each cluster. @@ -392,7 +392,10 @@ func (fs *FSTrustedCertsStore) addKnownHosts(proxyHost string, cas []authclient. // add every host key to the list of entries for _, ca := range cas { for _, hostKey := range ca.AuthorizedKeys { - fs.log.Debugf("Adding known host %s with proxy %s", ca.ClusterName, proxyHost) + fs.log.DebugContext(context.Background(), "Adding known host entry", + "cluster_name", ca.ClusterName, + "proxy", proxyHost, + ) // Write keys in an OpenSSH-compatible format. A previous format was not // quite OpenSSH-compatible, so we may write a duplicate entry here. Any @@ -467,7 +470,10 @@ func (fs *FSTrustedCertsStore) GetTrustedCertsPEM(proxyHost string) ([][]byte, e break } if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { - fs.log.Debugf("Skipping PEM block type=%v headers=%v.", block.Type, block.Headers) + fs.log.DebugContext(context.Background(), "Skipping PEM block", + "type", block.Type, + "headers", block.Headers, + ) data = rest continue } diff --git a/lib/client/weblogin.go b/lib/client/weblogin.go index c3415e340417d..668f22b45a903 100644 --- a/lib/client/weblogin.go +++ b/lib/client/weblogin.go @@ -27,6 +27,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net" "net/http" "net/http/cookiejar" @@ -37,7 +38,6 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/gravitational/roundtrip" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -547,16 +547,18 @@ type TOTPRegisterChallenge struct { // initClient creates a new client to the HTTPS web proxy. func initClient(proxyAddr string, insecure bool, pool *x509.CertPool, extraHeaders map[string]string, opts ...roundtrip.ClientParam) (*WebClient, *url.URL, error) { - log := logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentClient, - }) - log.Debugf("HTTPS client init(proxyAddr=%v, insecure=%v, extraHeaders=%v)", proxyAddr, insecure, extraHeaders) + log := slog.With(teleport.ComponentKey, teleport.ComponentClient) + log.DebugContext(context.Background(), "Initializing proxy HTTPS client", + "proxy_addr", proxyAddr, + "insecure", insecure, + "extra_headers", extraHeaders, + ) // validate proxy address host, port, err := net.SplitHostPort(proxyAddr) if err != nil || host == "" || port == "" { if err != nil { - log.Error(err) + log.ErrorContext(context.Background(), "invalid proxy address", "error", err) } return nil, nil, trace.BadParameter("'%v' is not a valid proxy address", proxyAddr) } diff --git a/lib/client/weblogin_test.go b/lib/client/weblogin_test.go index 39722c78c2efe..cca05b892fe2b 100644 --- a/lib/client/weblogin_test.go +++ b/lib/client/weblogin_test.go @@ -121,7 +121,6 @@ func newServer(handler http.HandlerFunc, loopback bool) (*httptest.Server, error func TestSSHAgentPasswordlessLogin(t *testing.T) { t.Parallel() - silenceLogger(t) clock := clockwork.NewFakeClockAt(time.Now()) sa := newStandaloneTeleport(t, clock) diff --git a/lib/events/auditlog.go b/lib/events/auditlog.go index 3570171f40996..274c3c65c56a6 100644 --- a/lib/events/auditlog.go +++ b/lib/events/auditlog.go @@ -509,9 +509,23 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID e := make(chan error, 1) c := make(chan apievents.AuditEvent) + sessionStartCh := make(chan apievents.AuditEvent, 1) + if startCb, err := sessionStartCallbackFromContext(ctx); err == nil { + go func() { + evt, ok := <-sessionStartCh + if !ok { + startCb(nil, trace.NotFound("session start event not found")) + return + } + + startCb(evt, nil) + }() + } + rawSession, err := os.CreateTemp(l.playbackDir, string(sessionID)+".stream.tar.*") if err != nil { e <- trace.Wrap(trace.ConvertSystemError(err), "creating temporary stream file") + close(sessionStartCh) return c, e } // The file is still perfectly usable after unlinking it, and the space it's @@ -528,6 +542,7 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID if err := os.Remove(rawSession.Name()); err != nil { _ = rawSession.Close() e <- trace.Wrap(trace.ConvertSystemError(err), "removing temporary stream file") + close(sessionStartCh) return c, e } @@ -538,6 +553,7 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID err = trace.NotFound("a recording for session %v was not found", sessionID) } e <- trace.Wrap(err) + close(sessionStartCh) return c, e } l.log.DebugContext(ctx, "Downloaded session to a temporary file for streaming.", @@ -547,6 +563,8 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID go func() { defer rawSession.Close() + defer close(sessionStartCh) + // this shouldn't be necessary as the position should be already 0 (Download // takes an io.WriterAt), but it's better to be safe than sorry if _, err := rawSession.Seek(0, io.SeekStart); err != nil { @@ -557,6 +575,7 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID protoReader := NewProtoReader(rawSession) defer protoReader.Close() + firstEvent := true for { if ctx.Err() != nil { e <- trace.Wrap(ctx.Err()) @@ -573,6 +592,11 @@ func (l *AuditLog) StreamSessionEvents(ctx context.Context, sessionID session.ID return } + if firstEvent { + sessionStartCh <- event + firstEvent = false + } + if event.GetIndex() >= startIndex { select { case c <- event: @@ -667,3 +691,39 @@ func (l *AuditLog) periodicSpaceMonitor() { } } } + +// streamSessionEventsContextKey represent context keys used by +// StreamSessionEvents function. +type streamSessionEventsContextKey string + +const ( + // sessionStartCallbackContextKey is the context key used to store the + // session start callback function. + sessionStartCallbackContextKey streamSessionEventsContextKey = "session-start" +) + +// SessionStartCallback is the function used when streaming reaches the start +// event. If any error, such as session not found, the event will be nil, and +// the error will be set. +type SessionStartCallback func(startEvent apievents.AuditEvent, err error) + +// ContextWithSessionStartCallback returns a context.Context containing a +// session start event callback. +func ContextWithSessionStartCallback(ctx context.Context, cb SessionStartCallback) context.Context { + return context.WithValue(ctx, sessionStartCallbackContextKey, cb) +} + +// sessionStartCallbackFromContext returns the session start callback from +// context.Context. +func sessionStartCallbackFromContext(ctx context.Context) (SessionStartCallback, error) { + if ctx == nil { + return nil, trace.BadParameter("context is nil") + } + + cb, ok := ctx.Value(sessionStartCallbackContextKey).(SessionStartCallback) + if !ok { + return nil, trace.BadParameter("session start callback function was not found in the context") + } + + return cb, nil +} diff --git a/lib/events/auditlog_test.go b/lib/events/auditlog_test.go index b76d27a0ee36a..416373e3e6951 100644 --- a/lib/events/auditlog_test.go +++ b/lib/events/auditlog_test.go @@ -154,6 +154,137 @@ func TestConcurrentStreaming(t *testing.T) { } } +func TestStreamSessionEvents(t *testing.T) { + uploader := eventstest.NewMemoryUploader() + alog, err := events.NewAuditLog(events.AuditLogConfig{ + DataDir: t.TempDir(), + Clock: clockwork.NewFakeClock(), + ServerID: "remote", + UploadHandler: uploader, + }) + require.NoError(t, err) + t.Cleanup(func() { alog.Close() }) + + ctx := context.Background() + sid := session.NewID() + sessionEvents := []apievents.AuditEvent{ + &apievents.DatabaseSessionStart{ + Metadata: apievents.Metadata{ + Type: events.DatabaseSessionStartEvent, + Code: events.DatabaseSessionStartCode, + Index: 0, + }, + SessionMetadata: apievents.SessionMetadata{ + SessionID: sid.String(), + }, + }, + &apievents.DatabaseSessionEnd{ + Metadata: apievents.Metadata{ + Type: events.DatabaseSessionEndEvent, + Code: events.DatabaseSessionEndCode, + Index: 1, + }, + SessionMetadata: apievents.SessionMetadata{ + SessionID: sid.String(), + }, + }, + } + + streamer, err := events.NewProtoStreamer(events.ProtoStreamerConfig{ + Uploader: uploader, + }) + require.NoError(t, err) + stream, err := streamer.CreateAuditStream(ctx, sid) + require.NoError(t, err) + for _, event := range sessionEvents { + require.NoError(t, stream.RecordEvent(ctx, eventstest.PrepareEvent(event))) + } + require.NoError(t, stream.Complete(ctx)) + + type callbackResult struct { + event apievents.AuditEvent + err error + } + + t.Run("Success", func(t *testing.T) { + for name, withCallback := range map[string]bool{ + "WithCallback": true, + "WithoutCallback": false, + } { + t.Run(name, func(t *testing.T) { + streamCtx, cancel := context.WithCancel(ctx) + defer cancel() + + callbackCh := make(chan callbackResult, 1) + if withCallback { + streamCtx = events.ContextWithSessionStartCallback(streamCtx, func(ae apievents.AuditEvent, err error) { + callbackCh <- callbackResult{ae, err} + }) + } + + ch, _ := alog.StreamSessionEvents(streamCtx, sid, 0) + for _, event := range sessionEvents { + select { + case receivedEvent := <-ch: + require.NotNil(t, receivedEvent) + require.Equal(t, event.GetCode(), receivedEvent.GetCode()) + require.Equal(t, event.GetType(), receivedEvent.GetType()) + case <-time.After(10 * time.Second): + require.Fail(t, "expected to receive session event %q but got nothing", event.GetType()) + } + } + + if withCallback { + select { + case res := <-callbackCh: + require.NoError(t, res.err) + require.Equal(t, sessionEvents[0].GetCode(), res.event.GetCode()) + require.Equal(t, sessionEvents[0].GetType(), res.event.GetType()) + case <-time.After(10 * time.Second): + require.Fail(t, "expected to receive callback result but got nothing") + } + } + }) + } + }) + + t.Run("Error", func(t *testing.T) { + for name, withCallback := range map[string]bool{ + "WithCallback": true, + "WithoutCallback": false, + } { + t.Run(name, func(t *testing.T) { + streamCtx, cancel := context.WithCancel(ctx) + defer cancel() + + callbackCh := make(chan callbackResult, 1) + if withCallback { + streamCtx = events.ContextWithSessionStartCallback(streamCtx, func(ae apievents.AuditEvent, err error) { + callbackCh <- callbackResult{ae, err} + }) + } + + _, errCh := alog.StreamSessionEvents(streamCtx, session.ID("random"), 0) + select { + case err := <-errCh: + require.Error(t, err) + case <-time.After(10 * time.Second): + require.Fail(t, "expected to get error while stream but got nothing") + } + + if withCallback { + select { + case res := <-callbackCh: + require.Error(t, res.err) + case <-time.After(10 * time.Second): + require.Fail(t, "expected to receive callback result but got nothing") + } + } + }) + } + }) +} + func TestExternalLog(t *testing.T) { m := &eventstest.MockAuditLog{ Emitter: &eventstest.MockRecorderEmitter{}, diff --git a/lib/integrations/awsoidc/credprovider/credentialscache_test.go b/lib/integrations/awsoidc/credprovider/credentialscache_test.go index 6384bed0b8db0..03fe165bbaf10 100644 --- a/lib/integrations/awsoidc/credprovider/credentialscache_test.go +++ b/lib/integrations/awsoidc/credprovider/credentialscache_test.go @@ -29,7 +29,6 @@ import ( ststypes "github.com/aws/aws-sdk-go-v2/service/sts/types" "github.com/google/uuid" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -75,8 +74,6 @@ func (f *fakeSTSClient) AssumeRoleWithWebIdentity(ctx context.Context, params *s } func TestCredentialsCache(t *testing.T) { - logrus.SetLevel(logrus.DebugLevel) - ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) diff --git a/lib/integrations/awsoidc/deployserviceconfig/deployservice_config.go b/lib/integrations/awsoidc/deployserviceconfig/deployservice_config.go index 1f2624b94d6c7..941ba7681f7c0 100644 --- a/lib/integrations/awsoidc/deployserviceconfig/deployservice_config.go +++ b/lib/integrations/awsoidc/deployserviceconfig/deployservice_config.go @@ -89,3 +89,26 @@ func GenerateTeleportConfigString(proxyHostPort, iamTokenName string, resourceMa return teleportConfigString, nil } + +// ParseResourceLabelMatchers receives a teleport config string and returns the Resource Matcher Label. +// The expected input is a base64 encoded yaml string containing a teleport configuration, +// the same format that GenerateTeleportConfigString returns. +func ParseResourceLabelMatchers(teleportConfigStringBase64 string) (types.Labels, error) { + teleportConfigString, err := base64.StdEncoding.DecodeString(teleportConfigStringBase64) + if err != nil { + return nil, trace.BadParameter("invalid base64 value, error=%v", err) + } + + var teleportConfig config.FileConfig + if err := yaml.Unmarshal(teleportConfigString, &teleportConfig); err != nil { + return nil, trace.BadParameter("invalid teleport config, error=%v", err) + } + + if len(teleportConfig.Databases.ResourceMatchers) == 0 { + return nil, trace.BadParameter("valid yaml configuration but db_service.resources has 0 items") + } + + resourceMatchers := teleportConfig.Databases.ResourceMatchers[0] + + return resourceMatchers.Labels, nil +} diff --git a/lib/integrations/awsoidc/deployserviceconfig/deployservice_config_test.go b/lib/integrations/awsoidc/deployserviceconfig/deployservice_config_test.go index 1f47d96e2dac4..3b40912ac9160 100644 --- a/lib/integrations/awsoidc/deployserviceconfig/deployservice_config_test.go +++ b/lib/integrations/awsoidc/deployserviceconfig/deployservice_config_test.go @@ -23,8 +23,10 @@ import ( "testing" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils" ) func TestDeployServiceConfig(t *testing.T) { @@ -39,3 +41,45 @@ func TestDeployServiceConfig(t *testing.T) { require.Contains(t, base64Config, base64SeverityDebug) }) } + +func TestParseResourceLabelMatchers(t *testing.T) { + labels := types.Labels{ + "vpc": utils.Strings{"vpc-1", "vpc-2"}, + "region": utils.Strings{"us-west-2"}, + "xyz": utils.Strings{}, + } + base64Config, err := GenerateTeleportConfigString("host:port", "iam-token", labels) + require.NoError(t, err) + + t.Run("recover matching labels", func(t *testing.T) { + gotLabels, err := ParseResourceLabelMatchers(base64Config) + require.NoError(t, err) + + require.Equal(t, labels, gotLabels) + }) + + t.Run("fails if invalid base64 string", func(t *testing.T) { + _, err := ParseResourceLabelMatchers("invalid base 64") + require.ErrorContains(t, err, "base64") + }) + + t.Run("invalid yaml", func(t *testing.T) { + input := base64.StdEncoding.EncodeToString([]byte("invalid yaml")) + _, err := ParseResourceLabelMatchers(input) + require.ErrorContains(t, err, "yaml") + }) + + t.Run("valid yaml but not a teleport config", func(t *testing.T) { + yamlInput := struct { + DBService string `yaml:"db_service"` + }{ + DBService: "not a valid teleport config", + } + yamlBS, err := yaml.Marshal(yamlInput) + require.NoError(t, err) + input := base64.StdEncoding.EncodeToString(yamlBS) + + _, err = ParseResourceLabelMatchers(input) + require.ErrorContains(t, err, "invalid teleport config") + }) +} diff --git a/lib/integrations/diagnostics/profile.go b/lib/integrations/diagnostics/profile.go index 5d185a271c8bd..f34466d749aac 100644 --- a/lib/integrations/diagnostics/profile.go +++ b/lib/integrations/diagnostics/profile.go @@ -17,6 +17,8 @@ package diagnostics import ( + "context" + "log/slog" "os" "path/filepath" "runtime" @@ -26,7 +28,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" ) // Profile captures various Go pprof profiles and writes @@ -34,6 +35,7 @@ import ( // with the same epoch time so that profiles can easily be associated // as being captured from the same call. func Profile(dir string) error { + ctx := context.Background() if err := os.MkdirAll(dir, 0o755); err != nil { return trace.Wrap(err, "creating profile directory %v", dir) } @@ -69,37 +71,37 @@ func Profile(dir string) error { } defer blockFile.Close() - logrus.Debugf("capturing trace profile to %s", traceFile.Name()) + slog.DebugContext(ctx, "capturing trace profile", "file", traceFile.Name()) if err := runtimetrace.Start(traceFile); err != nil { return trace.Wrap(err, "capturing trace profile") } - logrus.Debugf("capturing cpu profile to %s", cpuFile.Name()) + slog.DebugContext(ctx, "capturing cpu profile", "file", cpuFile.Name()) if err := pprof.StartCPUProfile(cpuFile); err != nil { return trace.Wrap(err, "capturing cpu profile") } defer func() { - logrus.Debugf("capturing goroutine profile to %s", cpuFile.Name()) + slog.DebugContext(ctx, "capturing goroutine profile", "file", cpuFile.Name()) if err := pprof.Lookup("goroutine").WriteTo(goroutineFile, 0); err != nil { - logrus.WithError(err).Warn("failed to capture goroutine profile") + slog.WarnContext(ctx, "failed to capture goroutine profile", "error", err) } - logrus.Debugf("capturing block profile to %s", cpuFile.Name()) + slog.DebugContext(ctx, "capturing block profile", "file", cpuFile.Name()) if err := pprof.Lookup("block").WriteTo(blockFile, 0); err != nil { - logrus.WithError(err).Warn("failed to capture block profile") + slog.WarnContext(ctx, "failed to capture block profile", "error", err) } runtime.GC() - logrus.Debugf("capturing heap profile to %s", cpuFile.Name()) + slog.DebugContext(ctx, "capturing heap profile", "file", cpuFile.Name()) if err := pprof.WriteHeapProfile(heapFile); err != nil { - logrus.WithError(err).Warn("failed to capture heap profile") + slog.WarnContext(ctx, "failed to capture heap profile", "error", err) } pprof.StopCPUProfile() diff --git a/lib/integrations/externalauditstorage/configurator_test.go b/lib/integrations/externalauditstorage/configurator_test.go index ba86e5f8e0c27..28d231b081b8e 100644 --- a/lib/integrations/externalauditstorage/configurator_test.go +++ b/lib/integrations/externalauditstorage/configurator_test.go @@ -30,7 +30,6 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/google/uuid" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -179,7 +178,6 @@ func TestConfiguratorIsUsed(t *testing.T) { } func TestCredentialsCache(t *testing.T) { - logrus.SetLevel(logrus.DebugLevel) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/lib/integrations/externalauditstorage/error_counter.go b/lib/integrations/externalauditstorage/error_counter.go index 1cc0f650c90f9..7525cd5631ffb 100644 --- a/lib/integrations/externalauditstorage/error_counter.go +++ b/lib/integrations/externalauditstorage/error_counter.go @@ -29,7 +29,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" auditlogpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/auditlog/v1" @@ -38,6 +37,7 @@ import ( apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/session" + logutils "github.com/gravitational/teleport/lib/utils/log" ) const ( @@ -53,7 +53,7 @@ const ( syncInterval = 30 * time.Second ) -var log = logrus.WithField(teleport.ComponentKey, "ExternalAuditStorage") +var log = logutils.NewPackageLogger(teleport.ComponentKey, "ExternalAuditStorage") // ClusterAlertService abstracts a service providing Upsert and Delete // operations for cluster alerts. @@ -189,16 +189,25 @@ func (c *ErrorCounter) sync(ctx context.Context) { types.WithAlertLabel(types.AlertOnLogin, "yes"), types.WithAlertLabel(types.AlertVerbPermit, "external_audit_storage:create")) if err != nil { - log.Infof("ErrorCounter failed to create cluster alert %s: %s", newAlert.name, err) + log.InfoContext(ctx, "ErrorCounter failed to create cluster alert", + "alert_name", newAlert.name, + "error", err, + ) continue } if err := c.alertService.UpsertClusterAlert(ctx, alert); err != nil { - log.Infof("ErrorCounter failed to upsert cluster alert %s: %s", newAlert.name, err) + log.InfoContext(ctx, "ErrorCounter failed to upsert cluster alert", + "alert_name", newAlert.name, + "error", err, + ) } } for _, alertToClear := range allAlertActions.clearAlerts { if err := c.alertService.DeleteClusterAlert(ctx, alertToClear); err != nil && !trace.IsNotFound(err) { - log.Infof("ErrorCounter failed to delete cluster alert %s: %s", alertToClear, err) + log.InfoContext(ctx, "ErrorCounter failed to delete cluster alert", + "alert_name", alertToClear, + "error", err, + ) } } } diff --git a/lib/inventory/controller.go b/lib/inventory/controller.go index 4bdbd2f596c41..b1825c240e439 100644 --- a/lib/inventory/controller.go +++ b/lib/inventory/controller.go @@ -1174,6 +1174,7 @@ func (c *Controller) keepAliveSSHServer(handle *upstreamHandle, now time.Time) e return nil } + handle.sshServer.resource.SetExpiry(now.Add(c.serverTTL).UTC()) if _, err := c.auth.UpsertNode(c.closeContext, handle.sshServer.resource); err == nil { if handle.sshServer.retryUpsert { c.testEvent(sshUpsertRetryOk) diff --git a/lib/kube/grpc/grpc.go b/lib/kube/grpc/grpc.go index 67f17fc4d5079..bbd982cd12da0 100644 --- a/lib/kube/grpc/grpc.go +++ b/lib/kube/grpc/grpc.go @@ -21,11 +21,11 @@ package kubev1 import ( "context" "errors" + "log/slog" "slices" "github.com/gravitational/trace" "github.com/gravitational/trace/trail" - "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -85,7 +85,7 @@ type Config struct { // Authz authenticates user. Authz authz.Authorizer // Log is the logger function. - Log logrus.FieldLogger + Log *slog.Logger // Emitter is used to emit audit events. Emitter apievents.Emitter // Component name to include in log output. @@ -139,9 +139,9 @@ func (c *Config) CheckAndSetDefaults() error { c.Component = "kube.grpc" } if c.Log == nil { - c.Log = logrus.New() + c.Log = slog.Default() } - c.Log = c.Log.WithFields(logrus.Fields{teleport.ComponentKey: c.Component}) + c.Log = c.Log.With(teleport.ComponentKey, c.Component) return nil } diff --git a/lib/kube/kubeconfig/kubeconfig.go b/lib/kube/kubeconfig/kubeconfig.go index 30e587da834d1..dc9f8d92833f1 100644 --- a/lib/kube/kubeconfig/kubeconfig.go +++ b/lib/kube/kubeconfig/kubeconfig.go @@ -21,13 +21,13 @@ package kubeconfig import ( "bytes" + "context" "fmt" "os" "path/filepath" "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/exp/maps" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/clientcmd" @@ -36,11 +36,10 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) -var log = logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.ComponentKubeClient, -}) +var log = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentKubeClient) const ( // teleportKubeClusterNameExtension is the name of the extension that @@ -268,7 +267,7 @@ func UpdateConfig(path string, v Values, storeAllCAs bool, fs ConfigFS) error { } else if !trace.IsBadParameter(err) { return trace.Wrap(err) } - log.WithError(err).Warn("Kubernetes integration is not supported when logging in with a hardware private key.") + log.WarnContext(context.Background(), "Kubernetes integration is not supported when logging in with a hardware private key", "error", err) } return SaveConfig(path, *config, fs) @@ -493,7 +492,7 @@ func PathFromEnv() string { var configPath string if len(parts) > 0 { configPath = parts[0] - log.Debugf("Using kubeconfig from environment: %q.", configPath) + log.DebugContext(context.Background(), "Using kubeconfig from environment", "config_path", configPath) } return configPath diff --git a/lib/kube/proxy/auth.go b/lib/kube/proxy/auth.go index 16ee58685e1a2..61842aca77bf0 100644 --- a/lib/kube/proxy/auth.go +++ b/lib/kube/proxy/auth.go @@ -23,12 +23,12 @@ import ( "context" "crypto/tls" "fmt" + "log/slog" "net" "net/http" "net/url" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" authzapi "k8s.io/api/authorization/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilnet "k8s.io/apimachinery/pkg/util/net" @@ -77,11 +77,11 @@ func (f *Forwarder) getKubeDetails(ctx context.Context) error { kubeClusterName := f.cfg.KubeClusterName tpClusterName := f.cfg.ClusterName - f.log. - WithField("kubeconfigPath", kubeconfigPath). - WithField("kubeClusterName", kubeClusterName). - WithField("serviceType", serviceType). - Debug("Reading Kubernetes details.") + f.log.DebugContext(ctx, "Reading Kubernetes details", + "kubeconfig_path", kubeconfigPath, + "kube_cluster_name", kubeClusterName, + "service_type", serviceType, + ) // Proxy service should never have creds, forwards to kube service if serviceType == ProxyService { @@ -100,7 +100,7 @@ func (f *Forwarder) getKubeDetails(ctx context.Context) error { case KubeService: return trace.BadParameter("no Kubernetes credentials found; Kubernetes_service requires either a valid kubeconfig_file or to run inside of a Kubernetes pod") case LegacyProxyService: - f.log.Debugf("Could not load Kubernetes credentials. This proxy will still handle Kubernetes requests for trusted teleport clusters or Kubernetes nodes in this teleport cluster") + f.log.DebugContext(ctx, "Could not load Kubernetes credentials. This proxy will still handle Kubernetes requests for trusted teleport clusters or Kubernetes nodes in this teleport cluster") } return nil } @@ -124,14 +124,20 @@ func (f *Forwarder) getKubeDetails(ctx context.Context) error { for cluster, clientCfg := range cfg.Contexts { clusterCreds, err := extractKubeCreds(ctx, serviceType, cluster, clientCfg, f.log, f.cfg.CheckImpersonationPermissions) if err != nil { - f.log.WithError(err).Warnf("failed to load credentials for cluster %q.", cluster) + f.log.WarnContext(ctx, "failed to load credentials for cluster", + "cluster", cluster, + "error", err, + ) continue } kubeCluster, err := types.NewKubernetesClusterV3(types.Metadata{ Name: cluster, }, types.KubernetesClusterSpecV3{}) if err != nil { - f.log.WithError(err).Warnf("failed to create KubernetesClusterV3 from credentials for cluster %q.", cluster) + f.log.WarnContext(ctx, "failed to create KubernetesClusterV3 from credentials for cluster", + "cluster", cluster, + "error", err, + ) continue } @@ -139,13 +145,16 @@ func (f *Forwarder) getKubeDetails(ctx context.Context) error { clusterDetailsConfig{ cluster: kubeCluster, kubeCreds: clusterCreds, - log: f.log.WithField("cluster", kubeCluster.GetName()), + log: f.log.With("cluster", kubeCluster.GetName()), checker: f.cfg.CheckImpersonationPermissions, component: serviceType, clock: f.cfg.Clock, }) if err != nil { - f.log.WithError(err).Warnf("Failed to create cluster details for cluster %q.", cluster) + f.log.WarnContext(ctx, "Failed to create cluster details for cluster", + "cluster", cluster, + "error", err, + ) return trace.Wrap(err) } f.clusterDetails[cluster] = details @@ -153,10 +162,10 @@ func (f *Forwarder) getKubeDetails(ctx context.Context) error { return nil } -func extractKubeCreds(ctx context.Context, component string, cluster string, clientCfg *rest.Config, log logrus.FieldLogger, checkPermissions servicecfg.ImpersonationPermissionsChecker) (*staticKubeCreds, error) { - log = log.WithField("cluster", cluster) +func extractKubeCreds(ctx context.Context, component string, cluster string, clientCfg *rest.Config, log *slog.Logger, checkPermissions servicecfg.ImpersonationPermissionsChecker) (*staticKubeCreds, error) { + log = log.With("cluster", cluster) - log.Debug("Checking Kubernetes impersonation permissions.") + log.DebugContext(ctx, "Checking Kubernetes impersonation permissions") client, err := kubernetes.NewForConfig(clientCfg) if err != nil { return nil, trace.Wrap(err, "failed to generate Kubernetes client for cluster %q", cluster) @@ -165,9 +174,11 @@ func extractKubeCreds(ctx context.Context, component string, cluster string, cli // For each loaded cluster, check impersonation permissions. This // check only logs when permissions are not configured, but does not fail startup. if err := checkPermissions(ctx, cluster, client.AuthorizationV1().SelfSubjectAccessReviews()); err != nil { - log.WithError(err).Warning("Failed to test the necessary Kubernetes permissions. The target Kubernetes cluster may be down or have misconfigured RBAC. This teleport instance will still handle Kubernetes requests towards this Kubernetes cluster.") + log.WarnContext(ctx, "Failed to test the necessary Kubernetes permissions. The target Kubernetes cluster may be down or have misconfigured RBAC. This teleport instance will still handle Kubernetes requests towards this Kubernetes cluster.", + "error", err, + ) } else { - log.Debug("Have all necessary Kubernetes impersonation permissions.") + log.DebugContext(ctx, "Have all necessary Kubernetes impersonation permissions") } targetAddr, err := parseKubeHost(clientCfg.Host) @@ -192,7 +203,7 @@ func extractKubeCreds(ctx context.Context, component string, cluster string, cli return nil, trace.Wrap(err, "failed to generate transport from kubeconfig: %v", err) } - log.Debug("Initialized Kubernetes credentials") + log.DebugContext(ctx, "Initialized Kubernetes credentials") return &staticKubeCreds{ tlsConfig: tlsConfig, transportConfig: transportConfig, diff --git a/lib/kube/proxy/auth_test.go b/lib/kube/proxy/auth_test.go index 1263a0e8b9ad2..9d8269297f8f1 100644 --- a/lib/kube/proxy/auth_test.go +++ b/lib/kube/proxy/auth_test.go @@ -140,7 +140,6 @@ func TestGetKubeCreds(t *testing.T) { rbacSupportedTypes[allowedResourcesKey{apiGroup: "resources.teleport.dev", resourceKind: "teleportroles"}] = utils.KubeCustomResource rbacSupportedTypes[allowedResourcesKey{apiGroup: "resources.teleport.dev", resourceKind: "teleportroles/status"}] = utils.KubeCustomResource - logger := utils.NewLoggerForTests() ctx := context.TODO() const teleClusterName = "teleport-cluster" dir := t.TempDir() @@ -351,7 +350,7 @@ current-context: foo CheckImpersonationPermissions: tt.impersonationCheck, Clock: clockwork.NewFakeClock(), }, - log: logger, + log: utils.NewSlogLoggerForTests(), } err := fwd.getKubeDetails(ctx) tt.assertErr(t, err) diff --git a/lib/kube/proxy/cluster_details.go b/lib/kube/proxy/cluster_details.go index c949494ac982d..1a66ce0562978 100644 --- a/lib/kube/proxy/cluster_details.go +++ b/lib/kube/proxy/cluster_details.go @@ -21,6 +21,7 @@ package proxy import ( "context" "encoding/base64" + "log/slog" "strings" "sync" "time" @@ -29,7 +30,6 @@ import ( "github.com/aws/aws-sdk-go/service/eks" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/version" @@ -91,7 +91,7 @@ type clusterDetailsConfig struct { // cluster is the cluster to create a proxied cluster for. cluster types.KubeCluster // log is the logger to use. - log *logrus.Entry + log *slog.Logger // checker is the permissions checker to use. checker servicecfg.ImpersonationPermissionsChecker // resourceMatchers is the list of resource matchers to match the cluster against @@ -135,7 +135,7 @@ func newClusterDetails(ctx context.Context, cfg clusterDetailsConfig) (_ *kubeDe // Create the codec factory and the list of supported types for RBAC. codecFactory, rbacSupportedTypes, gvkSupportedRes, err := newClusterSchemaBuilder(cfg.log, creds.getKubeClient()) if err != nil { - cfg.log.WithError(err).Warn("Failed to create cluster schema. Possibly the cluster is offline.") + cfg.log.WarnContext(ctx, "Failed to create cluster schema, the cluster may be offline", "error", err) // If the cluster is offline, we will not be able to create the codec factory // and the list of supported types for RBAC. // We mark the cluster as offline and continue to create the kubeDetails but @@ -145,7 +145,7 @@ func newClusterDetails(ctx context.Context, cfg clusterDetailsConfig) (_ *kubeDe kubeVersion, err := creds.getKubeClient().Discovery().ServerVersion() if err != nil { - cfg.log.WithError(err).Warn("Failed to get Kubernetes cluster version. Possibly the cluster is offline.") + cfg.log.WarnContext(ctx, "Failed to get Kubernetes cluster version, the cluster may be offline", "error", err) } ctx, cancel := context.WithCancel(ctx) @@ -198,13 +198,13 @@ func newClusterDetails(ctx context.Context, cfg clusterDetailsConfig) (_ *kubeDe } else { refreshDelay.Inc() } - cfg.log.WithError(err).Error("Failed to update cluster schema") + cfg.log.ErrorContext(ctx, "Failed to update cluster schema", "error", err) continue } kubeVersion, err := creds.getKubeClient().Discovery().ServerVersion() if err != nil { - cfg.log.WithError(err).Warn("Failed to get Kubernetes cluster version. Possibly the cluster is offline.") + cfg.log.WarnContext(ctx, "Failed to get Kubernetes cluster version, the cluster may be offline", "error", err) } // Restore details refresh delay to the default value, in case previously cluster was offline. @@ -389,7 +389,7 @@ func getAWSClientRestConfig(cloudClients cloud.Clients, clock clockwork.Clock, r // getStaticCredentialsFromKubeconfig loads a kubeconfig from the cluster and returns the access credentials for the cluster. // If the config defines multiple contexts, it will pick one (the order is not guaranteed). -func getStaticCredentialsFromKubeconfig(ctx context.Context, component KubeServiceType, cluster types.KubeCluster, log *logrus.Entry, checker servicecfg.ImpersonationPermissionsChecker) (*staticKubeCreds, error) { +func getStaticCredentialsFromKubeconfig(ctx context.Context, component KubeServiceType, cluster types.KubeCluster, log *slog.Logger, checker servicecfg.ImpersonationPermissionsChecker) (*staticKubeCreds, error) { config, err := clientcmd.Load(cluster.GetKubeconfig()) if err != nil { return nil, trace.WrapWithMessage(err, "unable to parse kubeconfig for cluster %q", cluster.GetName()) diff --git a/lib/kube/proxy/cluster_details_test.go b/lib/kube/proxy/cluster_details_test.go index 116a575bc4143..9b52a695752da 100644 --- a/lib/kube/proxy/cluster_details_test.go +++ b/lib/kube/proxy/cluster_details_test.go @@ -26,7 +26,6 @@ import ( "time" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/version" @@ -34,12 +33,12 @@ import ( "k8s.io/client-go/kubernetes" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/utils" ) func TestNewClusterDetails(t *testing.T) { t.Parallel() ctx := context.Background() - log := logrus.New().WithContext(ctx) getClusterDetailsConfig := func(c clockwork.FakeClock) (clusterDetailsConfig, *clusterDetailsClientSet) { client := &clusterDetailsClientSet{} @@ -48,7 +47,7 @@ func TestNewClusterDetails(t *testing.T) { kubeClient: client, }, cluster: &types.KubernetesClusterV3{}, - log: log, + log: utils.NewSlogLoggerForTests(), clock: c, }, client } diff --git a/lib/kube/proxy/ephemeral_containers.go b/lib/kube/proxy/ephemeral_containers.go index 1c9ae08e417a4..61947055c0067 100644 --- a/lib/kube/proxy/ephemeral_containers.go +++ b/lib/kube/proxy/ephemeral_containers.go @@ -83,7 +83,7 @@ func (f *Forwarder) ephemeralContainers(authCtx *authContext, w http.ResponseWri if err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to create cluster session: %v.", err) + f.log.ErrorContext(req.Context(), "Failed to create cluster session", "error", err) return nil, trace.Wrap(err) } // sess.Close cancels the connection monitor context to release it sooner. @@ -101,7 +101,7 @@ func (f *Forwarder) ephemeralContainers(authCtx *authContext, w http.ResponseWri if err := f.setupForwardingHeaders(sess, req, true /* withImpersonationHeaders */); err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to set up forwarding headers: %v.", err) + f.log.ErrorContext(req.Context(), "Failed to set up forwarding headers", "error", err) return nil, trace.Wrap(err) } if !sess.isLocalKubernetesCluster { diff --git a/lib/kube/proxy/forwarder.go b/lib/kube/proxy/forwarder.go index b3df6d6c0b153..aeed6d7c631ac 100644 --- a/lib/kube/proxy/forwarder.go +++ b/lib/kube/proxy/forwarder.go @@ -41,7 +41,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" "github.com/julienschmidt/httprouter" - "github.com/sirupsen/logrus" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" oteltrace "go.opentelemetry.io/otel/trace" kubeerrors "k8s.io/apimachinery/pkg/api/errors" @@ -86,6 +85,7 @@ import ( "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/sshca" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // KubeServiceType specifies a Teleport service type which can forward Kubernetes requests @@ -157,7 +157,7 @@ type ForwarderConfig struct { // PROXYSigner is used to sign PROXY headers for securely propagating client IP address PROXYSigner multiplexer.PROXYHeaderSigner // log is the logger function - log logrus.FieldLogger + log *slog.Logger // TracerProvider is used to create tracers capable // of starting spans. TracerProvider oteltrace.TracerProvider @@ -272,7 +272,7 @@ func (f *ForwarderConfig) CheckAndSetDefaults() error { f.KubeClusterName = f.ClusterName } if f.log == nil { - f.log = logrus.New() + f.log = slog.Default() } return nil } @@ -347,7 +347,7 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { fwd.router = instrumentHTTPHandler(fwd.cfg.KubeServiceType, router) if cfg.ClusterOverride != "" { - fwd.log.Debugf("Cluster override is set, forwarder will send all requests to remote cluster %v.", cfg.ClusterOverride) + fwd.log.DebugContext(closeCtx, "Cluster override is set, forwarder will send all requests to remote cluster", "cluster_override", cfg.ClusterOverride) } if len(cfg.KubeClusterName) > 0 || len(cfg.KubeconfigPath) > 0 || cfg.KubeServiceType != KubeService { if err := fwd.getKubeDetails(cfg.Context); err != nil { @@ -363,7 +363,7 @@ func NewForwarder(cfg ForwarderConfig) (*Forwarder, error) { // however some requests like exec sessions it intercepts and records. type Forwarder struct { mu sync.Mutex - log logrus.FieldLogger + log *slog.Logger router http.Handler cfg ForwarderConfig // activeRequests is a map used to serialize active CSR requests to the auth server @@ -540,7 +540,7 @@ func (f *Forwarder) authenticate(req *http.Request) (*authContext, error) { var isRemoteUser bool userTypeI, err := authz.UserFromContext(ctx) if err != nil { - f.log.WithError(err).Warn("error getting user from context") + f.log.WarnContext(ctx, "error getting user from context", "error", err) return nil, trace.AccessDenied(accessDeniedMsg) } switch userTypeI.(type) { @@ -549,10 +549,12 @@ func (f *Forwarder) authenticate(req *http.Request) (*authContext, error) { case authz.RemoteUser: isRemoteUser = true case authz.BuiltinRole: - f.log.Warningf("Denying proxy access to unauthenticated user of type %T - this can sometimes be caused by inadvertently using an HTTP load balancer instead of a TCP load balancer on the Kubernetes port.", userTypeI) + f.log.WarnContext(ctx, "Denying proxy access to unauthenticated user - this can sometimes be caused by inadvertently using an HTTP load balancer instead of a TCP load balancer on the Kubernetes port", + "user_type", logutils.TypeAttr(userTypeI), + ) return nil, trace.AccessDenied(accessDeniedMsg) default: - f.log.Warningf("Denying proxy access to unsupported user type: %T.", userTypeI) + f.log.WarnContext(ctx, "Denying proxy access to unsupported user type", "user_type", logutils.TypeAttr(userTypeI)) return nil, trace.AccessDenied(accessDeniedMsg) } @@ -563,7 +565,7 @@ func (f *Forwarder) authenticate(req *http.Request) (*authContext, error) { authContext, err := f.setupContext(ctx, *userContext, req, isRemoteUser) if err != nil { - f.log.WithError(err).Warn("Unable to setup context.") + f.log.WarnContext(ctx, "Unable to setup context", "error", err) if trace.IsAccessDenied(err) { return nil, trace.AccessDenied(accessDeniedMsg) } @@ -726,7 +728,7 @@ func (f *Forwarder) formatStatusResponseError(rw http.ResponseWriter, respErr er } data, err := runtime.Encode(globalKubeCodecs.LegacyCodec(), status) if err != nil { - f.log.Warningf("Failed encoding error into kube Status object: %v", err) + f.log.WarnContext(f.ctx, "Failed encoding error into kube Status object", "error", err) trace.WriteError(rw, respErr) return } @@ -737,7 +739,7 @@ func (f *Forwarder) formatStatusResponseError(rw http.ResponseWriter, respErr er // has prevented the request from succeeding`` instead of the correct reason. rw.WriteHeader(trace.ErrorToCode(respErr)) if _, err := rw.Write(data); err != nil { - f.log.Warningf("Failed writing kube error response body: %v", err) + f.log.WarnContext(f.ctx, "Failed writing kube error response body", "error", err) } } @@ -919,7 +921,7 @@ func (f *Forwarder) emitAuditEvent(req *http.Request, sess *clusterSession, stat r.populateEvent(event) if err := f.cfg.AuthClient.EmitAuditEvent(f.ctx, event); err != nil { - f.log.WithError(err).Warn("Failed to emit event.") + f.log.WarnContext(f.ctx, "Failed to emit event", "error", err) } } @@ -1033,13 +1035,17 @@ func (f *Forwarder) authorize(ctx context.Context, actx *authContext) error { if actx.teleportCluster.isRemote { // Authorization for a remote kube cluster will happen on the remote // end (by their proxy), after that cluster has remapped used roles. - f.log.WithField("auth_context", actx.String()).Debug("Skipping authorization for a remote kubernetes cluster name") + f.log.DebugContext(ctx, "Skipping authorization for a remote kubernetes cluster name", + "auth_context", logutils.StringerAttr(actx), + ) return nil } if actx.kubeClusterName == "" { // This should only happen for remote clusters (filtered above), but // check and report anyway. - f.log.WithField("auth_context", actx.String()).Debug("Skipping authorization due to unknown kubernetes cluster name") + f.log.DebugContext(ctx, "Skipping authorization due to unknown kubernetes cluster name", + "auth_context", logutils.StringerAttr(actx), + ) return nil } @@ -1135,7 +1141,9 @@ func (f *Forwarder) authorize(ctx context.Context, actx *authContext) error { return nil } if actx.kubeClusterName == f.cfg.ClusterName { - f.log.WithField("auth_context", actx.String()).Debug("Skipping authorization for proxy-based kubernetes cluster,") + f.log.DebugContext(ctx, "Skipping authorization for proxy-based kubernetes cluster", + "auth_context", logutils.StringerAttr(actx), + ) return nil } return trace.AccessDenied(notFoundMessage) @@ -1168,7 +1176,7 @@ func (f *Forwarder) join(ctx *authContext, w http.ResponseWriter, req *http.Requ joinSessionsInFlightGauge.WithLabelValues(f.cfg.KubeServiceType).Inc() defer joinSessionsInFlightGauge.WithLabelValues(f.cfg.KubeServiceType).Dec() - f.log.Debugf("Join %v.", req.URL.String()) + f.log.DebugContext(req.Context(), "Joining session", "join_url", logutils.StringerAttr(req.URL)) sess, err := f.newClusterSession(req.Context(), *ctx) if err != nil { @@ -1241,7 +1249,11 @@ func (f *Forwarder) join(ctx *authContext, w http.ResponseWriter, req *http.Requ close(closeC) if _, err := session.leave(party.ID); err != nil { - f.log.WithError(err).Debugf("Participant %q was unable to leave session %s", party.ID, session.id) + f.log.DebugContext(req.Context(), "Participant was unable to leave session", + "participant_id", party.ID, + "session_id", session.id, + "error", err, + ) } wg.Wait() @@ -1249,7 +1261,7 @@ func (f *Forwarder) join(ctx *authContext, w http.ResponseWriter, req *http.Requ }(); err != nil { writeErr := ws.WriteControl(gwebsocket.CloseMessage, gwebsocket.FormatCloseMessage(gwebsocket.CloseInternalServerErr, err.Error()), time.Now().Add(time.Second*10)) if writeErr != nil { - f.log.WithError(writeErr).Warn("Failed to send early-exit websocket close message.") + f.log.WarnContext(req.Context(), "Failed to send early-exit websocket close message", "error", writeErr) } } @@ -1337,7 +1349,7 @@ func (f *Forwarder) remoteJoin(ctx *authContext, w http.ResponseWriter, req *htt } defer wsSource.Close() - wsProxy(f.log, wsSource, wsTarget) + wsProxy(req.Context(), f.log, wsSource, wsTarget) return nil, nil } @@ -1362,7 +1374,7 @@ func (f *Forwarder) getSessionHostID(ctx context.Context, authCtx *authContext, // wsProxy proxies a websocket connection between two clusters transparently to allow for // remote joins. -func wsProxy(log logrus.FieldLogger, wsSource *gwebsocket.Conn, wsTarget *gwebsocket.Conn) { +func wsProxy(ctx context.Context, log *slog.Logger, wsSource *gwebsocket.Conn, wsTarget *gwebsocket.Conn) { errS := make(chan error, 1) errT := make(chan error, 1) wg := &sync.WaitGroup{} @@ -1416,7 +1428,7 @@ func wsProxy(log logrus.FieldLogger, wsSource *gwebsocket.Conn, wsTarget *gwebso var websocketErr *gwebsocket.CloseError if errors.As(err, &websocketErr) && websocketErr.Code == gwebsocket.CloseAbnormalClosure { - log.WithError(err).Debugf("websocket proxy: Error when copying from %s to %s", from, to) + log.DebugContext(ctx, "websocket proxying failed", "src", from, "target", to, "error", err) } wg.Wait() } @@ -1496,7 +1508,7 @@ func (f *Forwarder) execNonInteractive(ctx *authContext, req *http.Request, _ ht } if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, sessionStartEvent); err != nil { - f.log.WithError(err).Warn("Failed to emit event.") + f.log.WarnContext(f.ctx, "Failed to emit event", "error", err) return trace.Wrap(err) } @@ -1518,7 +1530,7 @@ func (f *Forwarder) execNonInteractive(ctx *authContext, req *http.Request, _ ht defer func() { if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, execEvent); err != nil { - f.log.WithError(err).Warn("Failed to emit exec event.") + f.log.WarnContext(f.ctx, "Failed to emit exec event", "error", err) } sessionEndEvent := &apievents.SessionEnd{ @@ -1541,7 +1553,7 @@ func (f *Forwarder) execNonInteractive(ctx *authContext, req *http.Request, _ ht } if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, sessionEndEvent); err != nil { - f.log.WithError(err).Warn("Failed to emit session end event.") + f.log.WarnContext(f.ctx, "Failed to emit session end event", "error", err) } }() @@ -1550,7 +1562,7 @@ func (f *Forwarder) execNonInteractive(ctx *authContext, req *http.Request, _ ht execEvent.Code = events.ExecFailureCode execEvent.Error, execEvent.ExitCode = exitCode(err) - f.log.WithError(err).Warning("Failed creating executor.") + f.log.WarnContext(f.ctx, "Failed creating executor", "error", err) return trace.Wrap(err) } @@ -1560,7 +1572,7 @@ func (f *Forwarder) execNonInteractive(ctx *authContext, req *http.Request, _ ht execEvent.Code = events.ExecFailureCode execEvent.Error, execEvent.ExitCode = exitCode(err) - f.log.WithError(err).Warning("Executor failed while streaming.") + f.log.WarnContext(f.ctx, "Executor failed while streaming", "error", err) return trace.Wrap(err) } @@ -1629,10 +1641,10 @@ func (f *Forwarder) exec(authCtx *authContext, w http.ResponseWriter, req *http. ) defer span.End() - f.log.Debugf("Exec %v.", req.URL.String()) + f.log.DebugContext(ctx, "Starting exec", "exec_url", logutils.StringerAttr(req.URL)) defer func() { if err != nil { - f.log.WithError(err).Debug("Exec request failed") + f.log.DebugContext(ctx, "Exec request failed", "error", err) } }() @@ -1640,7 +1652,7 @@ func (f *Forwarder) exec(authCtx *authContext, w http.ResponseWriter, req *http. if err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to create cluster session: %v.", err) + f.log.ErrorContext(ctx, "Failed to create cluster session", "error", err) return nil, trace.Wrap(err) } // sess.Close cancels the connection monitor context to release it sooner. @@ -1702,7 +1714,11 @@ func (f *Forwarder) exec(authCtx *authContext, w http.ResponseWriter, req *http. err = <-party.closeC if _, errLeave := session.leave(party.ID); errLeave != nil { - f.log.WithError(errLeave).Debugf("Participant %q was unable to leave session %s", party.ID, session.id) + f.log.DebugContext(ctx, "Participant was unable to leave session", + "participant_id", party.ID, + "session_id", session.id, + "error", errLeave, + ) } return trace.Wrap(err) @@ -1714,13 +1730,13 @@ func (f *Forwarder) exec(authCtx *authContext, w http.ResponseWriter, req *http. func (f *Forwarder) remoteExec(req *http.Request, sess *clusterSession, proxy *remoteCommandProxy) error { executor, err := f.getExecutor(sess, req) if err != nil { - f.log.WithError(err).Warning("Failed creating executor.") + f.log.WarnContext(req.Context(), "Failed creating executor", "error", err) return trace.Wrap(err) } streamOptions := proxy.options() err = executor.StreamWithContext(req.Context(), streamOptions) if err != nil { - f.log.WithError(err).Warning("Executor failed while streaming.") + f.log.WarnContext(req.Context(), "Executor failed while streaming", "error", err) } return trace.Wrap(err) @@ -1745,12 +1761,15 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req ) defer span.End() - f.log.Debugf("Port forward: %v. req headers: %v.", req.URL.String(), req.Header) + f.log.DebugContext(ctx, "Handling port forward request", + "request_url", logutils.StringerAttr(req.URL), + "request_headers", req.Header, + ) sess, err := f.newClusterSession(ctx, *authCtx) if err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to create cluster session: %v.", err) + f.log.ErrorContext(ctx, "Failed to create cluster session", "error", err) return nil, trace.Wrap(err) } // sess.Close cancels the connection monitor context to release it sooner. @@ -1765,7 +1784,7 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req } if err := f.setupForwardingHeaders(sess, req, true /* withImpersonationHeaders */); err != nil { - f.log.Debugf("DENIED Port forward: %v.", req.URL.String()) + f.log.DebugContext(ctx, "DENIED Port forward", "request_url", logutils.StringerAttr(req.URL)) return nil, trace.Wrap(err) } @@ -1805,7 +1824,7 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req portForward.Code = events.PortForwardFailureCode } if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, portForward); err != nil { - f.log.WithError(err).Warn("Failed to emit event.") + f.log.WarnContext(ctx, "Failed to emit event", "error", err) } } defer func() { @@ -1829,7 +1848,7 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req }, } if err := f.cfg.Emitter.EmitAuditEvent(f.ctx, portForward); err != nil { - f.log.WithError(err).Warn("Failed to emit event.") + f.log.WarnContext(ctx, "Failed to emit event", "error", err) } } }() @@ -1847,12 +1866,12 @@ func (f *Forwarder) portForward(authCtx *authContext, w http.ResponseWriter, req pingPeriod: f.cfg.ConnPingPeriod, idleTimeout: sess.clientIdleTimeout, } - f.log.Debugf("Starting %v.", request) + f.log.DebugContext(ctx, "Starting port forwarding", "request", request) err = runPortForwarding(request) if err != nil { return nil, trace.Wrap(err) } - f.log.Debugf("Done %v.", request) + f.log.DebugContext(ctx, "Completed port forwarding", "request", request) return nil, nil } @@ -2057,11 +2076,11 @@ func (f *Forwarder) catchAll(authCtx *authContext, w http.ResponseWriter, req *h req = req.WithContext(ctx) defer span.End() - sess, err := f.newClusterSession(req.Context(), *authCtx) + sess, err := f.newClusterSession(ctx, *authCtx) if err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to create cluster session: %v.", err) + f.log.ErrorContext(ctx, "Failed to create cluster session", "error", err) return nil, trace.Wrap(err) } // sess.Close cancels the connection monitor context to release it sooner. @@ -2079,7 +2098,7 @@ func (f *Forwarder) catchAll(authCtx *authContext, w http.ResponseWriter, req *h if err := f.setupForwardingHeaders(sess, req, true /* withImpersonationHeaders */); err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to set up forwarding headers: %v.", err) + f.log.ErrorContext(ctx, "Failed to set up forwarding headers", "error", err) return nil, trace.Wrap(err) } @@ -2151,7 +2170,10 @@ func (f *Forwarder) getWebsocketRestConfig(sess *clusterSession, req *http.Reque } func (f *Forwarder) getWebsocketExecutor(sess *clusterSession, req *http.Request) (remotecommand.Executor, error) { - f.log.Debugf("Creating websocket remote executor for request %s %s", req.Method, req.RequestURI) + f.log.DebugContext(req.Context(), "Creating websocket remote executor for request", + "request_method", req.Method, + "request_uri", req.RequestURI, + ) cfg, err := f.getWebsocketRestConfig(sess, req) if err != nil { return nil, trace.Wrap(err, "unable to create websocket executor") @@ -2190,7 +2212,10 @@ func (f *Forwarder) getExecutor(sess *clusterSession, req *http.Request) (remote } func (f *Forwarder) getSPDYExecutor(sess *clusterSession, req *http.Request) (remotecommand.Executor, error) { - f.log.Debugf("Creating SPDY remote executor for request %s %s", req.Method, req.RequestURI) + f.log.DebugContext(req.Context(), "Creating SPDY remote executor for request", + "request_method", req.Method, + "request_uri", req.RequestURI, + ) tlsConfig, useImpersonation, err := f.getTLSConfig(sess) if err != nil { @@ -2381,11 +2406,9 @@ func (s *clusterSession) monitorConn(conn net.Conn, err error, hostID string) (n Context: s.connCtx, TeleportUser: s.User.GetName(), ServerID: s.parent.cfg.HostID, - // TODO(tross) update this to use the child logger - // once Forwarder is converted to use a slog.Logger - Logger: slog.Default(), - Emitter: s.parent.cfg.AuthClient, - EmitterContext: s.parent.ctx, + Logger: s.parent.log, + Emitter: s.parent.cfg.AuthClient, + EmitterContext: s.parent.ctx, }) if err != nil { tc.CloseWithCause(err) @@ -2462,7 +2485,7 @@ func (f *Forwarder) newClusterSession(ctx context.Context, authCtx authContext) } func (f *Forwarder) newClusterSessionRemoteCluster(ctx context.Context, authCtx authContext) (*clusterSession, error) { - f.log.Debugf("Forwarding kubernetes session for %v to remote cluster.", authCtx) + f.log.DebugContext(ctx, "Forwarding kubernetes session to remote cluster", "auth_context", logutils.StringerAttr(authCtx)) connCtx, cancel := context.WithCancelCause(ctx) return &clusterSession{ parent: f, @@ -2511,7 +2534,7 @@ func (f *Forwarder) newClusterSessionLocal(ctx context.Context, authCtx authCont return nil, trace.Wrap(err) } connCtx, cancel := context.WithCancelCause(ctx) - f.log.Debugf("Handling kubernetes session for %v using local credentials.", authCtx) + f.log.DebugContext(ctx, "Handling kubernetes session using local credentials", "auth_context", logutils.StringerAttr(authCtx)) return &clusterSession{ parent: f, authContext: authCtx, @@ -2550,8 +2573,7 @@ func (f *Forwarder) makeSessionForwarder(sess *clusterSession) (*reverseproxy.Fo opts := []reverseproxy.Option{ reverseproxy.WithFlushInterval(100 * time.Millisecond), reverseproxy.WithRoundTripper(transport), - // TODO(tross): convert this to use f.log once it has been converted to use slog - reverseproxy.WithLogger(slog.Default()), + reverseproxy.WithLogger(f.log), reverseproxy.WithErrorHandler(f.formatForwardResponseError), } if sess.isLocalKubernetesCluster { diff --git a/lib/kube/proxy/forwarder_test.go b/lib/kube/proxy/forwarder_test.go index ef10408506f5d..860746ab97213 100644 --- a/lib/kube/proxy/forwarder_test.go +++ b/lib/kube/proxy/forwarder_test.go @@ -40,7 +40,6 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" "github.com/julienschmidt/httprouter" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" kubeerrors "k8s.io/apimachinery/pkg/api/errors" @@ -132,7 +131,7 @@ func TestAuthenticate(t *testing.T) { }, } f := &Forwarder{ - log: logrus.NewEntry(logrus.New()), + log: utils.NewSlogLoggerForTests(), cfg: ForwarderConfig{ ClusterName: "local", CachingAuthClient: ap, @@ -1112,7 +1111,7 @@ func newMockForwader(ctx context.Context, t *testing.T) *Forwarder { require.NoError(t, err) return &Forwarder{ - log: logrus.NewEntry(logrus.New()), + log: utils.NewSlogLoggerForTests(), router: httprouter.New(), cfg: ForwarderConfig{ Keygen: testauthority.New(), @@ -1316,7 +1315,7 @@ func (m *mockWatcher) Done() <-chan struct{} { func newTestForwarder(ctx context.Context, cfg ForwarderConfig) *Forwarder { return &Forwarder{ - log: logrus.NewEntry(logrus.New()), + log: utils.NewSlogLoggerForTests(), router: httprouter.New(), cfg: cfg, activeRequests: make(map[string]context.Context), @@ -1676,7 +1675,7 @@ func TestForwarderTLSConfigCAs(t *testing.T) { return x509.NewCertPool(), nil }, }, - log: logrus.NewEntry(logrus.New()), + log: utils.NewSlogLoggerForTests(), ctx: context.Background(), } diff --git a/lib/kube/proxy/kube_creds.go b/lib/kube/proxy/kube_creds.go index 19fd6edb2bd69..fd7e367d5f8cf 100644 --- a/lib/kube/proxy/kube_creds.go +++ b/lib/kube/proxy/kube_creds.go @@ -21,13 +21,13 @@ package proxy import ( "context" "crypto/tls" + "log/slog" "net/http" "sync" "time" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/transport" @@ -151,7 +151,7 @@ type dynamicKubeCreds struct { ctx context.Context renewTicker clockwork.Ticker staticCreds *staticKubeCreds - log logrus.FieldLogger + log *slog.Logger closeC chan struct{} client dynamicCredsClient checker servicecfg.ImpersonationPermissionsChecker @@ -164,7 +164,7 @@ type dynamicKubeCreds struct { // dynamicCredsConfig contains configuration for dynamicKubeCreds. type dynamicCredsConfig struct { kubeCluster types.KubeCluster - log logrus.FieldLogger + log *slog.Logger client dynamicCredsClient checker servicecfg.ImpersonationPermissionsChecker clock clockwork.Clock @@ -224,7 +224,7 @@ func newDynamicKubeCreds(ctx context.Context, cfg dynamicCredsConfig) (*dynamicK return case <-dyn.renewTicker.Chan(): if err := dyn.renewClientset(cfg.kubeCluster); err != nil { - logrus.WithError(err).Warnf("Unable to renew cluster %q credentials.", cfg.kubeCluster.GetName()) + cfg.log.WarnContext(ctx, "Unable to renew cluster credentials", "cluster", cfg.kubeCluster.GetName(), "error", err) } } } diff --git a/lib/kube/proxy/kube_creds_test.go b/lib/kube/proxy/kube_creds_test.go index ef8950691c0a1..b032964021b73 100644 --- a/lib/kube/proxy/kube_creds_test.go +++ b/lib/kube/proxy/kube_creds_test.go @@ -30,19 +30,19 @@ import ( "github.com/aws/aws-sdk-go/service/eks" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" authztypes "k8s.io/client-go/kubernetes/typed/authorization/v1" "k8s.io/client-go/rest" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/api/utils" + apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/cloud" "github.com/gravitational/teleport/lib/cloud/azure" "github.com/gravitational/teleport/lib/cloud/gcp" "github.com/gravitational/teleport/lib/cloud/mocks" "github.com/gravitational/teleport/lib/fixtures" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/utils" ) // Test_DynamicKubeCreds tests the dynamic kube credrentials generator for @@ -54,7 +54,6 @@ func Test_DynamicKubeCreds(t *testing.T) { t.Parallel() var ( fakeClock = clockwork.NewFakeClock() - log = logrus.New() notify = make(chan struct{}, 1) ttl = 14 * time.Minute ) @@ -303,7 +302,7 @@ func Test_DynamicKubeCreds(t *testing.T) { ) error { return nil }, - log: log, + log: utils.NewSlogLoggerForTests(), kubeCluster: tt.args.cluster, client: tt.args.client, initialRenewInterval: ttl / 2, @@ -332,8 +331,8 @@ func Test_DynamicKubeCreds(t *testing.T) { } require.NoError(t, got.close()) - require.Equal(t, tt.wantAssumedRole, utils.Deduplicate(sts.GetAssumedRoleARNs())) - require.Equal(t, tt.wantExternalIds, utils.Deduplicate(sts.GetAssumedRoleExternalIDs())) + require.Equal(t, tt.wantAssumedRole, apiutils.Deduplicate(sts.GetAssumedRoleARNs())) + require.Equal(t, tt.wantExternalIds, apiutils.Deduplicate(sts.GetAssumedRoleExternalIDs())) sts.ResetAssumeRoleHistory() }) } diff --git a/lib/kube/proxy/portforward_spdy.go b/lib/kube/proxy/portforward_spdy.go index 561750239250d..1745536fc44f1 100644 --- a/lib/kube/proxy/portforward_spdy.go +++ b/lib/kube/proxy/portforward_spdy.go @@ -19,6 +19,7 @@ package proxy import ( "context" "fmt" + "log/slog" "net" "net/http" "strconv" @@ -26,7 +27,6 @@ import ( "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/httpstream" spdystream "k8s.io/apimachinery/pkg/util/httpstream/spdy" @@ -91,10 +91,10 @@ func runPortForwardingHTTPStreams(req portForwardRequest) error { defer conn.Close() h := &portForwardProxy{ - Entry: log.WithFields(log.Fields{ - teleport.ComponentKey: teleport.Component(teleport.ComponentProxyKube), - events.RemoteAddr: req.httpRequest.RemoteAddr, - }), + logger: slog.With( + teleport.ComponentKey, teleport.Component(teleport.ComponentProxyKube), + events.RemoteAddr, req.httpRequest.RemoteAddr, + ), portForwardRequest: req, sourceConn: conn, streamChan: streamChan, @@ -104,7 +104,7 @@ func runPortForwardingHTTPStreams(req portForwardRequest) error { } defer h.Close() - h.Debugf("Setting port forwarding streaming connection idle timeout to %s.", req.idleTimeout) + h.logger.DebugContext(req.context, "Setting port forwarding streaming connection idle timeout", "idle_timeout", req.idleTimeout) conn.SetIdleTimeout(req.idleTimeout) h.run() @@ -149,7 +149,7 @@ func httpStreamReceived(ctx context.Context, streams chan httpstream.Stream) fun // portForwardProxy is capable of processing multiple port forward // requests over a single httpstream.Connection. type portForwardProxy struct { - *log.Entry + logger *slog.Logger portForwardRequest sourceConn httpstream.Connection streamChan chan httpstream.Stream @@ -200,7 +200,7 @@ func (h *portForwardProxy) forwardStreamPair(p *httpStreamPair, remotePort int64 go func() { defer wg.Done() if err := utils.ProxyConn(h.context, p.errorStream, targetErrorStream); err != nil { - h.WithError(err).Debugf("Unable to proxy portforward error-stream.") + h.logger.DebugContext(h.context, "Unable to proxy portforward error-stream", "error", err) } }() @@ -222,14 +222,14 @@ func (h *portForwardProxy) forwardStreamPair(p *httpStreamPair, remotePort int64 go func() { defer wg.Done() if err := utils.ProxyConn(h.context, p.dataStream, targetDataStream); err != nil { - h.WithError(err).Debugf("Unable to proxy portforward data-stream.") + h.logger.DebugContext(h.context, "Unable to proxy portforward data-stream", "error", err) } }() - h.Debugf("Streams have been created, Waiting for copy to complete.") + h.logger.DebugContext(h.context, "Streams have been created, Waiting for copy to complete") // wait for the copies to complete before returning. wg.Wait() - h.Debugf("Port forwarding pair completed.") + h.logger.DebugContext(h.context, "Port forwarding pair completed") return nil } @@ -241,11 +241,11 @@ func (h *portForwardProxy) getStreamPair(requestID string) (*httpStreamPair, boo defer h.streamPairsLock.Unlock() if p, ok := h.streamPairs[requestID]; ok { - log.Debugf("Request %s, found existing stream pair", requestID) + h.logger.DebugContext(h.context, "Found existing stream pair for request", "request_id", requestID) return p, false } - h.Debugf("Request %s, creating new stream pair.", requestID) + h.logger.DebugContext(h.context, "Creating new stream pair for request", "request_id", requestID) p := newPortForwardPair(requestID) h.streamPairs[requestID] = p @@ -261,9 +261,9 @@ func (h *portForwardProxy) monitorStreamPair(p *httpStreamPair) { defer timeC.Stop() select { case <-timeC.C: - h.Errorf("Request %s, timed out waiting for streams.", p.requestID) + h.logger.ErrorContext(h.context, "Request timed out waiting for streams", "request_id", p.requestID) case <-p.complete: - h.Debugf("Request %s, successfully received error and data streams.", p.requestID) + h.logger.DebugContext(h.context, "Request successfully received error and data streams", "request_id", p.requestID) } h.removeStreamPair(p.requestID) } @@ -296,23 +296,24 @@ func (h *portForwardProxy) requestID(stream httpstream.Stream) (string, error) { // streams, invoking portForward for each complete stream pair. The loop exits // when the httpstream.Connection is closed. func (h *portForwardProxy) run() { - h.Debugf("Waiting for port forward streams.") + h.logger.DebugContext(h.context, "Waiting for port forward streams") for { select { case <-h.context.Done(): - h.Debugf("Context is closing, returning.") + h.logger.DebugContext(h.context, "Context is closing, returning") return case <-h.sourceConn.CloseChan(): - h.Debugf("Upgraded connection closed.") + h.logger.DebugContext(h.context, "Upgraded connection closed") return case stream := <-h.streamChan: requestID, err := h.requestID(stream) if err != nil { - h.Warningf("Failed to parse request id: %v.", err) + h.logger.WarnContext(h.context, "Failed to parse request id", "error", err) return } + streamType := stream.Headers().Get(StreamType) - h.Debugf("Received new stream %v of type %v.", requestID, streamType) + h.logger.DebugContext(h.context, "Received new stream", "request_id", requestID, "stream_type", streamType) p, created := h.getStreamPair(requestID) if created { @@ -336,13 +337,15 @@ func (h *portForwardProxy) portForward(p *httpStreamPair) { portString := p.dataStream.Headers().Get(PortHeader) port, _ := strconv.ParseInt(portString, 10, 32) - h.Debugf("Forwarding port %v -> %v.", p.requestID, portString) + logger := h.logger.With("request_id", p.requestID, "port", portString) + + logger.DebugContext(h.context, "Forwarding port") if err := h.forwardStreamPair(p, port); err != nil { - h.WithError(err).Debugf("Error forwarding port %v -> %v.", p.requestID, portString) + logger.DebugContext(h.context, "Error forwarding port", "error", err) return } - h.Debugf("Completed forwarding port %v -> %v.", p.requestID, portString) + h.logger.DebugContext(h.context, "Completed forwarding port") } // httpStreamPair represents the error and data streams for a port diff --git a/lib/kube/proxy/portforward_test.go b/lib/kube/proxy/portforward_test.go index b923ca591129e..7dc7a147e22b7 100644 --- a/lib/kube/proxy/portforward_test.go +++ b/lib/kube/proxy/portforward_test.go @@ -31,7 +31,6 @@ import ( "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" kubeerrors "k8s.io/apimachinery/pkg/api/errors" @@ -43,6 +42,7 @@ import ( "k8s.io/client-go/transport/spdy" testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" + "github.com/gravitational/teleport/lib/utils" ) func TestPortForwardKubeService(t *testing.T) { @@ -269,7 +269,6 @@ type portForwarder interface { // connection, it will leak memory. func TestPortForwardProxy_run_connsClosed(t *testing.T) { t.Parallel() - logger := log.NewEntry(&log.Logger{Out: io.Discard}) const ( reqID = "reqID" // portHeaderValue is the value of the port header in the stream. @@ -285,7 +284,7 @@ func TestPortForwardProxy_run_connsClosed(t *testing.T) { context: context.Background(), onPortForward: func(addr string, success bool) {}, }, - Entry: logger, + logger: utils.NewSlogLoggerForTests(), sourceConn: sourceConn, targetConn: targetConn, streamChan: make(chan httpstream.Stream), diff --git a/lib/kube/proxy/portforward_websocket.go b/lib/kube/proxy/portforward_websocket.go index af1cb04ab525a..c2cb4cb6c97a9 100644 --- a/lib/kube/proxy/portforward_websocket.go +++ b/lib/kube/proxy/portforward_websocket.go @@ -23,13 +23,13 @@ import ( "encoding/binary" "fmt" "io" + "log/slog" "net/http" "strings" "sync" gwebsocket "github.com/gorilla/websocket" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/httpstream" spdystream "k8s.io/apimachinery/pkg/util/httpstream/spdy" "k8s.io/apimachinery/pkg/util/httpstream/wsstream" @@ -148,10 +148,10 @@ func runPortForwardingWebSocket(req portForwardRequest) error { podName: req.podName, targetConn: targetConn, onPortForward: req.onPortForward, - FieldLogger: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.Component(teleport.ComponentProxyKube), - events.RemoteAddr: req.httpRequest.RemoteAddr, - }), + logger: slog.With( + teleport.ComponentKey, teleport.Component(teleport.ComponentProxyKube), + events.RemoteAddr, req.httpRequest.RemoteAddr, + ), context: req.context, } // run the portforward request until termination. @@ -213,8 +213,8 @@ type websocketPortforwardHandler struct { podName string targetConn httpstream.Connection onPortForward portForwardCallback - logrus.FieldLogger - context context.Context + logger *slog.Logger + context context.Context } // run invokes the targetConn SPDY connection and copies the client data into @@ -237,10 +237,12 @@ func (h *websocketPortforwardHandler) run() { // portForward copies the client and upstream streams. func (h *websocketPortforwardHandler) portForward(p *websocketChannelPair) { - h.Debugf("Forwarding port %v -> %v.", p.requestID, p.port) + logger := h.logger.With("request_id", p.requestID, "port", p.port) + + logger.DebugContext(h.context, "Forwarding port") h.forwardStreamPair(p) - h.Debugf("Completed forwarding port %v -> %v.", p.requestID, p.port) + logger.DebugContext(h.context, "Completed forwarding port") } func (h *websocketPortforwardHandler) forwardStreamPair(p *websocketChannelPair) { @@ -269,7 +271,7 @@ func (h *websocketPortforwardHandler) forwardStreamPair(p *websocketChannelPair) go func() { defer wg.Done() if err := utils.ProxyConn(h.context, p.errorStream, targetErrorStream); err != nil { - h.WithError(err).Debugf("Unable to proxy portforward error-stream.") + h.logger.DebugContext(h.context, "Unable to proxy portforward error-stream", "error", err) } }() @@ -292,15 +294,15 @@ func (h *websocketPortforwardHandler) forwardStreamPair(p *websocketChannelPair) go func() { defer wg.Done() if err := utils.ProxyConn(h.context, p.dataStream, targetDataStream); err != nil { - h.WithError(err).Debugf("Unable to proxy portforward data-stream.") + h.logger.DebugContext(h.context, "Unable to proxy portforward data-stream", "error", err) } }() - h.Debugf("Streams have been created, Waiting for copy to complete.") + h.logger.DebugContext(h.context, "Streams have been created, Waiting for copy to complete") // Wait until every goroutine exits. wg.Wait() - h.Debugf("Port forwarding pair completed.") + h.logger.DebugContext(h.context, "Port forwarding pair completed") } // runPortForwardingTunneledHTTPStreams handles a port-forwarding request that uses SPDY protocol @@ -341,10 +343,10 @@ func runPortForwardingTunneledHTTPStreams(req portForwardRequest) error { defer conn.Close() h := &portForwardProxy{ - Entry: logrus.WithFields(logrus.Fields{ - teleport.ComponentKey: teleport.Component(teleport.ComponentProxyKube), - events.RemoteAddr: req.httpRequest.RemoteAddr, - }), + logger: slog.With( + teleport.ComponentKey, teleport.Component(teleport.ComponentProxyKube), + events.RemoteAddr, req.httpRequest.RemoteAddr, + ), portForwardRequest: req, sourceConn: spdyConn, streamChan: streamChan, @@ -354,7 +356,7 @@ func runPortForwardingTunneledHTTPStreams(req portForwardRequest) error { } defer h.Close() - h.Debugf("Setting port forwarding streaming connection idle timeout to %s.", req.idleTimeout) + h.logger.DebugContext(context.Background(), "Setting port forwarding streaming connection idle timeout to", "idle_timeout", req.idleTimeout) spdyConn.SetIdleTimeout(req.idleTimeout) h.run() diff --git a/lib/kube/proxy/remotecommand.go b/lib/kube/proxy/remotecommand.go index 09a9c868b43ca..2cd03c870d70b 100644 --- a/lib/kube/proxy/remotecommand.go +++ b/lib/kube/proxy/remotecommand.go @@ -22,12 +22,12 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "strings" "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -75,7 +75,7 @@ func (req remoteCommandRequest) eventPodMeta(ctx context.Context, creds kubeCred // here shouldn't prevent a session from starting. pod, err := creds.getKubeClient().CoreV1().Pods(req.podNamespace).Get(ctx, req.podName, metav1.GetOptions{}) if err != nil { - log.WithError(err).Debugf("Failed fetching pod from kubernetes API; skipping additional metadata on the audit event") + slog.DebugContext(ctx, "Failed fetching pod from kubernetes API; skipping additional metadata on the audit event", "error", err) return meta } meta.KubernetesNodeName = pod.Spec.NodeName @@ -121,7 +121,7 @@ func upgradeRequestToRemoteCommandProxy(req remoteCommandRequest, exec func(*rem err = nil } if err := proxy.sendStatus(err); err != nil { - log.Warningf("Failed to send status: %v", err) + slog.WarnContext(req.context, "Failed to send status", "error", err) } // return rsp=nil, err=nil to indicate that the request has been handled // by the hijacked connection. If we return an error, the request will be @@ -162,10 +162,10 @@ func createSPDYStreams(req remoteCommandRequest) (*remoteCommandProxy, error) { var handler protocolHandler switch protocol { case "": - log.Warningf("Client did not request protocol negotiation.") + slog.WarnContext(ctx, "Client did not request protocol negotiation") fallthrough case StreamProtocolV4Name: - log.Infof("Negotiated protocol %v.", protocol) + slog.InfoContext(ctx, "Negotiated protocol", "protocol", protocol) handler = &v4ProtocolHandler{} default: err = trace.BadParameter("protocol %v is not supported. upgrade the client", protocol) @@ -357,7 +357,7 @@ func (t *termQueue) handleResizeEvents(stream io.Reader) { size := remotecommand.TerminalSize{} if err := decoder.Decode(&size); err != nil { if !errors.Is(err, io.EOF) { - log.Warningf("Failed to decode resize event: %v", err) + slog.WarnContext(t.done, "Failed to decode resize event", "error", err) } t.cancel() return @@ -412,7 +412,7 @@ WaitForStreams: remoteProxy.resizeStream = stream go waitStreamReply(stopCtx, stream.replySent, replyChan) default: - log.Warningf("Ignoring unexpected stream type: %q", streamType) + slog.WarnContext(stopCtx, "Ignoring unexpected stream type", "stream_type", streamType) } case <-replyChan: receivedStreams++ diff --git a/lib/kube/proxy/resource_deletecollection.go b/lib/kube/proxy/resource_deletecollection.go index f73c5f2043426..0e9fc22540c02 100644 --- a/lib/kube/proxy/resource_deletecollection.go +++ b/lib/kube/proxy/resource_deletecollection.go @@ -21,10 +21,10 @@ package proxy import ( "context" "io" + "log/slog" "net/http" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" oteltrace "go.opentelemetry.io/otel/trace" appsv1 "k8s.io/api/apps/v1" @@ -566,7 +566,7 @@ func (f *Forwarder) handleDeleteCustomResourceCollection(w http.ResponseWriter, type deleteResourcesCommonParams struct { ctx context.Context - log logrus.FieldLogger + log *slog.Logger authCtx *authContext header http.Header kubeDetails *kubeDetails diff --git a/lib/kube/proxy/resource_filters.go b/lib/kube/proxy/resource_filters.go index 735aab9648f9d..16d8a6076c2d4 100644 --- a/lib/kube/proxy/resource_filters.go +++ b/lib/kube/proxy/resource_filters.go @@ -20,12 +20,13 @@ package proxy import ( "bytes" + "context" "io" + "log/slog" "mime" "net/http" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" certificatesv1 "k8s.io/api/certificates/v1" @@ -50,7 +51,7 @@ import ( // - deniedResources: excluded if (namespace,name) matches an entry even if it matches // the allowedResources's list. // - allowedResources: excluded if (namespace,name) not match a single entry. -func newResourceFilterer(kind, verb string, codecs *serializer.CodecFactory, allowedResources, deniedResources []types.KubernetesResource, log logrus.FieldLogger) responsewriters.FilterWrapper { +func newResourceFilterer(kind, verb string, codecs *serializer.CodecFactory, allowedResources, deniedResources []types.KubernetesResource, log *slog.Logger) responsewriters.FilterWrapper { // If the list of allowed resources contains a wildcard and no deniedResources, then we // don't need to filter anything. if containsWildcard(allowedResources) && len(deniedResources) == 0 { @@ -113,7 +114,7 @@ type resourceFilterer struct { // deniedResources is the list of kubernetes resources the user must not access. deniedResources []types.KubernetesResource // log is the logger. - log logrus.FieldLogger + log *slog.Logger // kind is the type of the resource. kind string // verb is the kube API verb based on HTTP verb. @@ -176,6 +177,8 @@ func pointerArrayToArray[T any](arr []*T) []T { // with the object. // The isListObj boolean returned indicates if the object is a list of resources. func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList bool, err error) { + ctx := context.Background() + switch o := obj.(type) { case *metav1.Status: // Status object is returned when the Kubernetes API returns an error and @@ -184,7 +187,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Pod: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -198,7 +201,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Secret: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -212,7 +215,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.ConfigMap: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -226,7 +229,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Namespace: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -240,7 +243,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Service: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -254,7 +257,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Endpoints: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -268,7 +271,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.ServiceAccount: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -282,7 +285,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.Node: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -296,7 +299,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.PersistentVolume: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -310,7 +313,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *corev1.PersistentVolumeClaim: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -325,7 +328,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *appsv1.Deployment: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -340,7 +343,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *appsv1.ReplicaSet: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -354,7 +357,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *appsv1.StatefulSet: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -369,7 +372,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *appsv1.DaemonSet: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -383,7 +386,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *authv1.ClusterRole: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -397,7 +400,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *authv1.Role: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -412,7 +415,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *authv1.ClusterRoleBinding: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -427,7 +430,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *authv1.RoleBinding: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -442,7 +445,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *batchv1.CronJob: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -457,7 +460,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *batchv1.Job: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -472,7 +475,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *certificatesv1.CertificateSigningRequest: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -486,7 +489,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *networkingv1.Ingress: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -500,7 +503,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *extensionsv1beta1.Ingress: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -515,7 +518,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *extensionsv1beta1.DaemonSet: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -530,7 +533,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *extensionsv1beta1.Deployment: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -545,7 +548,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList case *extensionsv1beta1.ReplicaSet: result, err := filterResource(d.kind, d.verb, o, d.allowedResources, d.deniedResources) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -569,7 +572,7 @@ func (d *resourceFilterer) FilterObj(obj runtime.Object) (isAllowed bool, isList d.allowedResources, d.deniedResources, ) if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expressions within kubernetes_resources.") + d.log.WarnContext(ctx, "Unable to compile regex expressions within kubernetes_resources", "error", err) } // if err is not nil or result is false, we should not include it. return result, false, nil @@ -632,13 +635,13 @@ func (d *resourceFilterer) encode(obj runtime.Object, w io.Writer) error { } // filterResourceList excludes resources the user should not have access to. -func filterResourceList[T kubeObjectInterface](kind, verb string, originalList []T, allowed, denied []types.KubernetesResource, log logrus.FieldLogger) []T { +func filterResourceList[T kubeObjectInterface](kind, verb string, originalList []T, allowed, denied []types.KubernetesResource, log *slog.Logger) []T { filteredList := make([]T, 0, len(originalList)) for _, resource := range originalList { if result, err := filterResource(kind, verb, resource, allowed, denied); err == nil && result { filteredList = append(filteredList, resource) } else if err != nil { - log.WithError(err).Warnf("Unable to compile regex expressions within kubernetes_resources.") + slog.WarnContext(context.Background(), "Unable to compile regex expressions within kubernetes_resources", "error", err) } } return filteredList @@ -686,7 +689,7 @@ func (d *resourceFilterer) filterMetaV1Table(table *metav1.Table, allowedResourc if result, err := matchKubernetesResource(resource, allowedResources, deniedResources); err == nil && result { resources = append(resources, *row) } else if err != nil { - d.log.WithError(err).Warn("Unable to compile regex expression.") + d.log.WarnContext(context.Background(), "Unable to compile regex expression", "error", err) } } table.Rows = resources @@ -799,7 +802,7 @@ func filterBuffer(filterWrapper responsewriters.FilterWrapper, src *responsewrit // filterUnstructuredList filters the unstructured list object to exclude resources // that the user must not have access to. // The filtered list is re-assigned to `obj.Object["items"]`. -func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed, denied []types.KubernetesResource, log logrus.FieldLogger) (hasElems bool) { +func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed, denied []types.KubernetesResource, log *slog.Logger) (hasElems bool) { const ( itemsKey = "items" ) @@ -809,7 +812,7 @@ func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed objList, err := obj.ToList() if err != nil { // This should never happen, but if it does, we should log it. - log.WithError(err).Warnf("Unable to convert unstructured object to list.") + slog.WarnContext(context.Background(), "Unable to convert unstructured object to list", "error", err) return false } @@ -822,7 +825,7 @@ func filterUnstructuredList(verb string, obj *unstructured.Unstructured, allowed ); result { filteredList = append(filteredList, resource.Object) } else if err != nil { - log.WithError(err).Warnf("Unable to compile regex expressions within kubernetes_resources.") + slog.WarnContext(context.Background(), "Unable to compile regex expressions within kubernetes_resources", "error", err) } } obj.Object[itemsKey] = filteredList diff --git a/lib/kube/proxy/resource_filters_test.go b/lib/kube/proxy/resource_filters_test.go index 3d49563712b81..aecfae1f3e154 100644 --- a/lib/kube/proxy/resource_filters_test.go +++ b/lib/kube/proxy/resource_filters_test.go @@ -30,7 +30,6 @@ import ( "text/template" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -42,10 +41,10 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/kube/proxy/responsewriters" + "github.com/gravitational/teleport/lib/utils" ) func Test_filterBuffer(t *testing.T) { - log := logrus.New() type objectAndAPI struct { obj string api string @@ -175,7 +174,7 @@ func Test_filterBuffer(t *testing.T) { buf, decompress := newMemoryResponseWriter(t, data.Bytes(), tt.args.contentEncoding) - err = filterBuffer(newResourceFilterer(r, types.KubeVerbList, &globalKubeCodecs, allowedResources, nil, log), buf) + err = filterBuffer(newResourceFilterer(r, types.KubeVerbList, &globalKubeCodecs, allowedResources, nil, utils.NewSlogLoggerForTests()), buf) require.NoError(t, err) // Decompress the buffer to compare the result. diff --git a/lib/kube/proxy/resource_list.go b/lib/kube/proxy/resource_list.go index d0401a600fe5d..f892c91bb8eb5 100644 --- a/lib/kube/proxy/resource_list.go +++ b/lib/kube/proxy/resource_list.go @@ -237,7 +237,7 @@ func (f *Forwarder) sendEphemeralContainerEvents(done <-chan struct{}, req *http podName, ) if err != nil { - f.log.WithError(err).Warn("error getting user ephemeral containers") + f.log.WarnContext(req.Context(), "error getting user ephemeral containers", "error", err) return } @@ -247,7 +247,7 @@ func (f *Forwarder) sendEphemeralContainerEvents(done <-chan struct{}, req *http } evt, err := f.getPatchedPodEvent(req.Context(), sess, wc) if err != nil { - f.log.WithError(err).Warn("error pushing pod event") + f.log.WarnContext(req.Context(), "error pushing pod event", "error", err) continue } sentDebugContainers[wc.Spec.ContainerName] = struct{}{} diff --git a/lib/kube/proxy/resource_rbac_test.go b/lib/kube/proxy/resource_rbac_test.go index 9ee1f0b931824..faebea646681c 100644 --- a/lib/kube/proxy/resource_rbac_test.go +++ b/lib/kube/proxy/resource_rbac_test.go @@ -32,7 +32,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/uuid" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -51,6 +50,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/kube/proxy/responsewriters" testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" + "github.com/gravitational/teleport/lib/utils" ) func TestListPodRBAC(t *testing.T) { @@ -518,8 +518,6 @@ func TestListPodRBAC(t *testing.T) { func TestWatcherResponseWriter(t *testing.T) { defaultNamespace := "default" devNamespace := "dev" - log := logrus.New() - log.SetLevel(logrus.DebugLevel) t.Parallel() statusErr := &metav1.Status{ TypeMeta: metav1.TypeMeta{ @@ -633,7 +631,7 @@ func TestWatcherResponseWriter(t *testing.T) { t.Run(tt.name, func(t *testing.T) { userReader, userWriter := io.Pipe() negotiator := newClientNegotiator(&globalKubeCodecs) - filterWrapper := newResourceFilterer(types.KindKubePod, types.KubeVerbWatch, &globalKubeCodecs, tt.args.allowed, tt.args.denied, log) + filterWrapper := newResourceFilterer(types.KindKubePod, types.KubeVerbWatch, &globalKubeCodecs, tt.args.allowed, tt.args.denied, utils.NewSlogLoggerForTests()) // watcher parses the data written into itself and if the user is allowed to // receive the update, it writes the event into target. watcher, err := responsewriters.NewWatcherResponseWriter(newFakeResponseWriter(userWriter) /*target*/, negotiator, filterWrapper) diff --git a/lib/kube/proxy/response_rewriter.go b/lib/kube/proxy/response_rewriter.go index 7fccfe0eb5132..1060762c16b87 100644 --- a/lib/kube/proxy/response_rewriter.go +++ b/lib/kube/proxy/response_rewriter.go @@ -87,7 +87,7 @@ func (f *Forwarder) rewriteResponseForbidden(s *clusterSession) func(r *http.Res newClientNegotiator(&globalKubeCodecs), ) if err != nil { - f.log.WithError(err).Error("Failed to create encoder") + f.log.ErrorContext(r.Request.Context(), "Failed to create encoder", "error", err) return nil } @@ -107,7 +107,7 @@ func (f *Forwarder) rewriteResponseForbidden(s *clusterSession) func(r *http.Res // Encode the new response. if err = encoder.Encode(status, b); err != nil { - f.log.WithError(err).Error("Failed to encode response") + f.log.ErrorContext(r.Request.Context(), "Failed to encode response", "error", err) return trace.Wrap(err) } diff --git a/lib/kube/proxy/roundtrip.go b/lib/kube/proxy/roundtrip.go index 3630f3e898dd7..7fb1bf9c8517a 100644 --- a/lib/kube/proxy/roundtrip.go +++ b/lib/kube/proxy/roundtrip.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net" "net/http" "net/url" @@ -31,7 +32,6 @@ import ( "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -90,7 +90,7 @@ type roundTripperConfig struct { // headers instead of relying on the certificate to transport it. useIdentityForwarding bool // log specifies the logger. - log log.FieldLogger + log *slog.Logger proxier func(*http.Request) (*url.URL, error) } diff --git a/lib/kube/proxy/scheme.go b/lib/kube/proxy/scheme.go index 85d80739ada50..0d88a0fdaef9c 100644 --- a/lib/kube/proxy/scheme.go +++ b/lib/kube/proxy/scheme.go @@ -19,11 +19,12 @@ package proxy import ( + "context" "errors" + "log/slog" "strings" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/exp/maps" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -113,7 +114,7 @@ type gvkSupportedResources map[gvkSupportedResourcesKey]*schema.GroupVersionKind // This schema includes all well-known Kubernetes types and all namespaced // custom resources. // It also returns a map of resources that we support RBAC restrictions for. -func newClusterSchemaBuilder(log logrus.FieldLogger, client kubernetes.Interface) (*serializer.CodecFactory, rbacSupportedResources, gvkSupportedResources, error) { +func newClusterSchemaBuilder(log *slog.Logger, client kubernetes.Interface) (*serializer.CodecFactory, rbacSupportedResources, gvkSupportedResources, error) { kubeScheme := runtime.NewScheme() kubeCodecs := serializer.NewCodecFactory(kubeScheme) supportedResources := maps.Clone(defaultRBACResources) @@ -135,7 +136,10 @@ func newClusterSchemaBuilder(log logrus.FieldLogger, client kubernetes.Interface // reachable. // In this case, we still want to register the other resources that are // available in the cluster. - log.WithError(err).Debugf("Failed to discover some API groups: %v", maps.Keys(discoveryErr.Groups)) + log.DebugContext(context.Background(), "Failed to discover some API groups", + "groups", maps.Keys(discoveryErr.Groups), + "error", err, + ) case err != nil: return nil, nil, nil, trace.Wrap(err) } diff --git a/lib/kube/proxy/scheme_test.go b/lib/kube/proxy/scheme_test.go index d13dbbc94df8f..ae7075db251f4 100644 --- a/lib/kube/proxy/scheme_test.go +++ b/lib/kube/proxy/scheme_test.go @@ -21,17 +21,18 @@ package proxy import ( "testing" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes" + + "github.com/gravitational/teleport/lib/utils" ) // TestNewClusterSchemaBuilder tests that newClusterSchemaBuilder doesn't panic // when it's given types already registered in the global scheme. func Test_newClusterSchemaBuilder(t *testing.T) { - _, _, _, err := newClusterSchemaBuilder(logrus.StandardLogger(), &clientSet{}) + _, _, _, err := newClusterSchemaBuilder(utils.NewSlogLoggerForTests(), &clientSet{}) require.NoError(t, err) } diff --git a/lib/kube/proxy/self_subject_reviews.go b/lib/kube/proxy/self_subject_reviews.go index 2130cfdaed034..25fb264a0db38 100644 --- a/lib/kube/proxy/self_subject_reviews.go +++ b/lib/kube/proxy/self_subject_reviews.go @@ -63,7 +63,7 @@ func (f *Forwarder) selfSubjectAccessReviews(authCtx *authContext, w http.Respon if err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to create cluster session: %v.", err) + f.log.ErrorContext(req.Context(), "Failed to create cluster session", "error", err) return nil, trace.Wrap(err) } // sess.Close cancels the connection monitor context to release it sooner. @@ -91,7 +91,7 @@ func (f *Forwarder) selfSubjectAccessReviews(authCtx *authContext, w http.Respon if err := f.setupForwardingHeaders(sess, req, true /* withImpersonationHeaders */); err != nil { // This error goes to kubernetes client and is not visible in the logs // of the teleport server if not logged here. - f.log.Errorf("Failed to set up forwarding headers: %v.", err) + f.log.ErrorContext(req.Context(), "Failed to set up forwarding headers", "error", err) return nil, trace.Wrap(err) } rw := httplib.NewResponseStatusRecorder(w) diff --git a/lib/kube/proxy/server.go b/lib/kube/proxy/server.go index 6f05f2a13a22f..6ac466746b51f 100644 --- a/lib/kube/proxy/server.go +++ b/lib/kube/proxy/server.go @@ -29,7 +29,6 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "golang.org/x/net/http2" "github.com/gravitational/teleport" @@ -68,7 +67,7 @@ type TLSServerConfig struct { // ConnectedProxyGetter gets the proxies teleport is connected to. ConnectedProxyGetter *reversetunnel.ConnectedProxyGetter // Log is the logger. - Log logrus.FieldLogger + Log *slog.Logger // Selectors is a list of resource monitor selectors. ResourceMatchers []services.ResourceMatcher // OnReconcile is called after each kube_cluster resource reconciliation. @@ -134,7 +133,7 @@ func (c *TLSServerConfig) CheckAndSetDefaults() error { } if c.Log == nil { - c.Log = logrus.New() + c.Log = slog.Default() } if c.CloudClients == nil { cloudClients, err := cloud.NewClients() @@ -180,7 +179,7 @@ type TLSServer struct { monitoredKubeClusters monitoredKubeClusters // reconcileCh triggers reconciliation of proxied kube_clusters. reconcileCh chan struct{} - log *logrus.Entry + log *slog.Logger } // NewTLSServer returns new unstarted TLS server @@ -188,9 +187,7 @@ func NewTLSServer(cfg TLSServerConfig) (*TLSServer, error) { if err := cfg.CheckAndSetDefaults(); err != nil { return nil, trace.Wrap(err) } - log := cfg.Log.WithFields(logrus.Fields{ - teleport.ComponentKey: cfg.Component, - }) + log := cfg.Log.With(teleport.ComponentKey, cfg.Component) // limiter limits requests by frequency and amount of simultaneous // connections per client limiter, err := limiter.NewLimiter(cfg.LimiterConfig) @@ -422,8 +419,7 @@ func (t *TLSServer) close(ctx context.Context) error { // and server's GetConfigForClient reloads the list of trusted // local and remote certificate authorities func (t *TLSServer) GetConfigForClient(info *tls.ClientHelloInfo) (*tls.Config, error) { - // TODO(tross): remove slog.Default once the TLSServer is updated to use a slog.Logger - return authclient.WithClusterCAs(t.TLS, t.AccessPoint, t.ClusterName, slog.Default())(info) + return authclient.WithClusterCAs(t.TLS, t.AccessPoint, t.ClusterName, t.log)(info) } // GetServerInfo returns a services.Server object for heartbeats (aka @@ -523,7 +519,7 @@ func (t *TLSServer) startHeartbeat(name string) error { func (t *TLSServer) getRotationState() types.Rotation { rotation, err := t.TLSServerConfig.GetRotation(types.RoleKube) if err != nil && !trace.IsNotFound(err) { - t.log.WithError(err).Warn("Failed to get rotation state.") + t.log.WarnContext(t.closeContext, "Failed to get rotation state", "error", err) } if rotation != nil { return *rotation @@ -539,14 +535,14 @@ func (t *TLSServer) startStaticClustersHeartbeat() error { // proxy_service will pretend to also be kube_server. if t.KubeServiceType == KubeService || t.KubeServiceType == LegacyProxyService { - t.log.Debugf("Starting kubernetes_service heartbeats for %q", t.Component) + t.log.DebugContext(t.closeContext, "Starting kubernetes_service heartbeats") for _, cluster := range t.fwd.kubeClusters() { if err := t.startHeartbeat(cluster.GetName()); err != nil { return trace.Wrap(err) } } } else { - t.log.Debug("No local kube credentials on proxy, will not start kubernetes_service heartbeats") + t.log.DebugContext(t.closeContext, "No local kube credentials on proxy, will not start kubernetes_service heartbeats") } return nil diff --git a/lib/kube/proxy/server_test.go b/lib/kube/proxy/server_test.go index 091f33599c96f..a5a28823080ed 100644 --- a/lib/kube/proxy/server_test.go +++ b/lib/kube/proxy/server_test.go @@ -35,7 +35,6 @@ import ( "time" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "github.com/gravitational/teleport/api/client/proto" @@ -45,6 +44,7 @@ import ( testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/tlsca" + "github.com/gravitational/teleport/lib/utils" ) func TestServeConfigureError(t *testing.T) { @@ -111,10 +111,9 @@ func TestMTLSClientCAs(t *testing.T) { } hostCert := genCert(t, "localhost", "localhost", "127.0.0.1", "::1") userCert := genCert(t, "user") - log := logrus.New() srv := &TLSServer{ TLSServerConfig: TLSServerConfig{ - Log: log, + Log: utils.NewSlogLoggerForTests(), ForwarderConfig: ForwarderConfig{ ClusterName: mainClusterName, }, @@ -125,7 +124,7 @@ func TestMTLSClientCAs(t *testing.T) { }, GetRotation: func(role types.SystemRole) (*types.Rotation, error) { return &types.Rotation{}, nil }, }, - log: logrus.NewEntry(log), + log: utils.NewSlogLoggerForTests(), } lis, err := net.Listen("tcp", "localhost:0") @@ -207,7 +206,7 @@ func TestGetServerInfo(t *testing.T) { srv := &TLSServer{ TLSServerConfig: TLSServerConfig{ - Log: logrus.New(), + Log: utils.NewSlogLoggerForTests(), ForwarderConfig: ForwarderConfig{ Clock: clockwork.NewFakeClock(), ClusterName: "kube-cluster", diff --git a/lib/kube/proxy/sess.go b/lib/kube/proxy/sess.go index bbf2f308a1a25..f017b59dbd851 100644 --- a/lib/kube/proxy/sess.go +++ b/lib/kube/proxy/sess.go @@ -22,6 +22,7 @@ import ( "context" "fmt" "io" + "log/slog" "net/http" "path" "reflect" @@ -33,7 +34,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/julienschmidt/httprouter" - log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" @@ -55,6 +55,7 @@ import ( tsession "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) const sessionRecorderID = "session-recorder" @@ -378,7 +379,7 @@ type session struct { // This is used for audit trails. partiesHistorical map[uuid.UUID]*party - log *log.Entry + log *slog.Logger io *srv.TermManager @@ -440,8 +441,8 @@ type session struct { // newSession creates a new session in pending mode. func newSession(ctx authContext, forwarder *Forwarder, req *http.Request, params httprouter.Params, initiator *party, sess *clusterSession) (*session, error) { id := uuid.New() - log := forwarder.log.WithField("session", id.String()) - log.Debug("Creating session") + log := forwarder.log.With("session", id.String()) + log.DebugContext(req.Context(), "Creating session") var policySets []*types.SessionTrackerPolicySet roles := ctx.Checker.Roles() @@ -502,7 +503,7 @@ func newSession(ctx authContext, forwarder *Forwarder, req *http.Request, params if _, open := <-s.io.TerminateNotifier(); open { err := s.Close() if err != nil { - s.log.Errorf("Failed to close session: %v.", err) + s.log.ErrorContext(req.Context(), "Failed to close session", "error", err) } } }() @@ -518,24 +519,33 @@ func newSession(ctx authContext, forwarder *Forwarder, req *http.Request, params // It is used to properly handle client disconnections. func (s *session) disconnectPartyOnErr(idString string, err error) { if idString == sessionRecorderID { - s.log.Error("Failed to write to session recorder, closing session.") + s.log.ErrorContext(s.sess.connCtx, "Failed to write to session recorder, closing session") s.Close() return } id, uuidParseErr := uuid.Parse(idString) if uuidParseErr != nil { - s.log.WithError(uuidParseErr).Errorf("Unable to decode %q into a UUID.", idString) + s.log.ErrorContext(s.sess.connCtx, "Unable to decode party id", + "party_id", idString, + "error", uuidParseErr, + ) return } wasActive, leaveErr := s.leave(id) if leaveErr != nil { - s.log.WithError(leaveErr).Errorf("Failed to disconnect party %v from the session.", idString) + s.log.ErrorContext(s.sess.connCtx, "Failed to disconnect party from the session", + "party_id", idString, + "error", leaveErr, + ) } if wasActive { // log the error only if it was the reason for the user disconnection. - s.log.Errorf("Encountered error: %v with party %v. Disconnecting them from the session.", err, idString) + s.log.ErrorContext(s.sess.connCtx, "Encountered error with party, disconnecting them from the session", + "error", err, + "party_id", idString, + ) } } @@ -551,11 +561,14 @@ func (s *session) checkPresence() error { } if participant.Mode == string(types.SessionModeratorMode) && time.Now().UTC().After(participant.LastActive.Add(PresenceMaxDifference)) { - s.log.Debugf("Participant %v is not active, kicking.", participant.ID) + s.log.DebugContext(s.sess.connCtx, "Participant is not active, kicking", "participant_id", participant.ID) id, _ := uuid.Parse(participant.ID) _, err := s.unlockedLeave(id) if err != nil { - s.log.WithError(err).Warnf("Failed to kick participant %v for inactivity.", participant.ID) + s.log.WarnContext(s.sess.connCtx, "Failed to kick participant for inactivity", + "participant_id", participant.ID, + "error", err, + ) } } } @@ -569,11 +582,14 @@ func (s *session) launch(ephemeralContainerStatus *corev1.ContainerStatus) (retu defer func() { err := s.Close() if err != nil { - s.log.WithError(err).Errorf("Failed to close session: %v", s.id) + s.log.ErrorContext(s.req.Context(), "Failed to close session", + "session_id", s.id, + "error", err, + ) } }() - s.log.Debugf("Launching session: %v", s.id) + s.log.DebugContext(s.req.Context(), "Launching session", "session_id", s.id) q := s.req.URL.Query() namespace := s.params.ByName("podNamespace") @@ -603,7 +619,7 @@ func (s *session) launch(ephemeralContainerStatus *corev1.ContainerStatus) (retu if returnErr != nil { s.setTerminationErr(returnErr) s.reportErrorToSessionRecorder(returnErr) - s.log.WithError(returnErr).Warning("Executor failed while streaming.") + s.log.WarnContext(s.req.Context(), "Executor failed while streaming", "error", returnErr) } // call onFinished to emit the session.end and exec events. // onFinished is never nil. @@ -640,13 +656,13 @@ func (s *session) launch(ephemeralContainerStatus *corev1.ContainerStatus) (retu }) if err == nil { if err := s.recorder.RecordEvent(s.forwarder.ctx, sessionStartEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to record session start event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to record session start event", "error", err) } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, sessionStartEvent.GetAuditEvent()); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit session start event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit session start event", "error", err) } } else { - s.forwarder.log.WithError(err).Warn("Failed to set up session start event - event will not be recorded") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to set up session start event - event will not be recorded", "error", err) } s.weakEventsWaiter.Add(1) @@ -660,21 +676,21 @@ func (s *session) launch(ephemeralContainerStatus *corev1.ContainerStatus) (retu s.BroadcastMessage("Session expired, closing...") err := s.Close() if err != nil { - s.log.WithError(err).Error("Failed to close session") + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } case <-s.closeC: } }() if err = s.tracker.UpdateState(s.forwarder.ctx, types.SessionState_SessionStateRunning); err != nil { - s.log.WithError(err).Warn("Failed to set tracker state to running") + s.log.WarnContext(s.forwarder.ctx, "Failed to set tracker state to running", "error", err) } var executor remotecommand.Executor executor, err = s.forwarder.getExecutor(s.sess, s.req) if err != nil { - s.log.WithError(err).Warning("Failed creating executor.") + s.log.WarnContext(s.forwarder.ctx, "Failed creating executor", "error", err) return trace.Wrap(err) } @@ -759,7 +775,10 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta } err := p.Client.resize(termSize.size) if err != nil { - s.log.WithError(err).Errorf("Failed to resize client: %v", id.String()) + s.log.ErrorContext(s.forwarder.ctx, "Failed to resize participant", + "party_id", id.String(), + "error", err, + ) } } @@ -789,10 +808,10 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta // Report the updated window size to the event log (this is so the sessions // can be replayed correctly). if err := s.recorder.RecordEvent(s.forwarder.ctx, resizeEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit terminal resize event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit terminal resize event", "error", err) } } else { - s.forwarder.log.WithError(err).Warn("Failed to set up terminal resize event - event will not be recorded") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to set up terminal resize event - event will not be recorded", "error", err) } } } else { @@ -844,7 +863,7 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, execEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit exec event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit exec event", "error", err) } sessionDataEvent := &apievents.SessionData{ @@ -864,7 +883,7 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, sessionDataEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit session data event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit session data event", "error", err) } sessionEndEvent, err := s.recorder.PrepareSessionEvent(&apievents.SessionEnd{ @@ -888,13 +907,13 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta }) if err == nil { if err := s.recorder.RecordEvent(s.forwarder.ctx, sessionEndEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to record session end event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to record session end event", "error", err) } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, sessionEndEvent.GetAuditEvent()); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit session end event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit session end event", "error", err) } } else { - s.forwarder.log.WithError(err).Warn("Failed to set up session end event - event will not be recorded") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to set up session end event - event will not be recorded", "error", err) } } @@ -934,9 +953,9 @@ func (s *session) lockedSetupLaunch(request *remoteCommandRequest, eventPodMeta case <-ticker.C: err := s.checkPresence() if err != nil { - s.log.WithError(err).Error("Failed to check presence, closing session as a security measure") + s.log.ErrorContext(s.forwarder.ctx, "Failed to check presence, closing session as a security measure", "error", err) if err := s.Close(); err != nil { - s.log.WithError(err).Error("Failed to close session") + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } return } @@ -969,7 +988,7 @@ func (s *session) join(p *party, emitJoinEvent bool) error { return trace.AccessDenied("The requested session is not active") } - s.log.Debugf("Tracking participant: %s", p.ID) + s.log.DebugContext(s.forwarder.ctx, "Tracking participant", "participant_id", p.ID) participant := &types.Participant{ ID: p.ID.String(), User: p.Ctx.User.GetName(), @@ -989,7 +1008,7 @@ func (s *session) join(p *party, emitJoinEvent bool) error { recentWrites := s.io.GetRecentHistory() if _, err := p.Client.stdoutStream().Write(recentWrites); err != nil { - s.log.Warnf("Failed to write history to client: %v.", err) + s.log.WarnContext(s.forwarder.ctx, "Failed to write history to participant", "error", err) } s.BroadcastMessage("User %v joined the session with participant mode: %v.", p.Ctx.User.GetName(), p.Mode) @@ -1009,7 +1028,10 @@ func (s *session) join(p *party, emitJoinEvent bool) error { // other parties' terminals and no discrepancies are present. if lastQueueSize := s.terminalSizeQueue.getLastSize(); lastQueueSize != nil { if err := p.Client.resize(lastQueueSize); err != nil { - s.log.WithError(err).Errorf("Failed to resize client: %v", stringID) + s.log.ErrorContext(s.forwarder.ctx, "Failed to resize participant", + "participant_id", stringID, + "error", err, + ) } } @@ -1022,7 +1044,10 @@ func (s *session) join(p *party, emitJoinEvent bool) error { if p.Ctx.User.GetName() != s.ctx.User.GetName() { err := srv.MsgParticipantCtrls(p.Client.stdoutStream(), p.Mode) if err != nil { - s.log.Errorf("Could not send intro message to participant: %v", err) + s.log.ErrorContext(s.forwarder.ctx, "Could not send intro message to participant", + "error", err, + "participant_id", stringID, + ) } } @@ -1036,10 +1061,10 @@ func (s *session) join(p *party, emitJoinEvent bool) error { case <-c: s.setTerminationErr(sessionTerminatedByModeratorErr) go func() { - s.log.Debugf("Received force termination request") + s.log.DebugContext(s.forwarder.ctx, "Received force termination request") err := s.Close() if err != nil { - s.log.Errorf("Failed to close session: %v.", err) + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } }() case <-s.closeC: @@ -1064,11 +1089,11 @@ func (s *session) join(p *party, emitJoinEvent bool) error { // we must inform all parties that the session is closing. s.setTerminationErrUnlocked(err) s.reportErrorToSessionRecorder(err) - s.log.WithError(err).Warning("Executor failed while creating ephemeral pod.") + s.log.WarnContext(s.forwarder.ctx, "Executor failed while creating ephemeral pod", "error", err) go func() { err := s.Close() if err != nil { - s.log.WithError(err).Error("Failed to close session") + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } }() return trace.Wrap(err) @@ -1076,7 +1101,7 @@ func (s *session) join(p *party, emitJoinEvent bool) error { go func() { if err := s.launch(startedEphemeralCont); err != nil { - s.log.WithError(err).Warning("Failed to launch Kubernetes session.") + s.log.WarnContext(s.forwarder.ctx, "Failed to launch Kubernetes session", "error", err) } }() } else if len(s.parties) == 1 { @@ -1098,7 +1123,7 @@ func (s *session) join(p *party, emitJoinEvent bool) error { // types.SessionState_SessionStatePending marks a session that is waiting for // a moderator to rejoin. if err := s.tracker.UpdateState(s.forwarder.ctx, types.SessionState_SessionStateRunning); err != nil { - s.log.Warnf("Failed to set tracker state to %v", types.SessionState_SessionStateRunning) + s.log.WarnContext(s.forwarder.ctx, "Failed to update tracker to running state") } } return nil @@ -1141,7 +1166,7 @@ func (s *session) createEphemeralContainer() (*corev1.ContainerStatus, error) { return nil, trace.Wrap(err) } - s.log.Debugf("Creating ephemeral container %s on pod %s", container, podName) + s.log.DebugContext(s.forwarder.ctx, "Creating ephemeral container on pod", "container", container, "pod", podName) containerStatus, err := s.patchAndWaitForPodEphemeralContainer(s.forwarder.ctx, &initUser.Ctx, s.req.Header, waitingCont) return containerStatus, trace.Wrap(err) } @@ -1179,7 +1204,7 @@ func (s *session) emitSessionJoinEvent(p *party) { } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, sessionJoinEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit event", "error", err) } } @@ -1228,10 +1253,10 @@ func (s *session) unlockedLeave(id uuid.UUID) (bool, error) { } if err := s.emitter.EmitAuditEvent(s.forwarder.ctx, sessionLeaveEvent); err != nil { - s.forwarder.log.WithError(err).Warn("Failed to emit event.") + s.forwarder.log.WarnContext(s.forwarder.ctx, "Failed to emit event", "error", err) } - s.log.Debugf("No longer tracking participant: %v", party.ID) + s.log.DebugContext(s.forwarder.ctx, "No longer tracking participant", "participant_id", party.ID) err := s.tracker.RemoveParticipant(s.forwarder.ctx, party.ID.String()) if err != nil { errs = append(errs, trace.Wrap(err)) @@ -1246,7 +1271,7 @@ func (s *session) unlockedLeave(id uuid.UUID) (bool, error) { // close session err := s.Close() if err != nil { - s.log.WithError(err).Errorf("Failed to close session") + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } }() return true, trace.NewAggregate(errs...) @@ -1267,7 +1292,7 @@ func (s *session) unlockedLeave(id uuid.UUID) (bool, error) { if options.OnLeaveAction == types.OnSessionLeaveTerminate { go func() { if err := s.Close(); err != nil { - s.log.WithError(err).Errorf("Failed to close session") + s.log.ErrorContext(s.forwarder.ctx, "Failed to close session", "error", err) } }() return true, nil @@ -1277,7 +1302,7 @@ func (s *session) unlockedLeave(id uuid.UUID) (bool, error) { s.io.Off() s.BroadcastMessage("Session paused, Waiting for required participants...") if err := s.tracker.UpdateState(s.forwarder.ctx, types.SessionState_SessionStatePending); err != nil { - s.log.Warnf("Failed to set tracker state to %v", types.SessionState_SessionStatePending) + s.log.WarnContext(s.forwarder.ctx, "Failed to set tracker state to pending") } go func() { @@ -1335,7 +1360,7 @@ func (s *session) Close() error { // Once tracker is closed parties cannot join the session. // check session.join for logic. if err := s.tracker.Close(s.forwarder.ctx); err != nil { - s.log.WithError(err).Debug("Failed to close session tracker") + s.log.DebugContext(s.forwarder.ctx, "Failed to close session tracker", "error", err) } s.mu.Lock() terminationErr := s.terminationErr @@ -1345,7 +1370,7 @@ func (s *session) Close() error { } recorder := s.recorder s.mu.Unlock() - s.log.Debugf("Closing session %v.", s.id.String()) + s.log.DebugContext(s.forwarder.ctx, "Closing session", "session_id", logutils.StringerAttr(s.id)) close(s.closeC) // Wait until every party leaves the session and emits the session leave // event before closing the recorder - if available. @@ -1405,18 +1430,18 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy InitialCommand: command, } - s.log.Debug("Creating session tracker") + s.log.DebugContext(ctx, "Creating session tracker") sessionTrackerService := s.forwarder.cfg.AuthClient tracker, err := srv.NewSessionTracker(ctx, trackerSpec, sessionTrackerService) switch { // there was an error creating the tracker for a moderated session - terminate the session case err != nil && s.accessEvaluator.IsModerated(): - s.log.WithError(err).Warn("Failed to create session tracker, unable to proceed for moderated session") + s.log.WarnContext(ctx, "Failed to create session tracker, unable to proceed for moderated session", "error", err) return trace.Wrap(err) // there was an error creating the tracker for a non-moderated session - permit the session with a local tracker case err != nil && !s.accessEvaluator.IsModerated(): - s.log.Warn("Failed to create session tracker, proceeding with local session tracker for non-moderated session") + s.log.WarnContext(ctx, "Failed to create session tracker, proceeding with local session tracker for non-moderated session") localTracker, err := srv.NewSessionTracker(ctx, trackerSpec, nil) // this error means there are problems with the trackerSpec, we need to return it @@ -1435,7 +1460,7 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy go func() { if err := s.tracker.UpdateExpirationLoop(s.forwarder.ctx, s.forwarder.cfg.Clock); err != nil { - s.log.WithError(err).Warn("Failed to update session tracker expiration") + s.log.WarnContext(ctx, "Failed to update session tracker expiration", "error", err) } }() @@ -1549,7 +1574,7 @@ func (s *session) retrieveAlreadyStoppedPodLogs(namespace, podName, container st func (s *session) retrieveEphemeralContainerCommand(ctx context.Context, username, containerName string) []string { containers, err := s.forwarder.getUserEphemeralContainersForPod(ctx, username, s.ctx.kubeClusterName, s.podNamespace, s.podName) if err != nil { - s.log.WithError(err).Warn("Failed to retrieve ephemeral containers") + s.log.WarnContext(ctx, "Failed to retrieve ephemeral containers", "error", err) return nil } if len(containers) == 0 { @@ -1569,7 +1594,7 @@ func (s *session) retrieveEphemeralContainerCommand(ctx context.Context, usernam newClientNegotiator(s.sess.codecFactory), ) if err != nil { - s.log.WithError(err).Warn("Failed to create encoder and decoder") + s.log.WarnContext(ctx, "Failed to create encoder and decoder", "error", err) return nil } pod, _, err := s.forwarder.mergeEphemeralPatchWithCurrentPod( @@ -1585,7 +1610,7 @@ func (s *session) retrieveEphemeralContainerCommand(ctx context.Context, usernam }, ) if err != nil { - s.log.WithError(err).Warn("Failed to merge ephemeral patch with current pod") + s.log.WarnContext(ctx, "Failed to merge ephemeral patch with current pod", "error", err) return nil } for _, ephemeral := range pod.Spec.EphemeralContainers { diff --git a/lib/kube/proxy/sess_test.go b/lib/kube/proxy/sess_test.go index 469fe2c4df27a..2c87ec555845d 100644 --- a/lib/kube/proxy/sess_test.go +++ b/lib/kube/proxy/sess_test.go @@ -34,13 +34,11 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/remotecommand" - "github.com/gravitational/teleport" kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1" "github.com/gravitational/teleport/api/types" apievents "github.com/gravitational/teleport/api/types/events" @@ -49,6 +47,7 @@ import ( "github.com/gravitational/teleport/lib/authz" "github.com/gravitational/teleport/lib/events" testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" + "github.com/gravitational/teleport/lib/utils" ) func TestSessionEndError(t *testing.T) { @@ -284,7 +283,7 @@ func Test_session_trackSession(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sess := &session{ - log: logrus.New().WithField(teleport.ComponentKey, "test"), + log: utils.NewSlogLoggerForTests(), id: uuid.New(), req: &http.Request{ URL: &url.URL{ diff --git a/lib/kube/proxy/streamproto/proto.go b/lib/kube/proxy/streamproto/proto.go index e2ee646dfe2b7..605f8e00748c4 100644 --- a/lib/kube/proxy/streamproto/proto.go +++ b/lib/kube/proxy/streamproto/proto.go @@ -19,16 +19,17 @@ package streamproto import ( + "context" "errors" "fmt" "io" + "log/slog" "sync" "sync/atomic" "time" "github.com/gorilla/websocket" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "k8s.io/client-go/tools/remotecommand" "github.com/gravitational/teleport/api/types" @@ -170,7 +171,7 @@ func (s *SessionStream) readTask() { ty, data, err := s.conn.ReadMessage() if err != nil { if !errors.Is(err, io.EOF) && !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseAbnormalClosure, websocket.CloseNoStatusReceived) { - log.WithError(err).Warn("Failed to read message from websocket") + slog.WarnContext(context.Background(), "Failed to read message from websocket", "error", err) } var closeErr *websocket.CloseError @@ -293,7 +294,7 @@ func (s *SessionStream) Close() error { if atomic.CompareAndSwapInt32(&s.closed, 0, 1) { err := s.conn.WriteMessage(websocket.CloseMessage, []byte{}) if err != nil { - log.Warnf("Failed to gracefully close websocket connection: %v", err) + slog.WarnContext(context.Background(), "Failed to gracefully close websocket connection", "error", err) } t := time.NewTimer(time.Second * 5) defer t.Stop() diff --git a/lib/kube/proxy/testing/kube_server/kube_mock.go b/lib/kube/proxy/testing/kube_server/kube_mock.go index 332d7327c6d69..0bdc27eeb4d67 100644 --- a/lib/kube/proxy/testing/kube_server/kube_mock.go +++ b/lib/kube/proxy/testing/kube_server/kube_mock.go @@ -26,6 +26,7 @@ import ( "errors" "fmt" "io" + "log/slog" "net/http" "net/http/httptest" "strings" @@ -36,7 +37,6 @@ import ( gwebsocket "github.com/gorilla/websocket" "github.com/gravitational/trace" "github.com/julienschmidt/httprouter" - log "github.com/sirupsen/logrus" "golang.org/x/net/http2" v1 "k8s.io/api/authorization/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -151,7 +151,7 @@ type KubeUpgradeRequests struct { type KubeMockServer struct { router *httprouter.Router - log *log.Entry + log *slog.Logger server *httptest.Server TLS *tls.Config URL string @@ -178,7 +178,7 @@ type KubeMockServer struct { func NewKubeAPIMock(opts ...Option) (*KubeMockServer, error) { s := &KubeMockServer{ router: httprouter.New(), - log: log.NewEntry(log.New()), + log: slog.Default(), deletedResources: make(map[deletedResource][]string), version: &apimachineryversion.Info{ Major: "1", @@ -273,7 +273,7 @@ func (s *KubeMockServer) writeResponseError(rw http.ResponseWriter, respErr erro status = status.DeepCopy() data, err := runtime.Encode(kubeCodecs.LegacyCodec(), status) if err != nil { - s.log.Warningf("Failed encoding error into kube Status object: %v", err) + s.log.WarnContext(context.Background(), "Failed encoding error into kube Status object", "error", err) trace.WriteError(rw, respErr) return } @@ -283,7 +283,7 @@ func (s *KubeMockServer) writeResponseError(rw http.ResponseWriter, respErr erro // embedded. rw.WriteHeader(int(status.Code)) if _, err := rw.Write(data); err != nil { - s.log.Warningf("Failed writing kube error response body: %v", err) + s.log.WarnContext(context.Background(), "Failed writing kube error response body", "error", err) } } @@ -323,13 +323,13 @@ func (s *KubeMockServer) exec(w http.ResponseWriter, req *http.Request, p httpro if request.stdout { if _, err := proxy.stdoutStream.Write([]byte(request.containerName + "\n")); err != nil { - s.log.WithError(err).Errorf("unable to send to stdout") + s.log.ErrorContext(request.context, "unable to send to stdout", "error", err) } } if request.stderr { if _, err := proxy.stderrStream.Write([]byte(request.containerName + "\n")); err != nil { - s.log.WithError(err).Errorf("unable to send to stderr") + s.log.ErrorContext(request.context, "unable to send to stderr", "error", err) } } @@ -341,7 +341,7 @@ func (s *KubeMockServer) exec(w http.ResponseWriter, req *http.Request, p httpro if errors.Is(err, io.EOF) && n == 0 { break } else if err != nil && n == 0 { - s.log.WithError(err).Errorf("unable to receive from stdin") + s.log.ErrorContext(request.context, "unable to receive from stdin", "error", err) break } @@ -359,13 +359,13 @@ func (s *KubeMockServer) exec(w http.ResponseWriter, req *http.Request, p httpro if request.stdout { if _, err := proxy.stdoutStream.Write(buffer); err != nil { - s.log.WithError(err).Errorf("unable to send to stdout") + s.log.ErrorContext(request.context, "unable to send to stdout", "error", err) } } if request.stderr { if _, err := proxy.stderrStream.Write(buffer); err != nil { - s.log.WithError(err).Errorf("unable to send to stdout") + s.log.ErrorContext(request.context, "unable to send to stdout", "error", err) } } @@ -536,10 +536,10 @@ func createSPDYStreams(req remoteCommandRequest) (*remoteCommandProxy, error) { var handler protocolHandler switch protocol { case "": - log.Warningf("Client did not request protocol negotiation.") + slog.WarnContext(req.context, "Client did not request protocol negotiation.") fallthrough case StreamProtocolV4Name: - log.Infof("Negotiated protocol %v.", protocol) + slog.InfoContext(req.context, "Negotiated protocol", "protocol", protocol) handler = &v4ProtocolHandler{} default: return nil, trace.BadParameter("protocol %v is not supported. upgrade the client", protocol) @@ -641,7 +641,7 @@ func (t *termQueue) handleResizeEvents(stream io.Reader) { size := remotecommand.TerminalSize{} if err := decoder.Decode(&size); err != nil { if !errors.Is(err, io.EOF) { - log.Warningf("Failed to decode resize event: %v", err) + slog.WarnContext(t.done, "Failed to decode resize event", "error", err) } t.cancel() return @@ -696,7 +696,7 @@ WaitForStreams: remoteProxy.resizeStream = stream go waitStreamReply(stopCtx, stream.replySent, replyChan) default: - log.Warningf("Ignoring unexpected stream type: %q", streamType) + slog.WarnContext(stopCtx, "Ignoring unexpected stream type", "stream_type", streamType) } case <-replyChan: receivedStreams++ diff --git a/lib/kube/proxy/utils_testing.go b/lib/kube/proxy/utils_testing.go index 462638df203c4..4f3f596ec0a82 100644 --- a/lib/kube/proxy/utils_testing.go +++ b/lib/kube/proxy/utils_testing.go @@ -35,7 +35,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/client-go/kubernetes" @@ -66,6 +65,7 @@ import ( "github.com/gravitational/teleport/lib/services" sessPkg "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/tlsca" + "github.com/gravitational/teleport/lib/utils" ) type TestContext struct { @@ -226,8 +226,6 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo require.NoError(t, err) testCtx.kubeProxyListener, err = net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) - log := logrus.New() - log.SetLevel(logrus.DebugLevel) inventoryHandle := inventory.NewDownstreamHandle(client.InventoryControlStream, proto.UpstreamInventoryHello{ ServerID: testCtx.HostID, @@ -281,7 +279,7 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo GetRotation: func(role types.SystemRole) (*types.Rotation, error) { return &types.Rotation{}, nil }, ResourceMatchers: cfg.ResourceMatchers, OnReconcile: cfg.OnReconcile, - Log: log, + Log: utils.NewSlogLoggerForTests(), InventoryHandle: inventoryHandle, }) require.NoError(t, err) @@ -358,7 +356,7 @@ func SetupTestContext(ctx context.Context, t *testing.T, cfg TestConfig) *TestCo LimiterConfig: limiter.Config{ MaxConnections: 1000, }, - Log: log, + Log: utils.NewSlogLoggerForTests(), InventoryHandle: inventoryHandle, GetRotation: func(role types.SystemRole) (*types.Rotation, error) { return &types.Rotation{}, nil diff --git a/lib/kube/proxy/watcher.go b/lib/kube/proxy/watcher.go index 24e52e2d9c923..56bea639d5260 100644 --- a/lib/kube/proxy/watcher.go +++ b/lib/kube/proxy/watcher.go @@ -20,7 +20,6 @@ package proxy import ( "context" - "log/slog" "sync" "time" @@ -37,7 +36,7 @@ import ( // kubernetes clusters according to the up-to-date list of kube_cluster resources. func (s *TLSServer) startReconciler(ctx context.Context) (err error) { if len(s.ResourceMatchers) == 0 || s.KubeServiceType != KubeService { - s.log.Debug("Not initializing Kube Cluster resource watcher.") + s.log.DebugContext(ctx, "Not initializing Kube Cluster resource watcher") return nil } s.reconciler, err = services.NewReconciler(services.ReconcilerConfig[types.KubeCluster]{ @@ -47,8 +46,7 @@ func (s *TLSServer) startReconciler(ctx context.Context) (err error) { OnCreate: s.onCreate, OnUpdate: s.onUpdate, OnDelete: s.onDelete, - // TODO(tross): update to use the server logger once it has been converted to slog - Logger: slog.With("kind", types.KindKubernetesCluster), + Logger: s.log.With("kind", types.KindKubernetesCluster), }) if err != nil { return trace.Wrap(err) @@ -71,16 +69,16 @@ func (s *TLSServer) startReconciler(ctx context.Context) (err error) { select { case <-reconcileTicker.C: if err := s.reconciler.Reconcile(ctx); err != nil { - s.log.WithError(err).Error("Failed to reconcile.") + s.log.ErrorContext(ctx, "Failed to reconcile", "error", err) } case <-s.reconcileCh: if err := s.reconciler.Reconcile(ctx); err != nil { - s.log.WithError(err).Error("Failed to reconcile.") + s.log.ErrorContext(ctx, "Failed to reconcile", "error", err) } else if s.OnReconcile != nil { s.OnReconcile(s.fwd.kubeClusters()) } case <-ctx.Done(): - s.log.Debug("Reconciler done.") + s.log.DebugContext(ctx, "Reconciler done") return } } @@ -92,16 +90,15 @@ func (s *TLSServer) startReconciler(ctx context.Context) (err error) { // registers/unregisters the proxied Kube Cluster accordingly. 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.") + s.log.DebugContext(ctx, "Not initializing Kube Cluster resource watcher") return nil, nil } - s.log.Debug("Initializing Kube Cluster resource watcher.") + s.log.DebugContext(ctx, "Initializing Kube Cluster resource watcher") watcher, err := services.NewKubeClusterWatcher(ctx, services.KubeClusterWatcherConfig{ ResourceWatcherConfig: services.ResourceWatcherConfig{ Component: s.Component, - // TODO(tross): update this once converted to use slog - // Logger: s.log, - Client: s.AccessPoint, + Logger: s.log, + Client: s.AccessPoint, }, KubernetesClusterGetter: s.AccessPoint, }) @@ -120,7 +117,7 @@ func (s *TLSServer) startKubeClusterResourceWatcher(ctx context.Context) (*servi return } case <-ctx.Done(): - s.log.Debug("Kube Cluster resource watcher done.") + s.log.DebugContext(ctx, "Kube Cluster resource watcher done") return } } diff --git a/lib/multiplexer/test/ping.pb.go b/lib/multiplexer/test/ping.pb.go index a78fd7c1a9e71..94cbf8e67b1b9 100644 --- a/lib/multiplexer/test/ping.pb.go +++ b/lib/multiplexer/test/ping.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.0 +// protoc-gen-go v1.36.1 // protoc (unknown) // source: teleport/lib/multiplexer/test/ping.proto diff --git a/lib/proxy/router.go b/lib/proxy/router.go index 1fc06a5e34754..61ba7f466c5de 100644 --- a/lib/proxy/router.go +++ b/lib/proxy/router.go @@ -492,7 +492,10 @@ func getServerWithResolver(ctx context.Context, host, port string, site site, re } } case len(matches) > 1: - return nil, trace.NotFound(teleport.NodeIsAmbiguous) + // TODO(tross) DELETE IN V20.0.0 + // NodeIsAmbiguous is included in the error message for backwards compatibility + // with older nodes that expect to see that string in the error message. + return nil, trace.Wrap(teleport.ErrNodeIsAmbiguous, teleport.NodeIsAmbiguous) case len(matches) == 1: server = matches[0] } diff --git a/lib/proxy/router_test.go b/lib/proxy/router_test.go index 6be18370437a2..e83ca44a2811d 100644 --- a/lib/proxy/router_test.go +++ b/lib/proxy/router_test.go @@ -211,7 +211,7 @@ func TestRouteScoring(t *testing.T) { t.Run(tt.desc, func(t *testing.T) { srv, err := getServerWithResolver(ctx, tt.host, tt.port, site, resolver) if tt.ambiguous { - require.ErrorIs(t, err, trace.NotFound(teleport.NodeIsAmbiguous)) + require.ErrorIs(t, err, teleport.ErrNodeIsAmbiguous) return } require.Equal(t, tt.expect, srv.GetHostname()) @@ -375,7 +375,7 @@ func TestGetServers(t *testing.T) { site: testSite{cfg: &unambiguousCfg, nodes: servers}, host: "sheep", errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, trace.NotFound(teleport.NodeIsAmbiguous)) + require.ErrorIs(t, err, teleport.ErrNodeIsAmbiguous) }, serverAssertion: func(t *testing.T, srv types.Server) { require.Empty(t, srv) @@ -456,7 +456,7 @@ func TestGetServers(t *testing.T) { site: testSite{cfg: &unambiguousInsensitiveCfg, nodes: servers}, host: "platypus", errAssertion: func(t require.TestingT, err error, i ...interface{}) { - require.ErrorIs(t, err, trace.NotFound(teleport.NodeIsAmbiguous)) + require.ErrorIs(t, err, teleport.ErrNodeIsAmbiguous) }, serverAssertion: func(t *testing.T, srv types.Server) { require.Empty(t, srv) @@ -667,7 +667,7 @@ func TestRouter_DialHost(t *testing.T) { router: Router{ clusterName: "test", tracer: tracing.NoopTracer("test"), - serverResolver: serverResolver(nil, trace.NotFound(teleport.NodeIsAmbiguous)), + serverResolver: serverResolver(nil, teleport.ErrNodeIsAmbiguous), }, assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.Error(t, err) diff --git a/lib/service/kubernetes.go b/lib/service/kubernetes.go index c642da43f4669..f25b46e42da4c 100644 --- a/lib/service/kubernetes.go +++ b/lib/service/kubernetes.go @@ -240,7 +240,7 @@ func (process *TeleportProcess) initKubernetesService(logger *slog.Logger, conn StaticLabels: cfg.Kube.StaticLabels, DynamicLabels: dynLabels, CloudLabels: process.cloudLabels, - Log: process.log.WithField(teleport.ComponentKey, teleport.Component(teleport.ComponentKube, process.id)), + Log: process.logger.With(teleport.ComponentKey, teleport.Component(teleport.ComponentKube, process.id)), PROXYProtocolMode: multiplexer.PROXYProtocolOff, // Kube service doesn't need to process unsigned PROXY headers. InventoryHandle: process.inventoryHandle, }) diff --git a/lib/service/service.go b/lib/service/service.go index ebdb99b6a282b..e2155affc208c 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -5119,7 +5119,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { AccessPoint: accessPoint, GetRotation: process.GetRotation, OnHeartbeat: process.OnHeartbeat(component), - Log: process.log.WithField(teleport.ComponentKey, teleport.Component(teleport.ComponentReverseTunnelServer, process.id)), + Log: process.logger.With(teleport.ComponentKey, teleport.Component(teleport.ComponentReverseTunnelServer, process.id)), IngressReporter: ingressReporter, KubernetesServersWatcher: kubeServerWatcher, PROXYProtocolMode: cfg.Proxy.PROXYProtocolMode, @@ -6748,7 +6748,7 @@ func (process *TeleportProcess) initSecureGRPCServer(cfg initSecureGRPCServerCfg kubeServer, err := kubegrpc.New(kubegrpc.Config{ AccessPoint: cfg.accessPoint, Authz: authorizer, - Log: process.log, + Log: process.logger, Emitter: cfg.emitter, KubeProxyAddr: cfg.kubeProxyAddr.String(), ClusterName: clusterName, diff --git a/lib/services/access_checker.go b/lib/services/access_checker.go index 1d3639bc742c8..acea13514adea 100644 --- a/lib/services/access_checker.go +++ b/lib/services/access_checker.go @@ -22,13 +22,13 @@ import ( "cmp" "context" "fmt" + "log/slog" "net" "slices" "strings" "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" "github.com/gravitational/teleport/api/constants" @@ -39,6 +39,7 @@ import ( "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" ) // AccessChecker interface checks access to resources based on roles, traits, @@ -406,10 +407,11 @@ func (a *accessChecker) checkAllowedResources(r AccessCheckable) error { return nil } - // Note: logging in this function only happens in debug mode. This is because + // Note: logging in this function only happens in trace mode. This is because // adding logging to this function (which is called on every resource returned // by the backend) can slow down this function by 50x for large clusters! - isDebugEnabled, debugf := rbacDebugLogger() + ctx := context.Background() + isLoggingEnabled := rbacLogger.Enabled(ctx, logutils.TraceLevel) for _, resourceID := range a.info.AllowedResourceIDs { if resourceID.ClusterName == a.localCluster && @@ -421,23 +423,33 @@ func (a *accessChecker) checkAllowedResources(r AccessCheckable) error { (resourceID.Kind == r.GetKind() || (slices.Contains(types.KubernetesResourcesKinds, resourceID.Kind) && r.GetKind() == types.KindKubernetesCluster)) && resourceID.Name == r.GetName() { // Allowed to access this resource by resource ID, move on to role checks. - if isDebugEnabled { - debugf("Matched allowed resource ID %q", types.ResourceIDToString(resourceID)) + + if isLoggingEnabled { + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Matched allowed resource ID", + slog.String("resource_id", types.ResourceIDToString(resourceID)), + ) } + return nil } } - if isDebugEnabled { + if isLoggingEnabled { allowedResources, err := types.ResourceIDsToString(a.info.AllowedResourceIDs) if err != nil { return trace.Wrap(err) } - err = trace.AccessDenied("access to %v denied, %q not in allowed resource IDs %s", + + slog.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, not in allowed resource IDs", + slog.String("resource_kind", r.GetKind()), + slog.String("resource_name", r.GetName()), + slog.Any("allowed_resources", allowedResources), + ) + + return trace.AccessDenied("access to %v denied, %q not in allowed resource IDs %s", r.GetKind(), r.GetName(), allowedResources) - debugf("Access denied: %v", err) - return err } + return trace.AccessDenied("access to %v denied, not in allowed resource IDs", r.GetKind()) } @@ -875,10 +887,11 @@ func (a *accessChecker) CheckAccessToRemoteCluster(rc types.RemoteCluster) error return trace.AccessDenied("access to cluster denied") } - // Note: logging in this function only happens in debug mode, this is because + // Note: logging in this function only happens in trace mode, this is because // adding logging to this function (which is called on every server returned // by GetRemoteClusters) can slow down this function by 50x for large clusters! - isDebugEnabled, debugf := rbacDebugLogger() + ctx := context.Background() + isLoggingEnabled := rbacLogger.Enabled(ctx, logutils.TraceLevel) rcLabels := rc.GetMetadata().Labels @@ -898,8 +911,10 @@ func (a *accessChecker) CheckAccessToRemoteCluster(rc types.RemoteCluster) error } if !usesLabels && len(rcLabels) == 0 { - debugf("Grant access to cluster %v - no role in %v uses cluster labels and the cluster is not labeled.", - rc.GetName(), a.RoleNames()) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Grant access to cluster - no role uses cluster labels and the cluster is not labeled", + slog.String("cluster_name", rc.GetName()), + slog.Any("roles", a.RoleNames()), + ) return nil } @@ -907,21 +922,24 @@ func (a *accessChecker) CheckAccessToRemoteCluster(rc types.RemoteCluster) error // the deny role set prohibits access. var errs []error for _, role := range a.RoleSet { - matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Deny, role, a.info.Traits, rc, isDebugEnabled) + matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Deny, role, a.info.Traits, rc, isLoggingEnabled) if err != nil { return trace.Wrap(err) } if matchLabels { // This condition avoids formatting calls on large scale. - debugf("Access to cluster %v denied, deny rule in %v matched; match(%s)", - rc.GetName(), role.GetName(), labelsMessage) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access to cluster denied, deny rule matched", + slog.String("cluster", rc.GetName()), + slog.String("role", role.GetName()), + slog.String("label_message", labelsMessage), + ) return trace.AccessDenied("access to cluster denied") } } // Check allow rules: label has to match in any role in the role set to be granted access. for _, role := range a.RoleSet { - matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Allow, role, a.info.Traits, rc, isDebugEnabled) + matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Allow, role, a.info.Traits, rc, isLoggingEnabled) if err != nil { return trace.Wrap(err) } @@ -929,22 +947,32 @@ func (a *accessChecker) CheckAccessToRemoteCluster(rc types.RemoteCluster) error if err != nil { return trace.Wrap(err) } - debugf("Check access to role(%v) rc(%v, labels=%v) matchLabels=%v, msg=%v, err=%v allow=%v rcLabels=%v", - role.GetName(), rc.GetName(), rcLabels, matchLabels, labelsMessage, err, labelMatchers, rcLabels) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Check access to role", + slog.String("role", role.GetName()), + slog.String("cluster", rc.GetName()), + slog.Any("cluster_labels", rcLabels), + slog.Any("match_labels", matchLabels), + slog.String("labels_message", labelsMessage), + slog.Any("error", err), + slog.Any("allow", labelMatchers), + ) if err != nil { return trace.Wrap(err) } if matchLabels { return nil } - if isDebugEnabled { + if isLoggingEnabled { deniedError := trace.AccessDenied("role=%v, match(%s)", role.GetName(), labelsMessage) errs = append(errs, deniedError) } } - debugf("Access to cluster %v denied, no allow rule matched; %v", rc.GetName(), errs) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access to cluster denied, no allow rule matched", + slog.String("cluster", rc.GetName()), + slog.Any("error", errs), + ) return trace.AccessDenied("access to cluster denied") } @@ -1095,7 +1123,10 @@ func (a *accessChecker) HostUsers(s types.Server) (*HostUsersInfo, error) { fmt.Fprintf(b, "%s=%v ", shell, roles) } - log.Warnf("Host user shell resolution is ambiguous due to conflicting roles. %q will be used, but consider unifying roles around a single shell. Current shell assignments: %s", shell, b) + slog.WarnContext(context.Background(), "Host user shell resolution is ambiguous due to conflicting roles, consider unifying roles around a single shell", + "selected_shell", shell, + "shell_assignments", b, + ) } for _, role := range a.RoleSet { @@ -1247,8 +1278,11 @@ func AccessInfoFromRemoteCertificate(cert *ssh.Certificate, roleMap types.RoleMa if len(roles) == 0 { return nil, trace.AccessDenied("no roles mapped for user with remote roles %v", unmappedRoles) } - log.Debugf("Mapped remote roles %v to local roles %v and traits %v.", - unmappedRoles, roles, traits) + slog.DebugContext(context.Background(), "Mapped remote roles to local roles and traits", + "remote_roles", unmappedRoles, + "local_roles", roles, + "traits", traits, + ) allowedResourceIDs, err := ExtractAllowedResourcesFromCert(cert) if err != nil { @@ -1281,10 +1315,10 @@ func AccessInfoFromLocalIdentity(identity tlsca.Identity, access UserGetter) (*A return nil, trace.Wrap(err) } - log.Warnf("Failed to find roles in x509 identity for %v. Fetching "+ - "from backend. If the identity provider allows username changes, this can "+ - "potentially allow an attacker to change the role of the existing user.", - identity.Username) + const msg = "Failed to find roles in x509 identity. Fetching " + + "from backend. If the identity provider allows username changes, this can " + + "potentially allow an attacker to change the role of the existing user." + slog.WarnContext(context.Background(), msg, "username", identity.Username) roles = u.GetRoles() traits = u.GetTraits() } @@ -1335,8 +1369,12 @@ func AccessInfoFromRemoteIdentity(identity tlsca.Identity, roleMap types.RoleMap if len(roles) == 0 { return nil, trace.AccessDenied("no roles mapped for remote user %q from cluster %q with remote roles %v", identity.Username, identity.TeleportCluster, unmappedRoles) } - log.Debugf("Mapped roles %v of remote user %q to local roles %v and traits %v.", - unmappedRoles, identity.Username, roles, traits) + slog.DebugContext(context.Background(), "Mapped roles of remote user to local roles and traits", + "remote_roles", unmappedRoles, + "user", identity.Username, + "local_roles", roles, + "traits", traits, + ) allowedResourceIDs := identity.AllowedResourceIDs diff --git a/lib/services/access_request.go b/lib/services/access_request.go index 67da35cde7381..2d5c407f05e48 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -41,6 +41,7 @@ import ( apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/utils/parse" "github.com/gravitational/teleport/lib/utils/typical" ) @@ -2170,10 +2171,9 @@ func (m *RequestValidator) pruneResourceRequestRoles( for _, resourceID := range resourceIDs { if resourceID.ClusterName != localClusterName { - _, debugf := rbacDebugLogger() - debugf("Requested resource %q is in a foreign cluster, unable to prune roles. "+ - `All available "search_as_roles" will be requested.`, - types.ResourceIDToString(resourceID)) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, `Requested resource is in a foreign cluster, unable to prune roles - All available "search_as_roles" will be requested`, + slog.Any("requested_resources", types.ResourceIDToString(resourceID)), + ) return roles, nil } } diff --git a/lib/services/database.go b/lib/services/database.go index a151f2956fc6f..9a3aba1ad9560 100644 --- a/lib/services/database.go +++ b/lib/services/database.go @@ -21,6 +21,7 @@ package services import ( "context" "errors" + "log/slog" "net" "net/netip" "net/url" @@ -28,7 +29,6 @@ import ( "strings" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "go.mongodb.org/mongo-driver/mongo/readpref" "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" @@ -277,7 +277,11 @@ func validateMongoDB(db types.Database) error { // DNS errors here by replacing the scheme and then ParseAndValidate again // to validate as much as we can. if isDNSError(err) { - log.Warnf("MongoDB database %q (connection string %q) failed validation with DNS error: %v.", db.GetName(), db.GetURI(), err) + slog.WarnContext(context.Background(), "MongoDB database %q (connection string %q) failed validation with DNS error", + "database_name", db.GetName(), + "database_uri", db.GetURI(), + "error", err, + ) connString, err = connstring.ParseAndValidate(strings.Replace( db.GetURI(), diff --git a/lib/services/local/access.go b/lib/services/local/access.go index eb467e76ed815..55f53a1715268 100644 --- a/lib/services/local/access.go +++ b/lib/services/local/access.go @@ -20,11 +20,11 @@ package local import ( "context" + "log/slog" "strings" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -36,14 +36,14 @@ import ( // AccessService manages roles type AccessService struct { backend.Backend - log *logrus.Entry + logger *slog.Logger } // NewAccessService returns new access service instance func NewAccessService(backend backend.Backend) *AccessService { return &AccessService{ Backend: backend, - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "AccessService"}), + logger: slog.With(teleport.ComponentKey, "AccessService"), } } @@ -124,7 +124,10 @@ func (s *AccessService) ListRoles(ctx context.Context, req *proto.ListRolesReque services.WithRevision(item.Revision), ) if err != nil { - s.log.Warnf("Failed to unmarshal role at %q: %v", item.Key, err) + s.logger.WarnContext(ctx, "Failed to unmarshal role", + "key", item.Key, + "error", err, + ) continue } diff --git a/lib/services/local/access_list.go b/lib/services/local/access_list.go index 611d9de23f094..955b691d503bc 100644 --- a/lib/services/local/access_list.go +++ b/lib/services/local/access_list.go @@ -27,9 +27,7 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" @@ -75,7 +73,6 @@ const ( // consistent view to the rest of the Teleport application. It makes no decisions // about granting or withholding list membership. type AccessListService struct { - log logrus.FieldLogger clock clockwork.Clock service *generic.Service[*accesslist.AccessList] memberService *generic.Service[*accesslist.AccessListMember] @@ -144,7 +141,6 @@ func NewAccessListService(b backend.Backend, clock clockwork.Clock, opts ...Serv } return &AccessListService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "access-list:local-service"}), clock: clock, service: service, memberService: memberService, diff --git a/lib/services/local/dynamic_access.go b/lib/services/local/dynamic_access.go index e11aa5a51b16a..cdacfbecd566b 100644 --- a/lib/services/local/dynamic_access.go +++ b/lib/services/local/dynamic_access.go @@ -20,11 +20,11 @@ package local import ( "context" + "log/slog" "slices" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -38,14 +38,14 @@ import ( // DynamicAccessService manages dynamic RBAC type DynamicAccessService struct { backend.Backend - log *logrus.Entry + logger *slog.Logger } // NewDynamicAccessService returns new dynamic access service instance func NewDynamicAccessService(backend backend.Backend) *DynamicAccessService { return &DynamicAccessService{ Backend: backend, - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "DynamicAccess"}), + logger: slog.With(teleport.ComponentKey, "DynamicAccess"), } } @@ -348,7 +348,10 @@ func (s *DynamicAccessService) ListAccessRequests(ctx context.Context, req *prot accessRequest, err := itemToAccessRequest(item) if err != nil { - s.log.Warnf("Failed to unmarshal access request at %q: %v", item.Key, err) + s.logger.WarnContext(ctx, "Failed to unmarshal access request", + "key", item.Key, + "error", err, + ) continue } diff --git a/lib/services/local/events.go b/lib/services/local/events.go index 9931b80857500..58e56ada292a4 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -20,11 +20,11 @@ package local import ( "context" + "log/slog" "strings" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" apidefaults "github.com/gravitational/teleport/api/defaults" @@ -48,14 +48,14 @@ import ( // EventsService implements service to watch for events type EventsService struct { - *logrus.Entry + logger *slog.Logger backend backend.Backend } // NewEventsService returns new events service instance func NewEventsService(b backend.Backend) *EventsService { return &EventsService{ - Entry: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "Events"}), + logger: slog.With(teleport.ComponentKey, "Events"), backend: b, } } @@ -287,13 +287,13 @@ func (e *EventsService) NewWatcher(ctx context.Context, watch types.Watch) (type if err != nil { return nil, trace.Wrap(err) } - return newWatcher(w, e.Entry, parsers, validKinds), nil + return newWatcher(w, e.logger, parsers, validKinds), nil } -func newWatcher(backendWatcher backend.Watcher, l *logrus.Entry, parsers []resourceParser, kinds []types.WatchKind) *watcher { +func newWatcher(backendWatcher backend.Watcher, l *slog.Logger, parsers []resourceParser, kinds []types.WatchKind) *watcher { w := &watcher{ backendWatcher: backendWatcher, - Entry: l, + logger: l, parsers: parsers, eventsC: make(chan types.Event), kinds: kinds, @@ -303,7 +303,7 @@ func newWatcher(backendWatcher backend.Watcher, l *logrus.Entry, parsers []resou } type watcher struct { - *logrus.Entry + logger *slog.Logger parsers []resourceParser backendWatcher backend.Watcher eventsC chan types.Event @@ -350,7 +350,7 @@ func (w *watcher) forwardEvents() { // node events as well, and there could be no // handler registered for nodes, only for namespaces if !trace.IsNotFound(err) { - w.Warning(trace.DebugReport(err)) + w.logger.WarnContext(context.Background(), "failed parsing event", "error", err) } } for _, c := range converted { @@ -2944,7 +2944,7 @@ func WaitForEvent(ctx context.Context, watcher types.Watcher, m EventMatcher, cl return res, nil } if !trace.IsCompareFailed(err) { - logrus.WithError(err).Debug("Failed to match event.") + slog.DebugContext(ctx, "Failed to match event", "error", err) } case <-watcher.Done(): // Watcher closed, probably due to a network error. diff --git a/lib/services/local/externalauditstorage.go b/lib/services/local/externalauditstorage.go index 96cd050bfd5be..fdb59e827d03a 100644 --- a/lib/services/local/externalauditstorage.go +++ b/lib/services/local/externalauditstorage.go @@ -22,9 +22,7 @@ import ( "context" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types/externalauditstorage" "github.com/gravitational/teleport/api/types/header" "github.com/gravitational/teleport/lib/backend" @@ -45,14 +43,12 @@ var ( // ExternalAuditStorageService manages External Audit Storage resources in the Backend. type ExternalAuditStorageService struct { backend backend.Backend - logger *logrus.Entry } // NewExternalAuditStorageService returns a new *ExternalAuditStorageService or an error if it fails. func NewExternalAuditStorageService(backend backend.Backend) *ExternalAuditStorageService { return &ExternalAuditStorageService{ backend: backend, - logger: logrus.WithField(teleport.ComponentKey, "ExternalAuditStorage.backend"), } } diff --git a/lib/services/local/externalauditstorage_watcher.go b/lib/services/local/externalauditstorage_watcher.go index 633e8a5c53f3e..f962e2e5cdcce 100644 --- a/lib/services/local/externalauditstorage_watcher.go +++ b/lib/services/local/externalauditstorage_watcher.go @@ -21,11 +21,11 @@ package local import ( "context" "errors" + "log/slog" "sync" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -38,8 +38,8 @@ import ( type ClusterExternalAuditStorageWatcherConfig struct { // Backend is the storage backend used to create watchers. Backend backend.Backend - // Log is a logger. - Log logrus.FieldLogger + // Logger is a logger. + Logger *slog.Logger // Clock is used to control time. Clock clockwork.Clock // OnChange is the action to take when the cluster ExternalAuditStorage @@ -52,8 +52,8 @@ func (cfg *ClusterExternalAuditStorageWatcherConfig) CheckAndSetDefaults() error if cfg.Backend == nil { return trace.BadParameter("missing parameter Backend") } - if cfg.Log == nil { - cfg.Log = logrus.StandardLogger().WithField(teleport.ComponentKey, "ExternalAuditStorage.watcher") + if cfg.Logger == nil { + cfg.Logger = slog.With(teleport.ComponentKey, "ExternalAuditStorage.watcher") } if cfg.Clock == nil { cfg.Clock = cfg.Backend.Clock() @@ -67,7 +67,7 @@ func (cfg *ClusterExternalAuditStorageWatcherConfig) CheckAndSetDefaults() error // ClusterExternalAuditWatcher is a light weight backend watcher for the cluster external audit resource. type ClusterExternalAuditWatcher struct { backend backend.Backend - log logrus.FieldLogger + logger *slog.Logger clock clockwork.Clock onChange func() retry retryutils.Retry @@ -97,7 +97,7 @@ func NewClusterExternalAuditWatcher(ctx context.Context, cfg ClusterExternalAudi w := &ClusterExternalAuditWatcher{ backend: cfg.Backend, - log: cfg.Log, + logger: cfg.Logger, clock: cfg.Clock, onChange: cfg.OnChange, retry: retry, @@ -137,7 +137,10 @@ func (w *ClusterExternalAuditWatcher) runWatchLoop(ctx context.Context) { startedWaiting := w.clock.Now() select { case t := <-w.retry.After(): - w.log.Warningf("Restarting watch on error after waiting %v. Error: %v.", t.Sub(startedWaiting), err) + w.logger.WarnContext(ctx, "Restarting watch on error", + "backoff", t.Sub(startedWaiting), + "error", err, + ) w.retry.Inc() case <-ctx.Done(): return @@ -156,7 +159,7 @@ func (w *ClusterExternalAuditWatcher) watch(ctx context.Context) error { for { select { case <-watcher.Events(): - w.log.Infof("Detected change to cluster ExternalAuditStorage config") + w.logger.InfoContext(ctx, "Detected change to cluster ExternalAuditStorage config") w.onChange() case w.running <- struct{}{}: case <-watcher.Done(): diff --git a/lib/services/local/headlessauthn_watcher.go b/lib/services/local/headlessauthn_watcher.go index d3ded3d60439c..dee036fa363df 100644 --- a/lib/services/local/headlessauthn_watcher.go +++ b/lib/services/local/headlessauthn_watcher.go @@ -21,12 +21,12 @@ package local import ( "context" "errors" + "log/slog" "sync" "time" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" @@ -51,8 +51,8 @@ var ErrHeadlessAuthenticationWatcherClosed = errors.New("headless authentication type HeadlessAuthenticationWatcherConfig struct { // Backend is the storage backend used to create watchers. Backend backend.Backend - // Log is a logger. - Log logrus.FieldLogger + // Logger is a logger. + Logger *slog.Logger // Clock is used to control time. Clock clockwork.Clock // MaxRetryPeriod is the maximum retry period on failed watchers. @@ -64,9 +64,8 @@ func (cfg *HeadlessAuthenticationWatcherConfig) CheckAndSetDefaults() error { if cfg.Backend == nil { return trace.BadParameter("missing parameter Backend") } - if cfg.Log == nil { - cfg.Log = logrus.StandardLogger() - cfg.Log.WithField("resource-kind", types.KindHeadlessAuthentication) + if cfg.Logger == nil { + cfg.Logger = slog.With("resource_kind", types.KindHeadlessAuthentication) } if cfg.MaxRetryPeriod == 0 { // On watcher failure, we eagerly retry in order to avoid login delays. @@ -159,12 +158,15 @@ func (h *HeadlessAuthenticationWatcher) runWatchLoop(ctx context.Context) { startedWaiting := h.Clock.Now() select { case t := <-h.retry.After(): - h.Log.Warningf("Restarting watch on error after waiting %v. Error: %v.", t.Sub(startedWaiting), err) + h.Logger.WarnContext(ctx, "Restarting watch on error", + "backoff", t.Sub(startedWaiting), + "error", err, + ) h.retry.Inc() case <-ctx.Done(): return case <-h.closed: - h.Log.Debug("Watcher closed. Returning from watch loop.") + h.Logger.DebugContext(ctx, "Watcher closed, terminating watch loop") return } } @@ -191,7 +193,7 @@ func (h *HeadlessAuthenticationWatcher) watch(ctx context.Context) error { case types.OpPut: headlessAuthn, err := unmarshalHeadlessAuthenticationFromItem(&event.Item) if err != nil { - h.Log.WithError(err).Debug("failed to unmarshal headless authentication from put event") + h.Logger.DebugContext(ctx, "failed to unmarshal headless authentication from put event", "error", err) } else { h.notify(headlessAuthn) } diff --git a/lib/services/local/inventory.go b/lib/services/local/inventory.go index 2b488e49e58aa..0eba8cadd618b 100644 --- a/lib/services/local/inventory.go +++ b/lib/services/local/inventory.go @@ -54,11 +54,17 @@ func (s *PresenceService) GetInstances(ctx context.Context, req types.InstanceFi return stream.FilterMap(items, func(item backend.Item) (types.Instance, bool) { instance, err := generic.FastUnmarshal[*types.InstanceV1](item) if err != nil { - s.log.Warnf("Skipping instance at %s, failed to unmarshal: %v", item.Key, err) + s.logger.WarnContext(ctx, "Skipping instance failed to unmarshal", + "key", item.Key, + "error", err, + ) return nil, false } if err := instance.CheckAndSetDefaults(); err != nil { - s.log.Warnf("Skipping instance at %s: %v", item.Key, err) + s.logger.WarnContext(ctx, "Skipping invalid instance", + "key", item.Key, + "error", err, + ) return nil, false } if !req.Match(instance) { diff --git a/lib/services/local/okta.go b/lib/services/local/okta.go index b1ab4e8f3b65d..dfbca6b4d29ee 100644 --- a/lib/services/local/okta.go +++ b/lib/services/local/okta.go @@ -24,9 +24,7 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/services" @@ -43,7 +41,6 @@ const ( // OktaService manages Okta resources in the Backend. type OktaService struct { - log logrus.FieldLogger clock clockwork.Clock importRuleSvc *generic.Service[types.OktaImportRule] assignmentSvc *generic.Service[types.OktaAssignment] @@ -76,7 +73,6 @@ func NewOktaService(b backend.Backend, clock clockwork.Clock) (*OktaService, err } return &OktaService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "okta:local-service"}), clock: clock, importRuleSvc: importRuleSvc, assignmentSvc: assignmentSvc, diff --git a/lib/services/local/presence.go b/lib/services/local/presence.go index ff95884151b34..520eae0f33c87 100644 --- a/lib/services/local/presence.go +++ b/lib/services/local/presence.go @@ -26,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -45,7 +44,7 @@ import ( // PresenceService records and reports the presence of all components // of the cluster - Nodes, Proxies and SSH nodes type PresenceService struct { - log *logrus.Entry + logger *slog.Logger jitter retryutils.Jitter backend.Backend } @@ -57,7 +56,7 @@ type backendItemToResourceFunc func(item backend.Item) (types.ResourceWithLabels // NewPresenceService returns new presence service instance func NewPresenceService(b backend.Backend) *PresenceService { return &PresenceService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "Presence"}), + logger: slog.With(teleport.ComponentKey, "Presence"), jitter: retryutils.FullJitter, Backend: b, } @@ -160,7 +159,10 @@ func (s *PresenceService) GetServerInfos(ctx context.Context) stream.Stream[type services.WithRevision(item.Revision), ) if err != nil { - s.log.Warnf("Skipping server info at %s, failed to unmarshal: %v", item.Key, err) + s.logger.WarnContext(ctx, "Failed to unmarshal server info", + "key", item.Key, + "error", err, + ) return nil, false } return si, true diff --git a/lib/services/local/saml_idp_service_provider.go b/lib/services/local/saml_idp_service_provider.go index 6b08cf084afd9..eadeb347367ab 100644 --- a/lib/services/local/saml_idp_service_provider.go +++ b/lib/services/local/saml_idp_service_provider.go @@ -22,6 +22,7 @@ import ( "context" "encoding/xml" "fmt" + "log/slog" "net/http" "net/url" "time" @@ -29,7 +30,6 @@ import ( "github.com/crewjam/saml" "github.com/crewjam/saml/samlsp" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -55,7 +55,7 @@ type SAMLIdPServiceProviderService struct { // backend is used to spawn Plugins storage service so that // it can be queried from the SAML service. backend backend.Backend - log logrus.FieldLogger + logger *slog.Logger httpClient *http.Client } @@ -86,7 +86,7 @@ func NewSAMLIdPServiceProviderService(b backend.Backend, opts ...SAMLIdPOption) samlSPService := &SAMLIdPServiceProviderService{ svc: *svc, backend: b, - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "saml-idp"}), + logger: slog.With(teleport.ComponentKey, "saml-idp"), } for _, opt := range opts { @@ -120,13 +120,17 @@ func (s *SAMLIdPServiceProviderService) CreateSAMLIdPServiceProvider(ctx context if err := services.ValidateSAMLIdPACSURLAndRelayStateInputs(sp); err != nil { // logging instead of returning an error cause we do not want to break cache writes on a cluster // that already has a service provider with unsupported characters/scheme in the acs_url or relay_state. - s.log.Warn(err) + s.logger.WarnContext(ctx, "Provided SAML IdP service provided is invalid", "error", err) } if sp.GetEntityDescriptor() == "" { if err := s.configureEntityDescriptorPerPreset(sp); err != nil { errMsg := fmt.Errorf("failed to configure entity descriptor with the given entity_id %q and acs_url %q: %w", sp.GetEntityID(), sp.GetACSURL(), err) - s.log.Errorf(errMsg.Error()) + s.logger.ErrorContext(ctx, "failed to configure entity descriptor", + "entity_id", sp.GetEntityID(), + "acs_url", sp.GetACSURL(), + "error", err, + ) return trace.BadParameter(errMsg.Error()) } } @@ -166,7 +170,7 @@ func (s *SAMLIdPServiceProviderService) UpdateSAMLIdPServiceProvider(ctx context if err := services.ValidateSAMLIdPACSURLAndRelayStateInputs(sp); err != nil { // logging instead of returning an error cause we do not want to break cache writes on a cluster // that already has a service provider with unsupported characters/scheme in the acs_url or relay_state. - s.log.Warn(err) + s.logger.WarnContext(ctx, "Provided SAML IdP service provided is invalid", "error", err) } // we only verify if the entity ID field in the spec matches with the entity descriptor. @@ -250,7 +254,10 @@ func (s *SAMLIdPServiceProviderService) configureEntityDescriptorPerPreset(sp ty // fetchAndSetEntityDescriptor is expected to return error if it fails // to fetch a valid entity descriptor. if err := s.fetchAndSetEntityDescriptor(sp); err != nil { - s.log.Debugf("Failed to fetch entity descriptor from %q: %v.", sp.GetEntityID(), err) + s.logger.DebugContext(context.Background(), "Failed to fetch entity descriptor", + "entity_id", sp.GetEntityID(), + "error", err, + ) // We aren't interested in checking error type as any occurrence of error // mean entity descriptor was not set. return trace.Wrap(s.generateAndSetEntityDescriptor(sp)) @@ -295,7 +302,10 @@ func (s *SAMLIdPServiceProviderService) fetchAndSetEntityDescriptor(sp types.SAM // generateAndSetEntityDescriptor generates and sets Service Provider entity descriptor // with ACS URL, Entity ID and unspecified NameID format. func (s *SAMLIdPServiceProviderService) generateAndSetEntityDescriptor(sp types.SAMLIdPServiceProvider) error { - s.log.Infof("Generating a default entity_descriptor with entity_id %q and acs_url %q.", sp.GetEntityID(), sp.GetACSURL()) + s.logger.InfoContext(context.Background(), "Generating a default entity_descriptor", + "entity_id", sp.GetEntityID(), + "acs_url", sp.GetACSURL(), + ) acsURL, err := url.Parse(sp.GetACSURL()) if err != nil { @@ -335,7 +345,9 @@ func (s *SAMLIdPServiceProviderService) embedAttributeMapping(sp types.SAMLIdPSe switch attrMapLen := len(sp.GetAttributeMapping()); { case attrMapLen == 0: if teleportSPSSODescriptorIndex == 0 { - s.log.Debugf("No custom attribute mapping values provided for %s. SAML assertion will default to uid and eduPersonAffiliate", sp.GetEntityID()) + s.logger.DebugContext(context.Background(), "No custom attribute mapping values provided,SAML assertion will default to uid and eduPersonAffiliate", + "entity_id", sp.GetEntityID(), + ) return nil } else { // delete Teleport SPSSODescriptor diff --git a/lib/services/local/secreports.go b/lib/services/local/secreports.go index c08ac60fe3a36..36307ce17d528 100644 --- a/lib/services/local/secreports.go +++ b/lib/services/local/secreports.go @@ -23,9 +23,7 @@ import ( "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/secreports" "github.com/gravitational/teleport/lib/backend" @@ -46,7 +44,6 @@ var ( // SecReportsService is the local implementation of the SecReports service. type SecReportsService struct { - log logrus.FieldLogger clock clockwork.Clock auditQuerySvc *generic.Service[*secreports.AuditQuery] securityReportSvc *generic.Service[*secreports.Report] @@ -99,7 +96,6 @@ func NewSecReportsService(backend backend.Backend, clock clockwork.Clock) (*SecR } return &SecReportsService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "secreports:local-service"}), clock: clock, auditQuerySvc: auditQuerySvc, securityReportSvc: securityReportSvc, diff --git a/lib/services/local/session.go b/lib/services/local/session.go index c2fde121ddce7..ce032ca6fc3b2 100644 --- a/lib/services/local/session.go +++ b/lib/services/local/session.go @@ -23,7 +23,6 @@ import ( "slices" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" @@ -315,7 +314,7 @@ func (s *IdentityService) DeleteAllSAMLIdPSessions(ctx context.Context) error { // WebSessions returns the web sessions manager. func (s *IdentityService) WebSessions() types.WebSessionInterface { - return &webSessions{backend: s.Backend, log: s.log} + return &webSessions{backend: s.Backend} } // Get returns the web session state described with req. @@ -423,12 +422,11 @@ func (r *webSessions) listLegacySessions(ctx context.Context) ([]types.WebSessio type webSessions struct { backend backend.Backend - log logrus.FieldLogger } // WebTokens returns the web token manager. func (s *IdentityService) WebTokens() types.WebTokenInterface { - return &webTokens{backend: s.Backend, log: s.log} + return &webTokens{backend: s.Backend} } // Get returns the web token described with req. @@ -504,7 +502,6 @@ func (r *webTokens) DeleteAll(ctx context.Context) error { type webTokens struct { backend backend.Backend - log logrus.FieldLogger } func webSessionKey(sessionID string) backend.Key { diff --git a/lib/services/local/sessiontracker.go b/lib/services/local/sessiontracker.go index ad6fc5e9d06f1..95ec34895d78e 100644 --- a/lib/services/local/sessiontracker.go +++ b/lib/services/local/sessiontracker.go @@ -20,10 +20,10 @@ package local import ( "context" + "log/slog" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" @@ -160,7 +160,7 @@ func (s *sessionTracker) getActiveSessionTrackers(ctx context.Context, filter *t for _, item := range noExpiry { if err := s.bk.Delete(ctx, item.Key); err != nil { if !trace.IsNotFound(err) { - logrus.WithError(err).Error("Failed to remove stale session tracker") + slog.ErrorContext(ctx, "Failed to remove stale session tracker", "error", err) } } } diff --git a/lib/services/local/status.go b/lib/services/local/status.go index 9af78ee0d4f2b..b6046e9bde34a 100644 --- a/lib/services/local/status.go +++ b/lib/services/local/status.go @@ -20,10 +20,10 @@ package local import ( "context" + "log/slog" "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -35,13 +35,13 @@ import ( // StatusService manages cluster status info. type StatusService struct { backend.Backend - log logrus.FieldLogger + logger *slog.Logger } func NewStatusService(bk backend.Backend) *StatusService { return &StatusService{ Backend: bk, - log: logrus.WithField(teleport.ComponentKey, "status"), + logger: slog.With(teleport.ComponentKey, "status"), } } @@ -68,7 +68,7 @@ func (s *StatusService) GetClusterAlerts(ctx context.Context, query types.GetClu filtered := alerts[:0] for _, alert := range alerts { if err := alert.CheckAndSetDefaults(); err != nil { - s.log.Warnf("Skipping invalid cluster alert: %v", err) + s.logger.WarnContext(ctx, "Skipping invalid cluster alert", "error", err) } if !query.Match(alert) { diff --git a/lib/services/local/user_login_state.go b/lib/services/local/user_login_state.go index 76e12b6b4c95d..a73c77b238dc4 100644 --- a/lib/services/local/user_login_state.go +++ b/lib/services/local/user_login_state.go @@ -22,9 +22,7 @@ import ( "context" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/userloginstate" "github.com/gravitational/teleport/lib/backend" @@ -38,7 +36,6 @@ const ( // UserLoginStateService manages user login state resources in the Backend. type UserLoginStateService struct { - log logrus.FieldLogger svc *generic.Service[*userloginstate.UserLoginState] } @@ -56,7 +53,6 @@ func NewUserLoginStateService(b backend.Backend) (*UserLoginStateService, error) } return &UserLoginStateService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "user-login-state:local-service"}), svc: svc, }, nil } diff --git a/lib/services/local/users.go b/lib/services/local/users.go index 760634dfa65b3..1c4790bcda886 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -26,6 +26,7 @@ import ( "encoding/base64" "encoding/json" "io" + "log/slog" "sort" "strings" "sync" @@ -37,7 +38,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" "golang.org/x/sync/errgroup" @@ -65,43 +65,30 @@ var GlobalSessionDataMaxEntries = 5000 // arbitrary // user accounts as well type IdentityService struct { backend.Backend - log logrus.FieldLogger + logger *slog.Logger bcryptCost int notificationsSvc *NotificationsService } -// TODO(rudream): Rename to NewIdentityService. +// TODO(tross): DELETE ONCE e is updated to use NewIdentityService // NewIdentityServiceV2 returns a new instance of IdentityService object func NewIdentityServiceV2(backend backend.Backend) (*IdentityService, error) { - notificationsSvc, err := NewNotificationsService(backend, backend.Clock()) - if err != nil { - return nil, trace.Wrap(err) - } - - return &IdentityService{ - Backend: backend, - log: logrus.WithField(teleport.ComponentKey, "identity"), - bcryptCost: bcrypt.DefaultCost, - notificationsSvc: notificationsSvc, - }, nil + return NewIdentityService(backend) } -// TODO(rudream): Remove once NewIdentityServiceV2 is merged. // NewIdentityService returns a new instance of IdentityService object -func NewIdentityService(backend backend.Backend) *IdentityService { +func NewIdentityService(backend backend.Backend) (*IdentityService, error) { notificationsSvc, err := NewNotificationsService(backend, backend.Clock()) - - log := logrus.WithField(teleport.ComponentKey, "identity") if err != nil { - log.Warnf("error initializing notifications service with identity service: %v", err) + return nil, trace.Wrap(err) } return &IdentityService{ Backend: backend, - log: log, + logger: slog.With(teleport.ComponentKey, "identity"), bcryptCost: bcrypt.DefaultCost, notificationsSvc: notificationsSvc, - } + }, nil } // NewTestIdentityService returns a new instance of IdentityService object to be @@ -201,7 +188,10 @@ func (s *IdentityService) streamUsersWithSecrets(itemStream stream.Stream[backen collectorStream := stream.FilterMap(itemStream, func(item backend.Item) (collector, bool) { name, suffix, err := splitUsernameAndSuffix(item.Key) if err != nil { - s.log.Warnf("Failed to extract name/suffix for user item at %q: %v", item.Key, err) + s.logger.WarnContext(context.Background(), "Failed to extract name/suffix for user item", + "key", item.Key, + "error", err, + ) return collector{}, false } @@ -242,7 +232,10 @@ func (s *IdentityService) streamUsersWithSecrets(itemStream stream.Stream[backen userStream := stream.FilterMap(collectorStream, func(c collector) (*types.UserV2, bool) { user, err := userFromUserItems(c.name, c.items) if err != nil { - s.log.Warnf("Failed to build user %q from user item aggregator: %v", c.name, err) + s.logger.WarnContext(context.Background(), "Failed to build user from user item aggregator", + "user", c.name, + "error", err, + ) return nil, false } @@ -263,7 +256,10 @@ func (s *IdentityService) streamUsersWithoutSecrets(itemStream stream.Stream[bac user, err := services.UnmarshalUser(item.Value, services.WithRevision(item.Revision)) if err != nil { - s.log.Warnf("Failed to unmarshal user at %q: %v", item.Key, err) + s.logger.WarnContext(context.Background(), "Failed to unmarshal user", + "key", item.Key, + "error", err, + ) return nil, false } @@ -874,6 +870,7 @@ func (s *IdentityService) DeleteUserLoginAttempts(user string) error { // `PasswordState` status flag accordingly. Returns an error if the user doesn't // exist. func (s *IdentityService) UpsertPassword(user string, password []byte) error { + ctx := context.TODO() if user == "" { return trace.BadParameter("missing username") } @@ -891,7 +888,7 @@ func (s *IdentityService) UpsertPassword(user string, password []byte) error { } _, err = s.UpdateAndSwapUser( - context.TODO(), + ctx, user, false, /*withSecrets*/ func(u types.User) (bool, error) { @@ -900,10 +897,10 @@ func (s *IdentityService) UpsertPassword(user string, password []byte) error { }) if err != nil { // Don't let the password state flag change fail the entire operation. - s.log. - WithError(err). - WithField("user", user). - Warn("Failed to set password state") + s.logger.WarnContext(ctx, "Failed to set password state", + "user", user, + "error", err, + ) } return nil @@ -924,7 +921,7 @@ func (s *IdentityService) DeletePassword(ctx context.Context, user string) error } if _, err := s.UpdateAndSwapUser( - context.TODO(), + ctx, user, false, /*withSecrets*/ func(u types.User) (bool, error) { @@ -933,10 +930,10 @@ func (s *IdentityService) DeletePassword(ctx context.Context, user string) error }, ); err != nil { // Don't let the password state flag change fail the entire operation. - s.log. - WithError(err). - WithField("user", user). - Warn("Failed to set password state") + s.logger.WarnContext(ctx, "Failed to set password state", + "user", user, + "error", err, + ) } // Now is the time to return the delete operation, if any. @@ -987,7 +984,7 @@ func (s *IdentityService) UpsertWebauthnLocalAuth(ctx context.Context, user stri // lib/auth/webauthn is prepared to deal with eventual inconsistencies // between "web/users/.../webauthnlocalauth" and "webauthn/users/" keys. if err := s.Delete(ctx, wlaKey); err != nil { - s.log.WithError(err).Warn("Failed to undo WebauthnLocalAuth update") + s.logger.WarnContext(ctx, "Failed to undo WebauthnLocalAuth update", "error", err) } return trace.Wrap(err, "writing webauthn user") } @@ -1208,7 +1205,7 @@ func (s *IdentityService) UpsertMFADevice(ctx context.Context, user string, d *t return trace.Wrap(err) } if err := s.upsertUserStatusMFADevice(ctx, user); err != nil { - s.log.WithError(err).Warn("Unable to update user status after adding MFA device") + s.logger.WarnContext(ctx, "Unable to update user status after adding MFA device", "error", err) } return nil } @@ -1308,7 +1305,7 @@ func (s *IdentityService) buildAndSetWeakestMFADeviceKind(ctx context.Context, u } state, err := s.buildWeakestMFADeviceKind(ctx, user.GetName(), upsertingMFA...) if err != nil { - s.log.WithError(err).Warn("Failed to determine weakest mfa device kind for user") + s.logger.WarnContext(ctx, "Failed to determine weakest mfa device kind for user", "error", err) return } user.SetWeakestDevice(state) @@ -1370,7 +1367,7 @@ func (s *IdentityService) DeleteMFADevice(ctx context.Context, user, id string) return trace.Wrap(err) } if err := s.upsertUserStatusMFADevice(ctx, user); err != nil { - s.log.WithError(err).Warn("Unable to update user status after deleting MFA device") + s.logger.WarnContext(ctx, "Unable to update user status after deleting MFA device", "error", err) } return nil } @@ -1607,10 +1604,10 @@ func (s *IdentityService) GetOIDCConnectors(ctx context.Context, withSecrets boo for _, item := range result.Items { conn, err := services.UnmarshalOIDCConnector(item.Value, services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { - logrus. - WithError(err). - WithField("key", item.Key). - Errorf("Error unmarshaling OIDC Connector") + s.logger.ErrorContext(ctx, "Error unmarshaling OIDC Connector", + "key", item.Key, + "error", err, + ) continue } if !withSecrets { @@ -1775,10 +1772,10 @@ func (s *IdentityService) GetSAMLConnectors(ctx context.Context, withSecrets boo for _, item := range result.Items { conn, err := services.UnmarshalSAMLConnector(item.Value, services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { - logrus. - WithError(err). - WithField("key", item.Key). - Errorf("Error unmarshaling SAML Connector") + s.logger.ErrorContext(ctx, "Error unmarshaling SAML Connector", + "key", item.Key, + "error", err, + ) continue } if !withSecrets { @@ -2016,10 +2013,10 @@ func (s *IdentityService) GetGithubConnectors(ctx context.Context, withSecrets b for _, item := range result.Items { connector, err := services.UnmarshalGithubConnector(item.Value, services.WithRevision(item.Revision)) if err != nil { - logrus. - WithError(err). - WithField("key", item.Key). - Errorf("Error unmarshaling GitHub Connector") + s.logger.ErrorContext(ctx, "Error unmarshaling GitHub Connector", + "key", item.Key, + "error", err, + ) continue } if !withSecrets { diff --git a/lib/services/matchers.go b/lib/services/matchers.go index e625d4ca59fab..84e8ba87bd793 100644 --- a/lib/services/matchers.go +++ b/lib/services/matchers.go @@ -19,10 +19,11 @@ package services import ( + "context" + "log/slog" "slices" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" @@ -115,8 +116,11 @@ func MatchResourceLabels(matchers []ResourceMatcher, labels map[string]string) b } match, _, err := MatchLabels(matcher.Labels, labels) if err != nil { - logrus.WithError(err).Errorf("Failed to match labels %v: %v.", - matcher.Labels, labels) + slog.ErrorContext(context.Background(), "Failed to match labels", + "error", err, + "matcher_labels", matcher.Labels, + "resource_labels", labels, + ) return false } if match { diff --git a/lib/services/parser.go b/lib/services/parser.go index 8d70f0f53b8fe..1ea6b6d7cdd60 100644 --- a/lib/services/parser.go +++ b/lib/services/parser.go @@ -19,14 +19,14 @@ package services import ( + "context" "fmt" - "io" + "log/slog" "slices" "strings" "time" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/vulcand/predicate" "github.com/vulcand/predicate/builder" @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/types/wrappers" "github.com/gravitational/teleport/lib/session" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/utils/typical" ) @@ -231,34 +232,41 @@ func NewActionsParser(ctx RuleContext) (predicate.Parser, error) { // NewLogActionFn creates logger functions func NewLogActionFn(ctx RuleContext) interface{} { l := &LogAction{ctx: ctx} - writer, ok := ctx.(io.Writer) - if ok && writer != nil { - l.writer = writer - } + return l.Log } // LogAction represents action that will emit log entry // when specified in the actions of a matched rule type LogAction struct { - ctx RuleContext - writer io.Writer + ctx RuleContext } -// Log logs with specified level and formatting string with arguments -func (l *LogAction) Log(level, format string, args ...interface{}) predicate.BoolPredicate { +// Log logs with specified level and message string and attributes +func (l *LogAction) Log(level, msg string, args ...any) predicate.BoolPredicate { return func() bool { - ilevel, err := log.ParseLevel(level) - if err != nil { - ilevel = log.DebugLevel + slevel := slog.LevelDebug + switch strings.ToLower(level) { + case "error": + slevel = slog.LevelError + case "warn", "warning": + slevel = slog.LevelWarn + case "info": + slevel = slog.LevelInfo + case "debug": + slevel = slog.LevelDebug + case "trace": + slevel = logutils.TraceLevel } - var writer io.Writer - if l.writer != nil { - writer = l.writer - } else { - writer = log.StandardLogger().WriterLevel(ilevel) + + ctx := context.Background() + // Expicitly check whether logging is enabled for the level + // to avoid formatting the message if the log won't be sampled. + if !slog.Default().Handler().Enabled(ctx, slevel) { + //nolint:sloglint // msg cannot be constant + slog.Log(context.Background(), slevel, fmt.Sprintf(msg, args...)) } - writer.Write([]byte(fmt.Sprintf(format, args...))) + return true } } diff --git a/lib/services/presets.go b/lib/services/presets.go index ec3f8ad529c9d..9f59ff004073e 100644 --- a/lib/services/presets.go +++ b/lib/services/presets.go @@ -19,10 +19,11 @@ package services import ( + "context" + "log/slog" "slices" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/constants" @@ -801,7 +802,7 @@ func defaultAllowAccountAssignments(enterprise bool) map[string][]types.Identity // AddRoleDefaults adds default role attributes to a preset role. // Only attributes whose resources are not already defined (either allowing or denying) are added. -func AddRoleDefaults(role types.Role) (types.Role, error) { +func AddRoleDefaults(ctx context.Context, role types.Role) (types.Role, error) { changed := false oldLabels := role.GetAllLabels() @@ -855,7 +856,10 @@ func AddRoleDefaults(role types.Role) (types.Role, error) { continue } - log.Debugf("Adding default allow rule %v for role %q", defaultRule, role.GetName()) + slog.DebugContext(ctx, "Adding default allow rule to role", + "rule", defaultRule, + "role", role.GetName(), + ) rules := role.GetRules(types.Allow) rules = append(rules, defaultRule) role.SetRules(types.Allow, rules) diff --git a/lib/services/presets_test.go b/lib/services/presets_test.go index 3e4f12c5d4084..8e0490c82f714 100644 --- a/lib/services/presets_test.go +++ b/lib/services/presets_test.go @@ -19,6 +19,7 @@ package services import ( + "context" "testing" "github.com/google/go-cmp/cmp" @@ -639,7 +640,7 @@ func TestAddRoleDefaults(t *testing.T) { }) } - role, err := AddRoleDefaults(test.role) + role, err := AddRoleDefaults(context.Background(), test.role) test.expectedErr(t, err) require.Empty(t, cmp.Diff(role, test.expected)) diff --git a/lib/services/readonly/readonly.go b/lib/services/readonly/readonly.go index c4ed3185ace66..744f2b4cd3a5c 100644 --- a/lib/services/readonly/readonly.go +++ b/lib/services/readonly/readonly.go @@ -71,6 +71,7 @@ func sealAuthPreference(p types.AuthPreference) AuthPreference { type ClusterNetworkingConfig interface { GetCaseInsensitiveRouting() bool GetWebIdleTimeout() time.Duration + GetRoutingStrategy() types.RoutingStrategy Clone() types.ClusterNetworkingConfig } diff --git a/lib/services/role.go b/lib/services/role.go index 37418d27c41a0..b9e3e04d83816 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -35,7 +35,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" jsoniter "github.com/json-iterator/go" - log "github.com/sirupsen/logrus" "github.com/vulcand/predicate" "golang.org/x/crypto/ssh" @@ -51,6 +50,7 @@ import ( "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" awsutils "github.com/gravitational/teleport/lib/utils/aws" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/utils/parse" ) @@ -1598,7 +1598,7 @@ func (set RoleSet) CheckGCPServiceAccounts(ttl time.Duration, overrideTTL bool) // //nolint:revive // Because we want this to be IdP. func (set RoleSet) CheckAccessToSAMLIdP(authPref readonly.AuthPreference, state AccessState) error { - _, debugf := rbacDebugLogger() + ctx := context.Background() if authPref != nil { if !authPref.IsSAMLIdPEnabled() { @@ -1607,7 +1607,7 @@ func (set RoleSet) CheckAccessToSAMLIdP(authPref readonly.AuthPreference, state } if state.MFARequired == MFARequiredAlways && !state.MFAVerified { - debugf("Access to SAML IdP denied, cluster requires per-session MFA") + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access to SAML IdP denied, cluster requires per-session MFA") return trace.Wrap(ErrSessionMFARequired) } @@ -1627,7 +1627,10 @@ func (set RoleSet) CheckAccessToSAMLIdP(authPref readonly.AuthPreference, state } if !mfaAllowed && options.RequireMFAType.IsSessionMFARequired() { - debugf("Access to SAML IdP denied, role %q requires per-session MFA", role.GetName()) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access to SAML IdP denied, role requires per-session MFA", + slog.String("role", role.GetName()), + ) + return trace.Wrap(ErrSessionMFARequired) } } @@ -2539,19 +2542,7 @@ type AccessCheckable interface { GetAllLabels() map[string]string } -// rbacDebugLogger creates a debug logger for Teleport's RBAC component. -// It also returns a flag indicating whether debug logging is enabled, -// allowing the RBAC system to generate more verbose errors in debug mode. -func rbacDebugLogger() (debugEnabled bool, debugf func(format string, args ...interface{})) { - debugEnabled = log.IsLevelEnabled(log.TraceLevel) - debugf = func(format string, args ...interface{}) {} - - if debugEnabled { - debugf = log.WithField(teleport.ComponentKey, teleport.ComponentRBAC).Tracef - } - - return -} +var rbacLogger = logutils.NewPackageLogger(teleport.ComponentKey, teleport.ComponentRBAC) // resourceRequiresLabelMatching decides if a resource requires lapel matching // when making RBAC access decisions. @@ -2567,13 +2558,18 @@ func resourceRequiresLabelMatching(r AccessCheckable) bool { } func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state AccessState, matchers ...RoleMatcher) error { - // Note: logging in this function only happens in debug mode. This is because + // Note: logging in this function only happens in trace mode. This is because // adding logging to this function (which is called on every resource returned // by the backend) can slow down this function by 50x for large clusters! - isDebugEnabled, debugf := rbacDebugLogger() + ctx := context.Background() + logger := rbacLogger + isLoggingEnabled := logger.Handler().Enabled(ctx, logutils.TraceLevel) + if isLoggingEnabled { + logger.With("resource_kind", r.GetKind(), "resource_name", r.GetName()) + } if !state.MFAVerified && state.MFARequired == MFARequiredAlways { - debugf("Access to %v %q denied, cluster requires per-session MFA", r.GetKind(), r.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, cluster requires per-session MFA") return ErrSessionMFARequired } @@ -2601,18 +2597,21 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state continue } if requiresLabelMatching { - matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Deny, role, traits, r, isDebugEnabled) + matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Deny, role, traits, r, isLoggingEnabled) if err != nil { return trace.Wrap(err) } if matchLabels { - debugf("Access to %v %q denied, deny rule in role %q matched; match(namespace=%v, %s)", - r.GetKind(), r.GetName(), role.GetName(), namespaceMessage, labelsMessage) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, deny rule in role matched", + slog.String("role", role.GetName()), + slog.String("namespace_message", namespaceMessage), + slog.String("label_message", labelsMessage), + ) return trace.AccessDenied("access to %v denied. User does not have permissions. %v", r.GetKind(), additionalDeniedMessage) } } else { - debugf("Role label matching skipped for %v %q", r.GetKind(), r.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Role label matching skipped") } // Deny rules are greedy on purpose. They will always match if // at least one of the matchers returns true. @@ -2621,8 +2620,10 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state return trace.Wrap(err) } if matchMatchers { - debugf("Access to %v %q denied, deny rule in role %q matched; match(matcher=%v)", - r.GetKind(), r.GetName(), role.GetName(), matchersMessage) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, deny rule in role matched", + slog.String("role", role.GetName()), + slog.Any("matcher_message", matchersMessage), + ) return trace.AccessDenied("access to %v denied. User does not have permissions. %v", r.GetKind(), additionalDeniedMessage) } @@ -2640,7 +2641,7 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state for _, role := range set { matchNamespace, namespaceMessage := MatchNamespace(role.GetNamespaces(types.Allow), namespace) if !matchNamespace { - if isDebugEnabled { + if isLoggingEnabled { errs = append(errs, trace.AccessDenied("role=%v, match(namespace=%v)", role.GetName(), namespaceMessage)) } @@ -2648,20 +2649,20 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state } if requiresLabelMatching { - matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Allow, role, traits, r, isDebugEnabled) + matchLabels, labelsMessage, err := checkRoleLabelsMatch(types.Allow, role, traits, r, isLoggingEnabled) if err != nil { return trace.Wrap(err) } if !matchLabels { - if isDebugEnabled { + if isLoggingEnabled { errs = append(errs, trace.AccessDenied("role=%v, match(%s)", role.GetName(), labelsMessage)) } continue } } else { - debugf("Role label matching skipped for %v %q", r.GetKind(), r.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Role label matching skipped for resource") } // Allow rules are not greedy. They will match only if all of the @@ -2671,7 +2672,7 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state return trace.Wrap(err) } if !matchMatchers { - if isDebugEnabled { + if isLoggingEnabled { errs = append(errs, fmt.Errorf("role=%v, match(matchers=%v)", role.GetName(), matchers)) } @@ -2689,37 +2690,43 @@ func (set RoleSet) checkAccess(r AccessCheckable, traits wrappers.Traits, state // ensure the access is permitted. if mfaAllowed && deviceAllowed { - debugf("Access to %v %q granted, allow rule in role %q matched.", - r.GetKind(), r.GetName(), role.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource granted, allow rule in role matched", + slog.String("role", role.GetName()), + ) return nil } // MFA verification. if !mfaAllowed && role.GetOptions().RequireMFAType.IsSessionMFARequired() { - debugf("Access to %v %q denied, role %q requires per-session MFA", - r.GetKind(), r.GetName(), role.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, role requires per-session MFA", + slog.String("role", role.GetName()), + ) return ErrSessionMFARequired } // Device verification. if !deviceAllowed && role.GetOptions().DeviceTrustMode == constants.DeviceTrustModeRequired { - debugf("Access to %v %q denied, role %q requires a trusted device", - r.GetKind(), r.GetName(), role.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, role requires a trusted device", + slog.String("role", role.GetName()), + ) return ErrTrustedDeviceRequired } // Current role allows access, but keep looking for a more restrictive // setting. allowed = true - debugf("Access to %v %q granted, allow rule in role %q matched.", - r.GetKind(), r.GetName(), role.GetName()) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource granted, allow rule in role matched", + slog.String("role", role.GetName()), + ) } if allowed { return nil } - debugf("Access to %v %q denied, no allow rule matched; %v", r.GetKind(), r.GetName(), errs) + logger.LogAttrs(ctx, logutils.TraceLevel, "Access to resource denied, no allow rule matched", + slog.Any("errors", errs), + ) return trace.AccessDenied("access to %v denied. User does not have permissions. %v", r.GetKind(), additionalDeniedMessage) } @@ -3224,6 +3231,8 @@ func (a *accessExplicitlyDenied) Unwrap() error { } func (set RoleSet) checkAccessToRuleImpl(p checkAccessParams) (err error) { + ctx := context.Background() + // Every unknown error, which could be due to a bad role or an expression // that can't parse, should be considered an explicit denial. explicitDeny := true @@ -3247,10 +3256,13 @@ func (set RoleSet) checkAccessToRuleImpl(p checkAccessParams) (err error) { return trace.Wrap(err) } if matched { - log.WithFields(log.Fields{ - teleport.ComponentKey: teleport.ComponentRBAC, - }).Tracef("Access to %v %v in namespace %v denied to %v: deny rule matched.", - p.verb, p.resource, p.namespace, role.GetName()) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access denied, deny rule matched", + slog.String("verb", p.verb), + slog.String("resource", p.resource), + slog.String("namespace", p.namespace), + slog.String("role", role.GetName()), + ) + return trace.AccessDenied("access denied to perform action %q on %q", p.verb, p.resource) } } @@ -3270,10 +3282,12 @@ func (set RoleSet) checkAccessToRuleImpl(p checkAccessParams) (err error) { } } - log.WithFields(log.Fields{ - teleport.ComponentKey: teleport.ComponentRBAC, - }).Tracef("Access to %v %v in namespace %v denied to %v: no allow rule matched.", - p.verb, p.resource, p.namespace, set) + rbacLogger.LogAttrs(ctx, logutils.TraceLevel, "Access denied, no allow rule matched", + slog.String("verb", p.verb), + slog.String("resource", p.resource), + slog.String("namespace", p.namespace), + slog.Any("set", set), + ) // At this point no deny rule has matched and there are no more unknown // errors, so this is only an implicit denial. diff --git a/lib/services/role_test.go b/lib/services/role_test.go index 7c85f6a07e0a8..13f2cc3f18c72 100644 --- a/lib/services/role_test.go +++ b/lib/services/role_test.go @@ -19,7 +19,6 @@ package services import ( - "bytes" "cmp" "context" "encoding/json" @@ -2180,27 +2179,13 @@ func makeAccessCheckerWithRoleSet(roleSet RoleSet) AccessChecker { return NewAccessCheckerWithRoleSet(accessInfo, "clustername", roleSet) } -// testContext overrides context and captures log writes in action -type testContext struct { - Context - // Buffer captures log writes - buffer *bytes.Buffer -} - -// Write is implemented explicitly to avoid collision -// of String methods when embedding -func (t *testContext) Write(data []byte) (int, error) { - return t.buffer.Write(data) -} - func TestCheckRuleAccess(t *testing.T) { type check struct { - hasAccess bool - verb string - namespace string - rule string - context testContext - matchBuffer string + hasAccess bool + verb string + namespace string + rule string + context Context } testCases := []struct { name string @@ -2320,9 +2305,6 @@ func TestCheckRuleAccess(t *testing.T) { Resources: []string{types.KindSession}, Verbs: []string{types.VerbRead}, Where: `contains(user.spec.traits["group"], "prod")`, - Actions: []string{ - `log("info", "4 - tc match for user %v", user.metadata.name)`, - }, }, }, }, @@ -2333,17 +2315,14 @@ func TestCheckRuleAccess(t *testing.T) { {rule: types.KindSession, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: false}, {rule: types.KindSession, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: false}, { - context: testContext{ - buffer: &bytes.Buffer{}, - Context: Context{ - User: &types.UserV2{ - Metadata: types.Metadata{ - Name: "bob", - }, - Spec: types.UserSpecV2{ - Traits: map[string][]string{ - "group": {"dev", "prod"}, - }, + context: Context{ + User: &types.UserV2{ + Metadata: types.Metadata{ + Name: "bob", + }, + Spec: types.UserSpecV2{ + Traits: map[string][]string{ + "group": {"dev", "prod"}, }, }, }, @@ -2354,14 +2333,11 @@ func TestCheckRuleAccess(t *testing.T) { hasAccess: true, }, { - context: testContext{ - buffer: &bytes.Buffer{}, - Context: Context{ - User: &types.UserV2{ - Spec: types.UserSpecV2{ - Traits: map[string][]string{ - "group": {"dev"}, - }, + context: Context{ + User: &types.UserV2{ + Spec: types.UserSpecV2{ + Traits: map[string][]string{ + "group": {"dev"}, }, }, }, @@ -2389,9 +2365,6 @@ func TestCheckRuleAccess(t *testing.T) { Resources: []string{types.KindRole}, Verbs: []string{types.VerbRead}, Where: `equals(resource.metadata.labels["team"], "dev")`, - Actions: []string{ - `log("error", "4 - tc match")`, - }, }, }, }, @@ -2402,13 +2375,10 @@ func TestCheckRuleAccess(t *testing.T) { {rule: types.KindRole, verb: types.VerbRead, namespace: apidefaults.Namespace, hasAccess: false}, {rule: types.KindRole, verb: types.VerbList, namespace: apidefaults.Namespace, hasAccess: false}, { - context: testContext{ - buffer: &bytes.Buffer{}, - Context: Context{ - Resource: &types.RoleV6{ - Metadata: types.Metadata{ - Labels: map[string]string{"team": "dev"}, - }, + context: Context{ + Resource: &types.RoleV6{ + Metadata: types.Metadata{ + Labels: map[string]string{"team": "dev"}, }, }, }, @@ -2439,9 +2409,6 @@ func TestCheckRuleAccess(t *testing.T) { Resources: []string{types.KindRole}, Verbs: []string{types.VerbRead}, Where: `equals(resource.metadata.labels["team"], "dev")`, - Actions: []string{ - `log("info", "matched more specific rule")`, - }, }, }, }, @@ -2450,21 +2417,17 @@ func TestCheckRuleAccess(t *testing.T) { }, checks: []check{ { - context: testContext{ - buffer: &bytes.Buffer{}, - Context: Context{ - Resource: &types.RoleV6{ - Metadata: types.Metadata{ - Labels: map[string]string{"team": "dev"}, - }, + context: Context{ + Resource: &types.RoleV6{ + Metadata: types.Metadata{ + Labels: map[string]string{"team": "dev"}, }, }, }, - rule: types.KindRole, - verb: types.VerbRead, - namespace: apidefaults.Namespace, - hasAccess: true, - matchBuffer: "more specific rule", + rule: types.KindRole, + verb: types.VerbRead, + namespace: apidefaults.Namespace, + hasAccess: true, }, }, }, @@ -2486,9 +2449,6 @@ func TestCheckRuleAccess(t *testing.T) { } else { require.True(t, trace.IsAccessDenied(result), comment) } - if check.matchBuffer != "" { - require.Contains(t, check.context.buffer.String(), check.matchBuffer, comment) - } } } } @@ -2498,7 +2458,7 @@ func TestDefaultImplicitRules(t *testing.T) { hasAccess bool verb string rule string - context testContext + context Context } testCases := []struct { name string diff --git a/lib/services/saml.go b/lib/services/saml.go index ad8e2dccaa36c..ab6988047e0a6 100644 --- a/lib/services/saml.go +++ b/lib/services/saml.go @@ -24,6 +24,7 @@ import ( "crypto/x509/pkix" "encoding/base64" "encoding/xml" + "log/slog" "net/http" "strings" "time" @@ -33,7 +34,6 @@ import ( saml2 "github.com/russellhaering/gosaml2" samltypes "github.com/russellhaering/gosaml2/types" dsig "github.com/russellhaering/goxmldsig" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" @@ -87,7 +87,11 @@ func ValidateSAMLConnector(sc types.SAMLConnector, rg RoleGetter) error { } sc.SetEntityDescriptor(entityDescriptor) - log.Debugf("[SAML] Successfully fetched entity descriptor from %v for connector %v", url, sc.GetName()) + slog.DebugContext(context.Background(), " Successfully fetched entity descriptor for connector", + teleport.ComponentKey, teleport.ComponentSAML, + "entity_descriptor_url", url, + "connector", sc.GetName(), + ) } if ed := sc.GetEntityDescriptor(); ed != "" { @@ -173,9 +177,12 @@ func ValidateSAMLConnector(sc types.SAMLConnector, rg RoleGetter) error { sc.SetMFASettings(mfa) } - log.Debugf("[SAML] SSO: %v", sc.GetSSO()) - log.Debugf("[SAML] Issuer: %v", sc.GetIssuer()) - log.Debugf("[SAML] ACS: %v", sc.GetAssertionConsumerService()) + slog.DebugContext(context.Background(), "connector validated", + teleport.ComponentKey, teleport.ComponentSAML, + "sso", sc.GetSSO(), + "issuer", sc.GetIssuer(), + "acs", sc.GetAssertionConsumerService(), + ) return nil } @@ -271,7 +278,9 @@ func GetSAMLServiceProvider(sc types.SAMLConnector, clock clockwork.Clock) (*sam // Case 1: Only the signing key pair is set. This means that SAML encryption is not expected // and we therefore configure the main key that gets used for all operations as the signing key. // This is done because gosaml2 mandates an encryption key even if not used. - log.Info("No assertion_key_pair was detected. Falling back to signing key for all SAML operations.") + slog.InfoContext(context.Background(), "No assertion_key_pair was detected, falling back to signing key for all SAML operations", + teleport.ComponentKey, teleport.ComponentSAML, + ) keyStore, err = utils.ParseKeyStorePEM(signingKeyPair.PrivateKey, signingKeyPair.Cert) signingKeyStore = keyStore if err != nil { @@ -281,7 +290,9 @@ func GetSAMLServiceProvider(sc types.SAMLConnector, clock clockwork.Clock) (*sam // Case 2: An encryption keypair is configured. This means that encrypted SAML responses are expected. // Since gosaml2 always uses the main key for encryption, we set it to assertion_key_pair. // To handle signing correctly, we now instead set the optional signing key in gosaml2 to signing_key_pair. - log.Info("Detected assertion_key_pair and configured it to decrypt SAML responses.") + slog.InfoContext(context.Background(), "Detected assertion_key_pair and configured it to decrypt SAML responses", + teleport.ComponentKey, teleport.ComponentSAML, + ) keyStore, err = utils.ParseKeyStorePEM(encryptionKeyPair.PrivateKey, encryptionKeyPair.Cert) if err != nil { return nil, trace.Wrap(err, "failed to parse certificate or private key defined in assertion_key_pair") @@ -313,9 +324,7 @@ func GetSAMLServiceProvider(sc types.SAMLConnector, clock clockwork.Clock) (*sam // be used. switch sc.GetProvider() { case teleport.ADFS, teleport.JumpCloud: - log.WithFields(log.Fields{ - teleport.ComponentKey: teleport.ComponentSAML, - }).Debug("Setting ADFS/JumpCloud values.") + slog.DebugContext(context.Background(), "Setting ADFS/JumpCloud values", teleport.ComponentKey, teleport.ComponentSAML) if sp.SignAuthnRequests { sp.SignAuthnRequestsCanonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList(dsig.DefaultPrefix) diff --git a/lib/services/saml_idp_service_provider.go b/lib/services/saml_idp_service_provider.go index 3d5882c5e5e67..51c60fa1e807f 100644 --- a/lib/services/saml_idp_service_provider.go +++ b/lib/services/saml_idp_service_provider.go @@ -21,6 +21,7 @@ package services import ( "context" "fmt" + "log/slog" "net/url" "slices" "strings" @@ -28,7 +29,6 @@ import ( "github.com/crewjam/saml" "github.com/crewjam/saml/samlsp" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/utils" @@ -139,7 +139,10 @@ func FilterSAMLEntityDescriptor(ed *saml.EntityDescriptor, quiet bool) error { filtered := slices.DeleteFunc(ed.SPSSODescriptors[i].AssertionConsumerServices, func(acs saml.IndexedEndpoint) bool { if err := ValidateAssertionConsumerService(acs); err != nil { if !quiet { - log.Warnf("AssertionConsumerService binding for entity %q is invalid and will be ignored: %v", ed.EntityID, err) + slog.WarnContext(context.Background(), "AssertionConsumerService binding for entity is invalid and will be ignored", + "entity_id", ed.EntityID, + "error", err, + ) } return true } diff --git a/lib/services/semaphore.go b/lib/services/semaphore.go index 52211acbfa33c..4e1a672423ced 100644 --- a/lib/services/semaphore.go +++ b/lib/services/semaphore.go @@ -20,12 +20,12 @@ package services import ( "context" + "log/slog" "sync" "time" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/retryutils" @@ -200,10 +200,17 @@ func (l *SemaphoreLock) keepAlive(ctx context.Context) { defer cancel() err = l.cfg.Service.CancelSemaphoreLease(cancelContext, lease) if err != nil { - log.Warnf("Failed to cancel semaphore lease %s/%s: %v", lease.SemaphoreKind, lease.SemaphoreName, err) + slog.WarnContext(cancelContext, "Failed to cancel semaphore lease %s/%s: %v", + "semaphore_kind", lease.SemaphoreKind, + "semaphore_name", lease.SemaphoreName, + "error", err, + ) } } else { - log.Errorf("Semaphore lease expired: %s/%s", lease.SemaphoreKind, lease.SemaphoreName) + slog.ErrorContext(context.Background(), "Semaphore lease expired", + "semaphore_kind", lease.SemaphoreKind, + "semaphore_name", lease.SemaphoreName, + ) } }() Outer: @@ -219,7 +226,11 @@ Outer: leaseCancel() // semaphore and/or lease no longer exist; best to log the error // and exit immediately. - log.Warnf("Halting keepalive on semaphore %s/%s early: %v", lease.SemaphoreKind, lease.SemaphoreName, err) + slog.WarnContext(leaseContext, "Halting keepalive on semaphore", + "semaphore_kind", lease.SemaphoreKind, + "semaphore_name", lease.SemaphoreName, + "error", err, + ) nodrop = true return } @@ -233,7 +244,11 @@ Outer: } continue Outer } - log.Debugf("Failed to renew semaphore lease %s/%s: %v", lease.SemaphoreKind, lease.SemaphoreName, err) + slog.DebugContext(leaseContext, "Failed to renew semaphore lease", + "semaphore_kind", lease.SemaphoreKind, + "semaphore_name", lease.SemaphoreName, + "error", err, + ) l.retry.Inc() select { case <-l.retry.After(): diff --git a/lib/services/simple/access_list.go b/lib/services/simple/access_list.go index 9effb4475c973..f8b8b78bdbe44 100644 --- a/lib/services/simple/access_list.go +++ b/lib/services/simple/access_list.go @@ -23,9 +23,7 @@ import ( "time" "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/accesslist" "github.com/gravitational/teleport/lib/backend" @@ -46,7 +44,6 @@ const ( // AccessListService is a simple access list backend service for use specifically by the cache. type AccessListService struct { - log logrus.FieldLogger service *generic.Service[*accesslist.AccessList] memberService *generic.Service[*accesslist.AccessListMember] reviewService *generic.Service[*accesslist.Review] @@ -93,7 +90,6 @@ func NewAccessListService(b backend.Backend) (*AccessListService, error) { } return &AccessListService{ - log: logrus.WithFields(logrus.Fields{teleport.ComponentKey: "access-list:simple-service"}), service: service, memberService: memberService, reviewService: reviewService, diff --git a/lib/services/suite/suite.go b/lib/services/suite/suite.go index ad2cb4695b3f2..3c1a445480166 100644 --- a/lib/services/suite/suite.go +++ b/lib/services/suite/suite.go @@ -22,6 +22,7 @@ import ( "context" "crypto/x509/pkix" "fmt" + "log/slog" "sort" "sync" "sync/atomic" @@ -33,7 +34,6 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" "golang.org/x/crypto/bcrypt" protobuf "google.golang.org/protobuf/proto" @@ -2140,7 +2140,7 @@ skiploop: for { select { case event := <-w.Events(): - log.Debugf("Skipping pre-test event: %v", event) + slog.DebugContext(ctx, "Skipping pre-test event", "event", event) continue skiploop default: break skiploop @@ -2215,11 +2215,11 @@ waitLoop: t.Fatalf("Watcher exited with error %v", w.Error()) case event := <-w.Events(): if event.Type != types.OpPut { - log.Debugf("Skipping event %+v", event) + slog.DebugContext(context.Background(), "Skipping event", "event", event) continue } if resource.GetName() != event.Resource.GetName() || resource.GetKind() != event.Resource.GetKind() || resource.GetSubKind() != event.Resource.GetSubKind() { - log.Debugf("Skipping event %v resource %v, expecting %v", event.Type, event.Resource.GetMetadata(), event.Resource.GetMetadata()) + slog.DebugContext(context.Background(), "Skipping event", "event", event) continue waitLoop } require.Empty(t, cmp.Diff(resource, event.Resource)) @@ -2240,7 +2240,10 @@ waitLoop: t.Fatalf("Watcher exited with error %v", w.Error()) case event := <-w.Events(): if event.Type != types.OpDelete { - log.Debugf("Skipping stale event %v %v", event.Type, event.Resource.GetName()) + slog.DebugContext(context.Background(), "Skipping stale event", + "event_type", event.Type, + "resource_name", event.Resource.GetName(), + ) continue } diff --git a/lib/services/traits.go b/lib/services/traits.go index 4c6fa2294dbf1..fb27619f98539 100644 --- a/lib/services/traits.go +++ b/lib/services/traits.go @@ -19,11 +19,12 @@ package services import ( + "context" "fmt" + "log/slog" "regexp" "github.com/gravitational/trace" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" @@ -144,13 +145,19 @@ TraitMappingLoop: // show at most maxMismatchedTraitValuesLogged trait values to prevent huge log lines switch l := len(mismatched); { case l > maxMismatchedTraitValuesLogged: - log.WithField("expression", mapping.Value). - WithField("values", mismatched[0:maxMismatchedTraitValuesLogged]). - Debugf("%d trait value(s) did not match (showing first %d values)", len(mismatched), maxMismatchedTraitValuesLogged) + slog. + DebugContext(context.Background(), "trait value(s) did not match (showing first %d values)", + "mismatch_count", len(mismatched), + "max_mismatch_logged", maxMismatchedTraitValuesLogged, + "expression", mapping.Value, + "values", mismatched[0:maxMismatchedTraitValuesLogged], + ) case l > 0: - log.WithField("expression", mapping.Value). - WithField("values", mismatched). - Debugf("%d trait value(s) did not match", len(mismatched)) + slog.DebugContext(context.Background(), "trait value(s) did not match", + "mismatch_count", len(mismatched), + "expression", mapping.Value, + "values", mismatched, + ) } } } diff --git a/lib/services/unified_resource.go b/lib/services/unified_resource.go index 2cf2e1c89995f..1bf8bd95747c0 100644 --- a/lib/services/unified_resource.go +++ b/lib/services/unified_resource.go @@ -20,6 +20,7 @@ package services import ( "context" + "log/slog" "strings" "sync" "time" @@ -28,7 +29,6 @@ import ( "github.com/google/btree" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" - log "github.com/sirupsen/logrus" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -37,6 +37,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/utils" + logutils "github.com/gravitational/teleport/lib/utils/log" "github.com/gravitational/teleport/lib/utils/pagination" ) @@ -68,9 +69,9 @@ type UnifiedResourceCacheConfig struct { // UnifiedResourceCache contains a representation of all resources that are displayable in the UI type UnifiedResourceCache struct { - rw sync.RWMutex - log *log.Entry - cfg UnifiedResourceCacheConfig + rw sync.RWMutex + logger *slog.Logger + cfg UnifiedResourceCacheConfig // nameTree is a BTree with items sorted by (hostname)/name/type nameTree *btree.BTreeG[*item] // typeTree is a BTree with items sorted by type/(hostname)/name @@ -101,10 +102,8 @@ func NewUnifiedResourceCache(ctx context.Context, cfg UnifiedResourceCacheConfig } m := &UnifiedResourceCache{ - log: log.WithFields(log.Fields{ - teleport.ComponentKey: cfg.Component, - }), - cfg: cfg, + logger: slog.With(teleport.ComponentKey, cfg.Component), + cfg: cfg, nameTree: btree.NewG(cfg.BTreeDegree, func(a, b *item) bool { return a.Less(b) }), @@ -267,7 +266,10 @@ func (c *UnifiedResourceCache) getRange(ctx context.Context, startKey backend.Ke } if len(res) == backend.DefaultRangeLimit { - c.log.Warnf("Range query hit backend limit. (this is a bug!) startKey=%q,limit=%d", startKey, backend.DefaultRangeLimit) + c.logger.WarnContext(ctx, "Range query hit backend limit. (this is a bug!)", + "start_key", startKey, + "range_limit", backend.DefaultRangeLimit, + ) } return res, nextKey, nil @@ -747,7 +749,11 @@ func (c *UnifiedResourceCache) processEventsAndUpdateCurrent(ctx context.Context for _, event := range events { if event.Resource == nil { - c.log.Warnf("Unexpected event: %v.", event) + c.logger.WarnContext(ctx, "Unexpected event", + "event_type", event.Type, + "resource_kind", event.Resource.GetKind(), + "resource_name", event.Resource.GetName(), + ) continue } @@ -775,15 +781,15 @@ func (c *UnifiedResourceCache) processEventsAndUpdateCurrent(ctx context.Context c.putLocked(types.Resource153ToUnifiedResource(unwrapped)) default: - c.log.Warnf("unsupported Resource153 type %T.", unwrapped) + c.logger.WarnContext(ctx, "unsupported Resource153 type", "resource_type", logutils.TypeAttr(unwrapped)) } default: - c.log.Warnf("unsupported Resource type %T.", r) + c.logger.WarnContext(ctx, "unsupported Resource type", "resource_type", logutils.TypeAttr(r)) } default: - c.log.Warnf("unsupported event type %s.", event.Type) + c.logger.WarnContext(ctx, "unsupported event type", "event_type", event.Type) continue } } diff --git a/lib/srv/transport/transportv1/transport.go b/lib/srv/transport/transportv1/transport.go index 820626ecfd211..e719941ee7098 100644 --- a/lib/srv/transport/transportv1/transport.go +++ b/lib/srv/transport/transportv1/transport.go @@ -290,6 +290,10 @@ func (s *Service) ProxySSH(stream transportv1pb.TransportService_ProxySSHServer) signer := s.cfg.SignerFn(authzContext, req.DialTarget.Cluster) hostConn, err := s.cfg.Dialer.DialHost(ctx, p.Addr, clientDst, host, port, req.DialTarget.Cluster, authzContext.Checker, s.cfg.agentGetterFn(agentStreamRW), signer) if err != nil { + // Return ambiguous errors unadorned so that clients can detect them easily. + if errors.Is(err, teleport.ErrNodeIsAmbiguous) { + return trace.Wrap(err) + } return trace.Wrap(err, "failed to dial target host") } diff --git a/lib/tbot/service_ssh_multiplexer.go b/lib/tbot/service_ssh_multiplexer.go index e979905d32039..de07a21eea848 100644 --- a/lib/tbot/service_ssh_multiplexer.go +++ b/lib/tbot/service_ssh_multiplexer.go @@ -667,7 +667,7 @@ func (s *SSHMultiplexerService) handleConn( host = cleanTargetHost(host, proxyHost, clusterName) target = net.JoinHostPort(host, port) } else { - node, err := resolveTargetHostWithClient(ctx, authClient, expanded.Search, expanded.Query) + node, err := resolveTargetHostWithClient(ctx, authClient.APIClient, expanded.Search, expanded.Query) if err != nil { return trace.Wrap(err, "resolving target host") } diff --git a/lib/tbot/ssh_proxy.go b/lib/tbot/ssh_proxy.go index 6769fd83103ae..3a048f6a43570 100644 --- a/lib/tbot/ssh_proxy.go +++ b/lib/tbot/ssh_proxy.go @@ -23,6 +23,7 @@ import ( "log/slog" "net" "path/filepath" + "slices" "strings" "github.com/gravitational/trace" @@ -220,38 +221,58 @@ func resolveTargetHost(ctx context.Context, cfg client.Config, search, query str // resolveTargetHostWithClient resolves the target host using the provided // client and search and query parameters. func resolveTargetHostWithClient( - ctx context.Context, clt client.ListUnifiedResourcesClient, search, query string, + ctx context.Context, clt *client.Client, search, query string, ) (types.Server, error) { - resources, _, err := client.GetUnifiedResourcePage(ctx, clt, &proto.ListUnifiedResourcesRequest{ - // We only want a single node, but, we set limit=2 so we can throw a - // helpful error when multiple match. In the happy path, where a single - // node matches, this does not degrade performance because even if - // limit=1 the UnifiedResource cache will still iterate to the end to - // determine if there is a NextKey to return. - Limit: 2, - Kinds: []string{types.KindNode}, + resp, err := clt.ResolveSSHTarget(ctx, &proto.ResolveSSHTargetRequest{ SearchKeywords: libclient.ParseSearchKeywords(search, ','), PredicateExpression: query, - SortBy: types.SortBy{Field: types.ResourceKind}, }) - if err != nil { - return nil, trace.Wrap(err) - } - if len(resources) == 0 { - return nil, trace.NotFound("no matching SSH hosts found for search terms or query expression") - } - if len(resources) > 1 { - names := make([]string, len(resources)) - for i, res := range resources { - names[i] = res.GetName() + switch { + //TODO(tross): DELETE IN v20.0.0 + case trace.IsNotImplemented(err): + resources, err := client.GetAllUnifiedResources(ctx, clt, &proto.ListUnifiedResourcesRequest{ + Kinds: []string{types.KindNode}, + SearchKeywords: libclient.ParseSearchKeywords(search, ','), + PredicateExpression: query, + SortBy: types.SortBy{Field: types.ResourceMetadataName}, + }) + if err != nil { + return nil, trace.Wrap(err) } - return nil, trace.BadParameter("found multiple matching SSH hosts %v", names) - } - node := resources[0].ResourceWithLabels.(*types.ServerV2) - if node == nil { - return nil, trace.BadParameter("expected node resource, got %T", resources[0].ResourceWithLabels) + + switch len(resources) { + case 0: + return nil, trace.NotFound("no matching SSH hosts found for search terms or query expression") + case 1: + node, ok := resources[0].ResourceWithLabels.(*types.ServerV2) + if !ok { + return nil, trace.BadParameter("expected node resource, got %T", resources[0].ResourceWithLabels) + } + return node, nil + default: + // If routing does not allow choosing the most recent host, then abort with + // an ambiguous host error. + cnc, err := clt.GetClusterNetworkingConfig(ctx) + if err != nil || cnc.GetRoutingStrategy() != types.RoutingStrategy_MOST_RECENT { + return nil, trace.BadParameter("found multiple matching SSH hosts %v", resources[:2]) + } + + // Get the most recent version of the resource. + enrichedResource := slices.MaxFunc(resources, func(a, b *types.EnrichedResource) int { + return a.Expiry().Compare(b.Expiry()) + }) + server, ok := enrichedResource.ResourceWithLabels.(types.Server) + if !ok { + return nil, trace.BadParameter("received unexpected resource type %T", resources[0].ResourceWithLabels) + } + + return server, nil + } + case err == nil: + return resp.GetServer(), nil + default: + return nil, trace.Wrap(err) } - return node, nil } func parseIdentity(destPath, proxy, cluster string, insecure, fips bool) (*identity.Facade, agent.ExtendedAgent, error) { diff --git a/lib/utils/log/buffer.go b/lib/utils/log/buffer.go index c158808bd545c..d12ac9e11bab0 100644 --- a/lib/utils/log/buffer.go +++ b/lib/utils/log/buffer.go @@ -21,6 +21,14 @@ func newBuffer() *buffer { return bufPool.Get().(*buffer) } +func (b *buffer) Len() int { + return len(*b) +} + +func (b *buffer) SetLen(n int) { + *b = (*b)[:n] +} + func (b *buffer) Free() { // To reduce peak allocation, return only smaller buffers to the pool. const maxBufferSize = 16 << 10 @@ -49,35 +57,6 @@ func (b *buffer) WriteByte(c byte) error { return nil } -func (b *buffer) WritePosInt(i int) { - b.WritePosIntWidth(i, 0) -} - -// WritePosIntWidth writes non-negative integer i to the buffer, padded on the left -// by zeroes to the given width. Use a width of 0 to omit padding. -func (b *buffer) WritePosIntWidth(i, width int) { - // Cheap integer to fixed-width decimal ASCII. - // Copied from log/log.go. - - if i < 0 { - panic("negative int") - } - - // Assemble decimal in reverse order. - var bb [20]byte - bp := len(bb) - 1 - for i >= 10 || width > 1 { - width-- - q := i / 10 - bb[bp] = byte('0' + i - q*10) - bp-- - i = q - } - // i < 10 - bb[bp] = byte('0' + i) - b.Write(bb[bp:]) -} - func (b *buffer) String() string { return string(*b) } diff --git a/lib/utils/log/formatter_test.go b/lib/utils/log/formatter_test.go index 39c717df3425d..e11a9f63620fb 100644 --- a/lib/utils/log/formatter_test.go +++ b/lib/utils/log/formatter_test.go @@ -45,7 +45,7 @@ import ( "github.com/gravitational/teleport" ) -const message = "Adding diagnostic debugging handlers.\t To connect with profiler, use `go tool pprof diag_addr`." +const message = "Adding diagnostic debugging handlers.\t To connect with profiler, use go tool pprof diag_addr." var ( logErr = errors.New("the quick brown fox jumped really high") @@ -76,7 +76,6 @@ func TestOutput(t *testing.T) { loc, err := time.LoadLocation("Africa/Cairo") require.NoError(t, err, "failed getting timezone") clock := clockwork.NewFakeClockAt(time.Now().In(loc)) - formattedNow := clock.Now().UTC().Format(time.RFC3339) t.Run("text", func(t *testing.T) { // fieldsRegex matches all the key value pairs emitted after the message and before the caller. All fields are @@ -88,7 +87,7 @@ func TestOutput(t *testing.T) { // 2) the message // 3) the fields // 4) the caller - outputRegex := regexp.MustCompile("(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z)(\\s+.*)(\".*diag_addr`\\.\")(.*)(\\slog/formatter_test.go:\\d{3})") + outputRegex := regexp.MustCompile(`(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)(\s+.*)(".*diag_addr\.")(.*)(\slog/formatter_test.go:\d{3})`) tests := []struct { name string @@ -149,7 +148,7 @@ func TestOutput(t *testing.T) { EnableColors: true, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { - a.Value = slog.StringValue(formattedNow) + a.Value = slog.TimeValue(clock.Now().UTC()) } return a }, @@ -188,7 +187,7 @@ func TestOutput(t *testing.T) { // Match level, and component: DEBU [TEST] assert.Empty(t, cmp.Diff(logrusMatches[2], slogMatches[2]), "level, and component to be identical") - // Match the log message: "Adding diagnostic debugging handlers.\t To connect with profiler, use `go tool pprof diag_addr`.\n" + // Match the log message: "Adding diagnostic debugging handlers.\t To connect with profiler, use go tool pprof diag_addr.\n" assert.Empty(t, cmp.Diff(logrusMatches[3], slogMatches[3]), "expected output messages to be identical") // The last matches are the caller information assert.Equal(t, fmt.Sprintf(" log/formatter_test.go:%d", logrusTestLogLineNumber), logrusMatches[5]) @@ -461,7 +460,13 @@ func TestConcurrentOutput(t *testing.T) { wg.Add(1) go func(i int) { defer wg.Done() - logger.InfoContext(ctx, "Teleport component entered degraded state", "component", i) + logger.InfoContext(ctx, "Teleport component entered degraded state", + slog.Int("component", i), + slog.Group("group", + slog.String("test", "123"), + slog.String("animal", "llama"), + ), + ) }(i) } wg.Wait() diff --git a/lib/utils/log/handle_state.go b/lib/utils/log/handle_state.go new file mode 100644 index 0000000000000..c60132b28e48e --- /dev/null +++ b/lib/utils/log/handle_state.go @@ -0,0 +1,352 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package log + +import ( + "encoding" + "fmt" + "log/slog" + "reflect" + "strconv" + "sync" + "time" + + "github.com/gravitational/trace" + "github.com/sirupsen/logrus" + + "github.com/gravitational/teleport" +) + +// handleState adapted from go/src/log/slog/handler.go +type handleState struct { + h *SlogTextHandler + buf *buffer + freeBuf bool // should buf be freed? + prefix *buffer // for text: key prefix + groups *[]string // pool-allocated slice of active groups, for ReplaceAttr +} + +var groupPool = sync.Pool{New: func() any { + s := make([]string, 0, 10) + return &s +}} + +func (s *handleState) free() { + if s.freeBuf { + s.buf.Free() + } + if gs := s.groups; gs != nil { + *gs = (*gs)[:0] + groupPool.Put(gs) + } + s.prefix.Free() +} + +func (s *handleState) openGroups() { + for _, n := range s.h.groups[s.h.nOpenGroups:] { + s.openGroup(n) + } +} + +// openGroup starts a new group of attributes +// with the given name. +func (s *handleState) openGroup(name string) { + s.prefix.WriteString(name) + s.prefix.WriteByte('.') + + // Collect group names for ReplaceAttr. + if s.groups != nil { + *s.groups = append(*s.groups, name) + } +} + +// closeGroup ends the group with the given name. +func (s *handleState) closeGroup(name string) { + *s.prefix = (*s.prefix)[:len(*s.prefix)-len(name)-1 /* for keyComponentSep */] + + if s.groups != nil { + *s.groups = (*s.groups)[:len(*s.groups)-1] + } +} + +// appendAttrs appends the slice of Attrs. +// It reports whether something was appended. +func (s *handleState) appendAttrs(as []slog.Attr) bool { + nonEmpty := false + for _, a := range as { + if s.appendAttr(a) { + nonEmpty = true + } + } + return nonEmpty +} + +// appendAttr appends the Attr's key and value. +// It handles replacement and checking for an empty key. +// It reports whether something was appended. +func (s *handleState) appendAttr(a slog.Attr) bool { + a.Value = a.Value.Resolve() + if rep := s.h.cfg.ReplaceAttr; rep != nil && a.Value.Kind() != slog.KindGroup { + var gs []string + if s.groups != nil { + gs = *s.groups + } + // a.Value is resolved before calling ReplaceAttr, so the user doesn't have to. + a = rep(gs, a) + // The ReplaceAttr function may return an unresolved Attr. + a.Value = a.Value.Resolve() + } + // Elide empty Attrs. + if a.Equal(slog.Attr{}) { + return false + } + + // Handle nested attributes from within component fields. + if a.Key == teleport.ComponentFields { + nonEmpty := false + switch fields := a.Value.Any().(type) { + case map[string]any: + for k, v := range fields { + if s.appendAttr(slog.Any(k, v)) { + nonEmpty = true + } + } + return nonEmpty + case logrus.Fields: + for k, v := range fields { + if s.appendAttr(slog.Any(k, v)) { + nonEmpty = true + } + } + return nonEmpty + } + } + + // Handle special cases before formatting. + if a.Value.Kind() == slog.KindAny { + switch v := a.Value.Any().(type) { + case *slog.Source: + a.Value = slog.StringValue(fmt.Sprintf(" %s:%d", v.File, v.Line)) + case trace.Error: + a.Value = slog.StringValue("[" + v.DebugReport() + "]") + case error: + a.Value = slog.StringValue(fmt.Sprintf("[%v]", v)) + } + } + + if a.Value.Kind() == slog.KindGroup { + attrs := a.Value.Group() + // Output only non-empty groups. + if len(attrs) > 0 { + // The group may turn out to be empty even though it has attrs (for + // example, ReplaceAttr may delete all the attrs). + // So remember where we are in the buffer, to restore the position + // later if necessary. + pos := s.buf.Len() + // Inline a group with an empty key. + if a.Key != "" { + s.openGroup(a.Key) + } + if !s.appendAttrs(attrs) { + s.buf.SetLen(pos) + return false + } + if a.Key != "" { + s.closeGroup(a.Key) + } + } + + return true + } + + if a.Value.Kind() == slog.KindString && a.Key != slog.LevelKey { + val := a.Value.String() + if needsQuoting(val) { + a.Value = slog.StringValue(strconv.Quote(val)) + } + } + + s.appendKey(a.Key) + + // Write the log key directly to avoid quoting + // color formatting that exists. + if a.Key == slog.LevelKey { + s.buf.WriteString(a.Value.String()) + } else { + s.appendValue(a.Value) + } + + return true +} + +func (s *handleState) appendError(err error) { + s.appendString(fmt.Sprintf("!ERROR:%v", err)) +} + +func (s *handleState) appendKey(key string) { + if s.buf.Len() > 0 { + s.buf.WriteString(" ") + } + + // These keys should not be included in the output to match + // the behavior of the lorgus formatter. + if key == slog.TimeKey || + key == teleport.ComponentKey || + key == slog.LevelKey || + key == CallerField || + key == slog.MessageKey || + key == slog.SourceKey { + return + } + + if s.prefix != nil && len(*s.prefix) > 0 { + // TODO: optimize by avoiding allocation. + s.appendString(string(*s.prefix) + key) + } else { + s.appendString(key) + } + + s.buf.WriteByte(':') +} + +func (s *handleState) appendString(str string) { + if str == "" { + return + } + + if needsQuoting(str) { + *s.buf = strconv.AppendQuote(*s.buf, str) + } else { + s.buf.WriteString(str) + } +} + +func (s *handleState) appendValue(v slog.Value) { + defer func() { + if r := recover(); r != nil { + // If it panics with a nil pointer, the most likely cases are + // an encoding.TextMarshaler or error fails to guard against nil, + // in which case "" seems to be the feasible choice. + // + // Adapted from the code in fmt/print.go. + if v := reflect.ValueOf(v.Any()); v.Kind() == reflect.Pointer && v.IsNil() { + s.appendString("") + return + } + + // Otherwise just print the original panic message. + s.appendString(fmt.Sprintf("!PANIC: %v", r)) + } + }() + + if err := appendTextValue(s, v); err != nil { + s.appendError(err) + } +} + +func (s *handleState) appendTime(t time.Time) { + *s.buf = appendRFC3339Millis(*s.buf, t) +} + +func (s *handleState) appendNonBuiltIns(r slog.Record) { + // preformatted Attrs + if pfa := s.h.preformatted; len(pfa) > 0 { + s.buf.WriteString(" ") + s.buf.Write(pfa) + } + // Attrs in Record -- unlike the built-in ones, they are in groups started + // from WithGroup. + // If the record has no Attrs, don't output any groups. + if r.NumAttrs() > 0 { + s.prefix.WriteString(s.h.groupPrefix) + // The group may turn out to be empty even though it has attrs (for + // example, ReplaceAttr may delete all the attrs). + // So remember where we are in the buffer, to restore the position + // later if necessary. + pos := s.buf.Len() + s.openGroups() + empty := true + r.Attrs(func(a slog.Attr) bool { + // The component is handled by the top level handler. + if a.Key == teleport.ComponentKey { + return true + } + if s.appendAttr(a) { + empty = false + } + return true + }) + if empty { + s.buf.SetLen(pos) + } + } +} + +func byteSlice(a any) ([]byte, bool) { + if bs, ok := a.([]byte); ok { + return bs, true + } + // Like Printf's %s, we allow both the slice type and the byte element type to be named. + t := reflect.TypeOf(a) + if t != nil && t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { + return reflect.ValueOf(a).Bytes(), true + } + return nil, false +} + +func appendTextValue(s *handleState, v slog.Value) error { + switch v.Kind() { + case slog.KindString: + s.appendString(v.String()) + case slog.KindTime: + s.appendTime(v.Time()) + case slog.KindAny: + if tm, ok := v.Any().(encoding.TextMarshaler); ok { + data, err := tm.MarshalText() + if err != nil { + return err + } + // TODO: avoid the conversion to string. + s.appendString(string(data)) + return nil + } + if bs, ok := byteSlice(v.Any()); ok { + // As of Go 1.19, this only allocates for strings longer than 32 bytes. + s.buf.WriteString(strconv.Quote(string(bs))) + return nil + } + s.appendString(fmt.Sprintf("%+v", v.Any())) + case slog.KindInt64: + *s.buf = strconv.AppendInt(*s.buf, v.Int64(), 10) + case slog.KindUint64: + *s.buf = strconv.AppendUint(*s.buf, v.Uint64(), 10) + case slog.KindFloat64: + *s.buf = strconv.AppendFloat(*s.buf, v.Float64(), 'g', -1, 64) + case slog.KindBool: + *s.buf = strconv.AppendBool(*s.buf, v.Bool()) + case slog.KindDuration: + *s.buf = append(*s.buf, v.Duration().String()...) + case slog.KindGroup: + *s.buf = fmt.Append(*s.buf, v.Group()) + case slog.KindLogValuer: + *s.buf = fmt.Append(*s.buf, v.Any()) + default: + panic(fmt.Sprintf("bad kind: %s", v.Kind())) + } + return nil +} + +func appendRFC3339Millis(b []byte, t time.Time) []byte { + // Format according to time.RFC3339Nano since it is highly optimized, + // but truncate it to use millisecond resolution. + // Unfortunately, that format trims trailing 0s, so add 1/10 millisecond + // to guarantee that there are exactly 4 digits after the period. + const prefixLen = len("2006-01-02T15:04:05.000") + n := len(b) + t = t.Truncate(time.Millisecond).Add(time.Millisecond / 10) + b = t.AppendFormat(b, time.RFC3339Nano) + b = append(b[:n+prefixLen], b[n+prefixLen+1:]...) // drop the 4th digit + return b +} diff --git a/lib/utils/log/logrus_formatter.go b/lib/utils/log/logrus_formatter.go index 87b3bff3bdc24..a21d922adf809 100644 --- a/lib/utils/log/logrus_formatter.go +++ b/lib/utils/log/logrus_formatter.go @@ -145,7 +145,7 @@ func (tf *TextFormatter) Format(e *logrus.Entry) ([]byte, error) { // write timestamp first if enabled if tf.timestampEnabled { - writeTimeRFC3339(w.b, e.Time) + *w.b = appendRFC3339Millis(*w.b, e.Time.Round(0)) } for _, field := range tf.ExtraFields { diff --git a/lib/utils/log/slog.go b/lib/utils/log/slog.go new file mode 100644 index 0000000000000..b1b0678ec5487 --- /dev/null +++ b/lib/utils/log/slog.go @@ -0,0 +1,131 @@ +/* + * 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 . + */ + +package log + +import ( + "context" + "fmt" + "log/slog" + "reflect" + "strings" + + oteltrace "go.opentelemetry.io/otel/trace" +) + +const ( + // TraceLevel is the logging level when set to Trace verbosity. + TraceLevel = slog.LevelDebug - 1 + + // TraceLevelText is the text representation of Trace verbosity. + TraceLevelText = "TRACE" +) + +// DiscardHandler is a [slog.Handler] that discards all messages. It +// is more efficient than a [slog.Handler] which outputs to [io.Discard] since +// it performs zero formatting. +// TODO(tross): Use slog.DiscardHandler once upgraded to Go 1.24. +type DiscardHandler struct{} + +func (dh DiscardHandler) Enabled(context.Context, slog.Level) bool { return false } +func (dh DiscardHandler) Handle(context.Context, slog.Record) error { return nil } +func (dh DiscardHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return dh } +func (dh DiscardHandler) WithGroup(name string) slog.Handler { return dh } + +func addTracingContextToRecord(ctx context.Context, r *slog.Record) { + const ( + traceID = "trace_id" + spanID = "span_id" + ) + + span := oteltrace.SpanFromContext(ctx) + if span == nil { + return + } + + spanContext := span.SpanContext() + if spanContext.HasTraceID() { + r.AddAttrs(slog.String(traceID, spanContext.TraceID().String())) + } + + if spanContext.HasSpanID() { + r.AddAttrs(slog.String(spanID, spanContext.SpanID().String())) + } +} + +// getCaller retrieves source information from the attribute +// and returns the file and line of the caller. The file is +// truncated from the absolute path to package/filename. +func getCaller(s *slog.Source) (file string, line int) { + count := 0 + idx := strings.LastIndexFunc(s.File, func(r rune) bool { + if r == '/' { + count++ + } + + return count == 2 + }) + file = s.File[idx+1:] + line = s.Line + + return file, line +} + +type stringerAttr struct { + fmt.Stringer +} + +// StringerAttr creates a [slog.LogValuer] that will defer to +// the provided [fmt.Stringer]. All slog attributes are always evaluated, +// even if the log event is discarded due to the configured log level. +// A text [slog.Handler] will try to defer evaluation if the attribute is a +// [fmt.Stringer], however, the JSON [slog.Handler] only defers to [json.Marshaler]. +// This means that to defer evaluation and creation of the string representation, +// the object must implement [fmt.Stringer] and [json.Marshaler], otherwise additional +// and unwanted values may be emitted if the logger is configured to use JSON +// instead of text. This wrapping mechanism allows a value that implements [fmt.Stringer], +// to be guaranteed to be lazily constructed and always output the same +// content regardless of the output format. +func StringerAttr(s fmt.Stringer) slog.LogValuer { + return stringerAttr{Stringer: s} +} + +func (s stringerAttr) LogValue() slog.Value { + if s.Stringer == nil { + return slog.StringValue("") + } + return slog.StringValue(s.Stringer.String()) +} + +type typeAttr struct { + val any +} + +// TypeAttr creates a lazily evaluated log value that presents the pretty type name of a value +// as a string. It is roughly equivalent to the '%T' format option, and should only perform +// reflection in the event that logs are actually being generated. +func TypeAttr(val any) slog.LogValuer { + return typeAttr{val} +} + +func (a typeAttr) LogValue() slog.Value { + if t := reflect.TypeOf(a.val); t != nil { + return slog.StringValue(t.String()) + } + return slog.StringValue("nil") +} diff --git a/lib/utils/log/slog_handler.go b/lib/utils/log/slog_handler.go deleted file mode 100644 index 14363bca8584e..0000000000000 --- a/lib/utils/log/slog_handler.go +++ /dev/null @@ -1,692 +0,0 @@ -/* - * 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 . - */ - -package log - -import ( - "context" - "fmt" - "io" - "log/slog" - "reflect" - "runtime" - "slices" - "strconv" - "strings" - "sync" - "time" - - "github.com/gravitational/trace" - "github.com/sirupsen/logrus" - oteltrace "go.opentelemetry.io/otel/trace" - - "github.com/gravitational/teleport" -) - -// TraceLevel is the logging level when set to Trace verbosity. -const TraceLevel = slog.LevelDebug - 1 - -// TraceLevelText is the text representation of Trace verbosity. -const TraceLevelText = "TRACE" - -// DiscardHandler is a [slog.Handler] that discards all messages. It -// is more efficient than a [slog.Handler] which outputs to [io.Discard] since -// it performs zero formatting. -// TODO(tross): Use slog.DiscardHandler once upgraded to Go 1.24. -type DiscardHandler struct{} - -func (dh DiscardHandler) Enabled(context.Context, slog.Level) bool { return false } -func (dh DiscardHandler) Handle(context.Context, slog.Record) error { return nil } -func (dh DiscardHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return dh } -func (dh DiscardHandler) WithGroup(name string) slog.Handler { return dh } - -// SlogTextHandler is a [slog.Handler] that outputs messages in a textual -// manner as configured by the Teleport configuration. -type SlogTextHandler struct { - cfg SlogTextHandlerConfig - // withCaller indicates whether the location the log was emitted from - // should be included in the output message. - withCaller bool - // withTimestamp indicates whether the times that the log was emitted at - // should be included in the output message. - withTimestamp bool - // component is the Teleport subcomponent that emitted the log. - component string - // preformatted data from previous calls to WithGroup and WithAttrs. - preformatted []byte - // groupPrefix is for the text handler only. - // It holds the prefix for groups that were already pre-formatted. - // A group will appear here when a call to WithGroup is followed by - // a call to WithAttrs. - groupPrefix buffer - // groups passed in via WithGroup and WithAttrs. - groups []string - // nOpenGroups the number of groups opened in preformatted. - nOpenGroups int - - // mu protects out - it needs to be a pointer so that all cloned - // SlogTextHandler returned from WithAttrs and WithGroup share the - // same mutex. Otherwise, output may be garbled since each clone - // will use its own copy of the mutex to protect out. See - // https://github.com/golang/go/issues/61321 for more details. - mu *sync.Mutex - out io.Writer -} - -// SlogTextHandlerConfig allow the SlogTextHandler functionality -// to be tweaked. -type SlogTextHandlerConfig struct { - // Level is the minimum record level that will be logged. - Level slog.Leveler - // EnableColors allows the level to be printed in color. - EnableColors bool - // Padding to use for various components. - Padding int - // ConfiguredFields are fields explicitly set by users to be included in - // the output message. If there are any entries configured, they will be honored. - // If empty, the default fields will be populated and included in the output. - ConfiguredFields []string - // ReplaceAttr is called to rewrite each non-group attribute before - // it is logged. - ReplaceAttr func(groups []string, a slog.Attr) slog.Attr -} - -// NewSlogTextHandler creates a SlogTextHandler that writes messages to w. -func NewSlogTextHandler(w io.Writer, cfg SlogTextHandlerConfig) *SlogTextHandler { - if cfg.Padding == 0 { - cfg.Padding = defaultComponentPadding - } - - handler := SlogTextHandler{ - cfg: cfg, - withCaller: len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, CallerField), - withTimestamp: len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, TimestampField), - out: w, - mu: &sync.Mutex{}, - } - - if handler.cfg.ConfiguredFields == nil { - handler.cfg.ConfiguredFields = defaultFormatFields - } - - return &handler -} - -// Enabled returns whether the provided level will be included in output. -func (s *SlogTextHandler) Enabled(ctx context.Context, level slog.Level) bool { - minLevel := slog.LevelInfo - if s.cfg.Level != nil { - minLevel = s.cfg.Level.Level() - } - return level >= minLevel -} - -func (s *SlogTextHandler) appendAttr(buf []byte, a slog.Attr) []byte { - if rep := s.cfg.ReplaceAttr; rep != nil && a.Value.Kind() != slog.KindGroup { - var gs []string - if s.groups != nil { - gs = s.groups - } - // Resolve before calling ReplaceAttr, so the user doesn't have to. - a.Value = a.Value.Resolve() - a = rep(gs, a) - } - - // Resolve the Attr's value before doing anything else. - a.Value = a.Value.Resolve() - // Ignore empty Attrs. - if a.Equal(slog.Attr{}) { - return buf - } - - switch a.Value.Kind() { - case slog.KindString: - value := a.Value.String() - if a.Key == slog.TimeKey { - buf = fmt.Append(buf, value) - break - } - - if a.Key == teleport.ComponentFields { - switch fields := a.Value.Any().(type) { - case map[string]any: - for k, v := range fields { - buf = s.appendAttr(buf, slog.Any(k, v)) - } - case logrus.Fields: - for k, v := range fields { - buf = s.appendAttr(buf, slog.Any(k, v)) - } - } - } - - if needsQuoting(value) { - if a.Key == teleport.ComponentKey || a.Key == slog.LevelKey || a.Key == CallerField || a.Key == slog.MessageKey { - if len(buf) > 0 { - buf = fmt.Append(buf, " ") - } - } else { - if len(buf) > 0 { - buf = fmt.Append(buf, " ") - } - buf = fmt.Appendf(buf, "%s%s:", s.groupPrefix, a.Key) - } - buf = strconv.AppendQuote(buf, value) - break - } - - if a.Key == teleport.ComponentKey || a.Key == slog.LevelKey || a.Key == CallerField || a.Key == slog.MessageKey { - if len(buf) > 0 { - buf = fmt.Append(buf, " ") - } - buf = fmt.Appendf(buf, "%s", a.Value.String()) - break - } - - buf = fmt.Appendf(buf, " %s%s:%s", s.groupPrefix, a.Key, a.Value.String()) - case slog.KindGroup: - attrs := a.Value.Group() - // Ignore empty groups. - if len(attrs) == 0 { - return buf - } - // If the key is non-empty, write it out and indent the rest of the attrs. - // Otherwise, inline the attrs. - if a.Key != "" { - s.groupPrefix = fmt.Append(s.groupPrefix, a.Key) - s.groupPrefix = fmt.Append(s.groupPrefix, ".") - } - for _, ga := range attrs { - buf = s.appendAttr(buf, ga) - } - if a.Key != "" { - s.groupPrefix = s.groupPrefix[:len(s.groupPrefix)-len(a.Key)-1 /* for keyComponentSep */] - if s.groups != nil { - s.groups = (s.groups)[:len(s.groups)-1] - } - } - default: - switch err := a.Value.Any().(type) { - case trace.Error: - buf = fmt.Appendf(buf, " error:[%v]", err.DebugReport()) - case error: - buf = fmt.Appendf(buf, " error:[%v]", a.Value) - default: - buf = fmt.Appendf(buf, " %s:%s", a.Key, a.Value) - } - } - return buf -} - -// writeTimeRFC3339 writes the time in [time.RFC3339Nano] to the buffer. -// This takes half the time of [time.Time.AppendFormat]. Adapted from -// go/src/log/slog/handler.go. -func writeTimeRFC3339(buf *buffer, t time.Time) { - year, month, day := t.Date() - buf.WritePosIntWidth(year, 4) - buf.WriteByte('-') - buf.WritePosIntWidth(int(month), 2) - buf.WriteByte('-') - buf.WritePosIntWidth(day, 2) - buf.WriteByte('T') - hour, min, sec := t.Clock() - buf.WritePosIntWidth(hour, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(min, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(sec, 2) - _, offsetSeconds := t.Zone() - if offsetSeconds == 0 { - buf.WriteByte('Z') - } else { - offsetMinutes := offsetSeconds / 60 - if offsetMinutes < 0 { - buf.WriteByte('-') - offsetMinutes = -offsetMinutes - } else { - buf.WriteByte('+') - } - buf.WritePosIntWidth(offsetMinutes/60, 2) - buf.WriteByte(':') - buf.WritePosIntWidth(offsetMinutes%60, 2) - } -} - -// Handle formats the provided record and writes the output to the -// destination. -func (s *SlogTextHandler) Handle(ctx context.Context, r slog.Record) error { - buf := newBuffer() - defer buf.Free() - - addTracingContextToRecord(ctx, &r) - - if s.withTimestamp && !r.Time.IsZero() { - if s.cfg.ReplaceAttr != nil { - *buf = s.appendAttr(*buf, slog.Time(slog.TimeKey, r.Time)) - } else { - writeTimeRFC3339(buf, r.Time) - } - } - - // Processing fields in this manner allows users to - // configure the level and component position in the output. - // This matches the behavior of the original logrus. All other - // fields location in the output message are static. - for _, field := range s.cfg.ConfiguredFields { - switch field { - case LevelField: - var color int - var level string - switch r.Level { - case TraceLevel: - level = "TRACE" - color = gray - case slog.LevelDebug: - level = "DEBUG" - color = gray - case slog.LevelInfo: - level = "INFO" - color = blue - case slog.LevelWarn: - level = "WARN" - color = yellow - case slog.LevelError: - level = "ERROR" - color = red - case slog.LevelError + 1: - level = "FATAL" - color = red - default: - color = blue - level = r.Level.String() - } - - if !s.cfg.EnableColors { - color = noColor - } - - level = padMax(level, defaultLevelPadding) - if color == noColor { - *buf = s.appendAttr(*buf, slog.String(slog.LevelKey, level)) - } else { - *buf = fmt.Appendf(*buf, " \u001B[%dm%s\u001B[0m", color, level) - } - case ComponentField: - // If a component is provided with the attributes, it should be used instead of - // the component set on the handler. Note that if there are multiple components - // specified in the arguments, the one with the lowest index is used and the others are ignored. - // In the example below, the resulting component in the message output would be "alpaca". - // - // logger := logger.With(teleport.ComponentKey, "fish") - // logger.InfoContext(ctx, "llama llama llama", teleport.ComponentKey, "alpaca", "foo", 123, teleport.ComponentKey, "shark") - component := s.component - r.Attrs(func(attr slog.Attr) bool { - if attr.Key == teleport.ComponentKey { - component = fmt.Sprintf("[%v]", attr.Value) - component = strings.ToUpper(padMax(component, s.cfg.Padding)) - if component[len(component)-1] != ' ' { - component = component[:len(component)-1] + "]" - } - - return false - } - - return true - }) - - *buf = s.appendAttr(*buf, slog.String(teleport.ComponentKey, component)) - default: - if _, ok := knownFormatFields[field]; !ok { - return trace.BadParameter("invalid log format key: %v", field) - } - } - } - - *buf = s.appendAttr(*buf, slog.String(slog.MessageKey, r.Message)) - - // Insert preformatted attributes just after built-in ones. - *buf = append(*buf, s.preformatted...) - if r.NumAttrs() > 0 { - if len(s.groups) > 0 { - for _, n := range s.groups[s.nOpenGroups:] { - s.groupPrefix = fmt.Append(s.groupPrefix, n) - s.groupPrefix = fmt.Append(s.groupPrefix, ".") - } - } - - r.Attrs(func(a slog.Attr) bool { - // Skip adding any component attrs since they are processed above. - if a.Key == teleport.ComponentKey { - return true - } - - *buf = s.appendAttr(*buf, a) - return true - }) - } - - if r.PC != 0 && s.withCaller { - fs := runtime.CallersFrames([]uintptr{r.PC}) - f, _ := fs.Next() - - src := &slog.Source{ - Function: f.Function, - File: f.File, - Line: f.Line, - } - - file, line := getCaller(src) - *buf = fmt.Appendf(*buf, " %s:%d", file, line) - } - - buf.WriteByte('\n') - - s.mu.Lock() - defer s.mu.Unlock() - _, err := s.out.Write(*buf) - return err -} - -// WithAttrs clones the current handler with the provided attributes -// added to any existing attributes. The values are preformatted here -// so that they do not need to be formatted per call to Handle. -func (s *SlogTextHandler) WithAttrs(attrs []slog.Attr) slog.Handler { - if len(attrs) == 0 { - return s - } - s2 := *s - // Force an append to copy the underlying arrays. - s2.preformatted = slices.Clip(s.preformatted) - s2.groups = slices.Clip(s.groups) - - // Add all groups from WithGroup that haven't already been added to the prefix. - if len(s.groups) > 0 { - for _, n := range s.groups[s.nOpenGroups:] { - s2.groupPrefix = fmt.Append(s2.groupPrefix, n) - s2.groupPrefix = fmt.Append(s2.groupPrefix, ".") - } - } - - // Now all groups have been opened. - s2.nOpenGroups = len(s2.groups) - - component := s.component - - // Pre-format the attributes. - for _, a := range attrs { - switch a.Key { - case teleport.ComponentKey: - component = fmt.Sprintf("[%v]", a.Value.String()) - component = strings.ToUpper(padMax(component, s.cfg.Padding)) - if component[len(component)-1] != ' ' { - component = component[:len(component)-1] + "]" - } - case teleport.ComponentFields: - switch fields := a.Value.Any().(type) { - case map[string]any: - for k, v := range fields { - s2.appendAttr(s2.preformatted, slog.Any(k, v)) - } - case logrus.Fields: - for k, v := range fields { - s2.preformatted = s2.appendAttr(s2.preformatted, slog.Any(k, v)) - } - } - default: - s2.preformatted = s2.appendAttr(s2.preformatted, a) - } - } - - s2.component = component - // Remember how many opened groups are in preformattedAttrs, - // so we don't open them again when we handle a Record. - s2.nOpenGroups = len(s2.groups) - return &s2 -} - -// WithGroup opens a new group. -func (s *SlogTextHandler) WithGroup(name string) slog.Handler { - if name == "" { - return s - } - - s2 := *s - s2.groups = append(s2.groups, name) - return &s2 -} - -// SlogJSONHandlerConfig allow the SlogJSONHandler functionality -// to be tweaked. -type SlogJSONHandlerConfig struct { - // Level is the minimum record level that will be logged. - Level slog.Leveler - // ConfiguredFields are fields explicitly set by users to be included in - // the output message. If there are any entries configured, they will be honored. - // If empty, the default fields will be populated and included in the output. - ConfiguredFields []string - // ReplaceAttr is called to rewrite each non-group attribute before - // it is logged. - ReplaceAttr func(groups []string, a slog.Attr) slog.Attr -} - -// SlogJSONHandler is a [slog.Handler] that outputs messages in a json -// format per the config file. -type SlogJSONHandler struct { - *slog.JSONHandler -} - -// NewSlogJSONHandler creates a SlogJSONHandler that outputs to w. -func NewSlogJSONHandler(w io.Writer, cfg SlogJSONHandlerConfig) *SlogJSONHandler { - withCaller := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, CallerField) - withComponent := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, ComponentField) - withTimestamp := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, TimestampField) - - return &SlogJSONHandler{ - JSONHandler: slog.NewJSONHandler(w, &slog.HandlerOptions{ - AddSource: true, - Level: cfg.Level, - ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { - switch a.Key { - case teleport.ComponentKey: - if !withComponent { - return slog.Attr{} - } - if a.Value.Kind() != slog.KindString { - return a - } - - a.Key = ComponentField - case slog.LevelKey: - // The slog.JSONHandler will inject "level" Attr. - // However, this lib's consumer might add an Attr using the same key ("level") and we end up with two records named "level". - // We must check its type before assuming this was injected by the slog.JSONHandler. - lvl, ok := a.Value.Any().(slog.Level) - if !ok { - return a - } - - var level string - switch lvl { - case TraceLevel: - level = "trace" - case slog.LevelDebug: - level = "debug" - case slog.LevelInfo: - level = "info" - case slog.LevelWarn: - level = "warning" - case slog.LevelError: - level = "error" - case slog.LevelError + 1: - level = "fatal" - default: - level = strings.ToLower(lvl.String()) - } - - a.Value = slog.StringValue(level) - case slog.TimeKey: - if !withTimestamp { - return slog.Attr{} - } - - // The slog.JSONHandler will inject "time" Attr. - // However, this lib's consumer might add an Attr using the same key ("time") and we end up with two records named "time". - // We must check its type before assuming this was injected by the slog.JSONHandler. - if a.Value.Kind() != slog.KindTime { - return a - } - - t := a.Value.Time() - if t.IsZero() { - return a - } - - a.Key = TimestampField - a.Value = slog.StringValue(t.Format(time.RFC3339)) - case slog.MessageKey: - // The slog.JSONHandler will inject "msg" Attr. - // However, this lib's consumer might add an Attr using the same key ("msg") and we end up with two records named "msg". - // We must check its type before assuming this was injected by the slog.JSONHandler. - if a.Value.Kind() != slog.KindString { - return a - } - a.Key = messageField - case slog.SourceKey: - if !withCaller { - return slog.Attr{} - } - - // The slog.JSONHandler will inject "source" Attr when AddSource is true. - // However, this lib's consumer might add an Attr using the same key ("source") and we end up with two records named "source". - // We must check its type before assuming this was injected by the slog.JSONHandler. - s, ok := a.Value.Any().(*slog.Source) - if !ok { - return a - } - - file, line := getCaller(s) - a = slog.String(CallerField, fmt.Sprintf("%s:%d", file, line)) - } - - // Convert [slog.KindAny] values that are backed by an [error] or [fmt.Stringer] - // to strings so that only the message is output instead of a json object. The kind is - // first checked to avoid allocating an interface for the values stored inline - // in [slog.Attr]. - if a.Value.Kind() == slog.KindAny { - if err, ok := a.Value.Any().(error); ok { - a.Value = slog.StringValue(err.Error()) - } - - if stringer, ok := a.Value.Any().(fmt.Stringer); ok { - a.Value = slog.StringValue(stringer.String()) - } - } - - return a - }, - }), - } -} - -const ( - traceID = "trace_id" - spanID = "span_id" -) - -func addTracingContextToRecord(ctx context.Context, r *slog.Record) { - span := oteltrace.SpanFromContext(ctx) - if span == nil { - return - } - - spanContext := span.SpanContext() - if spanContext.HasTraceID() { - r.AddAttrs(slog.String(traceID, spanContext.TraceID().String())) - } - - if spanContext.HasSpanID() { - r.AddAttrs(slog.String(spanID, spanContext.SpanID().String())) - } -} - -func (j *SlogJSONHandler) Handle(ctx context.Context, r slog.Record) error { - addTracingContextToRecord(ctx, &r) - return j.JSONHandler.Handle(ctx, r) -} - -// getCaller retrieves source information from the attribute -// and returns the file and line of the caller. The file is -// truncated from the absolute path to package/filename. -func getCaller(s *slog.Source) (file string, line int) { - count := 0 - idx := strings.LastIndexFunc(s.File, func(r rune) bool { - if r == '/' { - count++ - } - - return count == 2 - }) - file = s.File[idx+1:] - line = s.Line - - return file, line -} - -type stringerAttr struct { - fmt.Stringer -} - -// StringerAttr creates a [slog.LogValuer] that will defer to -// the provided [fmt.Stringer]. All slog attributes are always evaluated, -// even if the log event is discarded due to the configured log level. -// A text [slog.Handler] will try to defer evaluation if the attribute is a -// [fmt.Stringer], however, the JSON [slog.Handler] only defers to [json.Marshaler]. -// This means that to defer evaluation and creation of the string representation, -// the object must implement [fmt.Stringer] and [json.Marshaler], otherwise additional -// and unwanted values may be emitted if the logger is configured to use JSON -// instead of text. This wrapping mechanism allows a value that implements [fmt.Stringer], -// to be guaranteed to be lazily constructed and always output the same -// content regardless of the output format. -func StringerAttr(s fmt.Stringer) slog.LogValuer { - return stringerAttr{Stringer: s} -} - -func (s stringerAttr) LogValue() slog.Value { - if s.Stringer == nil { - return slog.StringValue("") - } - return slog.StringValue(s.Stringer.String()) -} - -type typeAttr struct { - val any -} - -// TypeAttr creates a lazily evaluated log value that presents the pretty type name of a value -// as a string. It is roughly equivalent to the '%T' format option, and should only perform -// reflection in the event that logs are actually being generated. -func TypeAttr(val any) slog.LogValuer { - return typeAttr{val} -} - -func (a typeAttr) LogValue() slog.Value { - if t := reflect.TypeOf(a.val); t != nil { - return slog.StringValue(t.String()) - } - return slog.StringValue("nil") -} diff --git a/lib/utils/log/slog_handler_test.go b/lib/utils/log/slog_handler_test.go index 20876b6c4df1c..a75d57fc66994 100644 --- a/lib/utils/log/slog_handler_test.go +++ b/lib/utils/log/slog_handler_test.go @@ -22,13 +22,11 @@ import ( "bytes" "context" "encoding/json" - "fmt" "log/slog" "regexp" "strings" "testing" "testing/slogtest" - "time" "github.com/jonboulle/clockwork" "github.com/stretchr/testify/assert" @@ -41,16 +39,17 @@ import ( func TestSlogTextHandler(t *testing.T) { t.Parallel() clock := clockwork.NewFakeClock() - now := clock.Now().UTC().Format(time.RFC3339) + now := clock.Now().UTC() // Create a handler that doesn't report the caller and automatically sets // the time to whatever time the fake clock has in UTC time. Since the timestamp // is not important for this test overriding, it allows the regex to be simpler. var buf bytes.Buffer h := NewSlogTextHandler(&buf, SlogTextHandlerConfig{ + ConfiguredFields: []string{LevelField, ComponentField, TimestampField}, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { - a.Value = slog.StringValue(now) + a.Value = slog.TimeValue(now) } return a }, @@ -62,8 +61,7 @@ func TestSlogTextHandler(t *testing.T) { // Group 2: verbosity level of output // Group 3: message contents // Group 4: additional attributes - regex := fmt.Sprintf("^(?:(%s)?)\\s?([A-Z]{4})\\s+(\\w+)(?:\\s(.*))?$", now) - lineRegex := regexp.MustCompile(regex) + lineRegex := regexp.MustCompile(`^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)?\s?([A-Z]{4})\s+(\w+)(?:\s(.*))?$`) results := func() []map[string]any { var ms []map[string]any @@ -75,7 +73,7 @@ func TestSlogTextHandler(t *testing.T) { var m map[string]any matches := lineRegex.FindSubmatch(line) if len(matches) == 0 { - assert.Failf(t, "log output did not match regular expression", "regex: %s output: %s", regex, string(line)) + assert.Failf(t, "log output did not match regular expression", "regex: %s output: %s", lineRegex.String(), string(line)) ms = append(ms, m) continue } diff --git a/lib/utils/log/slog_json_handler.go b/lib/utils/log/slog_json_handler.go new file mode 100644 index 0000000000000..f5c3ec4062b09 --- /dev/null +++ b/lib/utils/log/slog_json_handler.go @@ -0,0 +1,167 @@ +// 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 log + +import ( + "context" + "fmt" + "io" + "log/slog" + "slices" + "strings" + "time" + + "github.com/gravitational/teleport" +) + +// SlogJSONHandlerConfig allows the SlogJSONHandler functionality +// to be tweaked. +type SlogJSONHandlerConfig struct { + // Level is the minimum record level that will be logged. + Level slog.Leveler + // ConfiguredFields are fields explicitly set by users to be included in + // the output message. If there are any entries configured, they will be honored. + // If empty, the default fields will be populated and included in the output. + ConfiguredFields []string + // ReplaceAttr is called to rewrite each non-group attribute before + // it is logged. + ReplaceAttr func(groups []string, a slog.Attr) slog.Attr +} + +// SlogJSONHandler is a [slog.Handler] that outputs messages in a json +// format per the config file. +type SlogJSONHandler struct { + *slog.JSONHandler +} + +// NewSlogJSONHandler creates a SlogJSONHandler that outputs to w. +func NewSlogJSONHandler(w io.Writer, cfg SlogJSONHandlerConfig) *SlogJSONHandler { + withCaller := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, CallerField) + withComponent := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, ComponentField) + withTimestamp := len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, TimestampField) + + return &SlogJSONHandler{ + JSONHandler: slog.NewJSONHandler(w, &slog.HandlerOptions{ + AddSource: true, + Level: cfg.Level, + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + switch a.Key { + case teleport.ComponentKey: + if !withComponent { + return slog.Attr{} + } + if a.Value.Kind() != slog.KindString { + return a + } + + a.Key = ComponentField + case slog.LevelKey: + // The slog.JSONHandler will inject "level" Attr. + // However, this lib's consumer might add an Attr using the same key ("level") and we end up with two records named "level". + // We must check its type before assuming this was injected by the slog.JSONHandler. + lvl, ok := a.Value.Any().(slog.Level) + if !ok { + return a + } + + var level string + switch lvl { + case TraceLevel: + level = "trace" + case slog.LevelDebug: + level = "debug" + case slog.LevelInfo: + level = "info" + case slog.LevelWarn: + level = "warning" + case slog.LevelError: + level = "error" + case slog.LevelError + 1: + level = "fatal" + default: + level = strings.ToLower(lvl.String()) + } + + a.Value = slog.StringValue(level) + case slog.TimeKey: + if !withTimestamp { + return slog.Attr{} + } + + // The slog.JSONHandler will inject "time" Attr. + // However, this lib's consumer might add an Attr using the same key ("time") and we end up with two records named "time". + // We must check its type before assuming this was injected by the slog.JSONHandler. + if a.Value.Kind() != slog.KindTime { + return a + } + + t := a.Value.Time() + if t.IsZero() { + return a + } + + a.Key = TimestampField + a.Value = slog.StringValue(t.Format(time.RFC3339)) + case slog.MessageKey: + // The slog.JSONHandler will inject "msg" Attr. + // However, this lib's consumer might add an Attr using the same key ("msg") and we end up with two records named "msg". + // We must check its type before assuming this was injected by the slog.JSONHandler. + if a.Value.Kind() != slog.KindString { + return a + } + a.Key = messageField + case slog.SourceKey: + if !withCaller { + return slog.Attr{} + } + + // The slog.JSONHandler will inject "source" Attr when AddSource is true. + // However, this lib's consumer might add an Attr using the same key ("source") and we end up with two records named "source". + // We must check its type before assuming this was injected by the slog.JSONHandler. + s, ok := a.Value.Any().(*slog.Source) + if !ok { + return a + } + + file, line := getCaller(s) + a = slog.String(CallerField, fmt.Sprintf("%s:%d", file, line)) + } + + // Convert [slog.KindAny] values that are backed by an [error] or [fmt.Stringer] + // to strings so that only the message is output instead of a json object. The kind is + // first checked to avoid allocating an interface for the values stored inline + // in [slog.Attr]. + if a.Value.Kind() == slog.KindAny { + if err, ok := a.Value.Any().(error); ok { + a.Value = slog.StringValue(err.Error()) + } + + if stringer, ok := a.Value.Any().(fmt.Stringer); ok { + a.Value = slog.StringValue(stringer.String()) + } + } + + return a + }, + }), + } +} + +func (j *SlogJSONHandler) Handle(ctx context.Context, r slog.Record) error { + addTracingContextToRecord(ctx, &r) + return j.JSONHandler.Handle(ctx, r) +} diff --git a/lib/utils/log/slog_text_handler.go b/lib/utils/log/slog_text_handler.go new file mode 100644 index 0000000000000..b3bc4900ac64c --- /dev/null +++ b/lib/utils/log/slog_text_handler.go @@ -0,0 +1,359 @@ +// 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 log + +import ( + "context" + "fmt" + "io" + "log/slog" + "runtime" + "slices" + "strings" + "sync" + + "github.com/gravitational/trace" + "github.com/sirupsen/logrus" + + "github.com/gravitational/teleport" +) + +// SlogTextHandler is a [slog.Handler] that outputs messages in a textual +// manner as configured by the Teleport configuration. +type SlogTextHandler struct { + cfg SlogTextHandlerConfig + // withCaller indicates whether the location the log was emitted from + // should be included in the output message. + withCaller bool + // withTimestamp indicates whether the times that the log was emitted at + // should be included in the output message. + withTimestamp bool + // component is the Teleport subcomponent that emitted the log. + component string + // preformatted data from previous calls to WithGroup and WithAttrs. + preformatted []byte + // groupPrefix is for the text handler only. + // It holds the prefix for groups that were already pre-formatted. + // A group will appear here when a call to WithGroup is followed by + // a call to WithAttrs. + groupPrefix string + // groups passed in via WithGroup and WithAttrs. + groups []string + // nOpenGroups the number of groups opened in preformatted. + nOpenGroups int + + // mu protects out - it needs to be a pointer so that all cloned + // SlogTextHandler returned from WithAttrs and WithGroup share the + // same mutex. Otherwise, output may be garbled since each clone + // will use its own copy of the mutex to protect out. See + // https://github.com/golang/go/issues/61321 for more details. + mu *sync.Mutex + out io.Writer +} + +// SlogTextHandlerConfig allow the SlogTextHandler functionality +// to be tweaked. +type SlogTextHandlerConfig struct { + // Level is the minimum record level that will be logged. + Level slog.Leveler + // EnableColors allows the level to be printed in color. + EnableColors bool + // Padding to use for various components. + Padding int + // ConfiguredFields are fields explicitly set by users to be included in + // the output message. If there are any entries configured, they will be honored. + // If empty, the default fields will be populated and included in the output. + ConfiguredFields []string + // ReplaceAttr is called to rewrite each non-group attribute before + // it is logged. + ReplaceAttr func(groups []string, a slog.Attr) slog.Attr +} + +// NewSlogTextHandler creates a SlogTextHandler that writes messages to w. +func NewSlogTextHandler(w io.Writer, cfg SlogTextHandlerConfig) *SlogTextHandler { + if cfg.Padding == 0 { + cfg.Padding = defaultComponentPadding + } + + handler := SlogTextHandler{ + cfg: cfg, + withCaller: len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, CallerField), + withTimestamp: len(cfg.ConfiguredFields) == 0 || slices.Contains(cfg.ConfiguredFields, TimestampField), + out: w, + mu: &sync.Mutex{}, + } + + if handler.cfg.ConfiguredFields == nil { + handler.cfg.ConfiguredFields = defaultFormatFields + } + + return &handler +} + +// Enabled returns whether the provided level will be included in output. +func (s *SlogTextHandler) Enabled(ctx context.Context, level slog.Level) bool { + minLevel := slog.LevelInfo + if s.cfg.Level != nil { + minLevel = s.cfg.Level.Level() + } + return level >= minLevel +} + +func (s *SlogTextHandler) newHandleState(buf *buffer, freeBuf bool) handleState { + state := handleState{ + h: s, + buf: buf, + freeBuf: freeBuf, + prefix: newBuffer(), + } + if s.cfg.ReplaceAttr != nil { + state.groups = groupPool.Get().(*[]string) + *state.groups = append(*state.groups, s.groups[:s.nOpenGroups]...) + } + return state +} + +// Handle formats the provided record and writes the output to the +// destination. +func (s *SlogTextHandler) Handle(ctx context.Context, r slog.Record) error { + state := s.newHandleState(newBuffer(), true) + defer state.free() + + addTracingContextToRecord(ctx, &r) + + // Built-in attributes. They are not in a group. + stateGroups := state.groups + state.groups = nil // So ReplaceAttrs sees no groups instead of the pre groups. + rep := s.cfg.ReplaceAttr + + if s.withTimestamp && !r.Time.IsZero() { + if rep == nil { + state.appendKey(slog.TimeKey) + state.appendTime(r.Time.Round(0)) + } else { + state.appendAttr(slog.Time(slog.TimeKey, r.Time.Round(0))) + } + } + + // Processing fields in this manner allows users to + // configure the level and component position in the output. + // This matches the behavior of the original logrus. All other + // fields location in the output message are static. + for _, field := range s.cfg.ConfiguredFields { + switch field { + case LevelField: + var color int + var level string + switch r.Level { + case TraceLevel: + level = "TRACE" + color = gray + case slog.LevelDebug: + level = "DEBUG" + color = gray + case slog.LevelInfo: + level = "INFO" + color = blue + case slog.LevelWarn: + level = "WARN" + color = yellow + case slog.LevelError: + level = "ERROR" + color = red + case slog.LevelError + 1: + level = "FATAL" + color = red + default: + color = blue + level = r.Level.String() + } + + if !s.cfg.EnableColors { + color = noColor + } + + level = padMax(level, defaultLevelPadding) + if color != noColor { + level = fmt.Sprintf("\u001B[%dm%s\u001B[0m", color, level) + } + + if rep == nil { + state.appendKey(slog.LevelKey) + // Write the level directly to stat to avoid quoting + // color formatting that exists. + state.buf.WriteString(level) + } else { + state.appendAttr(slog.String(slog.LevelKey, level)) + } + case ComponentField: + // If a component is provided with the attributes, it should be used instead of + // the component set on the handler. Note that if there are multiple components + // specified in the arguments, the one with the lowest index is used and the others are ignored. + // In the example below, the resulting component in the message output would be "alpaca". + // + // logger := logger.With(teleport.ComponentKey, "fish") + // logger.InfoContext(ctx, "llama llama llama", teleport.ComponentKey, "alpaca", "foo", 123, teleport.ComponentKey, "shark") + component := s.component + r.Attrs(func(attr slog.Attr) bool { + if attr.Key != teleport.ComponentKey { + return true + } + component = fmt.Sprintf("[%v]", attr.Value) + component = strings.ToUpper(padMax(component, s.cfg.Padding)) + if component[len(component)-1] != ' ' { + component = component[:len(component)-1] + "]" + } + + return false + }) + + if rep == nil { + state.appendKey(teleport.ComponentKey) + state.appendString(component) + } else { + state.appendAttr(slog.String(teleport.ComponentKey, component)) + } + default: + if _, ok := knownFormatFields[field]; !ok { + return trace.BadParameter("invalid log format key: %v", field) + } + } + } + + if rep == nil { + state.appendKey(slog.MessageKey) + state.appendString(r.Message) + } else { + state.appendAttr(slog.String(slog.MessageKey, r.Message)) + } + + state.groups = stateGroups // Restore groups passed to ReplaceAttrs. + state.appendNonBuiltIns(r) + + if r.PC != 0 && s.withCaller { + fs := runtime.CallersFrames([]uintptr{r.PC}) + f, _ := fs.Next() + + src := slog.Source{ + Function: f.Function, + File: f.File, + Line: f.Line, + } + src.File, src.Line = getCaller(&src) + + if rep == nil { + state.appendKey(slog.SourceKey) + state.appendString(fmt.Sprintf("%s:%d", src.File, src.Line)) + } else { + state.appendAttr(slog.Any(slog.SourceKey, &src)) + } + + } + + state.buf.WriteByte('\n') + + s.mu.Lock() + defer s.mu.Unlock() + _, err := s.out.Write(*state.buf) + return err +} + +func (s *SlogTextHandler) clone() *SlogTextHandler { + // We can't use assignment because we can't copy the mutex. + return &SlogTextHandler{ + cfg: s.cfg, + withCaller: s.withCaller, + withTimestamp: s.withTimestamp, + component: s.component, + preformatted: slices.Clip(s.preformatted), + groupPrefix: s.groupPrefix, + groups: slices.Clip(s.groups), + nOpenGroups: s.nOpenGroups, + out: s.out, + mu: s.mu, // mutex shared among all clones of this handler + } +} + +// WithAttrs clones the current handler with the provided attributes +// added to any existing attributes. The values are preformatted here +// so that they do not need to be formatted per call to Handle. +func (s *SlogTextHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + if len(attrs) == 0 { + return s + } + + s2 := s.clone() + // Pre-format the attributes as an optimization. + state := s2.newHandleState((*buffer)(&s2.preformatted), false) + defer state.free() + state.prefix.WriteString(s.groupPrefix) + + // Remember the position in the buffer, in case all attrs are empty. + pos := state.buf.Len() + state.openGroups() + + nonEmpty := false + for _, a := range attrs { + switch a.Key { + case teleport.ComponentKey: + component := fmt.Sprintf("[%v]", a.Value.String()) + component = strings.ToUpper(padMax(component, s.cfg.Padding)) + if component[len(component)-1] != ' ' { + component = component[:len(component)-1] + "]" + } + s2.component = component + case teleport.ComponentFields: + switch fields := a.Value.Any().(type) { + case map[string]any: + for k, v := range fields { + if state.appendAttr(slog.Any(k, v)) { + nonEmpty = true + } + } + case logrus.Fields: + for k, v := range fields { + if state.appendAttr(slog.Any(k, v)) { + nonEmpty = true + } + } + } + default: + if state.appendAttr(a) { + nonEmpty = true + } + } + } + + if !nonEmpty { + state.buf.SetLen(pos) + } else { + // Remember the new prefix for later keys. + s2.groupPrefix = state.prefix.String() + // Remember how many opened groups are in preformattedAttrs, + // so we don't open them again when we handle a Record. + s2.nOpenGroups = len(s2.groups) + } + + return s2 +} + +// WithGroup opens a new group. +func (s *SlogTextHandler) WithGroup(name string) slog.Handler { + s2 := s.clone() + s2.groups = append(s2.groups, name) + return s2 +} diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 8bb6abd931cfe..d62b7d87d4593 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -657,10 +657,10 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*APIHandler, error) { h.logger.WarnContext(r.Context(), "Failed to generate CSRF token", "error", err) } - session, err := h.authenticateWebSession(w, r) - if err != nil { - h.logger.DebugContext(r.Context(), "Could not authenticate", "error", err) - } + // Ignore errors here, as unauthenticated requests for index.html are common - the user might + // not have logged in yet, or their session may have expired. + // The web app will show them the login page in this case. + session, _ := h.authenticateWebSession(w, r) session.XCSRF = csrfToken session.Version = teleport.Version @@ -726,7 +726,7 @@ type webSession struct { } func (h *Handler) authenticateWebSession(w http.ResponseWriter, r *http.Request) (webSession, error) { - ctx, err := h.AuthenticateRequest(w, r, false) + ctx, err := h.AuthenticateRequest(w, r, false /* validate bearer token */) if err != nil { return webSession{}, trace.Wrap(err) } @@ -1001,6 +1001,7 @@ func (h *Handler) bindDefaultEndpoints() { h.GET("/webapi/scripts/integrations/configure/listdatabases-iam.sh", h.WithLimiter(h.awsOIDCConfigureListDatabasesIAM)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/deployservice", h.WithClusterAuth(h.awsOIDCDeployService)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/deploydatabaseservices", h.WithClusterAuth(h.awsOIDCDeployDatabaseServices)) + h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/listdeployeddatabaseservices", h.WithClusterAuth(h.awsOIDCListDeployedDatabaseService)) h.GET("/webapi/scripts/integrations/configure/deployservice-iam.sh", h.WithLimiter(h.awsOIDCConfigureDeployServiceIAM)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/ec2", h.WithClusterAuth(h.awsOIDCListEC2)) h.POST("/webapi/sites/:site/integrations/aws-oidc/:name/eksclusters", h.WithClusterAuth(h.awsOIDCListEKSClusters)) diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index 44444f191c149..844391b1523f9 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -23,6 +23,8 @@ import ( "encoding/base64" "encoding/json" "fmt" + "log/slog" + "maps" "net/http" "net/url" "slices" @@ -31,6 +33,7 @@ import ( "github.com/google/safetext/shsprintf" "github.com/gravitational/trace" "github.com/julienschmidt/httprouter" + "google.golang.org/grpc" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client" @@ -39,6 +42,7 @@ import ( apidefaults "github.com/gravitational/teleport/api/defaults" integrationv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/types/discoveryconfig" "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/aws" "github.com/gravitational/teleport/lib/auth/authclient" @@ -49,6 +53,7 @@ import ( kubeutils "github.com/gravitational/teleport/lib/kube/utils" "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" + libui "github.com/gravitational/teleport/lib/ui" libutils "github.com/gravitational/teleport/lib/utils" awsutils "github.com/gravitational/teleport/lib/utils/aws" "github.com/gravitational/teleport/lib/utils/oidc" @@ -260,6 +265,228 @@ func (h *Handler) awsOIDCDeployDatabaseServices(w http.ResponseWriter, r *http.R }, nil } +// awsOIDCListDeployedDatabaseService lists the deployed Database Services in Amazon ECS. +func (h *Handler) awsOIDCListDeployedDatabaseService(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { + ctx := r.Context() + clt, err := sctx.GetUserClient(ctx, site) + if err != nil { + return nil, trace.Wrap(err) + } + + integrationName := p.ByName("name") + if integrationName == "" { + return nil, trace.BadParameter("an integration name is required") + } + + regions, err := fetchRelevantAWSRegions(ctx, clt, clt.DiscoveryConfigClient()) + if err != nil { + return nil, trace.Wrap(err) + } + + services, err := listDeployedDatabaseServices(ctx, h.logger, integrationName, regions, clt.IntegrationAWSOIDCClient()) + if err != nil { + return nil, trace.Wrap(err) + } + + return ui.AWSOIDCListDeployedDatabaseServiceResponse{ + Services: services, + }, nil +} + +type databaseGetter interface { + GetResources(ctx context.Context, req *proto.ListResourcesRequest) (*proto.ListResourcesResponse, error) + GetDatabases(context.Context) ([]types.Database, error) +} + +type discoveryConfigLister interface { + ListDiscoveryConfigs(ctx context.Context, pageSize int, nextToken string) ([]*discoveryconfig.DiscoveryConfig, string, error) +} + +func fetchRelevantAWSRegions(ctx context.Context, authClient databaseGetter, discoveryConfigsClient discoveryConfigLister) ([]string, error) { + regionsSet := make(map[string]struct{}) + + // Collect Regions from Database resources. + databases, err := authClient.GetDatabases(ctx) + if err != nil { + return nil, trace.Wrap(err) + } + + for _, resource := range databases { + regionsSet[resource.GetAWS().Region] = struct{}{} + regionsSet[resource.GetAllLabels()[types.DiscoveryLabelRegion]] = struct{}{} + } + + // Iterate over all DatabaseServices and fetch their AWS Region in the matchers. + var nextPageKey string + for { + req := &proto.ListResourcesRequest{ + ResourceType: types.KindDatabaseService, + Limit: defaults.MaxIterationLimit, + StartKey: nextPageKey, + Labels: map[string]string{types.AWSOIDCAgentLabel: types.True}, + } + page, err := client.GetResourcePage[types.DatabaseService](ctx, authClient, req) + if err != nil { + return nil, trace.Wrap(err) + } + + maps.Copy(regionsSet, extractRegionsFromDatabaseServicesPage(page.Resources)) + + if page.NextKey == "" { + break + } + nextPageKey = page.NextKey + } + + // Iterate over all DiscoveryConfigs and fetch their AWS Region in AWS Matchers. + nextPageKey = "" + for { + resp, respNextPageKey, err := discoveryConfigsClient.ListDiscoveryConfigs(ctx, defaults.MaxIterationLimit, nextPageKey) + if err != nil { + return nil, trace.Wrap(err) + } + + maps.Copy(regionsSet, extractRegionsFromDiscoveryConfigPage(resp)) + + if respNextPageKey == "" { + break + } + nextPageKey = respNextPageKey + } + + // Drop any invalid region. + ret := make([]string, 0, len(regionsSet)) + for region := range regionsSet { + if aws.IsValidRegion(region) == nil { + ret = append(ret, region) + } + } + + return ret, nil +} + +func extractRegionsFromDatabaseServicesPage(dbServices []types.DatabaseService) map[string]struct{} { + regionsSet := make(map[string]struct{}) + for _, resource := range dbServices { + for _, matcher := range resource.GetResourceMatchers() { + if matcher.Labels == nil { + continue + } + for labelKey, labelValues := range *matcher.Labels { + if labelKey != types.DiscoveryLabelRegion { + continue + } + for _, labelValue := range labelValues { + regionsSet[labelValue] = struct{}{} + } + } + } + } + + return regionsSet +} + +func extractRegionsFromDiscoveryConfigPage(discoveryConfigs []*discoveryconfig.DiscoveryConfig) map[string]struct{} { + regionsSet := make(map[string]struct{}) + + for _, dc := range discoveryConfigs { + for _, awsMatcher := range dc.Spec.AWS { + for _, region := range awsMatcher.Regions { + regionsSet[region] = struct{}{} + } + } + } + + return regionsSet +} + +type deployedDatabaseServiceLister interface { + ListDeployedDatabaseServices(ctx context.Context, in *integrationv1.ListDeployedDatabaseServicesRequest, opts ...grpc.CallOption) (*integrationv1.ListDeployedDatabaseServicesResponse, error) +} + +func listDeployedDatabaseServices(ctx context.Context, + logger *slog.Logger, + integrationName string, + regions []string, + awsOIDCClient deployedDatabaseServiceLister, +) ([]ui.AWSOIDCDeployedDatabaseService, error) { + var services []ui.AWSOIDCDeployedDatabaseService + for _, region := range regions { + var nextToken string + for { + resp, err := awsOIDCClient.ListDeployedDatabaseServices(ctx, &integrationv1.ListDeployedDatabaseServicesRequest{ + Integration: integrationName, + Region: region, + NextToken: nextToken, + }) + if err != nil { + return nil, trace.Wrap(err) + } + + for _, deployedDatabaseService := range resp.DeployedDatabaseServices { + matchingLabels, err := matchingLabelsFromDeployedService(deployedDatabaseService) + if err != nil { + logger.WarnContext(ctx, "Failed to obtain teleport config string from ECS Service", + "ecs_service", deployedDatabaseService.ServiceDashboardUrl, + "error", err, + ) + } + validTeleportConfigFound := err == nil + + services = append(services, ui.AWSOIDCDeployedDatabaseService{ + Name: deployedDatabaseService.Name, + DashboardURL: deployedDatabaseService.ServiceDashboardUrl, + MatchingLabels: matchingLabels, + ValidTeleportConfig: validTeleportConfigFound, + }) + } + + if resp.NextToken == "" { + break + } + nextToken = resp.NextToken + } + } + return services, nil +} + +func matchingLabelsFromDeployedService(deployedDatabaseService *integrationv1.DeployedDatabaseService) ([]libui.Label, error) { + commandArgs := deployedDatabaseService.ContainerCommand + // This command is what starts the teleport agent in the ECS Service Fargate container. + // See deployservice.go/upsertTask for details. + // It is expected to have at least 3 values, even if dumb-init is removed in the future. + if len(commandArgs) < 3 { + return nil, trace.BadParameter("unexpected command size, expected at least 3 args, got %d", len(commandArgs)) + } + + // The command should have a --config-string flag and then the teleport's base64 encoded configuration as argument + teleportConfigStringFlagIdx := slices.Index(commandArgs, "--config-string") + if teleportConfigStringFlagIdx == -1 { + return nil, trace.BadParameter("missing --config-string flag in container command") + } + if len(commandArgs) < teleportConfigStringFlagIdx+1 { + return nil, trace.BadParameter("missing --config-string argument in container command") + } + teleportConfigString := commandArgs[teleportConfigStringFlagIdx+1] + + labelMatchers, err := deployserviceconfig.ParseResourceLabelMatchers(teleportConfigString) + if err != nil { + return nil, trace.Wrap(err) + } + + var matchingLabels []libui.Label + for labelKey, labelValues := range labelMatchers { + for _, labelValue := range labelValues { + matchingLabels = append(matchingLabels, libui.Label{ + Name: labelKey, + Value: labelValue, + }) + } + } + + return matchingLabels, nil +} + // awsOIDCConfigureDeployServiceIAM returns a script that configures the required IAM permissions to enable the usage of DeployService action. func (h *Handler) awsOIDCConfigureDeployServiceIAM(w http.ResponseWriter, r *http.Request, p httprouter.Params) (any, error) { ctx := r.Context() diff --git a/lib/web/integrations_awsoidc_test.go b/lib/web/integrations_awsoidc_test.go index 9b2660fe36e99..b8414570999dc 100644 --- a/lib/web/integrations_awsoidc_test.go +++ b/lib/web/integrations_awsoidc_test.go @@ -23,6 +23,7 @@ import ( "encoding/base64" "fmt" "net/url" + "strconv" "strings" "testing" @@ -31,13 +32,18 @@ import ( "github.com/google/uuid" "github.com/gravitational/trace" "github.com/stretchr/testify/require" + "google.golang.org/grpc" "github.com/gravitational/teleport/api" "github.com/gravitational/teleport/api/client/proto" integrationv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/integration/v1" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/types/discoveryconfig" "github.com/gravitational/teleport/lib/integrations/awsoidc" + "github.com/gravitational/teleport/lib/integrations/awsoidc/deployserviceconfig" "github.com/gravitational/teleport/lib/services" + libui "github.com/gravitational/teleport/lib/ui" + "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/web/ui" ) @@ -1146,3 +1152,331 @@ func TestAWSOIDCAppAccessAppServerCreationDeletion(t *testing.T) { require.NoError(t, err) }) } + +type mockDeployedDatabaseServices struct { + integration string + servicesPerRegion map[string][]*integrationv1.DeployedDatabaseService +} + +func (m *mockDeployedDatabaseServices) ListDeployedDatabaseServices(ctx context.Context, in *integrationv1.ListDeployedDatabaseServicesRequest, opts ...grpc.CallOption) (*integrationv1.ListDeployedDatabaseServicesResponse, error) { + const pageSize = 10 + ret := &integrationv1.ListDeployedDatabaseServicesResponse{} + if in.Integration != m.integration { + return ret, nil + } + + services := m.servicesPerRegion[in.Region] + if len(services) == 0 { + return ret, nil + } + + requestedPage := 1 + totalResources := len(services) + + if in.NextToken != "" { + currentMarker, err := strconv.Atoi(in.NextToken) + if err != nil { + return nil, trace.Wrap(err) + } + requestedPage = currentMarker + } + + sliceStart := pageSize * (requestedPage - 1) + sliceEnd := pageSize * requestedPage + if sliceEnd > totalResources { + sliceEnd = totalResources + } + + ret.DeployedDatabaseServices = services[sliceStart:sliceEnd] + if sliceEnd < totalResources { + ret.NextToken = strconv.Itoa(requestedPage + 1) + } + + return ret, nil +} + +func TestAWSOIDCListDeployedDatabaseServices(t *testing.T) { + ctx := context.Background() + logger := utils.NewSlogLoggerForTests() + + for _, tt := range []struct { + name string + integration string + regions []string + servicesPerRegion func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService + expectedServices func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService + }{ + { + name: "valid", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, true, types.Labels{"vpc": []string{"vpc1", "vpc2"}}) + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-2": dummyDeployedDatabaseServices(1, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + return []ui.AWSOIDCDeployedDatabaseService{{ + Name: "database-service-vpc-0", + DashboardURL: "url", + ValidTeleportConfig: true, + MatchingLabels: []libui.Label{ + {Name: "vpc", Value: "vpc1"}, + {Name: "vpc", Value: "vpc2"}, + }, + }} + }, + }, + { + name: "no regions", + integration: "my-integration", + regions: []string{}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + return make(map[string][]*integrationv1.DeployedDatabaseService) + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { return nil }, + }, + { + name: "no services", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + return make(map[string][]*integrationv1.DeployedDatabaseService) + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { return nil }, + }, + { + name: "services exist but for another region", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-1": dummyDeployedDatabaseServices(1, []string{}), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { return nil }, + }, + { + name: "services exist for multiple regions", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, true, types.Labels{"vpc": []string{"vpc1", "vpc2"}}) + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-1": dummyDeployedDatabaseServices(1, command), + "us-west-2": dummyDeployedDatabaseServices(1, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + return []ui.AWSOIDCDeployedDatabaseService{{ + Name: "database-service-vpc-0", + DashboardURL: "url", + ValidTeleportConfig: true, + MatchingLabels: []libui.Label{ + {Name: "vpc", Value: "vpc1"}, + {Name: "vpc", Value: "vpc2"}, + }, + }} + }, + }, + { + name: "service exist but has invalid configuration", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, false, nil) + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-2": dummyDeployedDatabaseServices(1, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + return []ui.AWSOIDCDeployedDatabaseService{{ + Name: "database-service-vpc-0", + DashboardURL: "url", + ValidTeleportConfig: false, + }} + }, + }, + { + name: "service exist but was changed and --config-string argument is missing", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, true, types.Labels{"vpc": []string{"vpc1", "vpc2"}}) + command = command[:len(command)-1] + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-2": dummyDeployedDatabaseServices(1, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + return []ui.AWSOIDCDeployedDatabaseService{{ + Name: "database-service-vpc-0", + DashboardURL: "url", + ValidTeleportConfig: false, + }} + }, + }, + { + name: "service exist but was changed and --config-string flag is missing", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, true, types.Labels{"vpc": []string{"vpc1", "vpc2"}}) + command[1] = "--no-config-string" + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-2": dummyDeployedDatabaseServices(1, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + return []ui.AWSOIDCDeployedDatabaseService{{ + Name: "database-service-vpc-0", + DashboardURL: "url", + ValidTeleportConfig: false, + }} + }, + }, + { + name: "supports pagination", + integration: "my-integration", + regions: []string{"us-west-2"}, + servicesPerRegion: func(t *testing.T) map[string][]*integrationv1.DeployedDatabaseService { + command := buildCommandDeployedDatabaseService(t, true, types.Labels{"vpc": []string{"vpc1", "vpc2"}}) + return map[string][]*integrationv1.DeployedDatabaseService{ + "us-west-2": dummyDeployedDatabaseServices(1_024, command), + } + }, + expectedServices: func(t *testing.T) []ui.AWSOIDCDeployedDatabaseService { + var ret []ui.AWSOIDCDeployedDatabaseService + for i := 0; i < 1_024; i++ { + ret = append(ret, ui.AWSOIDCDeployedDatabaseService{ + Name: fmt.Sprintf("database-service-vpc-%d", i), + DashboardURL: "url", + ValidTeleportConfig: true, + MatchingLabels: []libui.Label{ + {Name: "vpc", Value: "vpc1"}, + {Name: "vpc", Value: "vpc2"}, + }, + }) + } + return ret + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + clt := &mockDeployedDatabaseServices{ + integration: tt.integration, + servicesPerRegion: tt.servicesPerRegion(t), + } + actual, err := listDeployedDatabaseServices(ctx, logger, tt.integration, tt.regions, clt) + require.NoError(t, err) + expected := tt.expectedServices(t) + require.Equal(t, expected, actual) + }) + } +} + +func buildCommandDeployedDatabaseService(t *testing.T, valid bool, matchingLabels types.Labels) []string { + t.Helper() + if !valid { + return []string{"not valid"} + } + + ret, err := deployserviceconfig.GenerateTeleportConfigString("host", "token", matchingLabels) + require.NoError(t, err) + + return []string{"start", "--config-string", ret} +} + +func dummyDeployedDatabaseServices(count int, command []string) []*integrationv1.DeployedDatabaseService { + var ret []*integrationv1.DeployedDatabaseService + for i := 0; i < count; i++ { + ret = append(ret, &integrationv1.DeployedDatabaseService{ + Name: fmt.Sprintf("database-service-vpc-%d", i), + ServiceDashboardUrl: "url", + ContainerEntryPoint: []string{"teleport"}, + ContainerCommand: command, + }) + } + return ret +} + +func TestFetchRelevantAWSRegions(t *testing.T) { + ctx := context.Background() + + t.Run("resources do not provide any region", func(t *testing.T) { + clt := &mockRelevantAWSRegionsClient{ + databaseServices: &proto.ListResourcesResponse{ + Resources: []*proto.PaginatedResource{}, + }, + databases: make([]types.Database, 0), + discoveryConfigs: make([]*discoveryconfig.DiscoveryConfig, 0), + } + gotRegions, err := fetchRelevantAWSRegions(ctx, clt, clt) + require.NoError(t, err) + require.Empty(t, gotRegions) + }) + + t.Run("resources provide multiple regions", func(t *testing.T) { + clt := &mockRelevantAWSRegionsClient{ + databaseServices: &proto.ListResourcesResponse{ + Resources: []*proto.PaginatedResource{{Resource: &proto.PaginatedResource_DatabaseService{ + DatabaseService: &types.DatabaseServiceV1{Spec: types.DatabaseServiceSpecV1{ + ResourceMatchers: []*types.DatabaseResourceMatcher{ + {Labels: &types.Labels{"region": []string{"us-east-1"}}}, + {Labels: &types.Labels{"region": []string{"us-east-2"}}}, + }, + }}, + }}}, + }, + databases: []types.Database{ + &types.DatabaseV3{Spec: types.DatabaseSpecV3{AWS: types.AWS{Region: "us-west-1"}}}, + &types.DatabaseV3{Metadata: types.Metadata{Labels: map[string]string{"region": "us-west-2"}}}, + }, + discoveryConfigs: []*discoveryconfig.DiscoveryConfig{{ + Spec: discoveryconfig.Spec{AWS: []types.AWSMatcher{{ + Regions: []string{"eu-west-1", "eu-west-2"}, + }}}, + }}, + } + gotRegions, err := fetchRelevantAWSRegions(ctx, clt, clt) + require.NoError(t, err) + expectedRegions := []string{"us-east-1", "us-east-2", "us-west-1", "us-west-2", "eu-west-1", "eu-west-2"} + require.ElementsMatch(t, expectedRegions, gotRegions) + }) + + t.Run("invalid regions are ignored", func(t *testing.T) { + clt := &mockRelevantAWSRegionsClient{ + databaseServices: &proto.ListResourcesResponse{ + Resources: []*proto.PaginatedResource{}, + }, + databases: []types.Database{ + &types.DatabaseV3{Spec: types.DatabaseSpecV3{AWS: types.AWS{Region: "us-west-1"}}}, + &types.DatabaseV3{Metadata: types.Metadata{Labels: map[string]string{"region": "bad-region"}}}, + }, + discoveryConfigs: make([]*discoveryconfig.DiscoveryConfig, 0), + } + gotRegions, err := fetchRelevantAWSRegions(ctx, clt, clt) + require.NoError(t, err) + expectedRegions := []string{"us-west-1"} + require.ElementsMatch(t, expectedRegions, gotRegions) + }) +} + +type mockRelevantAWSRegionsClient struct { + databaseServices *proto.ListResourcesResponse + databases []types.Database + discoveryConfigs []*discoveryconfig.DiscoveryConfig +} + +func (m *mockRelevantAWSRegionsClient) GetResources(ctx context.Context, req *proto.ListResourcesRequest) (*proto.ListResourcesResponse, error) { + return m.databaseServices, nil +} + +func (m *mockRelevantAWSRegionsClient) GetDatabases(context.Context) ([]types.Database, error) { + return m.databases, nil +} + +func (m *mockRelevantAWSRegionsClient) ListDiscoveryConfigs(ctx context.Context, pageSize int, nextToken string) ([]*discoveryconfig.DiscoveryConfig, string, error) { + return m.discoveryConfigs, "", nil +} diff --git a/lib/web/terminal.go b/lib/web/terminal.go index d9f20cd5396d7..9b3a109714eed 100644 --- a/lib/web/terminal.go +++ b/lib/web/terminal.go @@ -915,7 +915,7 @@ func (t *sshBaseHandler) connectToNode(ctx context.Context, ws terminal.WSConn, if err != nil { t.logger.WarnContext(ctx, "Unable to stream terminal - failed to dial host", "error", err) - if errors.Is(err, trace.NotFound(teleport.NodeIsAmbiguous)) { + if errors.Is(err, teleport.ErrNodeIsAmbiguous) { const message = "error: ambiguous host could match multiple nodes\n\nHint: try addressing the node by unique id (ex: user@node-id)\n" return nil, trace.NotFound(message) } diff --git a/lib/web/ui/integration.go b/lib/web/ui/integration.go index b08143978df21..3614a51d09a7f 100644 --- a/lib/web/ui/integration.go +++ b/lib/web/ui/integration.go @@ -371,6 +371,26 @@ type AWSOIDCDeployDatabaseServiceResponse struct { ClusterDashboardURL string `json:"clusterDashboardUrl"` } +// AWSOIDCDeployedDatabaseService represents a Teleport Database Service that is deployed in Amazon ECS. +type AWSOIDCDeployedDatabaseService struct { + // Name is the ECS Service name. + Name string `json:"name,omitempty"` + // DashboardURL is the link to the ECS Service in Amazon Web Console. + DashboardURL string `json:"dashboardUrl,omitempty"` + // ValidTeleportConfig returns whether this ECS Service has a valid Teleport Configuration for a deployed Database Service. + // ECS Services with non-valid configuration require the user to take action on them. + // No MatchingLabels are returned with an invalid configuration. + ValidTeleportConfig bool `json:"validTeleportConfig,omitempty"` + // MatchingLabels are the labels that are used by the Teleport Database Service to know which databases it should proxy. + MatchingLabels []ui.Label `json:"matchingLabels,omitempty"` +} + +// AWSOIDCListDeployedDatabaseServiceResponse is a list of Teleport Database Services that are deployed as ECS Services. +type AWSOIDCListDeployedDatabaseServiceResponse struct { + // Services are the ECS Services. + Services []AWSOIDCDeployedDatabaseService `json:"services"` +} + // AWSOIDCEnrollEKSClustersRequest is a request to ListEKSClusters using the AWS OIDC Integration. type AWSOIDCEnrollEKSClustersRequest struct { // Region is the AWS Region. diff --git a/proto/accessgraph/v1alpha/access_graph_service.proto b/proto/accessgraph/v1alpha/access_graph_service.proto index b78b473327ffe..7e61325e64a66 100644 --- a/proto/accessgraph/v1alpha/access_graph_service.proto +++ b/proto/accessgraph/v1alpha/access_graph_service.proto @@ -26,6 +26,7 @@ import "accessgraph/v1alpha/entra.proto"; import "accessgraph/v1alpha/events.proto"; import "accessgraph/v1alpha/gitlab.proto"; import "accessgraph/v1alpha/graph.proto"; +import "accessgraph/v1alpha/netiq.proto"; import "accessgraph/v1alpha/resources.proto"; option go_package = "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha;accessgraphv1alpha"; @@ -90,6 +91,9 @@ service AccessGraphService { // AzureEventsStream is a stream of commands to the Azure importer rpc AzureEventsStream(stream AzureEventsStreamRequest) returns (stream AzureEventsStreamResponse); + + // NetIQEventsStream is a stream of commands to the NetIQ importer. + rpc NetIQEventsStream(stream NetIQEventsStreamRequest) returns (stream NetIQEventsStreamResponse); } // QueryRequest is a request to query the access graph. @@ -289,3 +293,22 @@ message AzureSyncOperation {} // AzureEventsStreamResponse is a response from AzureEventsStream message AzureEventsStreamResponse {} + +// NetIQEventsStreamRequest is a request to send commands to the NetIQ importer +message NetIQEventsStreamRequest { + oneof operation { + // sync is a command to sync the access graph with the NetIQ state. + NetIQSyncOperation sync = 1; + // upsert is a command to put a resource into the access graph or update it. + NetIQResourceList upsert = 2; + // delete is a command to delete a resource from the access graph when it's deleted. + NetIQResourceList delete = 3; + } +} + +// NetIQSyncOperation is a command that Teleport sends to the access graph service +// at the end of the sync process. +message NetIQSyncOperation {} + +// NetIQEventsStreamResponse is a response from NetIQEventsStream +message NetIQEventsStreamResponse {} diff --git a/proto/accessgraph/v1alpha/netiq.proto b/proto/accessgraph/v1alpha/netiq.proto new file mode 100644 index 0000000000000..eb108781bbaaa --- /dev/null +++ b/proto/accessgraph/v1alpha/netiq.proto @@ -0,0 +1,187 @@ +/* + * 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 . + */ + +syntax = "proto3"; + +package accessgraph.v1alpha; + +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/gravitational/teleport/gen/proto/go/accessgraph/v1alpha;accessgraphv1alpha"; + +// NetIQResourceList is a request that contains resources to be sync. +message NetIQResourceList { + // resources is a list of NetIQ resources to sync. + repeated NetIQObject resources = 1; +} + +// NetIQObject represents a NetIQ resource +message NetIQObject { + oneof object { + // group represents a NetIQ group in an organization. + NetIQGroup group = 1; + // group_member represents a NetIQ group member. + NetIQGroupMember group_member = 2; + // resource represents a NetIQ resource. + NetIQResource resource = 3; + // role represents a role with certain access levels to a resource. + NetIQRole role = 4; + // parent_role_ref represents a parent relationship between roles. + NetIQRoleRef parent_role_ref = 5; + // user represents a NetIQ user. + NetIQUser user = 6; + // resource_role_ref represents a resource assignment to a role. + NetIQResourceAssignmentRef resource_role_ref = 7; + //role_member_ref represents a member being member of a role. + NetIQMemberAssignmentRef role_member_ref = 8; + } +} + +// NetIQGroup represents a NetIQ group +message NetIQGroup { + // name is the group name. + string name = 1; + // id is the universal identifier for the group. + string id = 2; + // description is the group description. + string description = 3; +} + +// NetIQGroupMember represents a NetIQ group member +message NetIQGroupMember { + // group_id is the group id. + string group_id = 1; + // user_id is the universal identifier for the user. + string user_id = 2; + // is_group_assignment is a flag that determines whether the member is a group assignment. + bool is_group_assignment = 3; +} + +// NetIQResource represents a NetIQ resource +message NetIQResource { + // name is the resource name. + string name = 1; + // id is the universal identifier for the resource. + string id = 2; + // description is the project description. + string description = 3; + + // categories is the list of categories the resource belongs to. + repeated NetIQCategory categories = 4; +} + +// NetIQCategory is a resource category. +message NetIQCategory { + // name is the resource name. + string name = 1; + // id is the universal identifier for the category. + string id = 2; +} + +// NetIQRole represents a NetIQ role +message NetIQRole { + // name is the resource name. + string name = 1; + // id is the universal identifier for the role. + string id = 2; + // description is the project description. + string description = 3; + // categories is the list of categories the resource belongs to. + repeated NetIQCategory categories = 4; + + // RoleLevel represents the role level. + message RoleLevel { + // name is the name of the role level. + string name = 1; + // level is the level of the role level. + int32 level = 2; + // cn is the common name. + string cn = 3; + } + RoleLevel level = 5; +} + +// NetIQRoleRef represents a NetIQ Role reference. +message NetIQRoleRef { + // child_role_id is the group id of a role that is a child role of parent_role_id. + string child_role_id = 1; + // parent_role_id is the universal identifier for the role that is parent to child_role_id. + string parent_role_id = 2; + // level is the level of the role. + int32 level = 3; + // request_description is the description of the request. + string request_description = 4; +} + +// NetIQUser represents a NetIQ user. +message NetIQUser { + // id is the id of the user. + string id = 1; + // email is the user's email. + string email = 2; + // name is the user's name. + string name = 3; + // is_disabled indicates if a user is disabled. + bool is_disabled = 4; +} + +// NetIQResourceAssignmentRef represents a NetIQ resource assignment reference. +message NetIQResourceAssignmentRef { + // role_id is the group id of a role that is assigned to resource_id. + string role_id = 1; + // resource_id is the universal identifier for the resource that is assigned to role_id. + string resource_id = 2; + // mapping_description is the description of the mapping. + string mapping_description = 4; + // status_code is the status code of the role assignment. + uint32 status_code = 5; +} + +// NetIQMemberAssignmentRef represents a NetIQ resource assignment reference. +message NetIQMemberAssignmentRef { + // role_id is the group id of a role that user_id is member of. + string role_id = 1; + // dn is the universal identifier for the user that is member of role_id. + string dn = 2; + // recipient_type identifies the recipient provenance. + RoleRecipientType recipient_type = 3; + // recipient_type_subcontainer is the sub container of the recipient type. + string recipient_type_subcontainer = 4; + // status_code is the status code of the role assignment. + uint32 status_code = 5; + // StatusDstatus_displayisplay is the display of the status. + string status_display = 6; + // effective_date is the effective date of the role assignment. + google.protobuf.Timestamp effective_date = 7; + // expiry_date is the expiry date of the role assignment. + google.protobuf.Timestamp expiry_date = 8; + // description is the description of the role assignment. + string description = 9; + // grant is a flag that determines whether the role assignment is granted. + bool grant = 10; +} + +// RoleRecipientType is the type of the recipient. +enum RoleRecipientType { + // ROLE_RECIPIENT_TYPE_UNSPECIFIED is a unspecified role recipient type. + ROLE_RECIPIENT_TYPE_UNSPECIFIED = 0; + // ROLE_RECIPIENT_TYPE_USER represents a user being member of a role. + ROLE_RECIPIENT_TYPE_USER = 1; + // ROLE_RECIPIENT_TYPE_GROUP represents a group being member of a role. + ROLE_RECIPIENT_TYPE_GROUP = 2; +} diff --git a/rfd/0016-dynamic-configuration.md b/rfd/0016-dynamic-configuration.md index 0b941d55c00bb..892f6e5fe1683 100644 --- a/rfd/0016-dynamic-configuration.md +++ b/rfd/0016-dynamic-configuration.md @@ -65,7 +65,7 @@ ensure backward compatibility with the already established workflows. #### Choice 2.A In this option, dynamic-configuration resources are understood to exist only -if they have been comitted as a result of having been specified in static +if they have been committed as a result of having been specified in static configuration or via `tctl create`. 3. The command `tctl get cap` would therefore return an error saying diff --git a/rfd/0047-drop-vendor.md b/rfd/0047-drop-vendor.md index 3a5fffd925bd8..b79f282a1d15f 100644 --- a/rfd/0047-drop-vendor.md +++ b/rfd/0047-drop-vendor.md @@ -97,7 +97,7 @@ which is difficult to maintain in a cross-platform way, and has broken [gopls integration](https://github.com/gravitational/teleport/blob/30effc1f08b6a699772ff22f79ebe756fe1a1e34/Makefile#L942-L952) a common tool used in Go development environments. -Lastly, there is no guarantee that the code comitted to vendor actually +Lastly, there is no guarantee that the code committed to vendor actually reflects the contents of go.mod. The onus is on the developer to remember to run `make update-vendor` and commit the results after making changes to dependencies. This has created several cases of confusing build results amongst diff --git a/rfd/0055-webui-ss-paginate-filter.md b/rfd/0055-webui-ss-paginate-filter.md index c4ee111769b43..d674ae9fc0daa 100644 --- a/rfd/0055-webui-ss-paginate-filter.md +++ b/rfd/0055-webui-ss-paginate-filter.md @@ -77,7 +77,7 @@ This technique does not support sorting, but provides faster performance and is The web UI will not request for the entire list of resources upfront, but will provide a user with a `fetch more` button if a user desires to see the next page if any. -We can branch off into two functions with current `ListResources` based on if sorting was requested (orting will be disabled for `tsh`, so that `tsh` performance will not be affected): +We can branch off into two functions with current `ListResources` based on if sorting was requested (sorting will be disabled for `tsh`, so that `tsh` performance will not be affected): - `listResources` (keeps current behavior) - `listResourcesWithSort` diff --git a/rfd/0067-desktop-access-file-system-sharing.md b/rfd/0067-desktop-access-file-system-sharing.md index f1870de298c93..7ef8b2fd30905 100644 --- a/rfd/0067-desktop-access-file-system-sharing.md +++ b/rfd/0067-desktop-access-file-system-sharing.md @@ -490,7 +490,7 @@ requested by RDP. For files, `last_modified` is the last modified time of the file as specified by the [`mtime`](https://www.makeuseof.com/linux-file-timestamps/), in milliseconds since the [UNIX epoch](https://en.wikipedia.org/wiki/Unix_time). For directories, `last_modified` should also be set to the -[directory's `mtime`](https://stackoverflow.com/a/3620704/6277051) when suchinformation is available. If such information is unavailable for a directory, such as +[directory's `mtime`](https://stackoverflow.com/a/3620704/6277051) when such information is available. If such information is unavailable for a directory, such as in a browser environment, this value should be assigned the UNIX epoch itself (0). For files, `size` is the size of the file in bytes. For directories, `size` is not the total size of the contents of the diff --git a/rfd/0073-discover.md b/rfd/0073-discover.md index 5d9e00944b958..21c094fb534d0 100644 --- a/rfd/0073-discover.md +++ b/rfd/0073-discover.md @@ -202,7 +202,7 @@ auto-discovery by going through the following flow: 3. The selected agent will perform initial discovery according to the provided filters. This can be implemented by providing an API for the web UI to create a "discovery request" which agents will watch. -4. The agent will attempt to fullfill the discovery request and will report +4. The agent will attempt to fulfill the discovery request and will report errors, e.g. insufficient IAM policy, to the user. This can be implemented by filling out a Status field on the agent's resource spec. 5. If successful, the UI wizard will display all resources matching the diff --git a/rfd/0083-machine-id-host-certs.md b/rfd/0083-machine-id-host-certs.md index 72ab3dfae912c..892471357c882 100644 --- a/rfd/0083-machine-id-host-certs.md +++ b/rfd/0083-machine-id-host-certs.md @@ -165,7 +165,7 @@ Are you sure you want to continue connecting (yes/no/[fingerprint])? This is nearly identical to the usual ssh TOFU message, save for the easy-to-miss "Certificate invalid: expired" message. Users are likely conditioned to accept this, and if that happens the expired or invalid host key -will be comitted to their `known_hosts` permanently, after which the "expired" +will be committed to their `known_hosts` permanently, after which the "expired" message will not be shown again. We'll need to document this caveat along with a workaround (e.g. a diff --git a/rfd/0084-license-expiration-warnings.md b/rfd/0084-license-expiration-warnings.md index 1baa850f6fc9f..6c5bd48080227 100644 --- a/rfd/0084-license-expiration-warnings.md +++ b/rfd/0084-license-expiration-warnings.md @@ -9,7 +9,7 @@ state: implemented ## Required approvers - Engineering: `@r0mant` -- Product: `@klizentas && @xinding33` +- Product: `@klizhentas && @xinding33` - Security: `@reedloden` ## What diff --git a/rfd/0089-merge-webapps.md b/rfd/0089-merge-webapps.md index 224c9ff34ce71..01e4b0f4f1224 100644 --- a/rfd/0089-merge-webapps.md +++ b/rfd/0089-merge-webapps.md @@ -187,7 +187,7 @@ build systems to successfully build Teleport. - [ ] Remove `/webassets` submodule - This submodule is no longer required as the web UI will be built on-demand. - The folder will remain as the output location of the on-demand build but - will not be comitted. + will not be committed. - [ ] Clone the [Webapps repository](https://github.com/gravitational/webapps) into the Teleport root. [Maintaining their respective git histories](https://stackoverflow.com/questions/13040958/merge-two-git-repositories-without-breaking-file-history) - [ ] This will need to be done for every respective version branch (v9, v10, v11) diff --git a/rfd/0122-moderated-file-transfers.md b/rfd/0122-moderated-file-transfers.md index 14e730dfb64c4..98e1de235c377 100644 --- a/rfd/0122-moderated-file-transfers.md +++ b/rfd/0122-moderated-file-transfers.md @@ -136,7 +136,7 @@ OnApprove: 3. We can then use a policy checker to see if the approvers fulfill any moderation policy on the original requester. We can treat this check the same as the `checkIfStart` conditional for opening a session. If this comes back true, we notify the original requester with an event containing the ID of the `FileTransferRequest` Once the client receives this final "approved" message, we can automatically send a "normal" SFTP request (over HTTP) with two new optional params, `sessionID` and `commandRequestId` (similar to the new optional `webauthn` param in this same request). The benefits of using the normal SFTP request is that we can conditionally choose to skip this entire approval process flow for non-moderated sessions. -If the session is not moderated, just send the SFTP request as usual. If it is, do the song and dance perscribed above. +If the session is not moderated, just send the SFTP request as usual. If it is, do the song and dance prescribed above. ### Updated file transfer api handler diff --git a/rfd/0133-connect-my-computer.md b/rfd/0133-connect-my-computer.md index 69cdc7964da44..a15bcdc2b7a9c 100644 --- a/rfd/0133-connect-my-computer.md +++ b/rfd/0133-connect-my-computer.md @@ -417,7 +417,7 @@ agent. This follows from the behavior described in the “Downloading the agent #### Log rotation -The MVP is not going to perform any extra log rotation beyond what the Teleport agent offerts out of +The MVP is not going to perform any extra log rotation beyond what the Teleport agent offers out of the box which is creating a new log file every 24 hours. The logs are thus stored in the same directory as the data directory of the agent and are removed together with the agent. diff --git a/rfd/0143-external-k8s-joining.md b/rfd/0143-external-k8s-joining.md index 0e1ab83eda266..306719be3c468 100644 --- a/rfd/0143-external-k8s-joining.md +++ b/rfd/0143-external-k8s-joining.md @@ -294,7 +294,7 @@ traced back to a specific Kubernetes pod. ## Alternatives -### Introducing a seperate `kubernetes_remote` join method +### Introducing a separate `kubernetes_remote` join method One alternative implementation was to introduce a new `kubernetes_remote` join method that would use a bi-di gRPC RPC to create a challenge and response flow diff --git a/rfd/cspell.json b/rfd/cspell.json index 13952ad731c8b..9982219bada5e 100644 --- a/rfd/cspell.json +++ b/rfd/cspell.json @@ -322,7 +322,6 @@ "cmpopts", "cockroachdb", "codingllama", - "comitted", "committerdate", "commonfolk", "compat", @@ -395,7 +394,6 @@ "fspmarshall", "ftruncate", "fullchain", - "fullfill", "fxamacker", "gcpxyz", "germaine", @@ -465,7 +463,6 @@ "keypresses", "keyv", "kimlisa", - "klizentas", "klizhentas", "kubeconfig", "kubeconfigs", @@ -554,7 +551,6 @@ "objc", "octocats", "offboarding", - "offerts", "olekukonko", "omitempty", "oncall", @@ -568,7 +564,6 @@ "opentelemetry", "oqzt", "orapki", - "orting", "osascript", "otel", "otelaws", @@ -583,7 +578,6 @@ "partman", "passwordless", "pchar", - "perscribed", "pgbouncer", "pgconn", "pgoutput", @@ -677,7 +671,6 @@ "selfsubjectaccessreviews", "selfsubjectrulesreviews", "sendmsg", - "seperate", "serviceaccount", "serviceaccounts", "servicecfg", @@ -734,7 +727,6 @@ "subselection", "subselects", "subtests", - "suchinformation", "sudoer", "sudoersfile", "supercede", diff --git a/tool/tctl/common/resource_command.go b/tool/tctl/common/resource_command.go index dd9d5ea13af20..cdb8115e9b9a6 100644 --- a/tool/tctl/common/resource_command.go +++ b/tool/tctl/common/resource_command.go @@ -409,6 +409,9 @@ func (rc *ResourceCommand) createTrustedCluster(ctx context.Context, client *aut return trace.AlreadyExists("trusted cluster %q already exists", name) } + //nolint:staticcheck // SA1019. UpsertTrustedCluster is deprecated but will + // continue being supported for tctl clients. + // TODO(bernardjkim) consider using UpsertTrustedClusterV2 in VX.0.0 out, err := client.UpsertTrustedCluster(ctx, tc) if err != nil { // If force is used and UpsertTrustedCluster returns trace.AlreadyExists, diff --git a/tool/teleport/testenv/test_server.go b/tool/teleport/testenv/test_server.go index 5d4607223c292..3e034d9fdf0d6 100644 --- a/tool/teleport/testenv/test_server.go +++ b/tool/teleport/testenv/test_server.go @@ -417,7 +417,7 @@ func SetupTrustedCluster(ctx context.Context, t *testing.T, rootServer, leafServ rootProxyTunnelAddr, err := rootServer.ProxyTunnelAddr() require.NoError(t, err) - tc, err := types.NewTrustedCluster("root-cluster", types.TrustedClusterSpecV2{ + tc, err := types.NewTrustedCluster(rootServer.Config.Auth.ClusterName.GetClusterName(), types.TrustedClusterSpecV2{ Enabled: true, Token: StaticToken, ProxyAddress: rootProxyAddr.String(), @@ -431,7 +431,7 @@ func SetupTrustedCluster(ctx context.Context, t *testing.T, rootServer, leafServ }) require.NoError(t, err) - _, err = leafServer.GetAuthServer().UpsertTrustedCluster(ctx, tc) + _, err = leafServer.GetAuthServer().UpsertTrustedClusterV2(ctx, tc) require.NoError(t, err) require.EventuallyWithT(t, func(t *assert.CollectT) { diff --git a/tool/tsh/common/proxy.go b/tool/tsh/common/proxy.go index 489c3f483846f..2feae62df3081 100644 --- a/tool/tsh/common/proxy.go +++ b/tool/tsh/common/proxy.go @@ -36,7 +36,6 @@ import ( "github.com/gravitational/trace" "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/constants" "github.com/gravitational/teleport/api/types" libclient "github.com/gravitational/teleport/lib/client" @@ -63,39 +62,25 @@ func onProxyCommandSSH(cf *CLIConf) error { return trace.Wrap(err) } - var target string - switch { - case tc.Host != "": - targetHost, targetPort, err := net.SplitHostPort(tc.Host) - if err != nil { - targetHost = tc.Host - targetPort = strconv.Itoa(tc.HostPort) - } - targetHost = cleanTargetHost(targetHost, tc.WebProxyHost(), clt.ClusterName()) - target = net.JoinHostPort(targetHost, targetPort) - case len(tc.SearchKeywords) != 0 || tc.PredicateExpression != "": - nodes, err := client.GetAllResources[types.Server](cf.Context, clt.AuthClient, tc.ResourceFilter(types.KindNode)) - if err != nil { - return trace.Wrap(err) - } - - if len(nodes) == 0 { - return trace.NotFound("no matching SSH hosts found for search terms or query expression") - } - - if len(nodes) > 1 { - return trace.BadParameter("found multiple matching SSH hosts %v", nodes[:2]) - } + targetHost, targetPort, err := net.SplitHostPort(tc.Host) + if err != nil { + targetHost = tc.Host + targetPort = strconv.Itoa(tc.HostPort) + } + targetHost = cleanTargetHost(targetHost, tc.WebProxyHost(), clt.ClusterName()) + tc.Host = targetHost + port, err := strconv.Atoi(targetPort) + if err != nil { + return trace.Wrap(err) + } + tc.HostPort = port - // Dialing is happening by UUID but a port is still required by - // the Proxy dial request. Zero is an indicator to the Proxy that - // it may chose the appropriate port based on the target server. - target = fmt.Sprintf("%s:0", nodes[0].GetName()) - default: - return trace.BadParameter("no hostname, search terms or query expression provided") + target, err := tc.GetTargetNode(cf.Context, clt.AuthClient, nil) + if err != nil { + return trace.Wrap(err) } - conn, _, err := clt.DialHostWithResumption(cf.Context, target, clt.ClusterName(), tc.LocalAgent().ExtendedAgent) + conn, _, err := clt.DialHostWithResumption(cf.Context, target.Addr, clt.ClusterName(), tc.LocalAgent().ExtendedAgent) if err != nil { return trace.Wrap(err) } diff --git a/tool/tsh/common/tsh.go b/tool/tsh/common/tsh.go index 582cce0fcd08d..454f37fe52168 100644 --- a/tool/tsh/common/tsh.go +++ b/tool/tsh/common/tsh.go @@ -3722,19 +3722,15 @@ func onSSHLatency(cf *CLIConf) error { } defer clt.Close() - // detect the common error when users use host:port address format - _, port, err := net.SplitHostPort(tc.Host) - // client has used host:port notation - if err == nil { - return trace.BadParameter("please use ssh subcommand with '--port=%v' flag instead of semicolon", port) + target, err := tc.GetTargetNode(cf.Context, clt.AuthClient, nil) + if err != nil { + return trace.Wrap(err) } - addr := net.JoinHostPort(tc.Host, strconv.Itoa(tc.HostPort)) - nodeClient, err := tc.ConnectToNode( cf.Context, clt, - client.NodeDetails{Addr: addr, Namespace: tc.Namespace, Cluster: tc.SiteName}, + client.NodeDetails{Addr: target.Addr, Namespace: tc.Namespace, Cluster: tc.SiteName}, tc.Config.HostLogin, ) if err != nil { @@ -3920,7 +3916,9 @@ func onSSH(cf *CLIConf) error { err = client.RetryWithRelogin(cf.Context, tc, sshFunc) } if err != nil { - if strings.Contains(utils.UserMessageFromError(err), teleport.NodeIsAmbiguous) { + if errors.Is(err, teleport.ErrNodeIsAmbiguous) || + // TODO(tross) DELETE IN v20.0.0 + strings.Contains(utils.UserMessageFromError(err), teleport.NodeIsAmbiguous) { clt, err := tc.ConnectToCluster(cf.Context) if err != nil { return trace.Wrap(err) diff --git a/tool/tsh/common/tsh_helper_test.go b/tool/tsh/common/tsh_helper_test.go index 380b012805d3c..85ec86097b3bd 100644 --- a/tool/tsh/common/tsh_helper_test.go +++ b/tool/tsh/common/tsh_helper_test.go @@ -230,7 +230,7 @@ func (s *suite) setupLeafCluster(t *testing.T, options testSuiteOptions) { tunnelAddr = s.root.Config.Proxy.ReverseTunnelListenAddr.String() } - tc, err := types.NewTrustedCluster("root-cluster", types.TrustedClusterSpecV2{ + tc, err := types.NewTrustedCluster(s.root.Config.Auth.ClusterName.GetClusterName(), types.TrustedClusterSpecV2{ Enabled: true, Token: staticToken, ProxyAddress: s.root.Config.Proxy.WebAddr.String(), @@ -249,7 +249,7 @@ func (s *suite) setupLeafCluster(t *testing.T, options testSuiteOptions) { } s.leaf = runTeleport(t, cfg) - _, err = s.leaf.GetAuthServer().UpsertTrustedCluster(s.leaf.ExitContext(), tc) + _, err = s.leaf.GetAuthServer().UpsertTrustedClusterV2(s.leaf.ExitContext(), tc) require.NoError(t, err) } diff --git a/tool/tsh/common/tsh_test.go b/tool/tsh/common/tsh_test.go index e19a3b945517d..9302a62ce29ae 100644 --- a/tool/tsh/common/tsh_test.go +++ b/tool/tsh/common/tsh_test.go @@ -2543,7 +2543,7 @@ func tryCreateTrustedCluster(t *testing.T, authServer *auth.Server, trustedClust ctx := context.TODO() for i := 0; i < 10; i++ { log.Debugf("Will create trusted cluster %v, attempt %v.", trustedCluster, i) - _, err := authServer.UpsertTrustedCluster(ctx, trustedCluster) + _, err := authServer.UpsertTrustedClusterV2(ctx, trustedCluster) if err == nil { return } @@ -7028,8 +7028,7 @@ func TestSCP(t *testing.T) { return filepath.Join(dir, targetFile1) }, assertion: func(tt require.TestingT, err error, i ...any) { - require.Error(tt, err, i...) - require.ErrorContains(tt, err, "multiple matching hosts", i...) + require.ErrorIs(tt, err, teleport.ErrNodeIsAmbiguous, i...) }, }, { @@ -7088,8 +7087,7 @@ func TestSCP(t *testing.T) { return "dev.example.com:" + filepath.Join(dir, targetFile1) }, assertion: func(tt require.TestingT, err error, i ...any) { - require.Error(tt, err, i...) - require.ErrorContains(tt, err, "multiple matching hosts", i...) + require.ErrorIs(tt, err, teleport.ErrNodeIsAmbiguous, i...) }, }, { diff --git a/web/packages/design/src/Mark/Mark.story.tsx b/web/packages/design/src/Mark/Mark.story.tsx index fdc202a8f2044..0b532cd03d2ab 100644 --- a/web/packages/design/src/Mark/Mark.story.tsx +++ b/web/packages/design/src/Mark/Mark.story.tsx @@ -17,8 +17,9 @@ */ import Box from 'design/Box'; +import { IconTooltip } from 'design/Tooltip'; -import { Mark as M } from './Mark'; +import { Mark as M, MarkInverse } from './Mark'; export default { title: 'Design/Mark', @@ -41,3 +42,12 @@ export const SampleText = () => { ); }; + +export const MarkInsideTooltip = () => { + return ( + + Example of MarkInverse component. Note the{' '} + inversed background and text color. + + ); +}; diff --git a/web/packages/design/src/Mark/Mark.tsx b/web/packages/design/src/Mark/Mark.tsx index 2c76a92e0a25c..95552b8e9882b 100644 --- a/web/packages/design/src/Mark/Mark.tsx +++ b/web/packages/design/src/Mark/Mark.tsx @@ -26,3 +26,16 @@ export const Mark = styled.mark` background-color: ${p => p.theme.colors.interactive.tonal.neutral[2]}; color: inherit; `; + +/** + * Returns a MarkInverse that inverts the colors from its parent Mark. + * For example, if current theme is dark theme, parent Mark would use + * light colors, but MarkInverse will use dark colors. + * + * Intended for use in tooltips since tooltips uses inverse background + * color of the current theme. + */ +export const MarkInverse = styled(Mark)` + background-color: ${p => p.theme.colors.tooltip.inverseBackground}; + color: ${p => p.theme.colors.text.main}; +`; diff --git a/web/packages/design/src/Mark/index.ts b/web/packages/design/src/Mark/index.ts index f12d3f30412e7..8ff108e93731d 100644 --- a/web/packages/design/src/Mark/index.ts +++ b/web/packages/design/src/Mark/index.ts @@ -16,4 +16,4 @@ * along with this program. If not, see . */ -export { Mark } from './Mark'; +export { Mark, MarkInverse } from './Mark'; diff --git a/web/packages/design/src/ResourceIcon/assets/argocd.svg b/web/packages/design/src/ResourceIcon/assets/argocd.svg new file mode 100644 index 0000000000000..b419034be124e --- /dev/null +++ b/web/packages/design/src/ResourceIcon/assets/argocd.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/web/packages/design/src/ResourceIcon/icons.ts b/web/packages/design/src/ResourceIcon/icons.ts index 69656120a82b8..fccf86a27aeff 100644 --- a/web/packages/design/src/ResourceIcon/icons.ts +++ b/web/packages/design/src/ResourceIcon/icons.ts @@ -35,6 +35,7 @@ import apolloIoLight from './assets/apollo.io-light.svg'; import appleDark from './assets/apple-dark.svg'; import appleLight from './assets/apple-light.svg'; import application from './assets/application.svg'; +import argocd from './assets/argocd.svg'; import asana from './assets/asana.svg'; import assembleDark from './assets/assemble-dark.svg'; import assembleLight from './assets/assemble-light.svg'; @@ -322,6 +323,7 @@ export { appleDark, appleLight, application, + argocd, asana, assembleDark, assembleLight, diff --git a/web/packages/design/src/ResourceIcon/resourceIconSpecs.ts b/web/packages/design/src/ResourceIcon/resourceIconSpecs.ts index 17ffe26bbdaeb..67021894b7ad9 100644 --- a/web/packages/design/src/ResourceIcon/resourceIconSpecs.ts +++ b/web/packages/design/src/ResourceIcon/resourceIconSpecs.ts @@ -50,6 +50,7 @@ export const resourceIconSpecs = { 'apollo.io': { dark: i.apolloIoDark, light: i.apolloIoLight }, apple: { dark: i.appleDark, light: i.appleLight }, application: forAllThemes(i.application), + argocd: forAllThemes(i.argocd), asana: forAllThemes(i.asana), assemble: { dark: i.assembleDark, light: i.assembleLight }, atlassian: forAllThemes(i.atlassian), diff --git a/web/packages/design/src/theme/themes/bblpTheme.ts b/web/packages/design/src/theme/themes/bblpTheme.ts index 94c03f70948b8..bab7835d0c80d 100644 --- a/web/packages/design/src/theme/themes/bblpTheme.ts +++ b/web/packages/design/src/theme/themes/bblpTheme.ts @@ -204,6 +204,7 @@ const colors: ThemeColors = { tooltip: { background: 'rgba(255, 255, 255, 0.8)', + inverseBackground: 'rgba(0, 0, 0, 0.5)', }, progressBarColor: '#00BFA5', diff --git a/web/packages/design/src/theme/themes/darkTheme.ts b/web/packages/design/src/theme/themes/darkTheme.ts index 9ba4d7b2a98c4..1a7ce32ece88c 100644 --- a/web/packages/design/src/theme/themes/darkTheme.ts +++ b/web/packages/design/src/theme/themes/darkTheme.ts @@ -203,6 +203,7 @@ const colors: ThemeColors = { tooltip: { background: 'rgba(255, 255, 255, 0.8)', + inverseBackground: 'rgba(0, 0, 0, 0.5)', }, progressBarColor: '#00BFA5', diff --git a/web/packages/design/src/theme/themes/lightTheme.ts b/web/packages/design/src/theme/themes/lightTheme.ts index 8c2cc6daf7677..c19ebb8e991cc 100644 --- a/web/packages/design/src/theme/themes/lightTheme.ts +++ b/web/packages/design/src/theme/themes/lightTheme.ts @@ -202,6 +202,7 @@ const colors: ThemeColors = { tooltip: { background: 'rgba(0, 0, 0, 0.80)', + inverseBackground: 'rgba(255, 255, 255, 0.5)', }, progressBarColor: '#007D6B', diff --git a/web/packages/design/src/theme/themes/types.ts b/web/packages/design/src/theme/themes/types.ts index 64a45651a7035..d0519eb98d3dc 100644 --- a/web/packages/design/src/theme/themes/types.ts +++ b/web/packages/design/src/theme/themes/types.ts @@ -141,6 +141,7 @@ export type ThemeColors = { tooltip: { background: string; + inverseBackground: string; }; progressBarColor: string; diff --git a/web/packages/shared/components/ButtonTextWithAddIcon/ButtonTextWithAddIcon.tsx b/web/packages/shared/components/ButtonTextWithAddIcon/ButtonTextWithAddIcon.tsx index 3d65b59944f06..e33a9849b37b4 100644 --- a/web/packages/shared/components/ButtonTextWithAddIcon/ButtonTextWithAddIcon.tsx +++ b/web/packages/shared/components/ButtonTextWithAddIcon/ButtonTextWithAddIcon.tsx @@ -33,7 +33,7 @@ export const ButtonTextWithAddIcon = ({ iconSize?: IconSize; }) => { return ( - + . + */ + +import { ResourceLabelTooltip } from './ResourceLabelTooltip'; + +export default { + title: 'Teleport/Discover/Shared/ResourceLabelTooltip', +}; + +export const RDS = () => ; +export const EKS = () => ; +export const Server = () => ; +export const Database = () => ; +export const Kube = () => ; diff --git a/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/ResourceLabelTooltip.tsx b/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/ResourceLabelTooltip.tsx new file mode 100644 index 0000000000000..2e7ad2d1980aa --- /dev/null +++ b/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/ResourceLabelTooltip.tsx @@ -0,0 +1,147 @@ +/** + * 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 Link from 'design/Link'; +import { MarkInverse } from 'design/Mark'; +import { Position } from 'design/Popover/Popover'; +import { IconTooltip } from 'design/Tooltip'; +import styled from 'styled-components'; + +/** + * Returns a IconTooltip component with its tip contents + * set to the requested resource kind. + * + * @param resourceKind - the tip contents differ slightly depending + * on the resource kind + * @param toolTipPosition (opt) - the position which the tooltip should + * render (see type Position) + * @returns JSX Element + */ +export function ResourceLabelTooltip({ + resourceKind, + toolTipPosition, +}: { + resourceKind: 'server' | 'eks' | 'rds' | 'kube' | 'db'; + toolTipPosition?: Position; +}) { + let tip; + + switch (resourceKind) { + case 'server': { + tip = ( + <> + Labels allow you to do the following: +
    +
  • + Filter servers by labels when using tsh, tctl, or the web UI. +
  • +
  • + Restrict access to this server with{' '} + + Teleport RBAC + + . Only roles with node_labels that + match these labels will be allowed to access this server. +
  • +
+ + ); + break; + } + case 'kube': + case 'eks': { + tip = ( + <> + Labels allow you to do the following: +
    +
  • + Filter Kubernetes clusters by labels when using tsh, tctl, or the + web UI. +
  • +
  • + Restrict access to this Kubernetes cluster with{' '} + + Teleport RBAC + + . Only roles with kubernetes_labels{' '} + that match these labels will be allowed to access this Kubernetes + cluster. +
  • + {resourceKind === 'eks' && ( +
  • + All the AWS tags from the selected EKS will be included upon + enrollment. +
  • + )} +
+ + ); + break; + } + case 'rds': + case 'db': { + tip = ( + <> + Labels allow you to do the following: +
    +
  • + Filter databases by labels when using tsh, tctl, or the web UI. +
  • +
  • + Restrict access to this database with{' '} + + Teleport RBAC + + . Only roles with db_labels that match + these labels will be allowed to access this database. +
  • + {resourceKind === 'rds' && ( +
  • + All the AWS tags from the selected RDS will be included upon + enrollment. +
  • + )} +
+ + ); + break; + } + default: + resourceKind satisfies never; + } + + return ( + + {tip} + + ); +} + +const Ul = styled.ul` + margin: 0; + padding-left: ${p => p.theme.space[4]}px; +`; diff --git a/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/index.ts b/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/index.ts new file mode 100644 index 0000000000000..fd093b71e1080 --- /dev/null +++ b/web/packages/teleport/src/Discover/Shared/ResourceLabelTooltip/index.ts @@ -0,0 +1,19 @@ +/** + * Teleport + * Copyright (C) 2024 Gravitational, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +export { ResourceLabelTooltip } from './ResourceLabelTooltip'; diff --git a/web/packages/teleport/src/Login/Login.test.tsx b/web/packages/teleport/src/Login/Login.test.tsx index f993acf319533..ce51ae5cdf160 100644 --- a/web/packages/teleport/src/Login/Login.test.tsx +++ b/web/packages/teleport/src/Login/Login.test.tsx @@ -22,6 +22,7 @@ import { render, fireEvent, screen, waitFor } from 'design/utils/testing'; import auth from 'teleport/services/auth/auth'; import history from 'teleport/services/history'; +import session from 'teleport/services/websession'; import cfg from 'teleport/config'; import { Login } from './Login'; @@ -31,6 +32,7 @@ let user: UserEvent; beforeEach(() => { jest.restoreAllMocks(); jest.spyOn(history, 'push').mockImplementation(); + jest.spyOn(history, 'replace').mockImplementation(); jest.spyOn(history, 'getRedirectParam').mockImplementation(() => '/'); jest.spyOn(history, 'hasAccessChangedParam').mockImplementation(() => false); user = userEvent.setup(); @@ -194,3 +196,25 @@ describe('test MOTD', () => { expect(screen.getByText(/Your access has changed/i)).toBeInTheDocument(); }); }); + +test('redirect to root if session is valid and path is not "/enterprise/saml-idp/sso"', () => { + jest.spyOn(session, 'isValid').mockImplementation(() => true); + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue( + 'http://localhost/web/login?redirect_url=http://localhost/web/cluster/localhost/resources' + ); + render(); + + expect(history.replace).toHaveBeenCalledWith('/web'); +}); + +test('redirect if session is valid and path matches "/enterprise/saml-idp/sso"', () => { + const samlIdPPath = new URL('http://localhost' + cfg.routes.samlIdpSso); + jest.spyOn(session, 'isValid').mockImplementation(() => true); + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue(samlIdPPath.toString()); + render(); + expect(history.push).toHaveBeenCalledWith(samlIdPPath, true); +}); diff --git a/web/packages/teleport/src/Login/useLogin.test.tsx b/web/packages/teleport/src/Login/useLogin.test.tsx new file mode 100644 index 0000000000000..9d2b461fe8ffe --- /dev/null +++ b/web/packages/teleport/src/Login/useLogin.test.tsx @@ -0,0 +1,100 @@ +/** + * 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 history from 'teleport/services/history'; +import session from 'teleport/services/websession'; +import cfg from 'teleport/config'; + +import { renderHook } from '@testing-library/react'; + +import useLogin from './useLogin'; + +beforeEach(() => { + jest.restoreAllMocks(); + jest.spyOn(session, 'isValid').mockImplementation(() => true); + jest.spyOn(history, 'push').mockImplementation(); + jest.spyOn(history, 'replace').mockImplementation(); + jest.mock('shared/hooks', () => ({ + useAttempt: () => { + return [ + { status: 'success', statusText: 'Success Text' }, + { + clear: jest.fn(), + }, + ]; + }, + })); +}); + +afterEach(() => { + jest.resetAllMocks(); +}); + +it('redirect to root on path not matching "/enterprise/saml-idp/sso"', () => { + jest.spyOn(history, 'getRedirectParam').mockReturnValue('http://localhost'); + renderHook(() => useLogin()); + expect(history.replace).toHaveBeenCalledWith('/web'); + + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue('http://localhost/web/cluster/name/resources'); + renderHook(() => useLogin()); + expect(history.replace).toHaveBeenCalledWith('/web'); +}); + +it('redirect to SAML SSO path on matching "/enterprise/saml-idp/sso"', () => { + const samlIdpPath = new URL('http://localhost' + cfg.routes.samlIdpSso); + cfg.baseUrl = 'http://localhost'; + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue(samlIdpPath.toString()); + renderHook(() => useLogin()); + expect(history.push).toHaveBeenCalledWith(samlIdpPath, true); +}); + +it('non-base domain redirects with base domain for a matching "/enterprise/saml-idp/sso"', async () => { + const samlIdpPath = new URL('http://different-base' + cfg.routes.samlIdpSso); + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue(samlIdpPath.toString()); + renderHook(() => useLogin()); + const expectedPath = new URL('http://localhost' + cfg.routes.samlIdpSso); + expect(history.push).toHaveBeenCalledWith(expectedPath, true); +}); + +it('base domain with different path is redirected to root', async () => { + const nonSamlIdpPath = new URL('http://localhost/web/cluster/name/resources'); + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue(nonSamlIdpPath.toString()); + renderHook(() => useLogin()); + expect(history.replace).toHaveBeenCalledWith('/web'); +}); + +it('invalid session does nothing', async () => { + const samlIdpPathWithDifferentBase = new URL( + 'http://different-base' + cfg.routes.samlIdpSso + ); + jest + .spyOn(history, 'getRedirectParam') + .mockReturnValue(samlIdpPathWithDifferentBase.toString()); + jest.spyOn(session, 'isValid').mockImplementation(() => false); + renderHook(() => useLogin()); + expect(history.replace).not.toHaveBeenCalled(); + expect(history.push).not.toHaveBeenCalled(); +}); diff --git a/web/packages/teleport/src/Login/useLogin.ts b/web/packages/teleport/src/Login/useLogin.ts index 8a36d5aba3e8e..aec71d83fe94c 100644 --- a/web/packages/teleport/src/Login/useLogin.ts +++ b/web/packages/teleport/src/Login/useLogin.ts @@ -17,6 +17,7 @@ */ import { useState, useEffect } from 'react'; +import { matchPath } from 'react-router'; import { useAttempt } from 'shared/hooks'; import { AuthProvider } from 'shared/services'; import { TrustedDeviceRequirement } from 'gen-proto-ts/teleport/legacy/types/trusted_device_requirement_pb'; @@ -69,8 +70,25 @@ export default function useLogin() { useEffect(() => { if (session.isValid()) { - history.replace(cfg.routes.root); - return; + try { + const redirectUrlWithBase = new URL(getEntryRoute()); + const matched = matchPath(redirectUrlWithBase.pathname, { + path: cfg.routes.samlIdpSso, + strict: true, + exact: true, + }); + if (matched) { + history.push(redirectUrlWithBase, true); + return; + } else { + history.replace(cfg.routes.root); + return; + } + } catch (e) { + console.error(e); + history.replace(cfg.routes.root); + return; + } } setCheckingValidSession(false); }, []); @@ -149,6 +167,11 @@ function loginSuccess() { history.push(redirect, withPageRefresh); } +/** + * getEntryRoute returns a base ensured redirect URL value that is safe + * for redirect. + * @returns base ensured URL string. + */ function getEntryRoute() { let entryUrl = history.getRedirectParam(); if (entryUrl) { diff --git a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.story.tsx b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.story.tsx index 14efa8fc69588..9fc5ba22f78ce 100644 --- a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.story.tsx +++ b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.story.tsx @@ -30,7 +30,7 @@ import { YamlSupportedResourceKind } from 'teleport/services/yaml/types'; import { Access } from 'teleport/services/user'; import useResources from 'teleport/components/useResources'; -import { withDefaults } from './withDefaults'; +import { withDefaults } from './StandardEditor/withDefaults'; import { RoleEditor } from './RoleEditor'; import { RoleEditorDialog } from './RoleEditorDialog'; diff --git a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.test.tsx b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.test.tsx index 0fa38219bd398..aeec6288e2431 100644 --- a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.test.tsx +++ b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.test.tsx @@ -31,7 +31,7 @@ import { import { CaptureEvent, userEventService } from 'teleport/services/userEvent'; import { RoleEditor, RoleEditorProps } from './RoleEditor'; -import { defaultOptions, withDefaults } from './withDefaults'; +import { defaultOptions, withDefaults } from './StandardEditor/withDefaults'; // The Ace editor is very difficult to deal with in tests, especially that for // handling its state, we are using input event, which is asynchronous. Thus, diff --git a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.tsx b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.tsx index 729360ecb4254..2eeb3dc9cc9ad 100644 --- a/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.tsx +++ b/web/packages/teleport/src/Roles/RoleEditor/RoleEditor.tsx @@ -32,11 +32,11 @@ import { newRole, StandardEditorModel, roleToRoleEditorModel as roleToRoleEditorModel, -} from './standardmodel'; +} from './StandardEditor/standardmodel'; import { YamlEditorModel } from './yamlmodel'; import { EditorTab } from './EditorTabs'; import { EditorHeader } from './EditorHeader'; -import { StandardEditor } from './StandardEditor'; +import { StandardEditor } from './StandardEditor/StandardEditor'; import { YamlEditor } from './YamlEditor'; export type RoleEditorProps = { diff --git a/web/packages/teleport/src/Roles/RoleEditor/StandardEditor.tsx b/web/packages/teleport/src/Roles/RoleEditor/StandardEditor.tsx deleted file mode 100644 index 49c5c5e30feb8..0000000000000 --- a/web/packages/teleport/src/Roles/RoleEditor/StandardEditor.tsx +++ /dev/null @@ -1,1279 +0,0 @@ -/** - * 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, { useId, useState } from 'react'; -import { - Box, - ButtonIcon, - ButtonSecondary, - Flex, - H3, - H4, - Input, - LabelInput, - Mark, - Text, -} from 'design'; -import FieldInput from 'shared/components/FieldInput'; -import { useValidation } from 'shared/components/Validation'; -import { - precomputed, - ValidationResult, -} from 'shared/components/Validation/rules'; -import * as Icon from 'design/Icon'; -import { HoverTooltip, IconTooltip } from 'design/Tooltip'; -import styled, { useTheme } from 'styled-components'; -import { MenuButton, MenuItem } from 'shared/components/MenuAction'; -import { - FieldSelect, - FieldSelectCreatable, -} from 'shared/components/FieldSelect'; -import { SlideTabs } from 'design/SlideTabs'; -import { RadioGroup } from 'design/RadioGroup'; -import Select from 'shared/components/Select'; - -import { components, MultiValueProps } from 'react-select'; - -import { Role, RoleWithYaml } from 'teleport/services/resources'; -import { LabelsInput } from 'teleport/components/LabelsInput'; - -import { FieldMultiInput } from '../../../../shared/components/FieldMultiInput/FieldMultiInput'; - -import { - roleEditorModelToRole, - hasModifiedFields, - MetadataModel, - RoleEditorModel, - StandardEditorModel, - AccessSpecKind, - AccessSpec, - ServerAccessSpec, - newAccessSpec, - KubernetesAccessSpec, - newKubernetesResourceModel, - kubernetesResourceKindOptions, - kubernetesVerbOptions, - KubernetesResourceModel, - AppAccessSpec, - DatabaseAccessSpec, - WindowsDesktopAccessSpec, - RuleModel, - resourceKindOptions, - verbOptions, - newRuleModel, - OptionsModel, - requireMFATypeOptions, - createHostUserModeOptions, - createDBUserModeOptions, - sessionRecordingModeOptions, - resourceKindOptionsMap, - ResourceKindOption, -} from './standardmodel'; -import { - validateRoleEditorModel, - MetadataValidationResult, - AccessSpecValidationResult, - ServerSpecValidationResult, - KubernetesSpecValidationResult, - KubernetesResourceValidationResult, - AppSpecValidationResult, - DatabaseSpecValidationResult, - WindowsDesktopSpecValidationResult, - AccessRuleValidationResult, -} from './validation'; -import { EditorSaveCancelButton } from './Shared'; -import { RequiresResetToStandard } from './RequiresResetToStandard'; - -export type StandardEditorProps = { - originalRole: RoleWithYaml; - standardEditorModel: StandardEditorModel; - isProcessing?: boolean; - onSave?(r: Role): void; - onCancel?(): void; - onChange?(s: StandardEditorModel): void; -}; - -/** - * A structured editor that represents a role with a series of UI controls, as - * opposed to a YAML text editor. - */ -export const StandardEditor = ({ - originalRole, - standardEditorModel, - isProcessing, - onSave, - onCancel, - onChange, -}: StandardEditorProps) => { - const isEditing = !!originalRole; - const { roleModel } = standardEditorModel; - const validation = validateRoleEditorModel(roleModel); - - /** All spec kinds except those that are already in the role. */ - const allowedSpecKinds = allAccessSpecKinds.filter(k => - roleModel.accessSpecs.every(as => as.kind !== k) - ); - - enum StandardEditorTab { - Overview, - Resources, - AccessRules, - Options, - } - - const [currentTab, setCurrentTab] = useState(StandardEditorTab.Overview); - const idPrefix = useId(); - const overviewTabId = `${idPrefix}-overview`; - const resourcesTabId = `${idPrefix}-resources`; - const accessRulesTabId = `${idPrefix}-access-rules`; - const optionsTabId = `${idPrefix}-options`; - - const validator = useValidation(); - - function handleSave() { - if (!validator.validate()) { - return; - } - onSave?.(roleEditorModelToRole(standardEditorModel.roleModel)); - } - - function handleChange(modified: Partial) { - const updatedResourceModel: RoleEditorModel = { - ...roleModel, - ...modified, - }; - - onChange?.({ - ...standardEditorModel, - roleModel: updatedResourceModel, - isDirty: hasModifiedFields(updatedResourceModel, originalRole?.object), - }); - } - - function addAccessSpec(kind: AccessSpecKind) { - handleChange({ - ...standardEditorModel.roleModel, - accessSpecs: [ - ...standardEditorModel.roleModel.accessSpecs, - newAccessSpec(kind), - ], - }); - } - - function removeAccessSpec(kind: AccessSpecKind) { - handleChange({ - ...standardEditorModel.roleModel, - accessSpecs: standardEditorModel.roleModel.accessSpecs.filter( - s => s.kind !== kind - ), - }); - } - - function setAccessSpec(value: AccessSpec) { - handleChange({ - ...standardEditorModel.roleModel, - accessSpecs: standardEditorModel.roleModel.accessSpecs.map(original => - original.kind === value.kind ? value : original - ), - }); - } - - function setRules(rules: RuleModel[]) { - handleChange({ - ...standardEditorModel.roleModel, - rules, - }); - } - - function setOptions(options: OptionsModel) { - handleChange({ - ...standardEditorModel, - options, - }); - } - - return ( - <> - {roleModel.requiresReset && ( - - - - )} - - - !s.valid) - ? validationErrorTabStatus - : undefined, - }, - { - key: StandardEditorTab.AccessRules, - title: 'Access Rules', - controls: accessRulesTabId, - status: - validator.state.validating && - validation.rules.some(s => !s.valid) - ? validationErrorTabStatus - : undefined, - }, - { - key: StandardEditorTab.Options, - title: 'Options', - controls: optionsTabId, - }, - ]} - activeIndex={currentTab} - onChange={setCurrentTab} - /> - - - - handleChange({ ...roleModel, metadata })} - /> - - - - {roleModel.accessSpecs.map((spec, i) => { - const validationResult = validation.accessSpecs[i]; - return ( - setAccessSpec(value)} - onRemove={() => removeAccessSpec(spec.kind)} - /> - ); - })} - - - - Add New Specifications - - } - buttonProps={{ - size: 'medium', - fill: 'filled', - disabled: isProcessing || allowedSpecKinds.length === 0, - }} - > - {allowedSpecKinds.map(kind => ( - addAccessSpec(kind)}> - {specSections[kind].title} - - ))} - - - - - - - - - - - - - handleSave()} - onCancel={onCancel} - disabled={ - isProcessing || - standardEditorModel.roleModel.requiresReset || - !standardEditorModel.isDirty - } - isEditing={isEditing} - /> - - ); -}; - -export type SectionProps = { - value: Model; - isProcessing: boolean; - validation?: ValidationResult; - onChange?(value: Model): void; -}; - -const validationErrorTabStatus = { - kind: 'danger', - ariaLabel: 'Invalid data', -} as const; - -const MetadataSection = ({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) => ( -
- onChange({ ...value, name: e.target.value })} - /> - ) => - onChange({ ...value, description: e.target.value }) - } - /> - - Labels - - onChange?.({ ...value, labels })} - rule={precomputed(validation.fields.labels)} - /> -
-); - -/** - * A wrapper for editor section. Its responsibility is rendering a header, - * expanding, collapsing, and removing the section. - */ -const Section = ({ - title, - tooltip, - children, - removable, - isProcessing, - validation, - onRemove, -}: React.PropsWithChildren<{ - title: string; - tooltip: string; - removable?: boolean; - isProcessing: boolean; - validation?: ValidationResult; - onRemove?(): void; -}>) => { - const theme = useTheme(); - const [expanded, setExpanded] = useState(true); - const ExpandIcon = expanded ? Icon.Minus : Icon.Plus; - const expandTooltip = expanded ? 'Collapse' : 'Expand'; - const validator = useValidation(); - - const handleExpand = (e: React.MouseEvent) => { - // Don't let handle the event, we'll do it ourselves to keep - // track of the state. - e.preventDefault(); - setExpanded(expanded => !expanded); - }; - - const handleRemove = (e: React.MouseEvent) => { - // Don't let handle the event. - e.stopPropagation(); - onRemove?.(); - }; - - return ( - - - {/* TODO(bl-nero): Show validation result in the summary. */} - -

{title}

- {tooltip && {tooltip}} -
- {removable && ( - - - - - - - - )} - - - -
- - {children} - -
- ); -}; - -/** - * All access spec kinds, in order of appearance in the resource kind dropdown. - */ -const allAccessSpecKinds: AccessSpecKind[] = [ - 'kube_cluster', - 'node', - 'app', - 'db', - 'windows_desktop', -]; - -/** Maps access specification kind to UI component configuration. */ -const specSections: Record< - AccessSpecKind, - { - title: string; - tooltip: string; - component: React.ComponentType>; - } -> = { - kube_cluster: { - title: 'Kubernetes', - tooltip: 'Configures access to Kubernetes clusters', - component: KubernetesAccessSpecSection, - }, - node: { - title: 'Servers', - tooltip: 'Configures access to SSH servers', - component: ServerAccessSpecSection, - }, - app: { - title: 'Applications', - tooltip: 'Configures access to applications', - component: AppAccessSpecSection, - }, - db: { - title: 'Databases', - tooltip: 'Configures access to databases', - component: DatabaseAccessSpecSection, - }, - windows_desktop: { - title: 'Windows Desktops', - tooltip: 'Configures access to Windows desktops', - component: WindowsDesktopAccessSpecSection, - }, -}; - -/** - * A generic access spec section. Details are rendered by components from the - * `specSections` map. - */ -const AccessSpecSection = < - T extends AccessSpec, - V extends AccessSpecValidationResult, ->({ - value, - isProcessing, - validation, - onChange, - onRemove, -}: SectionProps & { - onRemove?(): void; -}) => { - const { component: Body, title, tooltip } = specSections[value.kind]; - return ( -
- -
- ); -}; - -export function ServerAccessSpecSection({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) { - return ( - <> - - Labels - - onChange?.({ ...value, labels })} - rule={precomputed(validation.fields.labels)} - /> - `Login: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.logins} - onChange={logins => onChange?.({ ...value, logins })} - rule={precomputed(validation.fields.logins)} - mt={3} - mb={0} - /> - - ); -} - -export function KubernetesAccessSpecSection({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) { - return ( - <> - `Group: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.groups} - onChange={groups => onChange?.({ ...value, groups })} - /> - - - Labels - - onChange?.({ ...value, labels })} - /> - - - {value.resources.map((resource, index) => ( - - onChange?.({ - ...value, - resources: value.resources.map((res, i) => - i === index ? newRes : res - ), - }) - } - onRemove={() => - onChange?.({ - ...value, - resources: value.resources.toSpliced(index, 1), - }) - } - /> - ))} - - - - onChange?.({ - ...value, - resources: [...value.resources, newKubernetesResourceModel()], - }) - } - > - - {value.resources.length > 0 - ? 'Add Another Resource' - : 'Add a Resource'} - - - - - ); -} - -function KubernetesResourceView({ - value, - validation, - isProcessing, - onChange, - onRemove, -}: { - value: KubernetesResourceModel; - validation: KubernetesResourceValidationResult; - isProcessing: boolean; - onChange(m: KubernetesResourceModel): void; - onRemove(): void; -}) { - const { kind, name, namespace, verbs } = value; - const theme = useTheme(); - return ( - - - -

Resource

-
- - - -
- onChange?.({ ...value, kind: k })} - /> - - Name of the resource. Special value *{' '} - means any name. - - } - disabled={isProcessing} - value={name} - rule={precomputed(validation.name)} - onChange={e => onChange?.({ ...value, name: e.target.value })} - /> - - Namespace that contains the resource. Special value{' '} - * means any namespace. - - } - disabled={isProcessing} - value={namespace} - rule={precomputed(validation.namespace)} - onChange={e => onChange?.({ ...value, namespace: e.target.value })} - /> - onChange?.({ ...value, verbs: v })} - mb={0} - /> -
- ); -} - -export function AppAccessSpecSection({ - value, - validation, - isProcessing, - onChange, -}: SectionProps) { - return ( - - - - Labels - - onChange?.({ ...value, labels })} - rule={precomputed(validation.fields.labels)} - /> - - onChange?.({ ...value, awsRoleARNs: arns })} - rule={precomputed(validation.fields.awsRoleARNs)} - /> - onChange?.({ ...value, azureIdentities: ids })} - rule={precomputed(validation.fields.azureIdentities)} - /> - onChange?.({ ...value, gcpServiceAccounts: accts })} - rule={precomputed(validation.fields.gcpServiceAccounts)} - /> - - ); -} - -export function DatabaseAccessSpecSection({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) { - return ( - <> - - - Labels - - onChange?.({ ...value, labels })} - rule={precomputed(validation.fields.labels)} - /> - - - List of database names that this role is allowed to connect to. - Special value * means any name. - - } - isDisabled={isProcessing} - formatCreateLabel={label => `Database Name: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.names} - onChange={names => onChange?.({ ...value, names })} - /> - - List of database users that this role is allowed to connect as. - Special value * means any user. - - } - isDisabled={isProcessing} - formatCreateLabel={label => `Database User: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.users} - onChange={users => onChange?.({ ...value, users })} - /> - `Database Role: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.roles} - onChange={roles => onChange?.({ ...value, roles })} - rule={precomputed(validation.fields.roles)} - mb={0} - /> - - ); -} - -export function WindowsDesktopAccessSpecSection({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) { - return ( - <> - - - Labels - - onChange?.({ ...value, labels })} - rule={precomputed(validation.fields.labels)} - /> - - `Login: ${label}`} - components={{ - DropdownIndicator: null, - }} - openMenuOnClick={false} - value={value.logins} - onChange={logins => onChange?.({ ...value, logins })} - /> - - ); -} - -export function AccessRules({ - value, - isProcessing, - validation, - onChange, -}: SectionProps) { - function addRule() { - onChange?.([...value, newRuleModel()]); - } - function setRule(rule: RuleModel) { - onChange?.(value.map(r => (r.id === rule.id ? rule : r))); - } - function removeRule(id: string) { - onChange?.(value.filter(r => r.id !== id)); - } - return ( - - {value.map((rule, i) => ( - removeRule(rule.id)} - /> - ))} - - - Add New - - - ); -} - -function AccessRule({ - value, - isProcessing, - validation, - onChange, - onRemove, -}: SectionProps & { - onRemove?(): void; -}) { - const { resources, verbs } = value; - return ( -
- onChange?.({ ...value, resources: r })} - rule={precomputed(validation.fields.resources)} - /> - onChange?.({ ...value, verbs: v })} - rule={precomputed(validation.fields.verbs)} - mb={0} - /> -
- ); -} - -const ResourceKindSelect = styled( - FieldSelectCreatable -)` - .teleport-resourcekind__value--unknown { - background: ${props => props.theme.colors.interactive.solid.alert.default}; - .react-select__multi-value__label, - .react-select__multi-value__remove { - color: ${props => props.theme.colors.text.primaryInverse}; - } - } -`; - -function ResourceKindMultiValue(props: MultiValueProps) { - if (resourceKindOptionsMap.has(props.data.value)) { - return ; - } - return ( - - - - ); -} - -function Options({ - value, - isProcessing, - onChange, -}: SectionProps) { - const theme = useTheme(); - const id = useId(); - const maxSessionTTLId = `${id}-max-session-ttl`; - const clientIdleTimeoutId = `${id}-client-idle-timeout`; - const requireMFATypeId = `${id}-require-mfa-type`; - const createHostUserModeId = `${id}-create-host-user-mode`; - const createDBUserModeId = `${id}-create-db-user-mode`; - const defaultSessionRecordingModeId = `${id}-default-session-recording-mode`; - const sshSessionRecordingModeId = `${id}-ssh-session-recording-mode`; - return ( - - Global Settings - - Max Session TTL - onChange({ ...value, maxSessionTTL: e.target.value })} - /> - - - Client Idle Timeout - - - onChange({ ...value, clientIdleTimeout: e.target.value }) - } - /> - - Disconnect When Certificate Expires - onChange({ ...value, disconnectExpiredCert: d })} - /> - - Require Session MFA - onChange?.({ ...value, defaultSessionRecordingMode: m })} - /> - - SSH - - - Create Host User Mode - - onChange?.({ ...value, sshSessionRecordingMode: m })} - /> - - Database - - Create Database User - onChange({ ...value, createDBUser: c })} - /> - - {/* TODO(bl-nero): a bug in YAML unmarshalling backend breaks the - createDBUserMode field. Fix it and add the field here. */} - - Create Database User Mode - - onChange({ ...value, maxSessionTTL: e.target.value })} + /> + + + Client Idle Timeout + + + onChange({ ...value, clientIdleTimeout: e.target.value }) + } + /> + + Disconnect When Certificate Expires + onChange({ ...value, disconnectExpiredCert: d })} + /> + + Require Session MFA + onChange?.({ ...value, defaultSessionRecordingMode: m })} + /> + + SSH + + + Create Host User Mode + + onChange?.({ ...value, sshSessionRecordingMode: m })} + /> + + Database + + Create Database User + onChange({ ...value, createDBUser: c })} + /> + + {/* TODO(bl-nero): a bug in YAML unmarshalling backend breaks the + createDBUserMode field. Fix it and add the field here. */} + + Create Database User Mode + +