diff --git a/.DS_Store b/.DS_Store index 2a2dc9a3..16334541 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6dedfcf9..ff723dbc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,5 +29,5 @@ jobs: verb: call args: -s --name my-test build-images --source-folder ../ new-interlink --plugin-endpoint tcp://localhost:4000 --manifests ./manifests test stdout cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }} - version: "0.11.9" + version: "0.13.0" dagger-flags: -d diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 3117e9cf..096d9598 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -18,7 +18,7 @@ builds: - arm64 - amd64 main: ./cmd/virtual-kubelet - - id: "interlink" + - id: "interlink-api" binary: interlink hooks: pre: bash -c "KUBELET_VERSION={{.Version}} ./cmd/virtual-kubelet/set-version.sh" @@ -32,8 +32,8 @@ builds: - amd64 - ppc64le main: ./cmd/interlink - - id: "interlink-install" - binary: interlink-install + - id: "installer" + binary: interlink-installer env: - CGO_ENABLED=0 goos: @@ -44,6 +44,18 @@ builds: - amd64 - ppc64le main: ./cmd/installer + - id: "ssh-tunnel" + binary: ssh-tunnel + env: + - CGO_ENABLED=0 + goos: + - linux + - darwin + goarch: + - arm64 + - amd64 + - ppc64le + main: ./cmd/ssh-tunnel archives: - name_template: >- {{ .Binary }}_ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a8ed27c..26fa5667 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,6 +31,7 @@ you submit the pull request). We have a 3 steps process for contributions. understanding and appreciating your pull request, please use the template to explain _why_ you are making this contribution, rather than just _what_ the contribution entails. +2. **Run E2E tests with success**. You can follow the steps described [here](https://intertwin-eu.github.io/interLink/docs/Developers) ### Code Review Process @@ -44,7 +45,7 @@ follows: 1. A maintainer will review your code and merge it if no changes are necessary. Your change will be merged into the repository's `main` branch. -1. If a maintainer has feedback or questions on your changes then they will set +2. If a maintainer has feedback or questions on your changes then they will set `request changes` in the review and provide an explanation. ## Using git diff --git a/Makefile b/Makefile index 84dbae52..431d953b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -all: interlink vk installer +all: interlink vk installer ssh-tunnel interlink: CGO_ENABLED=0 OOS=linux go build -o bin/interlink cmd/interlink/main.go @@ -9,16 +9,16 @@ vk: installer: CGO_ENABLED=0 OOS=linux go build -o bin/installer cmd/installer/main.go +ssh-tunnel: + CGO_ENABLED=0 OOS=linux go build -o bin/ssh-tunnel cmd/ssh-tunnel/main.go + clean: rm -rf ./bin -dagger_registry_delete: - docker rm -fv registry || true - test: - dagger_registry_delete - docker run -d --rm --name registry -p 5432:5000 registry - cd ci - dagger go run go main.go k8s.go - cd - + dagger call -m ./ci \ + --name my-tests \ + build-images \ + new-interlink \ + test stdout diff --git a/ci/dagger.json b/ci/dagger.json index 927f0f5c..2374e7b1 100644 --- a/ci/dagger.json +++ b/ci/dagger.json @@ -4,9 +4,8 @@ "dependencies": [ { "name": "k3s", - "source": "github.com/marcosnils/daggerverse/k3s@e0bd6b9f5519c49db4b6eb0689927214720976f9" + "source": "github.com/marcosnils/daggerverse/k3s@ce8fe35d309bdb29f9983f7d90ea518e724534fe" } ], - "source": ".", - "engineVersion": "v0.11.9" + "engineVersion": "v0.13.0" } diff --git a/ci/go.mod b/ci/go.mod index 14facf9f..18ab4923 100644 --- a/ci/go.mod +++ b/ci/go.mod @@ -3,9 +3,9 @@ module dagger/interlink go 1.22.2 require ( - github.com/99designs/gqlgen v0.17.44 + github.com/99designs/gqlgen v0.17.49 github.com/Khan/genqlient v0.7.0 - github.com/vektah/gqlparser/v2 v2.5.11 + github.com/vektah/gqlparser/v2 v2.5.16 go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 @@ -28,13 +28,21 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect - github.com/sosodev/duration v1.2.0 // indirect + github.com/sosodev/duration v1.3.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect google.golang.org/protobuf v1.34.1 // indirect ) + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 + +replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp => go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.3.0 + +replace go.opentelemetry.io/otel/log => go.opentelemetry.io/otel/log v0.3.0 + +replace go.opentelemetry.io/otel/sdk/log => go.opentelemetry.io/otel/sdk/log v0.3.0 diff --git a/ci/go.sum b/ci/go.sum index 55494862..6fea81b9 100644 --- a/ci/go.sum +++ b/ci/go.sum @@ -1,5 +1,5 @@ -github.com/99designs/gqlgen v0.17.44 h1:OS2wLk/67Y+vXM75XHbwRnNYJcbuJd4OBL76RX3NQQA= -github.com/99designs/gqlgen v0.17.44/go.mod h1:UTCu3xpK2mLI5qcMNw+HKDiEL77it/1XtAjisC4sLwM= +github.com/99designs/gqlgen v0.17.49 h1:b3hNGexHd33fBSAd4NDT/c3NCcQzcAVkknhN9ym36YQ= +github.com/99designs/gqlgen v0.17.49/go.mod h1:tC8YFVZMed81x7UJ7ORUwXF4Kn6SXuucFqQBhN8+BU0= github.com/Khan/genqlient v0.7.0 h1:GZ1meyRnzcDTK48EjqB8t3bcfYvHArCUUvgOwpz1D4w= github.com/Khan/genqlient v0.7.0/go.mod h1:HNyy3wZvuYwmW3Y7mkoQLZsa/R5n5yIRajS1kPBvSFM= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= @@ -27,14 +27,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= -github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4= +github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= -github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/vektah/gqlparser/v2 v2.5.16 h1:1gcmLTvs3JLKXckwCwlUagVn/IlV2bwqle0vJ0vy5p8= +github.com/vektah/gqlparser/v2 v2.5.16/go.mod h1:1lz1OeCqgQbQepsGxPVywrjdBHW2T08PUS3pJqepRww= go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.0.0-20240518090000-14441aefdf88 h1:oM0GTNKGlc5qHctWeIGTVyda4iFFalOzMZ3Ehj5rwB4= @@ -63,14 +63,14 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= diff --git a/ci/helm_test/interlink-config.yaml b/ci/helm_test/interlink-config.yaml new file mode 100644 index 00000000..875aecba --- /dev/null +++ b/ci/helm_test/interlink-config.yaml @@ -0,0 +1,16 @@ +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: "interlink-config" +# namespace: interlink +# data: +# InterLinkConfig.yaml: | + #InterlinkAddress: "unix:///var/run/interlink.socket" +InterlinkAddress: "http://0.0.0.0" +InterlinkPort: "3000" +SidecarURL: "http://plugin" +SidecarPort: "4000" +VerboseLogging: true +ErrorsOnlyLogging: false +ExportPodData: true +DataRootFolder: "~/.interlink" diff --git a/ci/helm_test/kustomization.yaml b/ci/helm_test/kustomization.yaml new file mode 100644 index 00000000..8b98ba9d --- /dev/null +++ b/ci/helm_test/kustomization.yaml @@ -0,0 +1,13 @@ +resources: +- virtual-kubelet-config.yaml +- virtual-kubelet.yaml +#- interlink-config.yaml +#- interlink.yaml +#- plugin-k8s-config.yaml +#- plugin.yaml +patches: +- path: virtual-kubelet-merge.yaml + target: + kind: Deployment + labelSelector: nodeName=virtual-kubelet + diff --git a/ci/helm_test/plugin-config.yaml b/ci/helm_test/plugin-config.yaml new file mode 100644 index 00000000..61a766f9 --- /dev/null +++ b/ci/helm_test/plugin-config.yaml @@ -0,0 +1,21 @@ +InterlinkURL: "http://interlink" +InterlinkPort: "3000" +SidecarURL: "http://0.0.0.0" +SidecarPort: "4000" +VerboseLogging: true +ErrorsOnlyLogging: false +ExportPodData: true +# NEEDED PATH FOR GITHUB ACTIONS +#DataRootFolder: "/home/runner/work/interLink/interLink/.interlink/" +# on your host use something like: +DataRootFolder: "/home/ubuntu/.interlink/" +SbatchPath: "/usr/bin/sbatch" +ScancelPath: "/usr/bin/scancel" +SqueuePath: "/usr/bin/squeue" +CommandPrefix: "" +SingularityPrefix: "" +Namespace: "vk" +Tsocks: false +TsocksPath: "$WORK/tsocks-1.8beta5+ds1/libtsocks.so" +TsocksLoginNode: "login01" +BashPath: /bin/bash diff --git a/ci/helm_test/plugin-k8s-config.yaml b/ci/helm_test/plugin-k8s-config.yaml new file mode 100644 index 00000000..8db723f4 --- /dev/null +++ b/ci/helm_test/plugin-k8s-config.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "plugin-config" + namespace: interlink +data: + InterLinkConfig.yaml: | + InterlinkURL: "http://localhost" + InterlinkPort: "3000" + SidecarURL: "http://0.0.0.0" + SidecarPort: "4000" + VerboseLogging: true + ErrorsOnlyLogging: false + ExportPodData: true + DataRootFolder: "/home/runner/work/interLink/interLink/.interlink/" + SbatchPath: "/usr/bin/sbatch" + ScancelPath: "/usr/bin/scancel" + SqueuePath: "/usr/bin/squeue" + CommandPrefix: "" + SingularityPrefix: "" + Namespace: "vk" + Tsocks: false + TsocksPath: "$WORK/tsocks-1.8beta5+ds1/libtsocks.so" + TsocksLoginNode: "login01" + BashPath: /bin/bash diff --git a/ci/helm_test/plugin.yaml b/ci/helm_test/plugin.yaml new file mode 100644 index 00000000..082360e7 --- /dev/null +++ b/ci/helm_test/plugin.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +kind: Service +metadata: + name: plugin + namespace: interlink +spec: + selector: + app: plugin + ports: + - protocol: TCP + port: 4000 + targetPort: 4000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: plugin + namespace: interlink + labels: + app: plugin +spec: + replicas: 1 + selector: + matchLabels: + app: plugin + template: + metadata: + labels: + app: plugin + spec: + containers: + - name: plugin + image: "dciangot/docker-plugin:v1" + #image: "ghcr.io/intertwin-eu/interlink-sidecar-slurm/interlink-sidecar-slurm:0.2.3" + imagePullPolicy: Always + command: + - bash + - -c + args: + - dockerd --mtu 1450 & /sidecar/docker-sidecar + securityContext: + privileged: true + env: + - name: INTERLINKCONFIGPATH + value: "/etc/interlink/InterLinkConfig.yaml" + volumeMounts: + - name: config + mountPath: /etc/interlink/InterLinkConfig.yaml + subPath: InterLinkConfig.yaml + volumes: + - name: config + configMap: + # Provide the name of the ConfigMap you want to mount. + name: plugin-config diff --git a/helm/interlink/templates/service-account.yaml b/ci/helm_test/service-account.yaml similarity index 60% rename from helm/interlink/templates/service-account.yaml rename to ci/helm_test/service-account.yaml index b622e723..2169e592 100644 --- a/helm/interlink/templates/service-account.yaml +++ b/ci/helm_test/service-account.yaml @@ -1,14 +1,14 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ .Values.nodeName }} - namespace: {{ .Release.Namespace }} + name: virtual-kubelet + namespace: interlink --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: "{{ .Values.nodeName }}-role" - namespace: {{ .Release.Namespace }} + name: virtual-kubelet + namespace: interlink rules: - apiGroups: - "coordination.k8s.io" @@ -75,24 +75,14 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: "{{ .Values.nodeName }}-rolebinding" - namespace: {{ .Release.Namespace }} + name: virtual-kubelet + namespace: interlink subjects: - kind: ServiceAccount - name: {{ .Values.nodeName }} - namespace: {{ .Release.Namespace }} + name: virtual-kubelet + namespace: interlink roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: "{{ .Values.nodeName }}-role" ---- -apiVersion: v1 -kind: Secret -metadata: - name: "{{ .Values.nodeName }}-secret" - namespace: "{{ .Release.Namespace }}" - annotations: - kubernetes.io/service-account.name: {{ .Values.nodeName }} - labels: - kubernetes.io/service-account.name: {{ .Values.nodeName }} -type: kubernetes.io/service-account-token + name: virtual-kubelet + diff --git a/ci/helm_test/virtual-kubelet-config.yaml b/ci/helm_test/virtual-kubelet-config.yaml new file mode 100644 index 00000000..7feb69c2 --- /dev/null +++ b/ci/helm_test/virtual-kubelet-config.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "virtual-kubelet-config" + namespace: interlink +data: + InterLinkConfig.yaml: | + #InterlinkURL: unix:///var/run/interlink.socket + InterlinkURL: "http://interlink" + InterlinkPort: "3000" + ExportPodData: true + VerboseLogging: true + ErrorsOnlyLogging: false + ServiceAccount: "virtual-kubelet" + Namespace: interlink + VKTokenFile: "" + CPU: "100" + Memory: "128Gi" + Pods: "100" diff --git a/ci/helm_test/virtual-kubelet.yaml b/ci/helm_test/virtual-kubelet.yaml new file mode 100644 index 00000000..8dc1c2e7 --- /dev/null +++ b/ci/helm_test/virtual-kubelet.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: virtual-kubelet + namespace: interlink + labels: + nodeName: virtual-kubelet +spec: + replicas: 1 + selector: + matchLabels: + nodeName: virtual-kubelet + template: + metadata: + labels: + nodeName: virtual-kubelet + spec: + hostNetwork: true + automountServiceAccountToken: true + serviceAccountName: virtual-kubelet + containers: + # - name: interlink + # image: "ghcr.io/intertwin-eu/interlink/interlink" + # imagePullPolicy: Always + # env: + # - name: INTERLINKCONFIGPATH + # value: "/etc/interlink/InterLinkConfig.yaml" + # volumeMounts: + # - name: il-config + # mountPath: /etc/interlink/InterLinkConfig.yaml + # subPath: InterLinkConfig.yaml + # - name: sockets + # mountPath: /var/run/ + - name: inttw-vk + image: "ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw" + imagePullPolicy: Always + env: + - name: NODENAME + value: virtual-kubelet + - name: KUBELET_PORT + value: "10255" + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: CONFIGPATH + value: "/etc/interlink/InterLinkConfig.yaml" + volumeMounts: + - name: config + mountPath: /etc/interlink/InterLinkConfig.yaml + subPath: InterLinkConfig.yaml + # - name: sockets + # mountPath: /var/run/ + volumes: + - name: config + configMap: + # Provide the name of the ConfigMap you want to mount. + name: virtual-kubelet-config + - name: sockets + hostPath: + path: /var/run + type: Directory + # - name: il-config + # configMap: + # # Provide the name of the ConfigMap you want to mount. + # name: interlink-config + # - name: sockets + # emptyDir: {} diff --git a/ci/helm_test/vktest_config.yaml b/ci/helm_test/vktest_config.yaml new file mode 100644 index 00000000..2b02f2cb --- /dev/null +++ b/ci/helm_test/vktest_config.yaml @@ -0,0 +1,20 @@ +target_nodes: + - virtual-kubelet + +required_namespaces: + - default + - kube-system + - interlink + +timeout_multiplier: 10. +values: + namespace: interlink + + annotations: + slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800 --ntasks=8 --nodes=1 --mem-per-cpu=2000" + + tolerations: + - key: virtual-node.interlink/no-schedule + operator: Exists + effect: NoSchedule + diff --git a/ci/main.go b/ci/main.go index 74143371..24789bae 100644 --- a/ci/main.go +++ b/ci/main.go @@ -8,6 +8,7 @@ package main import ( "bytes" "context" + "dagger/interlink/internal/dagger" "fmt" "html/template" "strings" @@ -15,19 +16,6 @@ import ( ) var ( - interLinkPatch = ` -kind: Deployment -metadata: - name: interlink - namespace: interlink -spec: - template: - spec: - containers: - - name: interlink - image: "{{.InterLinkRef}}" - -` virtualKubeletPatch = ` kind: Deployment metadata: @@ -40,6 +28,11 @@ spec: - name: inttw-vk image: "{{.VirtualKubeletRef}}" ` + +// #- name: interlink +// # image: "{{.InterLinkRef}}" +// +// ` ) type patchSchema struct { @@ -50,32 +43,41 @@ type patchSchema struct { // Interlink struct for initialization and internal variables type Interlink struct { Name string - Registry *Service - Manifests *Directory + Registry *dagger.Service + Manifests *dagger.Directory VirtualKubeletRef string InterlinkRef string + PluginRef string // +private - Kubectl *Container + Kubectl *dagger.Container // +private - KubeAPIs *Service + KubeAPIs *dagger.Service // +private - KubeConfig *File + KubeConfig *dagger.File // +private - KubeConfigHost *File + KubeConfigHost *dagger.File + InterlinkContainer *dagger.Container + VKContainer *dagger.Container } // New initializes the Dagger module at each call func New(name string, // +optional + // +default="ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw:0.3.1-rc1" VirtualKubeletRef string, // +optional + // +default="ghcr.io/intertwin-eu/interlink/interlink:0.3.1-rc1" InterlinkRef string, + // +optional + // +default="ghcr.io/intertwin-eu/interlink-docker-plugin/docker-plugin:0.0.24-no-gpu" + pluginRef string, ) *Interlink { return &Interlink{ Name: name, VirtualKubeletRef: VirtualKubeletRef, InterlinkRef: InterlinkRef, + PluginRef: pluginRef, } } @@ -83,60 +85,85 @@ func New(name string, // virtual kubelet and interlink API server func (m *Interlink) NewInterlink( ctx context.Context, - manifests *Directory, // +optional - kubeconfig *File, + // +defaultPath="./manifests" + manifests *dagger.Directory, + // +optional + kubeconfig *dagger.File, // +optional - localRegistry *Service, + localRegistry *dagger.Service, // +optional - localCluster *Service, + localCluster *dagger.Service, // +optional - // +default="dciangot/docker-plugin:v1" - pluginImage string, + interlinkEndpoint *dagger.Service, // +optional - pluginEndpoint *Service, + // +defaultPath="./manifests/interlink-config.yaml" + interlinkConfig *dagger.File, // +optional - pluginConfig *File, + pluginEndpoint *dagger.Service, + // +optional + // +defaultPath="./manifests/plugin-config.yaml" + pluginConfig *dagger.File, ) (*Interlink, error) { if localRegistry != nil { m.Registry = localRegistry } + var err error if pluginEndpoint == nil { - plugin := dag.Container().From(pluginImage). + plugin := dag.Container().From(m.PluginRef). WithFile("/etc/interlink/InterLinkConfig.yaml", pluginConfig). WithEnvVariable("INTERLINKCONFIGPATH", "/etc/interlink/InterLinkConfig.yaml"). - WithExec([]string{"bash", "-c", "dockerd --mtu 1450 & /sidecar/docker-sidecar"}, ContainerWithExecOpts{InsecureRootCapabilities: true}). - WithExposedPort(4000) + WithExposedPort(4000). + WithExec([]string{"bash", "-c", "dockerd --mtu 1450 & /sidecar/docker-sidecar"}, dagger.ContainerWithExecOpts{UseEntrypoint: false, InsecureRootCapabilities: true}) - pluginEndpoint = plugin.AsService() + pluginEndpoint, err = plugin.AsService().Start(ctx) + if err != nil { + return nil, err + } } - //K3s := dag.K3S(m.Name, K3SOpts{Image: "rancher/k3s:v1.28.1-k3s1"}).With(func(k *K3S) *K3S { - K3s := dag.K3S(m.Name).With(func(k *K3S) *K3S { + if interlinkEndpoint == nil { + interlink := m.InterlinkContainer. + WithFile("/etc/interlink/InterLinkConfig.yaml", interlinkConfig). + WithServiceBinding("plugin", pluginEndpoint). + WithEnvVariable("INTERLINKCONFIGPATH", "/etc/interlink/InterLinkConfig.yaml"). + WithExposedPort(3000). + WithExec([]string{}, dagger.ContainerWithExecOpts{UseEntrypoint: true, InsecureRootCapabilities: true}) + + interlinkEndpoint, err = interlink.AsService().Start(ctx) + if err != nil { + return nil, err + } + } + + K3s := dag.K3S(m.Name).With(func(k *dagger.K3S) *dagger.K3S { return k.WithContainer( k.Container(). WithEnvVariable("BUST", time.Now().String()). - WithMountedDirectory("/manifests", manifests). WithExec([]string{"sh", "-c", ` cat < /etc/rancher/k3s/registries.yaml mirrors: "registry:5000": endpoint: - "http://registry:5000" -EOF`}, ContainerWithExecOpts{SkipEntrypoint: true}). +EOF`}). WithServiceBinding("registry", m.Registry). - WithServiceBinding("plugin", pluginEndpoint), + WithServiceBinding("interlink", interlinkEndpoint), ) + }) - K3s.Server().Start(ctx) + _, err = K3s.Server().Start(ctx) + if err != nil { + return nil, err + } m.Manifests = manifests m.KubeAPIs = K3s.Server() - m.KubeConfig = K3s.Config(false) - m.KubeConfigHost = K3s.Config(true) + m.KubeConfig = K3s.Config(dagger.K3SConfigOpts{Local: false}) + m.KubeConfigHost = K3s.Config(dagger.K3SConfigOpts{Local: true}) // create Kustomize patch for images to be used patch := patchSchema{ @@ -144,18 +171,8 @@ EOF`}, ContainerWithExecOpts{SkipEntrypoint: true}). VirtualKubeletRef: m.VirtualKubeletRef, } - interLinkCompiler, err := template.New("interlink").Parse(interLinkPatch) - if err != nil { - return nil, err - } - bufferIL := new(bytes.Buffer) - err = interLinkCompiler.Execute(bufferIL, patch) - if err != nil { - return nil, err - } - virtualKubeletCompiler, err := template.New("vk").Parse(virtualKubeletPatch) if err != nil { return nil, err @@ -171,72 +188,50 @@ EOF`}, ContainerWithExecOpts{SkipEntrypoint: true}). fmt.Println(bufferVK.String()) kubectl := dag.Container().From("bitnami/kubectl:1.29.7-debian-12-r3"). + WithServiceBinding("registry", m.Registry). + WithServiceBinding("plugin", pluginEndpoint). + WithServiceBinding("interlink", interlinkEndpoint). WithUser("root"). - WithExec([]string{"mkdir", "-p", "/opt/user"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"chown", "-R", "1001:0", "/opt/user"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"apt", "update"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"apt", "update"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"apt", "install", "-y", "curl", "python3", "python3-pip", "python3-venv", "git"}, ContainerWithExecOpts{SkipEntrypoint: true}). + WithExec([]string{"mkdir", "-p", "/opt/user"}). + WithExec([]string{"chown", "-R", "1001:0", "/opt/user"}). + WithExec([]string{"apt", "update"}). + WithExec([]string{"apt", "update"}). + WithExec([]string{"apt", "install", "-y", "curl", "python3", "python3-pip", "python3-venv", "git", "vim"}). WithMountedFile("/.kube/config", m.KubeConfig). - WithExec([]string{"chown", "1001:0", "/.kube/config"}, ContainerWithExecOpts{SkipEntrypoint: true}). + WithExec([]string{"chown", "1001:0", "/.kube/config"}). WithUser("1001"). WithDirectory("/manifests", m.Manifests). - WithNewFile("/manifests/virtual-kubelet-merge.yaml", ContainerWithNewFileOpts{ - Contents: bufferVK.String(), + WithNewFile("/manifests/virtual-kubelet-merge.yaml", bufferVK.String(), dagger.ContainerWithNewFileOpts{ Permissions: 0o755, }). - WithNewFile("/manifests/interlink-merge.yaml", ContainerWithNewFileOpts{ - Contents: bufferIL.String(), + WithNewFile("/manifests/interlink-merge.yaml", bufferIL.String(), dagger.ContainerWithNewFileOpts{ Permissions: 0o755, }). WithEntrypoint([]string{"kubectl"}) m.Kubectl = kubectl - ns, _ := kubectl.WithExec([]string{"create", "ns", "interlink"}).Stdout(ctx) + ns, _ := kubectl.WithExec([]string{"create", "ns", "interlink"}, dagger.ContainerWithExecOpts{UseEntrypoint: true}).Stdout(ctx) fmt.Println(ns) - sa, err := kubectl.WithExec([]string{"apply", "-f", "/manifests/service-account.yaml"}).Stdout(ctx) + sa, err := kubectl.WithExec([]string{"apply", "-f", "/manifests/service-account.yaml"}, dagger.ContainerWithExecOpts{UseEntrypoint: true}).Stdout(ctx) if err != nil { return nil, err } fmt.Println(sa) - vkConfig, err := kubectl.WithExec([]string{"apply", "-k", "/manifests/"}).Stdout(ctx) + vkConfig, err := kubectl.WithExec([]string{"apply", "-k", "/manifests/"}, dagger.ContainerWithExecOpts{UseEntrypoint: true}).Stdout(ctx) if err != nil { return nil, err } fmt.Println(vkConfig) return m, nil - //maxRetries := 10 - //retryBackoff := 10 * time.Second - // for i := 0; i < maxRetries; i++ { - // kubectlGetNodes, err := kubectl.WithExec([]string{"get", "nodes", "-o", "wide", "virtual-kubelet"}).Stdout(ctx) - // if err != nil { - // fmt.Println(fmt.Errorf("could not fetch nodes: %v", err)) - // fmt.Println("waiting for k8s to start:", kubectlGetNodes) - // time.Sleep(retryBackoff) - // continue - // } - // if strings.Contains(kubectlGetNodes, " Ready") { - // time.Sleep(30 * time.Second) - // return m, nil - // } - // time.Sleep(retryBackoff) - // } - // kubectlAll, err := kubectl.WithExec([]string{"logs", "-n", "interlink", "-l", "nodeName=virtual-kubelet"}).Stdout(ctx) - // if err != nil { - // return nil, err - // } - // fmt.Println(kubectlAll) - // - // return nil, fmt.Errorf("k8s took too long to start") } // Returns the kubeconfig file of the k3s cluster -func (m *Interlink) Config() *File { - return m.KubeConfigHost +func (m *Interlink) Config() *dagger.File { + return dag.K3S(m.Name).Config(dagger.K3SConfigOpts{Local: true}) } // Build interLink and virtual kubelet docker images from source @@ -252,7 +247,9 @@ func (m *Interlink) BuildImages( // +optional // +default="registry:5000/plugin-test" pluginRef string, - sourceFolder *Directory, + // +optional + // +defaultPath="../" + sourceFolder *dagger.Directory, ) (*Interlink, error) { // TODO: get tag @@ -262,11 +259,6 @@ func (m *Interlink) BuildImages( m.VirtualKubeletRef = virtualKubeletRef m.InterlinkRef = interlinkRef - workspace := dag.Container(). - WithDirectory("/src", sourceFolder). - WithWorkdir("/src"). - Directory("/src") - vkVersionSplits := strings.Split(virtualKubeletRef, ":") vkVersion := vkVersionSplits[len(vkVersionSplits)-1] @@ -274,31 +266,55 @@ func (m *Interlink) BuildImages( return nil, fmt.Errorf("no tag specified on the image for VK") } + builder := dag.Container(). + From("golang:1.22"). + WithDirectory("/src", sourceFolder). + WithWorkdir("/src"). + WithMountedCache("/go/pkg/mod", dag.CacheVolume("go-mod-122")). + WithEnvVariable("GOMODCACHE", "/go/pkg/mod"). + WithEnvVariable("VERSION", "local"). + WithMountedCache("/go/build-cache", dag.CacheVolume("go-build-122")). + WithEnvVariable("GOCACHE", "/go/build-cache"). + WithEnvVariable("CGO_ENABLED", "0"). + WithExec([]string{"bash", "-c", "KUBELET_VERSION=${VERSION} ./cmd/virtual-kubelet/set-version.sh"}). + WithExec([]string{"go", "build", "-o", "bin/interlink", "cmd/interlink/main.go"}) + + m.InterlinkContainer = dag.Container(). + From("alpine"). + WithFile("/bin/interlink", builder.File("/src/bin/interlink")). + WithEntrypoint([]string{"/bin/interlink"}) + _, err := dag.Container().From("quay.io/skopeo/stable"). WithServiceBinding("registry", m.Registry). - WithMountedFile("image.tar", dag.Container(). - Build(workspace, ContainerBuildOpts{ - Dockerfile: "docker/Dockerfile.vk", - BuildArgs: []BuildArg{ - {"VERSION", vkVersion}, - }, - }).AsTarball()). - WithExec([]string{"copy", "--dest-tls-verify=false", "docker-archive:image.tar", "docker://" + m.VirtualKubeletRef}). + WithMountedFile("image.tar", m.InterlinkContainer.AsTarball()). + WithExec([]string{"copy", "--dest-tls-verify=false", "docker-archive:image.tar", "docker://" + m.InterlinkRef}, dagger.ContainerWithExecOpts{UseEntrypoint: true}). Sync(ctx) if err != nil { return nil, err } + builderVK := dag.Container(). + From("golang:1.22"). + WithDirectory("/src", sourceFolder). + WithWorkdir("/src"). + WithMountedCache("/go/pkg/mod", dag.CacheVolume("go-mod-122")). + WithEnvVariable("GOMODCACHE", "/go/pkg/mod"). + WithEnvVariable("VERSION", "local"). + WithMountedCache("/go/build-cache", dag.CacheVolume("go-build-122")). + WithEnvVariable("GOCACHE", "/go/build-cache"). + WithEnvVariable("CGO_ENABLED", "0"). + WithExec([]string{"bash", "-c", "KUBELET_VERSION=${VERSION} ./cmd/virtual-kubelet/set-version.sh"}). + WithExec([]string{"go", "build", "-o", "bin/vk", "cmd/virtual-kubelet/main.go"}) + + m.VKContainer = dag.Container(). + From("alpine"). + WithFile("/bin/vk", builderVK.File("/src/bin/vk")). + WithEntrypoint([]string{"/bin/vk"}) + _, err = dag.Container().From("quay.io/skopeo/stable"). WithServiceBinding("registry", m.Registry). - WithMountedFile("image.tar", dag.Container(). - Build(workspace, ContainerBuildOpts{ - Dockerfile: "docker/Dockerfile.interlink", - BuildArgs: []BuildArg{ - {"VERSION", vkVersion}, - }, - }).AsTarball()). - WithExec([]string{"copy", "--dest-tls-verify=false", "docker-archive:image.tar", "docker://" + m.InterlinkRef}). + WithMountedFile("image.tar", m.VKContainer.AsTarball()). + WithExec([]string{"copy", "--dest-tls-verify=false", "docker-archive:image.tar", "docker://" + m.VirtualKubeletRef}, dagger.ContainerWithExecOpts{UseEntrypoint: true}). Sync(ctx) if err != nil { return nil, err @@ -309,7 +325,7 @@ func (m *Interlink) BuildImages( // Wait for virtual node to be ready and expose the k8s endpoint as a service func (m *Interlink) Kube( ctx context.Context, -) (*Service, error) { +) (*dagger.Service, error) { return dag.K3S(m.Name).Server(), nil @@ -318,18 +334,14 @@ func (m *Interlink) Kube( // Wait for cluster to be ready, then setup the test container func (m *Interlink) Run( ctx context.Context, -) (*Container, error) { - - // result := m.Kubectl. - // WithWorkdir("/opt"). - // WithExec([]string{"bash", "-c", "python3 -m venv .venv && source .venv/bin/activate && pip3 install -e ./ "}, ContainerWithExecOpts{SkipEntrypoint: true}). - // WithExec([]string{"bash", "-c", "source .venv/bin/activate && export KUBECONFIG=/.kube/config"}, ContainerWithExecOpts{SkipEntrypoint: true}) +) (*dagger.Container, error) { return m.Kubectl. WithWorkdir("/opt/user"). - WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithWorkdir("/opt/user/vk-test-set"), nil + WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}). + WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}). + WithWorkdir("/opt/user/vk-test-set"). + WithExec([]string{"bash", "-c", "python3 -m venv .venv && source .venv/bin/activate && pip3 install -e ./ "}), nil } @@ -337,19 +349,19 @@ func (m *Interlink) Run( func (m *Interlink) Test( ctx context.Context, // +optional - localCluster *Service, + localCluster *dagger.Service, // +optional // +default false //cleanup bool, -) (*Container, error) { +) (*dagger.Container, error) { result := m.Kubectl. WithWorkdir("/opt/user"). - WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}, ContainerWithExecOpts{SkipEntrypoint: true}). + WithExec([]string{"bash", "-c", "git clone https://github.com/interTwin-eu/vk-test-set.git"}). + WithExec([]string{"bash", "-c", "cp /manifests/vktest_config.yaml /opt/user/vk-test-set/vktest_config.yaml"}). WithWorkdir("/opt/user/vk-test-set"). - WithExec([]string{"bash", "-c", "python3 -m venv .venv && source .venv/bin/activate && pip3 install -e ./ "}, ContainerWithExecOpts{SkipEntrypoint: true}). - WithExec([]string{"bash", "-c", "source .venv/bin/activate && export KUBECONFIG=/.kube/config && pytest -vk 'not rclone'"}, ContainerWithExecOpts{SkipEntrypoint: true}) + WithExec([]string{"bash", "-c", "python3 -m venv .venv && source .venv/bin/activate && pip3 install -e ./ "}). + WithExec([]string{"bash", "-c", "source .venv/bin/activate && export KUBECONFIG=/.kube/config && pytest -vk 'not rclone'"}) return result, nil diff --git a/ci/manifests/interlink-config.yaml b/ci/manifests/interlink-config.yaml index a8782bbd..875aecba 100644 --- a/ci/manifests/interlink-config.yaml +++ b/ci/manifests/interlink-config.yaml @@ -1,16 +1,16 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "interlink-config" - namespace: interlink -data: - InterLinkConfig.yaml: | - InterlinkAddress: "http://0.0.0.0" - InterlinkPort: "3000" - #SidecarURL: "http://plugin.interlink.svc.cluster.local" - SidecarURL: "http://plugin" - SidecarPort: "4000" - VerboseLogging: true - ErrorsOnlyLogging: false - ExportPodData: true - DataRootFolder: "~/.interlink" +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: "interlink-config" +# namespace: interlink +# data: +# InterLinkConfig.yaml: | + #InterlinkAddress: "unix:///var/run/interlink.socket" +InterlinkAddress: "http://0.0.0.0" +InterlinkPort: "3000" +SidecarURL: "http://plugin" +SidecarPort: "4000" +VerboseLogging: true +ErrorsOnlyLogging: false +ExportPodData: true +DataRootFolder: "~/.interlink" diff --git a/ci/manifests/interlink.yaml b/ci/manifests/interlink.yaml deleted file mode 100644 index b7a3c048..00000000 --- a/ci/manifests/interlink.yaml +++ /dev/null @@ -1,47 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: interlink - namespace: interlink -spec: - selector: - app: interlink - ports: - - protocol: TCP - port: 3000 - targetPort: 3000 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: interlink - namespace: interlink - labels: - app: interlink -spec: - replicas: 1 - selector: - matchLabels: - app: interlink - template: - metadata: - labels: - app: interlink - spec: - hostNetwork: true - containers: - - name: interlink - image: "ghcr.io/intertwin-eu/interlink/interlink" - imagePullPolicy: Always - env: - - name: CONFIGPATH - value: "/etc/interlink/InterLinkConfig.yaml" - volumeMounts: - - name: config - mountPath: /etc/interlink/InterLinkConfig.yaml - subPath: InterLinkConfig.yaml - volumes: - - name: config - configMap: - # Provide the name of the ConfigMap you want to mount. - name: interlink-config diff --git a/ci/manifests/kustomization.yaml b/ci/manifests/kustomization.yaml index 168dc6f7..8b98ba9d 100644 --- a/ci/manifests/kustomization.yaml +++ b/ci/manifests/kustomization.yaml @@ -1,8 +1,8 @@ resources: - virtual-kubelet-config.yaml - virtual-kubelet.yaml -- interlink-config.yaml -- interlink.yaml +#- interlink-config.yaml +#- interlink.yaml #- plugin-k8s-config.yaml #- plugin.yaml patches: @@ -10,8 +10,4 @@ patches: target: kind: Deployment labelSelector: nodeName=virtual-kubelet -- path: interlink-merge.yaml - target: - kind: Deployment - labelSelector: app=interlink diff --git a/ci/manifests/plugin-config.yaml b/ci/manifests/plugin-config.yaml index 2163d46a..61a766f9 100644 --- a/ci/manifests/plugin-config.yaml +++ b/ci/manifests/plugin-config.yaml @@ -1,4 +1,4 @@ -InterlinkURL: "http://localhost" +InterlinkURL: "http://interlink" InterlinkPort: "3000" SidecarURL: "http://0.0.0.0" SidecarPort: "4000" @@ -6,9 +6,9 @@ VerboseLogging: true ErrorsOnlyLogging: false ExportPodData: true # NEEDED PATH FOR GITHUB ACTIONS -DataRootFolder: "/home/runner/work/interLink/interLink/.interlink/" +#DataRootFolder: "/home/runner/work/interLink/interLink/.interlink/" # on your host use something like: -#DataRootFolder: "/home/ubuntu/.interlink/" +DataRootFolder: "/home/ubuntu/.interlink/" SbatchPath: "/usr/bin/sbatch" ScancelPath: "/usr/bin/scancel" SqueuePath: "/usr/bin/squeue" diff --git a/ci/manifests/virtual-kubelet-config.yaml b/ci/manifests/virtual-kubelet-config.yaml index 4f13b589..7feb69c2 100644 --- a/ci/manifests/virtual-kubelet-config.yaml +++ b/ci/manifests/virtual-kubelet-config.yaml @@ -5,14 +5,15 @@ metadata: namespace: interlink data: InterLinkConfig.yaml: | - InterlinkURL: http://interlink.interlink.svc.cluster.local - InterlinkPort: 3000 + #InterlinkURL: unix:///var/run/interlink.socket + InterlinkURL: "http://interlink" + InterlinkPort: "3000" ExportPodData: true VerboseLogging: true ErrorsOnlyLogging: false ServiceAccount: "virtual-kubelet" Namespace: interlink - VKTokenFile: /dev/null + VKTokenFile: "" CPU: "100" Memory: "128Gi" Pods: "100" diff --git a/ci/manifests/virtual-kubelet.yaml b/ci/manifests/virtual-kubelet.yaml index 51b34a88..8dc1c2e7 100644 --- a/ci/manifests/virtual-kubelet.yaml +++ b/ci/manifests/virtual-kubelet.yaml @@ -15,9 +15,22 @@ spec: labels: nodeName: virtual-kubelet spec: + hostNetwork: true automountServiceAccountToken: true serviceAccountName: virtual-kubelet containers: + # - name: interlink + # image: "ghcr.io/intertwin-eu/interlink/interlink" + # imagePullPolicy: Always + # env: + # - name: INTERLINKCONFIGPATH + # value: "/etc/interlink/InterLinkConfig.yaml" + # volumeMounts: + # - name: il-config + # mountPath: /etc/interlink/InterLinkConfig.yaml + # subPath: InterLinkConfig.yaml + # - name: sockets + # mountPath: /var/run/ - name: inttw-vk image: "ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw" imagePullPolicy: Always @@ -25,7 +38,7 @@ spec: - name: NODENAME value: virtual-kubelet - name: KUBELET_PORT - value: "10250" + value: "10255" - name: POD_IP valueFrom: fieldRef: @@ -36,8 +49,20 @@ spec: - name: config mountPath: /etc/interlink/InterLinkConfig.yaml subPath: InterLinkConfig.yaml + # - name: sockets + # mountPath: /var/run/ volumes: - name: config configMap: # Provide the name of the ConfigMap you want to mount. name: virtual-kubelet-config + - name: sockets + hostPath: + path: /var/run + type: Directory + # - name: il-config + # configMap: + # # Provide the name of the ConfigMap you want to mount. + # name: interlink-config + # - name: sockets + # emptyDir: {} diff --git a/ci/manifests/vktest_config.yaml b/ci/manifests/vktest_config.yaml index 0263a20e..2b02f2cb 100644 --- a/ci/manifests/vktest_config.yaml +++ b/ci/manifests/vktest_config.yaml @@ -10,8 +10,8 @@ timeout_multiplier: 10. values: namespace: interlink - annotations: {} - # slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800 --ntasks=8 --nodes=1 --mem-per-cpu=2000" + annotations: + slurm-job.vk.io/flags: "--job-name=test-pod-cfg -t 2800 --ntasks=8 --nodes=1 --mem-per-cpu=2000" tolerations: - key: virtual-node.interlink/no-schedule diff --git a/cmd/installer/templates/interlink-install.sh b/cmd/installer/templates/interlink-install.sh index 0bff1517..a30d2ca1 100644 --- a/cmd/installer/templates/interlink-install.sh +++ b/cmd/installer/templates/interlink-install.sh @@ -27,8 +27,8 @@ install () { # set $HOME/.interlink/config/InterLinkConfig.yaml cat <>$HOME/.interlink/config/InterLinkConfig.yaml -InterlinkAddress: "http://localhost" -InterlinkPort: "30080" +InterlinkAddress: "unix://${HOME}/.interlink/interlink.sock" +InterlinkPort: "0" SidecarURL: "http://localhost" SidecarPort: "4000" VerboseLogging: true @@ -89,7 +89,7 @@ start() { $HOME/.interlink/bin/oauth2-proxy \ --client-id "{{.OAUTH.ClientID}}" \ --client-secret "\"{{.OAUTH.ClientSecret}}\"" \ - --http-address 0.0.0.0:{{.InterLinkPort}} \ + --http-address unix://${HOME}/.interlink/interlink.sock \ --oidc-issuer-url "{{.OAUTH.Issuer}}" \ --pass-authorization-header true \ --provider oidc \ diff --git a/cmd/interlink/main.go b/cmd/interlink/main.go index 3d6aed56..b24d9801 100644 --- a/cmd/interlink/main.go +++ b/cmd/interlink/main.go @@ -5,9 +5,12 @@ import ( "crypto/tls" "flag" "fmt" + "net" "net/http" "os" + "os/signal" "strings" + "syscall" "time" "github.com/sirupsen/logrus" @@ -134,10 +137,25 @@ func main() { sidecarEndpoint := "" if strings.HasPrefix(interLinkConfig.Sidecarurl, "unix://") { sidecarEndpoint = interLinkConfig.Sidecarurl + // Dial the Unix socket + var conn net.Conn + for { + conn, err = net.Dial("unix", sidecarEndpoint) + if err != nil { + log.G(ctx).Error(err) + time.Sleep(30 * time.Second) + } else { + break + } + } + + http.DefaultTransport.(*http.Transport).DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return conn, nil + } } else if strings.HasPrefix(interLinkConfig.Sidecarurl, "http://") { sidecarEndpoint = interLinkConfig.Sidecarurl + ":" + interLinkConfig.Sidecarport } else { - log.G(ctx).Fatal("Sidecar URL should either start per unix:// or http://") + log.G(ctx).Fatal("Sidecar URL should either start per unix:// or http://: getting ", interLinkConfig.Sidecarurl) } interLinkAPIs := api.InterLinkHandler{ @@ -157,15 +175,39 @@ func main() { interLinkEndpoint := "" if strings.HasPrefix(interLinkConfig.InterlinkAddress, "unix://") { interLinkEndpoint = interLinkConfig.InterlinkAddress + + // Create a Unix domain socket and listen for incoming connections. + socket, err := net.Listen("unix", strings.ReplaceAll(interLinkEndpoint, "unix://", "")) + if err != nil { + panic(err) + } + + // Cleanup the sockfile. + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + os.Remove(strings.ReplaceAll(interLinkEndpoint, "unix://", "")) + os.Exit(1) + }() + server := http.Server{ + Handler: mutex, + } + + log.G(ctx).Info(socket) + + if err := server.Serve(socket); err != nil { + log.G(ctx).Fatal(err) + } } else if strings.HasPrefix(interLinkConfig.InterlinkAddress, "http://") { interLinkEndpoint = strings.Replace(interLinkConfig.InterlinkAddress, "http://", "", -1) + ":" + interLinkConfig.Interlinkport - } else { - log.G(ctx).Fatal("Sidecar URL should either start per unix:// or http://") - } - err = http.ListenAndServe(interLinkEndpoint, mutex) + err = http.ListenAndServe(interLinkEndpoint, mutex) - if err != nil { - log.G(ctx).Fatal(err) + if err != nil { + log.G(ctx).Fatal(err) + } + } else { + log.G(ctx).Fatal("Interlink URL should either start per unix:// or http://. Getting: ", interLinkConfig.InterlinkAddress) } } diff --git a/cmd/ssh-tunnel/main.go b/cmd/ssh-tunnel/main.go new file mode 100644 index 00000000..a4f08f8a --- /dev/null +++ b/cmd/ssh-tunnel/main.go @@ -0,0 +1,95 @@ +package main + +import ( + "flag" + "fmt" + "io" + "log" + "net" + "os" + + "golang.org/x/crypto/ssh" +) + +func runTunnel(local, remote net.Conn) { + defer local.Close() + defer remote.Close() + done := make(chan struct{}, 2) + + go func() { + io.Copy(local, remote) + done <- struct{}{} + }() + + go func() { + io.Copy(remote, local) + done <- struct{}{} + }() + + <-done +} + +func main() { + addr := flag.String("addr", "", "ssh server address to dial as :") + username := flag.String("user", "", "username for ssh") + keyFile := flag.String("keyfile", "", "file with private key for SSH authentication") + remotePort := flag.String("rport", "", "remote port for tunnel") + localSocket := flag.String("lsock", "", "local socket for tunnel") + flag.Parse() + + // Implement a HostKeyCallback to verify the server's host key + hostKeyCallback := ssh.InsecureIgnoreHostKey() // This is insecure and should be replaced with proper host key verification + + key, err := os.ReadFile(*keyFile) + if err != nil { + log.Fatalf("unable to read private key: %v", err) + } + signer, err := ssh.ParsePrivateKey(key) + if err != nil { + log.Fatalf("unable to parse private key: %v", err) + } + // An SSH client is represented with a ClientConn. + // + // To authenticate with the remote server you must pass at least one + // implementation of AuthMethod via the Auth field in ClientConfig, + // and provide a HostKeyCallback. + config := &ssh.ClientConfig{ + User: *username, + Auth: []ssh.AuthMethod{ + ssh.PublicKeys(signer), + }, + HostKeyCallback: hostKeyCallback, + } + + client, err := ssh.Dial("tcp", *addr, config) + if err != nil { + log.Fatal("Failed to dial: ", err) + } + defer client.Close() + + listener, err := client.Listen("tcp", "localhost:"+*remotePort) + if err != nil { + log.Fatalf("Failed to listen on remote socket %s: %v", *remotePort, err) + } + defer listener.Close() + log.Printf("Listening on remote socket %s", *remotePort) + for { + remote, err := listener.Accept() + if err != nil { + log.Printf("Failed to accept connection on remote socket %s: %v", *remotePort, err) + continue + } + log.Printf("Accepted connection on remote socket %s", *remotePort) + go func() { + local, err := net.Dial("unix", *localSocket) + if err != nil { + log.Printf("Failed to dial local socket %s: %v", *localSocket, err) + remote.Close() + return + } + log.Printf("Connected to local socket %s", *localSocket) + fmt.Println("tunnel established with", local.LocalAddr()) + runTunnel(local, remote) + }() + } +} diff --git a/cmd/virtual-kubelet/main.go b/cmd/virtual-kubelet/main.go index ab63153d..a0a200df 100644 --- a/cmd/virtual-kubelet/main.go +++ b/cmd/virtual-kubelet/main.go @@ -24,6 +24,7 @@ import ( "os" "path" "strconv" + "strings" "time" // "k8s.io/client-go/rest" @@ -185,6 +186,8 @@ func main() { } log.L = logruslogger.FromLogrus(logrus.NewEntry(logger)) + log.G(ctx).Info("Config dump", interLinkConfig) + if os.Getenv("ENABLE_TRACING") == "1" { shutdown, err := initProvider(ctx) if err != nil { @@ -207,6 +210,25 @@ func main() { http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + if strings.HasPrefix(interLinkConfig.InterlinkURL, "unix://") { + // Dial the Unix socket + interLinkEndpoint := strings.Replace(interLinkConfig.InterlinkURL, "unix://", "", -1) + var conn net.Conn + for { + conn, err = net.Dial("unix", interLinkEndpoint) + if err != nil { + log.G(ctx).Error(err) + time.Sleep(30 * time.Second) + } else { + break + } + } + + http.DefaultTransport.(*http.Transport).DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return conn, nil + } + } + dport, err := strconv.ParseInt(os.Getenv("KUBELET_PORT"), 10, 32) if err != nil { log.G(ctx).Fatal(err) @@ -357,8 +379,10 @@ func main() { // TODO: create a csr auto approver https://github.com/liqotech/liqo/blob/master/cmd/liqo-controller-manager/main.go#L498 retriever := commonIL.NewSelfSignedCertificateRetriever(cfg.NodeName, net.ParseIP(cfg.InternalIP)) + kubeletPort := os.Getenv("KUBELET_PORT") + server := &http.Server{ - Addr: fmt.Sprintf("0.0.0.0:%d", 10250), + Addr: fmt.Sprintf("0.0.0.0:%s", kubeletPort), Handler: mux, ReadHeaderTimeout: 10 * time.Second, // Required to limit the effects of the Slowloris attack. TLSConfig: &tls.Config{ diff --git a/docker-plugin b/docker-plugin deleted file mode 100755 index ebda63fa..00000000 Binary files a/docker-plugin and /dev/null differ diff --git a/docs/README.md b/docs/README.md index 0c6c2c27..54f2f221 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ $ yarn ### Local Development ``` -$ yarn start +$ yarn start --config docusaurus.config.local.ts ``` This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. diff --git a/docs/docs/Cookbook.mdx b/docs/docs/Cookbook.mdx new file mode 100644 index 00000000..0c4d6641 --- /dev/null +++ b/docs/docs/Cookbook.mdx @@ -0,0 +1,452 @@ +--- +sidebar_position: 3 +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + + +# Cookbook + +These are practical recipes for different deployment scenarios. + +Select here the tab with the scenario you want deploy: + + + + + + + + + + + + + +Select here the featured plugin you want to try: + + + + Offload your pods to a remote machine with Docker engine available + + + Offload your pods to an HPC SLURM based batch system + + + Offload your pods to a remote Kubernetes cluster: COMING SOON + For test instructions contact us! + + + +There are more 3rd-party plugins developed that you can get inspired by or even use out of the box. You can find some ref in the [quick start section](guides/deploy-interlink#attach-your-favorite-plugin-or-develop-one) + +## Install interLink + +### Deploy Remote components (if any) + +In general, starting from the deployment of the remote components is adviced. Since the kubernetes virtual node won't reach the `Ready` status until all the stack is successfully deployed. + +#### Interlink API server + + + + __For this deployment mode the remote host has to allow the kubernetes cluster to connect to the Oauth2 proxy service port (30443 if you use the automatic script for installation)__ + + - You first need to initialize an OIDC client with you Identity Provider (IdP). + - Different options. We have instructions ready for [GitHub](./guides/deploy-interlink#create-an-oauth-github-app), [EGI checkin](./guides/oidc-IAM), [INFN IAM](./guides/oidc-IAM). + - Any OIDC provider working with [OAuth2 Proxy](https://oauth2-proxy.github.io/oauth2-proxy/) tool will do the work though. + - Create the `install.sh` utility script through the [installation utility](./guides/deploy-interlink#configuring-your-virtual-kubelet-setup) + - __N.B.__ if your machine is shared with other users, you better indicate a socket as address to communicate with the plugin. Instead of a web URL is enough to insert something like `unix:///var/run/myplugin.socket` + - Install Oauth2-Proxy and interLink API server services as per [Quick start](./deploy-interlink#deploy-the-interlink-core-components) + - by default logs are store in `~/.interlink/logs`, checkout there for any error before moving to the next step. + + + Go directly to ["Test and debugging tips"](Cookbook#test-and-debug). The selected scenario does not expect you to do anything here. + + + - Create a service trying to keep the tunnel with the kubernete cluster alive (__THIS WILL CORRECTLY FAIL__ until we setup all the stack) + - Create utility folders: + + ```bash + mkdir -p $HOME/.interlink/logs + mkdir -p $HOME/.interlink/bin + mkdir -p $HOME/.interlink/config + ``` + - Generate a pair of SSH keys: + - Download the [latest release]() binary in `$HOME/.interlink/bin/ssh-tunnel` + - Start the tunnel + + ```bash + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + ``` + + - Check the logs in `$HOME/.interlink/logs/plu.log`. + - To kill and restart the process is enough: + + ```bash + # kill + kill $(cat $HOME/.interlink/plugin.pid) + + # restart + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + - Download out tunnel utility here: + - Create a user-level systemd unit for keeping the tunnel alive (**if you don't have systemd you can easily take the logic from the code below and translates it into whatever system you have**). + + + + +#### Plugin service + + + + + + + - Create a configuration file: + + ```bash title="./plugin-config.yaml" + ## Multi user host + # SidecarURL: "unix:///home/myusername/plugin.socket" + # InterlinkPort: "0" + # SidecarPort: "0" + + ## Dedicated edge node + # InterlinkURL: "http://127.0.0.1" + # SidecarURL: "http://127.0.0.1" + # InterlinkPort: "3000" + # SidecarPort: "4000" + + CommandPrefix: "" + ExportPodData: true + DataRootFolder: "/home/myusername/.interlink/jobs/" + BashPath: /bin/bash + VerboseLogging: true + ErrorsOnlyLogging: false + ``` + - __N.B.__ Depending on wheter you edge is single user or not, you should know by previous steps which section to uncomment here. + - More on configuration options at [official repo](https://github.com/interTwin-eu/interlink-docker-plugin/blob/main/README.md) + + - Create utility folders: + + ```bash + mkdir -p $HOME/.interlink/logs + mkdir -p $HOME/.interlink/bin + mkdir -p $HOME/.interlink/config + ``` + - Download the [latest release](https://github.com/interTwin-eu/interlink-docker-plugin/releases) binary in `$HOME/.interlink/bin/plugin` for either GPU host or CPU host (tags ending with `no-GPU`) + - Start the plugins passing the configuration that you have just created: + + ```bash + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + ``` + + - Check the logs in `$HOME/.interlink/logs/plugin.log`. + - To kill and restart the process is enough: + + ```bash + # kill + kill $(cat $HOME/.interlink/plugin.pid) + + # restart + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + + Almost there! Now it's time to add this virtual node into the Kubernetes cluster! + + + - Create a configuration file: + + ```bash title="./plugin-config.yaml" + ## Multi user host + # SidecarURL: "unix:///home/myusername/plugin.socket" + # InterlinkPort: "0" + # SidecarPort: "0" + + ## Dedicated edge node + # InterlinkURL: "http://127.0.0.1" + # SidecarURL: "http://127.0.0.1" + # InterlinkPort: "3000" + # SidecarPort: "4000" + + CommandPrefix: "" + ExportPodData: true + DataRootFolder: "/home/myusername/.interlink/jobs/" + BashPath: /bin/bash + VerboseLogging: true + ErrorsOnlyLogging: false + SbatchPath: "/usr/bin/sbatch" + ScancelPath: "/usr/bin/scancel" + SqueuePath: "/usr/bin/squeue" + SingularityPrefix: "" + ``` + - __N.B.__ Depending on wheter you edge is single user or not, you should know by previous steps which section to uncomment here. + - More on configuration options at [official repo](https://github.com/interTwin-eu/interlink-slurm-plugin/blob/main/README.md) + + - Create utility folders + + ```bash + mkdir -p $HOME/.interlink/logs + mkdir -p $HOME/.interlink/bin + mkdir -p $HOME/.interlink/config + ``` + - Download the [latest release](https://github.com/interTwin-eu/interlink-slurm-plugin/releases) binary in `$HOME/.interlink/bin/plugin` for either GPU host or CPU host (tags ending with `no-GPU`) + - Start the plugins passing the configuration that you have just created: + + ```bash + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + ``` + + - Check the logs in `$HOME/.interlink/logs/plugin.log`. + - To kill and restart the process is enough: + + ```bash + # kill + kill $(cat $HOME/.interlink/plugin.pid) + + # restart + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + + Almost there! Now it's time to add this virtual node into the Kubernetes cluster! + + + __KUBERNTES PLUGIN COMING SOOON... CONTACT US FOR TEST INSTRUCTIONS__ + + + + + + Go directly to ["Test and debugging tips"](Cookbook#test-and-debug). The selected scenario does not expect you to do anything here. + + + + + + - Create a configuration file: + + ```bash title="./plugin-config.yaml" + SidecarURL: "unix:///home/myusername/plugin.socket" + SidecarPort: "0" + + CommandPrefix: "" + ExportPodData: true + DataRootFolder: "/home/myusername/.interlink/jobs/" + BashPath: /bin/bash + VerboseLogging: true + ErrorsOnlyLogging: false + ``` + - __N.B.__ you should know by previous steps what to put in place of `myusername` here. + - More on configuration options at [official repo](https://github.com/interTwin-eu/interlink-docker-plugin/blob/main/README.md) + + - Create utility folders: + + ```bash + mkdir -p $HOME/.interlink/logs + mkdir -p $HOME/.interlink/bin + mkdir -p $HOME/.interlink/config + ``` + - Download the [latest release](https://github.com/interTwin-eu/interlink-docker-plugin/releases) binary in `$HOME/.interlink/bin/plugin` for either GPU host or CPU host (tags ending with `no-GPU`) + - Start the plugins passing the configuration that you have just created: + + ```bash + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + ``` + + - Check the logs in `$HOME/.interlink/logs/plugin.log`. + - To kill and restart the process is enough: + + ```bash + # kill + kill $(cat $HOME/.interlink/plugin.pid) + + # restart + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + + Almost there! Now it's time to add this virtual node into the Kubernetes cluster! + + + - Create a configuration file: + + ```bash title="./plugin-config.yaml" + SidecarURL: "unix:///home/myusername/plugin.socket" + SidecarPort: "0" + + CommandPrefix: "" + ExportPodData: true + DataRootFolder: "/home/myusername/.interlink/jobs/" + BashPath: /bin/bash + VerboseLogging: true + ErrorsOnlyLogging: false + SbatchPath: "/usr/bin/sbatch" + ScancelPath: "/usr/bin/scancel" + SqueuePath: "/usr/bin/squeue" + SingularityPrefix: "" + ``` + - __N.B.__ you should know by previous steps what to put in place of `myusername` here. + - More on configuration options at [official repo](https://github.com/interTwin-eu/interlink-slurm-plugin/blob/main/README.md) + - Create utility folders: + + ```bash + mkdir -p $HOME/.interlink/logs + mkdir -p $HOME/.interlink/bin + mkdir -p $HOME/.interlink/config + ``` + - Download the [latest release](https://github.com/interTwin-eu/interlink-slurm-plugin/releases) binary in `$HOME/.interlink/bin/plugin` for either GPU host or CPU host (tags ending with `no-GPU`) + - Start the plugins passing the configuration that you have just created: + + ```bash + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + ``` + + - Check the logs in `$HOME/.interlink/logs/plugin.log`. + - To kill and restart the process is enough: + + ```bash + # kill + kill $(cat $HOME/.interlink/plugin.pid) + + # restart + export INTERLINKCONFIGPATH=$PWD/plugin-config.yaml + $HOME/.interlink/bin/plugin &> $HOME/.interlink/logs/plugin.log & + echo $! > $HOME/.interlink/plugin.pid + + Almost there! Now it's time to add this virtual node into the Kubernetes cluster! + + + COMING SOOON... + + + + + + + +### Deploy Kubernetes components + +The deployment of the Kubernetes components are managed by the official [HELM chart](https://github.com/interTwin-eu/interlink-helm-chart). Depending on the scenario you selected, there might be additional operations to be done. + + + + __For this deployment mode the remote host has to allow the kubernetes cluster to connect to the Oauth2 proxy service port (30443 if you use the automatic script for installation)__ + + - Since you might already have followed the installation script steps, you can simply follow the [Guide](./guides/deploy-interlink#deploy-the-interlink-kubernetes-agent-kubeclt-host) + + __If the installation script is not what you are currently used, you can configure the virtual kubelet manually:__ + - Create an helm values file: + + ```yaml title="values.yaml" + nodeName: interlink-with-rest + + interlink: + address: https://remote_oauth2_proxy_endpoint + port: 30443 + + virtualNode: + CPUs: 1000 + MemGiB: 1600 + Pods: 100 + HTTPProxies: + HTTP: null + HTTPs: null + OAUTH: + image: ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw-refresh:latest + TokenURL: DUMMY + ClientID: DUMMY + ClientSecret: DUMMY + RefreshToken: DUMMY + GrantType: authorization_code + Audience: DUMMY + ``` + - Substitute the OAuth value accordingly as + + + - Create an helm values file: + + ```yaml title="values.yaml" + nodeName: interlink-with-socket + + plugin: + enabled: true + image: "plugin docker image here" + command: ["/bin/bash", "-c"] + args: ["/app/plugin"] + config: | + your plugin + configuration + goes here!!! + socket: unix:///var/run/plugin.socket + + interlink: + enabled: true + socket: unix:///var/run/interlink.socket + ``` + + + - Create an helm values file: + + ```yaml title="values.yaml" + nodeName: interlink-with-socket + + interlink: + enabled: true + socket: unix:///var/run/interlink.socket + + sshBastion: + enabled: true + clientKeys: + authorizedKey: | + ssh-rsa A..........MG0yNvbLfJT+37pw== + port: 31021 + ``` + - insert the plublic key generated when installing interlink and ssh tunnel service + + + +Eventually deploy the latest release of the official [helm chart](https://github.com/interTwin-eu/interlink-helm-chart): + +```bash +helm upgrade --install --create-namespace -n interlink my-virtual-node oci://ghcr.io/intertwin-eu/interlink-helm-chart/interlink --values ./values.yaml +``` + +Whenever you see the node ready, you are good to go! + +## Test the setup + +Please find a demo pod to test your setup [here](./guides/develop-a-plugin#lets-test-is-out). + + diff --git a/docs/docs/Developers.md b/docs/docs/Developers.md index d8310508..61ef887f 100644 --- a/docs/docs/Developers.md +++ b/docs/docs/Developers.md @@ -1,5 +1,5 @@ --- -sidebar_position: 3 +sidebar_position: 5 --- # E2E integration tests @@ -9,7 +9,7 @@ Here you can find how to test a virtual kubelet implementation against the main ## Requirements - [Docker engine](https://docs.docker.com/engine/install/) -- [Dagger CLI v0.11.9](https://docs.dagger.io/install/) +- [Dagger CLI v0.13.x](https://docs.dagger.io/install/) ## What's in the Dagger module @@ -26,6 +26,8 @@ That means you can test your code **before** any commit, discovering in advance ### Run e2e tests +The easiest way is to simply run `make test` from the root folder of interlink. But if you need to debug or understand further the test utility or a plugin, you should follow these instructions. + #### Edit manifests with your images - `service-account.yaml` is the default set of permission needed by the virtualkubelet. Do not touch unless you know what you are doing. @@ -41,7 +43,7 @@ That means you can test your code **before** any commit, discovering in advance For a simple demonstration, you can use the plugin that we actually use in are Github Actions: ```bash -wget https://github.com/interTwin-eu/interlink-docker-plugin/releases/download/0.0.22-no-gpu/docker-plugin_Linux_x86_64 -O docker-plugin \ +wget https://github.com/interTwin-eu/interlink-docker-plugin/releases/download/0.0.24-no-gpu/docker-plugin_Linux_x86_64 -O docker-plugin \ && chmod +x docker-plugin \ && docker ps \ && export INTERLINKCONFIGPATH=$PWD/ci/manifests/plugin-config.yaml \ @@ -63,10 +65,8 @@ To run the default tests you can move to `ci` folder and execute the Dagger pipe dagger call \ --name my-tests \ build-images \ - --source-folder ../ \ new-interlink \ --plugin-endpoint tcp://localhost:4000 \ - --manifests ./manifests \ test stdout ``` @@ -103,9 +103,7 @@ In case something went wrong, you have the possibility to spawn a session inside dagger call \ --name my-tests \ build-images \ - --source-folder ../ \ new-interlink \ - --manifests ./manifests \ --plugin-endpoint tcp://localhost:4000 \ run terminal @@ -133,9 +131,7 @@ You can get the Kubernetes service running with: dagger call \ --name my-tests \ build-images \ - --source-folder ../ \ new-interlink \ - --manifests ./manifests \ --plugin-endpoint tcp://localhost:4000 \ kube up ``` diff --git a/docs/docs/Limitations.md b/docs/docs/Limitations.md index ea129510..06b99e66 100644 --- a/docs/docs/Limitations.md +++ b/docs/docs/Limitations.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 6 --- # Current limitations diff --git a/docs/docs/arch.mdx b/docs/docs/arch.mdx new file mode 100644 index 00000000..5ad980e7 --- /dev/null +++ b/docs/docs/arch.mdx @@ -0,0 +1,24 @@ +--- +sidebar_position: 2 +--- +import ThemedImage from '@theme/ThemedImage'; +import useBaseUrl from '@docusaurus/useBaseUrl'; + +# Architecture + +InterLink aims to provide an abstraction for the execution of a Kubernetes pod on any remote resource capable of managing a Container execution lifecycle. + +The project consists of two main components: + +- __A Kubernetes Virtual Node:__ based on the [VirtualKubelet](https://virtual-kubelet.io/) technology. Translating request for a kubernetes pod execution into a remote call to the interLink API server. +- __The interLink API server:__ a modular and pluggable REST server where you can create your own Container manager plugin (called sidecars), or use the existing ones: remote docker execution on a remote host, singularity Container on a remote SLURM batch system. + +The project got inspired by the [KNoC](https://github.com/CARV-ICS-FORTH/knoc) and [Liqo](https://github.com/liqotech/liqo/tree/master) projects, enhancing that with the implemention a generic API layer b/w the virtual kubelet component and the provider logic for the container lifecycle management. + + diff --git a/docs/docs/tutorial-admins/01-deploy-interlink.mdx b/docs/docs/guides/01-deploy-interlink.mdx similarity index 86% rename from docs/docs/tutorial-admins/01-deploy-interlink.mdx rename to docs/docs/guides/01-deploy-interlink.mdx index 18b35a77..da656b63 100644 --- a/docs/docs/tutorial-admins/01-deploy-interlink.mdx +++ b/docs/docs/guides/01-deploy-interlink.mdx @@ -8,22 +8,24 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; Learn how to deploy interLink virtual nodes on your cluster. In this tutorial you are going to setup all the needed components to be able to either __develop__ or __deploy__ the plugin for container management on a **remote** host via a **local** kubernetes cluster. -The installation script that we are going to configure will take care of providing you with a complete Kubernetes manifest to instantiate the virtual node interface. Also you will get an installation bash script to be executed on the remote host where you want to delegate your container execution. That script is already configured to **automatically** authenticate the incoming request from the virtual node component, and forward the correct instructions to the openAPI interface of the [interLink plugin](./03-api-reference.mdx) (a.k.a. sidecar) of your choice. Thus you can use this setup also for directly [developing a plugin](./02-develop-a-plugin.md), without caring for anything else. +The installation script that we are going to configure will take care of providing you with a complete Kubernetes manifest to instantiate the virtual node interface. Also you will get an installation bash script to be executed on the remote host where you want to delegate your container execution. That script is already configured to **automatically** authenticate the incoming request from the virtual node component, and forward the correct instructions to the openAPI interface of the [interLink plugin](/api-reference) (a.k.a. sidecar) of your choice. Thus you can use this setup also for directly [developing a plugin](/develop-a-plugin), without caring for anything else. + +For a complete guide on all the possible scenarios, please refer to the [Cookbook](/cookbook). ## Requirements -- MiniKube +- __kubectl host__: an host with MiniKube installed and running - A GitHub account -- A "remote" machine with a port that is reachable by the MiniKube host +- __remote host__: A "remote" machine with a port that is reachable by the MiniKube host :::danger -In this tutorial, we suppose the remote VM fully owned (not shared) by the user only. There is NO protection against call to the interLink services coming from the machine itself on the localhost. If you need to install it in a "multi user" environment, please refer to [this guide](./05-multi-user.md) +In this tutorial, we suppose the remote VM fully owned (not shared) by the user only. There is NO protection against call to the interLink services coming from the machine itself on the localhost. If you need to install it in a "multi user" environment, please refer to [this guide](/guides/multi-user) ::: ## Create an OAuth GitHub app :::warning -In this tutorial GitHub tokens are just an example of authentication mechanism, any OpenID compliant identity provider is also supported with the very same deployment script, see [examples here](./04-oidc-IAM.md). +In this tutorial GitHub tokens are just an example of authentication mechanism, any OpenID compliant identity provider is also supported with the very same deployment script, see [examples here](./oidc-IAM). ::: As a first step, you need to create a GitHub OAuth application to allow interLink to make authentication between your Kubernetes cluster and the remote endpoint. @@ -66,9 +68,9 @@ You can click then on your application that should now appear at [https://github Now it's all set for the next steps. -## Configuring your virtual kubelet setup +## Configuring your virtual kubelet setup (remote host) -You can download the interLink **installer CLI** for your OS and processor architecture from the [release page](https://github.com/interTwin-eu/interLink/releases), looking for the binaries starting with `interlink-install`. For instance, if on a `Linux` platform with `x86_64` processor: +Login into the machine and and download the interLink **installer CLI** for your OS and processor architecture from the [release page](https://github.com/interTwin-eu/interLink/releases), looking for the binaries starting with `interlink-install`. For instance, if on a `Linux` platform with `x86_64` processor: ```bash export VERSION=0.2.3-pre6 @@ -90,7 +92,7 @@ Let's take the following as an example of a valid configuration file: see [release page](https://github.com/interTwin-eu/interLink/releases) to get the latest one! And change the value accordingly! ::: -```yaml +```yaml title="$HOME/.interlink.yaml" interlink_ip: 192.168.1.127 interlink_port: 30443 interlink_version: 0.2.1-patch2 @@ -128,9 +130,10 @@ This config file has the following meaning: You are ready now to go ahead generating the needed manifests and script for the deployment. -## Deploy the interlink Kubernetes Agent -Generate the manifests and the automatic interlink installation script with: +## Deploy the interLink core components (remote host) + +Login into the machine and generate the manifests and the automatic interlink installation script with: ```bash ./interlink-install @@ -155,27 +158,8 @@ please enter code XXXX-XXXX at https://github.com/login/device "./interlink-remote.sh install" followed by "interlink-remote.sh start" ``` -We are almost there! Essentially you need to follow what suggested by the prompt. - -So go ahead and apply the produced manifest to your minikube/kubernetes instance with: - -```bash -kubectl apply -f $HOME/.interlink/interlink.yaml -``` - -Check that the node appears successfully after some time, or as soon as you see the pods in namespace `interlink` running. - -You are now ready to setup the second component on the remote host. -## Deploy the interLink core components - -Copy the `$HOME/.interlink/interlink-remote.sh` file on the remote host: - -```bash -scp -r $HOME/.interlink/interlink-remote.sh ubuntu@192.168.1.127:~ -``` - -Then login into the machine and start installing all the needed binaries and configurations: +Start installing all the needed binaries and configurations: ```bash chmod +x ./interlink-remote.sh @@ -203,9 +187,9 @@ To stop or restart the components you can use the dedicated commands: ./interlink-remote.sh restart ``` -## Attach your favorite plugin or develop one! +## Attach your favorite plugin or develop one! (remote host) -[Next chapter](./02-develop-a-plugin.md) will show the basics for developing a new plugin following the interLink openAPI spec. +[Next chapter](/develop-a-plugin) will show the basics for developing a new plugin following the interLink openAPI spec. In alterative you can start an already supported one. @@ -226,7 +210,7 @@ Note that the SLURM plugin repository is: [github.com/interTwin-eu/interlink-slu Create a config file `$HOME/.interlink/config/slurm.yaml`: -```yaml +```yaml title="$HOME/.interlink/config/slurm.yaml" # Plugin local endpoint SidecarPort: "4000" SidecarURL: "http://localhost" @@ -314,7 +298,7 @@ Logs will be stored at `$HOME/.interlink/logs/plugin.log`. :::warning An mantained plugin will come soon... -In the meantime you can take a look at the ["developing a plugin"](./02-develop-a-plugin.md) example. +In the meantime you can take a look at the ["developing a plugin"](./develop-a-plugin) example. ::: - [Docker plugin repository](https://github.com/interTwin-eu/interlink-docker-plugin) @@ -328,6 +312,20 @@ Coming soon - [HTCondor plugin repository](https://github.com/interTwin-eu/interlink-htcondor-plugin) - [ARC plugin repository](https://github.com/interTwin-eu/interlink-arc-plugin) +## Deploy the interlink Kubernetes Agent (kubeclt host) + +We are almost there! Essentially you need to follow what suggested by the prompt of the installation script, so copy the generated `interlink.yaml` into you __kubectl host__. + +So go ahead and apply the produced manifest to your minikube/kubernetes instance with: + +```bash +kubectl apply -f $HOME/.interlink/interlink.yaml +``` + +Check that the node appears successfully after some time, or as soon as you see the pods in namespace `interlink` running. + +You are all setup, congratulations! + ## Test your setup -Please find a demo pod to test your setup [here](https://intertwin-eu.github.io/interLink/docs/tutorial-admins/develop-a-plugin#lets-test-is-out). +Please find a demo pod to test your setup [here](./develop-a-plugin#lets-test-is-out). diff --git a/docs/docs/tutorial-admins/02-develop-a-plugin.md b/docs/docs/guides/02-develop-a-plugin.md similarity index 99% rename from docs/docs/tutorial-admins/02-develop-a-plugin.md rename to docs/docs/guides/02-develop-a-plugin.md index ed35d606..30039512 100644 --- a/docs/docs/tutorial-admins/02-develop-a-plugin.md +++ b/docs/docs/guides/02-develop-a-plugin.md @@ -37,7 +37,7 @@ Then you are ready to install the python SDK with: #pip install "uvicorn[standard]" "git+https://github.com/interTwin-eu/interLink.git@${VERSION}#egg=interlink&subdirectory=example" # Or download the latest one with -pip install "uvicorn[standard]" "git+https://github.com/interTwin-eu/interLink.git#egg=interlink&subdirectory=example" +pip install "uvicorn[standard]" "git+https://baltig.infn.it/mgattari/interlink-plugin-sdk" ``` diff --git a/docs/docs/tutorial-admins/03-api-reference.mdx b/docs/docs/guides/03-api-reference.mdx similarity index 100% rename from docs/docs/tutorial-admins/03-api-reference.mdx rename to docs/docs/guides/03-api-reference.mdx diff --git a/docs/docs/tutorial-admins/04-oidc-IAM.md b/docs/docs/guides/04-oidc-IAM.md similarity index 100% rename from docs/docs/tutorial-admins/04-oidc-IAM.md rename to docs/docs/guides/04-oidc-IAM.md diff --git a/docs/docs/tutorial-admins/05-multi-user.md b/docs/docs/guides/05-multi-user.md similarity index 100% rename from docs/docs/tutorial-admins/05-multi-user.md rename to docs/docs/guides/05-multi-user.md diff --git a/docs/docs/tutorial-admins/06-monitoring.md b/docs/docs/guides/06-monitoring.md similarity index 100% rename from docs/docs/tutorial-admins/06-monitoring.md rename to docs/docs/guides/06-monitoring.md diff --git a/docs/docs/tutorial-admins/_category_.json b/docs/docs/guides/_category_.json similarity index 90% rename from docs/docs/tutorial-admins/_category_.json rename to docs/docs/guides/_category_.json index c695e306..5d7733a7 100644 --- a/docs/docs/tutorial-admins/_category_.json +++ b/docs/docs/guides/_category_.json @@ -1,6 +1,6 @@ { "label": "Guides", - "position": 2, + "position": 4, "link": { "type": "generated-index", "description": "Learn how to deploy and adapt interLink plugins for your use case." diff --git a/docs/docs/tutorial-admins/img/dashboard.png b/docs/docs/guides/img/dashboard.png similarity index 100% rename from docs/docs/tutorial-admins/img/dashboard.png rename to docs/docs/guides/img/dashboard.png diff --git a/docs/docs/tutorial-admins/img/docsVersionDropdown.png b/docs/docs/guides/img/docsVersionDropdown.png similarity index 100% rename from docs/docs/tutorial-admins/img/docsVersionDropdown.png rename to docs/docs/guides/img/docsVersionDropdown.png diff --git a/docs/docs/tutorial-admins/img/iam-client0.png b/docs/docs/guides/img/iam-client0.png similarity index 100% rename from docs/docs/tutorial-admins/img/iam-client0.png rename to docs/docs/guides/img/iam-client0.png diff --git a/docs/docs/tutorial-admins/img/iam-client1.png b/docs/docs/guides/img/iam-client1.png similarity index 100% rename from docs/docs/tutorial-admins/img/iam-client1.png rename to docs/docs/guides/img/iam-client1.png diff --git a/docs/docs/tutorial-admins/img/iam-client2.png b/docs/docs/guides/img/iam-client2.png similarity index 100% rename from docs/docs/tutorial-admins/img/iam-client2.png rename to docs/docs/guides/img/iam-client2.png diff --git a/docs/docs/tutorial-admins/img/localeDropdown.png b/docs/docs/guides/img/localeDropdown.png similarity index 100% rename from docs/docs/tutorial-admins/img/localeDropdown.png rename to docs/docs/guides/img/localeDropdown.png diff --git a/docs/docs/tutorial-admins/img/vk_tracing.png b/docs/docs/guides/img/vk_tracing.png similarity index 100% rename from docs/docs/tutorial-admins/img/vk_tracing.png rename to docs/docs/guides/img/vk_tracing.png diff --git a/docs/docs/intro.mdx b/docs/docs/intro.mdx index b01d6661..be4358b1 100644 --- a/docs/docs/intro.mdx +++ b/docs/docs/intro.mdx @@ -12,21 +12,67 @@ interLink is in early development phase, thus subject to breaking changes with n ::: -## Overview -# -InterLink aims to provide an abstraction for the execution of a Kubernetes pod on any remote resource capable of managing a Container execution lifecycle. +## Targets -The project consists of two main components: +- __K8s applications with tasks to be executed on HPC systems__: This target focuses on Kubernetes applications that require high-performance computing (HPC) resources for executing tasks. These tasks might involve complex computations, simulations, or data processing that benefit from the specialized hardware and optimized performance of HPC systems. -- __A Kubernetes Virtual Node:__ based on the [VirtualKubelet](https://virtual-kubelet.io/) technology. Translating request for a kubernetes pod execution into a remote call to the interLink API server. -- __The interLink API server:__ a modular and pluggable REST server where you can create your own Container manager plugin (called sidecars), or use the existing ones: remote docker execution on a remote host, singularity Container on a remote SLURM batch system. +- __Remote "runner"-like application for heavy payload execution requiring GPUs__: This target is designed for applications that need to execute heavy computational payloads, particularly those requiring GPU resources. These applications can be run remotely, leveraging powerful GPU hardware to handle tasks such as machine learning model training, data analysis, or rendering. -The project got inspired by the [KNoC](https://github.com/CARV-ICS-FORTH/knoc) and [Liqo](https://github.com/liqotech/liqo/tree/master) projects, enhancing that with the implemention a generic API layer b/w the virtual kubelet component and the provider logic for the container lifecycle management. +- __Lambda-like functions calling on external resources__: This target involves running containers on demand with specific computing needs. Now these resources might also be outside of the Kubernetes cluster thanks to interLink functionality. + +## Target providers + +Our solution is designed to target a wide range of providers with container execution capabilities, including but not limited to: + +- __SLURM or HTCondor batch systems with Apptainer, Enroot, or Singularity__: These batch systems are widely used in high-performance computing environments to manage and schedule jobs. By integrating with container runtimes like Apptainer, Enroot, or Singularity, our solution can efficiently execute containerized tasks on these systems. +- __Remote/on-demand virtual machines with any container runtime__: This includes virtual machines that can be provisioned on-demand and support container runtimes such as Docker, Podman, or others. This flexibility allows for scalable and dynamic resource allocation based on workload requirements. +- __Remote Kubernetes clusters__: Our solution can extend the capabilities of existing Kubernetes clusters, enabling them to offload workloads to another remote cluster. This is particularly useful for distributing workloads across multiple clusters for better resource utilization and fault tolerance. +- __Lambda-like services__: These are serverless computing services that execute code in response to events and automatically manage the underlying compute resources. By targeting these services, our solution can leverage the scalability and efficiency of serverless architectures for containerized workloads. All of this, while exposing a bare Kubernetes API kind of orchestration. + +## NOT a target + +- __Long-running services__: Our solution is not designed for services that need to run continuously for extended periods. It is optimized for tasks that have a defined start and end, rather than persistent services exposing intra-cluster communication endpoints. +- __Kubernetes Federation__: We do not aim to support Kubernetes Federation, which involves managing multiple Kubernetes clusters as a single entity. Our focus is on enabling Kubernetes pods to execute on remote resources, not on federating all kind of resources on multiple clusters. + + +## Deployment scenarios + +### In-cluster mode + +This scenario involves deploying a Virtual Kubelet along with the interLink API server and the plugin to interact with a remote API. This setup allows Kubernetes pods to be executed on remote resources while all other components sits inside the Kubernetes cluster. + + + + +### Service remote edge node + +In this scenario, the Virtual Kubelet communicates with remote services deployed on a dedicate edge node exposing authenticated interLink APIs and its associated plugin. This setup is ideal for scenarios where edge computing resources are utilized for controlled communication b/w the Kubernetes cluster and the remote resources. + + + +### Tunneled mode + +This deployment involves the Virtual Kubelet connecting to a remote interLink API server and its plugin through a secure tunnel. This setup ensures secure communication between the Kubernetes cluster and the remote resources, making it suitable for environments with strict security requirements or to host services on a multi user host like a login node. + +For more information visit the [architecture page](arch) + diff --git a/docs/docusaurus.config.local.ts b/docs/docusaurus.config.local.ts new file mode 100644 index 00000000..90cd2de0 --- /dev/null +++ b/docs/docusaurus.config.local.ts @@ -0,0 +1,136 @@ +import {themes as prismThemes} from 'prism-react-renderer'; +import type {Config} from '@docusaurus/types'; +import type * as Preset from '@docusaurus/preset-classic'; +import type * as Redocusaurus from 'redocusaurus'; + +const config: Config = { + title: 'interLink', + tagline: 'Your virtual kubelet ecosystem!', + favicon: 'img/favicon.ico', + + // Set the production url of your site here + url: 'https://intertwin-eu.github.io', + // Set the // pathname under which your site is served + // For GitHub pages deployment, it is often '//' + baseUrl: '/', + + // GitHub pages deployment config. + // If you aren't using GitHub pages, you don't need these. + organizationName: 'INFN', // Usually your GitHub org/user name. + projectName: 'interLink', // Usually your repo name. + + onBrokenLinks: 'throw', + onBrokenMarkdownLinks: 'warn', + + // Even if you don't use internationalization, you can use this field to set + // useful metadata like html lang. For example, if your site is Chinese, you + // may want to replace "en" with "zh-Hans". + i18n: { + defaultLocale: 'en', + locales: ['en'], + }, + + presets: [ + [ + 'classic', + { + docs: { + sidebarPath: './sidebars.ts', + // Please change this to your repo. + // Remove this to remove the "edit this page" links. + editUrl: + 'https://github.com/interTwin-eu/interLink', + }, + blog: false, + theme: { + customCss: './src/css/custom.css', + }, + } satisfies Preset.Options, + ], + [ + 'redocusaurus', + { + // Plugin Options for loading OpenAPI files + specs: [ + // Pass it a path to a local OpenAPI YAML file + { + // Redocusaurus will automatically bundle your spec into a single file during the build + id: 'using-single-yaml', + spec: 'openapi/openapi.json', + route: '/openapi/', + }, + ], + // Theme Options for modifying how redoc renders them + theme: { + // Change with your site colors + primaryColor: '#1890ff', + }, + }, + ], + + ], + + themeConfig: { + // Replace with your project's social card + image: 'img/img/interlink_logo.png', + navbar: { + title: 'Home', + logo: { + alt: 'interLink Logo', + src: 'img/interlink_logo.png', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Docs', + }, + { + href: 'https://github.com/interTwin-eu/interLink', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Docs', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'interTwin project Slack', + href: 'https://join.slack.com/t/intertwin/shared_invite/zt-2cs67h9wz-2DFQ6EiSQGS1vlbbbJHctA', + } + ], + }, + { + title: 'More', + items: [ + { + label: 'GitHub', + href: 'https://github.com/interTwin-eu/interLink', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} Istituto Nazionale di Fisica Nucleare (INFN) - Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + } satisfies Preset.ThemeConfig, +}; + +export default config; diff --git a/docs/src/components/AdoptersFeatures/index.tsx b/docs/src/components/AdoptersFeatures/index.tsx new file mode 100644 index 00000000..ea028f14 --- /dev/null +++ b/docs/src/components/AdoptersFeatures/index.tsx @@ -0,0 +1,93 @@ +import clsx from 'clsx'; +import Heading from '@theme/Heading'; +import styles from './styles.module.css'; + +type FeatureItem = { + title: string; + Svg: React.ComponentType>; + description: JSX.Element; +}; + +const FeatureList: FeatureItem[] = [ + { + title: 'INFN', + Svg: require('@site/static/img/INFN_logo_sito.svg').default, + description: ( + <> + ... + + ), + }, + { + title: 'EGI', + Svg: require('@site/static/img/egi-logo.svg').default, + description: ( + <> + ... + + ), + }, + { + title: 'CERN', + Svg: require('@site/static/img/cern-logo.svg').default, + description: ( + <> + + ), + }, + { + title: 'UPV', + Svg: require('@site/static/img/cern-logo.svg').default, + description: ( + <> + + ), + }, + { + title: 'NuNet', + Svg: require('@site/static/img/cern-logo.svg').default, + description: ( + <> + + ), + }, + { + title: 'AOB', + Svg: require('@site/static/img/cern-logo.svg').default, + description: ( + <> + + ), + }, +]; + +function Feature({title, Svg, description}: FeatureItem) { + return ( +
+
+
+ +
+ {title} +

{description}

+
+
+ ); +} + +export default function AdoptersFeatures(): JSX.Element { + return ( +
+
+ + Evaluators and contributors + +
+ {FeatureList.map((props, idx) => ( + + ))} +
+
+
+ ); +} diff --git a/docs/src/components/AdoptersFeatures/styles.module.css b/docs/src/components/AdoptersFeatures/styles.module.css new file mode 100644 index 00000000..d83d9dac --- /dev/null +++ b/docs/src/components/AdoptersFeatures/styles.module.css @@ -0,0 +1,11 @@ +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featureSvg { + height: 300px; + width: 300px; +} diff --git a/docs/src/components/HomepageVideo/index.tsx b/docs/src/components/HomepageVideo/index.tsx index 62c0caab..a786fe09 100644 --- a/docs/src/components/HomepageVideo/index.tsx +++ b/docs/src/components/HomepageVideo/index.tsx @@ -6,14 +6,18 @@ export default function HomepageVideo(): JSX.Element { return (
-
- + + Video material + + +
+ Interlink overview at Kubecon colocated CloudNative AI Day
-
- +
+ SLURM at a EuroHPC is at your hand with interLink diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index c0525bc9..235bd597 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -10,6 +10,7 @@ import ThemedImage from '@theme/ThemedImage'; import useBaseUrl from '@docusaurus/useBaseUrl'; import styles from './index.module.css'; +import AdoptersFeatures from '../components/AdoptersFeatures'; function HomepageHeader() { const {siteConfig} = useDocusaurusContext(); @@ -19,11 +20,14 @@ function HomepageHeader() { + + {siteConfig.tagline}
@@ -32,7 +36,9 @@ function HomepageHeader() { to="/docs/intro"> Try it out! 🚀 +
+
); @@ -46,7 +52,6 @@ export default function Home(): JSX.Element { description="Virtual Kubelets for everyone">
-
diff --git a/docs/static/img/37a0d3_bd169579737d47318ca1b1735db6e497~mv2.webp b/docs/static/img/37a0d3_bd169579737d47318ca1b1735db6e497~mv2.webp new file mode 100644 index 00000000..40145c64 Binary files /dev/null and b/docs/static/img/37a0d3_bd169579737d47318ca1b1735db6e497~mv2.webp differ diff --git a/docs/static/img/INFN_logo_sito.png b/docs/static/img/INFN_logo_sito.png new file mode 100644 index 00000000..7f95ce46 Binary files /dev/null and b/docs/static/img/INFN_logo_sito.png differ diff --git a/docs/static/img/INFN_logo_sito.svg b/docs/static/img/INFN_logo_sito.svg new file mode 100644 index 00000000..36adf9a2 --- /dev/null +++ b/docs/static/img/INFN_logo_sito.svg @@ -0,0 +1,43 @@ + + + + + + + + + + diff --git a/docs/static/img/cern-logo.png b/docs/static/img/cern-logo.png new file mode 100644 index 00000000..b6320c3c Binary files /dev/null and b/docs/static/img/cern-logo.png differ diff --git a/docs/static/img/cern-logo.svg b/docs/static/img/cern-logo.svg new file mode 100644 index 00000000..8633e877 --- /dev/null +++ b/docs/static/img/cern-logo.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/docs/static/img/egi-logo.svg b/docs/static/img/egi-logo.svg new file mode 100644 index 00000000..1dbc7b9c --- /dev/null +++ b/docs/static/img/egi-logo.svg @@ -0,0 +1 @@ + Group 79 \ No newline at end of file diff --git a/docs/static/img/logo_infn b/docs/static/img/logo_infn new file mode 100644 index 00000000..83fdb01a Binary files /dev/null and b/docs/static/img/logo_infn differ diff --git a/docs/static/img/logo_infn.jpg b/docs/static/img/logo_infn.jpg new file mode 100644 index 00000000..14dec9ea Binary files /dev/null and b/docs/static/img/logo_infn.jpg differ diff --git a/docs/static/img/logo_infn.svg b/docs/static/img/logo_infn.svg new file mode 100644 index 00000000..9d1973b0 --- /dev/null +++ b/docs/static/img/logo_infn.svg @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/docs/static/img/nunet.webp b/docs/static/img/nunet.webp new file mode 100644 index 00000000..40145c64 Binary files /dev/null and b/docs/static/img/nunet.webp differ diff --git a/docs/static/img/scenario-1_dark.svg b/docs/static/img/scenario-1_dark.svg new file mode 100644 index 00000000..a23fe5db --- /dev/null +++ b/docs/static/img/scenario-1_dark.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO19WVdcdTAwMWJZ0u17/1xulu/jLfI789BvXHUwMDE4T3jAlClcdTAwMWLbt79VS0hcdTAwMDJkXHUwMDA0kiUxuVf997t3MihPKkUmWGBcXGWqy+1CUigzT0TsXHUwMDFkcVwi4vz3X0tLjyZnw+6jfy896p62W/1eZ9Q6efRcdTAwMWJ/f9xcdTAwMWSNe4NDvKTy/1x1MDAxZVx1MDAwZo5G7fyde5PJcPzv//mf1nCYTT+VtVx1MDAwN1x1MDAwN+ef7Pa7XHUwMDA33cPJXHUwMDE47/1/+O+lpf/mf+KVXoefX/lcdTAwMWPl9mjzY+tl/9v41WdcdTAwMTFcdTAwMDabvZX8o/mbLi9o1G1PWoe7/e70pVP8XmrhM+GtMdaKqL2yVy+f8WWhVSZcXJB4i9JaiXD18kmvM9nDW4xwmbDGXHUwMDA1P/3oXre3uzfhzfqQOa2CVFbkP+7qPedcdTAwMTfz7yVx9ZvxZDTY765cdTAwMGX6g1x1MDAxMa/4/+yI0Fx1MDAxNmJ6vdut9v7uaHB02Cm8Z6fbjnH6np1ev785Ocsl4yHjYT4qyd+6uG5Z+v28T+FcdTAwMGJ391x1MDAwZbvjcfKZwbDV7k3OXHUwMDFm0fRcdTAwMGV4dcO1Tr5W/zu9plHroLvGxTo86vevft077HS5XHUwMDA0j7aLN5nf38XXXa70dFx1MDAxOfXFb/6aXny328lcdTAwMWa0j8Jf/XaqbtqF8m/XXHUwMDA3h7nqRVx1MDAxN72QXCJOr2j8XHUwMDA02jbJXHUwMDA17rT64+700fOqnpY1saiNibJNuqeTq1sq6OrXXHUwMDE3Zufj20396s1cdTAwMWZ7W8OTbW93O38+unrfX1x1MDAxN3+bPrqjYad1fj3SK2dcdTAwMWTuxoYwXYZ+73C//Fxc+4P2/vRcdTAwMTb+VXhcXCXLqb6aXHUwMDE5y0lu5sJonM2sV0E7ZZ0xKpSNxtdcdTAwMTiNXG5cdTAwMTFGXHUwMDEzo3BC2GCjmTVcdTAwMWQr7tNU9lrtvaNR92cwXHUwMDE2WW0sydsvrFx1MDAwMutcdTAwMTN9XGLGVlx1MDAxOIbyap5hSG9s8EZHf1x1MDAwYtNIruP79XeqjlRDPICnT54/XVp/++Tp0tv1pXdPN9++f7f6dOk/h1x1MDAxYu/eflh78vRdYYFcdTAwMDeHk83eN96RXHUwMDEyyW+ftVx1MDAwZXp9rodNxK/0e7t8NI/auJfu6FHx+Ux6gKarN0xcdTAwMDbD6attSGz1XHUwMDBlu6O1JoA0XHUwMDE49XZ7h63+XHUwMDFm197P7N20jiaDd93x+f1MRkfd4kPsvrg0XHUwMDFimSlbafPXXHUwMDAwYUEp7IyqXFwqhZIqOlx1MDAxN5yLVUrZetRAVc7djtNcdTAwMWJff4/t10+fd549V09aoydbrf5DQbBZV8NcdTAwMWK03mRKO22iMULA+yX+LsKZ4SVtZ9xd2U3JLv+53k21bCfs7Ezfc+kybTBcdTAwMTm+XHUwMDFiLvOcS0zv5MplXHUwMDFhpTLpI6iIifnP1K1eOFx1MDAwNKmMcV44q2/nhm6KzjO4eefQ1kjN9axHvPJ9VkvrXHUwMDFjnmCVmm83V/Ozky9n4fnqyccj8eXrwejV23cv/vzj4aBPtaL7IDItnHMyVii6XHUwMDA0z81cdTAwMDJ03FxiZaP0/k5cdTAwMTRdm5CBjmupKlxitTQ6s9piidS5jvuyilx1MDAwNyGM0bJw6X9TXHJPeVlBue1cXGB31kBcdTAwMDdC0FW63W6u299cdTAwMGVf/bn/XndG708/nJ6tvX+/uv3m7KHrtlVcdTAwMGWqXHUwMDEzXHUwMDEx5lx1MDAwNa1UXGIpaY1aZNFqXHUwMDExrPRU/ztRbe9xXHQ+XHUwMDA24aSJYL5xVsG1LSu0Q2iDy1Xx+1x1MDAxNTp5obHmeq29Nz7eirZcdTAwMTVJWEh+O4eE8Vx1MDAwMcpsaX3Q6S6d9CZ7S93T4WDc7SyNu6PjXru71JosTfa6S93ObndpsLP0YmN1qd0/XHUwMDFhJ4RtYWwuucUydfvuy7xcdTAwMTdOXHUwMDA3Zz1cdTAwMTfsonfgXHUwMDAzskj0p1x1MDAwZaHT3CFMTv54XHUwMDFkn339+Pq53Fx1MDAxZO+vXHUwMDE5uXvwaeuhO4QgdFx1MDAxNoFcdTAwMTTzwC7azPP52LtcdTAwMDQ7IbOYo8NcXFZn8Y6o5Fx1MDAxNakruKZzXHUwMDA34Vx1MDAxMY+bIOKP4nRXn7lRLmR39GJt/YWfXGLZds86wk6ef42PXHUwMDBiuZDfqsWef1j8vjFcdTAwMWO+23+zubJ3XCJWXHUwMDFlt7efb5x9Sb/l8vtbo9HgpKncOFx1MDAxY+ndk9PVXHUwMDBmXHUwMDFmV/Xvbbf1QlxmnjxuJvfib/eUu6l+elP/Nzd3XHUwMDAz8M+8hupbq51SPqZKXHUwMDBmrc+UR1x1MDAxOFxieEqU/lJhpVGZZuYmXG7rnSwkXHUwMDExpklPe43hzVx1MDAxOE/0sq3+XHUwMDE5mZvOh+apm2BUhF8yU6OeevRcdTAwMDJcdTAwMTKXXHUwMDFjelxiXHUwMDExzFx1MDAxN1x1MDAxZa2B577vxM2H3mhy1OovvTra5lx1MDAxNd1Lnuag1+lcdTAwMTRRsZSqqYGtMt7PvYNF4TjfXVx1MDAwNeEhinkrLoWSXCJE2GqVxnWbQ/hK7P/+bfJ4f//FRm/txfrxpndhXHUwMDFlp2+PXHUwMDA24/HyXmvS3vvxMO7g0aQwTntrlHCi5NGEXGaZkyD11oiofMGgbuOKtHLtrp3FcalcIoJWRFx1MDAxNyYo6YHHXHUwMDE1oauyWVx1MDAxNC5GJ61cZipcdTAwMTSw/jI7XHUwMDAzlu1EwJ1UupopNo9emr2dz19enk2Oevth6+zw9+HXzVx1MDAwMkw9ev9p7UtP7Dw9XHUwMDFjPH+3tr4+7i6//fb+XHUwMDEyrO4hZPguhzGetEaTx9Di3uFu+SPdw86cV/qt8WR1cHDQm+AyNlx1MDAwNr3DyYxnpdxcdTAwMTXC9l63NXPTkDz3tSHFpWsw/dvSVFx1MDAxZvP/uPr7//62gHcv61xm4ZcyJmqD/1x1MDAwNyq75PNcdTAwMTlcdTAwMDA9XHUwMDA246VcbkpHo0OtQFx1MDAxMzKrYjTRwcLhPXxRnlJQY6H4TS5cbm3cfYtcdTAwMDPbRaCOd9tcdTAwMTiksMIm4kxcdTAwMDaeXHUwMDBiXHUwMDAz0SriO52uXHUwMDE3XHUwMDA331x1MDAwMI5cdTAwMGaKLH1ApGNcdTAwMTJxIVPGwVx1MDAxZSFP4fJkrThn4MKtNNb5XHUwMDEwrDChKFx1MDAwZcG9U9xcdTAwMDdWIEfG+vqlWLw4rYP3XHUwMDExXGZcdTAwMDAuxiU3XHUwMDFiRCZcZlx1MDAxNMlcdTAwMDNMPJhdvTSdXHRcdTAwMWRcdTAwMTD9RKVMiMm1weXil1pcdTAwMTmEJVoqUy9MZVx1MDAxNjdiLdxekMH6kjSwSWu9tPiuqFW9UchMK0REykXtXHUwMDExwenkViXUzoPaXG6pJC7fqfqbXbhA6JYmf5POc+cg2pBcbrSZgMHihqHF1Pd6gSazXHUwMDAxXHUwMDE3J5jh10basrxcdTAwMTRb6uThXHUwMDAzWFRcdTAwMWI0kdNcblxcwzXy6rVl0eJcdTAwMTCFwKE556BcdTAwMGXBXHUwMDE1djKunlx1MDAxZb5cdTAwMDSaLGg8oVb/tMrghISDR/EyKjGzui5Kg6v28KPC1i5cdTAwMDZMw2BprcTHYFx1MDAwNr5sXHUwMDFiXHUwMDAxLMTSaytowP1cbrPgQlbCacDcYOW+5Fx1MDAwMoyWxiltXHUwMDAznLWOXHKkXHRcdTAwMDRcdTAwMTNG5Kym5Fx1MDAwM+ifYP5cdTAwMGWsXHRr5Vxc7bXZPN1cIlx1MDAwM/BcZmtcdTAwMDAjKvliXHUwMDE5oT7AMVx1MDAxOVx1MDAwMCbR3rc4qFxi9EPDg1x1MDAwMk9h5WXkQbSrqFwi8NRYqFpvbKDCXHUwMDBlrlx1MDAxOF+udVx1MDAxNCpcdTAwMTWHIDpKXHUwMDBidbNcdTAwMGXr4VxcrUWYTGJcdTAwMTGwfLhcdTAwMTdn4YJmaFx1MDAwMGJ6fFx1MDAxNcVhwWrtf9Hyllx0L3lcdTAwMWRcdTAwMTS8XHUwMDFl1EHBVyVcIpcl31x1MDAxMDT+XHUwMDA1XG6A5lx1MDAxYd1dlrX3PY8t/av4/zeNp2jrc1x1MDAwMyqm51x1MDAxZP4sxNDTgGqneUC1Nd58az6vrHftk6O1/uNcdTAwMGZxS/rfXHUwMDFm9j73eSil6T5KUcxFXY/JXHUwMDFjIFx1MDAxMvZOzS1cdTAwMTSz3S6rU5FcdTAwMGaNsLOgPVNcdTAwMWZcdTAwMGV+ulwiXHUwMDFkXHUwMDFhNbfBNXTXRi1cdTAwMTDQzURRcJTAXHUwMDA17avzoVcq9CtI+vtcdTAwMDRJMoPTXHUwMDAxXHUwMDEwwJFcdTAwMDZQZkRcYqk3i9abIGn2XHUwMDAwXHUwMDBiqWvBYFx1MDAxOYzAOiHhXHUwMDFkoWdw4TZhXGZUQVx1MDAwMWORWmisYmxcdTAwMTDX1Fx09Fx1MDAwZWCF+N/qgODGfv9cdTAwMTXeQiBcdTAwMThcdTAwMTfwSuJcdTAwMTNMXHUwMDAx61x1MDAwNO1cdTAwMWT4MXxi8Fx1MDAwMp6bYUlcdTAwMDN5XHUwMDAyolx1MDAxNFx1MDAxOD94XHUwMDFmiJxLXHUwMDE5q8wrajTJNCSbRlx1MDAwMkNcdTAwMDTiwzVcdTAwMTlng1x0psTiMjBPXHJcYqL940Lr4yWVRTxBxtX0dTYkSiPxXGKB9VwiXHUwMDA07lx1MDAwZeFp1EPgouX5LHAphGXhXHUwMDE1o+FEXHUwMDFl4lx1MDAwMU39g0gv4G/rgzA8XCJP1+pcdTAwMTGIg1x1MDAxOUWVXqAjQIPl4bvAXHUwMDFlXHUwMDAx0/VcdTAwMDJ9hlxiXHUwMDEwi8FlXHUwMDE03qlEXHUwMDFlo+tcdTAwMThBwLSJXHUwMDE2MUl9tK5kXHUwMDA2/uA9XHUwMDAyVFx1MDAxMC3Eglx0Z5JcdTAwMTm03XtcdTAwMTVcZt5cdTAwMDAu3MDoXHUwMDEwlYCGaIu3e1x1MDAxYUFyw+B0oNZcdTAwMGXvXHUwMDAwXlx1MDAwMHN0XHUwMDAzXHUwMDE1dJnBWihcdTAwMDYz/CMxXHUwMDExXHUwMDA1Qlxuhlxi/FxmXnKd6+PYhctcdTAwMGIsvFx1MDAwNVx1MDAwYtNcdTAwMDFLaZxXJYHeQo+MXHUwMDE2gbZZy/9cdTAwMTlcdTAwMTZD/Vx1MDAxOIGARHtn07hdIZ7weLjgXG6K+df68GRZI9ihXHUwMDE5QFx1MDAwMSNcdTAwMGItTEljXHUwMDAwh/BpzoKD6OjrNVx1MDAxMIxcdTAwMDQqK5RcdTAwMTDeSlx1MDAxMFx1MDAxY12Sx11cXFx1MDAwNlWRil+vMItcdTAwMTaHsNdaPCPpsFx1MDAxY16VomKPICBcIjRAXGKDh1hcdTAwMWZALWteXHUwMDAxQi1cdTAwMGJcdTAwMWZcdTAwMDJfXHUwMDE3y5dcdTAwMDcwXG4+391z+K5cdTAwMDZZj1x1MDAwMFx1MDAwYlx1MDAwMCaypFx1MDAwYkGh0eXVXHJcdTAwMGXPgVx1MDAxMZGF0tSL88yBw6CYQUFcYjVcdTAwMTPycE9cdTAwMGL0XHUwMDBlT1x1MDAxNo6tweU5hCFGXHUwMDAwyGCeuKdyalx1MDAxMXqEXGLFXHUwMDA3xoCx3t0vWlx1MDAxY8mwxa1cInSH70gzRvAtsFx1MDAxOVx1MDAwZqdcYu+CXHUwMDE1aSBOZDZcdTAwMDbGqnB+MIPUcl1cdTAwMTbPk6g+eOhMg4xcdTAwMWLkXHUwMDAxOCyzr1hcdHysnPo0kWVyXHUwMDExYahSoFx1MDAwZvW+JWZcYlxmLPmE4Fx1MDAxNqNIrzBm+DWWNk/XMDtz/1x1MDAwMpnlUVA9J8gpbOr8sFxcUWvCXHUwMDBiWFtskK7gXHUwMDAyXHUwMDAzi5jgZOZcdTAwMWQ+uCjOXGLWbYDZMJBcdTAwMDVcdTAwMTA3IFjwXHUwMDA2XHUwMDAy/iN4R1x1MDAwNyOmNWa5PM90XHUwMDAxeYtcdTAwMTZcdTAwMDZg1Uz/XHUwMDAy7ldJXHUwMDBi8lx1MDAxN1M2ZDXoYcRvLf7R4Fx0XHJu12Z4OFx1MDAwZYaOlVx1MDAwMFx1MDAxM3AleVx1MDAxMTZcdTAwMGLKQN9cIppkVFx1MDAxNyxcdTAwMGVcdTAwMTZcdTAwMDDXXHUwMDA28IdnM6VtXHUwMDA2azNcdTAwMTghOCvcMnOu9apiJK6OVFx1MDAwN1x1MDAwNo/lc2VxcHjMVbs8XdZgT8WAXGKBOVx1MDAxYlx1MDAwYl31pWSKdbg6UjXvoJyhyZ5cbu5cdTAwMDeoXHUwMDFm4JJcdTAwMWQuJHUtXHUwMDEwpyX4XHUwMDE5XoHHXG66kThW74NmXHUwMDAwybmd8LDEuYycXHUwMDFkWlx1MDAxZsBcdTAwMTWlL4tjvs1FwFx1MDAxMLyZaGC2sCTgoLdRkZKE0uV5KJ6B23agzVKqXHUwMDA2muKoqlxuulwisHygLElUJDJ8XHUwMDEzliiA/UaQrnovXHUwMDAweVx1MDAxZWZcdTAwMGJcYlx1MDAwN9JAXHUwMDFk0tQ2XHUwMDA0srBcdTAwMDaMXHUwMDE0QVx1MDAwMpG8wf2S5DJcdTAwMGU1XHUwMDAwXHJoWeL1XHUwMDFjXHUwMDE4NbyeZ1JcdTAwMDQoXHUwMDA0PGiiy4jxwPVcZjwv4CtccjsgkLG0cPhcIpZcdTAwMDE1iKWNJlx1MDAwYkLU44VcdTAwMDNcdPdcdTAwMGKQXHUwMDA3XHUwMDFmwC0xgII3KVx1MDAwYoI8wy1cdTAwMWNcdTAwMDV25FxyXHUwMDAy4HtcdTAwMTcnspzCsv1cdTAwMDJxbeluXHUwMDA1Q1x1MDAwZTiqXHUwMDE4sMxNnJ6Ak1x1MDAwNCZoR0qaXFyajYigmbBG+CVcdTAwMTHVNdg1Q8hcYj5cdTAwMDBcdTAwMDJcdDDzQpXFXHUwMDAx7ExeiFxiuFxiXHLCP5B5UEfPkmrNqNGV5OGJ4luAXHUwMDAyXGLLRYNgY8HiRO7iibdeXHUwMDAwMUp6XGarsZbFUiyE87ZBbOV5eXmRh45w9unKepF5QJ1UwYI/ilx1MDAwNslcdTAwMDdcdTAwMDU+YjVA32NBpDKJ3XpcdTAwMGI36jTjU4svbWBcdTAwMTWIJnBcdTAwMTeOXHUwMDA1YFDmKEqbNey3xCV7vlx1MDAwMupRL47RO/yQ5Vx1MDAwNibgq7yRJFx1MDAwMsBWMbp3scHu5eLFXHR4SFx1MDAxMFx1MDAxY2mZXHUwMDAz84muXHUwMDA0OD1EuVx1MDAwNtRcdTAwMWOeVtXfLENcdTAwMWRcdTAwMDNSzTRB1Mqb9PJcdTAwMWM3wllcdTAwMDCPP41s8PCUzFg/XHSyXHUwMDAy9Vx1MDAwYsGn5Cdwb1xuZMZr8DZymia6olxms302kq1cdTAwMTTqtS/kRTB4b1x1MDAxNPOAXGLXfoQ8aLCW2nBcdTAwMTfTWpXoXlx1MDAxNFx1MDAxOdiPZ1Ypgus1SUXy+nSQhmlcdTAwMDeWliS2XHUwMDExsbzkRSCQQlx1MDAwMklcdTAwMWLllXInXG6mrLHKJt3bi7h6qFx0iFx1MDAxZb1cdTAwMGY8c736xYx7z560XHUwMDA0qJbmqWY2KJqIY4aFgTO9m4ulq0NY6OG+glx1MDAwMjOI9Xeb21x1MDAxYaNPXHUwMDA27oJAU5JcdTAwMDdcXIJEZmRcdTAwMWLQKWYpoFx1MDAwYlx1MDAwZTZcdTAwMWJcdTAwMDTUXCItoYl5XHUwMDFhN8KLsu3K1u/EU1x1MDAxZfBcdTAwMDU+yFx1MDAxOWAu7F6XdFx1MDAwNTbBWDB6+opcdTAwMDZ3u2h5LlN0ucZcdTAwMGKQWyd92TaEXHUwMDA3k4FcdTAwMTbD3atcdTAwMDZJXGZcdE9OXHUwMDFkIWowV5tcdTAwMTb5XHUwMDA0wJBcdTAwMDJblVwi4iFcdTAwMDZX71x1MDAwYiSiUtyqNlx1MDAwZTQ7MFxylci7LMyJpCyhifJRXVx1MDAxOaRcdTAwMDH2aXBJlFx1MDAxYvJdXHUwMDA2p6nqtO56WJPc2Vx1MDAwNlW2bFx1MDAxYsLnSp5cdTAwMWVsjz5cdTAwMDVxKcHXNzC1XHUwMDA1y3NMSktunFBt4fNt+fHBXTPwXHUwMDBiXGJcdTAwMWbqWUaeZFx1MDAwMYYz8lR4RjJNOrB8XHUwMDAzIYOialx1MDAwMvbqQz9ET1x1MDAxZSvBbDlUzOlyMVxiy9jA0jRcdTAwMTbZ16dH8fAsXCJccnwxnLJQprS4N4RJaopDXHUwMDFjppiAXHUwMDA0ekRVVlx1MDAxNWOMY4FcdTAwMTmgw9dubyxanGHyXHUwMDEx/lODqMNLXHUwMDA1U3p0oOJcdTAwMWUqXGZQbrA3RC9cdTAwMDD8jsztsYYjlJ1cdTAwMDC+h/ZcdTAwMDK7cfXkjD5cbrzWXCLw057J7bKPMtGwXlx1MDAwMlx1MDAwMOVcdTAwMDFpXHLEcdGY+IFRXHUwMDFhacvwKIOh9eO1XHUwMDE461x1MDAxZtxipVx1MDAwMXxcdTAwMWO3tY2E3TqbljNFNo84zVx1MDAxYYKgPFx1MDAxNrdWXHUwMDFjaD9UXHUwMDFlXHUwMDExNlx1MDAxNlx1MDAxNYgrS9JcdTAwMDBuiFmA2lx1MDAxYV6+1rrAK/LNNISh+X6LKmNZhMIh9NCM3uqrS0lTVFx1MDAxZVx1MDAxZDpgs4oylMR5WF6+XHUwMDFiyLRzrZaQRSFYJ9GEuzUlXHUwMDFhwMZseECGRlx1MDAwZcpUX+CHi0NcdTAwMDTKWEVbLIYpaXBcdTAwMDDdRpjHfLipj1x1MDAxZMlojTReXHUwMDFhOFx1MDAxMbi5Mp81XGLJoOFSMni7X2HcpoieYU2e6k75XHTwXHUwMDE1hC4wxy1Y3lkrjpFcdTAwMDWAmISfg1x1MDAxMtIkbeB2XHUwMDE4XHUwMDFjNL5PcMur3lJcdTAwMDOor2JcdTAwMGVcdTAwMTbmRc+d+jjGPUBcZpZ0ws3VYjUsXHUwMDE1JJrzdlx1MDAxMLNyQzNxI1x1MDAxZbQ9ssVcdTAwMDG0k6n9elxy0YxcdGFWMGwymlx1MDAwNFlcdTAwMTGAqnxcdTAwMGZWM0Cuz2shOsbTxSWBlUCnXFxcdTAwMWG9IzpcdTAwMDZnUYhorVx1MDAwMWmvXHUwMDBmj9mNjfU0XGbg8bhcdTAwMTNcdTAwMTVB6K7PKalkVlXWXlx1MDAxYlx1MDAxM1x1MDAwYoF8XHTxO1widFFOLIC4gkDAJ5Fk1z42ZlG4v8Z6XHUwMDEzRIPBl6Q5XHUwMDEzXHUwMDFjyDzTbVxySklcdTAwMTcsjXv4IP6KSFx1MDAwM36vStL4KCXoXHUwMDFlaFx1MDAxNGhL7YMzXCLzTHv6PPflSntIXHUwMDBlludcdTAwMThcdTAwMTRcdTAwMTg+WPilWnFcdTAwMWFYXHUwMDAyMGXRSn5H5UxbXHUwMDFlQ1xi06CgXHUwMDFjothcdTAwMTJvmJdcdTAwMDVVU2VRltX0MpDJhXpAZYZcdTAwMTK4ZEHBqcNcIt2W/uHioO8we5BMai+QuiTNSXxcciRxmll9MMx0e1RMfXtcdTAwMGZklzPpZ1xcXHUwMDE20FlbuM36XG5cdTAwMDEm21xyq0SxXHUwMDEyivmYksLhXHUwMDBiQO1cdTAwMDRzdj7UX1x1MDAxYp2IZ/V40PSLqfrCl+Y0XHUwMDE2ZFx1MDAxME+j3ofk14bbXHUwMDAwkUecVEq0Q1x1MDAxYeuScLfUOF2/XHUwMDAzhedcdTAwMDb+o1x1MDAxMaXDVp3zvrzHXHUwMDAzfXQs32a6olx1MDAxZVDzLVx1MDAxZe7+R9hcdTAwMTVrZErSXHUwMDE0Y1x0XHUwMDE2doGh14c1xmTchKSSsOrLzew/XHQyaSCQZlx1MDAxN9w9S5N51YnO/Vx1MDAxMnxIqlwibFxmgJOHXHUwMDFlWptvNjRwcexxhatg9Mbdl5I8KXTePkSWXHUwMDE3XHUwMDFhgIPNPHwsXHUwMDFjUmCnS5zZp1x1MDAwNKfQeek3qGN9zVx1MDAwN3dlWUAnc8ftYiyJc3ntXHUwMDAzPD58fT2JW7g0PmjBXHUwMDFhXHJthU90jlx1MDAxYtCKSTXcK/NcdTAwMTH19WR5sVxmLJX7XHRCXHSrk5XgXHUwMDA2Ob9cYsCrgFx1MDAxZvWNaZy0XHUwMDE5rYeriIKJ9lx1MDAwNPN56dxcIlx1MDAxNFx1MDAwZUSFpVC1V6eAdqBcdNws9i5vjfstfVx1MDAxNdG9xoVcdTAwMDO+XCIoTj3Bidn5vEKEo6DTdqaVjFxcOzCjXG6X0qjDZZHiNGNITeT0hOJy8VxiXHUwMDFlXHUwMDE4O408XGY6NOivXCIpXHUwMDExrMN2mlmDtHeJpS2ej1x1MDAxNjhcdTAwMTFcdTAwMTD+Nrg4lzEkXHUwMDBm3OFcdTAwMTVsO0jEKXJcZsvxnWTc9b5Oe3a5cT+HwUu61a7yXCJWgUhcZmE0iXD9rS5WWsicol6x6NaKlGkya1x1MDAxY7xkpaFlJU99clx1MDAwZeK48ShVIFx1MDAxOEtVrveyzGmCTSmjXHUwMDE4YDS4V1x0lII+IVx1MDAxZVx1MDAwMekvV6MxQonMXHUwMDA0XHUwMDA1w4RQk2XlPqZEKFx1MDAxN50sSzMsMlQycphkXHUwMDAz60e8kT+XPE1cdTAwMDbMNiVxmuk1w399k1BcdTAwMWacP7K+UMKOYEVOllx1MDAxZZ2g+lx1MDAxYVx1MDAwNixcYlxy6q9cdTAwMGVcdTAwMTGEXHUwMDA36GBt8b9cdTAwMThT0OFKYJmwXHUwMDE2LDxiNfO9y1x1MDAwM1x1MDAwYmTZXHUwMDEwwMLAMl2YqeRj1pO7zlx1MDAxMm6iPmud15HCXFzhilx1MDAxMaSrUlx1MDAwNVxu60ixTkzZMeDWXHLSXHUwMDA3IE9s0Vx1MDAxMsRcdTAwMDOYhpwpdDVwXHUwMDAxwWp2nNbX4bKul1x1MDAxM3vgUaCnLHcsOSju+ELJZVxmLPSrXd6Fy2MtXHUwMDFmjImZZNZcdTAwMTOm4Vx0l4Pmj5dcdTAwMTDDwzHWiZMgNYicXHUwMDEx0ll6cZlmwWBcdTAwMWKKXHRwXHUwMDEzQ74xXa8tLFx1MDAxY3CAXHUwMDFlWFx1MDAxNFx1MDAxOVKaUpdAWrhcdTAwMDHL2lx1MDAwNYJ6PWtXXHUwMDE5XHUwMDAyXHUwMDFk4cGIXHUwMDEx3Vx1MDAwNcTRqSdApFx1MDAwNlx1MDAxZcBdeDZcdTAwMTVZWf/0XHUwMDAwV5aNylBcdTAwMTZcXKBIU+p5nT88LHxcdTAwMGJbXHUwMDAwXHUwMDFhXHUwMDE0XHUwMDFks1x1MDAxMYFxk2HdXHUwMDFkQq40imUjXHUwMDAyXFwse6xBK9naVy8v7+zlJrtjeiStXGLKuO1ic+uIXHJoQFx1MDAwNl9nmVx1MDAxOYHae5fuRuDJ4ZusXHUwMDAy9SNcdTAwMWZz9cVANeLob4Bzno1cdTAwMTdYkPtcdTAwMTYnXHUwMDE5XFwyUctcdTAwMWFqhP9pco1cdTAwMDWV3rOMXHRcdTAwMTRcdTAwMTTkvtHmXHUwMDBiq41xXHUwMDE5cEFYYDz1VKBgaSFdospcdTAwMDfYqfrtybtpN1x1MDAxNNPmnHK7oeYuk9aictzobvNuQ7H25WXrRfw2fNs7XG6Ptzs93Vx1MDAxN29+ivEtPmY5yOm84l+UZ4kzQuSANs9u1WC/r+dw7vhcdTAwMTZcdTAwMDTcLuQ7XHUwMDEziFx1MDAwMlx1MDAwYmOvptNb8Fx1MDAwZfg4XmTgSLiZuaOsXHUwMDFhXHUwMDE33Fx1MDAwN6+e03ilSr/aXHUwMDBlXHUwMDFmcNvhMmvG4LjzST6sIU0zz5d771xiVZhPdlxyulx1MDAwNCDQS3Juxao1IYy7RmCTMrSFXHUwMDBiRJCDXHUwMDAwh/28oGYstk3kldW+Vlx1MDAxYzNcdTAwMTaMpqzL9zXSjKC0eTFcdTAwMGLxzIo8bVxcK2+eafKHJW9cdTAwMWXLoMCMPGdPNCiTW7C4fFx1MDAwYofhXHUwMDEym1x1MDAwYpjOTSFSXCLgZl2g40LVJ9zZ4+hB5FgllVx1MDAwZnws9bGyRolcdTAwMTM72Y1cdTAwMDVQadSVL6jRjEhcdTAwMDNnX4RSqJFpXrxnUz6bc4ztLtdnfu5cbiXnXHUwMDBlKmVcdTAwMGJcdTAwMWN7XHUwMDE2K1x1MDAwN1x1MDAxN+/dYMjZYF1cdTAwMGZbQ386Ontcbu88Wn45ls9+XG6UXGZcdTAwMGVBXGJcdTAwMTSD8ZZcZq485FxmKFx0xlx1MDAwNFx1MDAwMo5w293RiDPH4fJcYvhYXG5cdTAwMDRmVXXeXHKtXHUwMDBiXHUwMDEwI1x1MDAxZLPG4FxcaqY7P3L2XHUwMDEwi/Z+oeRPi5I3e3fIXHUwMDEw5VwiLGRxPVvW07a7XGZOiYO5XHUwMDEwLmkjZH2VxHw15I9n8b3n+lx1MDAwNSvpk+vEMbaXrKtcdTAwMTA2L9FLxzRcdTAwMTGuhEMsbySTSPVcdTAwMDHYgsWpjL2wllxy3uxcdTAwMWMyaYp91tpqXHUwMDFmXHUwMDFln1x1MDAxZDtcdTAwMTPyYVtwqL50fVx1MDAxY/XD/Vx1MDAwZVx1MDAxN4I2XHKAXHUwMDAwj1txdJmWlmO9VLlFXVwijFx1MDAxN8wxcExCLVx1MDAxN7krXFxx5V9PXHUwMDBmNVx1MDAwMdJyP2/qy1xuwNJrXHUwMDBlLI/N6LNeW18zn5+dbmnn9ejN+NtPXHUwMDAxLKx/gHFyXHUwMDAziXOup375/PNcdTAwMGXmy1Q1O4FNYazXYqHF5p1cdTAwMWbWcC5QjD5WXGbGZ35cdTAwMWFuJJKZkazOjME2UjDh5uuGZ/5CloeLLKDTLJbVLs/tcVx1MDAwN7z4cWgqXGKQziekgqnWbyqUxKl0XHUwMDAzJWasi7OOlZeCRTb3LVx1MDAwZeTbh3ycUmRy15XzkoHdPNw0g8I06NCOmWPNv2c9l4JcdTAwMTmlaVOdXHUwMDFmRKiF87h812B6RlwiLpb3siCOL+JZXHUwMDA0mC1QoE7cMpP8Nlx1MDAxZsfBYZxGp002uXlcdTAwMWImsFlLXHUwMDE5mzR63oFAXHUwMDAz5DPRSIdbiyFtXHUwMDEzXHRcdTAwMWPVodhccqjyXHUwMDEyqlrtXHUwMDEzeY9cdTAwMTJiZsOJVqzoTOd7LF+8wbm8YVZAXHUwMDEzYn3O844gcm6CUlFcdTAwMDGMqVx1MDAwNMgvzVx1MDAwMXLydu3levfV+vHkZPLqcK+18+zDmftcdTAwMTlcdTAwMDDSXHUwMDBibp9rTpCVQU5cdTAwMWLFp/jInLbmiUWF+HXR6GiY01HCkNtOK49SdOShfWBg0HQlXFxcdTAwMDGoL/KTgvlcdTAwMDTj5S98/Hnx8Wbvhj9zOq9Gy4upfcr2ecpcdTAwMTbQhTWKkUXgXHJGUHJ2XG7HXHUwMDA3s6VKuVx1MDAxOXebKmCtu41MWSDky/fSvEvr3Vx0MDJcdTAwMWaOzFlfcEL1ua6SPFtcdTAwMDYsa9nEkHf43fjivk9cdTAwMTj3XHUwMDE4g1x1MDAwMK5Idlx1MDAxN0mRJpUlXHUwMDE4Nlx1MDAwN1x1MDAxZnNOXHUwMDEw9/DrxVx0zsjOx65cbqO1LfVcdTAwMWRg1Vx1MDAwMzdcXC1Zsoj1IzYz3CdcdTAwMGaYUd57mU9cZvktfVlz5lx1MDAxMVusjGLH1Fx1MDAwM9xGY9+wXG5zYGr/XHUwMDA2QzvXzPH65+fi+WhjXHUwMDEy14fH/YP+45WfXHUwMDAxplxcXHUwMDEwXHUwMDE5XHUwMDAyuHxcXFxidGMmQeiBU6BDjlx1MDAwN8DBgq85zeg7kCqyPYKDvKFKpEhcdTAwMTVAda6dzFpcdTAwMDQ2XHUwMDAziFmcUkFcdTAwMWFdPNjvXHUwMDE3TF1cbvtZYMqwKDxyXHUwMDFin4PrdFqvsizZXHUwMDEzQ1x1MDAxZOVEvnxSY3e5vnjNgyyrXGJcdTAwMWHEMnhR6qRhOVx1MDAxNTxcdTAwMTS8q7JcdTAwMWOeVJ9cdGNPv1x1MDAwZk5ohFx1MDAwZTzGqJRFZPmB5NQnlvHUQ6PKpOb2ST6rivtHXHQ2lnW+wbZS5lx1MDAwMydJxrzyl0nD6y6vyWRK2CNcdTAwMWJgOIuMvW/+mqf3g2Yyi/lnXHUwMDBmXHUwMDA3YFx1MDAxZNM+Vc6939y5byy/PJVH72T/zejZq4PuR1x1MDAxMJXD1k/h3KPJeD6E9uyJ1dPW1suT6kTGI1mDXG4sXHUwMDE1MndcdTAwMTSGuIxccuqsuYdcdTAwMWWDxVSFITxiXHUwMDEzYWye7VxyplwiXG7JT4VcdTAwMGZ6zvGsv9z7z+Deb/huTmDg1DbojVRsoUl9T9AsRDRcdTAwMWNcdTAwMTLrfGxcdTAwMDJcdTAwMDWSg1vzIXrkubI0+T9jgoZeU3BXvkGP5mKl8aRcdTAwMTA4WDZcdTAwMWJC/0tz7/LjX+GBTeR36fr9XHUwMDFhwVx1MDAxMYScXHUwMDExXHUwMDFh87NcdTAwMDLS3i+8XG4z01x1MDAxY1x1MDAwN1x1MDAxOVx1MDAxNXG2Vlx1MDAxZUCUK0CoYu2IK6dcYpnPwzJcdTAwMTjByspcdTAwMDbHarBPiO1fPCOA0VAqr+xcZlx1MDAxYcCUYCeJod157kCVQZ57TDykwbJcdTAwMTi/yWCaRVx1MDAwYuRgXHUwMDFmrIbK9zJcdTAwMTWbyZM7znKE95wugVWz9dUy5djLhbRcdTAwMDNU5IXqilEmJ1nZJp0qd1x1MDAwNc9zj0xwkYNOna/E54Pm+Hxw+nV15+1rtbr/eHly8Hx/b7S5t/tT4LOXXHUwMDE5Ylx1MDAxNlx1MDAxM/LxVXpakjXFZ6+jlGzjXGLBlq5rYfDMoeg8XydcdTAwMWakV9jJK8KzkVx1MDAxY6fIzm4mXHUwMDAzZ6tcdTAwMThpxlbNO236XHUwMDE3Pv/98Fx1MDAxOS7NKY7jNkbI4vnC5y+K4LxWcJF5o0f9XHUwMDA2heKwU4lcYoOzr1jYUfK4kufNeMVcdH+yPjdVJ1xywoLSPP9cdTAwMTJcdTAwMTDYwN/qTFx1MDAxOVx1MDAwZXdcdTAwMDD1tzntKFx1MDAwMVbJPO5dXHUwMDFlu1x1MDAwMjnJiMNcdTAwMWU5liCtp+AgNSNZ5sVTLFSDXHTknIqDR854UWm2dqUzudn2YjnCXHUwMDFmXHUwMDAxIFt56lx1MDAwNeazajxcdTAwMWJcdTAwMTelXHUwMDA07Fx1MDAwN1GGq2JFPoeQ/SCRgi1cdTAwMDaSmFx01GecP5PTLFxuxer9MFj15V9Pi1Mk29eT03ynuHrYXHUwMDFjV/Xmy1x1MDAwZk9Gf/a3J6Mvr56oP198XFx+uvNT4CrPI+JcdTAwMWWAZi4plnOa0WWSXHUwMDA3I1xuS2an7yjs9fmoalx1MDAwZeFcZiE/nbVcdTAwMDJXbcZBhEpyyIxjdVdcdTAwMTlXYdImn9v/XHUwMDBiVv8xsKqIc5bTTlx1MDAxMGolQa/gjOzI5njOXHUwMDE4N7FBs71iIGhcdTAwMTFSXHUwMDA2do2rNEqVRKFcYj/Hmf7a2/rJcDxcdTAwMGaR43VcdTAwMTD4IFxmjDrdQirJa3B6XuQ0XHLNMdMw11JDoeYkN1x1MDAwNKk8OU9yUnGdMJdxYpXFs8N1sb4jXHUwMDExZzi4N7KDgPN66vvFXHUwMDE3K43Za8lkLlx1MDAwMzLO6k9niM16glqBgadS5CV4nP0lXfnUII7K4dBSXHUwMDFlYGNcdTAwMWG0XHUwMDEwyHxcZlx1MDAxNDsnWVtSPE06XHUwMDE3mOVnI0SBgFx1MDAwNC6pyaTiRVx1MDAwYrxcdTAwMDBfJkLYoIJbL3U5sI7PcKOZM1x1MDAwZXlq6J1C86jbnpzDT1x1MDAwNT47N1x1MDAxN55cdTAwMDNcdTAwMTXAXHUwMDE2XHUwMDA2fFx1MDAxN9F50Fx1MDAxY52ft0++rTzb3zz9eLKy9fjLeGdrd3I4XHUwMDA3nVx1MDAxZsg5gTygJJOcvpXvOFx1MDAxNrO5XHUwMDE3yOxcdTAwMTGMWsEt9Civ22zs8p/rgbllO6HqqEAtJI/gcPnEcp6nMYvLlqrL7IqJ5z8z4a7lsCOvZHU7wo1cdTAwMDD3v1d6d6lal+mkv+bj8NVn/lvQ4Fx1MDAwYsXY31x1MDAwZSdPN072d7e0X373xT/92lx1MDAxNvJRUdWvdLhFXHUwMDAwfHT1yl+/Vcu9fPukezpJXHUwMDA1XSRghp2vR4/XOyudg9WVI2V2tvybUC/2/MNxONK7J6erXHUwMDFmPq7q39tu64VcdTAwMTg8edzscmf4zVxmKWFPdeHMznpSUmny193llZzKh3Su9oi9OD7WI2qwXCIpR8jVXHUwMDFlP+xcdTAwMDZcdTAwMDPWeJuo/Vx1MDAxNZeEXbDnntP7XCL3UmZVdrpcdTAwMTFZYXu3O2az245xjj/Za7X3jkbd+/QoN7Kvokf98KjS7FKmeG7WXHUwMDFj3MpjpqfXUoi45NxtRjh07WIxQTffd5ctObmMXHUwMDA1cupcXFx1MDAwYvFcdTAwMDDWXHUwMDBlJ91cdTAwMTE/t7Sysba02Vx1MDAxZOHaXHUwMDBiizo4nGz2vuVRo0h++6x10OtzXHJsXCJypd/bPczjvS5cdTAwMDUn0DfptVv9qzdcdTAwMWP0Op1cIja2IbSFaHa01lx1MDAwNL1cdTAwMDaj3m7vsNX/o9FttI4mg3fd8fmNTEZH3eJcdTAwMTPrvrhcbreyXHUwMDBiXHUwMDFhdDtIn19FJCNcdTAwMGaZUV5V9lx1MDAxOVx1MDAwZZtjuvy0vt33fz7prmyqg6OzdSPN8MmDx/R8k1lZnscpgyh1gsho89HZilVlXHUwMDBmXHUwMDFh081579ecWPtHYXpcdTAwMWT2rr99erjf+Wrfb783x1+/tb6JYFx1MDAwZppi7+KpwrncV69ON4/fvt86Xt1queHOh6efd96+Wlx1MDAxOKZHUTgj/LaYXlxy11NzL1xmQ6tIsIH/XHUwMDE1hy9cdTAwMTbN/Wtzc69eu1x1MDAwN1x1MDAwM7lzXGbe5EfiOael4llPsWTwiGAzn4+tV/Z6g79cdTAwMDVcdTAwMGK5YkScXHUwMDBlyTGYXHUwMDAx6mBcdTAwMGJcdTAwMTNhKlx1MDAxOdGlhXvuXHUwMDFmqEIgentcdTAwMGK/dZpcZv6lOLXlXHUwMDA2kH5jsOZcdTAwMTPcXHUwMDE4XHKOe53uaGnYP1x1MDAwMqI+St6wMDSvwa0yms+9qEVcdTAwMDF5p9c6XHUwMDE4XHUwMDFjdirt2s+NzPNdLOVcdTAwMGLH2lx1MDAxNO161Nyuo32z1Xr2Yvxhy+rj/oFcdTAwMWavhP2jh1xy4zYg9LbO8UxcZjFcdTAwMWKZS+8yRu8sXHUwMDE3u9ao1U7sXHUwMDFhc71Rb6tcdTAwMWS1vV1h1MFkmkea6Fx1MDAwYpCeXHUwMDEyrqlVS4vrNCxTnzHvwIlSvrjvsUBcdTAwMDC/rOBZOIDrx0P9VFx1MDAxZX9ag8KAXHUwMDA2XHUwMDBmzdGbSWxcbrTi943h8N3+m82VvVx1MDAxM7HyuL39fOPsy8KA1kc97Vx1MDAxY78zoJVzgfbirFx1MDAxNa8rgXZ8g52symf8wIHWXHUwMDAx41xcPmHe89ygUnGI4kBuZcBYpTbfa5HzYNbbjF3VLFnikbVVXHUwMDA2OWuHXHUwMDFjXHUwMDEw7n3hXHUwMDFjilx1MDAxZoCyt1x1MDAwZpxvh7KDztLgcOk/h8e90eSo1cffXHUwMDBlXHUwMDA3ne5cdTAwMWShbVxyvMyg7fnFXV5aemGLQtxz71Jh3oWTXFzK5m3ZUVx1MDAxY3yohNtJc+u+3lx0PlDr9vnZ3JGDKKtcdTAwMDBX8XC3vIttXHUwMDAxgDvXvDloXG5cdTAwMGIkVcVMXHUwMDFlXHUwMDFlgaZlXHUwMDA1i3ZaOVxc8N3kvlx1MDAxYsDstWbPaee3MfvSXHUwMDFldOHCuudf3cT0ckfRPuJVspRcdTAwMDTL53lKlfA8WlNcdTAwMTZKaFx1MDAxZe22hnz+XHUwMDE5p59cYmvz3kdfXHUwMDFjXVx1MDAwZa09Tbe1Z1x1MDAxZUyyNT7vgicnf7yOz75+fP1cXO6O99eM3D34tFV1wVwiXHUwMDBiPFx1MDAwZVxcWU5mt1x1MDAxY7Y7c7k6XHUwMDBiXHUwMDFjXHUwMDEy54pNL1xyrnPBXHUwMDFi9WVXs9C9+lxui+DP8qUxTD8/Q5+6/e3BSUMuNNdbhjCXXGZcdTAwMDWeMeVtdY7x6Fx1MDAwNsHJtfstXHUwMDBm1FtKKeAued5gYFnEbHyiLGt6YExG+KiKU15cdTAwMTboL5XhVFx1MDAxYimkdVVcdTAwMWXTslx1MDAxZsrlfNVFISuqZHliL4dcdTAwMDL8XHUwMDEzXedccjyR4CBKYUVcYkJcdTAwMDQvna/wnXfgK6/fk0idu+ah34El/YGzg9zsXHUwMDA1qlxmtDxcdTAwMTZcdTAwMDPVv523rLRcdTAwMDf+zFjCXfvNaObO6lx1MDAwMl/xYe7mzHFzx3l9svyhOk7L0lwizdH5MfIwpdIgXHUwMDEyyVx0kDxcdTAwMWLB1WzPfJffzMBcdTAwMThl4PGobGIqRFx1MDAwNFe+U9vMiXl5nehl4dC6f5DPvIlHXHUwMDEyivOlrFx1MDAxMTpgvYMsluZduCRE8/qG7qiR41x1MDAxY/75ubO2/XHtQ/fP7c/RPls5a9svlZfJONJcdTAwMDfHM5GsXHUwMDE3MMpZlsmhXHUwMDE3KnqEXHUwMDE4uFxybuqZXHUwMDFiXfBP5T/n2Vx1MDAwNX9cblx1MDAxNrEg7zkvXHUwMDAzV6hcdTAwMWSccZ7B563dlYNcdTAwMGWluFx1MDAwMevsL0/c+3efj4N5XHUwMDFin3bPjle/rdiH7jyDN5nXzLCxXHUwMDBlu1x1MDAxOFx1MDAwYp9/XrLNJLJcdTAwMDXvXHUwMDBld7qcyzxrgSWPVeGpwlXOs+wzXHUwMDFk+1x1MDAxNp2aXHUwMDFl4f7T5uBC8ttrcnBcdTAwMWYu8lvr35F4m1xmXG7FXHUwMDFhadYtue5yiq36u1x1MDAxN5Vbm5s59/Mz50p4Y4Wo7K2U8lx1MDAwNnbb/mNldfRUfz3+2N48/bTtn1xy9+f1gDxcdTAwMTi7ldJcdTAwMDUwUFx1MDAwMFxmZ8JcdTAwMDQly4ZcdTAwMWJC5jiHaVx1MDAxMbtZc1xyV+vM8oymXGJcdTAwMTdcIsX1NXuXs0hcdTAwMDNrv439XHUwMDA3pc5f/PHHxtL/XVo5muzdt9VWfvVdXHUwMDFirSo8mrLRSi9cdTAwMTEzXG5TXHUwMDE1qUjV3Giv52NcdTAwMGbVaK3iKXhcdTAwMWHhfj47YaZK1nEstHYzVbKLNNpcdTAwMTBByfKj83i8oqmaVVJYv1x1MDAwYquFg8nPMbpzsL3igYst5ZohlVx1MDAwYlxmdFxuPmHahFvnXHUwMDEzjlx1MDAwZXunS2Ncbpzct0+o/Or7KEux892C4IhcdTAwMTOO2a5yXHUwMDBiurlbeLuxt663X+iNfbv5rLO25tdcdTAwMDZ784bUPVx1MDAxY7dcdTAwMTCFzni2XHUwMDE3sFFcdTAwMWLtSyRcdTAwMWPsm51OnGdcdTAwMTiu3Vx1MDAwNt9cdTAwMTGhLcTtvILiXHSYilx1MDAxZHRVaV/Fw1xcXHUwMDEwISRJ4cuKcjbdXHUwMDE5VYywfoaalOOz8dFZODl96d5+tJ0tfTZ4/alx8eee/PrxaGUy7m7vvVl9evx6c+/L5PfFeaJcdTAwMWKyk9uB9DXpRMtYXGZxe6U1mubWWP2MXHUwMDFmvDV6kV10pzrHMTglZi1gjt5cdTAwMDetjHHujsxRwiNcYlx1MDAxZnnYK/v6XHUwMDBifaOFvZhcdTAwMTmUltFEXHUwMDExwC3+QeR6Y9D5z+HqJfqNb1x1MDAwYqY19Sg1uFJRj1J9UYuC2W6/31x1MDAxYo4rmziMmlx1MDAxYjJzWq9hW1+VXdvmdt16ufP+3dej/cngz3ZU4vOnlY1h+2FcdTAwMTd/Sm9cXMZDg/OzPGYxVtpcZuCnOWdcdTAwMTiWXThqcaFWrU1cdTAwMTaU0JXFKMZJXHUwMDFljeuqMJaRvNI2/FxcZZ9cdTAwMWRxNGhcdTAwMGI93lx1MDAxZO9MXuy8dJ3BaLNx38Z39Ff83aFb67n1Zo6lS1x1MDAxY0RdZeGuuYVXL91DR27vY6aByVx1MDAxMVGt8bGQO7yooJCg2dFcdTAwMDdcdTAwMTMkp3V+n5HPa9RyIYuW50g5XHUwMDFmWOldUVA6i9xeW1x1MDAwM6hfgH3/LLj9mHN0/nO4eTaedFx1MDAwZu5cYrVrcKqM2nMu6Xsxu4k/m7f9n6u1c5xJYpS3ynObpqTWSvGYcckjp1XknIxcdTAwMTmVXGaKXHUwMDEzolx1MDAxNefLKqOFqCCTQCZcdTAwMGLwXHUwMDEzQVlCjSx4kPpm69uko360XHUwMDBiuWWztfSPKs2uXHSsXvVocUZcblx1MDAxZXEsKvZVWDZ/w4NBNohK4XOLasK+fcfWQjeL5+opf5ZnVXQqb1x1MDAwNppcdTAwMWLukddv/F/f97VUrOny1lhOqrFSXHUwMDFh4YunXHUwMDBmX1x1MDAxNSdcdTAwMTgpNU9H5tlcdTAwMTR3U6hwvc9bSuspLM+LM96w1cIqN3vFOjOe03csy7it9DcrSfuuMoQm2/5NKN21rjVcdTAwMDRcdTAwMDTzWjIq4lx0m+UzjKR03GRT1lx1MDAxYlx1MDAwMe8qZl2rXHUwMDEzXHUwMDE5x0PCOyO0goHGqnQ6vlx1MDAwM9/EXHUwMDAzt6DXYPi/fGu1b1xy3+9bLciv40D/Kt+q5o43MJwuzDlNXHUwMDBid63cV/DTR/OjXFzrfD3lz/Ksit6Hb23sqzhcdTAwMGJaXHUwMDEzN420XlxijVxivYBcclx1MDAxN77KZSDcrKr1PN5dJtX9XHUwMDBicq7Xp4FS58r9vVx1MDAxMFxcfoaUYqXvzFx1MDAwNUvAXT5S3MhcdTAwMTBcclx1MDAxYilcdTAwMWWWd62LQ838YymktsKFxFx1MDAwZVx1MDAwYna+0jxcdTAwMTD9dHo8XHUwMDE5a3/0+Wjr1dh8XHUwMDFhXHUwMDFkXHUwMDFm91ovXHUwMDFljqebXHUwMDEziCrhODCex0JpeIBQXHUwMDFhz1x0JpeBx5h4l1x1MDAxNanWgG3E6GDM4Fx1MDAxY77Z/Fx1MDAwMCypU7bYgfFcdTAwMDP2eVx1MDAxZj/fer92uqnt5/3na+J99/OuOPlQsLJcdTAwMTlMv3rlLlI031x1MDAxN+a+XXuyet9cdTAwMWK86XcuJnxtPd/deTV+fTjc+PN16Fx1MDAwZVx1MDAwNjvL7f6XWY41k5c+r1WKnsdfgfhcdTAwMWGeXG6nSlx1MDAwMax2MfNcdTAwMWNjXHJi76MsbKJfXHK/MVx1MDAwMa5cdTAwMTLE2nM2p5BcdTAwMTXp08Cpolx1MDAxY1x1MDAwMK0ssMIpeY2N3mIuz2TUOlx1MDAxY1x1MDAwZlsjrNnD8T635VnDXHUwMDA18CzlgzB2tqw2t7S5uFx1MDAwMMdcdTAwMTg9z2u/zSCxW6ah945efzRHr99cdTAwMWXGzeXO6N2qfHXw7kvTdPHD8kXXXHUwMDE4aPVdzlx1MDAxOGjF6D74+0xcIvxcdTAwMDct5Im2urTfqTmZz4M4Rlx1MDAxM4wvXHUwMDBleZ7WXHUwMDBlaM64XHIusIDX2Yox0Deb3fdPM8dcdTAwMWLM74N3XHUwMDE0NrAgu8rw1ExKaWp4XHUwMDEyXHUwMDBiXHUwMDE0iyNcdTAwMGJcdTAwMWXOXHUwMDA0P1x1MDAwMtbSWlx1MDAwN9+Gh7p0OTqnsLA/bIZfXHLsVSHvdTeyXHUwMDE4LL7eJ12b71x1MDAwMHxmPO1cdTAwMTbkU1x1MDAxNE9HvVx1MDAxY4HDc9eFMjEoo+MsXHUwMDBlg1Naza5A5lx1MDAwYlx1MDAxOTBWWLpQXHUwMDE5h8GH/Fx1MDAxNIbiIM9fhn++hlPDXHUwMDFmfTdcdTAwMGUjXHUwMDFhhvFcdTAwMTXr5lx1MDAxYU6dQXxcdTAwMTaKx1x1MDAwNvzN0lx1MDAxZHNcdTAwMTWVPzMqOpU2g9lcdTAwMGLLdVxcXHUwMDFmyC5cdTAwMTVzXHUwMDFkynqPxbFcdTAwMWHWalxc8cjhi8SBIdX1VmvQMFx1MDAxNlx1MDAwZsaimFx1MDAwNaWRr3V8S0mmw1x1MDAxOCl54rKNXHUwMDBlf1xys9f7nVnjmdzFLVJcdTAwMWL/uljUR63hcHNcdTAwMDKdvbr3R8e97snjysCaPyR0+bXRy3Rz8/zrX3/9f1xmJ4VPIn0= + + + + + EDGE NODE ON RESOURCE PROVIDER1. Node with exposed service at the edge of HPC clusterVirtual KubeletInterlink API ServerProvider pluginPod on virtual nodeVirtual NodeHTTP + Authunix socketPodContainersBatchSystemOIDCOIDC Identity Provider \ No newline at end of file diff --git a/docs/static/img/scenario-1_light.svg b/docs/static/img/scenario-1_light.svg new file mode 100644 index 00000000..a517f3b1 --- /dev/null +++ b/docs/static/img/scenario-1_light.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO19WVdcdTAwMWJZ0u17/1xulu/jLfI789BvXHUwMDE4T3jAlClcdTAwMWLbt79VS0hcdTAwMDJkXHUwMDA0kiUxuVf997t3MihPKkUmWGBcXGWqy+1CUigzT0TsXHUwMDFkcVwi4vz3X0tLjyZnw+6jfy896p62W/1eZ9Q6efRcdTAwMWJ/f9xcdTAwMWSNe4NDvKTy/1x1MDAxZVx1MDAwZo5G7fyde5PJcPzv//mf1nCYTT+VtVx1MDAwN1x1MDAwN+ef7Pa7XHUwMDA33cPJXHUwMDE47/1/+O+lpf/mf+KVXoefX/lcdTAwMWPl9mjzY+tl/9v41WdcdTAwMTFcdTAwMDabvZX8o/mbLi9o1G1PWoe7/e70pVP8XmrhM+GtMdaKqL2yVy+f8WWhVSZcXJB4i9JaiXD18kmvM9nDW4xwmbDGXHUwMDA1P/3oXre3uzfhzfqQOa2CVFbkP+7qPedcdTAwMTfz7yVx9ZvxZDTY765cdTAwMGX6g1x1MDAxMa/4/+yI0Fx1MDAxNmJ6vdut9v7uaHB02Cm8Z6fbjnH6np1ev785Ocsl4yHjYT4qyd+6uG5Z+v28T+FcdTAwMGJ391x1MDAwZbvjcfKZwbDV7k3OXHUwMDFm0fRcdTAwMGV4dcO1Tr5W/zu9plHroLvGxTo86vevft077HS5XHUwMDA0j7aLN5nf38XXXa70dFx1MDAxOfXFb/6aXny328lcdTAwMWa0j8Jf/XaqbtqF8m/XXHUwMDA3h7nqRVx1MDAxN72QXCJOr2j8XHUwMDA02jbJXHUwMDA17rT64+700fOqnpY1saiNibJNuqeTq1sq6OrXXHUwMDE3Zufj20396s1cdTAwMWZ7W8OTbW93O38+unrfX1x1MDAxN3+bPrqjYad1fj3SK2dcdTAwMWTuxoYwXYZ+73C//Fxc+4P2/vRcdTAwMTb+VXhcXCXLqb6aXHUwMDE5y0lu5sJonM2sV0E7ZZ0xKpSNxtdcdTAwMTiNXG5cdTAwMTFGXHUwMDEzo3BC2GCjmTVcdTAwMWQr7tNU9lrtvaNR92cwXHUwMDE2WW0sydsvrFx1MDAwMutcdTAwMTN9XGLGVlx1MDAxOIbyap5hSG9s8EZHf1x1MDAwYtNIruP79XeqjlRDPICnT54/XVp/++Tp0tv1pXdPN9++f7f6dOk/h1x1MDAxYu/eflh78vRdYYFcdTAwMDeHk83eN96RXHUwMDEyyW+ftVx1MDAwZXp9rodNxK/0e7t8NI/auJfu6FHx+Ux6gKarN0xcdTAwMDbD6attSGz1XHUwMDBlu6O1JoA0XHUwMDE49XZ7h63+XHUwMDFm197P7N20jiaDd93x+f1MRkfd4kPsvrg0XHUwMDFimSlbafPXXHUwMDAwYUEp7IyqXFwqhZIqOlx1MDAxN5yLVUrZetRAVc7djtNcdTAwMWJff4/t10+fd549V09aoydbrf5DQbBZV8NcdTAwMWK03mRKO22iMULA+yX+LsKZ4SVtZ9xd2U3JLv+53k21bCfs7Ezfc+kybTBcdTAwMTm+XHUwMDFiLvOcS0zv5MplXHUwMDFhpTLpI6iIifnP1K1eOFx1MDAwNKmMcV44q2/nhm6KzjO4eefQ1kjN9axHvPJ9VkvrXHUwMDFjnmCVmm83V/Ozky9n4fnqyccj8eXrwejV23cv/vzj4aBPtaL7IDItnHMyVii6XHUwMDA0z81cdTAwMDJ03FxiZaP0/k5cdTAwMTRdm5CBjmupKlxitTQ6s9piidS5jvuyilx1MDAwNyGM0bJw6X9TXHJPeVlBue1cXGB31kBcdTAwMDdC0FW63W6u299cdTAwMGVf/bn/XndG708/nJ6tvX+/uv3m7KHrtlVcdTAwMGWqXHUwMDEzXHUwMDEx5lx1MDAwNa1UXGIpaY1aZNFqXHUwMDExrPRU/ztRbe9xXHQ+XHUwMDA24aSJYL5xVsG1LSu0Q2iDy1Xx+1x1MDAxNTp5obHmeq29Nz7eirZcdTAwMTVJWEh+O4eE8Vx1MDAwMcpsaX3Q6S6d9CZ7S93T4WDc7SyNu6PjXru71JosTfa6S93ObndpsLP0YmN1qd0/XHUwMDFhJ4RtYWwuucUydfvuy7xcdTAwMTdOXHUwMDA3Zz1cdTAwMTfsonfgXHUwMDAzskj0p1x1MDAwZaHT3CFMTv54XHUwMDFkn339+Pq53Fx1MDAxZO+vXHUwMDE5uXvwaeuhO4QgdFx1MDAxNoFcdTAwMTTzwC7azPP52LtcdTAwMDQ7IbOYo8NcXFZn8Y6o5Fx1MDAxNakruKZzXHUwMDA34Vx1MDAxMY+bIOKP4nRXn7lRLmR39GJt/YWfXGLZds86wk6ef42PXHUwMDBiuZDfqsWef1j8vjFcdTAwMWO+23+zubJ3XCJWXHUwMDFlt7efb5x9Sb/l8vtbo9HgpKncOFx1MDAxY+ndk9PVXHUwMDBmXHUwMDFmV/Xvbbf1QlxmnjxuJvfib/eUu6l+elP/Nzd3XHUwMDAz8M+8hupbq51SPqZKXHUwMDBmrc+UR1x1MDAxOFxieEqU/lJhpVGZZuYmXG7rnSwkXHUwMDExpklPe43hzVx1MDAxOE/0sq3+XHUwMDE5mZvOh+apm2BUhF8yU6OeevRcdTAwMDJcdTAwMTKXXHUwMDFjelxiXHUwMDExzFx1MDAxN1x1MDAxZa2B577vxM2H3mhy1OovvTra5lx1MDAxNd1Lnuag1+lcdTAwMTRRsZSqqYGtMt7PvYNF4TjfXVx1MDAwNeEhinkrLoWSXCJE2GqVxnWbQ/hK7P/+bfJ4f//FRm/txfrxpndhXHUwMDFlp2+PXHUwMDA24/HyXmvS3vvxMO7g0aQwTntrlHCi5NGEXGaZkyD11oiofMGgbuOKtHLtrp3FcalcIoJWRFx1MDAxNyYo6YHHXHUwMDE1oauyWVx1MDAxNC5GJ61cZipcdTAwMTSw/jI7XHUwMDAzlu1EwJ1UupopNo9emr2dz19enk2Oevth6+zw9+HXzVx1MDAwMkw9ev9p7UtP7Dw9XHUwMDFjPH+3tr4+7i6//fb+XHUwMDEyrO4hZPguhzGetEaTx9Di3uFu+SPdw86cV/qt8WR1cHDQm+AyNlx1MDAwNr3DyYxnpdxcdTAwMTXC9l63NXPTkDz3tSHFpWsw/dvSVFx1MDAxZvP/uPr7//62gHcv61xm4ZcyJmqD/1x1MDAwNyq75PNcdTAwMTlcdTAwMDA9XHUwMDA246VcbkpHo0OtQFx1MDAxMzKrYjTRwcLhPXxRnlJQY6H4TS5cbm3cfYtcdTAwMDPbRaCOd9tcdTAwMTiksMIm4kxcdTAwMDaeXHUwMDBiXHUwMDAz0SriO52uXHUwMDE3XHUwMDA331x1MDAwMI5cdTAwMGaKLH1ApGNcdTAwMTJxIVPGwVx1MDAxZSFP4fJkrThn4MKtNNb5XHUwMDEwrDChKFx1MDAwZcG9U9xcdTAwMDdWIEfG+vqlWLw4rYP3XHUwMDExXGZcdTAwMDAuxiU3XHUwMDFiRCZcZlx1MDAxNMlcdTAwMDNMPJhdvTSdXHRcdTAwMWRcdTAwMTD9RKVMiMm1weXil1pcdTAwMTmEJVoqUy9MZVx1MDAxNjdiLdxekMH6kjSwSWu9tPiuqFW9UchMK0REykXtXHUwMDExwenkViXUzoPaXG6pJC7fqfqbXbhA6JYmf5POc+cg2pBcbrSZgMHihqHF1Pd6gSazXHUwMDAxXHUwMDE3J5jh10basrxcdTAwMTRb6uThXHUwMDAzWFRcdTAwMWI0kdNcblxcwzXy6rVl0eJcdTAwMTCFwKE556BcdTAwMGXBXHUwMDE1djKunlx1MDAxZb5cdTAwMDSaLGg8oVb/tMrghISDR/EyKjGzui5Kg6v28KPC1i5cdTAwMDZMw2BprcTHYFx1MDAwNr5sXHUwMDFiXHUwMDAxLMTSaytowP1cbrPgQlbCacDcYOW+5Fx1MDAwMoyWxiltXHUwMDAznLWOXHKkXHRcdTAwMDRcdTAwMTNG5Kym5Fx1MDAwM+ifYP5cdTAwMGWsXHRr5Vxc7bXZPN1cIlx1MDAwM/BcZmtcdTAwMDAjKvliXHUwMDE5oT7AMVx1MDAxOVx1MDAwMCbR3rc4qFxi9EPDg1x1MDAwMk9h5WXkQbSrqFwi8NRYqFpvbKDCXHUwMDBlrlx1MDAxOF+udVx1MDAxNCpcdTAwMTWHIDpKXHUwMDBidbNcdTAwMGXr4VxcrUWYTGJcdTAwMTGwfLhcdTAwMTdn4YJmaFx1MDAwMGJ6fFx1MDAxNcVhwWrtf9Hyllx0L3lcdTAwMWRcdTAwMTS8XHUwMDFl1EHBVyVcIpcl31x1MDAxMDT+XHUwMDA1XG6A5lx1MDAxYd1dlrX3PY8t/av4/zeNp2jrc1x1MDAwMyqm51x1MDAxZP4sxNDTgGqneUC1Nd58az6vrHftk6O1/uNcdTAwMGZxS/rfXHUwMDFm9j73eSil6T5KUcxFXY/JXHUwMDFjIFx1MDAxMvZOzS1cdTAwMTSz3S6rU5FcdTAwMGaNsLOgPVNcdTAwMWZcdTAwMGV+ulwiXHUwMDFkXHUwMDFhNbfBNXTXRi1cdTAwMTDQzURRcJTAXHUwMDA17avzoVcq9CtI+vtcdTAwMDRJMoPTXHUwMDAxXHUwMDEwwJFcdTAwMDZQZkRcYqk3i9abIGn2XHUwMDAwXHUwMDBiqWvBYFx1MDAxOYzAOiHhXHUwMDFkoWdw4TZhXGZUQVx1MDAwMWORWmisYmxcdTAwMTDX1Fx09Fx1MDAwZWCF+N/qgODGfv9cdTAwMTXeQiBcdTAwMThcdTAwMTfwSuJcdTAwMTNMXHUwMDAx61x1MDAwNO1cdTAwMWT4MXxi8Fx1MDAwMp6bYUlcdTAwMDN5XHUwMDAyolx1MDAxNFx1MDAxOD94XHUwMDFmiJxLXHUwMDE5q8wrajTJNCSbRlx1MDAwMkNcdTAwMDTiwzVcdTAwMTlng1x0psTiMjBPXHJcYqL940Lr4yWVRTxBxtX0dTYkSiPxXGKB9VwiXHUwMDA07lx1MDAwZeFp1EPgouX5LHAphGXhXHUwMDE1o+FEXHUwMDFl4lx1MDAwMU39g0gv4G/rgzA8XCJP1+pcdTAwMTGIg1x1MDAxOUWVXqAjQIPl4bvAXHUwMDFlXHUwMDAx0/VcdTAwMDJ9hlxiXHUwMDEwi8FlXHUwMDE03qlEXHUwMDFlo+tcdTAwMThBwLSJXHUwMDE2MUl9tK5kXHUwMDA2/uA9XHUwMDAyVFx1MDAxMC3Eglx0Z5JcdTAwMTm03XtcdTAwMTVcZt5cdTAwMDAu3MDoXHUwMDEwlYCGaIu3e1x1MDAxYUFyw+B0oNZcdTAwMGXvXHUwMDAwXlx1MDAwMHN0XHUwMDAzXHUwMDE1dJnBWihcdTAwMDYz/CMxXHUwMDExXHUwMDA1Qlxuhlxi/FxmXnKd6+PYhctcdTAwMGIsvFx1MDAwNVx1MDAwYtNcdTAwMDFLaZxXJYHeQo+MXHUwMDE2gbZZy/9cdTAwMTlcdTAwMTZD/Vx1MDAxOIGARHtn07hdIZ7weLjgXG6K+df68GRZI9ihXHUwMDE5QFx1MDAwMSNcdTAwMGItTEljXHUwMDAwh/BpzoKD6OjrNVx1MDAxMIxcdTAwMDQqK5RcdTAwMTDeSlx1MDAxMFx1MDAxY12Sx11cXFx1MDAwNlWRil+vMItcdTAwMTaHsNdaPCPpsFx1MDAxY16VomKPICBcIjRAXGKDh1hcdTAwMWZALWteXHUwMDAxQi1cdTAwMGJcdTAwMWZcdTAwMDJfXHUwMDE3y5dcdTAwMDcwXG4+391z+K5cdTAwMDZZj1x1MDAwMFx1MDAwYlx1MDAwMCaypFx1MDAwYkGh0eXVXHJcdTAwMGXPgVx1MDAxMZGF0tSL88yBw6CYQUFcYjVcdTAwMTPycE9cdTAwMGL0XHUwMDBlT1x1MDAxNo6tweU5hCFGXHUwMDAwyGCeuKdyalx1MDAxMXqEXGLFXHUwMDA3xoCx3t0vWlx1MDAxY8mwxa1cInSH70gzRvAtsFx1MDAxOVx1MDAwZqdcYu+CXHUwMDE1aSBOZDZcdTAwMDbGqnB+MIPUcl1cdTAwMTbPk6g+eOhMg4xcdTAwMWLkXHUwMDAxOCyzr1hcdHysnPo0kWVyXHUwMDExYahSoFx1MDAwZvW+JWZcYlxmLPmE4Fx1MDAxNqNIrzBm+DWWNk/XMDtz/1x1MDAwMpnlUVA9J8gpbOr8sFxcUWvCXHUwMDBiWFtskK7gXHUwMDAyXHUwMDAzi5jgZOZcdTAwMWQ+uCjOXGLWbYDZMJBcdTAwMDVcdTAwMTA3IFjwXHUwMDA2XHUwMDAy/iN4R1x1MDAwNyOmNWa5PM90XHUwMDAxeYtcdTAwMTZcdTAwMDZg1Uz/XHUwMDAy7ldJXHUwMDBi8lx1MDAxN1M2ZDXoYcRvLf7R4Fx0XHJu12Z4OFx1MDAwZYaOlVx1MDAwMFx1MDAxM3AleVx1MDAxMTZcdTAwMGLKQN9cIppkVFx1MDAxNyxcdTAwMGVcdTAwMTZcdTAwMDDXXHUwMDA28IdnM6VtXHUwMDA2azNcdTAwMTghOCvcMnOu9apiJK6OVFx1MDAwN1x1MDAwNo/lc2VxcHjMVbs8XdZgT8WAXGKBOVx1MDAxYlx1MDAwYl31pWSKdbg6UjXvoJyhyZ5cbu5cdTAwMDeoXHUwMDFm4JJcdTAwMWQuJHUtXHUwMDEwpyX4XHUwMDE5XoHHXG66kThW74NmXHUwMDAwybmd8LDEuYycXHUwMDFkWlx1MDAxZsBcdTAwMTWlL4tjvs1FwFx1MDAxMLyZaGC2sCTgoLdRkZKE0uV5KJ6B23agzVKqXHUwMDA2muKoqlxuulwisHygLElUJDJ8XHUwMDEzliiA/UaQrnovXHUwMDAweVx1MDAxZWZcdTAwMGJcYlx1MDAwN9JAXHUwMDFk0tQ2XHUwMDA0srBcdTAwMDaMXHUwMDE0QVx1MDAwMpG8wf2S5DJcdTAwMGU1XHUwMDAwXHJoWeL1XHUwMDFjXHUwMDE4NbyeZ1JcdTAwMDQoXHUwMDA0PGiiy4jxwPVcZjwv4CtccjsgkLG0cPhcIpZcdTAwMDE1iKWNJlx1MDAwYkLU44VcdTAwMDNcdPdcdTAwMGKQXHUwMDA3XHUwMDFmwC0xgII3KVx1MDAwYoI8wy1cdTAwMWNcdTAwMDV25FxyXHUwMDAy4HtcdTAwMTcnspzCsv1cdTAwMDJxbeluXHUwMDA1Q1x1MDAwZTiqXHUwMDE4sMxNnJ6Ak1x1MDAwNCZoR0qaXFyajYigmbBG+CVcdTAwMTHVNdg1Q8hcYj5cdTAwMDBcdTAwMDJcdDDzQpXFXHUwMDAx7ExeiFxiuFxiXHLCP5B5UEfPkmrNqNGV5OGJ4luAXHUwMDAyXGLLRYNgY8HiRO7iibdeXHUwMDAwMUp6XGarsZbFUiyE87ZBbOV5eXmRh45w9unKepF5QJ1UwYI/ilx1MDAwNslcdTAwMDdcdTAwMDU+YjVA32NBpDKJ3XpcdTAwMGI36jTjU4svbWBcdTAwMTWIJnBcdTAwMTeOXHUwMDA1YFDmKEqbNey3xCV7vlx1MDAwMupRL47RO/yQ5Vx1MDAwNibgq7yRJFx1MDAwMsBWMbp3scHu5eLFXHR4SFx1MDAxMFx1MDAxY2mZXHUwMDAz84muXHUwMDA0OD1EuVx1MDAwNtRcdTAwMWOeVtXfLENcdTAwMWRcdTAwMDNSzTRB1Mqb9PJcdTAwMWM3wllcdTAwMDCPP41s8PCUzFg/XHSyXHUwMDAy9Vx1MDAwYsGn5Cdwb1xuZMZr8DZymia6olxms302kq1cdTAwMTTqtS/kRTB4b1x1MDAxNPOAXGLXfoQ8aLCW2nBcdTAwMTfTWpXoXlx1MDAxNFx1MDAxOdiPZ1Ypgus1SUXy+nSQhmlcdTAwMDeWliS2XHUwMDExsbzkRSCQQlx1MDAwMklcdTAwMWLllXInXG6mrLHKJt3bi7h6qFx0iFx1MDAxZb1cdTAwMGY8c736xYx7z560XHUwMDA0qJbmqWY2KJqIY4aFgTO9m4ulq0NY6OG+glx1MDAwMjOI9Xeb21x1MDAxYaNPXHUwMDA27oJAU5JcdTAwMDdcXIJEZmRcdTAwMWLQKWYpoFx1MDAwYlx1MDAwZTZcdTAwMWJcdTAwMDTUXCItoYl5XHUwMDFhN8KLsu3K1u/EU1x1MDAxZfBcdTAwMDU+yFx1MDAxOWAu7F6XdFx1MDAwNTbBWDB6+opcdTAwMDZ3u2h5LlN0ucZcdTAwMGKQWyd92TaEXHUwMDA3k4FcdTAwMTbD3atcdTAwMDZJXGZcdE9OXHUwMDFkIWowV5tcdTAwMTb5XHUwMDA0wJBcdTAwMDJblVwi4iFcdTAwMDZX71x1MDAwYiSiUtyqNlx1MDAwZTQ7MFxylci7LMyJpCyhifJRXVx1MDAxOaRcdTAwMDH2aXBJlFx1MDAxYvJdXHUwMDA2p6nqtO56WJPc2Vx1MDAwNlW2bFx1MDAxYsLnSp5cdTAwMWVsjz5cdTAwMDVxKcHXNzC1XHUwMDA1y3NMSktunFBt4fNt+fHBXTPwXHUwMDBiXGJcdTAwMWbqWUaeZFx1MDAwMYYz8lR4RjJNOrB8XHUwMDAzIYOialx1MDAwMvbqQz9ET1x1MDAxZSvBbDlUzOlyMVxiy9jA0jRcdTAwMTbZ16dH8fAsXCJccnwxnLJQprS4N4RJaopDXHUwMDFjppiAXHUwMDA0ekRVVlx1MDAxNWOMY4FcdTAwMTmgw9dubyxanGHyXHUwMDEx/lODqMNLXHUwMDA1U3p0oOJcdTAwMWUqXGZQbrA3RC9cdTAwMDD8jsztsYYjlJ1cdTAwMDC+h/ZcdTAwMDK7cfXkjD5cbrzWXCLw057J7bKPMtGwXlx1MDAwMlx1MDAwMOVcdTAwMDFpXHLEcdGY+IFRXHUwMDFhacvwKIOh9eO1XHUwMDE461x1MDAxZtxipVx1MDAwMXxcdTAwMWO3tY2E3TqbljNFNo84zVx1MDAxYYKgPFx1MDAxNrdWXHUwMDFjaD9UXHUwMDFlXHUwMDExNlx1MDAxNlx1MDAxNYgrS9JcdTAwMDBuiFmA2lx1MDAxYV6+1rrAK/LNNISh+X6LKmNZhMIh9NCM3uqrS0lTVFx1MDAxZVx1MDAxZDpgs4oylMR5WF6+XHUwMDFiyLRzrZaQRSFYJ9GEuzUlXHUwMDFhwMZseECGRlx1MDAwZcpUX+CHi0NcdTAwMDTKWEVbLIYpaXBcdTAwMDDdRpjHfLipj1x1MDAxZMlojTReXHUwMDFhOFx1MDAxMbi5Mp81XGLJoOFSMni7X2HcpoieYU2e6k75XHTwXHUwMDE1hC4wxy1Y3lkrjpFcdTAwMDWAmISfg1x1MDAxMtIkbeB2XHUwMDE4XHUwMDFjNL5PcMur3lJcdTAwMDOor2JcdTAwMGVcdTAwMTbmRc+d+jjGPUBcZpZ0ws3VYjUsXHUwMDE1JJrzdlx1MDAxMLNyQzNxI1x1MDAxZbQ9ssVcdTAwMDG0k6n9elxy0YxcdGFWMGwymlx1MDAwNFlcdTAwMTGAqnxcdTAwMGZWM0Cuz2shOsbTxSWBlUCnXFxcdTAwMWG9IzpcdTAwMDZnUYhorVx1MDAwMWmvXHUwMDBmj9mNjfU0XGbg8bhcdTAwMTNcdTAwMTVB6K7PKalkVlXWXlx1MDAxYlx1MDAxM1x1MDAwYoF8XHTxO1widFFOLIC4gkDAJ5Fk1z42ZlG4v8Z6XHUwMDEzRIPBl6Q5XHUwMDEzXHUwMDFjyDzTbVxySklcdTAwMTcsjXv4IP6KSFx1MDAwM36vStL4KCXoXHUwMDFlaFx1MDAxNGhL7YMzXCLzTHv6PPflSntIXHUwMDBlludcdTAwMThcdTAwMTRcdTAwMTg+WPilWnFcdTAwMWFYXHUwMDAyMGXRSn5H5UxbXHUwMDFlQ1xi06CgXHUwMDFjothcdTAwMTJvmJdcdTAwMDVVU2VRltX0MpDJhXpAZYZcdTAwMTK4ZEHBqcNcIt2W/uHioO8we5BMai+QuiTNSXxcciRxmll9MMx0e1RMfXtcdTAwMGZklzPpZ1xcXHUwMDE20FlbuM36XG5cdTAwMDEm21xyq0SxXHUwMDEyivmYksLhXHUwMDBiQO1cdTAwMDRzdj7UX1x1MDAxYp2IZ/V40PSLqfrCl+Y0XHUwMDE2ZFx1MDAxME+j3ofk14bbXHUwMDAwkUecVEq0Q1x1MDAxYeuScLfUOF2/XHUwMDAzhedcdTAwMDb+o1x1MDAxMaXDVp3zvrzHXHUwMDAzfXQs32a6olx1MDAxZVDzLVx1MDAxZe7+R9hcdTAwMTVrZErSXHUwMDE0Y1x0XHUwMDE2doGh14c1xmTchKSSsOrLzew/XHQyaSCQZlx1MDAxN9w9S5N51YnO/Vx1MDAxMnxIqlwibFxmgJOHXHUwMDFlWptvNjRwcexxhatg9Mbdl5I8KXTePkSWXHUwMDE3XHUwMDFhgIPNPHwsXHUwMDFjUmCnS5zZp1x1MDAwNKfQeek3qGN9zVx1MDAwN3dlWUAnc8ftYiyJc3ntXHUwMDAzPD58fT2JW7g0PmjBXHUwMDFhXHJthU90jlx1MDAxYtCKSTXcK/NcdTAwMTH19WR5sVxmLJX7XHRCXHSrk5XgXHUwMDA2Ob9cYsCrgFx1MDAxZvWNaZy0XHUwMDE5rYeriIKJ9lx1MDAwNPN56dxcIlx1MDAxNFx1MDAwZUSFpVC1V6eAdqBcdNws9i5vjfstfVx1MDAxNdG9xoVcdTAwMDO+XCIoTj3Bidn5vEKEo6DTdqaVjFxcOzCjXG6X0qjDZZHiNGNITeT0hOJy8VxiXHUwMDFlXHUwMDE4O408XGY6NOivXCIpXHUwMDExrMN2mlmDtHeJpS2ej1x1MDAxNjhcdTAwMTFcdTAwMTD+Nrg4lzEkXHUwMDBm3OFcdTAwMTVsO0jEKXJcZsvxnWTc9b5Oe3a5cT+HwUu61a7yXCJWgUhcZmE0iXD9rS5WWsicol6x6NaKlGkya1x1MDAxY7xkpaFlJU99clx1MDAwZeK48ShVIFx1MDAxOEtVrveyzGmCTSmjXHUwMDE4YDS4V1x0lII+IVx1MDAxZVx1MDAwMekvV6MxQonMXHUwMDA0XHUwMDA1w4RQk2XlPqZEKFx1MDAxN50sSzMsMlQycphkXHUwMDAz60e8kT+XPE1cdTAwMDbMNiVxmuk1w399k1BcdTAwMWacP7K+UMKOYEVOllx1MDAxZZ2g+lx1MDAxYVx1MDAwNixcYlxy6q9cdTAwMGVcdTAwMTGEXHUwMDA36GBt8b9cdTAwMThT0OFKYJmwXHUwMDE2LDxiNfO9y1x1MDAwM1x1MDAwYmTZXHUwMDEwwMLAMl2YqeRj1pO7zlx1MDAxMm6iPmud15HCXFzhilx1MDAxMaSrUlx1MDAwNVxu60ixTkzZMeDWXHLSXHUwMDA3IE9s0Vx1MDAxMsRcdTAwMDOYhpwpdDVwXHUwMDAxwWp2nNbX4bKul1x1MDAxM3vgUaCnLHcsOSju+ELJZVxmLPSrXd6Fy2MtXHUwMDFmjImZZNZcdTAwMTOm4Vx0l4Pmj5dcdTAwMTDDwzHWiZMgNYicXHUwMDEx0ll6cZlmwWBcdTAwMWKKXHRwXHUwMDEzQ74xXa8tLFx1MDAxY3CAXHUwMDFlWFx1MDAxNFx1MDAxOVKaUpdAWrhcdTAwMDHL2lx1MDAwNYJ6PWtXXHUwMDE5XHUwMDAyXHUwMDFk4cGIXHUwMDEx3Vx1MDAwNcTRqSdApFx1MDAwNlx1MDAxZcBdeDZcdTAwMTVZWf/0XHUwMDAwV5aNylBcdTAwMTZcXKBIU+p5nT88LHxcdTAwMGJbXHUwMDAwXHUwMDFhXHUwMDE0XHUwMDFks1x1MDAxMYFxk2HdXHUwMDFkQq40imUjXHUwMDAyXFwse6xBK9naVy8v7+zlJrtjeiStXGLKuO1ic+uIXHJoQFx1MDAwNl9nmVx1MDAxOYHae5fuRuDJ4ZusXHUwMDAy9SNcdTAwMWZz9cVANeLob4Bzno1cdTAwMTdYkPtcdTAwMTYnXHUwMDE5XFwyUctcdTAwMWFqhP9pco1cdTAwMDWV3rOMXHRcdTAwMTRcdTAwMTTkvtHmXHUwMDBiq41xXHUwMDE5cEFYYDz1VKBgaSFdospcdTAwMDfYqfrtybtpN1x1MDAxNNPmnHK7oeYuk9aictzobvNuQ7H25WXrRfw2fNs7XG6Ptzs93Vx1MDAxN29+ivEtPmY5yOm84l+UZ4kzQuSANs9u1WC/r+dw7vhcdTAwMTZcdTAwMDTcLuQ7XHUwMDEziFx1MDAwMlx1MDAwYmOvptNb8Fx1MDAwZfg4XmTgSLiZuaOsXHUwMDFhXHUwMDE33Fx1MDAwN6+e03ilSr/aXHUwMDBlXHUwMDFmcNvhMmvG4LjzST6sIU0zz5d771xiVZhPdlxyulx1MDAwNCDQS3Juxao1IYy7RmCTMrSFXHUwMDBiRJCDXHUwMDAwh/28oGYstk3kldW+Vlx1MDAxYzNcdTAwMTaMpqzL9zXSjKC0eTFcdTAwMGLxzIo8bVxcK2+eafKHJW9cdTAwMWXLoMCMPGdPNCiTW7C4fFx1MDAwYofhXHUwMDEym1x1MDAwYpjOTSFSXCLgZl2g40LVJ9zZ4+hB5FgllVx1MDAwZnws9bGyRolcdTAwMTM72Y1cdTAwMDVQadSVL6jRjEhcdTAwMDNnX4RSqJFpXrxnUz6bc4ztLtdnfu5cbiXnXHUwMDBlKmVcdTAwMGJcdTAwMWN7XHUwMDE2K1x1MDAwN1x1MDAxN+/dYMjZYF1cdTAwMGZbQ386Ontcbu88Wn45ls9+XG6UXGZcdTAwMGVBXGJcdTAwMTSD8ZZcZq485FxmKFx0xlx1MDAwNFx1MDAwMo5w293RiDPH4fJcYvhYXG5cdTAwMDRmVXXeXHKtXHUwMDBiXHUwMDEwI1x1MDAxZLPG4FxcaqY7P3L2XHUwMDEwi/Z+oeRPi5I3e3fIXHUwMDEw5VwiLGRxPVvW07a7XGZOiYO5XHUwMDEwLmkjZH2VxHw15I9n8b3n+lx1MDAwNSvpk+vEMbaXrKtcdTAwMTA2L9FLxzRcdTAwMTGuhEMsbySTSPVcdTAwMDHYgsWpjL2wllxy3uxcdTAwMWMyaYp91tpqXHUwMDFmXHUwMDFln1x1MDAxZDtcdTAwMTPyYVtwqL50fVx1MDAxY/XD/Vx1MDAwZVx1MDAxN4I2XHKAXHUwMDAwj1txdJmWlmO9VLlFXVwijFx1MDAxN8wxcExCLVx1MDAxN7krXFxx5V9PXHUwMDBmNVx1MDAwMdJyP2/qy1xuwNJrXHUwMDBlLI/N6LNeW18zn5+dbmnn9ejN+NtPXHUwMDAxLKx/gHFyXHUwMDAziXOup375/PNcdTAwMGXmy1Q1O4FNYazXYqHF5p1cdTAwMWbWcC5QjD5WXGbGZ35cdTAwMWFuJJKZkazOjME2UjDh5uuGZ/5CloeLLKDTLJbVLs/tcVx1MDAwN7z4cWgqXGKQziekgqnWbyqUxKl0XHUwMDAzJWasi7OOlZeCRTb3LVx1MDAwZeTbh3ycUmRy15XzkoHdPNw0g8I06NCOmWPNv2c9l4JcdTAwMTmlaVOdXHUwMDFmRKiF87h812B6RlwiLpb3siCOL+JZXHUwMDA0mC1QoE7cMpP8Nlx1MDAxZsfBYZxGp002uXlcdTAwMWImsFlLXHUwMDE5mzR63oFAXHUwMDAz5DPRSIdbiyFtXHUwMDEzXHRcdTAwMWPVodhccqjyXHUwMDEyqlrtXHUwMDEzeY9cdTAwMTJiZsOJVqzoTOd7LF+8wbm8YVZAXHUwMDEzYn3O844gcm6CUlFcdTAwMDGMqVx1MDAwNMgvzVx1MDAwMXLydu3levfV+vHkZPLqcK+18+zDmftcdTAwMTlcdTAwMDDSXHUwMDBibp9rTpCVQU5cdTAwMWLFp/jInLbmiUWF+HXR6GiY01HCkNtOK49SdOShfWBg0HQlXFxcdTAwMDGoL/KTgvlcdTAwMDTj5S98/Hnx8Wbvhj9zOq9Gy4upfcr2ecpcdTAwMTbQhTWKkUXgXHJGUHJ2XG7HXHUwMDA3s6VKuVx1MDAxOXebKmCtu41MWSDky/fSvEvr3Vx0MDJcdTAwMWaOzFlfcEL1ua6SPFtcdTAwMDYsa9nEkHf43fjivk9cdTAwMTj3XHUwMDE4g1x1MDAwMK5Idlx1MDAxN0mRJpUlXHUwMDE4Nlx1MDAwN1x1MDAxZnNOXHUwMDEw9/DrxVx0zsjOx65cbqO1LfVcdTAwMWRg1Vx1MDAwMzdcXC1Zsoj1IzYz3CdcdTAwMGaYUd57mU9cZvktfVlz5lx1MDAxMVusjGLH1Fx1MDAwM9xGY9+wXG5zYGr/XHUwMDA2QzvXzPH65+fi+WhjXHUwMDEy14fH/YP+45WfXHUwMDAxplxcXHUwMDEwXHUwMDE5XHUwMDAyuHxcXFxidGMmQeiBU6BDjlx1MDAwN8DBgq85zeg7kCqyPYKDvKFKpEhcdTAwMTVAda6dzFpcdTAwMDQ2XHUwMDAziFmcUkFcdTAwMWFdPNjvXHUwMDE3TF1cbvtZYMqwKDxyXHUwMDFin4PrdFqvsizZXHUwMDEzQ1x1MDAxZOVEvnxSY3e5vnjNgyyrXGJcdTAwMWHEMnhR6qRhOVx1MDAxNTxcdTAwMTS8q7JcdTAwMWOeVJ9cdGNPv1x1MDAwZk5ohFx1MDAwZTzGqJRFZPmB5NQnlvHUQ6PKpOb2ST6rivtHXHQ2lnW+wbZS5lx1MDAwMydJxrzyl0nD6y6vyWRK2CNcdTAwMWJgOIuMvW/+mqf3g2Yyi/lnXHUwMDBmXHUwMDA3YFx1MDAxZNM+Vc6939y5byy/PJVH72T/zejZq4PuR1x1MDAxMJXD1k/h3KPJeD6E9uyJ1dPW1suT6kTGI1mDXG4sXHUwMDE1MndcdTAwMTSGuIxccuqsuYdcdTAwMWWDxVSFITxiXHUwMDEzYWye7VxyplwiXG7JT4VcdTAwMGZ6zvGsv9z7z+Deb/huTmDg1DbojVRsoUl9T9AsRDRcdTAwMWNcdTAwMTLrfGxcdTAwMDJcdTAwMDWSg1vzIXrkubI0+T9jgoZeU3BXvkGP5mKl8aRcdTAwMTA4WDZcdTAwMWJC/0tz7/LjX+GBTeR36fr9XHUwMDFhwVx1MDAxMYScXHUwMDExXHUwMDFh87NcdTAwMDLS3i+8XG4z01x1MDAxY1x1MDAwN1x1MDAxOVx1MDAxNXG2Vlx1MDAxZUCUK0CoYu2IK6dcYpnPwzJcdTAwMTjByspcdTAwMDbHarBPiO1fPCOA0VAqr+xcZlx1MDAxYcCUYCeJod157kCVQZ57TDykwbJcdTAwMTi/yWCaRVx1MDAwYuRgXHUwMDFmrIbK9zJcdTAwMTWbyZM7znKE95wugVWz9dUy5djLhbRcdTAwMDNU5IXqilEmJ1nZJp0qd1x1MDAwNc9zj0xwkYNOna/E54Pm+Hxw+nV15+1rtbr/eHly8Hx/b7S5t/tT4LOXXHUwMDE5Ylx1MDAxNlx1MDAxM/LxVXpakjXFZ6+jlGzjXGLBlq5rYfDMoeg8XydcdTAwMWakV9jJK8KzkVx1MDAxY6fIzm4mXHUwMDAzZ6tcdTAwMThpxlbNO236XHUwMDE3Pv/98Fx1MDAxOS7NKY7jNkbI4vnC5y+K4LxWcJF5o0f9XHUwMDA2heKwU4lcYoOzr1jYUfK4kufNeMVcdH+yPjdVJ1xywoLSPP9cdTAwMTJcdTAwMTDYwN/qTFx1MDAxOVx1MDAwZXdcdTAwMDD1tzntKFx1MDAwMVbJPO5dXHUwMDFlu1x1MDAwMjnJiMNcdTAwMWU5liCtp+AgNSNZ5sVTLFSDXHTknIqDR854UWm2dqUzudn2YjnCXHUwMDFmXHUwMDAxIFt56lx1MDAwNeazajxcdTAwMWJcdTAwMTelXHUwMDA07Fx1MDAwN1GGq2JFPoeQ/SCRgi1cdTAwMDaSmFx01GecP5PTLFxuxer9MFj15V9Pi1Mk29eT03ynuHrYXHUwMDFjV/Xmy1x1MDAwZk9Gf/a3J6Mvr56oP198XFx+uvNT4CrPI+JcdTAwMWWAZi4plnOa0WWSXHUwMDA3I1xuS2an7yjs9fmoalx1MDAwZeFcZiE/nbVcdTAwMDJXbcZBhEpyyIxjdVdcdTAwMTlXYdImn9v/XHUwMDBiVv8xsKqIc5bTTlx1MDAxMGolQa/gjOzI5njOXHUwMDE4N7FBs71iIGhcdTAwMTFSXHUwMDA2do2rNEqVRKFcYj/Hmf7a2/rJcDxcdTAwMGaR43VcdTAwMTD4IFxmjDrdQirJa3B6XuQ0XHLNMdMw11JDoeYkN1x1MDAwNKk8OU9yUnGdMJdxYpXFs8N1sb4jXHUwMDExZzi4N7KDgPN66vvFXHUwMDE3K43Za8lkLlx1MDAwMzLO6k9niM16glqBgadS5CV4nP0lXfnUII7K4dBSXHUwMDFlYGNcdTAwMWG0XHUwMDEwyHxcZlx1MDAxNDsnWVtSPE06XHUwMDE3mOVnI0SBgFx1MDAwNC6pyaTiRVx1MDAwYrxcdTAwMDBfJkLYoIJbL3U5sI7PcKOZM1x1MDAwZXlq6J1C86jbnpzDT1x1MDAwNT47N1x1MDAxN55cdTAwMDNcdTAwMTXAXHUwMDE2XHUwMDA2fFx1MDAxN9F50Fx1MDAxY52ft0++rTzb3zz9eLKy9fjLeGdrd3I4XHUwMDA3nVx1MDAxZsg5gTygJJOcvpXvOFx1MDAxNrO5XHUwMDE3yOxcdTAwMTGMWsEt9Civ22zs8p/rgbllO6HqqEAtJI/gcPnEcp6nMYvLlqrL7IqJ5z8z4a7lsCOvZHU7wo1cdTAwMDD3v1d6d6lal+mkv+bj8NVn/lvQ4Fx1MDAwYsXY31x1MDAwZSdPN072d7e0X373xT/92lx1MDAxNvJRUdWvdLhFXHUwMDAwfHT1yl+/Vcu9fPukezpJXHUwMDA1XSRghp2vR4/XOyudg9WVI2V2tvybUC/2/MNxONK7J6erXHUwMDFmPq7q39tu64VcdTAwMTg8edzscmf4zVxmKWFPdeHMznpSUmny193llZzKh3Su9oi9OD7WI2qwXCIpR8jVXHUwMDFlP+xcdTAwMDZcdTAwMDPWeJuo/Vx1MDAxNZeEXbDnntP7XCL3UmZVdrpcdTAwMTFZYXu3O2az245xjj/Za7X3jkbd+/QoN7Kvokf98KjS7FKmeG7WXHUwMDFj3MpjpqfXUoi45NxtRjh07WIxQTffd5ctObmMXHUwMDA1cupcXFx1MDAwYvFcdTAwMDDWXHUwMDBlJ91cdTAwMTE/t7Sysba02Vx1MDAxZOHaXHUwMDBiizo4nGz2vuVRo0h++6x10OtzXHJsXCJypd/bPczjvS5cdTAwMDUn0DfptVv9qzdcdTAwMWP0Op1cIja2IbSFaHa01lx1MDAwNL1cdTAwMDaj3m7vsNX/o9FttI4mg3fd8fmNTEZH3eJcdTAwMTPrvrhcbreyXHUwMDBiXHUwMDFhdDtIn19FJCNcdTAwMGaZUV5V9lx1MDAxOVx1MDAwZZtjuvy0vt33fz7prmyqg6OzdSPN8MmDx/R8k1lZnscpgyh1gsho89HZilVlXHUwMDBmXHUwMDFh081579ecWPtHYXpcdTAwMWT2rr99erjf+Wrfb783x1+/tb6JYFx1MDAwZppi7+KpwrncV69ON4/fvt86Xt1queHOh6efd96+Wlx1MDAxOKZHUTgj/LaYXlxy11NzL1xmQ6tIsIH/XHUwMDE1hy9cdTAwMTbN/Wtzc69eu1x1MDAwN1x1MDAwM7lzXGbe5EfiOael4llPsWTwiGAzn4+tV/Z6g79cdTAwMDVcdTAwMGK5YkScXHUwMDBlyTGYXHUwMDAx6mBcdTAwMGJcdTAwMTNhKlx1MDAxOdGlhXvuXHUwMDFmqEIgentcdTAwMGK/dZpcZv6lOLXlXHUwMDA2kH5jsOZcdTAwMTPcXHUwMDE4XHKOe53uaGnYP1x1MDAwMqI+St6wMDSvwa0yms+9qEVcdTAwMDF5p9c6XHUwMDE4XHUwMDFjdirt2s+NzPNdLOVcdTAwMGLH2lx1MDAxNO161Nyuo32z1Xr2Yvxhy+rj/oFcdTAwMWavhP2jh1xy4zYg9LbO8UxcZjFcdTAwMWKZS+8yRu8sXHUwMDE3u9ao1U7sXHUwMDFhc71Rb6tcdTAwMWS1vV1h1MFkmkea6Fx1MDAwYpCeXHUwMDEyrqlVS4vrNCxTnzHvwIlSvrjvsUBcdTAwMDC/rOBZOIDrx0P9VFx1MDAxZX9ag8KAXHUwMDA2XHUwMDBmzdGbSWxcbrTi943h8N3+m82VvVx1MDAxM7HyuL39fOPsy8KA1kc97Vx1MDAxY78zoJVzgfbirFx1MDAxNa8rgXZ8g52symf8wIHWXHUwMDAx41xcPmHe89ygUnGI4kBuZcBYpTbfa5HzYNbbjF3VLFnikbVVXHUwMDA2OWuHXHUwMDFjXHUwMDEw7n3hXHUwMDFjilx1MDAxZoCyt1x1MDAwZpxvh7KDztLgcOk/h8e90eSo1cffXHUwMDBlXHUwMDA3ne5cdTAwMWShbVxyvMyg7fnFXV5aemGLQtxz71Jh3oWTXFzK5m3ZUVx1MDAxY3yohNtJc+u+3lx0PlDr9vnZ3JGDKKtcdTAwMDBX8XC3vIttXHUwMDAxgDvXvDloXG5cdTAwMGIkVcVMXHUwMDFlXHUwMDFlgaZlXHUwMDA1i3ZaOVxc8N3kvlx1MDAxYsDstWbPaee3MfvSXHUwMDFldOHCuudf3cT0ckfRPuJVspRcdTAwMDTL53lKlfA8WlNcdTAwMTZKaFx1MDAxZe22hnz+XHUwMDE5p59cYmvz3kdfXHUwMDFjXVx1MDAwZa09Tbe1Z1x1MDAxZUyyNT7vgicnf7yOz75+fP1cXO6O99eM3D34tFV1wVwiXHUwMDBiPFx1MDAwZVxcWU5mt1x1MDAxY7Y7c7k6XHUwMDBiXHUwMDFjXHUwMDEy54pNL1xyrnPBXHUwMDFi9WVXs9C9+lxui+DP8qUxTD8/Q5+6/e3BSUMuNNdbhjCXXGZcdTAwMDWeMeVtdY7x6Fx1MDAwNsHJtfstXHUwMDBm1FtKKeAued5gYFnEbHyiLGt6YExG+KiKU15cdTAwMTboL5XhVFx1MDAxYimkdVVcdTAwMWXTslx1MDAxZsrlfNVFISuqZHliL4dcdTAwMDL8XHUwMDEzXedccjyR4CBKYUVcYkJcdTAwMDQvna/wnXfgK6/fk0idu+ah34El/YGzg9zsXHUwMDA1qlxmtDxcdTAwMTZcdTAwMDPVv523rLRcdTAwMDf+zFjCXfvNaObO6lx1MDAwMl/xYe7mzHFzx3l9svyhOk7L0lwizdH5MfIwpdIgXHUwMDEyyVx0kDxcdTAwMWLB1WzPfJffzMBcdTAwMThl4PGobGIqRFx1MDAwNFe+U9vMiXl5nehl4dC6f5DPvIlHXHUwMDEyivOlrFx1MDAxMTpgvYMsluZduCRE8/qG7qiR41x1MDAxY/75ubO2/XHtQ/fP7c/RPls5a9svlZfJONJcdTAwMDfHM5GsXHUwMDE3MMpZlsmhXHUwMDE3KnqEXHUwMDE4uFxybuqZXHUwMDFiXfBP5T/n2Vx1MDAwNX9cblx1MDAxNrEg7zkvXHUwMDAzV6hcdTAwMWSccZ7B563dlYNcdTAwMGWluFx1MDAwMevsL0/c+3efj4N5XHUwMDFin3bPjle/rdiH7jyDN5nXzLCxXHUwMDBlu1x1MDAxOFx1MDAwYp9/XrLNJLJcdTAwMDXvXHUwMDBld7qcyzxrgSWPVeGpwlXOs+wzXHUwMDFk+1x1MDAxNp2aXHUwMDFl4f7T5uBC8ttrcnBcdTAwMWYu8lvr35F4m1xmXG7FXHUwMDFhadYtue5yiq36u1x1MDAxN5Vbm5s59/Mz50p4Y4Wo7K2U8lx1MDAwNnbb/mNldfRUfz3+2N48/bTtn1xy9+f1gDxcdTAwMTi7ldJcdTAwMDUwUFx1MDAwMFxmZ8JcdTAwMDQly4ZcdTAwMWJC5jiHaVx1MDAxMbtZc1xyV+vM8oymXGJcdTAwMTdcIsX1NXuXs0hcdTAwMDNrv439XHUwMDA3pc5f/PHHxtL/XVo5muzdt9VWfvVdXHUwMDFirSo8mrLRSi9cdTAwMTEzXG5TXHUwMDE1qUjV3Giv52NcdTAwMGbVaK3iKXhcdTAwMWHhfj47YaZK1nEstHYzVbKLNNpcdTAwMTBByfKj83i8oqmaVVJYv1x1MDAwYquFg8nPMbpzsL3igYst5ZohlVx1MDAwYlxmdFxuPmHahFvnXHUwMDEzjlx1MDAwZXunS2Ncbpzct0+o/Or7KEux892C4IhcdTAwMTOO2a5yXHUwMDBiurlbeLuxt663X+iNfbv5rLO25tdcdTAwMDZ784bUPVx1MDAxY7dcdTAwMTCFzni2XHUwMDE3sFFcdTAwMWLtSyRcdTAwMWPsm51OnGdcdTAwMTiu3Vx1MDAwNt9cdTAwMTGhLcTtvILiXHSYilx1MDAxZHRVaV/Fw1xcXHUwMDEwISRJ4cuKcjbdXHUwMDE5VYywfoaalOOz8dFZODl96d5+tJ0tfTZ4/alx8eee/PrxaGUy7m7vvVl9evx6c+/L5PfFeaJcdTAwMWKyk9uB9DXpRMtYXGZxe6U1mubWWP2MXHUwMDFmvDV6kV10pzrHMTglZi1gjt5cdTAwMDetjHHujsxRwiNcYlx1MDAxZnnYK/v6XHUwMDBifaOFvZhcdTAwMTmUltFEXHUwMDExwC3+QeR6Y9D5z+HqJfqNb1x1MDAwYqY19Sg1uFJRj1J9UYuC2W6/31x1MDAxYo4rmziMmlx1MDAxYjJzWq9hW1+VXdvmdt16ufP+3dej/cngz3ZU4vOnlY1h+2FcdTAwMTd/Sm9cXMZDg/OzPGYxVtpcZuCnOWdcdTAwMTiWXThqcaFWrU1cdTAwMTaU0JXFKMZJXHUwMDFljeuqMJaRvNI2/FxcZZ9cdTAwMWRxNGhcdTAwMGI93lx1MDAxZO9MXuy8dJ3BaLNx38Z39Ff83aFb67n1Zo6lS1x1MDAxY0RdZeGuuYVXL91DR27vY6aByVx1MDAxMVGt8bGQO7yooJCg2dFcdTAwMDdcdTAwMTMkp3V+n5HPa9RyIYuW50g5XHUwMDFmWOldUVA6i9xeW1x1MDAwM6hfgH3/LLj9mHN0/nO4eTaedFx1MDAwZu5cYrVrcKqM2nMu6Xsxu4k/m7f9n6u1c5xJYpS3ynObpqTWSvGYcckjp1XknIxcdTAwMTmVXGaKXHUwMDEzolx1MDAxNefLKqOFqCCTQCZcdTAwMGLwXHUwMDEzQVlCjSx4kPpm69uko360XHUwMDBiuWWztfSPKs2uXHSsXvVocUZcblx1MDAxZXEsKvZVWDZ/w4NBNohK4XOLasK+fcfWQjeL5+opf5ZnVXQqb1x1MDAwNppcdTAwMWLukddv/F/f97VUrOny1lhOqrFSXHUwMDFh4YunXHUwMDBmX1x1MDAxNSdcdTAwMTgpNU9H5tlcdTAwMTR3U6hwvc9bSuspLM+LM96w1cIqN3vFOjOe03csy7it9DcrSfuuMoQm2/5NKN21rjVcdTAwMDRcdTAwMDTzWjIq4lx0m+UzjKR03GRT1lx1MDAxYlx1MDAwMe8qZl2rXHUwMDEzXHUwMDE5x0PCOyO0goHGqnQ6vlx1MDAwM9/EXHUwMDAzt6DXYPi/fGu1b1xy3+9bLciv40D/Kt+q5o43MJwuzDlNXHUwMDBid63cV/DTR/OjXFzrfD3lz/Ksit6Hb23sqzhcdTAwMGJaXHUwMDEzN420XlxijVxivYBcclx1MDAxN77KZSDcrKr1PN5dJtX9XHUwMDBicq7Xp4FS58r9vVx1MDAxMFxcfoaUYqXvzFx1MDAwNUvAXT5S3MhcdTAwMTBcclx1MDAxYilcdTAwMWWWd62LQ838YymktsKFxFx1MDAwZVx1MDAwYna+0jxcdTAwMTD9dHo8XHUwMDE5a3/0+Wjr1dh8XHUwMDFhXHUwMDFkXHUwMDFm91ovXHUwMDFljqebXHUwMDEziCrhODCex0JpeIBQXHUwMDFhz1x0JpeBx5h4l1x1MDAxNanWgG3E6GDM4Fx1MDAxY77Z/Fx1MDAwMCypU7bYgfFcdTAwMDP2eVx1MDAxZj/fer92uqnt5/3na+J99/OuOPlQsLJcdTAwMTlMv3rlLlI031x1MDAxN+a+XXuyet9cdTAwMWK86XcuJnxtPd/deTV+fTjc+PN16Fx1MDAwZVx1MDAwNjvL7f6XWY41k5c+r1WKnsdfgfhcdTAwMWGeXG6nSlx1MDAwMax2MfNcdTAwMWNjXHJi76MsbKJfXHK/MVx1MDAwMa5cdTAwMTLE2nM2p5BcdTAwMTXp08Cpolx1MDAxY1x1MDAwMK0ssMIpeY2N3mIuz2TUOlx1MDAxY1x1MDAwZlsjrNnD8T635VnDXHUwMDA18CzlgzB2tqw2t7S5uFx1MDAwMMdcdTAwMTg9z2u/zSCxW6ah945efzRHr99cdTAwMWXGzeXO6N2qfHXw7kvTdPHD8kXXXHUwMDE4aPVdzlx1MDAxOGjF6D74+0xcIvxcdTAwMDct5Im2urTfqTmZz4M4Rlx1MDAxM4wvXHUwMDBleZ7WXHUwMDBlaM64XHIusIDX2Yox0Deb3fdPM8dcdTAwMWLM74N3XHUwMDE0NrAgu8rw1ExKaWp4XHUwMDEyXHUwMDBiXHUwMDE0iyNcdTAwMGJcdTAwMWXOXHUwMDA0P1x1MDAwMtbSWlx1MDAwN9+Gh7p0OTqnsLA/bIZfXHLsVSHvdTeyXHUwMDE4LL7eJ12b71x1MDAwMHxmPO1cdTAwMTbkU1x1MDAxNE9HvVx1MDAxY4HDc9eFMjEoo+MsXHUwMDBlg1Naza5A5lx1MDAwYlx1MDAxOTBWWLpQXHUwMDE5h8GH/Fx1MDAxNIbiIM9fhn++hlPDXHUwMDFmfTdcdTAwMGUjXHUwMDFhhvFcdTAwMTXr5lx1MDAxYU6dQXxcdTAwMTaKx1x1MDAwNvzN0lx1MDAxZHNcdTAwMTWVPzMqOpU2g9lcdTAwMGLLdVxcXHUwMDFmyC5cdTAwMTVzXHUwMDFkynqPxbFcdTAwMWHWalxc8cjhi8SBIdX1VmvQMFx1MDAxNlx1MDAwZsaimFx1MDAwNaWRr3V8S0mmw1x1MDAxOCl54rKNXHUwMDBlf1xys9f7nVnjmdzFLVJcdTAwMWL/uljUR63hcHNcdTAwMDKdvbr3R8e97snjysCaPyR0+bXRy3Rz8/zrX3/9f1xmJ4VPIn0= + + + + + EDGE NODE ON RESOURCE PROVIDER1. Node with exposed service at the edge of HPC clusterVirtual KubeletInterlink API ServerProvider pluginPod on virtual nodeVirtual NodeHTTP + Authunix socketPodContainersBatchSystemOIDCOIDC Identity Provider \ No newline at end of file diff --git a/docs/static/img/scenario-2_dark.svg b/docs/static/img/scenario-2_dark.svg new file mode 100644 index 00000000..388f2042 --- /dev/null +++ b/docs/static/img/scenario-2_dark.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1da1dcdTAwMTTJsv0+v4LF/XiHuvl+nG/gXHUwMDEzXHUwMDE0RVx1MDAxMVDvucvV0FxytDTd2DQqzpr/fvcuXHUwMDFlXVldTVx1MDAxNdIgzFx1MDAxMUdH+1x1MDAxMZVVXHUwMDE5XHUwMDExO3ZkZORff8zNzY9Ojzrz/5qb73zfafW67WHr2/yffP1rZ3jcXHUwMDFk9PGWyv99PDhcdTAwMTnu5J/cXHUwMDFmjY6O//U//9M6OsrG38p2XHUwMDA2h2ff7PQ6h53+6Fx1MDAxOJ/9X/x7bu6v/E+8023z++/86dMt8TFuqM314Ubn63Cl92Mj/2r+oYtcdTAwMDFccjs7o1Z/r9dcdTAwMTm/9Vx1MDAxZK9bXHUwMDFmM+mDdDFcdTAwMDTjZZSX757iXVx1MDAxZEQmpNUqaCmFXHUwMDE0Vl++/a3bXHUwMDFl7VNAMJlcdTAwMTA6XG6nrMDPWMB+p7u3P8JHjFK4RnTBm5j/mMvPnI3oX3Pi8pXj0XBw0Hk06Fxyhlx1MDAxY/Z/yVx1MDAwZX+NXHUwMDA3vd3aOdhcdTAwMWJcdTAwMGVO+u3xZ1q2XHUwMDFkdnfHn9nt9nrro9NcXDKeNJ7ofEn+1vnoZen1ad/CXHUwMDA19/b7nePj5DuDo9ZOd8RcdTAwMDclxfhcdTAwMGU4uqPldj5h/zdcdTAwMWXTsHXYWeaM9U96vcuXu/12h/Mwvy1cXHK5fvv8clx1MDAxN9M9nkt9/srf48F3OpQspVHWXG5cdTAwMTPH0zTWO6kmXn016Oc6qITU0Vx1MDAxOevHn+hcdTAwMWU/huKNcrG7rd5xZzxcdTAwMDFcdTAwMWPbk7FSJrdzctRunX1JeuWs01x1MDAwMVxuZsfz3ev2XHUwMDBmyt/pXHJ2XHUwMDBlxtf5o3BnJU3f0+9aq5tcdTAwMWa3t8P6in2pl/qjl3t7jTXdXHUwMDA3mylcdTAwMTNMULpC041xXHUwMDE5XHUwMDFlXHUwMDFl3rduiqZrfERoKy00fVLJtdRZNFbLwpt3oN37rZ39k2HnIei3n4F+x6jgQ6Sv0m8np+q3UVpcdTAwMDZf+Np9VG/devtl7fDJalutb+mTha0vL/bWXHUwMDFmTar3qPN9VPLhwmTaXHUwMDA0LVx1MDAwMow4XHUwMDFhqU2i2lrILESt4Xg1noOXdkK1g5GZXHUwMDEy2rtgLb5cdTAwMWVdhX7/VutqtVx1MDAwZdVqnXz8XFx/XXRCeYBphfqq4Kapr6N3XHUwMDBlzsbZqq/XmPBcYpu6hvqOtZFaiPtX2dy7/c7csHM4XHUwMDE4deaOhoOv3XZnONf5fjQ47sy1+nOLa8tzo1x1MDAwMV7o7JzgXHUwMDEzO4P+qNXt41x1MDAwNlx1MDAwYjOP19a7P3JLXHLJq09bh91cdTAwMWUnyiZcdTAwMTde7HX3+Mzmd3CXneF88cGNulxioS4/MFx1MDAxYVx1MDAxY43fvbz25HxcdTAwMGWG3b1uv9V7N8Pbap2MXHUwMDA2bzvHZzc2XHUwMDFhnnSKz7nz/MKwYHn2XG6vMPSvX33e+No2neen4vny83c7XHUwMDBiq6Yx6Fx1MDAwNSmyqG2cXHUwMDAyelxi/oKV8GRhWnhH51x1MDAxMXNfNzW8s/hEVPIyulx1MDAxYuvTb0dRdFx1MDAxNIs3xz9N7Fx1MDAwM1xiVuGfXHUwMDE2U1x1MDAxZIiR0UVE8D+Df/97ObzxQC+V0/f1Zlh76T7vhD3/2qy+f7a2LC9vM1HQ1nA4+DZ/+c7ff14ld/vlM/3mQPdfLb3vf/ji9M6HJff8RnIr0bNwxa/t5d7Xb90t+7nlP6/8eN4+7q5cdTAwMGZcdTAwMGJiz/82nu9bXHJcdTAwMDWqR9MgXHUwMDE0XGJRZFx1MDAxZdGOhcmLXGKLTu09alx1MDAwNFxuXHUwMDFl/mBqkFx1MDAwYlx1MDAwNpHh/SiisN7h1ibt/XpcdTAwMDFu9HJHXW3gu7udnVx1MDAxOP9cdTAwMDFcdTAwMDa+2TxcdTAwMTSQ2jlcclx1MDAwMLZVpuzMNEtcdTAwMGVRXHUwMDFhfDHeg0h2XCJcdTAwMTTY7Fx1MDAwZUcnrd7ci5NtjqhcdTAwMWHfRfLqjfH9sNtuXHUwMDE3MS+F+DrwLKP+1Du4KZRfXHUwMDE4LD89XzHhPqppM25AKKVVXHUwMDA1clPQuFx1MDAwMj2Yrlx1MDAwN2cuZePtkWptrlx1MDAwZo9WzYr+0VrrvVnZmWZzO8PB8fHCfmu0s3+XdjfpTXibzqnMSYTHcGvOXHUwMDFinbo0XHUwMDFkTWaENFx1MDAwMn5cdTAwMDYxjPelcV3PXHUwMDEzaeV2Onb8mUuvqGJmjIaBXHUwMDA0Jb0u2OelV8Q0ZVG4XHUwMDE4nbQyXHUwMDE04thzg49CWyO8XHUwMDFkXHUwMDBmv+hmxjHA8sbeidj6rvufn784Pv34eFW4zV5cdTAwMDGx5vefPO/udlx1MDAwNt2WtCed02BcdTAwMGW3Py1+vUCqWnc11S9N4P4soa4wKa3haFx0XHUwMDFh3O3vlb/S6benvNNrXHUwMDFkj1x1MDAxZVxyXHUwMDBlXHUwMDBmuyNcZmNt0O2PJrwq5S4yXHUwMDE02O+0Jm5cdTAwMWGSp753RHHpXHUwMDFjjP82N9bF/Fx1MDAxZpd//78/Z/DpXHUwMDA1oLH2ylx1MDAwMJZccv4vxJh359/PQtCRYbtC+Fx1MDAxZY1cdTAwMGW1XHUwMDAyTcisilx1MDAxMVx1MDAwNFx1MDAxZVReqHHAx1x1MDAxZqWgw0LxSlx1MDAwZdpo3F2LXHUwMDAzUYAjw6dcdTAwMTGcIPhcdTAwMThcdTAwMDcnuTiTIWJcdFx1MDAwMEVcdTAwMTVxTafrxelMRuYz8Ds4L01cIi5kyoBvS8hTXHUwMDE4nqxcdTAwMTXnXGa8t5XGOlx1MDAxZoJcdTAwMTUmXHUwMDE0xXmXOeWCt1xugZGxvn4qZi9O6+Bhd87Bv7jkZpmlN1Akj/DPS+/rpelM6OAwuUqZXHUwMDEwk7FcdTAwMDWd4UWtXGZcdTAwMTidlsrUXHUwMDBiU5nFjVhcdTAwMWKEXGYyWF+ShkjSWi8trlx1MDAxNbWqN1xumWlcdTAwMDUyqUBZvESwk9yqhNp55aOQXG6oXHUwMDE4naq/2ZlcdTAwMGKEbmlcdTAwMTmNkc5cdTAwMDOSgFxuIVx1MDAxNWgzXHUwMDAxg8VcckOLqe/1XHUwMDAyTWZcdTAwMDNcdTAwMDYnuEqijbRleUVgXHUwMDExtaqML2BSbdDCOG1cdTAwMDXGcIW8em2ZtbhcYv1cbspcdTAwMDHXI3SwsFx1MDAxYXT59HBcdTAwMTFosqDxhFr90yqDXHUwMDEzXHUwMDEyIDRQsqjExOw6xMxcdTAwMTi1h1x1MDAxZlx1MDAxNbZ2MmBcdTAwMWFcdTAwMDZTayW+XHUwMDA2M/Bl21xiTkRLr62gXHUwMDAxdyvMZrhHXHSnXHUwMDAxc4OV+5JcdTAwMGIwXHUwMDFh3Fx1MDAwMNQvwFnr2ECacFx1MDAwZU8mXHUwMDBmaUo+gP5cdObvXHUwMDEwMmGunKtcdTAwMWRcdTAwMWJ8MVx1MDAxM1xmXHUwMDAxeIY5gFx1MDAxMZV8sYxQXHUwMDFm4JhcZlx1MDAwMJNo71pcdTAwMWNUXHUwMDA0+lx1MDAwMb6F+zSw8jLygOkqqlxiPDUmqtZcdTAwMWJcdTAwMWKosGNcYlx1MDAwNGvVUahUXHUwMDFjXGJ0lFx1MDAxNupmXHUwMDFk5sO5WoswmcQkYPpwL87CXHUwMDA1TYRcdTAwMDFBaFxciuIwYbX2P2t5XHUwMDBihFx1MDAxN2GNXHUwMDBi8HpQXHUwMDA3XHUwMDA1X5WIXFyQ/EDQ+FxyXHUwMDE0cFwiXHUwMDE43VmQtfc9LVr6o/j/61IpqVx1MDAwYkmPXHUwMDEyl4JLdjBcdTAwMGahXHUwMDBi9HlMplx1MDAxZTcnU1x1MDAxZjs7P37o5d1cdTAwMTf66LB/9OP15qfj9TCFTN35+vNVNIrTXHUwMDFkpVx1MDAwM7aPs7R5ZkjSfyhlnaUvMOpmPGq3mK+9IFFgaj5oXHUwMDFmoURcdTAwMGV+ulwik1x1MDAxYzVLXHQ0dNdGLZRcdTAwMWZTjIusSYCWOVx1MDAxM/149NUs6jdJ+seQJJnB6XCpXG6BNEJmMITUm0XrTaBiXHUwMDEzLKSuXHUwMDA1g1x1MDAwNdiBdULCO0LP4MJtXHUwMDEyMVBcdTAwMDVcdTAwMDVcdTAwMDBcdTAwMTR+RGNcdTAwMTZjXHUwMDAzXlMn0DuAlTfe6lx1MDAwMHJjbz7Cn1x1MDAxMIiIXHUwMDBi2ijxXHLlXHUwMDE1/ixcbnSIj8HI4Fx1MDAxOOG5SUtcdTAwMWHIy6uCXHUwMDEw8SPug2dxacQqM8bFmsE0JJtGXHUwMDAyQ1x1MDAwNOIr4Fx1MDAxMTy0XHSmXHUwMDE0xWWIPOHYXHJcdTAwMDIlkIxcdTAwMDZ8SWVcdTAwMTFPkLya6Vx1MDAxYVx1MDAxYlx1MDAxMqWReITAelx1MDAxMUI0QuBp1EPgrOX5LHAqXHUwMDA0XHUwMDEwyYUgUy4swVx1MDAwNzT1XHUwMDBmXCI9M1v1JFxmj8jTtXpcdTAwMTBxREZRpVx1MDAwM3RcdTAwMDRoeHZcXItcdTAwMTVCoV5lpM+AXHUwMDEymFxmTqPwTiXyyK5jRFx1MDAwMKZNtOAk9WxdyVxm8YP3IKhcYrTAXHUwMDA1k5hJZtB271Uw+Fx1MDAwMGLhXHUwMDA2Rlx1MDAwN1aCMETDy4L6wlxiklx1MDAxYkZMh9BcdTAwMWFIgfBcZnBcdTAwMGZuVS/QZVx1MDAwNnOhSGb4R2JcIlxuXHUwMDAxKVwiRJGXkXCe63nszOVcdTAwMDVcdTAwMDTsXHUwMDAxUZhcdTAwMGWYSuO8Klx09Fx1MDAxNnpktFxitM3a+J+0XHUwMDE46kdcdTAwMDaCINo7m/J2hXjA4+GCXHUwMDFiKFxc0tfTk1x1MDAwNVxyskMzgFx1MDAwMkZcdHdtSlx1MDAxYWNhIVI6q6XX0ddroDZcdTAwMTlUVighvJVcYnB0SZ5cdTAwMDR3XCKpilT8eoWZtTjQXmvxjFx1MDAxME1cdGhuiVx1MDAxNfuM9TZCgcLgIdZcdTAwMTOoXHUwMDA1zVx1MDAxMYBqWfhcdTAwMTD4ulhcdTAwMWVcdTAwMWXAKMD3wNRcdTAwMWOu1SDrXHUwMDExYFx1MDAwMcBEQCfXXHUwMDAzjS7PbnB4XHUwMDBlZERcdTAwMTZKUy/OM1x1MDAwMc7QS2Jm7STlgWdcdTAwMDaNZJkoXHUwMDFjW4PhOdBcdTAwMTAjXHUwMDAwZDBP3FM5tVxiPVx1MDAwMkPxgVx1MDAxYzDWu/tZi4P7MFx1MDAxNrdcbupcdTAwMGXfkWaM4FtgM1x1MDAxZU5cdTAwMTHeXHUwMDA1M9JAnMgs62ujg/ODXHUwMDE5pJbrwHXzJKpcdTAwMGY+ssCtiTxcdTAwMDCHZfZcdTAwMTUzga+VU59cdTAwMDY6JF1cdTAwMDRcclVcbuFDvW9hXHUwMDExsLWMJ4R1oMrpXGJjhpcxtXm6htmZu1x1MDAxN8gsj4LqsYBcboFH6vwwXVFrwlx1MDAwYqK22CBdwVx0XHUwMDA2XHUwMDE2McHJzDt8cFGcXHUwMDExLHlBZENcIlx1MDAwYiBuXHUwMDEwYMFcdTAwMWJcYviP4Fx1MDAxZFx1MDAxZIxcdTAwMTjXVOXyPNNcdTAwMDWMW7QwXHUwMDAwq2b6XHUwMDE3cL9KgpBhMpP5tVx1MDAxYeFhxKtcdTAwMTa/NOKEXHUwMDA2t2szPFx1MDAxY1x1MDAwN0PHTCBcdTAwMTJwJXlcdTAwMTE2i5CBvkU0yajOWFx1MDAxYyxcdTAwMDCuXHLgXHUwMDBmz2ZKy1xm1mYwQsSscMvMudaripFcdTAwMThcdTAwMWRDXHUwMDFkXHUwMDE4PKbPlcXB4TFX7fJ0WYM1XHUwMDE1g0BcYpGzsdBVX0qmWIfRMVTzXHUwMDBlylx1MDAxOZqsqeB+gPpcdTAwMDEu2WEgqWuBOC1cdTAwMTGf4Vx1MDAxZHgsUN0m4qAmXHUwMDExYVx1MDAwNpCcy1x090ucy1x1MDAxOLND61x1MDAwM2JF6cvimG9zXHUwMDExMFx1MDAwNG8mXHUwMDFhmC0sXHQ46G1UXGZJQml4XHUwMDFlimfgtlx1MDAxZMJmKVVcdTAwMDNNcVRVXHUwMDA1XVx1MDAxMZg+hCxcdCtcdTAwMTJcdTAwMTmuhClcboh+I4Kuei9cdTAwMDB5XHUwMDFlZlx1MDAwYlxi545cblx1MDAxN9LUNlx1MDAwNLKoXHUwMDA2XHUwMDExKUhcdTAwMDKRvMH9MsglXHUwMDBmNVx1MDAwMFxyaFni9Vx1MDAxY1wiang9sFx1MDAwMybSgeNccuRxr1x1MDAwNoJ6+FxywH/UKe2AQHJp4XAhllx1MDAwMDXg0kYzXG5cdTAwMDLr8cIhXGL3M5BcdTAwMDdcdTAwMWbAJTGAgjdpXHUwMDE0XHUwMDA0eYZLOFxu0ZE3IMB3Lk5keVxiyy0s4LWlu1x1MDAxNaRcdTAwMWNwVDFgmps4PVx1MDAwMSdcdEzQjiFpMjRcdTAwMWLBoJmwXHUwMDA2/ZJgdVxyVs1AXHUwMDE5XHUwMDExXHUwMDBmIIBknbtQZXFcdTAwMDA7k9dwXHUwMDAyLkJcdTAwMDP6h2BcdTAwMWWho4dZRlx1MDAxNlx1MDAxZlx1MDAwN1eShyeKq1x1MDAwMFx1MDAwNUDLRVx1MDAwM7IxY3FcInfxxFsvgFx1MDAxOCU9htVYXHUwMDBiplx1MDAwMUWHfdhcdTAwMDbcynN4eYWHjnD26cx61tQhWlHBSlbZ14tTLLrVXHUwMDAwfY9cdJHKJHbrLdyo0+SnXHUwMDE2XHUwMDE3bWBcdTAwMTVgXHUwMDEzuFx1MDAwYvhcdTAwMTM4XHUwMDE1XHUwMDAxh1BarIlZvizk+Vx1MDAwZUKPenFk7/BDllx1MDAwYpiAr/JCklxiXHUwMDAwW0V272KD1cvZi1x1MDAxM/CQXGJwpGVcdTAwMGXMJ7pcdTAwMTLg9MByXHJCc3haVX+zpDpcdTAwMDZBNdNcdTAwMDRRK2/S4XFLT8A7XGJFIbTBw1NcdTAwMTJeXFzgblxm1C9cdTAwMDSfXHUwMDA2P4FrU1xiZrxG3MaYpomuKMNsn42MVmT0JXlcdTAwMTFcdTAwMTG859akvJjhV8iDXHUwMDA2a6lcclcxrVWJ7kWRIfrxzCpFxHpNUpFcdTAwMWOfXHUwMDBl0jDtwNKSxDZcIqaXcVx1MDAxMVx1MDAwMkghgaSN8kq5XHUwMDEzRaSsMcsmXduLXHUwMDE4PdRcdTAwMDSBXHUwMDFlvVx1MDAwZjxzvfrFjGvPnmFcdFAtzVNNLFA0XHUwMDExx1xmXHUwMDBiiTO9m4ul0YFcdTAwMTZ6uK+gXHUwMDEwXHUwMDE5xPq7zW2N7JPEXVx1MDAxMGhK8oBLkMiMbINwillcbuiCg81cdTAwMDZcdTAwMDG1SEtoYp7GjfCisEdj61fiKVx1MDAwZvhcdTAwMDJcdTAwMWbkXGYwXHUwMDE3dq9Lulx1MDAwMpsgXHUwMDE3jJ6+osHdzlqey1x1MDAxNF2u8UKwpNKXbUN4RDLQYrh71SCJIeHJqSNEXHLmatNcIp9guaNcdTAwMTDxmYh4iMHV+1x1MDAwMlx0Vopb1cYhzFx1MDAwZUxDJfIuXG5zXCJDltBE+aiuJGmAfVx1MDAxYVxcwnJDvsrgNFWd1l1cdTAwMGZrkivbXGKVLbdcdTAwMGXheyVPj2iPPlx1MDAwNbyU4OtcdTAwMWKY2ozlOSalJVx1MDAxN06otvD5tvz44K5J/Fx1MDAwMuhDfZSRJ1mA4WSeilx1MDAxYqXSpFx1MDAwM8s3QFx1MDAxOVx1MDAxNFVcdTAwMTOwV0/9wJ48ZoLZcqiY0+ViXHUwMDEwlrEhStOYZF+fXHUwMDFlxcOzYFx1MDAxYbgwnLJQpjS514RJaopcdTAwMDNcdTAwMGZTTEBcdTAwMDI9oiqrijHGscBcZtDha5c3Zi3OMPlcYv+pXHUwMDExqMNLXHUwMDA1U3p0XGLFPVRcdTAwMTig3GBtiF5cdTAwMDD4XHUwMDFkmdtjXHJHKDtcdTAwMDFcXIf2XHUwMDAyu3H1wVx1MDAxOX1cdTAwMTTiWlx1MDAwYuKnPZPbZVx1MDAxZmWiYb1cdTAwMDRcdTAwMDDKXHUwMDAz0lx1MDAxYYjjpDHxXHUwMDAzozTSluFRXHUwMDA2Q+vHezHWP7jZSlx1MDAwM/iAX1x1MDAwMFx0uCGRlVx1MDAwMiXw4YKpUVQ5j8mtXHUwMDE1h7BcdTAwMWYqXHUwMDBmho1JXHUwMDA14sqSNIBcdTAwMWI4XHUwMDBiUFvDy9daXHUwMDE34op8MVxyNDRfb1FlLItQOFBcdTAwMGZN9lZfXcowReXs0Fx1MDAwMZtVlKEkzsPy8tVApp1rtYRRXHUwMDE0yDpcdTAwMDNNuFtTXG5cdTAwMDNcdTAwMTBEsTiJ1MhBmepcdTAwMGL8MDgwUHJcdTAwMTVti/t9+Vx1MDAwM1xyXHUwMDBlXGK3QfOYXHUwMDBmN/XckVx1MDAxMa2RxktcdTAwMDMnXHUwMDAyN1eOZ1xyKFx1MDAxOTRcXEqSt7tcdTAwMTXGZYroSWvyVHdcdTAwMWGfXHUwMDAwX1x1MDAxMdBcdTAwMDXmuFx1MDAwNcs7a8WRWVx1MDAwMIhcdTAwMTnwO1x1MDAxNlxmJpNcdTAwMTC4XHUwMDFjXHUwMDA2XHUwMDA3jetcdC551VtqQOirmIOFedFzpz6OvFx1MDAwN4jBkk64uVqshqVcIog2XHUwMDA2XHUwMDFj02ouaCZuxCNsx1NQXHUwMDFlYSdT+/VcdTAwMWGiyVx0YVYwbEY0XHSygoCqfFxyVpMg1+e1wI7xdDEkRCXQKZeyd7BjxCxcbozWXHUwMDFhXHUwMDA07fX0WDNcdTAwMGYmWF9cdTAwMWNcdTAwMTHTxURFQN31WUgqmVWVtWNjYiEwXuLWdqlEObGAwFx1MDAxNVx1MDAwMVx1MDAwNHxcdTAwMTKD7NrHxixcbtfXWG9cdTAwMDI2XHUwMDE4fEmaM8EhmGe6rUEp6YylcVxyXHUwMDFmgb9cItIgvlclaXyUXHUwMDEy4Vx1MDAxZcIohC21XHUwMDBmzojMM+3p89yXK60hOVieIykwfLDwS7XiNLBcdTAwMDRgyqKV/I7KmbacQ1xi06CgXHUwMDFjomBcbqw0jFxm1VRZXHUwMDE0O5xcdTAwMDRWglx0XHUwMDE36lx1MDAwMZVcdTAwMTlK4Fx1MDAxMrc8UodFuiz9y8VB32H2XGIyqb1A6pI0J3FcdTAwMTlIglOS9WSY6faomPr2XHUwMDFlyC4n0s9cdTAwMThcdTAwMTbQWVu4zfpcblx1MDAwMSbbXHKrRDFcdTAwMTOK+ZiSwuFcdTAwMDJcYu1cdTAwMDRzdj7Uj41OxLN6PGj6xVR94UvzMFx1MDAxNsEgnka9XHUwMDBmyceG20AgXHUwMDBmnlRKtENcdTAwMWHrknC31Dhdv1x1MDAwMsXeL5HF6Fx1MDAwNrbqnPflNVx1MDAxZeijY/k201x1MDAxNfWAmi/xcPU/wq5YI1OSpsglWNiFXGK9ntZcdTAwMTiTcVx1MDAxMZJKwqovN7H+JFx1MDAxOElcdTAwMDOBuL/srqXJvOpE535cdD4kVVx1MDAxMW5cZoCTh1x1MDAxZVqbLzY0cHHgb0w3kL25wma5c3lS6Hz7XHUwMDEwo7zQXHUwMDAwXHUwMDFjbObhY+GQXHUwMDAyd7rEiXVKxFx1MDAxNDov/UboWF/zwVVZXHUwMDE20MnccbtcdTAwMThL4lxcXvtcdTAwMDCPXHUwMDBmX19cdTAwMWbEzVxcXHUwMDFhXHUwMDFmtGCNhrbCJzrHXHUwMDA1aMWkXHUwMDFh7pX5iPp6srxYXHUwMDA2lsr1XHUwMDA0oYTVyUxwgZxcdTAwMTdcdTAwMDLwKuBH/cY0jeA8Wlx1MDAwZldcdTAwMTFcdTAwMDVcdTAwMTPtXHTmc+hcXFwiXHUwMDE0XHUwMDBlgVxuS6FqR6eAdlxiXHUwMDEzuFjsXb417s/0XbB7jYFcdTAwMDO+XCJCnPpcdTAwMDAnMryCL1x1MDAwM1x1MDAxZEU4bSe2kjHWXHUwMDBlzKjCpTTa4TJLcZpcdTAwMWNSXHUwMDEzOT2huFxcPIJcdTAwMDfGnUZcdTAwMWVcdTAwMDZcdTAwMWRcdTAwMWHsr2JQXCJYh+00s1x1MDAwNuneJZa2eD5a4ERcdTAwMDD9bTA4l5GSXHUwMDA3rvBcbm47SMQpxlx1MDAxOLD9vF5N1Ps67bnLjes5JC/pUrvKi1hcdTAwMDWYXHUwMDE4aDRcdTAwMDPh+ludrbSQOUW9YtEtfFRa71x1MDAwNThcZl6y0tCykqc+OVx1MDAwN3FcXHiUKlx1MDAxMIylKtd7WeY0XHUwMDExTSmjSDBcdTAwMWHcq1x1MDAwNEpBn8BHjInlajQylMhMXHUwMDEwXHUwMDFioKn6m8W0clx1MDAxZFOCykUny9JcZotcZpWEftvQwPrBN/LnkqfJgNmmJE4zvWb42zeh+oj5I+tcdTAwMGLZ7Y5bOmTp0Vx0qq8hYVx1MDAwMTWoXHUwMDFmXHUwMDFkXHUwMDE4hFx1MDAwN+hgbvFfjCnocCYwTZhcdTAwMGJcdTAwMTZcdTAwMWWxmvnO5SFcbmTZXHUwMDEwwMLAMl2YqORj1pOrzlx1MDAxMm6iPmud15HCXFzhikHSValcdTAwMDKFdaSYJ6bsSLh1g/RcdTAwMDFcdTAwMWLnXHUwMDAxXHUwMDA3XHUwMDA08Vx1MDAwMKYhJ1xuXVxyXFxAsJo7TuvrcFnXK1x1MDAwNLw3xqaYK3UlXHUwMDA3xVx1MDAxNV8ouYzcyONqp3fm8ljLXHUwMDA3Y2ImmfWEKT3hdND88Vx1MDAxNjg8XHUwMDFjY504iaBcdTAwMDbMOeQtW6DKaVx1MDAxNlxmtqGYXHUwMDAwNzHkXHUwMDBi0/XawsJcdTAwMDFcdTAwMDfogUUxQkpT6lx1MDAxMkhcdTAwMGI3YFm7QFCvj9pVXHUwMDA2oiM8XCJisLtcdTAwMDBcdTAwMWWdelx1MDAwMjA1xFx1MDAwMVxchVdcbuAu659cdTAwMWXgynKjMpRcdTAwMDVcdTAwMDNcdTAwMTRpSj2v84eHhW/hXHUwMDE2gFx1MDAwNkXH3IhA3mRYd1x1MDAwN8qVslhuRICL5Vx1MDAxZWuEldzaVy8v39nLRXbH9EhaXHUwMDExlHHZxebWXHUwMDExXHUwMDFihFx1MDAwMVx1MDAxOXydZWZcdTAwMDRq7126XHUwMDFhgSeHK1mF0I/xmKsvXHUwMDA2qlx1MDAxMUd/XHUwMDAznPPceIFcdLlrcZLkkola1lCD/qfJNVx1MDAxNlR6zzImhKBcYu5cdTAwMWItvrDaXHUwMDE4w4BcdTAwMGLCXHUwMDA046mnXHUwMDAyXHUwMDA1S1x1MDAwYulcdTAwMTJcdTAwMTXA1nM9vlZkXCJg/Ok/iv//++xDf52/WLvdMNrpXbc83FxySG1l55YnzTdcdTAwMWL+WDj5XHUwMDEyPveOT1e/v3q192bUXmw92n9cdTAwMTCdW1jGxEVcdTAwMDewXHUwMDEyXHUwMDAzrUjbUpp8XHUwMDAzQlx1MDAxNJhZwIeMwpRcdTAwMDY2o9Yt4Nsu5Fx1MDAwYlx1MDAxMyCBhf4w484t+Fx1MDAwNFxcXHUwMDFjeFxmgiNX9HFcdTAwMTfbXHUwMDBljeJSu7Hjx/B71+GFsIey63CBJWPw23lcdTAwMTdcdTAwMWaWkKaJ54uldzBcdTAwMTWmk12DTVx1MDAwMlx1MDAxMOglQ27FojUhjLtCYJMqtJlcdTAwMGJcdTAwMDTHXHUwMDAxv/HSsjSBtbaJvJLa15c7MGFBMmVdvqyRJlx1MDAwNKXNa1lcYmdW5FnjWnnTTJM/rHjzmFx1MDAwNoXAyLP1RIMquVx1MDAxOYvLV3DIlri3gNncXHUwMDE0ISX4NstcdTAwMDJcdTAwMWQnqj7fzi2OXHUwMDFlcVx1MDAxY4uk8laZpW2sLFFyzLmb6Fx1MDAwNcLRXHUwMDA22lwiXHUwMDA0NZqENLD1RSgxXHL2XHUwMDA0VojL8Tr35lx1MDAxONtZqE/83Fx1MDAxMkhObWjHjFx1MDAxZVx1MDAwYs2r+5s9bY6SO6cvn+283H/bsd+ePl56rtbDl+31XHUwMDA3gZLOkbpcdTAwMGKEg2Bcci6WWjaye1xylMZprqlDt29cciUlc1x1MDAxNyTiXHUwMDFhodW4XHUwMDAwNsVJgIx0TFx1MDAxYiPoXHUwMDFht6y72J1vJJRcclg5biv5XHUwMDFiJy+EPVx1MDAxNJy83qdDXHUwMDA2mss5Z2FcdTAwMGWZYkKGM7glduZcdTAwMDJf0kbI+jKJ6WrIXHUwMDFmz+p7z/lj0+JYX7xKci9ZWCFsXqOX9mlcImBcdMSoXFybtbFcdTAwMDFcdTAwMDObsTiVcTMs+5FwXHUwMDBmuDFpjn3C2lx1MDAxYVAw6fPTNfJuWyDRvjQ+9vrhgodcdTAwMGJBm1x1MDAwNlCAx63Yu0xLy75eqrxHXYLHXHUwMDBiJlx1MDAxOdgnoTZcdTAwMWG5JWRcdOVXx4daXHUwMDA0PDiur1chy7NrIMvG65VcdTAwMWarX+1g7VtrKJ6Fo6PXK/5BIItcdTAwMGXsWqDg7IJXflxccHh+4lx1MDAwNbuOIfpjrFx1MDAwNNJTaFx1MDAxZj1TZLH5zlx1MDAwZmvYXHUwMDE3KEZcdTAwMWarkMVzf6yNXGbNXHUwMDE4rY5n7KJxft4my/1cdTAwMDaWXHUwMDA3XGYsiKdZLKtdntvjXG548esxM0GA9jBFjFC1flGhJE6lXHUwMDBiKDFjXZx1rLxcdTAwMTQssrlrcYjafGBBXHUwMDA3kFwiKO3KecnA3TxcXDTT+Es9MMbMsebfs55LwYzStKnOXHUwMDFjj2hcdTAwMTLOY/iuQfeMRFxcLK9lQVx1MDAxY9/Es1xiMFuAQJ24hfzom7xcdTAwMWRcdTAwMDebcVx1MDAxYZ1ussnN2zCBzVrK2GSj5y1cYjRcdTAwMDA+no7icGsxpNtEXHUwMDAyW3Uo7lx1MDAwNlR5XHRVrfaJfI9cdTAwMTJIs2FHK1Z0pv09XHUwMDE2zj/gXFy+YVx1MDAxNvG7jPU5z9tByKlcdEo8PSfZn7Bw7NNcdTAwMTghnzdHyLcv3q98etp331x1MDAxZn/f2ttaXW/tvlr79iBcdTAwMTAyOHaPjojlJHd0jVx1MDAxZtUlQkZub/JcdTAwMTZBjr4l6lx1MDAwNYA0zOsoYVx1MDAxON2Oq6pTgDSWa1x1MDAwZtwmXHK2PJGilOxcdMlUxe9cdTAwMWPlw4XI631cdTAwMWEuzem8IC2vp/ZpvFx1MDAwZpeGXHUwMDE4n3t+eTafri/HN1x1MDAxOdunsIMwd1UpN+FxU1x1MDAwNaz1uMBM9nB1+XJcdTAwMWE4TJotZH1T3lx1MDAxZpntvpRv0ISyJM+WMYtHXrDAXHUwMDFlvv3ag7uZMC4zXHUwMDA2XHUwMDAxaJHcYCRFmliWmedmJG6RlVxcxq9cdTAwMTcn2CY777wqjNa2tPVcdTAwMDCzXHUwMDFluOZqXHUwMDE5KItY32Uzw33yeFx1MDAxZeW9l3nTkD/TtzXbXHUwMDFlcZeVUdw0dVx1MDAwZlfSJMvCXHUwMDEwjVTh1HJznPLt1rOjIPtvTlx1MDAxN9pra7td/+1t+82DwCnWY+f9v5Xi8S2llTTLdjFcXKQy3JMqVWlcXLPBqcj9XHUwMDEx7ORcckVijFRxXHUwMDA2wpluMmtcdTAwMTG4XHUwMDFiQEygVOC+X23s7/adXHUwMDBmXHUwMDE3pHjWoItcXMdn5zqdXHUwMDE2rCxIbopRJFwirOdmq8bOQn31mke0rFwigiDWwYvSVlx1MDAxYdZTwT/BtyrLNfX6TFx1MDAxODf1++CEXHUwMDA2d+BcdTAwMTlGpSxcIutcdTAwMGYk2z6xjqdcdTAwMWVcdTAwMThVJjVcdTAwMTdQ8mZVXFxBSpCxrPNcclx1MDAxNpYyXHUwMDFm2Eoy5qW/TFx1MDAxYV41vCatKWGP3Fx1MDAwMcNmZNz85q94er+mKXOcPOZo3JNZsVx1MDAxMNX4yp7MK82d+8uvvZMlp1x1MDAwNotvvVx1MDAxMlx1MDAxZsWPo6er2/1cdTAwMDfh3D1r8tllXYPRjutcXM58O1eHWLjpgYFs+WpL45rZ+lx1MDAwZneos+hcdTAwMWV6jFx1MDAxOGZMXHSL6z9cdTAwMTZmXHUwMDFm82xvMJNcdTAwMWMkP1ZM2d9cdTAwMTTkXHUwMDAxe/drfppcdTAwMWRcdTAwMTjYtVxyaiNcdTAwMTW30KSuJ2hcdTAwMTZcIlx1MDAxYTaJdT42QVx1MDAwMsnGrXlcdTAwMTM9XHUwMDA2ubLU+T9jgoZOU3BZvsFcdTAwMWXN2UrjSSHwr9xsXGL1L/W9g3V4PIBoXCKvpeuXa1x1MDAwNFtcdTAwMTCyR2jMz1xuSPd+4V1Ymc7PO+aKan1BOTCUM0CkYvGIK6dcYpnPwzRcdTAwMTjByspcdTAwMDbHanCfXHUwMDEwt3/xjFx1MDAwMFKhVF7ZXHUwMDE3NEApwZ0koFx1MDAxN0F6LkCVMZ5LTDykwbJcdTAwMTi/SWOaWVx1MDAwYmRjXHUwMDFmzIbKlzJcdTAwMTU3kyd3nOVcdTAwMDDv2V1cdTAwMDKzZuvLZcrEy4V0XHUwMDA3qMhcdTAwMGLVXHUwMDE1KSY7WdkmO1VuXHSdp5+YoFx1MDAxNUitnnL83Ivm6Nzb0kJcdTAwMGXk0L1cdTAwMTFuZNZW7PLSrn5cdTAwMTDobLnZiVx1MDAxM8iliUJ99iU8W8RWTrOvsFxm5pZcdTAwMTbRcJVg2H5M5Z30ZDU8gydbnjnEZeBiQHWOz0ww5rpYd1x1MDAwNt1vgP6nXHUwMDAwNHyaU+zHbZjmjukmQ1x0XHUwMDBm6jwsXFzofKdH/VxuhWK3U4Sjns2vWNhRcrmSXHUwMDA3znjFXHUwMDE2f7I+M1UnXHLCeG515MZcdTAwMDfVwOHqTFx1MDAxOXZ3XHUwMDEwztg87ighVsk87lxcXHUwMDFlt1x1MDAwNbKVXHUwMDExuz2yL0FaT8FOakZcbp67JOl2XHUwMDFiJFxuXHLPfHLki0pzb1falJv7Xix7+INcdTAwMDByL0+9wLxZjefORSmB+0GU8apYks8uZL9IpOBcdTAwMWVcdTAwMDNJ0Fx1MDAwNOyT509kNItCMXu/XG5XY/nVXHUwMDBiXFy1YPi6kJgoourL5qi6/MU9+jL6MVhd+mDfrbVbj3rrg96DQFV31lx1MDAxMIeN2KDxslT06CX3Zlx1MDAxYsVWpcq6UFx1MDAxYdeMQNXnjarZgjOwOMVVgarN2IZcdTAwMTBBkOAup+JS6cW5rkE69oj/ndL8z8FURZCz7HVcdTAwMDKilVBewVx1MDAwZdmRW+PZYdzEXHUwMDA2W+1cdTAwMTVpoFx1MDAwNaFcZtwzrlKOKlx0QVx1MDAxMU6OXHUwMDFk/XlaeP1e9izPp0nQXHUwMDFlkMCo09WjkrxcdTAwMDZn50X20tBsMlxy6CptJ9Ts41x1MDAwNorKc/Mk+1x1MDAxNNdcdHNcdTAwMTn7VcGkOS5WdyTiXGbb9kZuIGC3nvrd4rOVxtS1ZCaXdIyd+tNcdTAwMGViXHUwMDEznqA+MVx1MDAxYngmhVx1MDAwMZWU7PwlXfnMIDbKYctSXHUwMDFlX2NcdTAwMWHsIJB5XHUwMDEzKO6bZGVcdHG9NLU8XHUwMDE5IVxuj/DLuCZ9imct8Fx1MDAxY3mZXHUwMDA24f5cdTAwMTTcemmTg/CeXHUwMDA3XHUwMDA1RrY9YDv9WrC/XHUwMDExLlx1MDAwZjs7ozP4qVx1MDAwMGetp4Iz1MlcdTAwMDVbaFx1MDAxZllE59Xm6PzktTs+XHUwMDFkLlx1MDAxZC3ufu24XHUwMDFm611p7NBNQef91s7+ybDz65E5MFWUZ7HYv0LGlO/awMZiRkd22Fx1MDAxN4W+25PI3OGvq5G5Zduh6qRALSRP4HB5w3JcdTAwMWWnMVx0zJa6y+SKiWc/ZVxcholalt6NWXBcdTAwMTGXr1x1MDAwNbh/XerdhWpdJJP+no7Dl9/5q6DB54qx/fKZfnOg+6+W3vc/fHF658OSXHUwMDFil1slOtxcIlx1MDAwMM5fvvP3n1fJ/dJ5tvhi9Opg/WRl6dmnL892n348WbyR3IuPjzrfR6mgsyu+XHUwMDBiXHUwMDFmPo7ebu9+fbMqv+wtii39fG+jIHZcIr65eVBSafJXjeZSTuXNnCm9s1nkuVxybK/nQ1ooXHKOd9bVyzCdWNT5y0gy+oz77dm5L3JcdTAwMTllUl9cdTAwMGKh/qTd/dxcdTAwMTGbnZ1cdTAwMTjvjze5lnVcdTAwMTX96eZ8pdGlceJ5kVx1MDAxYk9ZgTuYXFxN5Fx1MDAxY16xxFx1MDAxOHlcYknxzNPprrtsyMk4Zlx1MDAxOFLnSkhcbtdcdTAwMWZ1hvze3OLa8tx6Z4jBXHUwMDE3ZnXQXHUwMDFmrXd/nO1nSF592jrs9nL1TEQu9rp7/ZzudSg4Qb5Rd6fVu/zAYbfdLkLjXHUwMDBlhLbAZIfLTcBrMOzudfut3rtGt9E6XHUwMDE5XHLedo7PbmQ0POlcdTAwMTSfWOf5JdvKzqOgn0P0gt2VXHUwMDExnUdcdTAwMGIyXHUwMDE2q9LAV81cdTAwMTE9XHUwMDFlfHuybLZPlzfeya/L71x1MDAwZV5snmxu3Vx1MDAxZlx1MDAxYpyC6II96GWsRnRcdTAwMTdExsS11fqeI7q0gWdcdTAwMWZcdTAwMTai1HtcdTAwMDTpz+KT0bfY0ivv9j9/P33U2txcdTAwMGYnXHUwMDFiXHUwMDBmXHUwMDEy0tvt5UX9ovu29/bLu07v8cHCyudHP35cdTAwMTmkV4+mXHSkXHUwMDA3bnJgfVJkqU0oaX00mWIxJPtcdTAwMDBXYzp7XHUwMDFisolj0Fx1MDAxMXHkuJ/Jb0yvxfTX14B0hedcIpRRXHUwMDEzbIyzNH3rgkBkb0PhRKd7XHUwMDA06WvDwdduuzOcO+qdXHUwMDAwJO9cdTAwMDOa11x1MDAwMFdcdTAwMTnNp97BTYH8zKhXeur7vvvwbct+XHUwMDE5nK682lLLh8ePJo260+t1j447qV3zXFzujFx1MDAwN9g4zap2Oa5LyFxyW/OsK3aNvzDssYJcXFq2NllQQktVsVx1MDAxNdGwhS+Pw3XXsu5dXHUwMDExdoS4gXWXrPT+2vabatueXHUwMDA01ItymjGgXpg8ezqrQjosieGmllwiXHUwMDAw/HlYn/qZIH5cbnTXQeHqs8dmY/Fwb/NH5/irfvmpc7D0etRcdTAwMTS5by1cIvj++dWXzd7S0/dLL/tb6t361vHn983k3i10Vz+9XHUwMDA20M3W7zyWi/1QXGLdhW2/uYtkk3imVVx1MDAwM2tkpZnEbvbyt0BtzbP/lKxqZmGvipp/xrrLke9Dxe6318DuwHaPslhcdTAwMWM0tmQ1ieiX4C25+9RGZ3/ClO9cbrz/3Vx1MDAwN5E9vlx1MDAwZthdg5bTsLt8XHUwMDAzs4Huz/7Rxt7K4fu1b5uPnz39+PrL3klrOGnU7W7rcNBvl+zaRJexoe1cdTAwMTToXHUwMDBl+elq3Os/XHK6XHUwMDE129wqLpRVYbdiyyZt5V1j91x1MDAwM7Lu9ZujN1x1MDAxZKrwXHUwMDE15p1bxlT4jmznaf3PxOs/id6LrXerg80l+2pvZ/HxxtHbXHUwMDBmj9vvn/zjULb6LpugrHXsKMeGh9E5X9xdd1bZXGJrzFx1MDAwZppzStvqQFx1MDAxYZG4XHUwMDAwRyZOi1x1MDAxOFxuq8O3iLP/XHUwMDE0S3zXXHUwMDFjZ1x1MDAxNVv5umJcdTAwMTg0trjCbtOJgFmwRuF+guyg/e/+o1x1MDAwYpi7XHUwMDE3KFtcdTAwMDNsXHUwMDEzKDvtXHUwMDBlZlx1MDAwM7NXk4eS60nNWnLTg46SR4xPgixocSZcdTAwMTG2xemJr6Cyqlx1MDAxZT08hkD6yJ3H1zBptVx1MDAxYjvG/GeY9MaNwVVcdTAwMWJcdTAwMWVcdTAwMWVcdTAwMTBkdUA91dKV4IG+qrBcdTAwMTdzhrbOht0/Y+uzbVx1MDAxZVRUSv4sXHUwMDE09XH87Vx07G1YgzauYCvMVufsITXJoOVOaueEt5tcdTAwMWZNrrTmSYiOlSSFXHUwMDAyrPm91lx1MDAxMac578BvtVT5Wkfx+Fx1MDAxMij/93SgXHUwMDEzupJcdTAwMTTcTVx1MDAxYu7VpCFcdTAwMTmuys/6MHBcdTAwMWPsXHUwMDA04Iu9XHUwMDEwzsfrMsRcdTAwMDc8XHUwMDAwOjBnnpxcdTAwMTjQYLzXKvIru7ROb3vwrVEgtH7w5MPrJ3ZnaeX49PWHx+tcdTAwMWZOWrvfXHUwMDFiMlx1MDAxM8uTk/OjMc58ZqnoxfnMs2nQ9Fx1MDAwMoBgMs2DfvX56lXF5nglbWatuVx1MDAwNf+5rXbV9vZDTyxOqVx1MDAwM7hcdTAwMGU10YH7rXSsKlx1MDAwZlBmXCJ8unCfrPlcdTAwMTO6cFx1MDAxMuHtc5ON5TdPhFo8tVx1MDAwYs+erfV0e/v9ilxcaMpNfF9vhrWX7vNO2POvzer7Z2vLclbcJHpb6DhyM25SfZdccrhcdFxiXHUwMDA1l6xZf4hh6ZD2ZWJfQ8mjhZ3hWVx1MDAxMVx1MDAxNfbobVx1MDAxNkFMuI1cdTAwMGZ/iipz/Fx1MDAxZMVMscOt5sQkalx1MDAxMVx1MDAxZNvnVFx1MDAxMZMgptlcdTAwMWK7tmmeRnRcdTAwMWbrcVx1MDAxMNjPXHL6c//uf+1cdTAwMGVHJ61cdTAwMWX+1lx1MDAxZrQ794Gi1CBcXFx1MDAwNUXhnVxc3Ed6XHUwMDE3s6EpV3uiq2iK1zJcdTAwMGJBqmhCXHUwMDA14jq2VLKFVGCVhcMvqFC5iFx1MDAxN13GY6WlXHUwMDExMVDVxlxu8dvUi6b+/saQXHUwMDBi3HRsjFnlXHUwMDAxlJq6fG/Zw8hcdTAwMTRcdTAwMWKF/8P4SoV68mdhQjPHgiageWbU5Wq/UeBcdTAwMDL51rqIXHUwMDAw38W8XHUwMDA3XGKPVJ5kLz5jO2hhbd5cbi5cdTAwMTRcdTAwMGZznFx1MDAxNXtcdTAwMTn6168+b3xtm87zU/F8+fm7nYVVM4VsOcvdoTyr0rJcdTAwMTlnXHUwMDA12VxuPDfjvPBMXHUwMDE0j8K+P+Tl6orwq1x1MDAxY2n0cKRcblPFsnwjS8xF68wqXHUwMDFlcDY125OF6LmxPVx1MDAwNLhkVzhcdTAwMDeqWFx1MDAxM1x1MDAwMaW9XHUwMDE15vJPcaRcdTAwMWZu7Ei5pDKlsFnJ6ZXNXG50XeooXG7Nk/5ZjnRhuoLyp6Cad+FJXHUwMDFi+yV6Uq9MhJ9cdTAwMDdcdLHsa1ZoT3LumWRcdTAwMDavZaMunnIwK1x1MDAwZnp1+XbiQYVyikfFXGJtrOCRdHZipIonXHUwMDFmhGuO845cXOfVXHUwMDE1sle7TsCHUS569lx1MDAwMLKl7r+Op1x1MDAxY1x1MDAwN8OzcmW171RcdTAwMTl3XHQqpWN+ILyoaNyrLXjsb9d5hev8ePOkucf8iThZOZZTzelVKEJcdTAwMTieWONvY4HsXvjOqfrJn4Jm3oXnbOyPXHUwMDE2zlx1MDAxY5JQmv2nvORhuZNcdTAwMTlpm92O27xGllx1MDAxZq5S5O3NlJeG7SYmXHUwMDA2aSZqVe6T35RcdTAwMDf90D+wJ62Pr9pcdTAwMDfD+PTTx1x1MDAxZlx1MDAxYofNKuvZ5FNcYqCx4YnupY5IXCIgJlfjZHlF3YBzmefmeclTiGWsOlx1MDAxMkRfx1/+J9XWf6v2l1XpOefy8/2qXHUwMDFko566migj29PEKG8jqLxpem7zPJv1ampOLiSv3jgnN1x1MDAxYVx1MDAxY01LyCXjLmffqlx1MDAwNzqbtNvTXHUwMDFk032z8Gr7udlaf3n4TD1pf3600sh0rcysZjdcdTAwMDQu9Mm0NFx1MDAwMPSZwTSmalx1MDAxYVlcZjFTLj+03rO5fKG/83iV6zr1Pv9Jcc735naLR0/qUGGi83l9x1TDtd475+y93Od60u9+nzvmZ0aVdjvu/vVr7bZynLPav5paZGFSp3eKMjy/geVcdTAwMDRVSnU632Cmz3zGXHUwMDBis6lcdTAwMGVcdTAwMGU/tX/Yg+7w82prZfR+ZdpcdTAwMTkt92frqvWZUWzgYuKEv3JcdTAwMDZvXHUwMDAy3kTtztWf8TM/5/MuXHUwMDBljPbEXmuqm0Ld925P17bKqXbzXHUwMDBmNlnlp/ph76JH0F/d3e1Hc5Ncclx1MDAwN1x1MDAxYm8+PVxub7fXh8Njv/rp+eNnXHUwMDA38r6brFx1MDAwNCXI2Nteapv3wihlVVxcYNmWm1xmMmZptFK4LLAy2VxurySMt2q3wITVSmZ70mWpWzLb8zcqqztcdTAwMGXWtpbF8FU/PDpuP+qPXHUwMDFlP9566T79ssrzmzmF5+/erc3999ziyWj/rp1C5aVnXHUwMDEzfl+9N+DK4lxcXHUwMDAzzJLGgfSGiuJcXGs1uyRoO3XZm9S7cslbhex3mnF6+C3jfKWZXmeFxmqedVvNpv30JVx1MDAxYWG4QqPkbVx1MDAwNOX3XCLNWNJJ/ixcXKrj+MtcdTAwMTPOaWa5xca1rswtXCKc5Fx1MDAxNrEgjJWI5yazdjHjOZBGXHUwMDBiNvf18nq1ro2SjFdvNSiN1/F8XHUwMDE0nlXGLuOxopjYZ3jbq2C0cizkvd5y/OyTjX+cz/F86+hofVx1MDAwNI29fFx1MDAxMvNfu51vS5VOhj9cdTAwMDSyfGB0Mp3cOv/+4+//XHUwMDA3bbKKhCJ9 + + + + + 2. The remote provider expose an API to execute containersVirtual KubeletInterlink API ServerProvider pluginProviderAPIsPodContainersPod on virtual nodeVirtual Nodeunix socketunix socketHTTP + Auth \ No newline at end of file diff --git a/docs/static/img/scenario-2_light.svg b/docs/static/img/scenario-2_light.svg new file mode 100644 index 00000000..be103dea --- /dev/null +++ b/docs/static/img/scenario-2_light.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1da1dcdTAwMTTJsv0+v4LF/XiHuvl+nG/gXHUwMDEzXHUwMDE0RVx1MDAxMVDvucvV0FxytDTd2DQqzpr/fvcuXHUwMDFlXVldTVx1MDAxNdIgzFx1MDAxMUdH+1x1MDAxMZVVXHUwMDE5XHUwMDExO3ZkZORff8zNzY9Ojzrz/5qb73zfafW67WHr2/yffP1rZ3jcXHUwMDFk9PGWyv99PDhcdTAwMTnu5J/cXHUwMDFmjY6O//U//9M6OsrG38p2XHUwMDA2h2ff7PQ6h53+6Fx1MDAxOJ/9X/x7bu6v/E+8023z++/86dMt8TFuqM314Ubn63Cl92Mj/2r+oYtcdTAwMDFccjs7o1Z/r9dcdTAwMTm/9Vx1MDAxZK9bXHUwMDFmM+mDdDFcdTAwMDTjZZSX757iXVx1MDAxZEQmpNUqaCmFXHUwMDE0Vl++/a3bXHUwMDFl7VNAMJlcdTAwMTA6XG6nrMDPWMB+p7u3P8JHjFK4RnTBm5j/mMvPnI3oX3Pi8pXj0XBw0Hk06Fxyhlx1MDAxY/Z/yVx1MDAwZX+NXHUwMDA3vd3aOdhcdTAwMWJcdTAwMGVO+u3xZ1q2XHUwMDFkdnfHn9nt9nrro9NcXDKeNJ7ofEn+1vnoZen1ad/CXHUwMDA19/b7nePj5DuDo9ZOd8RcdTAwMDclxfhcdTAwMGU4uqPldj5h/zdcdTAwMWXTsHXYWeaM9U96vcuXu/12h/Mwvy1cXHK5fvv8clx1MDAxN9M9nkt9/srf48F3OpQspVHWXG5cdTAwMTPH0zTWO6kmXn016Oc6qITU0Vx1MDAxOevHn+hcdTAwMWU/huKNcrG7rd5xZzxcdTAwMDFcdTAwMWPbk7FSJrdzctRunX1JeuWs01x1MDAwMVxuZsfz3ev2XHUwMDBmyt/pXHJ2XHUwMDBlxtf5o3BnJU3f0+9aq5tcdTAwMWa3t8P6in2pl/qjl3t7jTXdXHUwMDA3mylcdTAwMTNMULpC041xXHUwMDE5XHUwMDFlXHUwMDFl3rduiqZrfERoKy00fVLJtdRZNFbLwpt3oN37rZ39k2HnIei3n4F+x6jgQ6Sv0m8np+q3UVpcdTAwMDZf+Np9VG/devtl7fDJalutb+mTha0vL/bWXHUwMDFmTar3qPN9VPLhwmTaXHUwMDA0LVx1MDAwMow4XHUwMDFhqU2i2lrILESt4Xg1noOXdkK1g5GZXHUwMDEy2rtgLb5cdTAwMWVdhX7/VutqtVx1MDAwZdVqnXz8XFx/XXRCeYBphfqq4Kapr6N3XHUwMDBlzsbZqq/XmPBcYpu6hvqOtZFaiPtX2dy7/c7csHM4XHUwMDE4deaOhoOv3XZnONf5fjQ47sy1+nOLa8tzo1x1MDAwMV7o7JzgXHUwMDEzO4P+qNXt41x1MDAwNlx1MDAwYjOP19a7P3JLXHLJq09bh91cdTAwMWUnyiZcdTAwMTde7HX3+Mzmd3CXneF88cGNulxioS4/MFx1MDAxYVx1MDAxY43fvbz25HxcdTAwMGWG3b1uv9V7N8Pbap2MXHUwMDA2bzvHZzc2XHUwMDFhnnSKz7nz/MKwYHn2XG6vMPSvX33e+No2neen4vny83c7XHUwMDBiq6Yx6Fx1MDAwNSmyqG2cXHUwMDAyelxi/oKV8GRhWnhH51x1MDAxMXNfNzW8s/hEVPIyulx1MDAxYuvTb0dRdFx1MDAxNIs3xz9N7Fx1MDAwM1xiVuGfXHUwMDE2U1x1MDAxZIiR0UVE8D+Df/97ObzxQC+V0/f1Zlh76T7vhD3/2qy+f7a2LC9vM1HQ1nA4+DZ/+c7ff14ld/vlM/3mQPdfLb3vf/ji9M6HJff8RnIr0bNwxa/t5d7Xb90t+7nlP6/8eN4+7q5cdTAwMGZcdTAwMGJiz/82nu9bXHJcdTAwMDWqR9MgXHUwMDE0XGJRZFx1MDAxZdGOhcmLXGKLTu09alx1MDAwNFxuXHUwMDFl/mBqkFx1MDAwYlx1MDAwNpHh/SiisN7h1ibt/XpcdTAwMDFu9HJHXW3gu7udnVx1MDAxOP9cdTAwMDFcdTAwMDa+2TxcdTAwMTSQ2jlcclx1MDAwMLZVpuzMNEtcdTAwMGVRXHUwMDFhfDHeg0h2XCJcdTAwMTTY7Fx1MDAwZUcnrd7ci5NtjqhcdTAwMWHfRfLqjfH9sNtuXHUwMDE3MS+F+DrwLKP+1Du4KZRfXHUwMDE4LD89XzHhPqppM25AKKVVXHUwMDA1clPQuFx1MDAwMj2Yrlx1MDAwN2cuZePtkWptrlx1MDAwZo9WzYr+0VrrvVnZmWZzO8PB8fHCfmu0s3+XdjfpTXibzqnMSYTHcGvOXHUwMDFinbo0XHUwMDFkTWaENFx1MDAwMn5cdTAwMDYxjPelcV3PXHUwMDEzaeV2Onb8mUuvqGJmjIaBXHUwMDA0Jb0u2OelV8Q0ZVG4XHUwMDE4nbQyXHUwMDE04thzg49CWyO8XHUwMDFkXHUwMDBmv+hmxjHA8sbeidj6rvufn784Pv34eFW4zV5cdTAwMDGx5vefPO/udlx1MDAwNt2WtCed02BcdTAwMGW3Py1+vUCqWnc11S9N4P4soa4wKa3haFx0XHUwMDFh3O3vlb/S6benvNNrXHUwMDFkj1x1MDAxZVxyXHUwMDBlXHUwMDBmuyNcZmNt0O2PJrwq5S4yXHUwMDE02O+0Jm5cdTAwMWGSp753RHHpXHUwMDFjjP82N9bF/Fx1MDAxZpd//78/Z/DpXHUwMDA1oLH2ylx1MDAwMJZccv4vxJh359/PQtCRYbtC+Fx1MDAxZY1cdTAwMGW1XHUwMDAyTcisilx1MDAxMVx1MDAwNFx1MDAxZVReqHHAx1x1MDAxZqWgw0LxSlx1MDAwZdpo3F2LXHUwMDAzUYAjw6dcdTAwMTGcIPhcdTAwMThcdTAwMDcnuTiTIWJcdFx1MDAwMEVcdTAwMTVxTafrxelMRuYz8Ds4L01cIi5kyoBvS8hTXHUwMDE4nqxcdTAwMTXnXGa8t5XGOlx1MDAxZoJcdTAwMTUmXHUwMDE0xXmXOeWCt1xugZGxvn4qZi9O6+Bhd87Bv7jkZpmlN1Akj/DPS+/rpelM6OAwuUqZXHUwMDEwk7FcdTAwMDWd4UWtXGZcdTAwMTidlsrUXHUwMDBiU5nFjVhcdTAwMWKEXGYyWF+ShkjSWi8trlx1MDAxNbWqN1xumWlcdTAwMDUyqUBZvESwk9yqhNp55aOQXG6oXHUwMDE4naq/2ZlcdTAwMGKEbmlcdTAwMTmNkc5cdTAwMDOSgFxuIVx1MDAxNWgzXHUwMDAxg8VcckOLqe/1XHUwMDAyTWZcdTAwMDNcdTAwMDYnuEqijbRleUVgXHUwMDExtaqML2BSbdDCOG1cdTAwMDXGcIW8em2ZtbhcYv1cbspcdTAwMDHXI3SwsFx1MDAxYXT59HBcdTAwMTFosqDxhFr90yqDXHUwMDEzXHUwMDEyIDRQsqjExOw6xMxcdTAwMTi1h1x1MDAxZlx1MDAxNbZ2MmBcdTAwMWFcdTAwMDZTayW+XHUwMDA2M/Bl21xiTkRLr62gXHUwMDAxdyvMZrhHXHSnXHUwMDAxc4OV+5JcdTAwMGIwXHUwMDFh3Fx1MDAwMNQvwFnr2ECacFx1MDAwZU8mXHUwMDBmaUo+gP5cdObvXHUwMDEwMmGunKtcdTAwMWRcdTAwMWJ8MVx1MDAxM1xmXHUwMDAxeIY5gFx1MDAxMZV8sYxQXHUwMDFm4JhcZlx1MDAwMJNo71pcdTAwMWNUXHUwMDA0+lx1MDAwMb6F+zSw8jLygOkqqlxiPDUmqtZcdTAwMWJcdTAwMWKosGNcYlx1MDAwNGvVUahUXHUwMDFjXGJ0lFx1MDAxNupmXHUwMDFk5sO5WoswmcQkYPpwL87CXHUwMDA1TYRcdTAwMDFBaFxciuIwYbX2P2t5XHUwMDBihFx1MDAxN2GNXHUwMDBi8HpQXHUwMDA3XHUwMDA1X5WIXFyQ/EDQ+FxyXHUwMDE0cFwiXHUwMDE43VmQtfc9LVr6o/j/61IpqVx1MDAwYkmPXHUwMDEyl4JLdjBcdTAwMGahXHUwMDBi9HlMplx1MDAxZTcnU1x1MDAxZjs7P37o5d1cdTAwMTf66LB/9OP15qfj9TCFTN35+vNVNIrTXHUwMDFkpVx1MDAwM7aPs7R5ZkjSfyhlnaUvMOpmPGq3mK+9IFFgaj5oXHUwMDFmoURcdTAwMGV+ulwik1x1MDAxYzVLXHQ0dNdGLZRcdTAwMWZTjIusSYCWOVx1MDAxM/149NUs6jdJ+seQJJnB6XCpXG6BNEJmMITUm0XrTaBiXHUwMDEzLKSuXHUwMDA1g1x1MDAwNdiBdULCO0LP4MJtXHUwMDEyMVBcdTAwMDVcdTAwMDVcdTAwMDBcdTAwMTR+RGNcdTAwMTZjXHUwMDAzXlMn0DuAlTfe6lx1MDAwMHJjbz7Cn1x1MDAxMIiIXHUwMDBi2ijxXHLlXHUwMDE1/ixcbnSIj8HI4Fx1MDAxOOG5SUtcdTAwMWHIy6uCXHUwMDEw8SPug2dxacQqM8bFmsE0JJtGXHUwMDAyQ1x1MDAwNOIr4Fx1MDAxMTy0XHSmXHUwMDE0xWWIPOHYXHJcdTAwMDIlkIxcdTAwMDZ8SWVcdTAwMTFPkLya6Vx1MDAxYVx1MDAxYlx1MDAxMqWReITAelx1MDAxMUI0QuBp1EPgrOX5LHAqXHUwMDA0XHUwMDEwyYUgUy4swVx1MDAwNzT1XHUwMDBmXCI9M1v1JFxmj8jTtXpcdTAwMTBxREZRpVx1MDAwM3RcdTAwMDRoeHZcXItcdTAwMTVCoV5lpM+AXHUwMDEymFxmTqPwTiXyyK5jRFx1MDAwMKZNtOAk9WxdyVxm8YP3IKhcYrTAXHUwMDA1k5hJZtB271Uw+Fx1MDAwMGLhXHUwMDA2Rlx1MDAwN1aCMETDy4L6wlxiklx1MDAxYkZMh9BcdTAwMWFIgfBcZnBcdTAwMGZuVS/QZVx1MDAwNnOhSGb4R2JcIlxuXHUwMDAxKVwiRJGXkXCe63nszOVcdTAwMDVcdTAwMDTsXHUwMDAxUZhcdTAwMGWYSuO8Klx09Fx1MDAxNnpktFxitM3a+J+0XHUwMDE46kdcdTAwMDaCINo7m/J2hXjA4+GCXHUwMDFiKFxc0tfTk1x1MDAwNVxyskMzgFx1MDAwMkZcdHdtSlx1MDAxYWNhIVI6q6XX0ddroDZcdTAwMTlUVighvJVcYnB0SZ5cdTAwMDR3XCKpilT8eoWZtTjQXmvxjFx1MDAxME1cdGhuiVx1MDAxNfuM9TZCgcLgIdZcdTAwMTOoXHUwMDA1zVx1MDAxMYBqWfhcdTAwMTD4ulhcdTAwMWVcdTAwMWXAKMD3wNRcdTAwMWOu1SDrXHUwMDExYFx1MDAwMcBEQCfXXHUwMDAzjS7PbnB4XHUwMDBlZERcdTAwMTZKUy/OM1x1MDAwMc7QS2Jm7STlgWdcdTAwMDaNZJkoXHUwMDFjW4PhOdBcdTAwMTAjXHUwMDAwZDBP3FM5tVxiPVx1MDAwMkPxgVx1MDAxYzDWu/tZi4P7MFx1MDAxNrdcbupcdTAwMGXfkWaM4FtgM1x1MDAxZU5cdTAwMTHeXHUwMDA1M9JAnMgs62ujg/ODXHUwMDE5pJbrwHXzJKpcdTAwMGY+ssCtiTxcdTAwMDCHZfZcdTAwMTUzga+VU59cdTAwMDY6JF1cdTAwMDRcclVcbuFDvW9hXHUwMDExsLWMJ4R1oMrpXGJjhpcxtXm6htmZu1x1MDAxN8gsj4LqsYBcboFH6vwwXVFrwlx1MDAwYqK22CBdwVx0XHUwMDA2XHUwMDE2McHJzDt8cFGcXHUwMDExLHlBZENcIlx1MDAwYiBuXHUwMDEwYMFcdTAwMWJcYviP4Fx1MDAxZFx1MDAxZIxcdTAwMTjXVOXyPNNcdTAwMDWMW7QwXHUwMDAwq2b6XHUwMDE3cL9KgpBhMpP5tVx1MDAxYeFhxKtcdTAwMTa/NOKEXHUwMDA2t2szPFx1MDAxY1x1MDAwN0PHTCBcdTAwMTJwJXlcdTAwMTE2i5CBvkU0yajOWFx1MDAxYyxcdTAwMDCuXHLgXHUwMDBmz2ZKy1xm1mYwQsSscMvMudaripFcdTAwMThcdTAwMWRDXHUwMDFkXHUwMDE4PKbPlcXB4TFX7fJ0WYM1XHUwMDE1g0BcYpGzsdBVX0qmWIfRMVTzXHUwMDBlylx1MDAxOZqsqeB+gPpcdTAwMDEu2WEgqWuBOC1cdTAwMTGf4Vx1MDAxZHgsUN0m4qAmXHUwMDExYVx1MDAwNpCcy1x090ucy1x1MDAxOLND61x1MDAwM2JF6cvimG9zXHUwMDExMFx1MDAwNG8mXHUwMDFhmC0sXHQ46G1UXGZJQml4XHUwMDFlimfgtlx1MDAxZMJmKVVcdTAwMDNNcVRVXHUwMDA1XVx1MDAxMZg+hCxcdCtcdTAwMTJcdTAwMTmuhClcboh+I4Kuei9cdTAwMDB5XHUwMDFlZlx1MDAwYlxi545cblx1MDAxN9LUNlx1MDAwNLKoXHUwMDA2XHUwMDExKUhcdTAwMDKRvMH9MsglXHUwMDBmNVx1MDAwMFxyaFni9Vx1MDAxY1wiang9sFx1MDAwMybSgeNccuRxr1x1MDAwNoJ6+FxywH/UKe2AQHJp4XAhllx1MDAwMDXg0kYzXG5cdTAwMDLr8cIhXGL3M5BcdTAwMDdcdTAwMWbAJTGAgjdpXHUwMDE0XHUwMDA0eYZLOFxu0ZE3IMB3Lk5keVxiyy0s4LWlu1x1MDAxNaRcdTAwMWNwVDFgmps4PVx1MDAwMSdcdEzQjiFpMjRcdTAwMWLBoJmwXHUwMDA2/ZJgdVxyVs1AXHUwMDE5XHUwMDExXHUwMDBmIIBknbtQZXFcdTAwMDA7k9dwXHUwMDAyLkJcdTAwMDP6h2BcdTAwMWWho4dZRlx1MDAxNlx1MDAxZlx1MDAwN1eShyeKq1x1MDAwMFx1MDAwNUDLRVx1MDAwM7IxY3FcInfxxFsvgFx1MDAxOCU9htVYXHUwMDBiplx1MDAwMUWHfdhcdTAwMDbcynN4eYWHjnD26cx61tQhWlHBSlbZ14tTLLrVXHUwMDAwfY9cdJHKJHbrLdyo0+SnXHUwMDE2XHUwMDE3bWBcdTAwMTVgXHUwMDEzuFx1MDAwYvhcdTAwMTM4XHUwMDE1XHUwMDAxh1BarIlZvizk+Vx1MDAwZUKPenFk7/BDllx1MDAwYpiAr/JCklxiXHUwMDAwW0V272KD1cvZi1x1MDAxM/CQXGJwpGVcdTAwMGXMJ7pcdTAwMTLg9MByXHJCc3haVX+zpDpcdTAwMDZBNdNcdTAwMDRRK2/S4XFLT8A7XGJFIbTBw1NcdTAwMTJeXFzgblxm1C9cdTAwMDSfXHUwMDA2P4FrU1xiZrxG3MaYpomuKMNsn42MVmT0JXlcdTAwMTFcdTAwMTG859akvJjhV8iDXHUwMDA2a6lcclcxrVWJ7kWRIfrxzCpFxHpNUpFcdTAwMWOfXHUwMDBl0jDtwNKSxDZcIqaXcVx1MDAxMVx1MDAwMkghgaSN8kq5XHUwMDEzRaSsMcsmXduLXHUwMDE4PdRcdTAwMDSBXHUwMDFlvVx1MDAwZjxzvfrFjGvPnmFcdFAtzVNNLFA0XHUwMDExx1xmXHUwMDBiiTO9m4ul0YFcdTAwMTZ6uK+gXHUwMDEwXHUwMDE5xPq7zW2N7JPEXVx1MDAxMGhK8oBLkMiMbINwillcbuiCg81cdTAwMDZcdTAwMDG1SEtoYp7GjfCisEdj61fiKVx1MDAwZvhcdTAwMDJcdTAwMWbkXGYwXHUwMDE3dq9Lulx1MDAwMpsgXHUwMDE3jJ6+osHdzlqey1x1MDAxNF2u8UKwpNKXbUN4RDLQYrh71SCJIeHJqSNEXHLmatNcIp9guaNcdTAwMTDxmYh4iMHV+1x1MDAwMlx0Vopb1cYhzFx1MDAwZUxDJfIuXG5zXCJDltBE+aiuJGmAfVx1MDAxYVxcwnJDvsrgNFWd1l1cdTAwMGZrkivbXGKVLbdcdTAwMGXheyVPj2iPPlx1MDAwNbyU4OtcdTAwMWKY2ozlOSalJVx1MDAxN06otvD5tvz44K5J/Fx1MDAwMuhDfZSRJ1mA4WSeilx1MDAxYqXSpFx1MDAwM8s3QFx1MDAxOVx1MDAxNFVcdTAwMTOwV0/9wJ48ZoLZcqiY0+ViXHUwMDEwlrEhStOYZF+fXHUwMDFlxcOzYFx1MDAxYbgwnLJQpjS514RJaopcdTAwMDNcdTAwMGZTTEBcdTAwMDI9oiqrijHGscBcZtDha5c3Zi3OMPlcYv+pXHUwMDExqMNLXHUwMDA1U3p0XGLFPVRcdTAwMTig3GBtiF5cdTAwMDD4XHUwMDFkmdtjXHJHKDtcdTAwMDFcXIf2XHUwMDAyu3H1wVx1MDAxOX1cdTAwMTTiWlx1MDAwYuKnPZPbZVx1MDAxZmWiYb1cdTAwMDRcdTAwMDDKXHUwMDAz0lx1MDAxYYjjpDHxXHUwMDAzozTSluFRXHUwMDA2Q+vHezHWP7jZSlx1MDAwM/iAX1x1MDAwMFx0uCGRlVx1MDAwMiXw4YKpUVQ5j8mtXHUwMDE1h7BcdTAwMWYqXHUwMDBmho1JXHUwMDA14sqSNIBcdTAwMWI4XHUwMDBiUFvDy9daXHUwMDE34op8MVxyNDRfb1FlLItQOFBcdTAwMGZN9lZfXcowReXs0Fx1MDAwMZtVlKEkzsPy8tVApp1rtYRRXHUwMDE0yDpcdTAwMDNNuFtTXG5cdTAwMDNcdTAwMTBEsTiJ1MhBmepcdTAwMGL8MDgwUHJcdTAwMTVti/t9+Vx1MDAwM1xyXHUwMDBlXGK3QfOYXHUwMDBmN/XckVx1MDAxMa2RxktcdTAwMDMnXHUwMDAyN1eOZ1xyKFx1MDAxOTRcXEqSt7tcdTAwMTXGZYroSWvyVHdcdTAwMWGfXHUwMDAwX1x1MDAxMdBcdTAwMDXmuFx1MDAwNcs7a8WRWVx1MDAwMIhcdTAwMTnwO1x1MDAxNlxmJpNcdTAwMTC4XHUwMDFjXHUwMDA2XHUwMDA3jetcdC551VtqQOirmIOFedFzpz6OvFx1MDAwN4jBkk64uVqshqVcIog2XHUwMDA2XHUwMDFj02ouaCZuxCNsx1NQXHUwMDFlYSdT+/VcdTAwMWGiyVx0YVYwbEY0XHSygoCqfFxyVpMg1+e1wI7xdDEkRCXQKZeyd7BjxCxcbozWXHUwMDFhXHUwMDA07fX0WDNcdTAwMGYmWF9cdTAwMWNcdTAwMTHTxURFQN31WUgqmVWVtWNjYiEwXuLWdqlEObGAwFx1MDAxNVx1MDAwMVx1MDAwNHxcdTAwMTKD7NrHxixcbtfXWG9cdTAwMDI2XHUwMDE4fEmaM8EhmGe6rUEp6YylcVxyXHUwMDFmgb9cItIgvlclaXyUXHUwMDEy4Vx1MDAxZcIohC21XHUwMDBmzojMM+3p89yXK60hOVieIykwfLDwS7XiNLBcdTAwMDRgyqKV/I7KmbacQ1xi06CgXHUwMDFjomBcbqw0jFxm1VRZXHUwMDE0O5xcdTAwMDRWglx0XHUwMDE36lx1MDAwMZVcdTAwMTlK4Fx1MDAxMrc8UodFuiz9y8VB32H2XGIyqb1A6pI0J3FcdTAwMTlIglOS9WSY6faomPr2XHUwMDFlyC4n0s9cdTAwMThcdTAwMTbQWVu4zfpcblx1MDAwMSbbXHKrRDFcdTAwMTOK+ZiSwuFcdTAwMDJcYu1cdTAwMDRzdj7Uj41OxLN6PGj6xVR94UvzMFx1MDAxNsEgnka9XHUwMDBmyceG20AgXHUwMDBmnlRKtENcdTAwMWHrknC31Dhdv1x1MDAwMsXeL5HF6Fx1MDAwNrbqnPflNVx1MDAxZeijY/k201x1MDAxNfWAmi/xcPU/wq5YI1OSpsglWNiFXGK9ntZcdTAwMTiTcVx1MDAxMZJKwqovN7H+JFx1MDAxOElcdTAwMDOBuL/srqXJvOpE535cdD4kVVx1MDAxMW5cZoCTh1x1MDAxZVqbLzY0cHHgb0w3kL25wma5c3lS6Hz7XHUwMDEwo7zQXHUwMDAwXHUwMDFjbObhY+GQXHUwMDAyd7rEiXVKxFx1MDAxNDov/UboWF/zwVVZXHUwMDE20MnccbtcdTAwMThL4lxcXvtcdTAwMDCPXHUwMDBmX19cdTAwMWbEzVxcXHUwMDFhXHUwMDFmtGCNhrbCJzrHXHUwMDA1aMWkXHUwMDFh7pX5iPp6srxYXHUwMDA2lsr1XHUwMDA0oYTVyUxwgZxcdTAwMTdcdTAwMDLwKuBH/cY0jeA8Wlx1MDAwZldcdTAwMTFcdTAwMDVcdTAwMTPtXHTmc+hcXFwiXHUwMDE0XHUwMDBlgVxuS6FqR6eAdlxiXHUwMDEzuFjsXb417s/0XbB7jYFcdTAwMDO+XCJCnPpcdTAwMDAnMryCL1x1MDAwM1x1MDAxZEU4bSe2kjHWXHUwMDBlzKjCpTTa4TJLcZpcdTAwMWNSXHUwMDEzOT2huFxcPIJcdTAwMDfGnUZcdTAwMWVcdTAwMDZcdTAwMWRcdTAwMWHsr2JQXCJYh+00s1x1MDAwNuneJZa2eD5a4ERcdTAwMDD9bTA4l5GSXHUwMDA3rvBcbm47SMQpxlx1MDAxOLD9vF5N1Ps67bnLjes5JC/pUrvKi1hcdTAwMDWYXHUwMDE4aDRcdTAwMDPh+ludrbSQOUW9YtEtfFRa71x1MDAwNThcZl6y0tCykqc+OVx1MDAwN3FcXHiUKlx1MDAxMIylKtd7WeY0XHUwMDExTSmjSDBcdTAwMWHcq1x1MDAwNEpBn8BHjInlajQylMhMXHUwMDEwXHUwMDFioKn6m8W0clx1MDAxZFOCykUny9JcZotcZpWEftvQwPrBN/LnkqfJgNmmJE4zvWb42zeh+oj5I+tcdTAwMGLZ7Y5bOmTp0Vx0qq8hYVx1MDAwMTWoXHUwMDFmXHUwMDFkXHUwMDE4hFx1MDAwN+hgbvFfjCnocCYwTZhcdTAwMGJcdTAwMTZcdTAwMWWxmvnO5SFcbmTZXHUwMDEwwMLAMl2YqORj1pOrzlx1MDAxMm6iPmud15HCXFzhikHSValcdTAwMDKFdaSYJ6bsSLh1g/RcdTAwMDFcdTAwMWLnXHUwMDAxXHUwMDA3XHUwMDA08Vx1MDAwMKYhJ1xuXVxyXFxAsJo7TuvrcFnXK1x1MDAwNLw3xqaYK3UlXHUwMDA3xVx1MDAxNV8ouYzcyONqp3fm8ljLXHUwMDA3Y2ImmfWEKT3hdND88Vx1MDAxNjg8XHUwMDFjY504iaBcdTAwMDbMOeQtW6DKaVx1MDAxNlxmtqGYXHUwMDAwNzHkXHUwMDBi0/XawsJcdTAwMDFcdTAwMDfogUUxQkpT6lx1MDAxMkhcdTAwMGI3YFm7QFCvj9pVXHUwMDA2oiM8XCJisLtcdTAwMDBcdTAwMWWdelx1MDAwMjA1xFx1MDAwMVxchVdcbuAu659cdTAwMWXgynKjMpRcdTAwMDVcdTAwMDNcdTAwMTRpSj2v84eHhW/hXHUwMDE2gFx1MDAwNkXH3IhA3mRYd1x1MDAwN8qVslhuRICL5Vx1MDAxZWuEldzaVy8v39nLRXbH9EhaXHUwMDExlHHZxebWXHUwMDExXHUwMDFihFx1MDAwMVx1MDAxOXydZWZcdTAwMDRq7126XHUwMDFhgSeHK1mF0I/xmKsvXHUwMDA2qlx1MDAxMUd/XHUwMDAznPPceIFcdLlrcZLkkola1lCD/qfJNVx1MDAxNlR6zzImhKBcYu5cdTAwMWItvrDaXHUwMDE4w4BcdTAwMGLCXHUwMDA046mnXHUwMDAyXHUwMDA1S1x1MDAwYulcdTAwMTJcdTAwMTXA1nM9vlZkXCJg/Ok/iv//++xDf52/WLvdMNrpXbc83FxySG1l55YnzTdcdTAwMWL+WDj5XHUwMDEyPveOT1e/v3q192bUXmw92n9cdTAwMTCdW1jGxEVcdTAwMDewXHUwMDEyXHUwMDAzrUjbUpp8XHUwMDAzQlx1MDAxNJhZwIeMwpRcdTAwMDY2o9Yt4Nsu5Fx1MDAwYlx1MDAxMyCBhf4w484t+Fx1MDAwNFxcXHUwMDFjeFxmgiNX9HFcdTAwMTfbXHUwMDBljeJSu7Hjx/B71+GFsIey63CBJWPw23lcdTAwMTdcdTAwMWaWkKaJ54uldzBcdTAwMTWmk12DTVx1MDAwMlx1MDAxMOglQ27FojUhjLtCYJMqtJlcdTAwMGJcdTAwMDTHXHUwMDAxv/HSsjSBtbaJvJLa15c7MGFBMmVdvqyRJlx1MDAwNKXNa1lcYmdW5FnjWnnTTJM/rHjzmFx1MDAwNoXAyLP1RIMquVx1MDAxOYvLV3DIlri3gNncXHUwMDE0ISX4NstcdTAwMDJcdTAwMWQnqj7fzi2OXHUwMDFlcVx1MDAxY4uk8laZpW2sLFFyzLmb6Fx1MDAwNcLRXHUwMDA22lwiXHUwMDA0NZqENLD1RSgxXHL2XHUwMDA0VojL8Tr35lx1MDAxONtZqE/83Fx1MDAxMkhObWjHjFx1MDAxZVx1MDAwYs2r+5s9bY6SO6cvn+283H/bsd+ePl56rtbDl+31XHUwMDA3gZLOkbpcdTAwMGKEg2Bcci6WWjaye1xylMZprqlDt29cciUlc1x1MDAxNyTiXHUwMDFhodW4XHUwMDAwNsVJgIx0TFx1MDAxYiPoXHUwMDFht6y72J1vJJRcclg5biv5XHUwMDFiJy+EPVx1MDAxNJy83qdDXHUwMDA2mss5Z2FcdTAwMGWZYkKGM7glduZcdTAwMDJf0kbI+jKJ6WrIXHUwMDFmz+p7z/lj0+JYX7xKci9ZWCFsXqOX9mlcImBcdMSoXFybtbFcdTAwMDFcdTAwMDObsTiVcTMs+5FwXHUwMDBmuDFpjn3C2lx1MDAxYVAw6fPTNfJuWyDRvjQ+9vrhgodcdTAwMGJBm1x1MDAwNlCAx63Yu0xLy75eqrxHXYLHXHUwMDBiJlx1MDAxOdgnoTZcdTAwMWG5JWRcdOVXx4daXHUwMDA0PDiur1chy7NrIMvG65VcdTAwMWarX+1g7VtrKJ6Fo6PXK/5BIItcdTAwMGXsWqDg7IJXflxccHh+4lx1MDAwNbuOIfpjrFx1MDAwNNJTaFx1MDAxZj1TZLH5zlx1MDAwZmvYXHUwMDE3KEZcdTAwMWarkMVzf6yNXGbNXHUwMDE4rY5n7KJxft4my/1cdTAwMDaWXHUwMDA3XGYsiKdZLKtdntvjXG548esxM0GA9jBFjFC1flGhJE6lXHUwMDBiKDFjXZx1rLxcdTAwMTQssrlrcYjafGBBXHUwMDA3kFwiKO3KecnA3TxcXDTT+Es9MMbMsebfs55LwYzStKnOXHUwMDFjj2hcdTAwMTLOY/iuQfeMRFxcLK9lQVx1MDAxY9/Es1xiMFuAQJ24hfzom7xcdTAwMWRcdTAwMDebcVx1MDAxYZ1ussnN2zCBzVrK2GSj5y1cYjRcdTAwMDA+no7icGsxpNtEXHUwMDAyW3Uo7lx1MDAwNlR5XHRVrfaJfI9cdTAwMTJIs2FHK1Z0pv09XHUwMDE2zj/gXFy+YVx1MDAxNvG7jPU5z9tByKlcdEo8PSfZn7Bw7NNcdTAwMTghnzdHyLcv3q98etp331x1MDAxZn/f2ttaXW/tvlr79iBcdTAwMTAyOHaPjojlJHd0jVx1MDAxZtUlQkZub/JcdTAwMTZBjr4l6lx1MDAwNYA0zOsoYVx1MDAxON2Oq6pTgDSWa1x1MDAwZtwmXHK2PJGilOxcdMlUxe9cdTAwMWPlw4XI631cdTAwMWEuzem8IC2vp/ZpvFx1MDAwZpeGXHUwMDE4n3t+eTafri/HN1x1MDAxOdunsIMwd1UpN+FxU1x1MDAwNaz1uMBM9nB1+XJcdTAwMWE4TJotZH1T3lx1MDAxZpntvpRv0ISyJM+WMYtHXrDAXHUwMDFlvv3ag7uZMC4zXHUwMDA2XHUwMDAxaJHcYCRFmliWmedmJG6RlVxcxq9cdTAwMTcn2CY777wqjNa2tPVcdTAwMDCzXHUwMDFluOZqXHUwMDE5KItY32Uzw33yeFx1MDAxZeW9l3nTkD/TtzXbXHUwMDFlcZeVUdw0dVx1MDAwZlfSJMvCXHUwMDEwjVTh1HJznPLt1rOjIPtvTlx1MDAxN9pra7td/+1t+82DwCnWY+f9v5Xi8S2llTTLdjFcXKQy3JMqVWlcXLPBqcj9XHUwMDEx7ORcckVijFRxXHUwMDA2wpluMmtcdTAwMTG4XHUwMDFiQEygVOC+X23s7/adXHUwMDBmXHUwMDE3pHjWoItcXMdn5zqdXHUwMDE2rCxIbopRJFwirOdmq8bOQn31mke0rFwigiDWwYvSVlx1MDAxYdZTwT/BtyrLNfX6TFx1MDAxODf1++CEXHUwMDA2d+BcdTAwMTlGpSxcIutcdTAwMGYk2z6xjqdcdTAwMWVcdTAwMThVJjVcdTAwMTdQ8mZVXFxBSpCxrPNcclx1MDAxNpYyXHUwMDFm2Eoy5qW/TFx1MDAxYV41vCatKWGP3Fx1MDAwMcNmZNz85q94er+mKXOcPOZo3JNZsVx1MDAxMNX4yp7MK82d+8uvvZMlp1x1MDAwNotvvVx1MDAxMlx1MDAxZsWPo6er2/1cdTAwMDfh3D1r8tllXYPRjutcXM58O1eHWLjpgYFs+WpL45rZ+lx1MDAwZneos+hcdTAwMWV6jFx1MDAxOGZMXHSL6z9cdTAwMTZmXHUwMDFm82xvMJNcdTAwMWMkP1ZM2d9cdTAwMTTkXHUwMDAxe/drfppcdTAwMWRcdTAwMTjYtVxyaiNcdTAwMTW30KSuJ2hcdTAwMTZcIlx1MDAxYTaJdT42QVx1MDAwMsnGrXlcdTAwMTM9XHUwMDA2ubLU+T9jgoZOU3BZvsFcdTAwMWXN2UrjSSHwr9xsXGL1L/W9g3V4PIBoXCKvpeuXa1x1MDAwNFtcdTAwMTCyR2jMz1xuSPd+4V1Ymc7PO+aKan1BOTCUM0CkYvGIK6dcYpnPwzRcdTAwMTjByspcdTAwMDbHanCfXHUwMDEwt3/xjFx1MDAwMFKhVF7ZXHUwMDE3NEApwZ0koFx1MDAxN0F6LkCVMZ5LTDykwbJcdTAwMTi/SWOaWVx1MDAwYmRjXHUwMDFmzIbKlzJcdTAwMTU3kyd3nOVcdTAwMDDv2V1cdTAwMDKzZuvLZcrEy4V0XHUwMDA3qMhcdTAwMGLVXHUwMDE1KSY7WdkmO1VuXHSdp5+YoFx1MDAxNUitnnL83Ivm6Nzb0kJcdTAwMGXk0L1cdTAwMTFuZNZW7PLSrn5cdTAwMTDobLnZiVx1MDAxM8iliUJ99iU8W8RWTrOvsFxm5pZcdTAwMTbRcJVg2H5M5Z30ZDU8gydbnjnEZeBiQHWOz0ww5rpYd1x1MDAwNt1vgP6nXHUwMDAwNHyaU+zHbZjmjukmQ1x0XHUwMDBm6jwsXFzofKdH/VxuhWK3U4Sjns2vWNhRcrmSXHUwMDA3znjFXHUwMDE2f7I+M1UnXHLCeG515MZcdTAwMDfVwOHqTFx1MDAxOXZ3XHUwMDEwztg87ighVsk87lxcXHUwMDFlt1x1MDAwNbKVXHUwMDExuz2yL0FaT8FOakZcbp67JOl2XHUwMDFiJFxuXHLPfHLki0pzb1falJv7Xix7+INcdTAwMDByL0+9wLxZjefORSmB+0GU8apYks8uZL9IpOBcdTAwMWVcdTAwMDNJ0Fx1MDAwNOyT509kNItCMXu/XG5XY/nVXHUwMDBiXFy1YPi6kJgoourL5qi6/MU9+jL6MVhd+mDfrbVbj3rrg96DQFV31lx1MDAxMIeN2KDxslT06CX3Zlx1MDAxYsVWpcq6UFx1MDAxYdeMQNXnjarZgjOwOMVVgarN2IZcdTAwMTBBkOAup+JS6cW5rkE69oj/ndL8z8FURZCz7HVcdTAwMDKilVBewVx1MDAwZdmRW+PZYdzEXHUwMDA2W+1cdTAwMTVpoFx1MDAwNaFcZtwzrlKOKlx0QVx1MDAxMU6OXHUwMDFk/XlaeP1e9izPp0nQXHUwMDFlkMCo09WjkrxcdTAwMDZn50X20tBsMlxy6CptJ9Ts41x1MDAwNorKc/Mk+1x1MDAxNNdcdHNcdTAwMTn7VcGkOS5WdyTiXGbb9kZuIGC3nvrd4rOVxtS1ZCaXdIyd+tNcdTAwMGViXHUwMDEznqA+MVx1MDAxYngmhVx1MDAwMZWU7PwlXfnMIDbKYctSXHUwMDFlX2NcdTAwMWHsIJB5XHUwMDEzKO6bZGVcdHG9NLU8XHUwMDE5IVxuj/DLuCZ9imct8Fx1MDAxY3mZXHUwMDA24f5cdTAwMTTcemmTg/CeXHUwMDA3XHUwMDA1RrY9YDv9WrC/XHUwMDExLlx1MDAwZjs7ozP4qVx1MDAwMGetp4Iz1MlcdTAwMDVbaFx1MDAxZllE59Xm6PzktTs+XHUwMDFkLlx1MDAxZC3ufu24XHUwMDFm611p7NBNQef91s7+ybDz65E5MFWUZ7HYv0LGlO/awMZiRkd22Fx1MDAxN4W+25PI3OGvq5G5Zduh6qRALSRP4HB5w3JcdTAwMWWnMVx0zJa6y+SKiWc/ZVxcholalt6NWXBcdTAwMTGXr1x1MDAwNbh/XerdhWpdJJP+no7Dl9/5q6DB54qx/fKZfnOg+6+W3vc/fHF658OSXHUwMDFil1slOtxcIlx1MDAwMM5fvvP3n1fJ/dJ5tvhi9Opg/WRl6dmnL892n348WbyR3IuPjzrfR6mgsyu+XHUwMDBiXHUwMDFmPo7ebu9+fbMqv+wtii39fG+jIHZcIr65eVBSafJXjeZSTuXNnCm9s1nkuVxybK/nQ1ooXHKOd9bVyzCdWNT5y0gy+oz77dm5L3JcdTAwMTllUl9cdTAwMGKh/qTd/dxcdTAwMTGbnZ1cdTAwMTjvjze5lnVcdTAwMTX96eZ8pdGlceJ5kVx1MDAxYk9ZgTuYXFxN5Fx1MDAxY16xxFx1MDAxOHlcYknxzNPprrtsyMk4Zlx1MDAxOFLnSkhcbtdcdTAwMWZ1hvze3OLa8tx6Z4jBXHUwMDE3ZnXQXHUwMDFmrXd/nO1nSF592jrs9nL1TEQu9rp7/ZzudSg4Qb5Rd6fVu/zAYbfdLkLjXHUwMDBlhLbAZIfLTcBrMOzudfut3rtGt9E6XHUwMDE5XHLedo7PbmQ0POlcdTAwMTSfWOf5JdvKzqOgn0P0gt2VXHUwMDExnUdcdTAwMGIyXHUwMDE2q9LAV81cdTAwMTE9XHUwMDFlfHuybLZPlzfeya/L71x1MDAwZV5snmxu3Vx1MDAxZlx1MDAxYpyC6II96GWsRnRcdTAwMTdExsS11fqeI7q0gWdcdTAwMWZcdTAwMTai1HtcdTAwMDTpz+KT0bfY0ivv9j9/P33U2txcdTAwMGYnXHUwMDFiXHUwMDBmXHUwMDEy0tvt5UX9ovu29/bLu07v8cHCyudHP35cdTAwMTmkV4+mXHSkXHUwMDA3bnJgfVJkqU0oaX00mWIxJPtcdTAwMDBXYzp7XHUwMDFisolj0Fx1MDAxMXHkuJ/Jb0yvxfTX14B0hedcIpRRXHUwMDEzbIyzNH3rgkBkb0PhRKd7XHUwMDA06WvDwdduuzOcO+qdXHUwMDAwJO9cdTAwMDOa11x1MDAwMFdcdTAwMTnNp97BTYH8zKhXeur7vvvwbct+XHUwMDE5nK682lLLh8ePJo260+t1j447qV3zXFzujFx1MDAwN9g4zap2Oa5LyFxyW/OsK3aNvzDssYJcXFq2NllQQktVsVx1MDAxNdGwhS+Pw3XXsu5dXHUwMDExdoS4gXWXrPT+2vabatueXHUwMDA01ItymjGgXpg8ezqrQjosieGmllwiXHUwMDAw/HlYn/qZIH5cbnTXQeHqs8dmY/Fwb/NH5/irfvmpc7D0etRcdTAwMTS5by1cIvj++dWXzd7S0/dLL/tb6t361vHn983k3i10Vz+9XHUwMDA20M3W7zyWi/1QXGLdhW2/uYtkk3imVVx1MDAwM2tkpZnEbvbyt0BtzbP/lKxqZmGvipp/xrrLke9Dxe6318DuwHaPslhcdTAwMWM0tmQ1ieiX4C25+9RGZ3/ClO9cbrz/3Vx1MDAwN5E9vlx1MDAwZthdg5bTsLt8XHUwMDAzs4Huz/7Rxt7K4fu1b5uPnz39+PrL3klrOGnU7W7rcNBvl+zaRJexoe1cdTAwMTToXHUwMDBl+elq3Os/XHK6XHUwMDE129wqLpRVYbdiyyZt5V1j91x1MDAwM7Lu9ZujN1x1MDAxZKrwXHUwMDE15p1bxlT4jmznaf3PxOs/id6LrXerg80l+2pvZ/HxxtHbXHUwMDBmj9vvn/zjULb6LpugrHXsKMeGh9E5X9xdd1bZXGJrzFx1MDAwZppzStvqQFx1MDAxYZG4XHUwMDAwRyZOi1x1MDAxOFxuq8O3iLP/XHUwMDE0S3zXXHUwMDFjZ1x1MDAxNVv5umJcdTAwMTg0trjCbtOJgFmwRuF+guyg/e/+o1x1MDAwYpi7XHUwMDE3KFtcdTAwMDNsXHUwMDEzKDvtXHUwMDBlZlx1MDAwM7NXk4eS60nNWnLTg46SR4xPgixocSZcdTAwMTG2xemJr6Cyqlx1MDAxZT08hkD6yJ3H1zBptVx1MDAxYjvG/GeY9MaNwVVcdTAwMWJcdTAwMWVcdTAwMWVcdTAwMTBkdUA91dKV4IG+qrBcdTAwMTdzhrbOht0/Y+uzbVx1MDAxZVRUSv4sXHUwMDE09XH87Vx07G1YgzauYCvMVufsITXJoOVOaueEt5tcdTAwMWZNrrTmSYiOlSSFXHUwMDAyrPm91lx1MDAxMac578BvtVT5Wkfx+Fx1MDAxMij/93SgXHUwMDEzupJcdTAwMTTcTVx1MDAxYu7VpCFcdTAwMTmuys/6MHBcdTAwMWPsXHUwMDA04Iu9XHUwMDEwzsfrMsRcdTAwMDc8XHUwMDAwOjBnnpxcdTAwMTjQYLzXKvIru7ROb3vwrVEgtH7w5MPrJ3ZnaeX49PWHx+tcdTAwMWZOWrvfXHUwMDFiMlx1MDAxM8uTk/OjMc58ZqnoxfnMs2nQ9Fx1MDAwMoBgMs2DfvX56lXF5nglbWatuVx1MDAwNf+5rXbV9vZDTyxOqVx1MDAwM7hcdTAwMGU10YH7rXSsKlx1MDAwZlBmXCJ8unCfrPlcdTAwMTO6cFx1MDAxMuHtc5ON5TdPhFo8tVx1MDAwYs+erfV0e/v9ilxcaMpNfF9vhrWX7vNO2POvzer7Z2vLclbcJHpb6DhyM25SfZdccrhcdFxiXHUwMDA1l6xZf4hh6ZD2ZWJfQ8mjhZ3hWVx1MDAxMVx1MDAxNfbobVx1MDAxNkFMuI1cdTAwMGZ/iipz/Fx1MDAxZMVMscOt5sQkalx1MDAxMVx1MDAxZNvnVFx1MDAxMZMgptlcdTAwMWK7tmmeRnRcdTAwMWbrcVx1MDAxMNjPXHL6c//uf+1cdTAwMGVHJ61cdTAwMWX+1lx1MDAxZrQ794Gi1CBcXFx1MDAwNUXhnVxc3Ed6XHUwMDE3s6EpV3uiq2iK1zJcdTAwMGJBqmhCXHUwMDA14jq2VLKFVGCVhcMvqFC5iFx1MDAxN13GY6WlXHUwMDExMVDVxlxu8dvUi6b+/saQXHUwMDBi3HRsjFnlXHUwMDAxlJq6fG/Zw8hcdTAwMTRcdTAwMWKF/8P4SoV68mdhQjPHgiageWbU5Wq/UeBcdTAwMDL51rqIXHUwMDAw38W8XHUwMDA3XGKPVJ5kLz5jO2hhbd5cbi5cdTAwMTRcdTAwMGZznFx1MDAxNXtcdTAwMTn6168+b3xtm87zU/F8+fm7nYVVM4VsOcvdoTyr0rJcdTAwMTlnXHUwMDA12VxuPDfjvPBMXHUwMDE0j8K+P+Tl6orwq1x1MDAxY2n0cKRcblPFsnwjS8xF68wqXHUwMDFlcDY125OF6LmxPVx1MDAwNLhkVzhcdTAwMDeqWFx1MDAxM1x1MDAwMaW9XHUwMDE15vJPcaRcdTAwMWZu7Ei5pDKlsFnJ6ZXNXG50XeooXG7Nk/5ZjnRhuoLyp6Cad+FJXHUwMDFi+yV6Uq9MhJ9cdTAwMDdcdLHsa1ZoT3LumWRcdTAwMDavZaMunnIwK1x1MDAwZnp1+XbiQYVyikfFXGJtrOCRdHZipIonXHUwMDFmhGuO845cXOfVXHUwMDE1sle7TsCHUS569lx1MDAwMLKl7r+Op1x1MDAxY1x1MDAwN8OzcmW171RcdTAwMTl3XHQqpWN+ILyoaNyrLXjsb9d5hev8ePOkucf8iThZOZZTzelVKEJcdTAwMTieWONvY4HsXvjOqfrJn4Jm3oXnbOyPXHUwMDE2zlx1MDAxY5JQmv2nvORhuZNcdTAwMTlpm92O27xGllx1MDAxZq5S5O3NlJeG7SYmXHUwMDA2aSZqVe6T35RcdTAwMDf90D+wJ62Pr9pcdTAwMDfD+PTTx1x1MDAxZlx1MDAxYofNKuvZ5FNcYqCx4YnupY5IXCIgJlfjZHlF3YBzmefmeclTiGWsOlx1MDAxMkRfx1/+J9XWf6v2l1XpOefy8/2qXHUwMDFko566migj29PEKG8jqLxpem7zPJv1ampOLiSv3jgnN1x1MDAxYVx1MDAxY01LyCXjLmffqlx1MDAwNzqbtNvTXHUwMDFk032z8Gr7udlaf3n4TD1pf3600sh0rcysZjdcdTAwMDQu9Mm0NFx1MDAwMPSZwTSmalx1MDAxYVlcZjFTLj+03rO5fKG/83iV6zr1Pv9Jcc735naLR0/qUGGi83l9x1TDtd475+y93Od60u9+nzvmZ0aVdjvu/vVr7bZynLPav5paZGFSp3eKMjy/geVcdTAwMDRVSnU632Cmz3zGXHUwMDBis6lcdTAwMGVcdTAwMGU/tX/Yg+7w82prZfR+ZdpcdTAwMTkt92frqvWZUWzgYuKEv3JcdTAwMDZvXHUwMDAy3kTtztWf8TM/5/MuXHUwMDBljPbEXmuqm0Ld925P17bKqXbzXHUwMDBmNlnlp/ph76JH0F/d3e1Hc5Ncclx1MDAwN1x1MDAxYm8+PVxub7fXh8Njv/rp+eNnXHUwMDA38r6brFx1MDAwNCXI2Nteapv3wihlVVxcYNmWm1xmMmZptFK4LLAy2VxurySMt2q3wITVSmZ70mWpWzLb8zcqqztcdTAwMGXWtpbF8FU/PDpuP+qPXHUwMDFlP9566T79ssrzmzmF5+/erc3999ziyWj/rp1C5aVnXHUwMDEzfl+9N+DK4lxcXHUwMDAzzJLGgfSGiuJcXGs1uyRoO3XZm9S7cslbhex3mnF6+C3jfKWZXmeFxmqedVvNpv30JVx1MDAxYWG4QqPkbVx1MDAwNOX3XCLNWNJJ/ixcXKrj+MtcdTAwMTPOaWa5xca1rswtXCKc5Fx1MDAxNrEgjJWI5yazdjHjOZBGXHUwMDBiNvf18nq1ro2SjFdvNSiN1/F8XHUwMDE0nlXGLuOxopjYZ3jbq2C0cizkvd5y/OyTjX+cz/F86+hofVx1MDAwNI29fFx1MDAxMvNfu51vS5VOhj9cdTAwMDSyfGB0Mp3cOv/+4+//XHUwMDA3bbKKhCJ9 + + + + + 2. The remote provider expose an API to execute containersVirtual KubeletInterlink API ServerProvider pluginProviderAPIsPodContainersPod on virtual nodeVirtual Nodeunix socketunix socketHTTP + Auth \ No newline at end of file diff --git a/docs/static/img/scenario-3_dark.svg b/docs/static/img/scenario-3_dark.svg new file mode 100644 index 00000000..e2ce7009 --- /dev/null +++ b/docs/static/img/scenario-3_dark.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO19bVtcdTAwMTPZ0vX38yu4fL5cdTAwMGV97/eX801cdTAwMTFcdTAwMTVfXHUwMDAwXHUwMDA1UXnOfXFcdTAwMDVcYlx1MDAxMFxyXHSGoMC55r/fazVIunc66UZcdTAwMDLGmWHOeJwkVHZ3V9VaVbuq9n//tbDwaHhx0n7074VH7fO9VrezP2h9f/RcdTAwMDdf/9ZcdTAwMWWcdvo9vKXy/z7tn1xy9vJPXHUwMDFlXHKHJ6f//p//aZ2cZKPfyvb6x1e/2e62j9u94Sk++//x31x1MDAwYlx1MDAwYv/N/yx816C9N2z1XHUwMDBlu+38XHUwMDE38rdGX2eCSF9d7ffyr9ZeSK1kiDdcdTAwMWbo9Pbb51x1MDAxNLkrn4yEdU6fYlx1MDAxMcP2Pt45aHVP26N3+NKjy8vn60cni8+fq/bX3eXtXHUwMDBmS4+3RXf061x1MDAwN51ud2N40c3XetrH9Y3eO1x1MDAxZFx1MDAwZfpf2lx1MDAxZjr7wyO8K5PXJ/3WoH92eNRrn56Wfqd/0trrXGYv+JpcdTAwMThd89WN+ffC6Fx1MDAxNV6g1EJmJiqpXFxQVpubN/Nfd0FmXG43x0vhoo9eJeta6nf7XHUwMDAzruv/XHUwMDFkiLAnxGhlu629L4dYXm+/8JmD9l6Mo898v75aI1xcJqxxwdub947ancOjIbXEh8xpXHUwMDE1pLJcIv9xozW08ychI17VVsnR4+M3n6zs56ryv6P7P2hcdTAwMWS3V/grvbNut3hcdTAwMTN7+9c38YdKjZRKX7/y5+jS+PnlVFx1MDAxOYtcbllSymH7fHhzzVx1MDAwNWVx51x1MDAxNyefzOKJOP9uV97IXHUwMDBmu+77jnh087k/r/82Wv7ZyX7rSvekV8467ZzVcvRIup3el/Tauv29LyN1/VfhQsaMp7TOgt3oKCfZjbfQmmhcXKXdLDW3m+pbUW03R629o7NBe1x1MDAxZSzHeqhttMqE6JyKqem4XHUwMDA3MFx1MDAxZFx1MDAxNU1cdTAwMTZlXGaRqzFFXHUwMDEzuDEgK1KDgeJcYi2NlHe3l9JcdTAwMWJjhjFL3Vx1MDAxZK2q31x1MDAxYm50LvlAlCi9+qx13Ony5o/cSK7UuIGv156vrC6srj1dXlhbXXi3vLH2/t3S8sJ/euvv1rZWni6/e1T6lcfdziF1/9FcdTAwMWUupT0omcWwXHUwMDAzaLr5wLB/Mnp3XHUwMDBmi2h1eu3BSlx1MDAxMzjoXHUwMDBmOoedXqu7OX2N4ytsnVxy++/ap1f3YDg4a1x1MDAxN29j+8WPXHUwMDA3XHUwMDBm122nWvxUuMRcdTAwMTOaZPZSSy+E915X2f3T5nZcdTAwMWZfxt7773ZxcP7t4PT8+bMtefbhy3zjpXWAI6uFXHUwMDE23jrATmr12mdOwiV4ay0+Z5OFjSxatvnPdKtv2f1wcDBu9TaYjN8t3Fx1MDAxNSiOLuXG6o1SmfRcdTAwMTGYamL+M0L2XHUwMDFmXkBcdTAwMWJcdTAwMTiicf5cdTAwMTeh5oNcdTAwMDHbdFZcdTAwMTgnskLp8Vx1MDAxNJ1cdTAwMTGqXHUwMDEy3pabq/nJY3/ycXHt7ZZ9/+JsZWWlfXm425t3ePNcdTAwMWU6XHUwMDE2RYxSiqBdwdbz3/dCZ0A3qJePMVx1MDAwNOvvRdG1iZmMUFx1MDAwNmltXGLKODOu6UrJLFxiXHUwMDAznVx0XllcdTAwMGaNXHUwMDFlI4hBeFx1MDAxZEw0f3lVn8ThTPRcdTAwMTO1XFxL61xcMLZKyZ81V/KLnS9cdTAwMTftJ8f7/c3X3fNXn9c/f758ujXvSm61y6BW0PVglFAyUXLrfWYl3GTUXG5cdTAwMGU1TOZwd/Lm4JFQ8GBMrlx1MDAxMqpcIlxiKuLItU5cdTAwMWJLblx0u/iFJC5IXHUwMDAxs7wriVx1MDAwYqVXp5A4nS2s9lx1MDAxN1ZWn6y9X326XHUwMDAwstWDZ+98w8NeXHUwMDE49lx1MDAxN4ZH7YVcdTAwMTfrS/dA5EpcdTAwMTeUsrZbLupBuJuVXHUwMDEzQzZqjFx1MDAwMqjFSu72vLm9XHUwMDFmbHefr2/KrZWzrTerXHUwMDFmXHUwMDA38lKYt+15t3dcdTAwMWZDpk3QRqsq9uZccqIpXHUwMDFmrFxuQdxcdTAwMWZ7Y8YlXpv6XHUwMDA09mbxiajkXHJ5XHUwMDFirfPa/K2Bv0DoOXqK85DyuNJcZiN6W+sve9sn8XCo5MXK5eDV7ogtlbS4NVx1MDAxOPS/XHUwMDE3clx1MDAxZX9Mk/tk/61+9mHz8OVy5+XJcvfpnuzu+DvJrUvRXFxcZl6ZNy/7Ty63vm9dtrut+PXg4qDpcodcdTAwMTeX21/P9O7qRf+FXHKrK4tvj49Xmy33+m+/nDYoodNXR7QhRlxy6iBHxKLgR17cgjdU3uM59yPBh0xa46VcdTAwMGLMO9qUXHUwMDFj25BcdTAwMTlvnFK1UWD0ck/9XFzuR1x1MDAxYZVpXHUwMDFiwdFcdTAwMDVoryxkmEbceJw3SG013Ir+XHUwMDFiJX+2OoPhWau78Opsl6r4s1xm4bizv1/E2yTbU1x1MDAwM4gpb5i4qFkxXHUwMDA0frrKqKHdKn35xqpcclwiLq2LRLhg1SvNrXr7y9n+6fKrlYtcdTAwMTX35Pmz7feL7U/mdIJV71xy+qeni0et4d7Rr7dsR8qP65eIaYNQIbFs53xcdTAwMTakXHUwMDBlKkTQditCsrDbWbZWbq9tKyxbxcxcdTAwMThcdTAwMWStXHRKel1cdTAwMTX1SmWzKFxcjFx1MDAwZT5cdTAwMTjLKbCIXHUwMDFmli6CxZMs+vCipY9Q/+jr25Xds4/m4Gzn85Otw71n5ycrb1x1MDAwYkD16PGTnVxycfj0eH+19bn3/ltr6/TLsf9cdTAwMDFX8+4xToetwfBcdLS40ztMf6Xd25/wTrd1Olxc6lx1MDAxZlx1MDAxZneGWMZ6v9NcdTAwMWKmn8jlPiZwXHUwMDFmtVtjXHUwMDE3XHLJXHUwMDEz3zuhuPIzXHUwMDE4/W1hpI/5f9z8/X//mMGnXHUwMDE3daa1V1x1MDAwNkZu8P9CRFf6/SxcdTAwMDRcdTAwMWRcdTAwMDNwXHKxro5Gh1qBJsBcXGI00XlcdTAwMDd7XHUwMDE50Vx1MDAwMf4oXHUwMDA1NVx1MDAxNorf5KLQxj20OPBoRDv4tI2MVYUtiTNZXHUwMDEwMTj4u4jvdLpenM4kkNMzXHUwMDAxXHUwMDFlnJemJC5kyjjYI+QpLE/WinNcdTAwMDY+3FwikndcdTAwMWXeRphQXHUwMDE0513mXHUwMDE0t0RcdTAwMTXw3Vhf/yhmL07r4H20MD5cdTAwMTlcXOlig8iEgVwi+Vx1MDAxMIWX3tdL05nQweHhKu6XldZcdTAwMTZ0hlx1MDAxN7UyXGJ4YOWmXpjKXHUwMDEwxVxuXHUwMDBiXHUwMDBmLYMsJFx1MDAxZq+lgVx1MDAxMME7S4vvilrVXHUwMDFihcy0QqylXFzUoHROly5VQu288lFIJbF8p+ovduZcdTAwMDKhW1pGY6TzSjtcdTAwMDBDKFx1MDAwYrSZgMHigqHF1Pd6gSazIbLuweNXjLSpvDK21MnDL+Ch2qCFcdpcbqxhirx6bZm1uJgxeee4SVx1MDAwYlx1MDAxZCzshdzcPXxcdDRZ0HhCrf5plcFcdFx0XHUwMDA3j+JlVGLs6booXHJW7eFHha19XHUwMDE4MFxyg0drJX5ccmbgU9tcYk4gwoCxKWjAw1xus1x1MDAxOa5cdTAwMTHhXGb8XG58sfeJXHUwMDBiMFpcIsjRNsBZ69hAmnBcdTAwMGV3Jmc1iVx1MDAwZqB/gvk7sCY8K+dq11x1MDAwNl9cZlcsXHUwMDAz8Fxmz1x1MDAwMEaU+GJcdTAwMTmhPsAxXHUwMDE5XHUwMDAwJtE+tDioXGL0Q8ODXHUwMDAyT2HlKfIgYFNUXHUwMDExeGo8qFpvbKDCXHUwMDBlrlx1MDAxOF+udVx1MDAxNKosXHUwMDBlcWBkslpyP1x1MDAwZnpea1x1MDAxMSaTeFxieHy4XHUwMDE2Z+GCxmhAXHUwMDEwXHUwMDFhX0VxeGC19j9reYuEl7wkXGJeXHUwMDBm6lx1MDAwMLqtS1wiXHUwMDE3JT9cdTAwMTA0/lx1MDAwNVxuOFx1MDAxMYxuL8ra657Elv5V/P9bXHUwMDA3VHbkPsdcdTAwMDIqXHUwMDA0XHROXHUwMDA34SvTJC+bXHUwMDA3VJsw6v3F02/d9vfOxsfXn7bbS1x1MDAxZk8mXHUwMDA0VHOyVZ6HUrBcdTAwMWJmQLxcdTAwMTd6dFx1MDAwYq5cdTAwMGJk4I2Mcd5cdTAwMDK6XG5cdTAwMDb3kzmSikRrhJlcdTAwMDXto2SJkqrKs0bNfXSEc8ZGLZRcdTAwMWbbJI9cZjzwR/XO4Y1cdTAwMDL9XHUwMDEzXCL9dUIkmcHlXHUwMDAwXHUwMDA28NBcdTAwMDNcYjPig7Ivi9abIFx08IBcbqlroWBcdTAwMTF8wDoh4Vx1MDAxYqFmcOC2xFx1MDAxN6iBXHUwMDAytiC10HiKsUFUUyfQO0BcdTAwMTWLXHUwMDE3dEBoY+++wp9cdTAwMTBcYr5cdTAwMDW0kvhccuVcdTAwMTX+LFxudGDHiMeCXHUwMDE38NtcZkpcdTAwMWHIXHUwMDEzXHUwMDEwpcD3wfpA41xcma/KjKxYk0pDsmkkMETgvVLc3VxyXHUwMDA2fqjM4TLwTlxyXHUwMDAwXHUwMDAyTWKRQ320pLKIO8iomvlcdTAwMWFcdTAwMWJKSiNxXHUwMDBigfRcIoRohMDdqFx1MDAwN8BZy/NZ4KNcdTAwMTBcdTAwMDBnXHUwMDE3XHUwMDE4XHUwMDBil+QhXHUwMDFh0NQ/iPRcdTAwMDLutj5cdTAwMDTDLfL0rFx1MDAxZWE4eFFU5Vx1MDAwNTrCMzhcdTAwMWW+XHUwMDBi3Fx1MDAxMSBdL9BniP/wMPhcdTAwMTiFd6okj7F1jKBfmrteIFx1MDAxM/U3UGZgXHUwMDBmwFx1MDAxZETrXGK2VElcdTAwMWXehLZ7r4LBXHUwMDA3wIRcdTAwMWJcdTAwMThcdTAwMWRiXHUwMDEykFx1MDAxMG3xcU8jKF0wXHUwMDE4XHUwMDFkiLXDJ1x1MDAxMEVcdTAwMDBydFx1MDAwM1x1MDAxNXSZwbNQXGZl+EfJRFx1MDAxNOgo+KHQUD7J51xcXHUwMDFmxc5cXF5cdTAwMDBdXHUwMDBm4GA64FFcdTAwMDKnVVwiXHUwMDEwwC2F0Vwi0DZr2T+DYqhcdTAwMWbjXHUwMDBmUGjvbDlqV4gmPG4uXCJcdTAwMDOFr/T1wcmiRqhDM4BcdTAwMDJGXHR3bVx1MDAxMo2xsFx1MDAxMCmJil5HX6+B2mRQWaGE8FaC3uhEnlx1MDAxNKz1xcOl4tcrzKzFIei1XHUwMDE290g6PFx1MDAwZa+SmNgjXHUwMDA0iJFcdGvexPrwaVFzXHUwMDA1gVVT0cDXxXR5XHUwMDAwo1x1MDAwMN9cdTAwMDNTc/iuXHUwMDA2OY+QcUddXHUwMDAzOlx1MDAwMZ/W6PTpXHUwMDA2MD3JeMhCaerFeWbAYVDMnyCAXHUwMDFhXHUwMDBieOCZXHUwMDExROq8Oq2Bw2ehXHUwMDBm9Fx1MDAxOEBcdTAwMDbzxDWliUXoXHUwMDEx4lx1MDAxM1x1MDAxZlx1MDAxOFx1MDAwMcZ6dz9rcXBcdTAwMWbG4lJcdTAwMTFLwHeU80WKhXjBwynCu+CJNFx1MDAxMCcyXHUwMDFiXHUwMDAzI1U4P1x1MDAxNs6VxDlEunlcbtVcdTAwMDdcdTAwMGadaZBvgzxcdTAwMTa6M/eKJ4FfS1x1MDAxM59cdTAwMDY6JF1EXHUwMDEwqlx1MDAxNOhDvW+JmWSFLPiEsFx1MDAwZYFyeYUxw8t4tHmyhrmZh1x1MDAxN8hcdTAwMWOPguo5QU5hy85cdTAwMGaPK2pNeFx1MDAwMWuLXHKSXHUwMDE1fMDAXCKmN5l3h1x1MDAwZi6KM4L1IGA2XGZjXHUwMDAxxFxyXGJcdTAwMTa8gYD/XGLe0cGIUd1/Ls8zWUDeolx1MDAwNYvKmulfwPUqiWBcclx1MDAwZrP0fK1cdTAwMDY9jHjV4lx1MDAxZlxyntDgcm2Gm+Ng6HhcdTAwMTJgXHUwMDAyLpFcdTAwMTdhs6BcZvQtokk+dcbiYFx1MDAwMXBtXHUwMDAwf3g2k2wyWJuxqlx1MDAwMY9cdTAwMWPGgaC7XlWMxOpIdWDweHwuXHUwMDE1XHUwMDA3h8dMtcuTZVxydlRcZohcdTAwMTCYs7HQVZ+kUqzD6kjVvJOs2mywo4Lr4W4mXFyyw0LKrlx1MDAwNeK0XHUwMDA0P8M78FhBN1x1MDAxMlx1MDAwNzWJoFx1MDAxOUBybibMlziXkbND61x1MDAwM7ii9Kk4ZttcXFx1MDAwNFxmwZuJXHUwMDA2Zlx1MDAwYktcdTAwMDJcdTAwMGV6XHUwMDFiXHUwMDE1KUlIlueheFx1MDAwNm7bgTZLqVx1MDAxYWiKo6oq6IrA4/Ou9GidyPBNeERcdTAwMDHsN4J01XtcdTAwMDHI8zBbQDiQxrFcdTAwMTUrXHUwMDExyMpcdTAwMTAwUlx1MDAwNFx0RPJcdTAwMDbXS5LLONRcdTAwMDA0oGUlr+fAqOH1XHUwMDEwXHUwMDFkMI1cdTAwMGVcdTAwMWNvII99XG4g9fBcdTAwMWKA/6jLYVx1MDAwN1x1MDAwNDKWXHUwMDE2XHUwMDBlX8Q6llx1MDAwNrG00WRBiHq8cCDhflx1MDAwNvLgXHUwMDAzuCFcdTAwMDZQYFlMXCLPcFx1MDAwM0eBXHUwMDFkeYNcdTAwMDD4wcWJLKewbN9AXFybXFytYMhcdTAwMDFHXHUwMDE1XHUwMDAzXHUwMDFlc1x1MDAxM6cn4CSBXHTakZKWlmYjXCJopqtcdTAwMTF+SUR1XHL2zFx1MDAxMDKCXHUwMDBmgEBcdTAwMDLMvFCpOICdyVx1MDAwYlx1MDAxY1x1MDAwMVx1MDAxN6FB+Fx1MDAwNzJcdTAwMGbq6GGWIDmIXHUwMDFhXVwiXHUwMDBmd1x1MDAxNN9cdTAwMDJcdTAwMTRAWC5cdTAwMWFcdTAwMDRcdTAwMWIzXHUwMDE2J3JcdTAwMTdPvPVcdTAwMDKIkegxrMZaRFx1MDAxYVB02IdtXHUwMDEwW3kuLy/x0Fx1MDAxMc6+/GS9yDygTqpgwVx1MDAxZkWD5INcdTAwMDJcdTAwMWaxXHUwMDFhoO/xQKQyJbv1XHUwMDE2btRpxqdcdTAwMTZf2sAqXHUwMDEwTVxctXbCqVxiOIRkqyZm+aaQ5zugXHUwMDFl9eJcdTAwMTi9w1x1MDAwZlluX1x1MDAwMr7SbSRcdTAwMTFcdTAwMDC2itG9i1xy9i5nL07AQ4LgSMtcdTAwMWOYL+lKgNNDlGtAzeFpVf3FMtQxINVMXHUwMDEzRK28KS/PcVx1MDAxYlx1MDAxY++AikJog5unJLy4wNVcdTAwMTioX1xivkx+XHUwMDAyd6ZcIlvxwNvIaZroijLM9tlItlwio0/kRTB4b1x1MDAxNPOAXGLXfoU8aLCW2nBcdTAwMGbTWlXSvSgysFx1MDAxZs+sUlx1MDAwNNdrkork+nSQhmlcdTAwMDdcdTAwMTaWlGwj4vGSXHUwMDE3gUBcblx0JG2UV8qdKJiyxlM25Z29iNVDTVj6qdlcdTAwMTjVwDhixp1nT1pcdTAwMDJUK+epxvYnmohjhoWBM72bi8nqXHUwMDEwXHUwMDE2enZtKDCDWH+1ua0x+mTgLlxiNIk84Fx1MDAxMiQyI9uATjFLXHUwMDAxXeB+UFx1MDAxMFCLclx1MDAwMU3M07hcdTAwMTFeXHUwMDE09sj69ibygC/wQc5cdTAwMDBzWe+W6FxubIKxYPT0XHUwMDE1XHKudtbyXFym6HKNXHUwMDE3ILdO+tQ2hFx1MDAwN5OBXHUwMDE2w92rXHUwMDA2SVxmXHRPTlx1MDAxZCFqMFdbLvFcdIAhXHUwMDA1tipFxE1cZq7eXHUwMDE3SESluFRtXHUwMDFj++uYhirJ+1GWXHUwMDEzSVlCXHUwMDEz5aO6Mkiz7C+PoVx1MDAxNOWGfJfBaao6rbtcdTAwMWXWJPe1QZVxTVxmO33i6cH26FNcdTAwMTCXXHUwMDEyfH1cdTAwMDNTm7E8x6S05MZcdNVcdTAwMTY+36a3XHUwMDBm7pqBX0D4UM8y8iRcdTAwMGIwnJGnwj2S5aRcdTAwMDO3S1x1MDAxMTIoqiZgrz70Q/Tk8SSYLYeKOZ2WgrCIXHIsTSs2wNU6Utw8i0hcdTAwMDNfXGanLJRJXHUwMDFl7i1hkpriXHUwMDEwhykmIIFcdTAwMWVRpapijHEsL1x1MDAwM3T42u2NWYszTD7Cf2pcdTAwMTB1eKlgkltcdTAwMDcq7qHCXHUwMDAw5Vx1MDAwNntD9Fx1MDAwMsDvyNxcdTAwMWUrOELqXHUwMDA08D20XHUwMDE32I2rJ2f0UZ7Fx1xi0DyT26mPMtGwWlx1MDAwMlx1MDAwMOVcdTAwMDFpXHLE8aEx8Vx1MDAwM6M00qbwKIOh9eO9XHUwMDE462/cbKVcdTAwMDF8XHUwMDEwX1x1MDAwMFx0JPfgbbmYKbL7wWmjqHJcdTAwMWVcdTAwMGa3Vlx1MDAxY2g/VFx1MDAxZVx1MDAxMTZcdTAwMWUqXHUwMDEwVybSXHUwMDAwbohZgNpcdTAwMWFevta6wCvyzTSEofl+i0qxLELhXHUwMDEwemhGb/W1paQpKo9cdTAwMGVcdTAwMWSwWUVcdTAwMTlcdTAwMTJxXHUwMDFllpfvXHUwMDA2Mu1cXKslZFFcYtZJNOFuTUJcdTAwMDNAoliaxNDIQZnqy/uwOESgjFW0xcMwiVx1MDAwNlx1MDAwN9BthHnMh5v62JGM1kjjpYFcdTAwMTOJUibCYFxiglx1MDAxYS4lg7eHXHUwMDE1xm2K6Fx1MDAxOdbkqe4yP1x1MDAwMb6C0Fx1MDAwNea4XHUwMDA1iztrxTGyXHUwMDAwXHUwMDEwk/A7llx1MDAwYpZcdTAwMWVC4HZcdTAwMThcdTAwMWM0vk9wy6veUlx1MDAwM6ivYlx1MDAwZVx1MDAxNuZFz132cYx7gFx1MDAxOCzohJurxWpYKlx1MDAxYupccmJMq7mhWXIjXHUwMDFltFx1MDAxZHdBedBOpvbrNUQzJoRZwbDJaErIilx1MDAwMFTle7CaXHUwMDAxcn1eXHUwMDBi0THuLpZcdTAwMDRWXHUwMDAynXLl6Fx1MDAxZNExhzIgorVcdTAwMDakvT481syDXHRWXHUwMDE3R3C6WFJcdTAwMTGE7vqKkkpmVWXt2phYXGLkS4jfXHUwMDExoYs0sVx1MDAwMOJcblx1MDAwMlx1MDAwMZ9Ekl1725hF4f5cdTAwMWHrTVx1MDAxMFxyXHUwMDA2n0hzJjiQeabbXHUwMDFhXHUwMDE0ks5YXHUwMDFh9/BB/Fx1MDAxNZFcdTAwMDb8XiXSeCsl6Fx1MDAxZWhcdTAwMTRoS+2NM1wi80x7+jz35ZI9JFx1MDAwN8tzXGZcblxmbyz8Uq04XHIsXHUwMDAxmLJoJb+iNNOWx1x1MDAxMMI0KCeHKJhcdTAwMDLrXGYjqZpKRVnW0stAJlx1MDAxN+pcdTAwMDGVXHUwMDE5SuCSXHUwMDA1XHUwMDA1p1x1MDAwZYvytvQvXHUwMDE3XHUwMDA3fedcdTAwMWNccs/dMGjpWIJX4msgXHROSdZcdTAwMDfDTLdHxdS390B2OZZ+xrKAztrCbdZXXGIw2W5YI4onoZiPSVx1MDAxNFx1MDAwZV/Apm3m7HyoX1x1MDAxYp2IZ+140PSLZfWFL81pLMgg7ka9XHUwMDBmydeGy1x1MDAwMJFHnJQk2iGNdUm4Wmqcrt+Bwn1cdTAwMDP/0YjSYavOeZ/u8UBcdTAwMWZcdTAwMWSLt5muqFx1MDAwN9R8i4e7/1x1MDAxMXbFXHUwMDFhmUSaYizBwi4w9PqwxpiMm5BUXHUwMDEyVn25sf0nQSZcclx1MDAwNIL/rVx1MDAwZmpmLE3mVSc690vwIWVcdTAwMTVhW1x1MDAwMJw89NDafLOhgYtD/MZ0XHUwMDAzozfuviTypNB581x1MDAxMFleaFx1MDAwMFx1MDAwZTbz8LFwSIF9LnFsn1x1MDAxMpxC54XfoI71NVx1MDAxZtyVZVx1MDAwMZ3MXHUwMDFkt4sxXHUwMDEx5/LaXHUwMDA3eHz4+npcdTAwMTI3c2m80YI1XHUwMDFh2lxuX9I5bkArJtVwrcxH1NeT5cUysFTuJ1xiJVxuLdO5PLhcdTAwMTJ+XHUwMDExgFdcdTAwMDE/6tvSNMh5tFx1MDAxZa5cIlxuJtpLmM+lc4tQOFx1MDAxMFx1MDAxNZZC1a5OXHUwMDAx7UBcdTAwMTO4Wexd3lx1MDAxOPdH+V1E91x1MDAxYVx1MDAwYlx1MDAwN3xFUJx6glx1MDAxM0mv4MtcdTAwMTCOgk7bsUYycu3AjCpcXEqj/pZZitOMITWR01x1MDAxM4rT4lx1MDAxMdww9lx1MDAxOXlcdTAwMTh0aNBdRVJcIliG7TSzXHUwMDA25c4llrZ43lrgRED422BxLmNIXHUwMDFluMMr2HRQXHUwMDEyp8gxYPt5vZqo93Xas8eN+zlcZl7KW+0qL2JcdTAwMTWIxFx1MDAxMEaTXGLXX+pspYXMKepcdTAwMTWLbq0oM01mjYOXrDS0rOSpT85BXHUwMDFjN1x1MDAxZaVcblx1MDAwNGOp0novy5wm2JQyilx1MDAwMUaDa5VAKehcdTAwMTPiXHUwMDExkP60XHUwMDFhjVx1MDAxMUpkJihcdTAwMTgmhJo8Vu5jSoRy0clUmmGRoZLQb1x1MDAxYlx1MDAxYVg/4o38vuRpMmC2ScRpptdcZv/1TUJ9cP7I+kJcdDuCXHUwMDE1OZncOkH1NVxmWFx1MDAxMFx1MDAxYdSvXHUwMDBlXHUwMDExhFx1MDAwN+jg2eJ/MZZBh09cdTAwMDKPXHTPgoVHrGZ+cHlggSxcdTAwMWJcdTAwMDJYXHUwMDE4WKZcdTAwMGJjlXzMenLXWcJN1Get8zpSmCtcXDGCdJVUoLCOXHUwMDE0z4kpO1x1MDAwNty6QfpcdTAwMDDkiVxyWoJ4XHUwMDEwOLY5kVx1MDAxN1xyXFxA4IxGVuTUirOMXHUwMDE14L2xNsVcXKlLXHUwMDFjXHUwMDE0d3yh5DJcdTAwMDZcdTAwMTb61T7emctjLVx1MDAxZoyJmWTWXHUwMDEzlsNcdTAwMTM+XHUwMDBlmj/eQlxmXHUwMDBmx1gnToLUIHJGSGfpxWU5XHUwMDBiXHUwMDA221BMgJtcdTAwMTjyjel6bWHhgFx1MDAwM/TAosiQyil1XHSkhVx1MDAxYrCsXSCo17N2lSHQ4WhRuHhcdTAwMWJcdTAwMTBHlz1cdTAwMDE7hnDPgD1KXHUwMDAx3GX93Vx1MDAwM1xccVx1MDAxYSfsM2CBopxSz+v84WHhW9hcdTAwMDLQoOiYjVxijJtcZuvuXHUwMDEwcpWjWDZcIsDFssNcdTAwMWG0ko199fLyvl5usjumR8pcdTAwMTVBXHUwMDE5t11sblx1MDAxZLFcdTAwMDFccsjg6ywzI1B778q7XHUwMDExuHP4JqtA/cjHXFx9MVCNOPpcdTAwMWLgnGfjXHUwMDA1XHUwMDFlyEOLk1xmLpmoZVxyNcL/cnKNXHUwMDA1lZ7DO0lBQe5cdTAwMWJtvrDaXHUwMDE4y4BcdTAwMGJSXHUwMDFj4SrLXHUwMDAyXHUwMDA1S1x1MDAwYulcdTAwMTKV58xLVb89eT/NhnLKXFxeXHUwMDA0UVx1MDAxMfGRrmw2fNW82fDZ5esvvuNfX7zVne72kjrbXSmMrprr6S3sRIWxsOTSy8LAxuuhpfB+itliJl7dlHGOd1x1MDAxOd6CgNuFfGdcdTAwMDJRYKHxczS7XHUwMDA1n4CPQyBcdTAwMDN2XHUwMDA0XHUwMDA1LrQ+Xo9uyfmJVLF6ov2NKv3TdjjHbYeLrFx1MDAxOYPjzuf4sIa0nHn+sfcuOHtcdTAwMTSMt0GXXHUwMDAwXHUwMDA0UqdcdTAwMDVJXHUwMDE0XHUwMDA3XHUwMDA3XHUwMDFhN0VgkzK0mVx1MDAwYkSQw2G70rI2gcW2JXmp2teKY8aC0ZR1+b5GOSMobV7MQjyzXCJPXHUwMDFi18qbZJr8Ycmbx2NQYEaekydcdTAwMWGUyc1YXFy+hcNwic1cdTAwMDVM55YhUlwi4GZdoOODqk+4s8fRg8ixSipcdTAwMWYkmfSxskaJ47/ZjSXAR1x1MDAxYmiLXHUwMDEw1GhGpIGTL0JcdTAwMTJqcLSmXHUwMDAyMcfrbM4xtr1Yn/m5L5Q06cujyYWCNVx1MDAwMLpyxNnr5iD5aXX18/vex/W17pH9uvX669fd7tdJg1x1MDAwYudcdTAwMGIkg8zYq5hP45GFTq1cdTAwMWYgaTJcdTAwMTagXHUwMDA0XHUwMDA1XHUwMDBlJFx1MDAwYlx1MDAxYlx1MDAwZbNGScnkXHUwMDA1kU6DW1VcdTAwMWT9QvtcdTAwMDLISMe8MViXXHUwMDFha8/nkFx1MDAxM3YyVVx1MDAwZjP8XHUwMDA3J39cdTAwMDecvN2nQ4Y4XHUwMDE3gSHL69m0Xm68y0j6nGfApI2Q9XVcdTAwMTKT1ZA/nuX3ns8vWEmvXFwnjtG9ZGWFsHmRXnlMXHUwMDEzXHUwMDAxSzhQdCOZRqpcdTAwMGbBZixOZeyGtWzxZu+QKSfZx62t9ubx3rE3IVx1MDAxZraFKNon6+OoXHUwMDFm7ni4XHUwMDEwtGlcdTAwMDBcdTAwMDVcdTAwMTknLlx1MDAwNlx1MDAxNlx1MDAwZlqO9VJpkzqYO1ttbD4ooZaN3Fx1MDAxN7KE9OVcdTAwMWJkXHUwMDExjEfDhFn6b5pDy+rmrvn6+vOGtp+OluS37id3tvjkt4BcdTAwMTbLXHRTLDFQV4N5XHUwMDEyaJE+i8xcdTAwMTMppWRcdTAwMTThnqZn2rz3w1x1MDAxYc5cdTAwMDVCLFx1MDAxOCtcdTAwMGVFYoZcdTAwMWFuJJKbka6OXHLYlpHFVsqHfya//L7QXHUwMDAyRs16We3y9Fx1MDAxZTfBi79cdTAwMWUzXHUwMDEzXHUwMDA0XHUwMDAyXHUwMDFmZolBVuv3XHUwMDE1XHUwMDEycaq8h1x1MDAxMjOWxlnH4kvBOpuHXHUwMDE2XHUwMDA3/u1cdTAwMDNrOoBcdTAwMTVcdTAwMWOplKYmXHUwMDAzXHUwMDFierhvpvGXemiMmWPZv2dJl4JcdTAwMWSVM6c6P5RPXHUwMDBi51x1MDAxZI9lqa9GLomL6XZcdTAwMTbE8U3ci1x1MDAwMLtcdTAwMDVcZtSJW2Se3+ZcdTAwMTM5OI3T6HKfTW7fhjlsllPGJr2e9yDQwDRNNNLh0mIod4pcdTAwMDRO61BsXGJUeVx1MDAxNVWt9om8TVx0YbPhTCtcdTAwMTZ1lkd8LF5/wLm8Z1ZAXHUwMDEzYn3a854wcnKOXHUwMDEyioSQw1VcdTAwMGZEW71cdTAwMDVGvjveePP5ZWtz8/Hi8+9cdTAwMTf7K+dcdTAwMDerr39cdTAwMDeM9Fx1MDAwMoYqhY4gYKylTY7c9Hk/XHUwMDFhXHUwMDE0MadWhc3GmWOkYW5HXHRDhjuqQCpjpLHcgGCvNMKs8YOVXGaLzZWy/+Qpf1+QvN2n4dSczqvS8qJqX+b8cGrg+Wz85eF0ur4m32ScocIhwmytUm7M55ZcdTAwMTWw1udcdTAwMDI1OcbV5XtqiGPKXHUwMDE5Q1x1MDAxNjnlI5I584uHc95Wnk1Ry1o2M+Sdfrde3N2Eca8xXGKAi2SXkVx1MDAxNOXkssw8O5LYJyu5l18vTnBSdj58VVx1MDAxOK1t0n+Ap1x1MDAxZbjxasmVRaxcdTAwMWa0meE6eYCN8t7LfHLIXHUwMDFm5bc1Z1x1MDAxZrHVyih2Ts3ldprncEpRXHUwMDFkzq01h6pcdTAwMTft/tn54cbjo+5B72Sw07nsXHUwMDFkfmz9XHUwMDBlUOXYOs5hiDIgmDIm3U5jaVx1MDAwN2sj2X2jw/0kXG4j2yQ4zlx1MDAxYqpEnlRcdTAwMDFUV9rJ3EVgU0DFXHTRtLtYrIj/XHUwMDA3p347nDKsXHUwMDBlj9zP51x1MDAwNDtdLlxcWZRsjlGMRljXzZGN7cX6KjZcdTAwMGaqpVwieFx1MDAxMOvhRdJSw7oquCjFYyU5Rak+Icbmflx1MDAxZpyAweRcdTAwMDfyJMlE1iFIjn9iPU89NqpMau6j5EOruJFUXHUwMDAyx1TpXHUwMDFi7C9lPnCkZMxLgJk7nLa8JiMqYZDshOFQMjbB+Sl371x1MDAxN41mloXJvWNn3Vh6XHUwMDE2U3m663pz7270MFx1MDAxY27CcHdfPH63Ozy+aPm132RcdTAwMWYoXHUwMDFmKs5yb8fAcZSNu/LumqNcdTAwMDRcdTAwMTDbO5OnoF2ysJntXHUwMDAzsVWd1fdQZPCYqkDEsa9JxjzrXHUwMDFizHhcdTAwMWOCxctcdTAwMTBcbvnsf9z7b+feb/lpjmLg+Dbqr2IvTdn3XHUwMDA0zYpEnmZlnY9NoEBygms+TY9EVyZcdTAwMDdcdTAwMDBkTNPQa1xubs83aNacrTRcdTAwMWVcdTAwMThcdTAwMDJcdTAwMDfLrkOofzJcdTAwMDBcdTAwMGbW4XFcdTAwMDOiifwuXb9tIziLkMNCY35kQLlcdFxm78LKNOdCRkWcrZVcdTAwMDdcdTAwMTDlXHUwMDEzIFSxiMSliUJm9VwiXHUwMDBm0maJZYPTNdgwxD4wXHUwMDFlXHUwMDE1wHCoLC/1XHUwMDA1XHJgSrClXHUwMDA0IUaQnlx1MDAxYlEpyHOriWc1WFblN5lQM2uBnPCDp6HyLU3FrvLSXHUwMDE1ZznCe46ZwFOz9WUzafDlQrlcdTAwMTVU5Fx1MDAxNeuKYSZHWtkmLSv3XHUwMDA1z5NPTpDgIJqLq8Lnt83x2YeLuNzuPIlftlx1MDAwZd7KtaXPvc9rj39cdTAwMGJ8djajXCLBj1x1MDAwNVuc8TnCZ4b/7OKmSdxbNSPno/OgnXymXuFkwFwiPlx1MDAxYsnJimzyjtH48YJGnr/AXHUwMDE2qbqz6P5B6L9cbkLDqTnFydzGQHVjud1QwoU6r1x1MDAxNZxk3vNRv1GhOPdUXCLG4Fx1MDAxOCxWeCQ+V/LgXHUwMDE5rzjsT9anp+qkQVhQgFS2QKhcdTAwMDZcdTAwMWVXZ8pwzoNwxubEI4GsxDxcdTAwMWVcXFx1MDAxZVx1MDAxYlx1MDAwNDnUiHNcdTAwMWY5oaBcXFjBmWpcdTAwMDbMm7PhXHUwMDExcjZcdTAwMThGzlx1MDAwMTm45YxcdTAwMTiVZpdXeTw3O2Asp/kjXHUwMDA0ZFdPvcB8bI1nXHUwMDBmIzNyKohcdTAwMTSwisX5nEf2i0RcbnZcdTAwMWJIoiZwn5H+WFqzKFx1MDAxNE/vl1x1MDAwMWtMX/5cdTAwMDGs4GHQfMB/XHUwMDE1rr5rjqvdzeHG6YuzXHUwMDBmbm+4bE9f2W3z9N3lb4GrPJeIdc+GZU7OpfWPnJFAospcdTAwMDJ8uIB7int9PrWa8zhcdTAwMDPrVFxcXHUwMDE1rrJbgVWYnDfjWOY1XHUwMDFl+EaeXG4m/slr/n1gVVx1MDAxMecsXHUwMDA3nyDYKoW9guOyI/vkOW7cxFx1MDAwNn33iqGghSVcdTAwMDQ2kKtynCqJQlx1MDAxMX6O4/1BxeuHxPFgRE7aQeiDQDDq8i5SXCKvwTF6kYM1NCdOXHUwMDAzvZLeQs2hblxiU3mEnuTQ4jphLuPwKot7h3WxzqMkznCGb2QzXHUwMDAxR/fUt47PVlx1MDAxYfPXkulcXIZkXHUwMDFj219cdTAwMWUnNu5cdGpcdTAwMDVcdTAwMDZcdTAwMWVQYVx1MDAxME5Kjlx1MDAwMZMuPUCIU3M4v5Rn2ZhcdTAwMDbdXHUwMDA0Mp9cYsUmStaYXHUwMDEw2pNHy2NcdTAwMTKiQFTijGsytHjWXHUwMDAyr8GXqVx1MDAxMPaq4NKThlx1MDAwN+E9z1xmjJyBwNn6tXh/J2hcdTAwMWW094ZX+FOBz4WjNFN45jhcdTAwMWb2XGZV1sdsNIfnb2eby0ut1feLT1x1MDAwZbcv11eevFh9sSTn+8BAuFxylVx1MDAxZv9cdTAwMWPY0ClEWlx1MDAxOZOPu+dcdTAwMTa1tTxT0CZcdTAwMGIrXHUwMDAwc5v/TFx1MDAwN+aW3Vx1MDAwZlWHXHUwMDA2aiF5XHUwMDFhh8uHl/NojXFcXLZUXeZXTLz6XHUwMDE5XHUwMDBid5nzo3uuXHUwMDBld29cdTAwMDW4/73Ru1x1MDAxZqr1I6H052RcdTAwMWO++Z3/XHUwMDE2NPhaMZ7sv9XPPmxcdTAwMWW+XFzuvDxZ7j7dk91cdTAwMWT/qKjqNzrcXCJcdTAwMDA+unnnzz+myV1ZP39+XHUwMDFlP7/8uipPn7WeXXRPn75avpPcXHUwMDFmXHUwMDFmXHUwMDFmts+HZUFX3/jx7UXn/Mh8PJHfnlx1MDAxZr7a9vJC6fWC2DF+M0ZKeMLHKHXcgJRMNfnSOlx1MDAwYtZegNXxknFcclx1MDAwMIbrl1Xmvtnc3KvvRbW5XHUwMDFmtfaOzlx1MDAwNu05MHgjXGaAyOm8078wROja4J3IXHUwMDE0Jzw4XHUwMDFl6jPV4Fx1MDAxYlx1MDAxZFx1MDAxMdrei7GCiUefcXhcdTAwMDHHIEZuRY1cdTAwMWK8sqmFa8TmXHUwMDFjwlrdeDTvjPqg31x1MDAxYm50LvlAlCi9+qx13Ony5o+uONdq2ndv2Fx1MDAxZfBLXHUwMDE2XHUwMDFlr68sbLRcdTAwMDdQ5UelTz3udlx1MDAwZXt5uNfmZ0umMOzstbo3XHUwMDFmOO7s71x1MDAxN5FxXHUwMDBmX91CLDtYaYJd/UHnsNNrdTdcdTAwMWKtrHU27L9rn15d7nBw1i7esfaLm2AruyZBP1x1MDAwN+iFZvLUxFx1MDAxMWpcbs4mrkxkv79cdTAwMDWih297345cdTAwMDavetvq07fDXHUwMDEwN+3up1x1MDAxN/OO6CbkXHUwMDAz+zlfc1x1MDAxY9FDPo7Qa3b4grj5KSnsX4zonFx1MDAwZodIY0Kj4a9cdTAwMDX0h1x1MDAwN97hwaZXXHUwMDE3x2+Gr9pLe+L1ivy0eLTUlCc8jlu9nUUnV15e7Fx1MDAwZbaWjlx1MDAwZd7uf1xcbbbcJoDuXHUwMDExXHLeN6BbMbm7mIdW5FFLlbVvNbf26ns894DOaXM8XHUwMDE2L1x1MDAwMrGVTFx1MDAwMD1YRqVcdTAwMWOcznNCptr7XVx1MDAwMJ1TXCI5XHUwMDBlM0BcdTAwMWRsYTLMNEA3PE9cdTAwMDEk41dcdTAwMDI654RcdTAwMTdSefdccujrg/63zn57sHDSPVx1MDAwM57eXHUwMDE3lk9HrVx1MDAxNMsnLmpWML7faVx1MDAxZPd7+1VmbcK0YjFcdTAwMGVcdTAwMWPU1Wb9oblZv3p89jp8Xn+1/aLvdlePdnaXvu5Mqlx1MDAxNptcdTAwMTNcdTAwMTCHXHRcdTAwMDE/NUdcdTAwMWZx/q5O9qGD4lxmbVx1MDAxZrldNZ2lq4PYNma6Ue+qXHUwMDAztbtbYdTBZJpHm+hrjFx1MDAxZXngkVVLm1lrWKaemnc+Vl+bqO9cdTAwMDXAf1x1MDAxNPDcXHUwMDFhwOuA9nJ7uL6+tvHa7Vx1MDAxZD6LavHL2lHncWhcbrRG9LbWX/a2T+LhUMmLlcvBq92GvKBcdTAwMDHQcqLnvUfOxZFcdTAwMGapRTqhjOExQlVcdTAwMTb5sblFVt/jOVx1MDAwN1rH6eyeh2yIwFx1MDAxNvuUWEfLijHrefzAnW1yXHUwMDEy0HqbsUuNNUs8vLbKJCssUVtcdTAwMWXBU7TRv3zovN7fX+j3XHUwMDE2/tP71lx1MDAxOVxmz1pd/K3X32/fXHUwMDEz4tZAzFx1MDAxOOJeLe7H0spcdTAwMGKbXHUwMDE16l45mFxuXHUwMDBij2LiOFx1MDAwNe5dWFx1MDAwZausMvBPtyjQnupcdTAwMDfn1MC9kjzeRlracFx1MDAwNeg6MGnYtVxus1x1MDAwMN2JXHUwMDA2zqFT1lx1MDAwN6kqpvPwODQtx5k0S1M8nIGq3pS+f6idaveuOFx1MDAxNPDnN6FcdTAwMGJcdTAwMGJrX311XHUwMDEz28s9xd5cdTAwMTlXyVpcdTAwMTIrjeeJVXDkjoe6XHUwMDE1tvxcdTAwMWVcdTAwMWS2TvhcdTAwMDAyXHUwMDBlQlx1MDAxMdbmXHKQoTjHXHUwMDFjente3thcdTAwMWW7M6XN8UkrPtjuPl/flFsrZ1tvVj9cdTAwMGXkpTBv21UrXHUwMDE2WeDZ4OCAQbNJv1hyfb1cXJ1cdTAwMDVOjLvOs4jiKTBccpY741x1MDAxZPvU58x0077CMviz+MMoRr8/RqXa3d3+94a8aKLblKqwYzA+hiZGLaSu3FPYbu44p+9cdTAwMTTNqePkyLJMXHUwMDE4nunjI1x1MDAwZqxcdTAwMWGJufacPIdQhFx1MDAxOJRj8czk/vq7eE7Fk69cdTAwMWTP0OXIXHUwMDBigFxcRVtL0Dz9XCJKXHUwMDFl0aVD4ajOXHUwMDFmntRLizjnnnZcdTAwMTHn3JGePn239aE92L1cXDp42Wpccndar5bWNqrdkmNLINM9+UkqRYO8dkuGXHUwMDA3McIsXHJwUkhXXHUwMDFhWzgrNzp9y6K0Xk5j1KxnMYrTp8e9vmJcbi0yjM3T1aXCl/vxo6mjeUhXOtlU+LM4ZiX371r9xJbwaFx1MDAwMpspbCUlbTX3rNNT9vPqWa2ImXXQSqgtz3lcdTAwMWRcdTAwMTG8K8/KwZGS53iImvqMO3nWTPGEVGZro+FhkuOOXHUwMDE1sbE1kocr8cxcdTAwMDbtx4NQXHUwMDA3/DSziUFn7Vl/Plx03NCzroWN3U9f3698XFxvvTk+2Vx1MDAxYrqT5fCiylMxqFx1MDAwMzO1UVx1MDAwNcHaND/uWSWPQlVwZIpHfUVZPIZtZp51alx1MDAwMrnkWVx1MDAwNYe2uXyghIpQgDi2YJPhyXPW/u0g4Heiplx1MDAxM1xyhD/jpjEjdzqx9sVP7PBiSp1cdTAwMDOIKp3pbnNnumaGw8fvPj7dWJXv1zaXulx1MDAxNzsvzt7MuzNcci7m4ywjjzDhdLCyL1x1MDAwNafJNNN78l5LX5yDx5YsXHUwMDE0hrLwdOJcbmc65jxcdTAwMDPIi1My/v5cdLxQenVKXHUwMDAyb+s6ObZ6h6zdsH8yKWVXWnean6v+7lkl5ibZrdNcdTAwMTNcdTAwMGJaXCKslmcqVpntXnOzPX1x/q2155Zff97zy+2lleVcdTAwMTX7+tm8m62UNlx1MDAxZp7tXGLUUlx1MDAxNKdcdTAwMDddV7T4LCqdXHUwMDBm7eWJcZNn4tyFXHUwMDAzSVx1MDAxMzNcdTAwMTVtXHUwMDBlcTz7p8DERptho4Vf221+tJdcdTAwMTFcdTAwMTN6MH8ju1x1MDAxZLXr1dntxsaLhferK1x1MDAxZlx1MDAxNzbWll4tbz606U78+vu2Xq0nZ4dcIqd88SDxKvvdv1x1MDAwNexO5ZHzar+WJ1XzXHUwMDAwXG5cdTAwMDZyxUNcdTAwMDCuzFx1MDAxN4RWXHUwMDFiXHUwMDFl3FBcdTAwMDe7dzHffO5Kflx1MDAxNlx1MDAxZs9rNFUjT8atV/KwZfaF3Lv53jDC2daajdHLX+1cdTAwMWPOep3zhVNcblx1MDAxYz60Y6j86oeocIlcIn31XHUwMDA21Vx1MDAxNc/LUqGSjbebu4WLwbu9/vOl81dq7WD1yfOnT95ePt+ee7dcdTAwMTCi5yHxWoFcdTAwMDOLdDdcdTAwMWRRMFx1MDAwZsqR7Gibvpt+IMKeXHUwMDEwP5nY4JGaSXBarG1hf5OV1lXsuLGPVatiWup3KG55/+3bZst9cFx1MDAwN1x1MDAxZt/tvPz+/FX3YnfTNC1uef763U7/cNA53926XFxZ3nizv/lhW/0yR/RzIFx1MDAxZCbnXHUwMDE5RVByUo/2QXNjrL7F826M0dmMLZ9Rq6uirbI5Olx1MDAxZZCez9OOwND7MkcpQFx1MDAxNHzk6bGcXHUwMDBlIKs4tlx1MDAxZEdpxcPOpbh/lJ6r6pb/9JZ+gN/pPVW11OBKRVVL9aJmhbLtbrdzclrZXGZi3USUXHUwMDA1sfQ8kKt6qtFhc8vePn6sLr7smFx1MDAwZi831Prxent1aWdz0vjzOakj5UCnTEhcdTAwMGXlsN6OgSyMXiBEhfbiXHUwMDEz02rD72TV2mSs462saDFO8qxdV4Wxxlx1MDAxOVx1MDAxMU10v2ov9ucg9uNJZ+n9Tu/l8f6X9+bbxc7J+atcdTAwMWT5XHUwMDAwjVx1MDAxYX916DZhooXz1F8/XHS6j5pcdTAwMWJ49aObd+j2XmdcdTAwMWONXHUwMDAz+1x1MDAwZaJ4yu91R6dcdTAwMTeZi5wmrXmC95SZZU2MfFLDl1x1MDAwYlx1MDAxObmBsY7t4pV1qePIrVx1MDAxNI+A8X+njs4nnMfzn97GxemwfXxPsF2DUylsT1jSvZehOjE5YeZDVFFcdTAwMTX7iFxuXHUwMDE23Wlu0dP96bxatLM289yp0lx1MDAxY1x1MDAxZVacS3GVMfMq46BcdTAwMGUpgOq2OM9xplx1MDAxOTOVRW1kkPAgweiqIYTaZkpFg5XyPC9cdTAwMTHGzopk/ixcdTAwMWZI93fc9L/FJrrnXGJSydM9gmGJY+FDV3voNjNS6nwupeaMU1dcdTAwMTQzmz3/6V6jsNy8jJYnuFx1MDAxOZBLxfGpxakvN2WpoJxcbkvVUGJbXHUwMDFlf/dcdTAwMTfb/J9oKPxZXHUwMDFjs5GRuDFmNZNaquJU0jG3aj1cdTAwMGZcdTAwMDGs3Eb83NyrTmeT8+pVXHUwMDAzXHUwMDFllMDzXHSeXHUwMDA36aixXHUwMDE5dFxihoxlxTc7eEJMXHUwMDE2Nlx1MDAxYqfqYOvGXHUwMDA2qVx1MDAwM7tkQciq9iF85oyHc4I/gFx1MDAwNVx1MDAxNY9cdTAwMDBcdTAwMTmdreGgcH/PKtXGfoojmbXkgVxi0nrB+FNcdTAwMTSmRl/7qXy8kfA8X4ddjFHfQ53q9DRK2bMqyYNYXHUwMDExiqvIXHUwMDAzIeT4iiW0OFx1MDAxZu1cclxyiFx1MDAwNu7X3GrFv5NnnWwt/FlcdTAwMWM3lFx1MDAxOfnWqWNH7OQ5Ylx1MDAxY1LKXHUwMDAx2pXbvN1blGlMLcSeU//qY4QtgbpysDrZSkJadci0YnVj1L5Y6TJvY0dgWFx1MDAxMDBfU8Tqck7761x1MDAxZs2q8rtvn5++uny69Xn96dPBt6a5oftcdTAwMWFONry43P56pndXL/ovbFhdWXx7fDyzoSNcdTAwMGaTc1J+ysHTXHUwMDE27Ffo6ilix82NvfrZzbmxR1x1MDAxOFx1MDAxYU9KUlx1MDAxNubmtU1LsmBlgafCXHUwMDBiXHUwMDE3plx1MDAxYvtcdTAwMWQqKeFvOIxbKcOuTGmrqNT4vi1blFx1MDAwMsKov1HOiSVRrUOs657yTTVwVVWhlSznrrmmJlx1MDAwZWdS5JSrs+GQXHUwMDFjXHUwMDA3XHUwMDAyyCnixSNcdTAwMTOuQoPoM+CW5NhojVx1MDAwMC+O6aLIjNLsb1x1MDAxMDpP2PhQkVx1MDAwMNU+XHUwMDBignvMwinlfXGCwLiVzVwi6vjVvuNWllXwnr1HlfbWJFT5kVlcdTAwMTY8XytGPTaSPfdcblPqbNlcdTAwMWVcXMxIT3bfqcWXrqY6LtJFvW5q8zOl1ItTNJU/4zo6hVM3jCVm2lx1MDAxMFxyVlx1MDAxN33keeZcdTAwMWW8PzppxztO7qFlu3FvZH5cdTAwMTKQ14xcdTAwMDRcdTAwMDLucjRKqfF8nsr81XQ+UFxiXHUwMDAzvnzLsPNOIdpMWkwmj5CQzFxyOqB/Ze6+35xcdTAwMTi9e7qzXHUwMDExNs3jo6VccnHUVp8/dva77+fHuU3oMdEx0/A9Klx1MDAwNJ7QKJLNuCBcdTAwMDJcdTAwMDfGa1x1MDAxN1x1MDAxY0fGXHUwMDE3SlZ+ebGrVuCyzD787sTob1SN+q9rb/yodXKyMcS9vPFgj7512t+fVOpcZn9cdTAwMThr5TZPM2rn4Prnv/78P1x1MDAwZn2PiyJ9 + + + + + LOGIN NODE ON RESOURCE PROVIDER3. No INBOUND connectivity to the HPCVirtual KubeletInterlink API ServerProvider pluginPod on virtual nodeVirtual NodeSSH UNIX SOCKETunix socketPodContainersBatchSystemSSH agentunix socket \ No newline at end of file diff --git a/docs/static/img/scenario-3_light.svg b/docs/static/img/scenario-3_light.svg new file mode 100644 index 00000000..64a87249 --- /dev/null +++ b/docs/static/img/scenario-3_light.svg @@ -0,0 +1,13 @@ + + + eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO19bVtcdTAwMTPZ0vX38yu4fL5cdTAwMGV97/eX801cdTAwMTFcdTAwMTVfXHUwMDAwXHUwMDA1UXnOfXFcdTAwMDVcYlx1MDAxMFxyXHSGoMC55r/fazVIunc66UZcdTAwMDLGmWHOeJwkVHZ3V9VaVbuq9n//tbDwaHhx0n7074VH7fO9VrezP2h9f/RcdTAwMDdf/9ZcdTAwMWWcdvo9vKXy/z7tn1xy9vJPXHUwMDFlXHKHJ6f//p//aZ2cZKPfyvb6x1e/2e62j9u94Sk++//x31x1MDAwYlx1MDAwYv/N/yx816C9N2z1XHUwMDBlu+38XHUwMDE38rdGX2eCSF9d7ffyr9ZeSK1kiDdcdTAwMWbo9Pbb51x1MDAxNLkrn4yEdU6fYlx1MDAxMcP2Pt45aHVP26N3+NKjy8vn60cni8+fq/bX3eXtXHUwMDBmS4+3RXf061x1MDAwN51ud2N40c3XetrH9Y3eO1x1MDAxZFx1MDAwZfpf2lx1MDAxZjr7wyO8K5PXJ/3WoH92eNRrn56Wfqd/0trrXGYv+JpcdTAwMThd89WN+ffC6Fx1MDAxNV6g1EJmJiqpXFxQVpubN/Nfd0FmXG43x0vhoo9eJeta6nf7XHUwMDAzruv/XHUwMDFkiLAnxGhlu629L4dYXm+/8JmD9l6Mo898v75aI1xcJqxxwdub947ancOjIbXEh8xpXHUwMDE1pLJcIv9xozW08ychI17VVsnR4+M3n6zs56ryv6P7P2hcdTAwMWS3V/grvbNut3hcdTAwMTN7+9c38YdKjZRKX7/y5+jS+PnlVFx1MDAxOYtcbllSymH7fHhzzVx1MDAwNWVx51x1MDAxNyefzOKJOP9uV97IXHUwMDBmu+77jnh087k/r/82Wv7ZyX7rSvekV8467ZzVcvRIup3el/Tauv29LyN1/VfhQsaMp7TOgt3oKCfZjbfQmmhcXKXdLDW3m+pbUW03R629o7NBe1x1MDAxZSzHeqhttMqE6JyKqem4XHUwMDA3MFx1MDAxZFx1MDAxNU1cdTAwMTZlXGaRqzFFXHUwMDEzuDEgK1KDgeJcYi2NlHe3l9JcdTAwMWJjhjFL3Vx1MDAxZK2q31x1MDAxYm50LvlAlCi9+qx13Ony5o/cSK7UuIGv156vrC6srj1dXlhbXXi3vLH2/t3S8sJ/euvv1rZWni6/e1T6lcfdziF1/9FcdTAwMWUupT0omcWwXHUwMDAzaLr5wLB/Mnp3XHUwMDBmi2h1eu3BSlx1MDAxMzjoXHUwMDBmOoedXqu7OX2N4ytsnVxy++/ap1f3YDg4a1x1MDAxN29j+8WPXHUwMDA3XHUwMDBm122nWvxUuMRcdTAwMTOaZPZSSy+E915X2f3T5nZcdTAwMWZfxt7773ZxcP7t4PT8+bMtefbhy3zjpXWAI6uFXHUwMDE23jrATmr12mdOwiV4ay0+Z5OFjSxatvnPdKtv2f1wcDBu9TaYjN8t3Fx1MDAxNSiOLuXG6o1SmfRcdTAwMTGYamL+M0L2XHUwMDFmXkBcdTAwMWJcdTAwMTiicf5cdTAwMTeh5oNcdTAwMDHbdFZcdTAwMTgnskLp8Vx1MDAxNJ1cdTAwMTGqXHUwMDEy3pabq/nJY3/ycXHt7ZZ9/+JsZWWlfXm425t3ePNcdTAwMWU6XHUwMDE2RYxSiqBdwdbz3/dCZ0A3qJePMVx1MDAwNOvvRdG1iZmMUFx1MDAwNmltXGLKODOu6UrJLFxiXHUwMDAznVx0XllcdTAwMGaNXHUwMDFlI4hBeFx1MDAxZEw0f3lVn8ThTPRcdTAwMTO1XFxL61xcMLZKyZ81V/KLnS9cdTAwMTftJ8f7/c3X3fNXn9c/f758ujXvSm61y6BW0PVglFAyUXLrfWYl3GTUXG5cdTAwMGU1TOZwd/Lm4JFQ8GBMrlx1MDAxMqpcIlxiKuLItU5cdTAwMWJLblx0u/iFJC5IXHUwMDAxs7wriVx1MDAwYqVXp5A4nS2s9lx1MDAxN1ZWn6y9X326XHUwMDAwstWDZ+98w8NeXHUwMDE49lx1MDAxN4ZH7YVcdTAwMTfrS/dA5EpcdTAwMTeUsrZbLupBuJuVXHUwMDEzQzZqjFx1MDAwMqjFSu72vLm9XHUwMDFmbHefr2/KrZWzrTerXHUwMDFmXHUwMDA38lKYt+15t3dcdTAwMWZDpk3QRqsq9uZccqIpXHUwMDFmrFxuQdxcdTAwMWZ7Y8YlXpv6XHUwMDA09mbxiajkXHJ5XHUwMDFirfPa/K2Bv0DoOXqK85DyuNJcZiN6W+sve9sn8XCo5MXK5eDV7ogtlbS4NVx1MDAxOPS/XHUwMDE3clx1MDAxZX9Mk/tk/61+9mHz8OVy5+XJcvfpnuzu+DvJrUvRXFxcZl6ZNy/7Ty63vm9dtrut+PXg4qDpcodcdTAwMTeX21/P9O7qRf+FXHKrK4tvj49Xmy33+m+/nDYoodNXR7QhRlxy6iBHxKLgR17cgjdU3uM59yPBh0xa46VcdTAwMGLMO9qUXHUwMDFj25BcdTAwMTlvnFK1UWD0ck/9XFzuR1x1MDAxYZVpXHUwMDFiwdFcdTAwMDVoryxkmEbceJw3SG013Ir+XHUwMDFiJX+2OoPhWau78Opsl6r4s1xm4bizv1/E2yTbU1x1MDAwM4gpb5i4qFkxXHUwMDA0frrKqKHdKn35xqpcclwiLq2LRLhg1SvNrXr7y9n+6fKrlYtcdTAwMTX35Pmz7feL7U/mdIJV71xy+qeni0et4d7Rr7dsR8qP65eIaYNQIbFs53xcdTAwMTakXHUwMDBlKkTQditCsrDbWbZWbq9tKyxbxcxcdTAwMThcdTAwMWStXHRKel1cdTAwMTX1SmWzKFxcjFx1MDAwZT5cdTAwMTjLKbCIXHUwMDFmli6CxZMs+vCipY9Q/+jr25Xds4/m4Gzn85Otw71n5ycrb1x1MDAwYkD16PGTnVxycfj0eH+19bn3/ltr6/TLsf9cdTAwMDFX8+4xToetwfBcdLS40ztMf6Xd25/wTrd1Olxc6lx1MDAxZlx1MDAxZneGWMZ6v9NcdTAwMWKmn8jlPiZwXHUwMDFmtVtjXHUwMDE3XHLJXHUwMDEz3zuhuPIzXHUwMDE4/W1hpI/5f9z8/X//mMGnXHUwMDE3daa1V1x1MDAwNkZu8P9CRFf6/SxcdTAwMDRcdTAwMWRcdTAwMDNwXHKxro5Gh1qBJsBcXGI00XlcdTAwMDd7XHUwMDE50Vx1MDAwMf4oXHUwMDA1NVx1MDAxNorf5KLQxj20OPBoRDv4tI2MVYUtiTNZXHUwMDEwMTj4u4jvdLpenM4kkNMzXHUwMDAxXHUwMDFlnJemJC5kyjjYI+QpLE/WinNcdTAwMDY+3FwikndcdTAwMWXeRphQXHUwMDE0513mXHUwMDE0t0RcdTAwMTXw3Vhf/yhmL07r4H20MD5cdTAwMTlcXOlig8iEgVwi+Vx1MDAxMIWX3tdL05nQweHhKu6XldZcdTAwMTZ0hlx1MDAxN7UyXGJ4YOWmXpjKXHUwMDEwxVxuXHUwMDBiXHUwMDBmLYMsJFx1MDAxZq+lgVx1MDAxMME7S4vvilrVXHUwMDFihcy0QqylXFzUoHROly5VQu288lFIJbF8p+ovduZcdTAwMDKhW1pGY6TzSjtcdTAwMDBDKFx1MDAwYrSZgMHigqHF1Pd6gSazIbLuweNXjLSpvDK21MnDL+Ch2qCFcdpcbqxhirx6bZm1uJgxeee4SVx1MDAwYlx1MDAxZCzshdzcPXxcdDRZ0HhCrf5plcFcdFx0XHUwMDA3j+JlVGLs6booXHJW7eFHha19XHUwMDE4MFxyg0drJX5ccmbgU9tcYk4gwoCxKWjAw1xus1x1MDAxOa5cdTAwMTHhXGb8XG58sfeJXHUwMDBiMFpcIsjRNsBZ69hAmnBcdTAwMGV3Jmc1iVx1MDAwZqB/gvk7sCY8K+dq11x1MDAwNl9cZlcsXHUwMDAz8Fxmz1x1MDAwMEaU+GJcdTAwMTmhPsAxXHUwMDE5XHUwMDAwJtE+tDioXGL0Q8ODXHUwMDAyT2HlKfIgYFNUXHUwMDExeGo8qFpvbKDCXHUwMDBlrlx1MDAxOF+udVx1MDAxNKosXHUwMDBlcWBkslpyP1x1MDAwZnpea1x1MDAxMSaTeFxieHy4XHUwMDE2Z+GCxmhAXHUwMDEwXHUwMDFhX0VxeGC19j9reYuEl7wkXGJeXHUwMDBm6lx1MDAwMLqtS1wiXHUwMDE3JT9cdTAwMTA0/lx1MDAwNVxuOFx1MDAxMYxuL8ra657Elv5V/P9bXHUwMDA3VHbkPsdcdTAwMDIqXHUwMDA0XHROXHUwMDA34SvTJC+bXHUwMDA3VJsw6v3F02/d9vfOxsfXn7bbS1x1MDAxZk8mXHUwMDA0VHOyVZ6HUrBcdTAwMWJmQLxcdTAwMTd6dFx1MDAwYq5cdTAwMGJk4I2Mcd5cdTAwMDK6XG5cdTAwMDb3kzmSikRrhJlcdTAwMDXto2SJkqrKs0bNfXSEc8ZGLZRcdTAwMWbbJI9cZjzwR/XO4Y1cdTAwMDL9XHUwMDEzXCL9dUIkmcHlXHUwMDAwXHUwMDA28NBcdTAwMDNcYjPig7Ivi9abIFx08IBcbqlroWBcdTAwMTF8wDoh4Vx1MDAxYqFmcOC2xFx1MDAxN6iBXHUwMDAytiC10HiKsUFUUyfQO0BcdTAwMTWLXHUwMDE3dEBoY+++wp9cdTAwMTBcYr5cdTAwMDW0kvhccuVcdTAwMTX+LFxudGDHiMeCXHUwMDE38NtcZkpcdTAwMWHIXHUwMDEzXHUwMDEwpcD3wfpA41xcma/KjKxYk0pDsmkkMETgvVLc3VxyXHUwMDA2fqjM4TLwTlxyXHUwMDAwXHUwMDAyTWKRQ320pLKIO8iomvlcdTAwMWFcdTAwMWJKSiNxXHUwMDBigfRcIoRohMDdqFx1MDAwN8BZy/NZ4KNcdTAwMTBcdTAwMDBnXHUwMDE3XHUwMDE4XHUwMDBil+QhXHUwMDFh0NQ/iPRcdTAwMDLutj5cdTAwMDTDLfL0rFx1MDAxZWE4eFFU5Vx1MDAwNTrCMzhcdTAwMWW+XHUwMDBi3Fx1MDAxMSBdL9BniP/wMPhcdTAwMTiFd6okj7F1jKBfmrteIFx1MDAxM/U3UGZgXHUwMDBmwFx1MDAxZETrXGK2VElcdTAwMWXehLZ7r4LBXHUwMDA3wIRcdTAwMWJcdTAwMThcdTAwMWRiXHUwMDEykFx1MDAxMG3xcU8jKF0wXHUwMDE4XHUwMDFkiLXDJ1x1MDAxMEVcdTAwMDBydFx1MDAwM1x1MDAxNXSZwbNQXGZl+EfJRFx1MDAxNOgo+KHQUD7J51xcXHUwMDFmxc5cXF5cdTAwMDBdXHUwMDBm4GA64FFcdTAwMDKnVVwiXHUwMDEwwC2F0Vwi0DZr2T+DYqhcdTAwMWbjXHUwMDBmUGjvbDlqV4gmPG4uXCJcdTAwMDOFr/T1wcmiRqhDM4BcdTAwMDJGXHR3bVx1MDAxMo2xsFx1MDAxMCmJil5HX6+B2mRQWaGE8FaC3uhEnlx1MDAxNKz1xcOl4tcrzKzFIei1XHUwMDE290g6PFx1MDAwZa+SmNgjXHUwMDA0iJFcdGvexPrwaVFzXHUwMDA1gVVT0cDXxXR5XHUwMDAwo1x1MDAwMN9cdTAwMDNTc/iuXHUwMDA2OY+QcUddXHUwMDAzOlx1MDAwMZ/W6PTpXHUwMDA2MD3JeMhCaerFeWbAYVDMnyCAXHUwMDFhXHUwMDBieOCZXHUwMDExROq8Oq2Bw2ehXHUwMDBm9Fx1MDAxOEBcdTAwMDbzxDWliUXoXHUwMDEx4lx1MDAxM1x1MDAxZlx1MDAxOFx1MDAwMcZ6dz9rcXBcdTAwMWbG4lJcdTAwMTFLwHeU80WKhXjBwynCu+CJNFx1MDAxMCcyXHUwMDFiXHUwMDAzI1U4P1x1MDAxNs6VxDlEunlcbtVcdTAwMDdcdTAwMGadaZBvgzxcdTAwMTa6M/eKJ4FfS1x1MDAxM59cdTAwMDY6JF1EXHUwMDEwqlx1MDAxNOhDvW+JmWSFLPiEsFx1MDAwZYFyeYUxw8t4tHmyhrmZh1x1MDAxN8hcdTAwMWOPguo5QU5hy85cdTAwMGaPK2pNeFx1MDAwMWuLXHKSXHUwMDE1fMDAXCKmN5l3h1x1MDAwZi6KM4L1IGA2XGZjXHUwMDAxxFxyXGJcdTAwMTa8gYD/XGLe0cGIUd1/Ls8zWUDeolx1MDAwNYvKmulfwPUqiWBcclx1MDAwZrP0fK1cdTAwMDY9jHjV4lx1MDAxZlxyntDgcm2Gm+Ng6HhcdTAwMTJgXHUwMDAyLpFcdTAwMTdhs6BcZvQtokk+dcbiYFx1MDAwMXBtXHUwMDAwf3g2k2wyWJuxqlx1MDAwMY9cdTAwMWPGgaC7XlWMxOpIdWDweHwuXHUwMDE1XHUwMDA3h8dMtcuTZVxydlRcZohcdTAwMTCYs7HQVZ+kUqzD6kjVvJOs2mywo4Lr4W4mXFyyw0LKrlx1MDAwNeK0XHUwMDA0P8M78FhBN1x1MDAxMlx1MDAwNzWJoFx1MDAxOUBybibMlziXkbND61x1MDAwM7ii9Kk4ZttcXFx1MDAwNFxmwZuJXHUwMDA2Zlx1MDAwYktcdTAwMDJcdTAwMGV6XHUwMDFiXHUwMDE1KUlIlueheFx1MDAwNm7bgTZLqVx1MDAxYWiKo6oq6IrA4/Ou9GidyPBNeERcdTAwMDHsN4J01XtcdTAwMDHI8zBbQDiQxrFcdTAwMTUrXHUwMDExyMpcdTAwMTAwUlx1MDAwNFx0RPJcdTAwMDbXS5LLONRcdTAwMDA0oGUlr+fAqOH1XHUwMDEwXHUwMDFkMI1cdTAwMGVcdTAwMWNvII99XG4g9fBcdTAwMWKA/6jLYVx1MDAwN1x1MDAwNDKWXHUwMDE2XHUwMDBlX8Q6llx1MDAwNrG00WRBiHq8cCDhflx1MDAwNvLgXHUwMDAzuCFcdTAwMDZQYFlMXCLPcFx1MDAwM0eBXHUwMDFkeYNcdTAwMDD4wcWJLKewbN9AXFybXFytYMhcdTAwMDFHXHUwMDE1XHUwMDAzXHUwMDFlc1x1MDAxM6cn4CSBXHTakZKWlmYjXCJopqtcdTAwMTF+SUR1XHL2zFx1MDAxMDKCXHUwMDBmgEBcdTAwMDLMvFCpOICdyVx1MDAwYlx1MDAxY1x1MDAwMVx1MDAxN6FB+Fx1MDAwNzJcdTAwMGbq6GGWIDmIXHUwMDFhXVwiXHUwMDBmd1x1MDAxNN9cdTAwMDJcdTAwMTRAWC5cdTAwMWFcdTAwMDRcdTAwMWIzXHUwMDE2J3JcdTAwMTdPvPVcdTAwMDKIkegxrMZaRFx1MDAxYVB02IdtXHUwMDEwW3kuLy/x0Fx1MDAxMc6+/GS9yDygTqpgwVx1MDAxZkWD5INcdTAwMDJcdTAwMWaxXHUwMDFhoO/xQKQyJbv1XHUwMDE2btRpxqdcdTAwMTZf2sAqXHUwMDEwTVxctXbCqVxiOIRkqyZm+aaQ5zugXHUwMDFl9eJcdTAwMTi9w1x1MDAwZlluX1x1MDAwMr7SbSRcdTAwMTFcdTAwMDC2itG9i1xy9i5nL07AQ4LgSMtcdTAwMWOYL+lKgNNDlGtAzeFpVf3FMtQxINVMXHUwMDEzRK28KS/PcVx1MDAxYlx1MDAxY++AikJog5unJLy4wNVcdTAwMTioX1xivkx+XHUwMDAyd6ZcIlvxwNvIaZroijLM9tlItlwio0/kRTB4b1x1MDAxNPOAXGLXfoU8aLCW2nBcdTAwMGbTWlXSvSgysFx1MDAxZs+sUlx1MDAwNNdrkork+nSQhmlcdTAwMDdcdTAwMTaWlGwj4vGSXHUwMDE3gUBcblx0JG2UV8qdKJiyxlM25Z29iNVDTVj6qdlcdTAwMTjVwDhixp1nT1pcdTAwMDJUK+epxvYnmohjhoWBM72bi8nqXHUwMDEwXHUwMDE2enZtKDCDWH+1ua0x+mTgLlxiNIk84Fx1MDAxMiQyI9uATjFLXHUwMDAxXeB+UFx1MDAxMFCLclx1MDAwMU3M07hcdTAwMTFeXHUwMDE09sj69ibygC/wQc5cdTAwMDBzWe+W6FxubIKxYPT0XHUwMDE1XHKudtbyXFym6HKNXHUwMDE3ILdO+tQ2hFx1MDAwN5OBXHUwMDE2w92rXHUwMDA2SVxmXHRPTlx1MDAxZCFqMFdbLvFcdIAhXHUwMDA1tipFxE1cZq7eXHUwMDE3SESluFRtXHUwMDFj++uYhirJ+1GWXHUwMDEzSVlCXHUwMDEz5aO6Mkiz7C+PoVx1MDAxNOWGfJfBaao6rbtcdTAwMWXWJPe1QZVxTVxmO33i6cH26FNcdTAwMTCXXHUwMDEyfH1cdTAwMDNTm7E8x6S05MZcdNVcdTAwMTY+36a3XHUwMDBm7pqBX0D4UM8y8iRcdTAwMGIwnJGnwj2S5aRcdTAwMDO3S1x1MDAxMTIoqiZgrz70Q/Tk8SSYLYeKOZ2WgrCIXHIsTSs2wNU6Utw8i0hcdTAwMDNfXGanLJRJXHUwMDFl7i1hkpriXHUwMDEwhykmIIFcdTAwMWVRpapijHEsL1x1MDAwM3T42u2NWYszTD7Cf2pcdTAwMTB1eKlgkltcdTAwMDcq7qHCXHUwMDAw5Vx1MDAwNntD9Fx1MDAwMsDvyNxcdTAwMWUrOELqXHUwMDA08D20XHUwMDE32I2rJ2f0UZ7Fx1xi0DyT26mPMtGwWlx1MDAwMlx1MDAwMOVcdTAwMDFpXHLE8aEx8Vx1MDAwM6M00qbwKIOh9eO9XHUwMDE462/cbKVcdTAwMDF8XHUwMDEwX1x1MDAwMFx0JPfgbbmYKbL7wWmjqHJcdTAwMWVcdTAwMGa3Vlx1MDAxY2g/VFx1MDAxZVx1MDAxMTZcdTAwMWUqXHUwMDEwVybSXHUwMDAwbohZgNpcdTAwMWFevta6wCvyzTSEofl+i0qxLELhXHUwMDEwemhGb/W1paQpKo9cdTAwMGVcdTAwMWSwWUVcdTAwMTlcdTAwMTJxXHUwMDFllpfvXHUwMDA2Mu1cXKslZFFcYtZJNOFuTUJcdTAwMDNAoliaxNDIQZnqy/uwOESgjFW0xcMwiVx1MDAwNlx1MDAwN9BthHnMh5v62JGM1kjjpYFcdTAwMTOJUibCYFxiglx1MDAxYS4lg7eHXHUwMDE1xm2K6Fx1MDAxOdbkqe4yP1x1MDAwMb6C0Fx1MDAwNea4XHUwMDA1iztrxTGyXHUwMDAwXHUwMDEwk/A7llx1MDAwYpZcdTAwMWVC4HZcdTAwMThcdTAwMWM0vk9wy6veUlx1MDAwM6ivYlx1MDAwZVx1MDAxNuZFz132cYx7gFx1MDAxOCzohJurxWpYKlx1MDAxYupccmJMq7mhWXIjXHUwMDFltFx1MDAxZHdBedBOpvbrNUQzJoRZwbDJaErIilx1MDAwMFTle7CaXHUwMDAxcn1eXHUwMDBi0THuLpZcdTAwMDRWXHUwMDAynXLl6Fx1MDAxZNExhzIgorVcdTAwMDakvT481syDXHRWXHUwMDE3R3C6WFJcdTAwMTGE7vqKkkpmVWXt2phYXGLkS4jfXHUwMDExoYs0sVx1MDAwMOJcblx1MDAwMlx1MDAwMZ9Ekl1725hF4f5cdTAwMWHrTVx1MDAxMFxyXHUwMDA2n0hzJjiQeabbXHUwMDFhXHUwMDE0ks5YXHUwMDFh9/BB/Fx1MDAxNZFcdTAwMDb8XiXSeCsl6Fx1MDAxZWhcdTAwMTRoS+2NM1wi80x7+jz35ZI9JFx1MDAwN8tzXGZcblxmbyz8Uq04XHIsXHUwMDAxmLJoJb+iNNOWx1x1MDAxMMI0KCeHKJhcdTAwMDLrXGYjqZpKRVnW0stAJlx1MDAxN+pcdTAwMDGVXHUwMDE5SuCSXHUwMDA1XHUwMDA1p1x1MDAwZYvytvQvXHUwMDE3XHUwMDA3fedcdTAwMWNccs/dMGjpWIJX4msgXHROSdZcdTAwMDfDTLdHxdS390B2OZZ+xrKAztrCbdZXXGIw2W5YI4onoZiPSVx1MDAxNFx1MDAwZV/Apm3m7HyoX1x1MDAxYp2IZ+140PSLZfWFL81pLMgg7ka9XHUwMDBmydeGy1x1MDAwMJFHnJQk2iGNdUm4Wmqcrt+Bwn1cdTAwMDP/0YjSYavOeZ/u8UBcdTAwMWZcdTAwMWSLt5muqFx1MDAwN9R8i4e7/1x1MDAxMXbFXHUwMDFhmUSaYizBwi4w9PqwxpiMm5BUXHUwMDEyVn25sf0nQSZcclx1MDAwNIL/rVx1MDAwZmpmLE3mVSc690vwIWVcdTAwMTVhW1x1MDAwMJw89NDafLOhgYtD/MZ0XHUwMDAzozfuviTypNB581x1MDAxMFleaFx1MDAwMFx1MDAwZTbz8LFwSIF9LnFsn1x1MDAxMpxC54XfoI71NVx1MDAxZtyVZVx1MDAwMZ3MXHUwMDFkt4sxXHUwMDEx5/LaXHUwMDA3eHz4+npcdTAwMTI3c2m80YI1XHUwMDFh2lxuX9I5bkArJtVwrcxH1NeT5cUysFTuJ1xiJVxuLdO5PLhcdTAwMTJ+XHUwMDExgFdcdTAwMDE/6tvSNMh5tFx1MDAxZa5cIlxuJtpLmM+lc4tQOFx1MDAxMFx1MDAxNZZC1a5OXHUwMDAx7UBcdTAwMTO4Wexd3lx1MDAxOPdH+V1E91x1MDAxYVx1MDAwYlx1MDAwN3xFUJx6glx1MDAxM0mv4MtcdTAwMTCOgk7bsUYycu3AjCpcXEqj/pZZitOMITWR01x1MDAxM4rT4lx1MDAxMdww9lx1MDAxOXlcdTAwMTh0aNBdRVJcIliG7TSzXHUwMDA25c4llrZ43lrgRED422BxLmNIXHUwMDFluMMr2HRQXHUwMDEyp8gxYPt5vZqo93Xas8eN+zlcZl7KW+0qL2JcdTAwMTWIxFx1MDAxMEaTXGLXX+pspYXMKepcdTAwMTWLbq0oM01mjYOXrDS0rOSpT85BXHUwMDFjN1x1MDAxZaVcblx1MDAwNGOp0novy5wm2JQyilx1MDAwMUaDa5VAKehcdTAwMTPiXHUwMDExkP60XHUwMDFhjVx1MDAxMUpkJihcdTAwMTgmhJo8Vu5jSoRy0clUmmGRoZLQb1x1MDAxYlx1MDAxYVg/4o38vuRpMmC2ScRpptdcZv/1TUJ9cP7I+kJcdDuCXHUwMDE1OZncOkH1NVxmWFx1MDAxMFx1MDAxYdSvXHUwMDBlXHUwMDExhFx1MDAwN+jg2eJ/MZZBh09cdTAwMDKPXHTPgoVHrGZ+cHlggSxcdTAwMWJcdTAwMDJYXHUwMDE4WKZcdTAwMGJjlXzMenLXWcJN1Get8zpSmCtcXDGCdJVUoLCOXHUwMDE0z4kpO1x1MDAwNty6QfpcdTAwMDDkiVxyWoJ4XHUwMDEwOLY5kVx1MDAxN1xyXFxA4IxGVuTUirOMXHUwMDE14L2xNsVcXKlLXHUwMDFjXHUwMDE0d3yh5DJcdTAwMDZcdTAwMTb61T7emctjLVx1MDAxZoyJmWTWXHUwMDEzlsNcdTAwMTM+XHUwMDBlmj/eQlxmXHUwMDBmx1gnToLUIHJGSGfpxWU5XHUwMDBiXHUwMDA221BMgJtcdTAwMTjyjel6bWHhgFx1MDAwM/TAosiQyil1XHSkhVx1MDAxYrCsXSCo17N2lSHQ4WhRuHhcdTAwMWJcdTAwMTBHlz1cdTAwMDE7hnDPgD1KXHUwMDAx3GX93Vx1MDAwM1xccVx1MDAxYSfsM2CBopxSz+v84WHhW9hcdTAwMDLQoOiYjVxijJtcZuvuXHUwMDEwcpWjWDZcIsDFssNcdTAwMWG0ko199fLyvl5usjumR8pcdTAwMTVBXHUwMDE5t11sblx1MDAxZLFcdTAwMDFccsjg6ywzI1B778q7XHUwMDExuHP4JqtA/cjHXFx9MVCNOPpcdTAwMWLgnGfjXHUwMDA1XHUwMDFlyEOLk1xmLpmoZVxyNcL/cnKNXHUwMDA1lZ7DO0lBQe5cdTAwMWJtvrDaXHUwMDE4y4BcdTAwMGJSXHUwMDFj4SrLXHUwMDAyXHUwMDA1S1x1MDAwYulcdTAwMTKV58xLVb89eT/NhnLKXFxeXHUwMDA0UVx1MDAxMfGRrmw2fNW82fDZ5esvvuNfX7zVne72kjrbXSmMrprr6S3sRIWxsOTSy8LAxuuhpfB+itliJl7dlHGOd1x1MDAxOd6CgNuFfGdcdTAwMDJRYKHxczS7XHUwMDA1n4CPQyBcdTAwMDN2XHUwMDA0XHUwMDA1LrQ+Xo9uyfmJVLF6ov2NKv3TdjjHbYeLrFx1MDAxOYPjzuf4sIa0nHn+sfcuOHtcdTAwMTSMt0GXXHUwMDAwXHUwMDA0UqdcdTAwMDVJXHUwMDE0XHUwMDA3XHUwMDA3XHUwMDFhN0VgkzK0mVx1MDAwYkSQw2G70rI2gcW2JXmp2teKY8aC0ZR1+b5GOSMobV7MQjyzXCJPXHUwMDFi18qbZJr8Ycmbx2NQYEaekydcdTAwMWGUyc1YXFy+hcNwic1cdTAwMDVM55YhUlwi4GZdoOODqk+4s8fRg8ixSipcdTAwMWYkmfSxskaJ47/ZjSXAR1x1MDAxYmiLXHUwMDEw1GhGpIGTL0JcdTAwMTJqcLSmXHUwMDAyMcfrbM4xtr1Yn/m5L5Q06cujyYWCNVx1MDAwMLpyxNnr5iD5aXX18/vex/W17pH9uvX669fd7tdJg1x1MDAwYudcdTAwMGIkg8zYq5hP45GFTq1cdTAwMWYgaTJcdTAwMTagXHUwMDA0XHUwMDA1XHUwMDBlJFx1MDAwYlx1MDAxYlx1MDAwZbNGScnkXHUwMDA1kU6DW1VcdTAwMWT9QvtcdTAwMDLISMe8MViXXHUwMDFha8/nkFx1MDAxM3YyVVx1MDAwZjP8XHUwMDA3J39cdTAwMDecvN2nQ4Y4XHUwMDE3gSHL69m0Xm68y0j6nGfApI2Q9XVcdTAwMTKT1ZA/nuX3ns8vWEmvXFwnjtG9ZGWFsHmRXnlMXHUwMDEzXHUwMDAxSzhQdCOZRqpcdTAwMGbBZixOZeyGtWzxZu+QKSfZx62t9ubx3rE3IVx1MDAxZraFKNon6+OoXHUwMDFm7ni4XHUwMDEwtGlcdTAwMDBcdTAwMDVcdTAwMTknLlx1MDAwNlx1MDAxNlx1MDAwZlqO9VJpkzqYO1ttbD4ooZaN3Fx1MDAxN7KE9OVcdTAwMWJkXHUwMDExjEfDhFn6b5pDy+rmrvn6+vOGtp+OluS37id3tvjkt4BcdTAwMTbLXHRTLDFQV4N5XHUwMDEyaJE+i8xcdTAwMTMppWRcdTAwMTThnqZn2rz3w1x1MDAxYc5cdTAwMDVCLFx1MDAxOCtcdTAwMGVFYoZcdTAwMWFuJJKbka6OXHLYlpHFVsqHfya//L7QXHUwMDAyRs16We3y9Fx1MDAxZTfBi79cdTAwMWUzXHUwMDEzXHUwMDA0XHUwMDAyXHUwMDFmZolBVuv3XHUwMDE1XHUwMDEycaq8h1x1MDAxMjOWxlnH4kvBOpuHXHUwMDE2XHUwMDA3/u1cdTAwMDNrOoBcdTAwMTVcdTAwMWOplKYmXHUwMDAzXHUwMDFierhvpvGXemiMmWPZv2dJl4JcdTAwMWSVM6c6P5RPXHUwMDBi51x1MDAxZI9lqa9GLomL6XZcdTAwMTbE8U3ci1x1MDAwMLtcdTAwMDVcZtSJW2Se3+ZcdTAwMTM5OI3T6HKfTW7fhjlsllPGJr2e9yDQwDRNNNLh0mIod4pcdTAwMDRO61BsXGJUeVx1MDAxNVWt9om8TVx0YbPhTCtcdTAwMTZ1lkd8LF5/wLm8Z1ZAXHUwMDEzYn3a854wcnKOXHUwMDEyioSQw1VcdTAwMGZEW71cdTAwMDVGvjveePP5ZWtz8/Hi8+9cdTAwMTf7K+dcdTAwMDerr39cdTAwMDeM9Fx1MDAwMoYqhY4gYKylTY7c9Hk/XHUwMDFhXHUwMDE0MadWhc3GmWOkYW5HXHRDhjuqQCpjpLHcgGCvNMKs8YOVXGaLzZWy/+Qpf1+QvN2n4dSczqvS8qJqX+b8cGrg+Wz85eF0ur4m32ScocIhwmytUm7M55ZcdTAwMTWw1udcdTAwMDI1OcbV5XtqiGPKXHUwMDE5Q1x1MDAxNjnlI5I584uHc95Wnk1Ry1o2M+Sdfrde3N2Eca8xXGKAi2SXkVx1MDAxNOXkssw8O5LYJyu5l18vTnBSdj58VVx1MDAxOK1t0n+Ap1x1MDAxZbjxasmVRaxcdTAwMWa0meE6eYCN8t7LfHLIXHUwMDFm5bc1Z1x1MDAxZrHVyih2Ts3ldprncEpRXHUwMDFkzq01h6pcdTAwMTft/tn54cbjo+5B72Sw07nsXHUwMDFkfmz9XHUwMDBlUOXYOs5hiDIgmDIm3U5jaVx1MDAwN2sj2X2jw/0kXG4j2yQ4zlx1MDAxYqpEnlRcdTAwMDFUV9rJ3EVgU0DFXHTRtLtYrIj/XHUwMDA3p347nDKsXHUwMDBlj9zP51x1MDAwNDtdLlxcWZRsjlGMRljXzZGN7cX6KjZcdTAwMGaqpVwieFx1MDAxMOvhRdJSw7oquCjFYyU5Rak+Icbmflx1MDAxZpyAweRcdTAwMDfyJMlE1iFIjn9iPU89NqpMau6j5EOruJFUXHUwMDAyx1TpXHUwMDFi7C9lPnCkZMxLgJk7nLa8JiMqYZDshOFQMjbB+Sl371x1MDAxN41mloXJvWNn3Vh6XHUwMDE2U3m663pz7270MFx1MDAxY27CcHdfPH63Ozy+aPm132RcdTAwMWYoXHUwMDFmKs5yb8fAcZSNu/LumqNcdTAwMDRcdTAwMTDbO5OnoF2ysJntXHUwMDAzsVWd1fdQZPCYqkDEsa9JxjzrXHUwMDFizHhcdTAwMWOCxctcdTAwMTBcbvnsf9z7b+feb/lpjmLg+Dbqr2IvTdn3XHUwMDA0zYpEnmZlnY9NoEBygms+TY9EVyZcdTAwMDdcdTAwMDBkTNPQa1xubs83aNacrTRcdTAwMWVcdTAwMThcdTAwMDJcdTAwMDfLrkOofzJcdTAwMDBcdTAwMGbW4XFcdTAwMDOiifwuXb9tIziLkMNCY35kQLlcdFxm78LKNOdCRkWcrZVcdTAwMDdcdTAwMTDlXHUwMDEzIFSxiMSliUJm9VwiXHUwMDBm0maJZYPTNdgwxD4wXHUwMDFlXHUwMDE1wHCoLC/1XHUwMDA1XHJgSrClXHUwMDA0IUaQnlx1MDAxYlEpyHOriWc1WFblN5lQM2uBnPCDp6HyLU3FrvLSXHUwMDE1ZznCe46ZwFOz9WUzafDlQrlcdTAwMTVU5Fx1MDAxNeuKYSZHWtkmLSv3XHUwMDA1z5NPTpDgIJqLq8Lnt83x2YeLuNzuPIlftlx1MDAwZd7KtaXPvc9rj39cdTAwMGJ8djajXCLBj1x1MDAwNVuc8TnCZ4b/7OKmSdxbNSPno/OgnXymXuFkwFwiPlx1MDAxYsnJimzyjtH48YJGnr/AXHUwMDE2qbqz6P5B6L9cbkLDqTnFydzGQHVjud1QwoU6r1x1MDAxNZxk3vNRv1GhOPdUXCLG4Fx1MDAxOCxWeCQ+V/LgXHUwMDE5rzjsT9anp+qkQVhQgFS2QKhcdTAwMDZcdTAwMWVXZ8pwzoNwxubEI4GsxDxcdTAwMWVcXFx1MDAxZVx1MDAxYlx1MDAwNDnUiHNcdTAwMWY5oaBcXFjBmWpcdTAwMDbMm7PhXHUwMDExcjZcdTAwMThGzlx1MDAwMTm45YxcdTAwMTiVZpdXeTw3O2Asp/kjXHUwMDA0ZFdPvcB8bI1nXHUwMDBmIzNyKohcdTAwMTSwisX5nEf2i0RcbnZcdTAwMWJIoiZwn5H+WFqzKFx1MDAxNE/vl1x1MDAwMWtMX/5cdTAwMDGs4GHQfMB/XHUwMDE1rr5rjqvdzeHG6YuzXHUwMDBmbm+4bE9f2W3z9N3lb4GrPJeIdc+GZU7OpfWPnJFAospcdTAwMDJ8uIB7int9PrWa8zhcdTAwMDPrVFxcXHUwMDE1rrJbgVWYnDfjWOY1XHUwMDFl+EaeXG4m/slr/n1gVVx1MDAxMecsXHUwMDA3nyDYKoW9guOyI/vkOW7cxFx1MDAwNn33iqGghSVcdTAwMDQ2kKtynCqJQlx1MDAxMX6O4/1BxeuHxPFgRE7aQeiDQDDq8i5SXCKvwTF6kYM1NCdOXHUwMDAzvZLeQs2hblxiU3mEnuTQ4jphLuPwKot7h3WxzqMkznCGb2QzXHUwMDAxR/fUt47PVlx1MDAxYfPXkulcXIZkXHUwMDFj219cdTAwMWUnNu5cdGpcdTAwMDVcdTAwMDZcdTAwMWVQYVx1MDAxME5Kjlx1MDAwMZMuPUCIU3M4v5Rn2ZhcdTAwMDbdXHUwMDA0Mp9cYsUmStaYXHUwMDEw2pNHy2NcdTAwMTKiQFTijGsytHjWXHUwMDAyr8GXqVx1MDAxMPaq4NKThlx1MDAwN+E9z1xmjJyBwNn6tXh/J2hcdTAwMWW094ZX+FOBz4WjNFN45jhcdTAwMWb2XGZV1sdsNIfnb2eby0ut1feLT1x1MDAwZbcv11eevFh9sSTn+8BAuFxylVx1MDAxZv9cdTAwMWPY0ClEWlx1MDAxOZOPu+dcdTAwMTa1tTxT0CZcdTAwMGIrXHUwMDAwc5v/TFx1MDAwN+aW3Vx1MDAwZlWHXHUwMDA2aiF5XHUwMDFhh8uHl/NojXFcXLZUXeZXTLz6XHUwMDE5XHUwMDBid5nzo3uuXHUwMDBld29cdTAwMDW4/73Ru1x1MDAxZqr1I6H052RcdTAwMWO++Z3/XHUwMDE2NPhaMZ7sv9XPPmxcdTAwMWW+XFzuvDxZ7j7dk91cdTAwMWT/qKjqNzrcXCJcdTAwMDA+unnnzz+myV1ZP39+XHUwMDFlP7/8uipPn7WeXXRPn75avpPcXHUwMDFmXHUwMDFmXHUwMDFmts+HZUFX3/jx7UXn/Mh8PJHfnlx1MDAxZr7a9vJC6fWC2DF+M0ZKeMLHKHXcgJRMNfnSOlx1MDAwYtZegNXxknFcclx1MDAwMIbrl1Xmvtnc3KvvRbW5XHUwMDFmtfaOzlx1MDAwNu05MHgjXGaAyOm8078wROja4J3IXHUwMDE0Jzw4XHUwMDFl6jPV4Fx1MDAxYlx1MDAxZFx1MDAxMdrei7GCiUefcXhcdTAwMDHHIEZuRY1cdTAwMWK8sqmFa8TmXHUwMDFjwlrdeDTvjPqg31x1MDAxYm50LvlAlCi9+qx13Ony5o+uONdq2ndv2Fx1MDAxZfBLXHUwMDE2XHUwMDFlr68sbLRcdTAwMDdQ5UelTz3udlx1MDAwZXt5uNfmZ0umMOzstbo3XHUwMDFmOO7s71x1MDAxN5FxXHUwMDBmX91CLDtYaYJd/UHnsNNrdTdcdTAwMWKtrHU27L9rn15d7nBw1i7esfaLm2AruyZBP1x1MDAwN+iFZvLUxFx1MDAxMWpcbs4mrkxkv79cdTAwMDWih297345cdTAwMDavetvq07fDXHUwMDEwN+3up1x1MDAxN/OO6CbkXHUwMDAz+zlfc1x1MDAxY9FDPo7Qa3b4grj5KSnsX4zonFx1MDAwZodIY0Kj4a9cdTAwMDX0h1x1MDAwN97hwaZXXHUwMDE3x2+Gr9pLe+L1ivy0eLTUlCc8jlu9nUUnV15e7Fx1MDAwZbaWjlx1MDAwZd7uf1xcbbbcJoDuXHUwMDExXHLeN6BbMbm7mIdW5FFLlbVvNbf26ns894DOaXM8XHUwMDE2L1x1MDAwMrGVTFx1MDAwMD1YRqVcdTAwMWOcznNCptr7XVx1MDAwMJ1TXCI5XHUwMDBlM0BcdTAwMWRsYTLMNEA3PE9cdTAwMDEk41dcdTAwMDI654RcdTAwMTdSefdccujrg/63zn57sHDSPVx1MDAwM57eXHUwMDE3lk9HrVx1MDAxNMsnLmpWML7faVx1MDAxZPd7+1VmbcK0YjFcdTAwMGVcdTAwMWPU1Wb9oblZv3p89jp8Xn+1/aLvdlePdnaXvu5Mqlx1MDAxNptcdTAwMTNcdTAwMTCHXHRcdTAwMDE/NUdcdTAwMWZx/q5O9qGD4lxmbVx1MDAxZrldNZ2lq4PYNma6Ue+qXHUwMDAztbtbYdTBZJpHm+hrjFx1MDAxZXngkVVLm1lrWKaemnc+Vl+bqO9cdTAwMDXAf1x1MDAxNPDcXHUwMDFhwOuA9nJ7uL6+tvHa7Vx1MDAxZD6LavHL2lHncWhcbrRG9LbWX/a2T+LhUMmLlcvBq92GvKBcdTAwMDHQcqLnvUfOxZFcdTAwMGapRTqhjOExQlVcdTAwMTb5sblFVt/jOVx1MDAwN1rH6eyeh2yIwFx1MDAxNvuUWEfLijHrefzAnW1yXHUwMDEy0HqbsUuNNUs8vLbKJCssUVtcdTAwMWXBU7TRv3zovN7fX+j3XHUwMDE2/tP71lx1MDAxOVxmz1pd/K3X32/fXHUwMDEz4tZAzFx1MDAxOOJeLe7H0spcdTAwMGKbXHUwMDE16l45mFxuXHUwMDBij2LiOFx1MDAwNe5dWFx1MDAwZausMvBPtyjQnupcdTAwMDfn1MC9kjzeRlracFx1MDAwNeg6MGnYtVxus1x1MDAwMN2JXHUwMDA2zqFT1lx1MDAwN6kqpvPwODQtx5k0S1M8nIGq3pS+f6idaveuOFx1MDAxNPDnN6FcdTAwMGJcdTAwMGJrX311XHUwMDEz28s9xd5cdTAwMTlXyVpcdTAwMTIrjeeJVXDkjoe6XHUwMDE1tvxcdTAwMWVcdTAwMWS2TvhcdTAwMDAyXHUwMDBlQlx1MDAxMdbmXHKQoTjHXHUwMDFjente3thcdTAwMWW7M6XN8UkrPtjuPl/flFsrZ1tvVj9cdTAwMGXkpTBv21UrXHUwMDE2WeDZ4OCAQbNJv1hyfb1cXJ1cdTAwMDVOjLvOs4jiKTBccpY741x1MDAxZPvU58x0077CMviz+MMoRr8/RqXa3d3+94a8aKLblKqwYzA+hiZGLaSu3FPYbu44p+9cdTAwMTTNqePkyLJMXHUwMDE4nunjI1x1MDAwZqxcdTAwMWGJufacPIdQhFx1MDAxOJRj8czk/vq7eE7Fk69cdTAwMWTP0OXIXHUwMDBigFxcRVtL0Dz9XCJKXHUwMDFl0aVD4ajOXHUwMDFmntRLizjnnnZcdTAwMTHn3JGePn239aE92L1cXDp42Wpccndar5bWNqrdkmNLINM9+UkqRYO8dkuGXHUwMDA3McIsXHJwUkhXXHUwMDFhWzgrNzp9y6K0Xk5j1KxnMYrTp8e9vmJcbi0yjM3T1aXCl/vxo6mjeUhXOtlU+LM4ZiX371r9xJbwaFx1MDAwMpspbCUlbTX3rNNT9vPqWa2ImXXQSqgtz3lcdTAwMWRcdTAwMTG8K8/KwZGS53iImvqMO3nWTPGEVGZro+FhkuOOXHUwMDE1sbE1kocr8cxcdTAwMDbtx4NQXHUwMDA3/DSziUFn7Vl/Plx03NCzroWN3U9f3698XFxvvTk+2Vx1MDAxYrqT5fCiylMxqFx1MDAwMzO1UVx1MDAwNcHaND/uWSWPQlVwZIpHfUVZPIZtZp51alx1MDAwMrnkWVx1MDAwNYe2uXyghIpQgDi2YJPhyXPW/u0g4Heiplx1MDAxM1xyhD/jpjEjdzqx9sVP7PBiSp1cdTAwMDOIKp3pbnNnumaGw8fvPj7dWJXv1zaXulx1MDAxNzsvzt7MuzNcci7m4ywjjzDhdLCyL1x1MDAwNafJNNN78l5LX5yDx5YsXHUwMDE0hrLwdOJcbmc65jxcdTAwMDPIi1My/v5cdLxQenVKXHUwMDAyb+s6ObZ6h6zdsH8yKWVXWnean6v+7lkl5ibZrdNcdTAwMTNcdTAwMGJaXCKslmcqVpntXnOzPX1x/q2155Zff97zy+2lleVcdTAwMTX7+tm8m62UNlx1MDAxZp7tXGLUUlx1MDAxNKdcdTAwMDddV7T4LCqdXHUwMDBm7eWJcZNn4tyFXHUwMDAzSVx1MDAxMzNcdTAwMTVtXHUwMDBlcTz7p8DERptho4Vf221+tJdcdTAwMTFcdTAwMTN6MH8ju1x1MDAxZLXr1dntxsaLhferK1x1MDAxZlx1MDAxNzbWll4tbz606U78+vu2Xq0nZ4dcIqd88SDxKvvdv1x1MDAwNexO5ZHzar+WJ1XzXHUwMDAwXG5cdTAwMDZyxUNcdTAwMDCuzFx1MDAxN4RWXHUwMDFiXHUwMDFl3FBcdTAwMDe7dzHffO5Kflx1MDAxNlx1MDAxZs9rNFUjT8atV/KwZfaF3Lv53jDC2daajdHLX+1cdTAwMWPOep3zhVNcblx1MDAxYz60Y6j86oeocIlcIn31XHUwMDA21Vx1MDAxNc/LUqGSjbebu4WLwbu9/vOl81dq7WD1yfOnT95ePt+ee7dcdTAwMTCi5yHxWoFcdTAwMDOLdDdcdTAwMWRRMFx1MDAwZsqR7Gibvpt+IMKeXHUwMDEwP5nY4JGaSXBarG1hf5OV1lXsuLGPVatiWup3KG55/+3bZst9cFx1MDAwN1x1MDAxZt/tvPz+/FX3YnfTNC1uef763U7/cNA53926XFxZ3nizv/lhW/0yR/RzIFx1MDAxZCbnXHUwMDE5RVByUo/2QXNjrL7F826M0dmMLZ9Rq6uirbI5Olx1MDAxZZCez9OOwND7MkcpQFx1MDAxNHzk6bGcXHUwMDBlIKs4tlx1MDAxZEdpxcPOpbh/lJ6r6pb/9JZ+gN/pPVW11OBKRVVL9aJmhbLtbrdzclrZXGZi3USUXHUwMDA1sfQ8kKt6qtFhc8vePn6sLr7smFx1MDAwZi831Prxent1aWdz0vjzOakj5UCnTEhcdTAwMGXlsN6OgSyMXiBEhfbiXHUwMDEz02rD72TV2mSs462saDFO8qxdV4Wxxlx1MDAxOVx1MDAxMU10v2ov9ucg9uNJZ+n9Tu/l8f6X9+bbxc7J+atcdTAwMWT5XHUwMDAwjVx1MDAxYX916DZhooXz1F8/XHS6j5pcdTAwMWJ49aObd+j2XmdcdTAwMWONXHUwMDAz+1x1MDAwZaJ4yu91R6dcdTAwMTeZi5wmrXmC95SZZU2MfFLDl1x1MDAwYlx1MDAxObmBsY7t4pV1qePIrVx1MDAxNI+A8X+njs4nnMfzn97GxemwfXxPsF2DUylsT1jSvZehOjE5YeZDVFFcdTAwMTX7iFxuXHUwMDE23Wlu0dP96bxatLM289yp0lx1MDAxY1x1MDAxZVacS3GVMfMq46BcdTAwMGUpgOq2OM9xplx1MDAxOTOVRW1kkPAgweiqIYTaZkpFg5XyPC9cdTAwMTHGzopk/ixcdTAwMWZI93fc9L/FJrrnXGJSydM9gmGJY+FDV3voNjNS6nwupeaMU1dcdTAwMTQzmz3/6V6jsNy8jJYnuFx1MDAxOZBLxfGpxakvN2WpoJxcbkvVUGJbXHUwMDFlf/dcdTAwMTfb/J9oKPxZXHUwMDFjs5GRuDFmNZNaquJU0jG3aj1cdTAwMGZcdTAwMDGs3Eb83NyrTmeT8+pVXHUwMDAzXHUwMDFllMDzXHSeXHUwMDA36aixXHUwMDE5dFxihoxlxTc7eEJMXHUwMDE2Nlx1MDAxYqfqYOvGXHUwMDA2qVx1MDAwM7tkQciq9iF85oyHc4I/gFx1MDAwNVx1MDAxNY9cdTAwMDBcdTAwMTmdreGgcH/PKtXGfoojmbXkgVxi0nrB+FNcdTAwMTSmRl/7qXy8kfA8X4ddjFHfQ53q9DRK2bMqyYNYXHUwMDExiqvIXHUwMDAzIeT4iiW0OFx1MDAxZu1cclxyiFx1MDAwNu7X3GrFv5NnnWwt/FlcdTAwMWM3lFx1MDAxOfnWqWNH7OQ5Ylx1MDAxY1LKXHUwMDAx2pXbvN1blGlMLcSeU//qY4QtgbpysDrZSkJadci0YnVj1L5Y6TJvY0dgWFx1MDAxMDBfU8Tqck7761x1MDAxZs2q8rtvn5++uny69Xn96dPBt6a5oftcdTAwMWFONry43P56pndXL/ovbFhdWXx7fDyzoSNcdTAwMGaTc1J+ysHTXHUwMDE27Ffo6ilix82NvfrZzbmxR1x1MDAxOFx1MDAxYU9KUlx1MDAxNubmtU1LsmBlgafCXHUwMDBiXHUwMDE3plx1MDAxYvtcdTAwMWQqKeFvOIxbKcOuTGmrqNT4vi1blFx1MDAwMsKov1HOiSVRrUOs657yTTVwVVWhlSznrrmmJlx1MDAwZWdS5JSrs+GQXHUwMDFjXHUwMDA3XHUwMDAyyCnixSNcdTAwMTOuQoPoM+CW5NhojVx1MDAwMC+O6aLIjNLsb1x1MDAxMDpP2PhQkVx1MDAwMNU+XHUwMDBignvMwinlfXGCwLiVzVwi6vjVvuNWllXwnr1HlfbWJFT5kVlcdTAwMTY8XytGPTaSPfdcblPqbNlcdTAwMWVcXMxIT3bfqcWXrqY6LtJFvW5q8zOl1ItTNJU/4zo6hVM3jCVm2lx1MDAxMFxyVlx1MDAxN33keeZcdTAwMWW8PzppxztO7qFlu3FvZH5cdTAwMTKQ14xcdTAwMDRcdTAwMDLucjRKqfF8nsr81XQ+UFxiXHUwMDAzvnzLsPNOIdpMWkwmj5CQzFxyOqB/Ze6+35xcdTAwMTi9e7qzXHUwMDExNs3jo6VccnHUVp8/dva77+fHuU3oMdEx0/A9Klx1MDAwNJ7QKJLNuCBcdTAwMDJcdTAwMDfGa1x1MDAxN1x1MDAxY0fGXHUwMDE3SlZ+ebGrVuCyzD787sTob1SN+q9rb/yodXKyMcS9vPFgj7512t+fVOpcZn9cdTAwMThr5TZPM2rn4Prnv/78P1x1MDAwZn2PiyJ9 + + + + + LOGIN NODE ON RESOURCE PROVIDER3. No INBOUND connectivity to the HPCVirtual KubeletInterlink API ServerProvider pluginPod on virtual nodeVirtual NodeSSH UNIX SOCKETunix socketPodContainersBatchSystemSSH agentunix socket \ No newline at end of file diff --git a/helm/interlink/.helmignore b/helm/interlink/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/helm/interlink/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/helm/interlink/Chart.yaml b/helm/interlink/Chart.yaml deleted file mode 100644 index cc8bd96d..00000000 --- a/helm/interlink/Chart.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: v2 -name: interlink -description: A Helm chart for interLink virtual kubelet provider - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "0.2.3" diff --git a/helm/interlink/README.md b/helm/interlink/README.md deleted file mode 100644 index acb2b0e8..00000000 --- a/helm/interlink/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# interLink Helm Chart - -::: danger ::: - -Work in progress! - -::: danger ::: - diff --git a/helm/interlink/templates/NOTES.txt b/helm/interlink/templates/NOTES.txt deleted file mode 100644 index 6eb8cbc5..00000000 --- a/helm/interlink/templates/NOTES.txt +++ /dev/null @@ -1,5 +0,0 @@ -Check node status with: - -``` -kubectl get node {{ .Values.nodeName }} -``` diff --git a/helm/interlink/templates/_helpers.tpl b/helm/interlink/templates/_helpers.tpl deleted file mode 100644 index 38ea4b10..00000000 --- a/helm/interlink/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "interlink.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "interlink.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "interlink.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "interlink.labels" -}} -helm.sh/chart: {{ include "interlink.chart" . }} -{{ include "interlink.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "interlink.selectorLabels" -}} -app.kubernetes.io/name: {{ include "interlink.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "interlink.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "interlink.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/helm/interlink/templates/virtual-kubelet-config.yaml b/helm/interlink/templates/virtual-kubelet-config.yaml deleted file mode 100644 index cda7870f..00000000 --- a/helm/interlink/templates/virtual-kubelet-config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: "virtual-kubelet-config" - namespace: {{ .Release.Namespace }} -data: - InterLinkConfig.yaml: | - InterlinkAddress: {{ .Values.interlink.URL }} - InterlinkPort: {{ .Values.interlink.port }} - ExportPodData: true - VerboseLogging: true - ErrorsOnlyLogging: false - ServiceAccount: "{{ .Values.nodeName }}" - Namespace: "" - VKTokenFile: /opt/interlink/token - CPU: "{{ .Values.virtualNode.CPUs }}" - Memory: "{{ .Values.virtualNode.MemGiB }}GiB" - Pods: "{{ .Values.virtualNode.Pods }}" diff --git a/helm/interlink/templates/virtual-kubelet.yaml b/helm/interlink/templates/virtual-kubelet.yaml deleted file mode 100644 index d4db5fb6..00000000 --- a/helm/interlink/templates/virtual-kubelet.yaml +++ /dev/null @@ -1,82 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Values.deployment.name}} - namespace: {{ .Release.Namespace}} - labels: - nodeName: {{ .Values.nodeName }} -spec: - replicas: 1 - selector: - matchLabels: - nodeName: {{ .Values.nodeName }} - template: - metadata: - labels: - nodeName: {{ .Values.nodeName }} - spec: - automountServiceAccountToken: true - serviceAccountName: {{ .Values.deployment.name }} - containers: - - name: inttw-vk - image: {{ .Values.deployment.image }} - imagePullPolicy: Always - env: - - name: NODENAME - value: {{ .Values.nodeName }} - - name: KUBELET_PORT - value: "10250" - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: CONFIGPATH - value: "/etc/interlink/InterLinkConfig.yaml" - - name: VKTOKENFILE - value: "/opt/interlink/token" - volumeMounts: - - name: config - mountPath: /etc/interlink/InterLinkConfig.yaml - subPath: InterLinkConfig.yaml - - name: token - mountPath: /opt/interlink - - name: jaeger - image: jaegertracing/all-in-one:1.51 - - name: refresh-token - image: ghcr.io/intertwin-eu/virtual-kubelet-inttw-refresh:latest - imagePullPolicy: Always - env: - - name: IAM_TOKEN_ENDPOINT - value: {{.Values.OAUTH.TokenURL}} - # TODO load env IAM client from secret - - name: IAM_CLIENT_ID - value: {{.Values.OAUTH.ClientID}} - - name: IAM_CLIENT_SECRET - value: {{.Values.OAUTH.ClientSecret}} - - name: IAM_REFRESH_TOKEN - value: {{.Values.OAUTH.RefreshToken}} - - name: IAM_VK_AUD - value: {{.Values.OAUTH.Audience}} - - name: TOKEN_PATH - value: /opt/interlink/token - command: - - python3 - - /opt/refresh.py - resources: - limits: - cpu: 200m - memory: 500Mi - requests: - cpu: 100m - memory: 300Mi - volumeMounts: - - name: token - mountPath: /opt/interlink - volumes: - - name: config - configMap: - name: virtual-kubelet-config - - name: token - hostPath: - path: /tmp - type: Directory diff --git a/helm/interlink/values.yaml b/helm/interlink/values.yaml deleted file mode 100644 index 6d53fd6c..00000000 --- a/helm/interlink/values.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Default values for interlink. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -nodeName: default-vk - -deployment: - image: ghcr.io/intertwin-eu/interlink/virtual-kubelet-inttw:latest - name: default-vk - -interlink: - URL: http://localhost - port: 5000 - -virtualNode: - CPUs: 100 - MemGiB: 1600 - Pods: 100 - -OAUTH: - TokenURL: DUMMY - ClientID: DUMMY - ClientSecret: DUMMY - RefreshToken: DUMMY - Audience: DUMMY - diff --git a/pkg/virtualkubelet/execute.go b/pkg/virtualkubelet/execute.go index cca1db40..95a69990 100644 --- a/pkg/virtualkubelet/execute.go +++ b/pkg/virtualkubelet/execute.go @@ -25,7 +25,9 @@ import ( func doRequest(req *http.Request, token string) (*http.Response, error) { - req.Header.Add("Authorization", "Bearer "+token) + if token != "" { + req.Header.Add("Authorization", "Bearer "+token) + } req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) @@ -33,8 +35,9 @@ func doRequest(req *http.Request, token string) (*http.Response, error) { func getSidecarEndpoint(ctx context.Context, interLinkURL string, interLinkPort string) string { interLinkEndpoint := "" + log.G(ctx).Info("InterlingURL: ", interLinkURL) if strings.HasPrefix(interLinkURL, "unix://") { - interLinkEndpoint = interLinkURL + interLinkEndpoint = "http://unix" } else if strings.HasPrefix(interLinkURL, "http://") { interLinkEndpoint = interLinkURL + ":" + interLinkPort } else if strings.HasPrefix(interLinkURL, "https://") { @@ -57,12 +60,14 @@ func PingInterLink(ctx context.Context, config VirtualKubeletConfig) (bool, int, log.G(ctx).Error(err) } - token, err := os.ReadFile(config.VKTokenFile) // just pass the file name - if err != nil { - log.G(ctx).Error(err) - return false, retVal, err + if config.VKTokenFile != "" { + token, err := os.ReadFile(config.VKTokenFile) // just pass the file name + if err != nil { + log.G(ctx).Error(err) + return false, retVal, err + } + req.Header.Add("Authorization", "Bearer "+string(token)) } - req.Header.Add("Authorization", "Bearer "+string(token)) startHttpCall := time.Now().UnixMicro() _, spanHttp := tracer.Start(ctx, "PingHttpCall", trace.WithAttributes( @@ -117,7 +122,9 @@ func updateCacheRequest(ctx context.Context, config VirtualKubeletConfig, pod v1 return err } - req.Header.Add("Authorization", "Bearer "+token) + if token != "" { + req.Header.Add("Authorization", "Bearer "+token) + } req.Header.Set("Content-Type", "application/json") startHttpCall := time.Now().UnixMicro() @@ -312,11 +319,16 @@ func LogRetrieval(ctx context.Context, config VirtualKubeletConfig, logsRequest tracer := otel.Tracer("interlink-service") var returnValue io.ReadCloser interLinkEndpoint := getSidecarEndpoint(ctx, config.InterlinkURL, config.Interlinkport) - b, err := os.ReadFile(config.VKTokenFile) // just pass the file name - if err != nil { - log.G(ctx).Fatal(err) + + token := "" + + if config.VKTokenFile != "" { + b, err := os.ReadFile(config.VKTokenFile) // just pass the file name + if err != nil { + log.G(ctx).Fatal(err) + } + token = string(b) } - token := string(b) bodyBytes, err := json.Marshal(logsRequest) if err != nil { @@ -366,13 +378,15 @@ func LogRetrieval(ctx context.Context, config VirtualKubeletConfig, logsRequest // If after 5m they are not still available, the function errors out func RemoteExecution(ctx context.Context, config VirtualKubeletConfig, p *VirtualKubeletProvider, pod *v1.Pod, mode int8) error { - b, err := os.ReadFile(config.VKTokenFile) // just pass the file name - if err != nil { - log.G(ctx).Fatal(err) - return err + token := "" + if config.VKTokenFile != "" { + b, err := os.ReadFile(config.VKTokenFile) // just pass the file name + if err != nil { + log.G(ctx).Fatal(err) + return err + } + token = string(b) } - token := string(b) - switch mode { case CREATE: var req types.PodCreateRequests diff --git a/pkg/virtualkubelet/virtualkubelet.go b/pkg/virtualkubelet/virtualkubelet.go index 159ac9a7..aedb799e 100644 --- a/pkg/virtualkubelet/virtualkubelet.go +++ b/pkg/virtualkubelet/virtualkubelet.go @@ -160,6 +160,7 @@ func NewProvider(providerConfig, nodeName, nodeVersion, operatingSystem string, if err != nil { return nil, err } + log.G(ctx).Info("Init server with config:", config) return NewProviderConfig(config, nodeName, nodeVersion, operatingSystem, internalIP, daemonEndpointPort) } @@ -176,6 +177,7 @@ func LoadConfig(providerConfig, nodeName string, ctx context.Context) (config Vi err = yaml.Unmarshal(data, &config) if err != nil { + log.G(ctx).Fatal(err) return config, err } @@ -230,9 +232,11 @@ func (p *VirtualKubeletProvider) nodeUpdate(ctx context.Context) { log.G(ctx).Info("nodeLoop") - _, err := os.ReadFile(p.config.VKTokenFile) // just pass the file name - if err != nil { - log.G(context.Background()).Fatal(err) + if p.config.VKTokenFile != "" { + _, err := os.ReadFile(p.config.VKTokenFile) // just pass the file name + if err != nil { + log.G(context.Background()).Fatal(err) + } } for { @@ -703,11 +707,6 @@ func (p *VirtualKubeletProvider) statusLoop(ctx context.Context) { <-t.C } - _, err := os.ReadFile(p.config.VKTokenFile) // just pass the file name - if err != nil { - log.G(context.Background()).Fatal(err) - } - for { log.G(ctx).Info("statusLoop") t.Reset(5 * time.Second) @@ -717,16 +716,20 @@ func (p *VirtualKubeletProvider) statusLoop(ctx context.Context) { case <-t.C: } - b, err := os.ReadFile(p.config.VKTokenFile) // just pass the file name - if err != nil { - fmt.Print(err) + token := "" + if p.config.VKTokenFile != "" { + b, err := os.ReadFile(p.config.VKTokenFile) // just pass the file name + if err != nil { + fmt.Print(err) + } + token = string(b) } var podsList []*v1.Pod for _, pod := range p.pods { if pod.Status.Phase != "Initializing" { podsList = append(podsList, pod) - err = p.UpdatePod(ctx, pod) + err := p.UpdatePod(ctx, pod) if err != nil { log.G(ctx).Error(err) } @@ -734,7 +737,7 @@ func (p *VirtualKubeletProvider) statusLoop(ctx context.Context) { } if len(podsList) > 0 { - _, err = checkPodsStatus(ctx, p, podsList, string(b), p.config) + _, err := checkPodsStatus(ctx, p, podsList, token, p.config) if err != nil { log.G(ctx).Error(err) }