Compare commits

...

11 Commits

Author SHA1 Message Date
argo-bot
b4c79ccb88 Bump version to 1.7.3 2020-09-01 23:07:14 +00:00
argo-bot
3d91e911cf Bump version to 1.7.3 2020-09-01 23:07:04 +00:00
Alexander Matyushentsev
4f92c28eea fix: application details page crash when app is deleted (#4229) 2020-09-01 15:26:48 -07:00
Alexander Matyushentsev
d08dba171e fix: api-server unnecessary normalize projects on every start (#4219) 2020-09-01 13:09:05 -07:00
Alexander Matyushentsev
fe9d71d47a refactor: load only project names in UI (#4217) 2020-09-01 13:08:58 -07:00
jannfis
79ffa9fb9f fix: Re-create already initialized ARGOCD_GNUPGHOME on startup (#4214) (#4223) 2020-09-01 13:08:45 -07:00
Alexander Matyushentsev
918a19d69c feat: support gzip compression in api server (#4218) 2020-09-01 10:50:08 -07:00
chrisob
ed77b994e3 fix: Add openshift as a dex connector type which requires a redirectURI (#4222) 2020-09-01 10:33:29 -07:00
Alexander Matyushentsev
fba91aec51 refactor: Replace status.observedAt with redis pub/sub channels for resource tree updates (#1340) (#4208) 2020-08-31 14:01:10 -07:00
Alexander Matyushentsev
8a7fa9d665 fix: cache inconsistency of child resources (#4053) (#4202) 2020-08-31 14:01:05 -07:00
Oleg Sucharevich
26fda7ce52 feat: do not include kube-api check in application liveness flow (#4163)
* feat: do not include kube-api liveness check in application liveness flow
2020-08-31 14:01:01 -07:00
41 changed files with 610 additions and 235 deletions

View File

@@ -1 +1 @@
1.7.2
1.7.3

View File

@@ -2227,6 +2227,56 @@
}
}
},
"/api/v1/stream/applications/{applicationName}/resource-tree": {
"get": {
"tags": [
"ApplicationService"
],
"summary": "Watch returns stream of application resource tree",
"operationId": "WatchResourceTree",
"parameters": [
{
"type": "string",
"name": "applicationName",
"in": "path",
"required": true
},
{
"type": "string",
"name": "namespace",
"in": "query"
},
{
"type": "string",
"name": "name",
"in": "query"
},
{
"type": "string",
"name": "version",
"in": "query"
},
{
"type": "string",
"name": "group",
"in": "query"
},
{
"type": "string",
"name": "kind",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/x-stream-definitions/v1alpha1ApplicationTree"
}
}
}
}
},
"/api/version": {
"get": {
"tags": [

View File

@@ -58,6 +58,7 @@ func NewCommand() *cobra.Command {
repoServerAddress string
dexServerAddress string
disableAuth bool
enableGZip bool
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
cacheSrc func() (*servercache.Cache, error)
frameOptions string
@@ -115,6 +116,7 @@ func NewCommand() *cobra.Command {
RepoClientset: repoclientset,
DexServerAddr: dexServerAddress,
DisableAuth: disableAuth,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
XFrameOptions: frameOptions,
@@ -146,6 +148,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&repoServerAddress, "repo-server", common.DefaultRepoServerAddr, "Repo server address")
command.Flags().StringVar(&dexServerAddress, "dex-server", common.DefaultDexServerAddr, "Dex server address")
command.Flags().BoolVar(&disableAuth, "disable-auth", false, "Disable client authentication")
command.Flags().BoolVar(&enableGZip, "enable-gzip", false, "Enable GZIP compression")
command.AddCommand(cli.NewVersionCmd(cliName))
command.Flags().IntVar(&listenPort, "port", common.DefaultPortAPIServer, "Listen on given port")
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDAPIServerMetrics, "Start metrics on given port")

View File

@@ -177,8 +177,7 @@ func NewApplicationController(
})
metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort)
ctrl.metricsServer = metrics.NewMetricsServer(metricsAddr, appLister, func() error {
_, err := kubeClientset.Discovery().ServerVersion()
return err
return nil
})
stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated)
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer)
@@ -1031,8 +1030,6 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
appv1.ApplicationConditionComparisonError: true,
})
}
now := metav1.Now()
app.Status.ObservedAt = &now
ctrl.persistAppStatus(origApp, &app.Status)
return
}
@@ -1056,7 +1053,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
revision = app.Status.Sync.Revision
}
observedAt := metav1.Now()
now := metav1.Now()
compareResult := ctrl.appStateManager.CompareAppState(app, project, revision, app.Spec.Source, refreshType == appv1.RefreshTypeHard, localManifests)
for k, v := range compareResult.timings {
logCtx = logCtx.WithField(k, v.Milliseconds())
@@ -1089,9 +1086,8 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
}
if app.Status.ReconciledAt == nil || comparisonLevel == CompareWithLatest {
app.Status.ReconciledAt = &observedAt
app.Status.ReconciledAt = &now
}
app.Status.ObservedAt = &observedAt
app.Status.Sync = *compareResult.syncStatus
app.Status.Health = *compareResult.healthStatus
app.Status.Resources = compareResult.resources

View File

@@ -962,7 +962,7 @@ func TestUpdateReconciledAt(t *testing.T) {
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
assert.NoError(t, err)
assert.True(t, updated)
assert.False(t, updated)
})
t.Run("NotUpdatedOnPartialReconciliation", func(t *testing.T) {
@@ -978,7 +978,7 @@ func TestUpdateReconciledAt(t *testing.T) {
_, updated, err = unstructured.NestedString(receivedPatch, "status", "observedAt")
assert.NoError(t, err)
assert.True(t, updated)
assert.False(t, updated)
})
}

3
go.mod
View File

@@ -8,7 +8,7 @@ require (
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect
github.com/alicebob/miniredis v2.5.0+incompatible
github.com/argoproj/gitops-engine v0.1.3-0.20200826062957-2cf3a72c659c
github.com/argoproj/gitops-engine v0.1.3-0.20200829034824-8472746916e6
github.com/argoproj/pkg v0.0.0-20200624215116-23e74cb168fe
github.com/casbin/casbin v1.9.1
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
@@ -35,6 +35,7 @@ require (
github.com/google/go-jsonnet v0.16.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.1.1
github.com/gorilla/handlers v1.5.0
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0

9
go.sum
View File

@@ -57,8 +57,8 @@ github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+Dx
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/argoproj/gitops-engine v0.1.3-0.20200826062957-2cf3a72c659c h1:sX3CD5rYfYe9l/tcVq6Zp09byT29EFOSDTggY8Zimgg=
github.com/argoproj/gitops-engine v0.1.3-0.20200826062957-2cf3a72c659c/go.mod h1:LhzAS5UB6MusZ8MJj1dys1Em5xGPxEIZHdp2oz81ViY=
github.com/argoproj/gitops-engine v0.1.3-0.20200829034824-8472746916e6 h1:aoDGrZdTtFFoddKV5+azCOcFBfcDlJk6ddIK6SKZm04=
github.com/argoproj/gitops-engine v0.1.3-0.20200829034824-8472746916e6/go.mod h1:jeiFokbkgLXjvx3eXB0MddyxsmftWsFTY7paLH4ZqCg=
github.com/argoproj/pkg v0.0.0-20200624215116-23e74cb168fe h1:HjTM7H8Z+J1xt340LNpH9q4jc8pXeqzkC8QKIjQphp4=
github.com/argoproj/pkg v0.0.0-20200624215116-23e74cb168fe/go.mod h1:2EZ44RG/CcgtPTwrRR0apOc7oU6UIw8GjCUJWZ8X3bM=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -155,7 +155,6 @@ github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw=
github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
@@ -165,6 +164,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo
github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
@@ -341,6 +342,8 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.5.0 h1:4wjo3sf9azi99c8hTmyaxp9y5S+pFszsy3pP0rAw/lw=
github.com/gorilla/handlers v1.5.0/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=

View File

@@ -12,4 +12,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: v1.7.2
newTag: v1.7.3

View File

@@ -821,7 +821,7 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated without querying latest git state
description: 'ObservedAt indicates when the application state was updated without querying latest git state Deprecated: controller no longer updates ObservedAt field'
format: date-time
type: string
operationState:

View File

@@ -18,4 +18,4 @@ bases:
images:
- name: argoproj/argocd
newName: argoproj/argocd
newTag: v1.7.2
newTag: v1.7.3

View File

@@ -922,8 +922,9 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
description: 'ObservedAt indicates when the application state was updated
without querying latest git state Deprecated: controller no longer
updates ObservedAt field'
format: date-time
type: string
operationState:
@@ -3082,7 +3083,7 @@ spec:
- "10"
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3138,7 +3139,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3188,7 +3189,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-repo-server
ports:
@@ -3263,7 +3264,7 @@ spec:
env:
- name: ARGOCD_API_SERVER_REPLICAS
value: "2"
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-server
ports:

View File

@@ -922,8 +922,9 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
description: 'ObservedAt indicates when the application state was updated
without querying latest git state Deprecated: controller no longer
updates ObservedAt field'
format: date-time
type: string
operationState:
@@ -2997,7 +2998,7 @@ spec:
- "10"
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3053,7 +3054,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3103,7 +3104,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis-ha-haproxy:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-repo-server
ports:
@@ -3178,7 +3179,7 @@ spec:
env:
- name: ARGOCD_API_SERVER_REPLICAS
value: "2"
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-server
ports:

View File

@@ -922,8 +922,9 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
description: 'ObservedAt indicates when the application state was updated
without querying latest git state Deprecated: controller no longer
updates ObservedAt field'
format: date-time
type: string
operationState:
@@ -2582,7 +2583,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2638,7 +2639,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2707,7 +2708,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-repo-server
ports:
@@ -2762,7 +2763,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-server
ports:

View File

@@ -922,8 +922,9 @@ spec:
type: object
type: array
observedAt:
description: ObservedAt indicates when the application state was updated
without querying latest git state
description: 'ObservedAt indicates when the application state was updated
without querying latest git state Deprecated: controller no longer
updates ObservedAt field'
format: date-time
type: string
operationState:
@@ -2497,7 +2498,7 @@ spec:
- "20"
- --operation-processors
- "10"
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2553,7 +2554,7 @@ spec:
- -n
- /usr/local/bin/argocd-util
- /shared
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -2622,7 +2623,7 @@ spec:
- argocd-repo-server
- --redis
- argocd-redis:6379
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-repo-server
ports:
@@ -2677,7 +2678,7 @@ spec:
- argocd-server
- --staticassets
- /shared/app
image: argoproj/argocd:v1.7.2
image: argoproj/argocd:v1.7.3
imagePullPolicy: Always
name: argocd-server
ports:

View File

@@ -1898,140 +1898,142 @@ func init() {
}
var fileDescriptor_df6e82b174b5eaec = []byte{
// 2121 bytes of a gzipped FileDescriptorProto
// 2146 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xcd, 0x6f, 0x1c, 0x49,
0x15, 0xa7, 0xc6, 0x63, 0xcf, 0xf8, 0x39, 0xbb, 0xc9, 0xd6, 0x6e, 0x42, 0x6f, 0x67, 0xe2, 0x8c,
0x2a, 0x89, 0xe3, 0x38, 0x71, 0x4f, 0x6c, 0x02, 0x2c, 0x06, 0x29, 0xc4, 0x9b, 0xe0, 0x18, 0x9c,
0x60, 0xda, 0x09, 0x2b, 0x21, 0x21, 0xd4, 0xdb, 0x5d, 0x1e, 0x37, 0x9e, 0xe9, 0x6e, 0xba, 0x7b,
0x26, 0x1a, 0xa2, 0x1c, 0x58, 0x24, 0xc4, 0x01, 0x81, 0x10, 0x1c, 0x00, 0xf1, 0xb1, 0x82, 0x2b,
0x37, 0xe0, 0xc2, 0x61, 0x6f, 0xa0, 0x1c, 0x11, 0xbb, 0xe7, 0x08, 0x59, 0xfc, 0x01, 0x9c, 0x38,
0xa3, 0xaa, 0xae, 0xea, 0xae, 0x9e, 0xf4, 0xf4, 0x4c, 0xd6, 0xc3, 0x21, 0xb7, 0xa9, 0x57, 0xd5,
0xef, 0xfd, 0xde, 0x47, 0xfd, 0xaa, 0xea, 0x69, 0xe0, 0x62, 0x44, 0xc3, 0x3e, 0x0d, 0x5b, 0x56,
0x10, 0x74, 0x5c, 0xdb, 0x8a, 0x5d, 0xdf, 0x53, 0x7f, 0x1b, 0x41, 0xe8, 0xc7, 0x3e, 0x5e, 0x50,
0x44, 0xfa, 0x1b, 0x6d, 0xbf, 0xed, 0x73, 0x79, 0x8b, 0xfd, 0x4a, 0x96, 0xe8, 0x8d, 0xb6, 0xef,
0xb7, 0x3b, 0xb4, 0x65, 0x05, 0x6e, 0xcb, 0xf2, 0x3c, 0x3f, 0xe6, 0x8b, 0x23, 0x31, 0x4b, 0x0e,
0xdf, 0x8a, 0x0c, 0xd7, 0xe7, 0xb3, 0xb6, 0x1f, 0xd2, 0x56, 0x7f, 0xad, 0xd5, 0xa6, 0x1e, 0x0d,
0xad, 0x98, 0x3a, 0x62, 0xcd, 0x8d, 0x6c, 0x4d, 0xd7, 0xb2, 0x0f, 0x5c, 0x8f, 0x86, 0x83, 0x56,
0x70, 0xd8, 0x66, 0x82, 0xa8, 0xd5, 0xa5, 0xb1, 0x55, 0xf4, 0xd5, 0x76, 0xdb, 0x8d, 0x0f, 0x7a,
0xef, 0x1a, 0xb6, 0xdf, 0x6d, 0x59, 0x21, 0x07, 0xf6, 0x6d, 0xfe, 0x63, 0xd5, 0x76, 0xb2, 0xaf,
0x55, 0xf7, 0xfa, 0x6b, 0x56, 0x27, 0x38, 0xb0, 0x9e, 0x57, 0xb5, 0x59, 0xa6, 0x2a, 0xa4, 0x81,
0x2f, 0x62, 0xc5, 0x7f, 0xba, 0xb1, 0x1f, 0x0e, 0x94, 0x9f, 0x89, 0x0e, 0xf2, 0x57, 0x04, 0xa7,
0x6e, 0x65, 0xc6, 0xbe, 0xd6, 0xa3, 0xe1, 0x00, 0x63, 0xa8, 0x7a, 0x56, 0x97, 0x6a, 0xa8, 0x89,
0x96, 0xe7, 0x4d, 0xfe, 0x1b, 0x6b, 0x50, 0x0b, 0xe9, 0x7e, 0x48, 0xa3, 0x03, 0xad, 0xc2, 0xc5,
0x72, 0x88, 0x97, 0xa0, 0xc6, 0x2c, 0x53, 0x3b, 0xd6, 0x66, 0x9a, 0x33, 0xcb, 0xf3, 0x9b, 0x27,
0x8e, 0x9e, 0x9d, 0xaf, 0xef, 0x26, 0xa2, 0xc8, 0x94, 0x93, 0xd8, 0x80, 0x93, 0x21, 0x8d, 0xfc,
0x5e, 0x68, 0xd3, 0xaf, 0xd3, 0x30, 0x72, 0x7d, 0x4f, 0xab, 0x32, 0x4d, 0x9b, 0xd5, 0xa7, 0xcf,
0xce, 0x7f, 0xc2, 0x1c, 0x9e, 0xc4, 0x4d, 0xa8, 0x47, 0xb4, 0x43, 0xed, 0xd8, 0x0f, 0xb5, 0x59,
0x65, 0x61, 0x2a, 0x25, 0x5b, 0x70, 0xda, 0xa4, 0x7d, 0x97, 0xad, 0xbe, 0x47, 0x63, 0xcb, 0xb1,
0x62, 0x6b, 0xd8, 0x81, 0x4a, 0xea, 0x80, 0x0e, 0xf5, 0x50, 0x2c, 0xd6, 0x2a, 0x5c, 0x9e, 0x8e,
0x59, 0x14, 0x16, 0x95, 0x28, 0x98, 0x02, 0xc9, 0x9d, 0x3e, 0xf5, 0xe2, 0x68, 0xb4, 0xca, 0x75,
0x78, 0x4d, 0x82, 0xbe, 0x6f, 0x75, 0x69, 0x14, 0x58, 0x36, 0x4d, 0x74, 0x0b, 0xa8, 0xcf, 0x4f,
0xe3, 0x65, 0x38, 0xa1, 0x0a, 0xb5, 0x19, 0x65, 0x79, 0x6e, 0x06, 0x2f, 0xc1, 0x82, 0x1c, 0x3f,
0xdc, 0xbe, 0xad, 0x55, 0x95, 0x85, 0xea, 0x04, 0xd9, 0x05, 0x4d, 0xc1, 0x7e, 0xcf, 0xf2, 0xdc,
0x7d, 0x1a, 0xc5, 0xa3, 0x51, 0x37, 0x73, 0x81, 0x50, 0xe2, 0x9a, 0x86, 0xe3, 0x34, 0xbc, 0x9e,
0x8f, 0x46, 0xe0, 0x7b, 0x11, 0x25, 0x1f, 0xa0, 0x9c, 0xa5, 0xb7, 0x43, 0x6a, 0xc5, 0xd4, 0xa4,
0xdf, 0xe9, 0xd1, 0x28, 0xc6, 0x1e, 0xa8, 0x9b, 0x8e, 0x1b, 0x5c, 0x58, 0xff, 0x92, 0x91, 0x95,
0xa8, 0x21, 0x4b, 0x94, 0xff, 0xf8, 0x96, 0xed, 0x18, 0xc1, 0x61, 0xdb, 0x60, 0xd5, 0x6e, 0xa8,
0x1b, 0x58, 0x56, 0xbb, 0xa1, 0x58, 0x92, 0x5e, 0x2b, 0xeb, 0xf0, 0x19, 0x98, 0xeb, 0x05, 0x11,
0x0d, 0x63, 0xee, 0x43, 0xdd, 0x14, 0x23, 0x96, 0xe6, 0xbe, 0xd5, 0x71, 0x1d, 0x2b, 0x66, 0xb1,
0x65, 0x33, 0xe9, 0x98, 0xbc, 0x9f, 0x77, 0xe0, 0x61, 0xe0, 0x28, 0x0e, 0x1c, 0xfc, 0x1f, 0x1d,
0xc8, 0x43, 0x57, 0x21, 0x56, 0x86, 0x20, 0xde, 0xcd, 0x21, 0xbc, 0x4d, 0x3b, 0x34, 0x43, 0x58,
0x94, 0x4c, 0x0d, 0x6a, 0xb6, 0x15, 0xd9, 0x96, 0x23, 0x55, 0xc9, 0x21, 0x79, 0x5a, 0x85, 0x33,
0x8a, 0xaa, 0xbd, 0x81, 0x67, 0x97, 0x29, 0x1a, 0x5b, 0x15, 0xb8, 0x01, 0x73, 0x4e, 0x38, 0x30,
0x7b, 0x5e, 0x12, 0x57, 0x31, 0x2f, 0x64, 0x58, 0x87, 0xd9, 0x20, 0xec, 0x79, 0x94, 0xef, 0x69,
0x39, 0x99, 0x88, 0xb0, 0x0d, 0xf5, 0x28, 0x66, 0xcc, 0xd5, 0x1e, 0xf0, 0x9d, 0xbc, 0xb0, 0xbe,
0x75, 0x8c, 0xb8, 0x32, 0x4f, 0xf6, 0x84, 0x3a, 0x33, 0x55, 0x8c, 0x63, 0x98, 0x97, 0xbb, 0x22,
0xd2, 0x6a, 0xcd, 0x99, 0xe5, 0x85, 0xf5, 0xdd, 0x63, 0x5a, 0xf9, 0x6a, 0xc0, 0xf8, 0x56, 0x21,
0x04, 0xe1, 0x56, 0x66, 0x08, 0x37, 0x60, 0xbe, 0x2b, 0x76, 0x5c, 0xa4, 0xd5, 0x19, 0xfd, 0x99,
0x99, 0x00, 0x3f, 0x84, 0x59, 0xd7, 0xdb, 0xf7, 0x23, 0x6d, 0x9e, 0xe3, 0xb9, 0x79, 0x0c, 0x3c,
0xdb, 0xde, 0xbe, 0x6f, 0x26, 0xda, 0xb0, 0x07, 0xaf, 0x84, 0x34, 0x0e, 0x07, 0x32, 0x0a, 0x1a,
0xf0, 0xa0, 0xde, 0x3d, 0x86, 0x7a, 0x53, 0xd5, 0x67, 0xe6, 0xd5, 0x93, 0x3f, 0x23, 0x68, 0x3c,
0xb7, 0x6f, 0xf6, 0x02, 0x5a, 0x5a, 0x50, 0x0e, 0x54, 0xa3, 0x80, 0xda, 0x9c, 0x0f, 0x17, 0xd6,
0xbf, 0x3c, 0x9d, 0x8d, 0xc4, 0x8c, 0x8a, 0x24, 0x70, 0xed, 0xa5, 0xdb, 0xbd, 0x0b, 0x9f, 0x54,
0x3e, 0xdd, 0xb5, 0x62, 0xfb, 0xa0, 0x0c, 0x30, 0xab, 0x60, 0xb6, 0x26, 0xc7, 0xe0, 0x89, 0x08,
0x13, 0x98, 0xe7, 0x3f, 0x1e, 0x0c, 0x82, 0x3c, 0x65, 0x67, 0x62, 0xf2, 0x03, 0x04, 0xba, 0xba,
0xe7, 0xfd, 0x4e, 0xe7, 0x5d, 0xcb, 0x3e, 0x2c, 0x37, 0x59, 0x71, 0x1d, 0x6e, 0x6f, 0x66, 0x13,
0x98, 0xbe, 0xa3, 0x67, 0xe7, 0x2b, 0xdb, 0xb7, 0xcd, 0x8a, 0xeb, 0x7c, 0xfc, 0xed, 0x46, 0x3e,
0x1a, 0x02, 0x22, 0x8a, 0xb5, 0x0c, 0x08, 0x81, 0x79, 0xaf, 0xf0, 0x04, 0xcb, 0xc4, 0x2f, 0x70,
0x72, 0x2d, 0x42, 0xad, 0x9f, 0x9e, 0xf0, 0xd9, 0x22, 0x29, 0x64, 0xe0, 0xdb, 0xa1, 0xdf, 0x0b,
0xb4, 0x59, 0x35, 0xd2, 0x5c, 0x84, 0x35, 0xa8, 0x1e, 0xba, 0x9e, 0xa3, 0xcd, 0x29, 0x53, 0x5c,
0x42, 0x7e, 0x59, 0x81, 0xf3, 0x05, 0x6e, 0x8d, 0xcd, 0xeb, 0x4b, 0xe0, 0x5b, 0x56, 0x7b, 0xb5,
0x31, 0xb5, 0x57, 0x2f, 0xae, 0xbd, 0xff, 0x22, 0x68, 0x16, 0xc4, 0x66, 0xfc, 0xf9, 0xf1, 0x92,
0x04, 0x67, 0xdf, 0x0f, 0x6d, 0xaa, 0xd5, 0xd2, 0x5a, 0x47, 0x66, 0x22, 0x22, 0xff, 0x41, 0xa0,
0x49, 0x6f, 0x6f, 0xd9, 0xdc, 0xf7, 0x9e, 0xf7, 0xb2, 0x3b, 0xdc, 0x80, 0x39, 0x8b, 0xfb, 0x92,
0x2b, 0x07, 0x21, 0x23, 0x3f, 0x44, 0x70, 0x36, 0xef, 0x72, 0xb4, 0xe3, 0x46, 0xb1, 0xbc, 0xa6,
0x61, 0x17, 0x6a, 0xc9, 0xca, 0x48, 0x43, 0xfc, 0xd8, 0xd9, 0x3e, 0xd6, 0xb9, 0xa0, 0x1a, 0x92,
0xee, 0x09, 0xfd, 0xe4, 0x26, 0x9c, 0x2d, 0x24, 0x1a, 0x81, 0xa4, 0x09, 0x75, 0x79, 0x16, 0x26,
0x39, 0x90, 0x77, 0x0a, 0x29, 0x25, 0x7f, 0xab, 0xe4, 0x39, 0xda, 0x77, 0x76, 0xfc, 0x76, 0xc9,
0x8d, 0x7b, 0x92, 0xec, 0x69, 0x50, 0x0b, 0x7c, 0x27, 0x4b, 0x9c, 0x29, 0x87, 0xec, 0x6b, 0xdb,
0xf7, 0x62, 0x8b, 0x3d, 0xd5, 0x72, 0xf9, 0xca, 0xc4, 0x2c, 0xf7, 0x91, 0xeb, 0xd9, 0x74, 0x8f,
0xda, 0xbe, 0xe7, 0x44, 0x3c, 0x71, 0x33, 0x32, 0xf7, 0xea, 0x0c, 0xbe, 0x0b, 0xf3, 0x7c, 0xfc,
0xc0, 0xed, 0x52, 0x6d, 0x8e, 0x9f, 0xc0, 0x2b, 0x46, 0xf2, 0x26, 0x34, 0xd4, 0x37, 0x61, 0x16,
0x61, 0xf6, 0x26, 0x34, 0xfa, 0x6b, 0x06, 0xfb, 0xc2, 0xcc, 0x3e, 0x66, 0xb8, 0x62, 0xcb, 0xed,
0xec, 0xb8, 0x1e, 0xbf, 0xba, 0x64, 0x06, 0x33, 0x31, 0xab, 0x89, 0x7d, 0xbf, 0xd3, 0xf1, 0x1f,
0x71, 0x0a, 0x48, 0x8f, 0x83, 0x44, 0x46, 0xbe, 0x0b, 0xf5, 0x1d, 0xbf, 0x7d, 0xc7, 0x8b, 0xc3,
0x01, 0xab, 0x49, 0xe6, 0x0e, 0xf5, 0xf2, 0x41, 0x97, 0x42, 0x7c, 0x1f, 0xe6, 0x63, 0xb7, 0x4b,
0xf7, 0x62, 0xab, 0x1b, 0x88, 0xd3, 0xf9, 0x05, 0x70, 0xa7, 0xc8, 0xa4, 0x0a, 0xd2, 0x82, 0x37,
0xd3, 0x8b, 0xd2, 0x03, 0x1a, 0x76, 0x5d, 0xcf, 0x2a, 0xe5, 0x1c, 0xb2, 0x96, 0xab, 0x1a, 0x76,
0xd1, 0x7a, 0xc7, 0xf5, 0x1c, 0xff, 0xd1, 0xe8, 0xbc, 0x93, 0x7f, 0xe6, 0x1f, 0x68, 0xca, 0x37,
0x69, 0xb1, 0xdd, 0x85, 0x57, 0x58, 0x59, 0xf6, 0xa9, 0x98, 0x10, 0xc5, 0x4f, 0x72, 0x75, 0x5d,
0xa8, 0xc3, 0xcc, 0x7f, 0x88, 0x77, 0xe0, 0xa4, 0x15, 0x45, 0x6e, 0xdb, 0xa3, 0x8e, 0xd4, 0x55,
0x99, 0x58, 0xd7, 0xf0, 0xa7, 0xc9, 0x0d, 0x9d, 0xaf, 0xe0, 0xe5, 0xc8, 0x6f, 0xe8, 0x7c, 0x48,
0xbe, 0x8f, 0xe0, 0x74, 0xa1, 0x12, 0x16, 0x02, 0x4e, 0x0d, 0x22, 0x04, 0x82, 0x05, 0xeb, 0x91,
0x7d, 0x40, 0x9d, 0x5e, 0x87, 0xca, 0xf7, 0xab, 0x1c, 0xb3, 0x39, 0xa7, 0x97, 0x64, 0x40, 0xd4,
0x7c, 0x3a, 0xc6, 0x8b, 0x00, 0x5d, 0xcb, 0xeb, 0x59, 0x1d, 0x0e, 0xa1, 0xca, 0x21, 0x28, 0x12,
0xd2, 0x00, 0xbd, 0x28, 0x7d, 0xe2, 0xcd, 0xf7, 0x11, 0x82, 0x57, 0xe5, 0xbe, 0x16, 0xf9, 0x31,
0xe0, 0xa4, 0x12, 0x86, 0xfb, 0x69, 0xaa, 0x04, 0x31, 0x0f, 0x4f, 0x0e, 0xef, 0x59, 0x54, 0xbc,
0x67, 0x93, 0x9c, 0xcf, 0x28, 0xd3, 0xc9, 0x8e, 0xcf, 0x31, 0x2c, 0x2a, 0x65, 0x58, 0x34, 0x9a,
0x61, 0xd1, 0xd0, 0x5d, 0x62, 0x00, 0xda, 0x3d, 0xcb, 0xb3, 0xda, 0xd4, 0x49, 0x9d, 0x4b, 0x0b,
0xe9, 0x9b, 0x30, 0xeb, 0xc6, 0xb4, 0x2b, 0x0b, 0x68, 0x6b, 0x0a, 0xec, 0x79, 0xdb, 0xdd, 0xdf,
0x37, 0x13, 0xad, 0xeb, 0x1f, 0x36, 0x00, 0xab, 0x59, 0xa7, 0x61, 0xdf, 0xb5, 0x29, 0xfe, 0x09,
0x82, 0x2a, 0xa3, 0x71, 0x7c, 0x6e, 0x54, 0x91, 0xf1, 0xe8, 0xeb, 0x53, 0xba, 0x48, 0x33, 0x53,
0xa4, 0xf1, 0xde, 0x87, 0xff, 0xfe, 0x59, 0xe5, 0x0c, 0x7e, 0x83, 0xf7, 0xb9, 0xfa, 0x6b, 0x6a,
0xdb, 0x29, 0xc2, 0x3f, 0x42, 0x80, 0xc5, 0xc1, 0xa2, 0x74, 0x43, 0xf0, 0xd5, 0x51, 0xf8, 0x0a,
0xba, 0x26, 0xfa, 0x39, 0x85, 0x58, 0x0c, 0xdb, 0x0f, 0x29, 0xa3, 0x11, 0xbe, 0x80, 0x03, 0x58,
0xe1, 0x00, 0x2e, 0x62, 0x52, 0x04, 0xa0, 0xf5, 0x98, 0x15, 0xc0, 0x93, 0x16, 0x4d, 0xec, 0xfe,
0x0e, 0xc1, 0xec, 0x3b, 0xfc, 0x42, 0x34, 0x26, 0x42, 0xbb, 0xd3, 0x89, 0x10, 0xb7, 0xc5, 0xa1,
0x92, 0x0b, 0x1c, 0xe6, 0x39, 0x7c, 0x56, 0xc2, 0x8c, 0xe2, 0x90, 0x5a, 0xdd, 0x1c, 0xda, 0xeb,
0x08, 0xff, 0x1e, 0xc1, 0x5c, 0xd2, 0x14, 0xc1, 0x97, 0x46, 0x41, 0xcc, 0x35, 0x4d, 0xf4, 0x29,
0xb5, 0x17, 0xc8, 0x15, 0x0e, 0xf0, 0x02, 0x29, 0x4c, 0xe4, 0x46, 0xae, 0xf9, 0xf0, 0x53, 0x04,
0x33, 0x5b, 0x74, 0x6c, 0x99, 0x4d, 0x0b, 0xd9, 0x73, 0xa1, 0x2b, 0xc8, 0x30, 0xfe, 0x03, 0x82,
0x37, 0xb7, 0x68, 0x5c, 0x4c, 0xf0, 0x78, 0x79, 0x3c, 0xeb, 0x8a, 0x6a, 0xbb, 0x3a, 0xc1, 0xca,
0x94, 0xd9, 0x5a, 0x1c, 0xd9, 0x15, 0x7c, 0xb9, 0xac, 0xf6, 0xa2, 0x81, 0x67, 0x3f, 0x12, 0x38,
0xfe, 0x8e, 0xe0, 0xd4, 0x70, 0xbb, 0x11, 0xe7, 0x8f, 0x84, 0xc2, 0x6e, 0xa4, 0xfe, 0x95, 0x63,
0x31, 0x48, 0x5e, 0x23, 0xb9, 0xc5, 0x61, 0x7f, 0x1e, 0x7f, 0xae, 0x0c, 0xb6, 0xec, 0xd9, 0x44,
0xad, 0xc7, 0xf2, 0xe7, 0x13, 0xde, 0x91, 0xe6, 0x98, 0xdf, 0x43, 0x70, 0x62, 0x8b, 0xc6, 0xf7,
0xd2, 0x36, 0xc5, 0xc8, 0x6a, 0xcd, 0x35, 0x13, 0xf5, 0x86, 0xa1, 0xb4, 0x8f, 0xe5, 0x54, 0x1a,
0xcf, 0x55, 0x0e, 0xec, 0x32, 0xbe, 0x54, 0x06, 0x2c, 0x6b, 0x8d, 0x7c, 0x80, 0x60, 0x2e, 0x69,
0x24, 0x8c, 0x36, 0x9f, 0x6b, 0xd0, 0x4d, 0xad, 0x24, 0xef, 0x70, 0xa0, 0x37, 0xf5, 0xeb, 0xc5,
0x40, 0xd5, 0xef, 0x65, 0xc8, 0x0c, 0x8e, 0x3e, 0xbf, 0x91, 0xfe, 0x84, 0x00, 0xb2, 0x4e, 0x08,
0xbe, 0x52, 0xee, 0x84, 0xd2, 0x2d, 0xd1, 0xa7, 0xd8, 0x0b, 0x21, 0x06, 0x77, 0x66, 0x59, 0x6f,
0x96, 0x56, 0x71, 0x40, 0xed, 0x8d, 0xa4, 0x5f, 0xf2, 0x1b, 0x04, 0xb3, 0xfc, 0xc5, 0x8c, 0x2f,
0x8e, 0x02, 0xac, 0x3e, 0xa8, 0xa7, 0x16, 0xf4, 0x25, 0x8e, 0xb3, 0xb9, 0x5e, 0xc6, 0x03, 0x1b,
0x68, 0x05, 0xf7, 0x61, 0x2e, 0x79, 0xb4, 0x8e, 0xae, 0x8a, 0xdc, 0xa3, 0x56, 0x6f, 0x96, 0x1c,
0x47, 0x49, 0x61, 0x0a, 0x0a, 0x5a, 0x29, 0xa5, 0xa0, 0xf7, 0x11, 0x54, 0x19, 0x4b, 0xe0, 0x0b,
0x65, 0x1c, 0x32, 0xed, 0xa8, 0x5c, 0xe5, 0xd0, 0x2e, 0x91, 0xe6, 0x38, 0x0e, 0x62, 0xa1, 0xf9,
0x05, 0x82, 0x53, 0xc3, 0x97, 0x16, 0x7c, 0x76, 0x88, 0x7f, 0xd4, 0x9b, 0x9a, 0x9e, 0x0f, 0xe1,
0xa8, 0x0b, 0x0f, 0xf9, 0x22, 0x47, 0xb1, 0x81, 0xdf, 0x1a, 0xbb, 0x21, 0xee, 0xcb, 0x4d, 0xcc,
0x14, 0xad, 0x66, 0x5d, 0xd0, 0xbf, 0x20, 0x38, 0x21, 0xf5, 0x3e, 0x08, 0x29, 0x2d, 0x87, 0x35,
0xa5, 0xfa, 0x67, 0x86, 0xc8, 0x17, 0x38, 0xf6, 0xcf, 0xe0, 0x1b, 0x13, 0x62, 0x97, 0x98, 0x57,
0x63, 0x06, 0xf3, 0x8f, 0x08, 0xea, 0xb2, 0x4f, 0x87, 0x2f, 0x8f, 0xac, 0xa4, 0x7c, 0x27, 0x6f,
0x6a, 0xd9, 0x17, 0x27, 0x10, 0xb9, 0x58, 0x4a, 0xe5, 0xc2, 0x38, 0xab, 0x80, 0x9f, 0x23, 0xc0,
0xe9, 0x15, 0x3d, 0xbd, 0xb4, 0xe3, 0xa5, 0x9c, 0xa9, 0x91, 0x6f, 0x31, 0xfd, 0xf2, 0xd8, 0x75,
0x79, 0x2a, 0x5f, 0x29, 0xa5, 0x72, 0x3f, 0xb5, 0xff, 0x63, 0x04, 0x0b, 0x5b, 0x34, 0xbd, 0x27,
0x96, 0x04, 0x32, 0xdf, 0x89, 0xd4, 0x97, 0xc7, 0x2f, 0x14, 0x88, 0xae, 0x71, 0x44, 0x4b, 0xb8,
0x3c, 0x54, 0x12, 0xc0, 0xaf, 0x11, 0xbc, 0x22, 0x58, 0x4c, 0x48, 0xae, 0x8d, 0xb3, 0x94, 0x23,
0xbd, 0xc9, 0x71, 0x7d, 0x8a, 0xe3, 0x5a, 0x25, 0x13, 0xe1, 0xda, 0x10, 0x0d, 0xbd, 0xdf, 0x22,
0x78, 0x5d, 0xbd, 0x58, 0x8b, 0x26, 0xce, 0xc7, 0x8d, 0x5b, 0x49, 0x2f, 0x88, 0xdc, 0xe0, 0xf8,
0x0c, 0x7c, 0x6d, 0x12, 0x7c, 0x2d, 0xd1, 0xd6, 0xc1, 0xbf, 0x42, 0xf0, 0x1a, 0x6f, 0xa3, 0xa9,
0x8a, 0x87, 0x08, 0x79, 0x54, 0xd3, 0x6d, 0x02, 0x42, 0x16, 0x7b, 0x96, 0xbc, 0x10, 0xa8, 0x0d,
0xd1, 0xfe, 0x62, 0x0f, 0xa5, 0x57, 0xe5, 0x11, 0x20, 0xb2, 0xbb, 0x3a, 0x2e, 0x70, 0x2f, 0x7a,
0x64, 0x88, 0x72, 0x5b, 0x99, 0xac, 0xdc, 0xbe, 0x87, 0xa0, 0x26, 0x3a, 0x57, 0x25, 0xa7, 0xaa,
0xd2, 0xda, 0xd2, 0x4f, 0xe7, 0x56, 0xc9, 0xce, 0x0d, 0xf9, 0x2c, 0x37, 0xbb, 0x86, 0x5b, 0x65,
0x66, 0x03, 0xdf, 0x89, 0x5a, 0x8f, 0x45, 0x4b, 0xeb, 0x49, 0xab, 0xe3, 0xb7, 0xa3, 0xeb, 0x68,
0xf3, 0xed, 0xa7, 0x47, 0x8b, 0xe8, 0x1f, 0x47, 0x8b, 0xe8, 0x5f, 0x47, 0x8b, 0xe8, 0x1b, 0x9f,
0x9e, 0xe0, 0x4f, 0x06, 0x76, 0xc7, 0xa5, 0x5e, 0xac, 0x9a, 0xf8, 0x5f, 0x00, 0x00, 0x00, 0xff,
0xff, 0x00, 0x68, 0x8b, 0x98, 0x5d, 0x21, 0x00, 0x00,
0x15, 0xa7, 0xc6, 0x63, 0xcf, 0xf8, 0x39, 0xd9, 0x24, 0xb5, 0x9b, 0xd0, 0xdb, 0x71, 0x9c, 0x51,
0xe5, 0xcb, 0x71, 0xe2, 0x9e, 0xd8, 0x04, 0x58, 0xbc, 0xa0, 0x10, 0x27, 0xc1, 0x31, 0x38, 0xc1,
0xb4, 0x13, 0x22, 0x21, 0x21, 0xd4, 0xdb, 0x5d, 0x1e, 0x37, 0x9e, 0xe9, 0x6e, 0xba, 0x7b, 0x26,
0x1a, 0xa2, 0x1c, 0x58, 0x24, 0xc4, 0x01, 0x81, 0x10, 0x1c, 0x58, 0xc4, 0xc7, 0x0a, 0xae, 0xdc,
0x80, 0x0b, 0x87, 0xbd, 0x20, 0x50, 0x8e, 0x08, 0xf6, 0x1c, 0x21, 0x8b, 0x3f, 0x80, 0x13, 0x67,
0x54, 0xd5, 0x55, 0xdd, 0xd5, 0x93, 0x9e, 0x9e, 0xc9, 0x7a, 0x10, 0xca, 0x6d, 0xea, 0x55, 0xf5,
0x7b, 0xbf, 0xf7, 0xea, 0x57, 0xef, 0x55, 0x3d, 0x0d, 0x9c, 0x8f, 0x68, 0xd8, 0xa3, 0x61, 0xd3,
0x0a, 0x82, 0xb6, 0x6b, 0x5b, 0xb1, 0xeb, 0x7b, 0xea, 0x6f, 0x23, 0x08, 0xfd, 0xd8, 0xc7, 0x73,
0x8a, 0x48, 0x7f, 0xa3, 0xe5, 0xb7, 0x7c, 0x2e, 0x6f, 0xb2, 0x5f, 0xc9, 0x12, 0x7d, 0xbe, 0xe5,
0xfb, 0xad, 0x36, 0x6d, 0x5a, 0x81, 0xdb, 0xb4, 0x3c, 0xcf, 0x8f, 0xf9, 0xe2, 0x48, 0xcc, 0x92,
0xfd, 0xb7, 0x22, 0xc3, 0xf5, 0xf9, 0xac, 0xed, 0x87, 0xb4, 0xd9, 0x5b, 0x69, 0xb6, 0xa8, 0x47,
0x43, 0x2b, 0xa6, 0x8e, 0x58, 0x73, 0x3d, 0x5b, 0xd3, 0xb1, 0xec, 0x3d, 0xd7, 0xa3, 0x61, 0xbf,
0x19, 0xec, 0xb7, 0x98, 0x20, 0x6a, 0x76, 0x68, 0x6c, 0x15, 0x7d, 0xb5, 0xd9, 0x72, 0xe3, 0xbd,
0xee, 0x3b, 0x86, 0xed, 0x77, 0x9a, 0x56, 0xc8, 0x81, 0x7d, 0x93, 0xff, 0x58, 0xb6, 0x9d, 0xec,
0x6b, 0xd5, 0xbd, 0xde, 0x8a, 0xd5, 0x0e, 0xf6, 0xac, 0x17, 0x55, 0xad, 0x97, 0xa9, 0x0a, 0x69,
0xe0, 0x8b, 0x58, 0xf1, 0x9f, 0x6e, 0xec, 0x87, 0x7d, 0xe5, 0x67, 0xa2, 0x83, 0xfc, 0x09, 0xc1,
0xf1, 0x9b, 0x99, 0xb1, 0xaf, 0x74, 0x69, 0xd8, 0xc7, 0x18, 0xaa, 0x9e, 0xd5, 0xa1, 0x1a, 0x6a,
0xa0, 0xc5, 0x59, 0x93, 0xff, 0xc6, 0x1a, 0xd4, 0x42, 0xba, 0x1b, 0xd2, 0x68, 0x4f, 0xab, 0x70,
0xb1, 0x1c, 0xe2, 0x8b, 0x50, 0x63, 0x96, 0xa9, 0x1d, 0x6b, 0x53, 0x8d, 0xa9, 0xc5, 0xd9, 0xf5,
0x23, 0x07, 0xcf, 0xcf, 0xd6, 0xb7, 0x13, 0x51, 0x64, 0xca, 0x49, 0x6c, 0xc0, 0xb1, 0x90, 0x46,
0x7e, 0x37, 0xb4, 0xe9, 0x57, 0x69, 0x18, 0xb9, 0xbe, 0xa7, 0x55, 0x99, 0xa6, 0xf5, 0xea, 0xb3,
0xe7, 0x67, 0x3f, 0x66, 0x0e, 0x4e, 0xe2, 0x06, 0xd4, 0x23, 0xda, 0xa6, 0x76, 0xec, 0x87, 0xda,
0xb4, 0xb2, 0x30, 0x95, 0x92, 0x0d, 0x38, 0x69, 0xd2, 0x9e, 0xcb, 0x56, 0xdf, 0xa3, 0xb1, 0xe5,
0x58, 0xb1, 0x35, 0xe8, 0x40, 0x25, 0x75, 0x40, 0x87, 0x7a, 0x28, 0x16, 0x6b, 0x15, 0x2e, 0x4f,
0xc7, 0x2c, 0x0a, 0x0b, 0x4a, 0x14, 0x4c, 0x81, 0xe4, 0x4e, 0x8f, 0x7a, 0x71, 0x34, 0x5c, 0xe5,
0x2a, 0x9c, 0x90, 0xa0, 0xef, 0x5b, 0x1d, 0x1a, 0x05, 0x96, 0x4d, 0x13, 0xdd, 0x02, 0xea, 0x8b,
0xd3, 0x78, 0x11, 0x8e, 0xa8, 0x42, 0x6d, 0x4a, 0x59, 0x9e, 0x9b, 0xc1, 0x17, 0x61, 0x4e, 0x8e,
0x1f, 0x6e, 0xde, 0xd6, 0xaa, 0xca, 0x42, 0x75, 0x82, 0x6c, 0x83, 0xa6, 0x60, 0xbf, 0x67, 0x79,
0xee, 0x2e, 0x8d, 0xe2, 0xe1, 0xa8, 0x1b, 0xb9, 0x40, 0x28, 0x71, 0x4d, 0xc3, 0x71, 0x12, 0x5e,
0xcf, 0x47, 0x23, 0xf0, 0xbd, 0x88, 0x92, 0x0f, 0x50, 0xce, 0xd2, 0xad, 0x90, 0x5a, 0x31, 0x35,
0xe9, 0xb7, 0xba, 0x34, 0x8a, 0xb1, 0x07, 0xea, 0xa1, 0xe3, 0x06, 0xe7, 0x56, 0xbf, 0x60, 0x64,
0x14, 0x35, 0x24, 0x45, 0xf9, 0x8f, 0x6f, 0xd8, 0x8e, 0x11, 0xec, 0xb7, 0x0c, 0xc6, 0x76, 0x43,
0x3d, 0xc0, 0x92, 0xed, 0x86, 0x62, 0x49, 0x7a, 0xad, 0xac, 0xc3, 0xa7, 0x60, 0xa6, 0x1b, 0x44,
0x34, 0x8c, 0xb9, 0x0f, 0x75, 0x53, 0x8c, 0xd8, 0x36, 0xf7, 0xac, 0xb6, 0xeb, 0x58, 0x31, 0x8b,
0x2d, 0x9b, 0x49, 0xc7, 0xe4, 0xfd, 0xbc, 0x03, 0x0f, 0x03, 0x47, 0x71, 0x60, 0xef, 0x7f, 0xe8,
0x40, 0x1e, 0xba, 0x0a, 0xb1, 0x32, 0x00, 0xf1, 0x6e, 0x0e, 0xe1, 0x6d, 0xda, 0xa6, 0x19, 0xc2,
0xa2, 0xcd, 0xd4, 0xa0, 0x66, 0x5b, 0x91, 0x6d, 0x39, 0x52, 0x95, 0x1c, 0x92, 0x67, 0x55, 0x38,
0xa5, 0xa8, 0xda, 0xe9, 0x7b, 0x76, 0x99, 0xa2, 0x91, 0xac, 0xc0, 0xf3, 0x30, 0xe3, 0x84, 0x7d,
0xb3, 0xeb, 0x25, 0x71, 0x15, 0xf3, 0x42, 0x86, 0x75, 0x98, 0x0e, 0xc2, 0xae, 0x47, 0xf9, 0x99,
0x96, 0x93, 0x89, 0x08, 0xdb, 0x50, 0x8f, 0x62, 0x96, 0xb9, 0x5a, 0x7d, 0x7e, 0x92, 0xe7, 0x56,
0x37, 0x0e, 0x11, 0x57, 0xe6, 0xc9, 0x8e, 0x50, 0x67, 0xa6, 0x8a, 0x71, 0x0c, 0xb3, 0xf2, 0x54,
0x44, 0x5a, 0xad, 0x31, 0xb5, 0x38, 0xb7, 0xba, 0x7d, 0x48, 0x2b, 0x5f, 0x0e, 0x58, 0xbe, 0x55,
0x12, 0x82, 0x70, 0x2b, 0x33, 0x84, 0xe7, 0x61, 0xb6, 0x23, 0x4e, 0x5c, 0xa4, 0xd5, 0x59, 0xfa,
0x33, 0x33, 0x01, 0x7e, 0x08, 0xd3, 0xae, 0xb7, 0xeb, 0x47, 0xda, 0x2c, 0xc7, 0x73, 0xe3, 0x10,
0x78, 0x36, 0xbd, 0x5d, 0xdf, 0x4c, 0xb4, 0x61, 0x0f, 0x8e, 0x86, 0x34, 0x0e, 0xfb, 0x32, 0x0a,
0x1a, 0xf0, 0xa0, 0xde, 0x3d, 0x84, 0x7a, 0x53, 0xd5, 0x67, 0xe6, 0xd5, 0x93, 0x3f, 0x20, 0x98,
0x7f, 0xe1, 0xdc, 0xec, 0x04, 0xb4, 0x94, 0x50, 0x0e, 0x54, 0xa3, 0x80, 0xda, 0x3c, 0x1f, 0xce,
0xad, 0x7e, 0x71, 0x32, 0x07, 0x89, 0x19, 0x15, 0x9b, 0xc0, 0xb5, 0x97, 0x1e, 0xf7, 0x0e, 0x7c,
0x5c, 0xf9, 0x74, 0xdb, 0x8a, 0xed, 0xbd, 0x32, 0xc0, 0x8c, 0xc1, 0x6c, 0x4d, 0x2e, 0x83, 0x27,
0x22, 0x4c, 0x60, 0x96, 0xff, 0x78, 0xd0, 0x0f, 0xf2, 0x29, 0x3b, 0x13, 0x93, 0xef, 0x21, 0xd0,
0xd5, 0x33, 0xef, 0xb7, 0xdb, 0xef, 0x58, 0xf6, 0x7e, 0xb9, 0xc9, 0x8a, 0xeb, 0x70, 0x7b, 0x53,
0xeb, 0xc0, 0xf4, 0x1d, 0x3c, 0x3f, 0x5b, 0xd9, 0xbc, 0x6d, 0x56, 0x5c, 0xe7, 0xa3, 0x1f, 0x37,
0xf2, 0xe1, 0x00, 0x10, 0x41, 0xd6, 0x32, 0x20, 0x04, 0x66, 0xbd, 0xc2, 0x0a, 0x96, 0x89, 0x5f,
0xa2, 0x72, 0x2d, 0x40, 0xad, 0x97, 0x56, 0xf8, 0x6c, 0x91, 0x14, 0x32, 0xf0, 0xad, 0xd0, 0xef,
0x06, 0xda, 0xb4, 0x1a, 0x69, 0x2e, 0xc2, 0x1a, 0x54, 0xf7, 0x5d, 0xcf, 0xd1, 0x66, 0x94, 0x29,
0x2e, 0x21, 0xef, 0x55, 0xe0, 0x6c, 0x81, 0x5b, 0x23, 0xf7, 0xf5, 0x15, 0xf0, 0x2d, 0xe3, 0x5e,
0x6d, 0x04, 0xf7, 0xea, 0xc5, 0xdc, 0xfb, 0x0f, 0x82, 0x46, 0x41, 0x6c, 0x46, 0xd7, 0x8f, 0x57,
0x24, 0x38, 0xbb, 0x7e, 0x68, 0x53, 0xad, 0x96, 0x72, 0x1d, 0x99, 0x89, 0x88, 0xfc, 0x1b, 0x81,
0x26, 0xbd, 0xbd, 0x69, 0x73, 0xdf, 0xbb, 0xde, 0xab, 0xee, 0xf0, 0x3c, 0xcc, 0x58, 0xdc, 0x97,
0x1c, 0x1d, 0x84, 0x8c, 0x7c, 0x1f, 0xc1, 0xe9, 0xbc, 0xcb, 0xd1, 0x96, 0x1b, 0xc5, 0xf2, 0x9a,
0x86, 0x5d, 0xa8, 0x25, 0x2b, 0x23, 0x0d, 0xf1, 0xb2, 0xb3, 0x79, 0xa8, 0xba, 0xa0, 0x1a, 0x92,
0xee, 0x09, 0xfd, 0xe4, 0x06, 0x9c, 0x2e, 0x4c, 0x34, 0x02, 0x49, 0x03, 0xea, 0xb2, 0x16, 0x26,
0x7b, 0x20, 0xef, 0x14, 0x52, 0x4a, 0xfe, 0x52, 0xc9, 0xe7, 0x68, 0xdf, 0xd9, 0xf2, 0x5b, 0x25,
0x37, 0xee, 0x71, 0x76, 0x4f, 0x83, 0x5a, 0xe0, 0x3b, 0xd9, 0xc6, 0x99, 0x72, 0xc8, 0xbe, 0xb6,
0x7d, 0x2f, 0xb6, 0xd8, 0x53, 0x2d, 0xb7, 0x5f, 0x99, 0x98, 0xed, 0x7d, 0xe4, 0x7a, 0x36, 0xdd,
0xa1, 0xb6, 0xef, 0x39, 0x11, 0xdf, 0xb8, 0x29, 0xb9, 0xf7, 0xea, 0x0c, 0xbe, 0x0b, 0xb3, 0x7c,
0xfc, 0xc0, 0xed, 0x50, 0x6d, 0x86, 0x57, 0xe0, 0x25, 0x23, 0x79, 0x13, 0x1a, 0xea, 0x9b, 0x30,
0x8b, 0x30, 0x7b, 0x13, 0x1a, 0xbd, 0x15, 0x83, 0x7d, 0x61, 0x66, 0x1f, 0x33, 0x5c, 0xb1, 0xe5,
0xb6, 0xb7, 0x5c, 0x8f, 0x5f, 0x5d, 0x32, 0x83, 0x99, 0x98, 0x71, 0x62, 0xd7, 0x6f, 0xb7, 0xfd,
0xc7, 0x3c, 0x05, 0xa4, 0xe5, 0x20, 0x91, 0x91, 0x6f, 0x43, 0x7d, 0xcb, 0x6f, 0xdd, 0xf1, 0xe2,
0xb0, 0xcf, 0x38, 0xc9, 0xdc, 0xa1, 0x5e, 0x3e, 0xe8, 0x52, 0x88, 0xef, 0xc3, 0x6c, 0xec, 0x76,
0xe8, 0x4e, 0x6c, 0x75, 0x02, 0x51, 0x9d, 0x5f, 0x02, 0x77, 0x8a, 0x4c, 0xaa, 0x20, 0x4d, 0x78,
0x33, 0xbd, 0x28, 0x3d, 0xa0, 0x61, 0xc7, 0xf5, 0xac, 0xd2, 0x9c, 0x43, 0x56, 0x72, 0xac, 0x61,
0x17, 0xad, 0x47, 0xae, 0xe7, 0xf8, 0x8f, 0x87, 0xef, 0x3b, 0xf9, 0x7b, 0xfe, 0x81, 0xa6, 0x7c,
0x93, 0x92, 0xed, 0x2e, 0x1c, 0x65, 0xb4, 0xec, 0x51, 0x31, 0x21, 0xc8, 0x4f, 0x72, 0xbc, 0x2e,
0xd4, 0x61, 0xe6, 0x3f, 0xc4, 0x5b, 0x70, 0xcc, 0x8a, 0x22, 0xb7, 0xe5, 0x51, 0x47, 0xea, 0xaa,
0x8c, 0xad, 0x6b, 0xf0, 0xd3, 0xe4, 0x86, 0xce, 0x57, 0x70, 0x3a, 0xf2, 0x1b, 0x3a, 0x1f, 0x92,
0xef, 0x22, 0x38, 0x59, 0xa8, 0x84, 0x85, 0x80, 0xa7, 0x06, 0x11, 0x02, 0x91, 0x05, 0xeb, 0x91,
0xbd, 0x47, 0x9d, 0x6e, 0x9b, 0xca, 0xf7, 0xab, 0x1c, 0xb3, 0x39, 0xa7, 0x9b, 0xec, 0x80, 0xe0,
0x7c, 0x3a, 0xc6, 0x0b, 0x00, 0x1d, 0xcb, 0xeb, 0x5a, 0x6d, 0x0e, 0xa1, 0xca, 0x21, 0x28, 0x12,
0x32, 0x0f, 0x7a, 0xd1, 0xf6, 0x89, 0x37, 0xdf, 0x87, 0x08, 0x5e, 0x93, 0xe7, 0x5a, 0xec, 0x8f,
0x01, 0xc7, 0x94, 0x30, 0xdc, 0x4f, 0xb7, 0x4a, 0x24, 0xe6, 0xc1, 0xc9, 0xc1, 0x33, 0x8b, 0x8a,
0xcf, 0x6c, 0xb2, 0xe7, 0x53, 0xca, 0x74, 0x72, 0xe2, 0x73, 0x19, 0x16, 0x95, 0x66, 0x58, 0x34,
0x3c, 0xc3, 0xa2, 0x81, 0xbb, 0x44, 0x1f, 0xb4, 0x7b, 0x96, 0x67, 0xb5, 0xa8, 0x93, 0x3a, 0x97,
0x12, 0xe9, 0xeb, 0x30, 0xed, 0xc6, 0xb4, 0x23, 0x09, 0xb4, 0x31, 0x81, 0xec, 0x79, 0xdb, 0xdd,
0xdd, 0x35, 0x13, 0xad, 0xab, 0xef, 0x2d, 0x00, 0x56, 0x77, 0x9d, 0x86, 0x3d, 0xd7, 0xa6, 0xf8,
0x47, 0x08, 0xaa, 0x2c, 0x8d, 0xe3, 0x33, 0xc3, 0x48, 0xc6, 0xa3, 0xaf, 0x4f, 0xe8, 0x22, 0xcd,
0x4c, 0x91, 0xf9, 0x77, 0xff, 0xf1, 0xaf, 0x9f, 0x54, 0x4e, 0xe1, 0x37, 0x78, 0x9f, 0xab, 0xb7,
0xa2, 0xb6, 0x9d, 0x22, 0xfc, 0x03, 0x04, 0x58, 0x14, 0x16, 0xa5, 0x1b, 0x82, 0xaf, 0x0c, 0xc3,
0x57, 0xd0, 0x35, 0xd1, 0xcf, 0x28, 0x89, 0xc5, 0xb0, 0xfd, 0x90, 0xb2, 0x34, 0xc2, 0x17, 0x70,
0x00, 0x4b, 0x1c, 0xc0, 0x79, 0x4c, 0x8a, 0x00, 0x34, 0x9f, 0x30, 0x02, 0x3c, 0x6d, 0xd2, 0xc4,
0xee, 0xaf, 0x11, 0x4c, 0x3f, 0xe2, 0x17, 0xa2, 0x11, 0x11, 0xda, 0x9e, 0x4c, 0x84, 0xb8, 0x2d,
0x0e, 0x95, 0x9c, 0xe3, 0x30, 0xcf, 0xe0, 0xd3, 0x12, 0x66, 0x14, 0x87, 0xd4, 0xea, 0xe4, 0xd0,
0x5e, 0x43, 0xf8, 0x37, 0x08, 0x66, 0x92, 0xa6, 0x08, 0xbe, 0x30, 0x0c, 0x62, 0xae, 0x69, 0xa2,
0x4f, 0xa8, 0xbd, 0x40, 0x2e, 0x73, 0x80, 0xe7, 0x48, 0xe1, 0x46, 0xae, 0xe5, 0x9a, 0x0f, 0x3f,
0x46, 0x30, 0xb5, 0x41, 0x47, 0xd2, 0x6c, 0x52, 0xc8, 0x5e, 0x08, 0x5d, 0xc1, 0x0e, 0xe3, 0xdf,
0x22, 0x78, 0x73, 0x83, 0xc6, 0xc5, 0x09, 0x1e, 0x2f, 0x8e, 0xce, 0xba, 0x82, 0x6d, 0x57, 0xc6,
0x58, 0x99, 0x66, 0xb6, 0x26, 0x47, 0x76, 0x19, 0x5f, 0x2a, 0xe3, 0x5e, 0xd4, 0xf7, 0xec, 0xc7,
0x02, 0xc7, 0x5f, 0x11, 0x1c, 0x1f, 0x6c, 0x37, 0xe2, 0x7c, 0x49, 0x28, 0xec, 0x46, 0xea, 0x5f,
0x3a, 0x54, 0x06, 0xc9, 0x6b, 0x24, 0x37, 0x39, 0xec, 0xb7, 0xf1, 0x67, 0xca, 0x60, 0xcb, 0x9e,
0x4d, 0xd4, 0x7c, 0x22, 0x7f, 0x3e, 0xe5, 0x1d, 0x69, 0x8e, 0xf9, 0x5d, 0x04, 0x47, 0x36, 0x68,
0x7c, 0x2f, 0x6d, 0x53, 0x0c, 0x65, 0x6b, 0xae, 0x99, 0xa8, 0xcf, 0x1b, 0x4a, 0xfb, 0x58, 0x4e,
0xa5, 0xf1, 0x5c, 0xe6, 0xc0, 0x2e, 0xe1, 0x0b, 0x65, 0xc0, 0xb2, 0xd6, 0xc8, 0x07, 0x08, 0x66,
0x92, 0x46, 0xc2, 0x70, 0xf3, 0xb9, 0x06, 0xdd, 0xc4, 0x28, 0x79, 0x87, 0x03, 0xbd, 0xa1, 0x5f,
0x2b, 0x06, 0xaa, 0x7e, 0x2f, 0x43, 0x66, 0x70, 0xf4, 0xf9, 0x83, 0xf4, 0x7b, 0x04, 0x90, 0x75,
0x42, 0xf0, 0xe5, 0x72, 0x27, 0x94, 0x6e, 0x89, 0x3e, 0xc1, 0x5e, 0x08, 0x31, 0xb8, 0x33, 0x8b,
0x7a, 0xa3, 0x94, 0xc5, 0x01, 0xb5, 0xd7, 0x92, 0x7e, 0xc9, 0x2f, 0x11, 0x4c, 0xf3, 0x17, 0x33,
0x3e, 0x3f, 0x0c, 0xb0, 0xfa, 0xa0, 0x9e, 0x58, 0xd0, 0x2f, 0x72, 0x9c, 0x8d, 0xd5, 0xb2, 0x3c,
0xb0, 0x86, 0x96, 0x70, 0x0f, 0x66, 0x92, 0x47, 0xeb, 0x70, 0x56, 0xe4, 0x1e, 0xb5, 0x7a, 0xa3,
0xa4, 0x1c, 0x25, 0xc4, 0x14, 0x29, 0x68, 0xa9, 0x34, 0x05, 0xbd, 0x8f, 0xa0, 0xca, 0xb2, 0x04,
0x3e, 0x57, 0x96, 0x43, 0x26, 0x1d, 0x95, 0x2b, 0x1c, 0xda, 0x05, 0xd2, 0x18, 0x95, 0x83, 0x58,
0x68, 0x7e, 0x86, 0xe0, 0xf8, 0xe0, 0xa5, 0x05, 0x9f, 0x1e, 0xc8, 0x3f, 0xea, 0x4d, 0x4d, 0xcf,
0x87, 0x70, 0xd8, 0x85, 0x87, 0x7c, 0x9e, 0xa3, 0x58, 0xc3, 0x6f, 0x8d, 0x3c, 0x10, 0xf7, 0xe5,
0x21, 0x66, 0x8a, 0x96, 0xb3, 0x2e, 0xe8, 0x1f, 0x11, 0x1c, 0x91, 0x7a, 0x1f, 0x84, 0x94, 0x96,
0xc3, 0x9a, 0x10, 0xff, 0x99, 0x21, 0xf2, 0x59, 0x8e, 0xfd, 0x53, 0xf8, 0xfa, 0x98, 0xd8, 0x25,
0xe6, 0xe5, 0x98, 0xc1, 0xfc, 0x33, 0x82, 0x13, 0x8f, 0x12, 0xba, 0xff, 0x3f, 0xc0, 0xdf, 0xe2,
0xe0, 0x3f, 0x87, 0xdf, 0x2e, 0xb9, 0x57, 0x8c, 0xf2, 0xe1, 0x1a, 0xc2, 0xbf, 0x43, 0x50, 0x97,
0xdd, 0x46, 0x7c, 0x69, 0xe8, 0x79, 0xc8, 0xf7, 0x23, 0x27, 0xc6, 0x61, 0x51, 0x47, 0xc9, 0xf9,
0xd2, 0x82, 0x24, 0x8c, 0x33, 0x1e, 0xff, 0x14, 0x01, 0x4e, 0x1f, 0x1a, 0xe9, 0xd3, 0x03, 0x5f,
0xcc, 0x99, 0x1a, 0xfa, 0xa2, 0xd4, 0x2f, 0x8d, 0x5c, 0x97, 0x2f, 0x48, 0x4b, 0xa5, 0x05, 0xc9,
0x4f, 0xed, 0xff, 0x10, 0xc1, 0xdc, 0x06, 0x4d, 0x6f, 0xbb, 0x25, 0x81, 0xcc, 0xf7, 0x53, 0xf5,
0xc5, 0xd1, 0x0b, 0x05, 0xa2, 0xab, 0x1c, 0xd1, 0x45, 0x5c, 0x1e, 0x2a, 0x09, 0xe0, 0x17, 0x08,
0x8e, 0x6e, 0xab, 0xe4, 0xc4, 0x57, 0x47, 0x59, 0xca, 0xa5, 0xee, 0xf1, 0x71, 0x7d, 0x82, 0xe3,
0x5a, 0x26, 0x63, 0xe1, 0x5a, 0x13, 0x6d, 0xc9, 0x5f, 0x21, 0x78, 0x5d, 0x7d, 0x1e, 0x88, 0x56,
0xd4, 0x47, 0x8d, 0x5b, 0x49, 0x47, 0x8b, 0x5c, 0xe7, 0xf8, 0x0c, 0x7c, 0x75, 0x1c, 0x7c, 0x4d,
0xd1, 0x9c, 0xc2, 0x3f, 0x47, 0x70, 0x82, 0x37, 0x03, 0x55, 0xc5, 0x03, 0x65, 0x65, 0x58, 0xeb,
0x70, 0x8c, 0xb2, 0x22, 0x32, 0x0f, 0x79, 0x29, 0x50, 0x6b, 0xa2, 0x89, 0xc7, 0x9e, 0x7b, 0xaf,
0xc9, 0x42, 0x26, 0x76, 0x77, 0x79, 0x54, 0xe0, 0x5e, 0xb6, 0xf0, 0x09, 0xba, 0x2d, 0x8d, 0x47,
0xb7, 0xef, 0x20, 0xa8, 0x89, 0xfe, 0x5b, 0xc9, 0xdd, 0x40, 0x69, 0xd0, 0xe9, 0x27, 0x73, 0xab,
0x64, 0xff, 0x89, 0x7c, 0x9a, 0x9b, 0x5d, 0xc1, 0xcd, 0x32, 0xb3, 0x81, 0xef, 0x44, 0xcd, 0x27,
0xa2, 0x31, 0xf7, 0xb4, 0xd9, 0xf6, 0x5b, 0xd1, 0x35, 0xb4, 0x7e, 0xeb, 0xd9, 0xc1, 0x02, 0xfa,
0xdb, 0xc1, 0x02, 0xfa, 0xe7, 0xc1, 0x02, 0xfa, 0xda, 0x27, 0xc7, 0xf8, 0xab, 0x84, 0xdd, 0x76,
0xa9, 0x17, 0xab, 0x26, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x67, 0x2b, 0xcb, 0xbc, 0x23, 0x22,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -2074,6 +2076,8 @@ type ApplicationServiceClient interface {
Sync(ctx context.Context, in *ApplicationSyncRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error)
ManagedResources(ctx context.Context, in *ResourcesQuery, opts ...grpc.CallOption) (*ManagedResourcesResponse, error)
ResourceTree(ctx context.Context, in *ResourcesQuery, opts ...grpc.CallOption) (*v1alpha1.ApplicationTree, error)
// Watch returns stream of application resource tree
WatchResourceTree(ctx context.Context, in *ResourcesQuery, opts ...grpc.CallOption) (ApplicationService_WatchResourceTreeClient, error)
// Rollback syncs an application to its target state
Rollback(ctx context.Context, in *ApplicationRollbackRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error)
// TerminateOperation terminates the currently running operation
@@ -2256,6 +2260,38 @@ func (c *applicationServiceClient) ResourceTree(ctx context.Context, in *Resourc
return out, nil
}
func (c *applicationServiceClient) WatchResourceTree(ctx context.Context, in *ResourcesQuery, opts ...grpc.CallOption) (ApplicationService_WatchResourceTreeClient, error) {
stream, err := c.cc.NewStream(ctx, &_ApplicationService_serviceDesc.Streams[1], "/application.ApplicationService/WatchResourceTree", opts...)
if err != nil {
return nil, err
}
x := &applicationServiceWatchResourceTreeClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type ApplicationService_WatchResourceTreeClient interface {
Recv() (*v1alpha1.ApplicationTree, error)
grpc.ClientStream
}
type applicationServiceWatchResourceTreeClient struct {
grpc.ClientStream
}
func (x *applicationServiceWatchResourceTreeClient) Recv() (*v1alpha1.ApplicationTree, error) {
m := new(v1alpha1.ApplicationTree)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *applicationServiceClient) Rollback(ctx context.Context, in *ApplicationRollbackRequest, opts ...grpc.CallOption) (*v1alpha1.Application, error) {
out := new(v1alpha1.Application)
err := c.cc.Invoke(ctx, "/application.ApplicationService/Rollback", in, out, opts...)
@@ -2320,7 +2356,7 @@ func (c *applicationServiceClient) DeleteResource(ctx context.Context, in *Appli
}
func (c *applicationServiceClient) PodLogs(ctx context.Context, in *ApplicationPodLogsQuery, opts ...grpc.CallOption) (ApplicationService_PodLogsClient, error) {
stream, err := c.cc.NewStream(ctx, &_ApplicationService_serviceDesc.Streams[1], "/application.ApplicationService/PodLogs", opts...)
stream, err := c.cc.NewStream(ctx, &_ApplicationService_serviceDesc.Streams[2], "/application.ApplicationService/PodLogs", opts...)
if err != nil {
return nil, err
}
@@ -2381,6 +2417,8 @@ type ApplicationServiceServer interface {
Sync(context.Context, *ApplicationSyncRequest) (*v1alpha1.Application, error)
ManagedResources(context.Context, *ResourcesQuery) (*ManagedResourcesResponse, error)
ResourceTree(context.Context, *ResourcesQuery) (*v1alpha1.ApplicationTree, error)
// Watch returns stream of application resource tree
WatchResourceTree(*ResourcesQuery, ApplicationService_WatchResourceTreeServer) error
// Rollback syncs an application to its target state
Rollback(context.Context, *ApplicationRollbackRequest) (*v1alpha1.Application, error)
// TerminateOperation terminates the currently running operation
@@ -2446,6 +2484,9 @@ func (*UnimplementedApplicationServiceServer) ManagedResources(ctx context.Conte
func (*UnimplementedApplicationServiceServer) ResourceTree(ctx context.Context, req *ResourcesQuery) (*v1alpha1.ApplicationTree, error) {
return nil, status.Errorf(codes.Unimplemented, "method ResourceTree not implemented")
}
func (*UnimplementedApplicationServiceServer) WatchResourceTree(req *ResourcesQuery, srv ApplicationService_WatchResourceTreeServer) error {
return status.Errorf(codes.Unimplemented, "method WatchResourceTree not implemented")
}
func (*UnimplementedApplicationServiceServer) Rollback(ctx context.Context, req *ApplicationRollbackRequest) (*v1alpha1.Application, error) {
return nil, status.Errorf(codes.Unimplemented, "method Rollback not implemented")
}
@@ -2748,6 +2789,27 @@ func _ApplicationService_ResourceTree_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler)
}
func _ApplicationService_WatchResourceTree_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(ResourcesQuery)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ApplicationServiceServer).WatchResourceTree(m, &applicationServiceWatchResourceTreeServer{stream})
}
type ApplicationService_WatchResourceTreeServer interface {
Send(*v1alpha1.ApplicationTree) error
grpc.ServerStream
}
type applicationServiceWatchResourceTreeServer struct {
grpc.ServerStream
}
func (x *applicationServiceWatchResourceTreeServer) Send(m *v1alpha1.ApplicationTree) error {
return x.ServerStream.SendMsg(m)
}
func _ApplicationService_Rollback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ApplicationRollbackRequest)
if err := dec(in); err != nil {
@@ -2990,6 +3052,11 @@ var _ApplicationService_serviceDesc = grpc.ServiceDesc{
Handler: _ApplicationService_Watch_Handler,
ServerStreams: true,
},
{
StreamName: "WatchResourceTree",
Handler: _ApplicationService_WatchResourceTree_Handler,
ServerStreams: true,
},
{
StreamName: "PodLogs",
Handler: _ApplicationService_PodLogs_Handler,

View File

@@ -559,6 +559,52 @@ func request_ApplicationService_ResourceTree_0(ctx context.Context, marshaler ru
}
var (
filter_ApplicationService_WatchResourceTree_0 = &utilities.DoubleArray{Encoding: map[string]int{"applicationName": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_ApplicationService_WatchResourceTree_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (ApplicationService_WatchResourceTreeClient, runtime.ServerMetadata, error) {
var protoReq ResourcesQuery
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["applicationName"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "applicationName")
}
protoReq.ApplicationName, err = runtime.StringP(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "applicationName", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_WatchResourceTree_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.WatchResourceTree(ctx, &protoReq)
if err != nil {
return nil, metadata, err
}
header, err := stream.Header()
if err != nil {
return nil, metadata, err
}
metadata.HeaderMD = header
return stream, metadata, nil
}
func request_ApplicationService_Rollback_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ApplicationRollbackRequest
var metadata runtime.ServerMetadata
@@ -1222,6 +1268,26 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
})
mux.Handle("GET", pattern_ApplicationService_WatchResourceTree_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ApplicationService_WatchResourceTree_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ApplicationService_WatchResourceTree_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ApplicationService_Rollback_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -1416,6 +1482,8 @@ var (
pattern_ApplicationService_ResourceTree_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "applicationName", "resource-tree"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_WatchResourceTree_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"api", "v1", "stream", "applications", "applicationName", "resource-tree"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_Rollback_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "rollback"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_TerminateOperation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "operation"}, "", runtime.AssumeColonVerbOpt(true)))
@@ -1464,6 +1532,8 @@ var (
forward_ApplicationService_ResourceTree_0 = runtime.ForwardResponseMessage
forward_ApplicationService_WatchResourceTree_0 = runtime.ForwardResponseStream
forward_ApplicationService_Rollback_0 = runtime.ForwardResponseMessage
forward_ApplicationService_TerminateOperation_0 = runtime.ForwardResponseMessage

View File

@@ -11,6 +11,7 @@ import (
func init() {
forward_ApplicationService_PodLogs_0 = http.StreamForwarder
forward_ApplicationService_WatchResourceTree_0 = http.StreamForwarder
forward_ApplicationService_Watch_0 = http.NewStreamForwarder(func(message proto.Message) (string, error) {
event, ok := message.(*v1alpha1.ApplicationWatchEvent)
if !ok {

View File

@@ -0,0 +1,9 @@
package project
import (
"github.com/argoproj/pkg/grpc/http"
)
func init() {
forward_ProjectService_List_0 = http.UnaryForwarder
}

View File

@@ -283,6 +283,7 @@ message ApplicationStatus {
optional OperationState operationState = 7;
// ObservedAt indicates when the application state was updated without querying latest git state
// Deprecated: controller no longer updates ObservedAt field
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time observedAt = 8;
optional string sourceType = 9;

View File

@@ -1058,7 +1058,7 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference
},
"observedAt": {
SchemaProps: spec.SchemaProps{
Description: "ObservedAt indicates when the application state was updated without querying latest git state",
Description: "ObservedAt indicates when the application state was updated without querying latest git state Deprecated: controller no longer updates ObservedAt field",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},

View File

@@ -425,6 +425,7 @@ type ApplicationStatus struct {
ReconciledAt *metav1.Time `json:"reconciledAt,omitempty" protobuf:"bytes,6,opt,name=reconciledAt"`
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,7,opt,name=operationState"`
// ObservedAt indicates when the application state was updated without querying latest git state
// Deprecated: controller no longer updates ObservedAt field
ObservedAt *metav1.Time `json:"observedAt,omitempty" protobuf:"bytes,8,opt,name=observedAt"`
SourceType ApplicationSourceType `json:"sourceType,omitempty" protobuf:"bytes,9,opt,name=sourceType"`
Summary ApplicationSummary `json:"summary,omitempty" protobuf:"bytes,10,opt,name=summary"`
@@ -2603,7 +2604,7 @@ func jwtTokensCombine(tokens1 []JWTToken, tokens2 []JWTToken) []JWTToken {
tokensMap[token.ID] = token
}
tokens := []JWTToken{}
var tokens []JWTToken
for _, v := range tokensMap {
tokens = append(tokens, v)
}

View File

@@ -1695,6 +1695,11 @@ func TestProjectNormalize(t *testing.T) {
assert.Nil(t, p.Spec.Roles)
assert.Nil(t, p.Status.JWTTokensByRole)
})
t.Run("HasRoles_NoTokens", func(t *testing.T) {
p := AppProject{Spec: AppProjectSpec{Roles: []ProjectRole{{Name: "test-role"}}}}
needNormalize := p.NormalizeJWTTokens()
assert.False(t, needNormalize)
})
t.Run("SpecRolesToken-StatusRolesTokenEmpty", func(t *testing.T) {
p := AppProject{Spec: AppProjectSpec{Roles: []ProjectRole{{Name: "test-role", JWTTokens: testTokens}}}}
needNormalize := p.NormalizeJWTTokens()

View File

@@ -901,6 +901,17 @@ func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery
return s.getAppResources(ctx, a)
}
func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application.ApplicationService_WatchResourceTreeServer) error {
return s.cache.OnAppResourcesTreeChanged(ws.Context(), q.GetApplicationName(), func() error {
var tree appv1.ApplicationTree
err := s.cache.GetAppResourcesTree(q.GetApplicationName(), &tree)
if err != nil {
return err
}
return ws.Send(&tree)
})
}
func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) {
a, err := s.appLister.Get(q.GetName())
if err != nil {

View File

@@ -294,6 +294,12 @@ service ApplicationService {
rpc ResourceTree(ResourcesQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationTree) {
option (google.api.http).get = "/api/v1/applications/{applicationName}/resource-tree";
}
// Watch returns stream of application resource tree
rpc WatchResourceTree(ResourcesQuery) returns (stream github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationTree) {
option (google.api.http).get = "/api/v1/stream/applications/{applicationName}/resource-tree";
}
// Rollback syncs an application to its target state
rpc Rollback(ApplicationRollbackRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
option (google.api.http) = {

View File

@@ -1,6 +1,7 @@
package cache
import (
"context"
"fmt"
"time"
@@ -57,6 +58,10 @@ func (c *Cache) GetAppResourcesTree(appName string, res *appv1.ApplicationTree)
return c.cache.GetAppResourcesTree(appName, res)
}
func (c *Cache) OnAppResourcesTreeChanged(ctx context.Context, appName string, callback func() error) error {
return c.cache.OnAppResourcesTreeChanged(ctx, appName, callback)
}
func (c *Cache) GetAppManagedResources(appName string, res *[]*appv1.ResourceDiff) error {
return c.cache.GetAppManagedResources(appName, res)
}

View File

@@ -412,7 +412,6 @@ func (s *Server) NormalizeProjs() error {
return status.Errorf(codes.Internal, "Error retrieving project list: %s", err.Error())
}
for _, proj := range projList.Items {
// if !apierr.IsConflict(err), retry 3 times
for i := 0; i < 3; i++ {
if proj.NormalizeJWTTokens() {
_, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(context.Background(), &proj, metav1.UpdateOptions{})
@@ -432,6 +431,8 @@ func (s *Server) NormalizeProjs() error {
if i == 2 {
return status.Errorf(codes.Internal, "Failed normalize project %s", proj.Name)
}
} else {
break
}
}
}

View File

@@ -22,6 +22,7 @@ import (
jwt "github.com/dgrijalva/jwt-go"
"github.com/go-redis/redis"
golang_proto "github.com/golang/protobuf/proto"
"github.com/gorilla/handlers"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
@@ -45,11 +46,6 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
cacheutil "github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/healthz"
"github.com/argoproj/argo-cd/util/swagger"
"github.com/argoproj/argo-cd/util/webhook"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apiclient"
accountpkg "github.com/argoproj/argo-cd/pkg/apiclient/account"
@@ -85,18 +81,22 @@ import (
"github.com/argoproj/argo-cd/server/version"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/assets"
cacheutil "github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/db"
"github.com/argoproj/argo-cd/util/dex"
dexutil "github.com/argoproj/argo-cd/util/dex"
"github.com/argoproj/argo-cd/util/env"
grpc_util "github.com/argoproj/argo-cd/util/grpc"
"github.com/argoproj/argo-cd/util/healthz"
httputil "github.com/argoproj/argo-cd/util/http"
"github.com/argoproj/argo-cd/util/jwt/zjwt"
"github.com/argoproj/argo-cd/util/oidc"
"github.com/argoproj/argo-cd/util/rbac"
util_session "github.com/argoproj/argo-cd/util/session"
settings_util "github.com/argoproj/argo-cd/util/settings"
"github.com/argoproj/argo-cd/util/swagger"
tlsutil "github.com/argoproj/argo-cd/util/tls"
"github.com/argoproj/argo-cd/util/webhook"
)
const maxConcurrentLoginRequestsCountEnv = "ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT"
@@ -159,6 +159,7 @@ type ArgoCDServer struct {
type ArgoCDServerOpts struct {
DisableAuth bool
EnableGZip bool
Insecure bool
ListenPort int
MetricsPort int
@@ -520,7 +521,19 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
}
sessionService := session.NewServer(a.sessionMgr, a, a.policyEnforcer, loginRateLimiter)
projectLock := util.NewKeyLock()
applicationService := application.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.appLister, a.appInformer, a.RepoClientset, a.Cache, kubectl, db, a.enf, projectLock, a.settingsMgr)
applicationService := application.NewServer(
a.Namespace,
a.KubeClientset,
a.AppClientset,
a.appLister,
a.appInformer,
a.RepoClientset,
a.Cache,
kubectl,
db,
a.enf,
projectLock,
a.settingsMgr)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer)
settingsService := settings.NewServer(a.settingsMgr, a, a.DisableAuth)
accountService := account.NewServer(a.sessionMgr, a.settingsMgr, a.enf)
@@ -577,13 +590,23 @@ func withRootPath(handler http.Handler, a *ArgoCDServer) http.Handler {
mux.Handle("/"+root+"/", http.StripPrefix("/"+root, handler))
healthz.ServeHealthCheck(mux, func() error {
_, err := a.KubeClientset.(*kubernetes.Clientset).ServerVersion()
return err
return nil
})
return mux
}
func compressHandler(handler http.Handler) http.Handler {
compr := handlers.CompressHandler(handler)
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
if request.Header.Get("Accept") == "text/event-stream" {
handler.ServeHTTP(writer, request)
} else {
compr.ServeHTTP(writer, request)
}
})
}
// newHTTPServer returns the HTTP server to serve HTTP/HTTPS requests. This is implemented
// using grpc-gateway as a proxy to the gRPC server.
func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandler http.Handler) *http.Server {
@@ -629,7 +652,13 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
gwMuxOpts := runtime.WithMarshalerOption(runtime.MIMEWildcard, new(grpc_util.JSONMarshaler))
gwCookieOpts := runtime.WithForwardResponseOption(a.translateGrpcCookieHeader)
gwmux := runtime.NewServeMux(gwMuxOpts, gwCookieOpts)
mux.Handle("/api/", gwmux)
var handler http.Handler = gwmux
if a.EnableGZip {
handler = compressHandler(handler)
}
mux.Handle("/api/", handler)
mustRegisterGWHandler(versionpkg.RegisterVersionServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
mustRegisterGWHandler(clusterpkg.RegisterClusterServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
mustRegisterGWHandler(applicationpkg.RegisterApplicationServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
@@ -645,8 +674,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
// Swagger UI
swagger.ServeSwaggerUI(mux, assets.SwaggerJSON, "/swagger-ui", a.RootPath)
healthz.ServeHealthCheck(mux, func() error {
_, err := a.KubeClientset.(*kubernetes.Clientset).ServerVersion()
return err
return nil
})
// Dex reverse proxy and client app and OAuth2 login/callback

View File

@@ -120,7 +120,7 @@ export const ApplicationCreatePanel = (props: {
key='creation-deps'
load={() =>
Promise.all([
services.projects.list().then(projects => projects.map(proj => proj.metadata.name).sort()),
services.projects.list('items.metadata.name').then(projects => projects.map(proj => proj.metadata.name).sort()),
services.clusters.list().then(clusters => clusters.sort()),
services.repos.list()
]).then(([projects, clusters, reposInfo]) => ({projects, clusters, reposInfo}))

View File

@@ -475,42 +475,38 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
}
private loadAppInfo(name: string): Observable<{application: appModels.Application; tree: appModels.ApplicationTree}> {
return Observable.merge(
Observable.fromPromise(services.applications.get(name).then(app => ({app, watchEvent: false}))),
services.applications
.watch({name})
.map(watchEvent => {
if (watchEvent.type === 'DELETED') {
this.onAppDeleted();
}
return {app: watchEvent.application, watchEvent: true};
})
.repeat()
.retryWhen(errors => errors.delay(500)),
this.refreshRequested.filter(e => e !== null).flatMap(() => services.applications.get(name).then(app => ({app, watchEvent: true})))
).flatMap(appInfo => {
const app = appInfo.app;
const fallbackTree: appModels.ApplicationTree = {
nodes: app.status.resources.map(res => ({...res, parentRefs: [], info: [], resourceVersion: '', uid: ''})),
orphanedNodes: []
};
const treeSource = new Observable<{application: appModels.Application; tree: appModels.ApplicationTree}>(observer => {
services.applications
.resourceTree(app.metadata.name)
.then(tree => observer.next({application: app, tree}))
.catch(e => {
observer.next({application: app, tree: fallbackTree});
observer.error(e);
});
return Observable.fromPromise(services.applications.get(name))
.flatMap(app => {
const fallbackTree = {
nodes: app.status.resources.map(res => ({...res, parentRefs: [], info: [], resourceVersion: '', uid: ''})),
orphanedNodes: []
} as appModels.ApplicationTree;
return Observable.combineLatest(
Observable.merge(
Observable.from([app]),
services.applications
.watch({name})
.map(watchEvent => {
if (watchEvent.type === 'DELETED') {
this.onAppDeleted();
}
return watchEvent.application;
})
.repeat()
.retryWhen(errors => errors.delay(500))
),
Observable.merge(
Observable.from([fallbackTree]),
services.applications.resourceTree(name).catch(() => fallbackTree),
services.applications
.watchResourceTree(name)
.repeat()
.retryWhen(errors => errors.delay(500))
)
);
})
.repeat()
.retryWhen(errors => errors.delay(1000));
if (appInfo.watchEvent) {
return treeSource;
} else {
return Observable.merge(Observable.from([{application: app, tree: fallbackTree}]), treeSource);
}
});
.filter(([application, tree]) => !!application && !!tree)
.map(([application, tree]) => ({application, tree}));
}
private onAppDeleted() {

View File

@@ -35,7 +35,7 @@ export const ApplicationSummary = (props: {app: models.Application; updateApp: (
title: 'PROJECT',
view: <a href={'/settings/projects/' + app.spec.project}>{app.spec.project}</a>,
edit: (formApi: FormApi) => (
<DataLoader load={() => services.projects.list().then(projs => projs.map(item => item.metadata.name))}>
<DataLoader load={() => services.projects.list('items.metadata.name').then(projs => projs.map(item => item.metadata.name))}>
{projects => <FormField formApi={formApi} field='spec.project' component={FormSelect} componentProps={{options: projects}} />}
</DataLoader>
)

View File

@@ -146,7 +146,7 @@ export class ApplicationsFilter extends React.Component<ApplicationsFilterProps,
<p>Projects</p>
<ul>
<li>
<DataLoader load={() => services.projects.list()}>
<DataLoader load={() => services.projects.list('items.metadata.name')}>
{projects => {
const projAppCount = new Map<string, number>();
projects.forEach(proj => projAppCount.set(proj.metadata.name, 0));

View File

@@ -54,6 +54,10 @@ export class ApplicationsService {
return requests.get(`/applications/${name}/resource-tree`).then(res => res.body as models.ApplicationTree);
}
public watchResourceTree(name: string): Observable<models.ApplicationTree> {
return requests.loadEventSource(`/stream/applications/${name}/resource-tree`).map(data => JSON.parse(data).result as models.ApplicationTree);
}
public managedResources(name: string, options: {id?: models.ResourceID; fields?: string[]} = {}): Promise<models.ResourceDiff[]> {
return requests
.get(`/applications/${name}/managed-resources`)

View File

@@ -90,9 +90,10 @@ function paramsToProj(params: ProjectParams) {
}
export class ProjectsService {
public list(): Promise<models.Project[]> {
public list(...fields: string[]): Promise<models.Project[]> {
return requests
.get('/projects')
.query({fields: fields.join(',')})
.then(res => res.body as models.ProjectList)
.then(list => list.items || []);
}

View File

@@ -1,6 +1,7 @@
package appstate
import (
"context"
"fmt"
"time"
@@ -76,8 +77,16 @@ func (c *Cache) GetAppResourcesTree(appName string, res *appv1.ApplicationTree)
return err
}
func (c *Cache) OnAppResourcesTreeChanged(ctx context.Context, appName string, callback func() error) error {
return c.Cache.OnUpdated(ctx, appManagedResourcesKey(appName), callback)
}
func (c *Cache) SetAppResourcesTree(appName string, resourcesTree *appv1.ApplicationTree) error {
return c.SetItem(appResourcesTreeKey(appName), resourcesTree, c.appStateCacheExpiration, resourcesTree == nil)
err := c.SetItem(appResourcesTreeKey(appName), resourcesTree, c.appStateCacheExpiration, resourcesTree == nil)
if err != nil {
return err
}
return c.Cache.NotifyUpdated(appManagedResourcesKey(appName))
}
func (c *Cache) SetClusterInfo(server string, info *appv1.ClusterInfo) error {

9
util/cache/cache.go vendored
View File

@@ -1,6 +1,7 @@
package cache
import (
"context"
"fmt"
"math"
"os"
@@ -96,3 +97,11 @@ func (c *Cache) GetItem(key string, item interface{}) error {
key = fmt.Sprintf("%s|%s", key, common.CacheVersion)
return c.client.Get(key, item)
}
func (c *Cache) OnUpdated(ctx context.Context, key string, callback func() error) error {
return c.client.OnUpdated(ctx, fmt.Sprintf("%s|%s", key, common.CacheVersion), callback)
}
func (c *Cache) NotifyUpdated(key string) error {
return c.client.NotifyUpdated(fmt.Sprintf("%s|%s", key, common.CacheVersion))
}

View File

@@ -1,6 +1,7 @@
package cache
import (
"context"
"errors"
"time"
)
@@ -18,4 +19,6 @@ type CacheClient interface {
Set(item *Item) error
Get(key string, obj interface{}) error
Delete(key string) error
OnUpdated(ctx context.Context, key string, callback func() error) error
NotifyUpdated(key string) error
}

View File

@@ -2,6 +2,7 @@ package cache
import (
"bytes"
"context"
"encoding/gob"
"time"
@@ -45,3 +46,11 @@ func (i *InMemoryCache) Delete(key string) error {
func (i *InMemoryCache) Flush() {
i.memCache.Flush()
}
func (i *InMemoryCache) OnUpdated(ctx context.Context, key string, callback func() error) error {
return nil
}
func (i *InMemoryCache) NotifyUpdated(key string) error {
return nil
}

25
util/cache/redis.go vendored
View File

@@ -1,8 +1,10 @@
package cache
import (
"context"
"time"
ioutil "github.com/argoproj/gitops-engine/pkg/utils/io"
rediscache "github.com/go-redis/cache"
"github.com/go-redis/redis"
"github.com/vmihailenco/msgpack"
@@ -10,6 +12,7 @@ import (
func NewRedisCache(client *redis.Client, expiration time.Duration) CacheClient {
return &redisCache{
client: client,
expiration: expiration,
codec: &rediscache.Codec{
Redis: client,
@@ -25,6 +28,7 @@ func NewRedisCache(client *redis.Client, expiration time.Duration) CacheClient {
type redisCache struct {
expiration time.Duration
client *redis.Client
codec *rediscache.Codec
}
@@ -52,6 +56,27 @@ func (r *redisCache) Delete(key string) error {
return r.codec.Delete(key)
}
func (r *redisCache) OnUpdated(ctx context.Context, key string, callback func() error) error {
pubsub := r.client.Subscribe(key)
defer ioutil.Close(pubsub)
ch := pubsub.Channel()
for {
select {
case <-ctx.Done():
return nil
case <-ch:
if err := callback(); err != nil {
return err
}
}
}
}
func (r *redisCache) NotifyUpdated(key string) error {
return r.client.Publish(key, "").Err()
}
type MetricsRegistry interface {
IncRedisRequest(failed bool)
ObserveRedisRequestDuration(duration time.Duration)

View File

@@ -134,7 +134,7 @@ func replaceListSecrets(obj []interface{}, secretValues map[string]string) []int
// https://github.com/dexidp/dex/tree/master/Documentation/connectors
func needsRedirectURI(connectorType string) bool {
switch connectorType {
case "oidc", "saml", "microsoft", "linkedin", "gitlab", "github", "bitbucket-cloud":
case "oidc", "saml", "microsoft", "linkedin", "gitlab", "github", "bitbucket-cloud", "openshift":
return true
}
return false

View File

@@ -54,6 +54,9 @@ Expire-Date: 6m
%commit
`
// Canary marker for GNUPGHOME created by Argo CD
const canaryMarkerFilename = ".argocd-generated"
type PGPKeyID string
func isHexString(s string) bool {
@@ -162,6 +165,39 @@ func writeKeyToFile(keyData string) (string, error) {
return f.Name(), nil
}
// removeKeyRing removes an already initialized keyring from the file system
// This must only be called on container startup, when no gpg-agent is running
// yet, otherwise key generation will fail.
func removeKeyRing(path string) error {
_, err := os.Stat(filepath.Join(path, canaryMarkerFilename))
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("refusing to remove directory %s: it's not initialized by Argo CD", path)
} else {
return err
}
}
rd, err := os.Open(path)
if err != nil {
return err
}
defer rd.Close()
dns, err := rd.Readdirnames(-1)
if err != nil {
return err
}
for _, p := range dns {
if p == "." || p == ".." {
continue
}
err := os.RemoveAll(filepath.Join(path, p))
if err != nil {
return err
}
}
return nil
}
// IsGPGEnabled returns true if GPG feature is enabled
func IsGPGEnabled() bool {
if en := os.Getenv("ARGOCD_GPG_ENABLED"); strings.ToLower(en) == "false" || strings.ToLower(en) == "no" {
@@ -197,8 +233,17 @@ func InitializeGnuPG() error {
return err
}
} else {
// We can't initialize a second time
return fmt.Errorf("%s at %s already initialized, can't initialize again.", common.EnvGnuPGHome, gnuPgHome)
// This usually happens with emptyDir mount on container crash - we need to
// re-initialize key ring.
err = removeKeyRing(gnuPgHome)
if err != nil {
return fmt.Errorf("re-initializing keyring at %s failed: %v", gnuPgHome, err)
}
}
err = ioutil.WriteFile(filepath.Join(gnuPgHome, canaryMarkerFilename), []byte("canary"), 0644)
if err != nil {
return fmt.Errorf("could not create canary: %v", err)
}
f, err := ioutil.TempFile("", "gpg-key-recipe")

View File

@@ -5,10 +5,12 @@ import (
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/test"
@@ -60,10 +62,20 @@ func Test_GPG_InitializeGnuPG(t *testing.T) {
assert.Len(t, keys, 1)
assert.Equal(t, keys[0].Trust, "ultimate")
// Second run should return error
// During unit-tests, we need to also kill gpg-agent so we can create a new key.
// In real world scenario -- i.e. container crash -- gpg-agent is not running yet.
cmd := exec.Command("gpgconf", "--kill", "gpg-agent")
cmd.Env = []string{fmt.Sprintf("GNUPGHOME=%s", p)}
err = cmd.Run()
require.NoError(t, err)
// Second run should not return error
err = InitializeGnuPG()
assert.Error(t, err)
assert.Contains(t, err.Error(), "already initialized")
require.NoError(t, err)
keys, err = GetInstalledPGPKeys(nil)
assert.NoError(t, err)
assert.Len(t, keys, 1)
assert.Equal(t, keys[0].Trust, "ultimate")
// GNUPGHOME is a file - we need to error out
f, err := ioutil.TempFile("", "gpg-test")