fix: add optional safer Git file generator globbing (#13313) (#13314)

Signed-off-by: Denis Dupeyron <denis.dupeyron@gmail.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
This commit is contained in:
Calchan 2023-05-27 19:15:03 -06:00 committed by GitHub
parent d01d67b2fc
commit 96567956d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 425 additions and 166 deletions

View file

@ -18,10 +18,11 @@ type RepositoryDB interface {
}
type argoCDService struct {
repositoriesDB RepositoryDB
storecreds git.CredsStore
submoduleEnabled bool
repoServerClientSet apiclient.Clientset
repositoriesDB RepositoryDB
storecreds git.CredsStore
submoduleEnabled bool
repoServerClientSet apiclient.Clientset
newFileGlobbingEnabled bool
}
type Repos interface {
@ -33,11 +34,12 @@ type Repos interface {
GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error)
}
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset) (Repos, error) {
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) {
return &argoCDService{
repositoriesDB: db.(RepositoryDB),
submoduleEnabled: submoduleEnabled,
repoServerClientSet: repoClientset,
repositoriesDB: db.(RepositoryDB),
submoduleEnabled: submoduleEnabled,
repoServerClientSet: repoClientset,
newFileGlobbingEnabled: newFileGlobbingEnabled,
}, nil
}
@ -48,10 +50,11 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
}
fileRequest := &apiclient.GitFilesRequest{
Repo: repo,
SubmoduleEnabled: a.submoduleEnabled,
Revision: revision,
Path: pattern,
Repo: repo,
SubmoduleEnabled: a.submoduleEnabled,
Revision: revision,
Path: pattern,
NewGitFileGlobbingEnabled: a.newFileGlobbingEnabled,
}
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
if err != nil {

View file

@ -185,7 +185,7 @@ func TestGetFiles(t *testing.T) {
}
func TestNewArgoCDService(t *testing.T) {
service, err := NewArgoCDService(&db_mocks.ArgoDB{}, false, &repo_mocks.Clientset{})
service, err := NewArgoCDService(&db_mocks.ArgoDB{}, false, &repo_mocks.Clientset{}, false)
assert.NoError(t, err, err)
assert.NotNil(t, service)
}

View file

@ -58,6 +58,7 @@ func NewCommand() *cobra.Command {
debugLog bool
dryRun bool
enableProgressiveSyncs bool
enableNewGitFileGlobbing bool
repoServerPlaintext bool
repoServerStrictTLS bool
repoServerTimeoutSeconds int
@ -141,7 +142,7 @@ func NewCommand() *cobra.Command {
}
repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, repoServerTimeoutSeconds, tlsConfig)
argoCDService, err := services.NewArgoCDService(argoCDDB, getSubmoduleEnabled(), repoClientset)
argoCDService, err := services.NewArgoCDService(argoCDDB, getSubmoduleEnabled(), repoClientset, enableNewGitFileGlobbing)
errors.CheckError(err)
terminalGenerators := map[string]generators.Generator{
@ -224,6 +225,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error")
command.Flags().BoolVar(&dryRun, "dry-run", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN", false), "Enable dry run mode")
command.Flags().BoolVar(&enableProgressiveSyncs, "enable-progressive-syncs", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS", false), "Enable use of the experimental progressive syncs feature.")
command.Flags().BoolVar(&enableNewGitFileGlobbing, "enable-new-git-file-globbing", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING", false), "Enable new globbing in Git files generator.")
command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server")
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server")
command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.")

View file

@ -0,0 +1,85 @@
# Git File Generator Globbing
## Problem Statement
The original and default implementation of the Git file generator does very greedy globbing. This can trigger errors or catch users off-guard. For example, consider the following repository layout:
```
└── cluster-charts/
├── cluster1
│ ├── mychart/
│ │  ├── charts/
│ │   │   └── mysubchart/
│ │ │ ├── values.yaml
│ │   │   └── etc…
│ │   ├── values.yaml
│ │ └── etc…
│ └── myotherchart/
│ ├── values.yaml
│ └── etc…
└── cluster2
└── etc…
```
In `cluster1` we have two charts, one of them with a subchart.
Assuming we need the ApplicationSet to template values in the `values.yaml`, then we need to use a Git file generator instead of a directory generator. The value of the `path` key of the Git file generator should be set to:
```
path: cluster-charts/*/*/values.yaml
```
However, the default implementation will interpret the above pattern as:
```
path: cluster-charts/**/values.yaml
```
Meaning, for `mychart` in `cluster1`, that it will pick up both the chart's `values.yaml` but also the one from its subchart. This will most likely fail, and even if it didn't it would be wrong.
There are multiple other ways this undesirable globbing can fail. For example:
```
path: some-path/*.yaml
```
This will return all YAML files in any directory at any level under `some-path`, instead of only those directly under it.
## Enabling the New Globbing
Since some users may rely on the old behavior it was decided to make the fix optional and not enabled by default.
It can be enabled in any of these ways:
1. Pass `--enable-new-git-file-globbing` to the ApplicationSet controller args.
1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING=true` in the ApplicationSet controller environment variables.
1. Set `applicationsetcontroller.enable.new.git.file.globbing: true` in the Argo CD ConfigMap.
Note that the default may change in the future.
## Usage
The new Git file generator globbing uses the `doublestar` package. You can find it [here](https://github.com/bmatcuk/doublestar).
Below is a short excerpt from its documentation.
doublestar patterns match files and directories recursively. For example, if
you had the following directory structure:
```bash
grandparent
`-- parent
|-- child1
`-- child2
```
You could find the children with patterns such as: `**/child*`,
`grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will
return all files and directories recursively).
Bash's globstar is doublestar's inspiration and, as such, works similarly.
Note that the doublestar must appear as a path component by itself. A pattern
such as `/path**` is invalid and will be treated the same as `/path*`, but
`/path*/**` should achieve the desired result. Additionally, `/path/**` will
match all directories and files under the path directory, but `/path/**/` will
only match directories.

View file

@ -288,6 +288,8 @@ The filename can always be accessed using `{{path.filename}}`.
**Note**: If the `pathParamPrefix` option is specified, all `path`-related parameter names above will be prefixed with the specified value and a dot separator. E.g., if `pathParamPrefix` is `myRepo`, then the generated parameter name would be `myRepo.path` instead of `path`. Using this option is necessary in a Matrix generator where both child generators are Git generators (to avoid conflicts when merging the child generators items).
**Note**: The default behavior of the Git file generator is very greedy. Please see [Git File Generator Globbing](./Generators-Git-File-Globbing.md) for more information.
## Webhook Configuration
When using a Git generator, ApplicationSet polls Git repositories every three minutes to detect changes. To eliminate

1
go.mod
View file

@ -14,6 +14,7 @@ require (
github.com/argoproj/notifications-engine v0.4.1-0.20230228182525-f754726f03da
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d
github.com/aws/aws-sdk-go v1.44.164
github.com/bmatcuk/doublestar/v4 v4.6.0
github.com/bombsimon/logrusr/v2 v2.0.1
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0
github.com/casbin/casbin/v2 v2.60.0

2
go.sum
View file

@ -168,6 +168,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM=
github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio=

View file

@ -91,6 +91,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
@ -162,4 +168,4 @@ spec:
- key: tls.key
path: tls.key
- key: ca.crt
path: ca.crt
path: ca.crt

View file

@ -16723,6 +16723,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:

View file

@ -17944,6 +17944,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:

View file

@ -1587,6 +1587,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:

View file

@ -17061,6 +17061,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:

View file

@ -704,6 +704,12 @@ spec:
key: applicationsetcontroller.enable.progressive.syncs
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:

View file

@ -107,6 +107,7 @@ nav:
- Controlling Resource Modification: operator-manual/applicationset/Controlling-Resource-Modification.md
- Application Pruning & Resource Deletion: operator-manual/applicationset/Application-Deletion.md
- Progressive Syncs: operator-manual/applicationset/Progressive-Syncs.md
- Git File Generator Globbing: operator-manual/applicationset/Generators-Git-File-Globbing.md
- Server Configuration Parameters:
- operator-manual/server-commands/argocd-server.md
- operator-manual/server-commands/argocd-application-controller.md

View file

@ -1904,13 +1904,14 @@ func (m *HelmChartsResponse) GetItems() []*HelmChart {
}
type GitFilesRequest struct {
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"`
NewGitFileGlobbingEnabled bool `protobuf:"varint,5,opt,name=NewGitFileGlobbingEnabled,proto3" json:"NewGitFileGlobbingEnabled,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GitFilesRequest) Reset() { *m = GitFilesRequest{} }
@ -1974,6 +1975,13 @@ func (m *GitFilesRequest) GetPath() string {
return ""
}
func (m *GitFilesRequest) GetNewGitFileGlobbingEnabled() bool {
if m != nil {
return m.NewGitFileGlobbingEnabled
}
return false
}
type GitFilesResponse struct {
// Map consisting of path of the path to its contents in bytes
Map map[string][]byte `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
@ -2180,138 +2188,140 @@ func init() {
}
var fileDescriptor_dd8723cfcc820480 = []byte{
// 2092 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0x5b, 0x6f, 0x1c, 0x49,
0x15, 0x9e, 0x9e, 0xf1, 0x65, 0xe6, 0xd8, 0xb1, 0xc7, 0x15, 0x5f, 0x3a, 0xb3, 0x59, 0xcb, 0xdb,
0x90, 0xc8, 0x24, 0xbb, 0x33, 0xb2, 0xa3, 0xdd, 0xa0, 0x2c, 0x2c, 0xf2, 0x7a, 0x13, 0x3b, 0x9b,
0x38, 0x31, 0x9d, 0x00, 0x5a, 0x08, 0xa0, 0x72, 0x4f, 0xcd, 0x4c, 0xed, 0xf4, 0x74, 0x57, 0xba,
0xab, 0x8d, 0x1c, 0x89, 0x07, 0x04, 0xe2, 0x27, 0xf0, 0xc0, 0xff, 0x40, 0x3c, 0x21, 0x9e, 0xb8,
0x48, 0xbc, 0xac, 0xf8, 0x03, 0xa0, 0x3c, 0xf2, 0x2b, 0x50, 0x5d, 0xfa, 0x3a, 0x6d, 0x27, 0xcb,
0x38, 0x5e, 0xb1, 0x2f, 0x49, 0xd7, 0xa9, 0x53, 0xe7, 0x9c, 0x3a, 0x75, 0x2e, 0x5f, 0xd5, 0x18,
0xae, 0x07, 0x84, 0xf9, 0x21, 0x09, 0x8e, 0x49, 0xd0, 0x91, 0x9f, 0x94, 0xfb, 0xc1, 0x49, 0xe6,
0xb3, 0xcd, 0x02, 0x9f, 0xfb, 0x08, 0x52, 0x4a, 0xeb, 0x61, 0x9f, 0xf2, 0x41, 0x74, 0xd4, 0x76,
0xfc, 0x51, 0x07, 0x07, 0x7d, 0x9f, 0x05, 0xfe, 0xe7, 0xf2, 0xe3, 0x3d, 0xa7, 0xdb, 0x39, 0xde,
0xee, 0xb0, 0x61, 0xbf, 0x83, 0x19, 0x0d, 0x3b, 0x98, 0x31, 0x97, 0x3a, 0x98, 0x53, 0xdf, 0xeb,
0x1c, 0x6f, 0x61, 0x97, 0x0d, 0xf0, 0x56, 0xa7, 0x4f, 0x3c, 0x12, 0x60, 0x4e, 0xba, 0x4a, 0x72,
0xeb, 0xad, 0xbe, 0xef, 0xf7, 0x5d, 0xd2, 0x91, 0xa3, 0xa3, 0xa8, 0xd7, 0x21, 0x23, 0xc6, 0xb5,
0x5a, 0xeb, 0x3f, 0xf3, 0xb0, 0x78, 0x80, 0x3d, 0xda, 0x23, 0x21, 0xb7, 0xc9, 0xf3, 0x88, 0x84,
0x1c, 0x3d, 0x83, 0x29, 0x61, 0x8c, 0x69, 0x6c, 0x18, 0x9b, 0x73, 0xdb, 0xfb, 0xed, 0xd4, 0x9a,
0x76, 0x6c, 0x8d, 0xfc, 0xf8, 0xb9, 0xd3, 0x6d, 0x1f, 0x6f, 0xb7, 0xd9, 0xb0, 0xdf, 0x16, 0xd6,
0xb4, 0x33, 0xd6, 0xb4, 0x63, 0x6b, 0xda, 0x76, 0xb2, 0x2d, 0x5b, 0x4a, 0x45, 0x2d, 0xa8, 0x07,
0xe4, 0x98, 0x86, 0xd4, 0xf7, 0xcc, 0xea, 0x86, 0xb1, 0xd9, 0xb0, 0x93, 0x31, 0x32, 0x61, 0xd6,
0xf3, 0x77, 0xb1, 0x33, 0x20, 0x66, 0x6d, 0xc3, 0xd8, 0xac, 0xdb, 0xf1, 0x10, 0x6d, 0xc0, 0x1c,
0x66, 0xec, 0x21, 0x3e, 0x22, 0xee, 0x03, 0x72, 0x62, 0x4e, 0xc9, 0x85, 0x59, 0x92, 0x58, 0x8b,
0x19, 0x7b, 0x84, 0x47, 0xc4, 0x9c, 0x96, 0xb3, 0xf1, 0x10, 0x5d, 0x85, 0x86, 0x87, 0x47, 0x24,
0x64, 0xd8, 0x21, 0x66, 0x5d, 0xce, 0xa5, 0x04, 0xf4, 0x4b, 0x58, 0xca, 0x18, 0xfe, 0xc4, 0x8f,
0x02, 0x87, 0x98, 0x20, 0xb7, 0xfe, 0x78, 0xb2, 0xad, 0xef, 0x14, 0xc5, 0xda, 0xe3, 0x9a, 0xd0,
0xcf, 0x60, 0x5a, 0x9e, 0xbc, 0x39, 0xb7, 0x51, 0x3b, 0x57, 0x6f, 0x2b, 0xb1, 0xc8, 0x83, 0x59,
0xe6, 0x46, 0x7d, 0xea, 0x85, 0xe6, 0xbc, 0xd4, 0xf0, 0x74, 0x32, 0x0d, 0xbb, 0xbe, 0xd7, 0xa3,
0xfd, 0x03, 0xec, 0xe1, 0x3e, 0x19, 0x11, 0x8f, 0x1f, 0x4a, 0xe1, 0x76, 0xac, 0x04, 0xbd, 0x80,
0xe6, 0x30, 0x0a, 0xb9, 0x3f, 0xa2, 0x2f, 0xc8, 0x63, 0x26, 0xd6, 0x86, 0xe6, 0x25, 0xe9, 0xcd,
0x47, 0x93, 0x29, 0x7e, 0x50, 0x90, 0x6a, 0x8f, 0xe9, 0x11, 0x41, 0x32, 0x8c, 0x8e, 0xc8, 0x0f,
0x49, 0x20, 0xa3, 0x6b, 0x41, 0x05, 0x49, 0x86, 0xa4, 0xc2, 0x88, 0xea, 0x51, 0x68, 0x2e, 0x6e,
0xd4, 0x54, 0x18, 0x25, 0x24, 0xb4, 0x09, 0x8b, 0xc7, 0x24, 0xa0, 0xbd, 0x93, 0x27, 0xb4, 0xef,
0x61, 0x1e, 0x05, 0xc4, 0x6c, 0xca, 0x50, 0x2c, 0x92, 0xd1, 0x08, 0x2e, 0x0d, 0x88, 0x3b, 0x12,
0x2e, 0xdf, 0x0d, 0x48, 0x37, 0x34, 0x97, 0xa4, 0x7f, 0xf7, 0x26, 0x3f, 0x41, 0x29, 0xce, 0xce,
0x4b, 0x17, 0x86, 0x79, 0xbe, 0xad, 0x33, 0x45, 0xe5, 0x08, 0x52, 0x86, 0x15, 0xc8, 0xe8, 0x3a,
0x2c, 0xf0, 0x00, 0x3b, 0x43, 0xea, 0xf5, 0x0f, 0x08, 0x1f, 0xf8, 0x5d, 0xf3, 0xb2, 0xf4, 0x44,
0x81, 0x8a, 0x1c, 0x40, 0xc4, 0xc3, 0x47, 0x2e, 0xe9, 0xaa, 0x58, 0x7c, 0x7a, 0xc2, 0x48, 0x68,
0x2e, 0xcb, 0x5d, 0xdc, 0x6a, 0x67, 0x2a, 0x54, 0xa1, 0x40, 0xb4, 0xef, 0x8e, 0xad, 0xba, 0xeb,
0xf1, 0xe0, 0xc4, 0x2e, 0x11, 0x87, 0x86, 0x30, 0x27, 0xf6, 0x11, 0x87, 0xc2, 0x8a, 0x0c, 0x85,
0xfb, 0x93, 0xf9, 0x68, 0x3f, 0x15, 0x68, 0x67, 0xa5, 0xa3, 0x36, 0xa0, 0x01, 0x0e, 0x0f, 0x22,
0x97, 0x53, 0xe6, 0x12, 0x65, 0x46, 0x68, 0xae, 0x4a, 0x37, 0x95, 0xcc, 0xa0, 0x07, 0x00, 0x01,
0xe9, 0xc5, 0x7c, 0x6b, 0x72, 0xe7, 0x37, 0xcf, 0xda, 0xb9, 0x9d, 0x70, 0xab, 0x1d, 0x67, 0x96,
0x0b, 0xe5, 0x62, 0x1b, 0xc4, 0xe1, 0x3a, 0xdb, 0x65, 0x5a, 0x9b, 0x32, 0xc4, 0x4a, 0x66, 0x44,
0x2c, 0x6a, 0xaa, 0x2c, 0x5a, 0x57, 0x54, 0xb4, 0x66, 0x48, 0xad, 0xbb, 0xb0, 0x76, 0x8a, 0xab,
0x51, 0x13, 0x6a, 0x43, 0x72, 0x22, 0x4b, 0x74, 0xc3, 0x16, 0x9f, 0x68, 0x19, 0xa6, 0x8f, 0xb1,
0x1b, 0x11, 0x59, 0x54, 0xeb, 0xb6, 0x1a, 0xdc, 0xa9, 0x7e, 0xdb, 0x68, 0xfd, 0xd6, 0x80, 0xc5,
0x82, 0xe1, 0x25, 0xeb, 0x7f, 0x9a, 0x5d, 0x7f, 0x0e, 0x61, 0xdc, 0x7b, 0x8a, 0x83, 0x3e, 0xe1,
0x19, 0x43, 0xac, 0x7f, 0x1a, 0x60, 0x16, 0x3c, 0xfa, 0x23, 0xca, 0x07, 0xf7, 0xa8, 0x4b, 0x42,
0x74, 0x1b, 0x66, 0x03, 0x45, 0xd3, 0x8d, 0xe7, 0xad, 0x33, 0x0e, 0x62, 0xbf, 0x62, 0xc7, 0xdc,
0xe8, 0x23, 0xa8, 0x8f, 0x08, 0xc7, 0x5d, 0xcc, 0xb1, 0xb6, 0x7d, 0xa3, 0x6c, 0xa5, 0xd0, 0x72,
0xa0, 0xf9, 0xf6, 0x2b, 0x76, 0xb2, 0x06, 0xbd, 0x0f, 0xd3, 0xce, 0x20, 0xf2, 0x86, 0xb2, 0xe5,
0xcc, 0x6d, 0xbf, 0x7d, 0xda, 0xe2, 0x5d, 0xc1, 0xb4, 0x5f, 0xb1, 0x15, 0xf7, 0xc7, 0x33, 0x30,
0xc5, 0x70, 0xc0, 0xad, 0x7b, 0xb0, 0x5c, 0xa6, 0x42, 0xf4, 0x39, 0x67, 0x40, 0x9c, 0x61, 0x18,
0x8d, 0xb4, 0x9b, 0x93, 0x31, 0x42, 0x30, 0x15, 0xd2, 0x17, 0xca, 0xd5, 0x35, 0x5b, 0x7e, 0x5b,
0xdf, 0x82, 0xa5, 0x31, 0x6d, 0xe2, 0x50, 0x95, 0x6d, 0x42, 0xc2, 0xbc, 0x56, 0x6d, 0x45, 0xb0,
0xf2, 0x54, 0xfa, 0x22, 0x29, 0xf6, 0x17, 0xd1, 0xb9, 0xad, 0x7d, 0x58, 0x2d, 0xaa, 0x0d, 0x99,
0xef, 0x85, 0x44, 0x84, 0xbe, 0xac, 0x8e, 0x94, 0x74, 0xd3, 0x59, 0x69, 0x45, 0xdd, 0x2e, 0x99,
0xb1, 0x7e, 0x55, 0x85, 0x55, 0x9b, 0x84, 0xbe, 0x7b, 0x4c, 0xe2, 0xd2, 0x75, 0x31, 0xe0, 0xe3,
0x27, 0x50, 0xc3, 0x8c, 0xe9, 0x30, 0xb9, 0x7f, 0x6e, 0xed, 0xdd, 0x16, 0x52, 0xd1, 0xbb, 0xb0,
0x84, 0x47, 0x47, 0xb4, 0x1f, 0xf9, 0x51, 0x18, 0x6f, 0x4b, 0x06, 0x55, 0xc3, 0x1e, 0x9f, 0xb0,
0x1c, 0x58, 0x1b, 0x73, 0x81, 0x76, 0x67, 0x16, 0x22, 0x19, 0x05, 0x88, 0x54, 0xaa, 0xa4, 0x7a,
0x9a, 0x92, 0xbf, 0x1a, 0xd0, 0x4c, 0x53, 0x47, 0x8b, 0xbf, 0x0a, 0x8d, 0x91, 0xa6, 0x85, 0xa6,
0x21, 0xeb, 0x53, 0x4a, 0xc8, 0xa3, 0xa5, 0x6a, 0x11, 0x2d, 0xad, 0xc2, 0x8c, 0x02, 0xb3, 0x7a,
0x63, 0x7a, 0x94, 0x33, 0x79, 0xaa, 0x60, 0xf2, 0x3a, 0x40, 0x98, 0xd4, 0x2f, 0x73, 0x46, 0xce,
0x66, 0x28, 0xc8, 0x82, 0x79, 0xd5, 0x5b, 0x6d, 0x12, 0x46, 0x2e, 0x37, 0x67, 0x25, 0x47, 0x8e,
0x66, 0xf9, 0xb0, 0xf8, 0x90, 0x8a, 0x3d, 0xf4, 0xc2, 0x8b, 0x09, 0xf6, 0x0f, 0x60, 0x4a, 0x28,
0x13, 0x1b, 0x3b, 0x0a, 0xb0, 0xe7, 0x0c, 0x48, 0xec, 0xab, 0x64, 0x2c, 0xd2, 0x98, 0xe3, 0x7e,
0x68, 0x56, 0x25, 0x5d, 0x7e, 0x5b, 0x7f, 0xac, 0x2a, 0x4b, 0x77, 0x18, 0x0b, 0xbf, 0x7a, 0x40,
0x5d, 0xde, 0xe2, 0x6b, 0xe3, 0x2d, 0xbe, 0x60, 0xf2, 0x97, 0x69, 0xf1, 0xe7, 0xd4, 0xa6, 0xac,
0x08, 0x66, 0x77, 0x18, 0x13, 0x86, 0xa0, 0x2d, 0x98, 0xc2, 0x8c, 0x29, 0x87, 0x17, 0x2a, 0xb2,
0x66, 0x11, 0xff, 0x6b, 0x93, 0x24, 0x6b, 0xeb, 0x36, 0x34, 0x12, 0xd2, 0xab, 0xd4, 0x36, 0xb2,
0x6a, 0x37, 0x00, 0x14, 0x86, 0xbd, 0xef, 0xf5, 0x7c, 0x71, 0xa4, 0x22, 0xd8, 0xf5, 0x52, 0xf9,
0x6d, 0xdd, 0x89, 0x39, 0xa4, 0x6d, 0xef, 0xc2, 0x34, 0xe5, 0x64, 0x14, 0x1b, 0xb7, 0x9a, 0x35,
0x2e, 0x15, 0x64, 0x2b, 0x26, 0xeb, 0x6f, 0x75, 0xb8, 0x22, 0x4e, 0xec, 0x89, 0x4c, 0x93, 0x1d,
0xc6, 0x3e, 0x21, 0x1c, 0x53, 0x37, 0xfc, 0x7e, 0x44, 0x82, 0x93, 0x37, 0x1c, 0x18, 0x7d, 0x98,
0x51, 0x59, 0xa6, 0xeb, 0xdd, 0xb9, 0x5f, 0x67, 0xb4, 0xf8, 0xf4, 0x0e, 0x53, 0x7b, 0x33, 0x77,
0x98, 0xb2, 0x3b, 0xc5, 0xd4, 0x05, 0xdd, 0x29, 0x4e, 0xbf, 0x56, 0x66, 0x2e, 0xab, 0x33, 0xf9,
0xcb, 0x6a, 0x09, 0x54, 0x9f, 0x7d, 0x5d, 0xa8, 0x5e, 0x2f, 0x85, 0xea, 0xa3, 0xd2, 0x3c, 0x6e,
0x48, 0x77, 0x7f, 0x37, 0x1b, 0x81, 0xa7, 0xc6, 0xda, 0x24, 0xa0, 0x1d, 0xde, 0x28, 0x68, 0xff,
0x41, 0x0e, 0x84, 0xab, 0x6b, 0xf0, 0xfb, 0xaf, 0xb7, 0xa7, 0x33, 0xe0, 0xf8, 0xd7, 0x0e, 0x3c,
0xff, 0x46, 0x62, 0x26, 0xe6, 0xa7, 0x3e, 0x48, 0x1a, 0xba, 0xe8, 0x43, 0xa2, 0xb5, 0xea, 0xa2,
0x25, 0xbe, 0xd1, 0x4d, 0x98, 0x12, 0x4e, 0xd6, 0xa0, 0x76, 0x2d, 0xeb, 0x4f, 0x71, 0x12, 0x3b,
0x8c, 0x3d, 0x61, 0xc4, 0xb1, 0x25, 0x13, 0xba, 0x03, 0x8d, 0x24, 0xf0, 0x75, 0x66, 0x5d, 0xcd,
0xae, 0x48, 0xf2, 0x24, 0x5e, 0x96, 0xb2, 0x8b, 0xb5, 0x5d, 0x1a, 0x10, 0x47, 0x42, 0xbe, 0xe9,
0xf1, 0xb5, 0x9f, 0xc4, 0x93, 0xc9, 0xda, 0x84, 0x1d, 0x6d, 0xc1, 0x8c, 0x7a, 0x37, 0x90, 0x19,
0x34, 0xb7, 0x7d, 0x65, 0xbc, 0x98, 0xc6, 0xab, 0x34, 0xa3, 0xf5, 0x17, 0x03, 0xde, 0x49, 0x03,
0x22, 0xce, 0xa6, 0x18, 0x75, 0x7f, 0xf5, 0x1d, 0xf7, 0x3a, 0x2c, 0x48, 0x98, 0x9f, 0x3e, 0x1f,
0xa8, 0x97, 0xac, 0x02, 0xd5, 0xfa, 0x83, 0x01, 0xd7, 0xc6, 0xf7, 0xb1, 0x3b, 0xc0, 0x01, 0x4f,
0x8e, 0xf7, 0x22, 0xf6, 0x12, 0x37, 0xbc, 0x6a, 0xda, 0xf0, 0x72, 0xfb, 0xab, 0xe5, 0xf7, 0x67,
0xfd, 0xb9, 0x0a, 0x73, 0x99, 0x00, 0x2a, 0x6b, 0x98, 0x02, 0xf0, 0xc9, 0xb8, 0x95, 0x17, 0x3b,
0xd9, 0x14, 0x1a, 0x76, 0x86, 0x82, 0x86, 0x00, 0x0c, 0x07, 0x78, 0x44, 0x38, 0x09, 0x44, 0x25,
0x17, 0x19, 0xff, 0x60, 0xf2, 0xea, 0x72, 0x18, 0xcb, 0xb4, 0x33, 0xe2, 0x05, 0x62, 0x95, 0xaa,
0x43, 0x5d, 0xbf, 0xf5, 0x08, 0xfd, 0x02, 0x16, 0x7a, 0xd4, 0x25, 0x87, 0xa9, 0x21, 0x33, 0xd2,
0x90, 0xc7, 0x93, 0x1b, 0x72, 0x2f, 0x2b, 0xd7, 0x2e, 0xa8, 0xb1, 0x6e, 0x40, 0xb3, 0x98, 0x4f,
0xc2, 0x48, 0x3a, 0xc2, 0xfd, 0xc4, 0x5b, 0x7a, 0x64, 0x21, 0x68, 0x16, 0xf3, 0xc7, 0xfa, 0x57,
0x15, 0x56, 0x12, 0x71, 0x3b, 0x9e, 0xe7, 0x47, 0x9e, 0x23, 0x9f, 0xe2, 0x4a, 0xcf, 0x62, 0x19,
0xa6, 0x39, 0xe5, 0x6e, 0x02, 0x7c, 0xe4, 0x40, 0xf4, 0x2e, 0xee, 0xfb, 0x2e, 0xa7, 0x4c, 0x1f,
0x70, 0x3c, 0x54, 0x67, 0xff, 0x3c, 0xa2, 0x01, 0xe9, 0xca, 0x4a, 0x50, 0xb7, 0x93, 0xb1, 0x98,
0x13, 0xa8, 0x46, 0xc2, 0x78, 0xe5, 0xcc, 0x64, 0x2c, 0xe3, 0xde, 0x77, 0x5d, 0xe2, 0x08, 0x77,
0x64, 0x80, 0x7e, 0x81, 0x2a, 0x2f, 0x10, 0x3c, 0xa0, 0x5e, 0x5f, 0xc3, 0x7c, 0x3d, 0x12, 0x76,
0xe2, 0x20, 0xc0, 0x27, 0x66, 0x5d, 0x3a, 0x40, 0x0d, 0xd0, 0x77, 0xa0, 0x36, 0xc2, 0x4c, 0x37,
0xba, 0x1b, 0xb9, 0xea, 0x50, 0xe6, 0x81, 0xf6, 0x01, 0x66, 0xaa, 0x13, 0x88, 0x65, 0xad, 0x0f,
0xa0, 0x1e, 0x13, 0xbe, 0x14, 0x24, 0xfc, 0x1c, 0x2e, 0xe5, 0x8a, 0x0f, 0xfa, 0x0c, 0x56, 0xd3,
0x88, 0xca, 0x2a, 0xd4, 0x20, 0xf0, 0x9d, 0x57, 0x5a, 0x66, 0x9f, 0x22, 0xc0, 0x7a, 0x0e, 0x4b,
0x22, 0x64, 0x64, 0xe2, 0x5f, 0xd0, 0xd5, 0xe6, 0x43, 0x68, 0x24, 0x2a, 0x4b, 0x63, 0xa6, 0x05,
0xf5, 0xe3, 0xf8, 0x89, 0x54, 0xdd, 0x6d, 0x92, 0xb1, 0xb5, 0x03, 0x28, 0x6b, 0xaf, 0xee, 0x40,
0x37, 0xf3, 0xa0, 0x78, 0xa5, 0xd8, 0x6e, 0x24, 0x7b, 0x8c, 0x89, 0xff, 0x61, 0xc0, 0xe2, 0x1e,
0x95, 0xaf, 0x1c, 0x17, 0x54, 0xe4, 0x6e, 0x40, 0x33, 0x8c, 0x8e, 0x46, 0x7e, 0x37, 0x72, 0x89,
0x06, 0x05, 0xba, 0xd3, 0x8f, 0xd1, 0xcf, 0x2a, 0x7e, 0xc2, 0x59, 0x0c, 0xf3, 0x81, 0xbe, 0xe1,
0xca, 0x6f, 0xeb, 0xd7, 0x06, 0x34, 0xd3, 0xdd, 0x68, 0x7f, 0xdc, 0x56, 0x71, 0xab, 0xbc, 0x71,
0x2d, 0xeb, 0x8d, 0x22, 0xeb, 0xff, 0x1e, 0xb2, 0xf3, 0xd9, 0x90, 0xfd, 0x93, 0x01, 0x2b, 0x7b,
0x94, 0xc7, 0xc5, 0x82, 0xfe, 0x9f, 0x79, 0xd6, 0x6a, 0xc3, 0x6a, 0xd1, 0x7c, 0xed, 0xca, 0x65,
0x98, 0x16, 0x7e, 0x8e, 0x6f, 0xdf, 0x6a, 0xb0, 0xfd, 0x45, 0x03, 0x96, 0xd2, 0xf6, 0x29, 0xfe,
0xa5, 0x0e, 0x41, 0x8f, 0xa1, 0xb9, 0xa7, 0x7f, 0xfd, 0x8a, 0x5f, 0x3d, 0xd0, 0x59, 0xcf, 0x88,
0xad, 0xab, 0xe5, 0x93, 0x4a, 0xb5, 0x55, 0x41, 0x0e, 0x5c, 0x29, 0x0a, 0x4c, 0x5f, 0x2c, 0xbf,
0x79, 0x86, 0xe4, 0x84, 0xeb, 0x55, 0x2a, 0x36, 0x0d, 0xf4, 0x19, 0x2c, 0xe4, 0xdf, 0xd5, 0x50,
0xae, 0x9e, 0x94, 0x3e, 0xf5, 0xb5, 0xac, 0xb3, 0x58, 0x12, 0xfb, 0x9f, 0x09, 0xf0, 0x9a, 0x7b,
0x64, 0x42, 0x56, 0x1e, 0x5a, 0x97, 0x3d, 0xc2, 0xb5, 0xbe, 0x71, 0x26, 0x4f, 0x22, 0xfd, 0x43,
0xa8, 0xc7, 0x8f, 0x32, 0x79, 0x37, 0x17, 0x9e, 0x6a, 0x5a, 0xcd, 0xbc, 0xbc, 0x5e, 0x68, 0x55,
0xd0, 0x47, 0x6a, 0xb1, 0xb8, 0xb4, 0x8f, 0x2f, 0xce, 0x3c, 0x45, 0xb4, 0x2e, 0x97, 0x5c, 0xff,
0xad, 0x0a, 0xfa, 0x1e, 0xcc, 0x89, 0xaf, 0x43, 0xfd, 0xbb, 0xd3, 0x6a, 0x5b, 0xfd, 0xcc, 0xd9,
0x8e, 0x7f, 0xe6, 0x6c, 0xdf, 0x1d, 0x31, 0x7e, 0xd2, 0x2a, 0xb9, 0x9f, 0x6b, 0x01, 0xcf, 0xe0,
0xd2, 0x1e, 0xe1, 0x29, 0x9c, 0x46, 0xd7, 0x5e, 0xeb, 0xd2, 0xd1, 0xb2, 0x8a, 0x6c, 0xe3, 0x88,
0xdc, 0xaa, 0xa0, 0xdf, 0x19, 0x70, 0x79, 0x8f, 0xf0, 0x22, 0x40, 0x45, 0xef, 0x95, 0x2b, 0x39,
0x05, 0xc8, 0xb6, 0x1e, 0x4d, 0x9a, 0xaf, 0x79, 0xb1, 0x56, 0x05, 0xfd, 0xde, 0x80, 0xb5, 0x8c,
0x61, 0x59, 0xc4, 0x89, 0xb6, 0xce, 0x36, 0xae, 0x04, 0x9d, 0xb6, 0x3e, 0x9d, 0xf0, 0xe7, 0xc4,
0x8c, 0x48, 0xab, 0x82, 0x0e, 0xe5, 0x99, 0xa4, 0x0d, 0x06, 0xbd, 0x5d, 0xda, 0x49, 0x12, 0xed,
0xeb, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x29, 0xcc, 0xed, 0x11, 0x1e, 0x57, 0xdd, 0x7c, 0xa4, 0x15,
0x9a, 0x50, 0x3e, 0x55, 0x8b, 0x85, 0x5a, 0x46, 0xcc, 0x92, 0x92, 0x95, 0xa9, 0x53, 0xf9, 0x5c,
0x2d, 0x2d, 0xc1, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x56, 0xe5, 0xe3, 0x9d, 0xbf, 0xbf, 0x5c, 0x37,
0xbe, 0x78, 0xb9, 0x6e, 0xfc, 0xfb, 0xe5, 0xba, 0xf1, 0xe3, 0x5b, 0xaf, 0xf8, 0x1b, 0x80, 0xcc,
0x9f, 0x15, 0x60, 0x46, 0x1d, 0x97, 0x12, 0x8f, 0x1f, 0xcd, 0xc8, 0xe0, 0xbf, 0xf5, 0xdf, 0x00,
0x00, 0x00, 0xff, 0xff, 0x38, 0x69, 0xf2, 0xff, 0x75, 0x20, 0x00, 0x00,
// 2114 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0x5b, 0x6f, 0x1b, 0xc7,
0x15, 0xe6, 0x92, 0xba, 0x90, 0x47, 0xb2, 0x44, 0x8d, 0x75, 0x59, 0x31, 0x8e, 0xa0, 0x6c, 0x6b,
0x43, 0xb5, 0x13, 0x12, 0x92, 0x91, 0xb8, 0x70, 0xd2, 0x14, 0x8a, 0x62, 0x4b, 0x8e, 0x2d, 0x5b,
0x5d, 0xbb, 0x2d, 0xd2, 0xba, 0x2d, 0x86, 0xcb, 0x21, 0xb9, 0xe1, 0x5e, 0xc6, 0xbb, 0xb3, 0x0a,
0x64, 0xa0, 0x0f, 0x45, 0x8b, 0x02, 0xfd, 0x03, 0x7d, 0xe8, 0xff, 0x28, 0xfa, 0x54, 0xf4, 0xa9,
0x97, 0xc7, 0xa0, 0x7f, 0xa0, 0x85, 0x1f, 0xfb, 0x2b, 0x8a, 0xb9, 0xec, 0x95, 0x2b, 0xd9, 0x29,
0x65, 0x19, 0xcd, 0x8b, 0xbd, 0x73, 0xe6, 0xcc, 0x39, 0x67, 0xce, 0x9c, 0xcb, 0x37, 0x43, 0xc1,
0xb5, 0x80, 0x50, 0x3f, 0x24, 0xc1, 0x31, 0x09, 0x3a, 0xe2, 0xd3, 0x66, 0x7e, 0x70, 0x92, 0xf9,
0x6c, 0xd3, 0xc0, 0x67, 0x3e, 0x82, 0x94, 0xd2, 0x7a, 0x30, 0xb0, 0xd9, 0x30, 0xea, 0xb6, 0x2d,
0xdf, 0xed, 0xe0, 0x60, 0xe0, 0xd3, 0xc0, 0xff, 0x42, 0x7c, 0xbc, 0x67, 0xf5, 0x3a, 0xc7, 0x3b,
0x1d, 0x3a, 0x1a, 0x74, 0x30, 0xb5, 0xc3, 0x0e, 0xa6, 0xd4, 0xb1, 0x2d, 0xcc, 0x6c, 0xdf, 0xeb,
0x1c, 0x6f, 0x63, 0x87, 0x0e, 0xf1, 0x76, 0x67, 0x40, 0x3c, 0x12, 0x60, 0x46, 0x7a, 0x52, 0x72,
0xeb, 0xad, 0x81, 0xef, 0x0f, 0x1c, 0xd2, 0x11, 0xa3, 0x6e, 0xd4, 0xef, 0x10, 0x97, 0x32, 0xa5,
0xd6, 0xf8, 0xcf, 0x3c, 0x2c, 0x1e, 0x62, 0xcf, 0xee, 0x93, 0x90, 0x99, 0xe4, 0x59, 0x44, 0x42,
0x86, 0x9e, 0xc2, 0x14, 0x37, 0x46, 0xd7, 0x36, 0xb5, 0xad, 0xb9, 0x9d, 0x83, 0x76, 0x6a, 0x4d,
0x3b, 0xb6, 0x46, 0x7c, 0xfc, 0xc2, 0xea, 0xb5, 0x8f, 0x77, 0xda, 0x74, 0x34, 0x68, 0x73, 0x6b,
0xda, 0x19, 0x6b, 0xda, 0xb1, 0x35, 0x6d, 0x33, 0xd9, 0x96, 0x29, 0xa4, 0xa2, 0x16, 0xd4, 0x03,
0x72, 0x6c, 0x87, 0xb6, 0xef, 0xe9, 0xd5, 0x4d, 0x6d, 0xab, 0x61, 0x26, 0x63, 0xa4, 0xc3, 0xac,
0xe7, 0xef, 0x61, 0x6b, 0x48, 0xf4, 0xda, 0xa6, 0xb6, 0x55, 0x37, 0xe3, 0x21, 0xda, 0x84, 0x39,
0x4c, 0xe9, 0x03, 0xdc, 0x25, 0xce, 0x7d, 0x72, 0xa2, 0x4f, 0x89, 0x85, 0x59, 0x12, 0x5f, 0x8b,
0x29, 0x7d, 0x88, 0x5d, 0xa2, 0x4f, 0x8b, 0xd9, 0x78, 0x88, 0xae, 0x40, 0xc3, 0xc3, 0x2e, 0x09,
0x29, 0xb6, 0x88, 0x5e, 0x17, 0x73, 0x29, 0x01, 0xfd, 0x12, 0x96, 0x32, 0x86, 0x3f, 0xf6, 0xa3,
0xc0, 0x22, 0x3a, 0x88, 0xad, 0x3f, 0x9a, 0x6c, 0xeb, 0xbb, 0x45, 0xb1, 0xe6, 0xb8, 0x26, 0xf4,
0x73, 0x98, 0x16, 0x27, 0xaf, 0xcf, 0x6d, 0xd6, 0xce, 0xd5, 0xdb, 0x52, 0x2c, 0xf2, 0x60, 0x96,
0x3a, 0xd1, 0xc0, 0xf6, 0x42, 0x7d, 0x5e, 0x68, 0x78, 0x32, 0x99, 0x86, 0x3d, 0xdf, 0xeb, 0xdb,
0x83, 0x43, 0xec, 0xe1, 0x01, 0x71, 0x89, 0xc7, 0x8e, 0x84, 0x70, 0x33, 0x56, 0x82, 0x9e, 0x43,
0x73, 0x14, 0x85, 0xcc, 0x77, 0xed, 0xe7, 0xe4, 0x11, 0xe5, 0x6b, 0x43, 0xfd, 0x92, 0xf0, 0xe6,
0xc3, 0xc9, 0x14, 0xdf, 0x2f, 0x48, 0x35, 0xc7, 0xf4, 0xf0, 0x20, 0x19, 0x45, 0x5d, 0xf2, 0x23,
0x12, 0x88, 0xe8, 0x5a, 0x90, 0x41, 0x92, 0x21, 0xc9, 0x30, 0xb2, 0xd5, 0x28, 0xd4, 0x17, 0x37,
0x6b, 0x32, 0x8c, 0x12, 0x12, 0xda, 0x82, 0xc5, 0x63, 0x12, 0xd8, 0xfd, 0x93, 0xc7, 0xf6, 0xc0,
0xc3, 0x2c, 0x0a, 0x88, 0xde, 0x14, 0xa1, 0x58, 0x24, 0x23, 0x17, 0x2e, 0x0d, 0x89, 0xe3, 0x72,
0x97, 0xef, 0x05, 0xa4, 0x17, 0xea, 0x4b, 0xc2, 0xbf, 0xfb, 0x93, 0x9f, 0xa0, 0x10, 0x67, 0xe6,
0xa5, 0x73, 0xc3, 0x3c, 0xdf, 0x54, 0x99, 0x22, 0x73, 0x04, 0x49, 0xc3, 0x0a, 0x64, 0x74, 0x0d,
0x16, 0x58, 0x80, 0xad, 0x91, 0xed, 0x0d, 0x0e, 0x09, 0x1b, 0xfa, 0x3d, 0xfd, 0xb2, 0xf0, 0x44,
0x81, 0x8a, 0x2c, 0x40, 0xc4, 0xc3, 0x5d, 0x87, 0xf4, 0x64, 0x2c, 0x3e, 0x39, 0xa1, 0x24, 0xd4,
0x97, 0xc5, 0x2e, 0x6e, 0xb6, 0x33, 0x15, 0xaa, 0x50, 0x20, 0xda, 0x77, 0xc6, 0x56, 0xdd, 0xf1,
0x58, 0x70, 0x62, 0x96, 0x88, 0x43, 0x23, 0x98, 0xe3, 0xfb, 0x88, 0x43, 0x61, 0x45, 0x84, 0xc2,
0xbd, 0xc9, 0x7c, 0x74, 0x90, 0x0a, 0x34, 0xb3, 0xd2, 0x51, 0x1b, 0xd0, 0x10, 0x87, 0x87, 0x91,
0xc3, 0x6c, 0xea, 0x10, 0x69, 0x46, 0xa8, 0xaf, 0x0a, 0x37, 0x95, 0xcc, 0xa0, 0xfb, 0x00, 0x01,
0xe9, 0xc7, 0x7c, 0x6b, 0x62, 0xe7, 0x37, 0xce, 0xda, 0xb9, 0x99, 0x70, 0xcb, 0x1d, 0x67, 0x96,
0x73, 0xe5, 0x7c, 0x1b, 0xc4, 0x62, 0x2a, 0xdb, 0x45, 0x5a, 0xeb, 0x22, 0xc4, 0x4a, 0x66, 0x78,
0x2c, 0x2a, 0xaa, 0x28, 0x5a, 0xeb, 0x32, 0x5a, 0x33, 0xa4, 0xd6, 0x1d, 0x58, 0x3b, 0xc5, 0xd5,
0xa8, 0x09, 0xb5, 0x11, 0x39, 0x11, 0x25, 0xba, 0x61, 0xf2, 0x4f, 0xb4, 0x0c, 0xd3, 0xc7, 0xd8,
0x89, 0x88, 0x28, 0xaa, 0x75, 0x53, 0x0e, 0x6e, 0x57, 0xbf, 0xab, 0xb5, 0x7e, 0xab, 0xc1, 0x62,
0xc1, 0xf0, 0x92, 0xf5, 0x3f, 0xcb, 0xae, 0x3f, 0x87, 0x30, 0xee, 0x3f, 0xc1, 0xc1, 0x80, 0xb0,
0x8c, 0x21, 0xc6, 0x3f, 0x35, 0xd0, 0x0b, 0x1e, 0xfd, 0xb1, 0xcd, 0x86, 0x77, 0x6d, 0x87, 0x84,
0xe8, 0x16, 0xcc, 0x06, 0x92, 0xa6, 0x1a, 0xcf, 0x5b, 0x67, 0x1c, 0xc4, 0x41, 0xc5, 0x8c, 0xb9,
0xd1, 0xc7, 0x50, 0x77, 0x09, 0xc3, 0x3d, 0xcc, 0xb0, 0xb2, 0x7d, 0xb3, 0x6c, 0x25, 0xd7, 0x72,
0xa8, 0xf8, 0x0e, 0x2a, 0x66, 0xb2, 0x06, 0xbd, 0x0f, 0xd3, 0xd6, 0x30, 0xf2, 0x46, 0xa2, 0xe5,
0xcc, 0xed, 0xbc, 0x7d, 0xda, 0xe2, 0x3d, 0xce, 0x74, 0x50, 0x31, 0x25, 0xf7, 0x27, 0x33, 0x30,
0x45, 0x71, 0xc0, 0x8c, 0xbb, 0xb0, 0x5c, 0xa6, 0x82, 0xf7, 0x39, 0x6b, 0x48, 0xac, 0x51, 0x18,
0xb9, 0xca, 0xcd, 0xc9, 0x18, 0x21, 0x98, 0x0a, 0xed, 0xe7, 0xd2, 0xd5, 0x35, 0x53, 0x7c, 0x1b,
0xdf, 0x81, 0xa5, 0x31, 0x6d, 0xfc, 0x50, 0xa5, 0x6d, 0x5c, 0xc2, 0xbc, 0x52, 0x6d, 0x44, 0xb0,
0xf2, 0x44, 0xf8, 0x22, 0x29, 0xf6, 0x17, 0xd1, 0xb9, 0x8d, 0x03, 0x58, 0x2d, 0xaa, 0x0d, 0xa9,
0xef, 0x85, 0x84, 0x87, 0xbe, 0xa8, 0x8e, 0x36, 0xe9, 0xa5, 0xb3, 0xc2, 0x8a, 0xba, 0x59, 0x32,
0x63, 0xfc, 0xaa, 0x0a, 0xab, 0x26, 0x09, 0x7d, 0xe7, 0x98, 0xc4, 0xa5, 0xeb, 0x62, 0xc0, 0xc7,
0x4f, 0xa1, 0x86, 0x29, 0x55, 0x61, 0x72, 0xef, 0xdc, 0xda, 0xbb, 0xc9, 0xa5, 0xa2, 0x77, 0x61,
0x09, 0xbb, 0x5d, 0x7b, 0x10, 0xf9, 0x51, 0x18, 0x6f, 0x4b, 0x04, 0x55, 0xc3, 0x1c, 0x9f, 0x30,
0x2c, 0x58, 0x1b, 0x73, 0x81, 0x72, 0x67, 0x16, 0x22, 0x69, 0x05, 0x88, 0x54, 0xaa, 0xa4, 0x7a,
0x9a, 0x92, 0xbf, 0x69, 0xd0, 0x4c, 0x53, 0x47, 0x89, 0xbf, 0x02, 0x0d, 0x57, 0xd1, 0x42, 0x5d,
0x13, 0xf5, 0x29, 0x25, 0xe4, 0xd1, 0x52, 0xb5, 0x88, 0x96, 0x56, 0x61, 0x46, 0x82, 0x59, 0xb5,
0x31, 0x35, 0xca, 0x99, 0x3c, 0x55, 0x30, 0x79, 0x03, 0x20, 0x4c, 0xea, 0x97, 0x3e, 0x23, 0x66,
0x33, 0x14, 0x64, 0xc0, 0xbc, 0xec, 0xad, 0x26, 0x09, 0x23, 0x87, 0xe9, 0xb3, 0x82, 0x23, 0x47,
0x33, 0x7c, 0x58, 0x7c, 0x60, 0xf3, 0x3d, 0xf4, 0xc3, 0x8b, 0x09, 0xf6, 0x0f, 0x60, 0x8a, 0x2b,
0xe3, 0x1b, 0xeb, 0x06, 0xd8, 0xb3, 0x86, 0x24, 0xf6, 0x55, 0x32, 0xe6, 0x69, 0xcc, 0xf0, 0x20,
0xd4, 0xab, 0x82, 0x2e, 0xbe, 0x8d, 0x3f, 0x55, 0xa5, 0xa5, 0xbb, 0x94, 0x86, 0x6f, 0x1e, 0x50,
0x97, 0xb7, 0xf8, 0xda, 0x78, 0x8b, 0x2f, 0x98, 0xfc, 0x75, 0x5a, 0xfc, 0x39, 0xb5, 0x29, 0x23,
0x82, 0xd9, 0x5d, 0x4a, 0xb9, 0x21, 0x68, 0x1b, 0xa6, 0x30, 0xa5, 0xd2, 0xe1, 0x85, 0x8a, 0xac,
0x58, 0xf8, 0xff, 0xca, 0x24, 0xc1, 0xda, 0xba, 0x05, 0x8d, 0x84, 0xf4, 0x32, 0xb5, 0x8d, 0xac,
0xda, 0x4d, 0x00, 0x89, 0x61, 0xef, 0x79, 0x7d, 0x9f, 0x1f, 0x29, 0x0f, 0x76, 0xb5, 0x54, 0x7c,
0x1b, 0xb7, 0x63, 0x0e, 0x61, 0xdb, 0xbb, 0x30, 0x6d, 0x33, 0xe2, 0xc6, 0xc6, 0xad, 0x66, 0x8d,
0x4b, 0x05, 0x99, 0x92, 0xc9, 0xf8, 0x7b, 0x1d, 0xd6, 0xf9, 0x89, 0x3d, 0x16, 0x69, 0xb2, 0x4b,
0xe9, 0xa7, 0x84, 0x61, 0xdb, 0x09, 0x7f, 0x10, 0x91, 0xe0, 0xe4, 0x35, 0x07, 0xc6, 0x00, 0x66,
0x64, 0x96, 0xa9, 0x7a, 0x77, 0xee, 0xd7, 0x19, 0x25, 0x3e, 0xbd, 0xc3, 0xd4, 0x5e, 0xcf, 0x1d,
0xa6, 0xec, 0x4e, 0x31, 0x75, 0x41, 0x77, 0x8a, 0xd3, 0xaf, 0x95, 0x99, 0xcb, 0xea, 0x4c, 0xfe,
0xb2, 0x5a, 0x02, 0xd5, 0x67, 0x5f, 0x15, 0xaa, 0xd7, 0x4b, 0xa1, 0xba, 0x5b, 0x9a, 0xc7, 0x0d,
0xe1, 0xee, 0xef, 0x65, 0x23, 0xf0, 0xd4, 0x58, 0x9b, 0x04, 0xb4, 0xc3, 0x6b, 0x05, 0xed, 0x3f,
0xcc, 0x81, 0x70, 0x79, 0x0d, 0x7e, 0xff, 0xd5, 0xf6, 0x74, 0x06, 0x1c, 0xff, 0xc6, 0x81, 0xe7,
0xdf, 0x08, 0xcc, 0x44, 0xfd, 0xd4, 0x07, 0x49, 0x43, 0xe7, 0x7d, 0x88, 0xb7, 0x56, 0x55, 0xb4,
0xf8, 0x37, 0xba, 0x01, 0x53, 0xdc, 0xc9, 0x0a, 0xd4, 0xae, 0x65, 0xfd, 0xc9, 0x4f, 0x62, 0x97,
0xd2, 0xc7, 0x94, 0x58, 0xa6, 0x60, 0x42, 0xb7, 0xa1, 0x91, 0x04, 0xbe, 0xca, 0xac, 0x2b, 0xd9,
0x15, 0x49, 0x9e, 0xc4, 0xcb, 0x52, 0x76, 0xbe, 0xb6, 0x67, 0x07, 0xc4, 0x12, 0x90, 0x6f, 0x7a,
0x7c, 0xed, 0xa7, 0xf1, 0x64, 0xb2, 0x36, 0x61, 0x47, 0xdb, 0x30, 0x23, 0xdf, 0x0d, 0x44, 0x06,
0xcd, 0xed, 0xac, 0x8f, 0x17, 0xd3, 0x78, 0x95, 0x62, 0x34, 0xfe, 0xaa, 0xc1, 0x3b, 0x69, 0x40,
0xc4, 0xd9, 0x14, 0xa3, 0xee, 0x37, 0xdf, 0x71, 0xaf, 0xc1, 0x82, 0x80, 0xf9, 0xe9, 0xf3, 0x81,
0x7c, 0xc9, 0x2a, 0x50, 0x8d, 0x3f, 0x6a, 0x70, 0x75, 0x7c, 0x1f, 0x7b, 0x43, 0x1c, 0xb0, 0xe4,
0x78, 0x2f, 0x62, 0x2f, 0x71, 0xc3, 0xab, 0xa6, 0x0d, 0x2f, 0xb7, 0xbf, 0x5a, 0x7e, 0x7f, 0xc6,
0x5f, 0xaa, 0x30, 0x97, 0x09, 0xa0, 0xb2, 0x86, 0xc9, 0x01, 0x9f, 0x88, 0x5b, 0x71, 0xb1, 0x13,
0x4d, 0xa1, 0x61, 0x66, 0x28, 0x68, 0x04, 0x40, 0x71, 0x80, 0x5d, 0xc2, 0x48, 0xc0, 0x2b, 0x39,
0xcf, 0xf8, 0xfb, 0x93, 0x57, 0x97, 0xa3, 0x58, 0xa6, 0x99, 0x11, 0xcf, 0x11, 0xab, 0x50, 0x1d,
0xaa, 0xfa, 0xad, 0x46, 0xe8, 0x4b, 0x58, 0xe8, 0xdb, 0x0e, 0x39, 0x4a, 0x0d, 0x99, 0x11, 0x86,
0x3c, 0x9a, 0xdc, 0x90, 0xbb, 0x59, 0xb9, 0x66, 0x41, 0x8d, 0x71, 0x1d, 0x9a, 0xc5, 0x7c, 0xe2,
0x46, 0xda, 0x2e, 0x1e, 0x24, 0xde, 0x52, 0x23, 0x03, 0x41, 0xb3, 0x98, 0x3f, 0xc6, 0xbf, 0xaa,
0xb0, 0x92, 0x88, 0xdb, 0xf5, 0x3c, 0x3f, 0xf2, 0x2c, 0xf1, 0x14, 0x57, 0x7a, 0x16, 0xcb, 0x30,
0xcd, 0x6c, 0xe6, 0x24, 0xc0, 0x47, 0x0c, 0x78, 0xef, 0x62, 0xbe, 0xef, 0x30, 0x9b, 0xaa, 0x03,
0x8e, 0x87, 0xf2, 0xec, 0x9f, 0x45, 0x76, 0x40, 0x7a, 0xa2, 0x12, 0xd4, 0xcd, 0x64, 0xcc, 0xe7,
0x38, 0xaa, 0x11, 0x30, 0x5e, 0x3a, 0x33, 0x19, 0x8b, 0xb8, 0xf7, 0x1d, 0x87, 0x58, 0xdc, 0x1d,
0x19, 0xa0, 0x5f, 0xa0, 0x8a, 0x0b, 0x04, 0x0b, 0x6c, 0x6f, 0xa0, 0x60, 0xbe, 0x1a, 0x71, 0x3b,
0x71, 0x10, 0xe0, 0x13, 0xbd, 0x2e, 0x1c, 0x20, 0x07, 0xe8, 0x23, 0xa8, 0xb9, 0x98, 0xaa, 0x46,
0x77, 0x3d, 0x57, 0x1d, 0xca, 0x3c, 0xd0, 0x3e, 0xc4, 0x54, 0x76, 0x02, 0xbe, 0xac, 0xf5, 0x01,
0xd4, 0x63, 0xc2, 0xd7, 0x82, 0x84, 0x5f, 0xc0, 0xa5, 0x5c, 0xf1, 0x41, 0x9f, 0xc3, 0x6a, 0x1a,
0x51, 0x59, 0x85, 0x0a, 0x04, 0xbe, 0xf3, 0x52, 0xcb, 0xcc, 0x53, 0x04, 0x18, 0xcf, 0x60, 0x89,
0x87, 0x8c, 0x48, 0xfc, 0x0b, 0xba, 0xda, 0x7c, 0x08, 0x8d, 0x44, 0x65, 0x69, 0xcc, 0xb4, 0xa0,
0x7e, 0x1c, 0x3f, 0x91, 0xca, 0xbb, 0x4d, 0x32, 0x36, 0x76, 0x01, 0x65, 0xed, 0x55, 0x1d, 0xe8,
0x46, 0x1e, 0x14, 0xaf, 0x14, 0xdb, 0x8d, 0x60, 0x8f, 0x31, 0xf1, 0xef, 0xaa, 0xb0, 0xb8, 0x6f,
0x8b, 0x57, 0x8e, 0x0b, 0x2a, 0x72, 0xd7, 0xa1, 0x19, 0x46, 0x5d, 0xd7, 0xef, 0x45, 0x0e, 0x51,
0xa0, 0x40, 0x75, 0xfa, 0x31, 0xfa, 0x59, 0xc5, 0x8f, 0x3b, 0x8b, 0x62, 0x36, 0x54, 0x37, 0x5c,
0xf1, 0x8d, 0x3e, 0x82, 0xf5, 0x87, 0xe4, 0x4b, 0xb5, 0x9f, 0x7d, 0xc7, 0xef, 0x76, 0x6d, 0x6f,
0x10, 0x2b, 0x99, 0x16, 0x4a, 0x4e, 0x67, 0x30, 0x7e, 0xad, 0x41, 0x33, 0xf5, 0x85, 0xf2, 0xe6,
0x2d, 0x19, 0xf5, 0xd2, 0x97, 0x57, 0xb3, 0xbe, 0x2c, 0xb2, 0xfe, 0xef, 0x01, 0x3f, 0x9f, 0x0d,
0xf8, 0x3f, 0x6b, 0xb0, 0xb2, 0x6f, 0xb3, 0xb8, 0xd4, 0xd8, 0xff, 0x67, 0xe7, 0x62, 0xb4, 0x61,
0xb5, 0x68, 0xbe, 0x72, 0xe5, 0x32, 0x4c, 0xf3, 0x53, 0x8a, 0xef, 0xee, 0x72, 0xb0, 0xf3, 0x55,
0x03, 0x96, 0xd2, 0xe6, 0xcb, 0xff, 0xb5, 0x2d, 0x82, 0x1e, 0x41, 0x73, 0x5f, 0xfd, 0x76, 0x16,
0xbf, 0x99, 0xa0, 0xb3, 0x1e, 0x21, 0x5b, 0x57, 0xca, 0x27, 0xa5, 0x6a, 0xa3, 0x82, 0x2c, 0x58,
0x2f, 0x0a, 0x4c, 0xdf, 0x3b, 0xbf, 0x7d, 0x86, 0xe4, 0x84, 0xeb, 0x65, 0x2a, 0xb6, 0x34, 0xf4,
0x39, 0x2c, 0xe4, 0x5f, 0xe5, 0x50, 0xae, 0x1a, 0x95, 0x3e, 0x14, 0xb6, 0x8c, 0xb3, 0x58, 0x12,
0xfb, 0x9f, 0x72, 0xe8, 0x9b, 0x7b, 0xa2, 0x42, 0x46, 0x1e, 0x98, 0x97, 0x3d, 0xe1, 0xb5, 0xbe,
0x75, 0x26, 0x4f, 0x22, 0xfd, 0x43, 0xa8, 0xc7, 0x4f, 0x3a, 0x79, 0x37, 0x17, 0x1e, 0x7a, 0x5a,
0xcd, 0xbc, 0xbc, 0x7e, 0x68, 0x54, 0xd0, 0xc7, 0x72, 0x31, 0xbf, 0xf2, 0x8f, 0x2f, 0xce, 0x3c,
0x64, 0xb4, 0x2e, 0x97, 0x3c, 0x1e, 0x18, 0x15, 0xf4, 0x7d, 0x98, 0xe3, 0x5f, 0x47, 0xea, 0x57,
0xab, 0xd5, 0xb6, 0xfc, 0x91, 0xb4, 0x1d, 0xff, 0x48, 0xda, 0xbe, 0xe3, 0x52, 0x76, 0xd2, 0x2a,
0xb9, 0xdd, 0x2b, 0x01, 0x4f, 0xe1, 0xd2, 0x3e, 0x61, 0x29, 0x18, 0x47, 0x57, 0x5f, 0xe9, 0xca,
0xd2, 0x32, 0x8a, 0x6c, 0xe3, 0x78, 0xde, 0xa8, 0xa0, 0xdf, 0x6b, 0x70, 0x79, 0x9f, 0xb0, 0x22,
0xbc, 0x45, 0xef, 0x95, 0x2b, 0x39, 0x05, 0x06, 0xb7, 0x1e, 0x4e, 0x9a, 0xaf, 0x79, 0xb1, 0x46,
0x05, 0xfd, 0x41, 0x83, 0xb5, 0x8c, 0x61, 0x59, 0xbc, 0x8a, 0xb6, 0xcf, 0x36, 0xae, 0x04, 0xdb,
0xb6, 0x3e, 0x9b, 0xf0, 0xc7, 0xc8, 0x8c, 0x48, 0xa3, 0x82, 0x8e, 0xc4, 0x99, 0xa4, 0xed, 0x09,
0xbd, 0x5d, 0xda, 0x87, 0x12, 0xed, 0x1b, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x19, 0xcc, 0xed, 0x13,
0x16, 0x57, 0xdd, 0x7c, 0xa4, 0x15, 0x5a, 0x58, 0x3e, 0x55, 0x8b, 0x85, 0x5a, 0x44, 0xcc, 0x92,
0x94, 0x95, 0xa9, 0x53, 0xf9, 0x5c, 0x2d, 0x2d, 0xc1, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x46, 0xe5,
0x93, 0xdd, 0x7f, 0xbc, 0xd8, 0xd0, 0xbe, 0x7a, 0xb1, 0xa1, 0xfd, 0xfb, 0xc5, 0x86, 0xf6, 0x93,
0x9b, 0x2f, 0xf9, 0x0b, 0x82, 0xcc, 0x1f, 0x25, 0x60, 0x6a, 0x5b, 0x8e, 0x4d, 0x3c, 0xd6, 0x9d,
0x11, 0xc1, 0x7f, 0xf3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x86, 0xe4, 0x0d, 0xb3, 0x20,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -4668,6 +4678,16 @@ func (m *GitFilesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.NewGitFileGlobbingEnabled {
i--
if m.NewGitFileGlobbingEnabled {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x28
}
if len(m.Path) > 0 {
i -= len(m.Path)
copy(dAtA[i:], m.Path)
@ -5662,6 +5682,9 @@ func (m *GitFilesRequest) Size() (n int) {
if l > 0 {
n += 1 + l + sovRepository(uint64(l))
}
if m.NewGitFileGlobbingEnabled {
n += 2
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@ -10830,6 +10853,26 @@ func (m *GitFilesRequest) Unmarshal(dAtA []byte) error {
}
m.Path = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NewGitFileGlobbingEnabled", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.NewGitFileGlobbingEnabled = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])

View file

@ -2552,6 +2552,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
repo := request.GetRepo()
revision := request.GetRevision()
gitPath := request.GetPath()
enableNewGitFileGlobbing := request.GetNewGitFileGlobbingEnabled()
if gitPath == "" {
gitPath = "."
}
@ -2585,7 +2586,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
}
defer io.Close(closer)
gitFiles, err := gitClient.LsFiles(gitPath)
gitFiles, err := gitClient.LsFiles(gitPath, enableNewGitFileGlobbing)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to list files. repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err)
}

View file

@ -234,6 +234,7 @@ message GitFilesRequest {
bool submoduleEnabled = 2;
string revision = 3;
string path = 4;
bool NewGitFileGlobbingEnabled = 5;
}
message GitFilesResponse {

View file

@ -3026,7 +3026,7 @@ func TestGetGitFiles(t *testing.T) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return(nil)
gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("Root").Return(root)
gitClient.On("LsFiles", mock.Anything).Once().Return(files, nil)
gitClient.On("LsFiles", mock.Anything, mock.Anything).Once().Return(files, nil)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
}, root)

View file

@ -17,6 +17,7 @@ import (
"time"
argoexec "github.com/argoproj/pkg/exec"
"github.com/bmatcuk/doublestar/v4"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
@ -66,7 +67,7 @@ type Client interface {
Checkout(revision string, submoduleEnabled bool) error
LsRefs() (*Refs, error)
LsRemote(revision string) (string, error)
LsFiles(path string) ([]string, error)
LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error)
LsLargeFiles() ([]string, error)
CommitSHA() (string, error)
RevisionMetadata(revision string) (*RevisionMetadata, error)
@ -365,14 +366,44 @@ func (m *nativeGitClient) Fetch(revision string) error {
}
// LsFiles lists the local working tree, including only files that are under source control
func (m *nativeGitClient) LsFiles(path string) ([]string, error) {
out, err := m.runCmd("ls-files", "--full-name", "-z", "--", path)
if err != nil {
return nil, err
func (m *nativeGitClient) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {
if enableNewGitFileGlobbing {
// This is the new way with safer globbing
err := os.Chdir(m.root)
if err != nil {
return nil, err
}
all_files, err := doublestar.FilepathGlob(path)
if err != nil {
return nil, err
}
var files []string
for _, file := range all_files {
link, err := filepath.EvalSymlinks(file)
if err != nil {
return nil, err
}
absPath, err := filepath.Abs(link)
if err != nil {
return nil, err
}
if strings.HasPrefix(absPath, m.root) {
files = append(files, file)
} else {
log.Warnf("Absolute path for %s is outside of repository, removing it", file)
}
}
return files, nil
} else {
// This is the old and default way
out, err := m.runCmd("ls-files", "--full-name", "-z", "--", path)
if err != nil {
return nil, err
}
// remove last element, which is blank regardless of whether we're using nullbyte or newline
ss := strings.Split(out, "\000")
return ss[:len(ss)-1], nil
}
// remove last element, which is blank regardless of whether we're using nullbyte or newline
ss := strings.Split(out, "\000")
return ss[:len(ss)-1], nil
}
// LsLargeFiles lists all files that have references to LFS storage

View file

@ -411,3 +411,54 @@ func TestListRevisions(t *testing.T) {
assert.NotContains(t, lsResult.Branches, testTag)
assert.NotContains(t, lsResult.Tags, testBranch)
}
func TestLsFiles(t *testing.T) {
tmpDir1 := t.TempDir()
tmpDir2 := t.TempDir()
client, err := NewClientExt("", tmpDir1, NopCreds{}, false, false, "")
assert.NoError(t, err)
err = runCmd(tmpDir1, "git", "init")
assert.NoError(t, err)
// Prepare files
a, err := os.Create(filepath.Join(tmpDir1, "a.yaml"))
assert.NoError(t, err)
a.Close()
err = os.MkdirAll(filepath.Join(tmpDir1, "subdir"), 0755)
assert.NoError(t, err)
b, err := os.Create(filepath.Join(tmpDir1, "subdir", "b.yaml"))
assert.NoError(t, err)
b.Close()
err = os.MkdirAll(filepath.Join(tmpDir2, "subdir"), 0755)
assert.NoError(t, err)
c, err := os.Create(filepath.Join(tmpDir2, "c.yaml"))
assert.NoError(t, err)
c.Close()
err = os.Symlink(filepath.Join(tmpDir2, "c.yaml"), filepath.Join(tmpDir1, "link.yaml"))
assert.NoError(t, err)
err = runCmd(tmpDir1, "git", "add", ".")
assert.NoError(t, err)
err = runCmd(tmpDir1, "git", "commit", "-m", "Initial commit")
assert.NoError(t, err)
// Old and default globbing
expectedResult := []string{"a.yaml", "link.yaml", "subdir/b.yaml"}
lsResult, err := client.LsFiles("*.yaml", false)
assert.NoError(t, err)
assert.Equal(t, lsResult, expectedResult)
// New and safer globbing, do not return symlinks resolving outside of the repo
expectedResult = []string{"a.yaml"}
lsResult, err = client.LsFiles("*.yaml", true)
assert.NoError(t, err)
assert.Equal(t, lsResult, expectedResult)
// New globbing, do not return files outside of the repo
var nilResult []string
lsResult, err = client.LsFiles(filepath.Join(tmpDir2, "*.yaml"), true)
assert.NoError(t, err)
assert.Equal(t, lsResult, nilResult)
}

View file

@ -75,8 +75,8 @@ func (_m *Client) Init() error {
return r0
}
// LsFiles provides a mock function with given fields: path
func (_m *Client) LsFiles(path string) ([]string, error) {
// LsFiles provides a mock function with given fields: path, enableNewGitFileGlobbing
func (_m *Client) LsFiles(path string, enableNewGitFileGlobbing bool) ([]string, error) {
ret := _m.Called(path)
var r0 []string