From a2ccab5f7f646b8e51794281ce242742cbac56f1 Mon Sep 17 00:00:00 2001 From: Chad Moon Date: Tue, 6 Jun 2017 16:59:36 -0600 Subject: [PATCH 01/89] remove 1.6 declaration --- part1.yml | 2 +- steps.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/part1.yml b/part1.yml index 408fdb33f..62db5d3b1 100644 --- a/part1.yml +++ b/part1.yml @@ -5,7 +5,7 @@ parts: steps: - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources. - com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0 + com: minikube start --memory 8000 --cpus 2 - cap: Enable the Minikube add-ons Heapster and Ingress. com: minikube addons enable heapster; minikube addons enable ingress diff --git a/steps.yml b/steps.yml index fb71f83ca..01916976a 100644 --- a/steps.yml +++ b/steps.yml @@ -5,7 +5,7 @@ parts: steps: - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources. - com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0 + com: minikube start --memory 8000 --cpus 2 - cap: Enable the Minikube add-ons Heapster and Ingress. com: minikube addons enable heapster; minikube addons enable ingress From 03750446f0bb96d1f916e7ab56f3d1ba3b4f3b20 Mon Sep 17 00:00:00 2001 From: Chad Moon Date: Tue, 6 Jun 2017 19:24:44 -0600 Subject: [PATCH 02/89] add missing fetch-retry dependency --- applications/kr8sswordz-pages/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/kr8sswordz-pages/package.json b/applications/kr8sswordz-pages/package.json index 49374abe8..0e522c777 100644 --- a/applications/kr8sswordz-pages/package.json +++ b/applications/kr8sswordz-pages/package.json @@ -40,6 +40,7 @@ "chance": "1.0.4", "classnames": "^2.2.5", "d3": "4.4.1", + "fetch-retry": "^1.1.1", "jquery": "3.1.1", "js-cookie": "^2.1.3", "lodash.capitalize": "^4.2.1", From cf77172de56bd2deb726e773d3a9f91215c0edf0 Mon Sep 17 00:00:00 2001 From: Chad Moon Date: Fri, 9 Jun 2017 14:42:59 -0600 Subject: [PATCH 03/89] Add links --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 85eef7b8c..a5da5f681 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan +[Linux.com Part 1] https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview + +[Linux.com Part 2] https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/6/set-cicd-pipeline-jenkins-pod-kubernetes-part-2 + To generate this readme: `node readme.js` ## Interactive Tutorial Version @@ -412,4 +416,4 @@ After it triggers, observe how the puzzle services disappear in the Kr8sswordz P Try clicking Submit to test that hits now register as light green. -`echo ''` \ No newline at end of file +`echo ''` From d228d28d216a5a256da48431140524eb055bb33e Mon Sep 17 00:00:00 2001 From: Chad Moon Date: Fri, 9 Jun 2017 14:43:22 -0600 Subject: [PATCH 04/89] links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5da5f681..ed4a9730f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan -[Linux.com Part 1] https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview +[Linux.com Part 1](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview) -[Linux.com Part 2] https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/6/set-cicd-pipeline-jenkins-pod-kubernetes-part-2 +[Linux.com Part 2](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/6/set-cicd-pipeline-jenkins-pod-kubernetes-part-2) To generate this readme: `node readme.js` From bdeb0bb2a9fe262d56177b96465cd0c662ee9453 Mon Sep 17 00:00:00 2001 From: Mason Traylor Date: Mon, 12 Jun 2017 10:24:50 -0600 Subject: [PATCH 05/89] removed unused files and directories --- applications/kubescale/Dockerfile | 23 -- applications/kubescale/index.js | 95 ------- .../kubescale/k8s/dashboard-ingress.yml | 15 -- applications/kubescale/k8s/ing.yml | 46 ---- applications/kubescale/k8s/jenkins.yml | 96 -------- applications/kubescale/k8s/kubescale.yml | 38 --- applications/kubescale/k8s/registry.yml | 142 ----------- applications/kubescale/k8s/set.yml | 43 ---- applications/kubescale/k8s/traefik.yml | 35 --- applications/kubescale/ksh | 18 -- applications/kubescale/package.json | 29 --- applications/kubescale/public/index.html | 232 ------------------ applications/kubescale/set/Dockerfile | 17 -- applications/kubescale/set/down.sh | 3 - applications/kubescale/set/package.json | 16 -- applications/kubescale/set/server.js | 23 -- applications/kubescale/set/up.sh | 3 - docs.yml | 59 ----- manifests/kubescale/Dockerfile | 23 -- manifests/kubescale/index.js | 95 ------- manifests/kubescale/k8s/dashboard-ingress.yml | 15 -- manifests/kubescale/k8s/ing.yml | 46 ---- manifests/kubescale/k8s/jenkins.yml | 96 -------- manifests/kubescale/k8s/kubescale.yml | 39 --- manifests/kubescale/k8s/registry.yml | 142 ----------- manifests/kubescale/k8s/set.yml | 43 ---- manifests/kubescale/k8s/traefik.yml | 35 --- manifests/kubescale/ksh | 18 -- manifests/kubescale/package.json | 29 --- manifests/kubescale/public/index.html | 232 ------------------ old/etcd.sh | 27 -- old/part1/README.md | 104 -------- old/part1/apply.sh | 4 - old/part1/bootstrap.sh | 17 -- old/part1/cluster-compose.md | 63 ----- old/part1/europa.yml | 76 ------ old/part1/hello-kenzan/DockerFileEx.jpg | Bin 62809 -> 0 bytes old/part1/hello-kenzan/Dockerfile | 6 - old/part1/hello-kenzan/Jenkinsfile | 26 -- old/part1/hello-kenzan/index.html | 4 - old/part1/hello-kenzan/k8s/deployment.yaml | 52 ---- old/part1/img/prefs.png | Bin 163821 -> 0 bytes old/part1/img/registry.png | Bin 139217 -> 0 bytes old/part1/ingress.yml | 78 ------ old/part1/mysql.yml | 58 ----- old/part1/notes.txt | 0 old/part1/registry.yml | 85 ------- old/part1/start.sh | 29 --- old/part1/svc.sh | 1 - old/part1/volumes.yml | 57 ----- old/part3/Jenkinsfile | 26 -- old/part3/README.md | 40 --- old/part3/jenkins.yml | 92 ------- old/part5/spinnaker/apply-config.sh | 10 - old/part5/spinnaker/clouddriver.yml | 63 ----- old/part5/spinnaker/config/clouddriver.yml | 85 ------- old/part5/spinnaker/config/echo.yml | 67 ----- old/part5/spinnaker/config/front50.yml | 44 ---- old/part5/spinnaker/config/gate.yml | 203 --------------- old/part5/spinnaker/config/igor.yml | 45 ---- old/part5/spinnaker/config/kube.config | 15 -- old/part5/spinnaker/config/orca.yml | 54 ---- old/part5/spinnaker/config/run-apache2.sh | 59 ----- old/part5/spinnaker/config/settings-old.js | 132 ---------- old/part5/spinnaker/config/settings.js | 132 ---------- old/part5/spinnaker/ctop.yml | 38 --- old/part5/spinnaker/deck.yml | 51 ---- old/part5/spinnaker/echo.yml | 46 ---- old/part5/spinnaker/front50.yml | 46 ---- old/part5/spinnaker/gate.yml | 46 ---- old/part5/spinnaker/igor.yml | 46 ---- old/part5/spinnaker/ingress.yml | 71 ------ old/part5/spinnaker/install.sh | 11 - old/part5/spinnaker/ksh.sh | 14 -- old/part5/spinnaker/namespace.yml | 4 - old/part5/spinnaker/orca.yml | 46 ---- old/part5/spinnaker/redis.yml | 38 --- old/part5/spinnaker/rollout.sh | 10 - steps.yml | 213 ---------------- 79 files changed, 4180 deletions(-) delete mode 100644 applications/kubescale/Dockerfile delete mode 100644 applications/kubescale/index.js delete mode 100644 applications/kubescale/k8s/dashboard-ingress.yml delete mode 100644 applications/kubescale/k8s/ing.yml delete mode 100644 applications/kubescale/k8s/jenkins.yml delete mode 100644 applications/kubescale/k8s/kubescale.yml delete mode 100644 applications/kubescale/k8s/registry.yml delete mode 100644 applications/kubescale/k8s/set.yml delete mode 100644 applications/kubescale/k8s/traefik.yml delete mode 100755 applications/kubescale/ksh delete mode 100644 applications/kubescale/package.json delete mode 100644 applications/kubescale/public/index.html delete mode 100644 applications/kubescale/set/Dockerfile delete mode 100755 applications/kubescale/set/down.sh delete mode 100644 applications/kubescale/set/package.json delete mode 100644 applications/kubescale/set/server.js delete mode 100755 applications/kubescale/set/up.sh delete mode 100644 docs.yml delete mode 100644 manifests/kubescale/Dockerfile delete mode 100644 manifests/kubescale/index.js delete mode 100644 manifests/kubescale/k8s/dashboard-ingress.yml delete mode 100644 manifests/kubescale/k8s/ing.yml delete mode 100644 manifests/kubescale/k8s/jenkins.yml delete mode 100644 manifests/kubescale/k8s/kubescale.yml delete mode 100644 manifests/kubescale/k8s/registry.yml delete mode 100644 manifests/kubescale/k8s/set.yml delete mode 100644 manifests/kubescale/k8s/traefik.yml delete mode 100755 manifests/kubescale/ksh delete mode 100644 manifests/kubescale/package.json delete mode 100644 manifests/kubescale/public/index.html delete mode 100755 old/etcd.sh delete mode 100644 old/part1/README.md delete mode 100755 old/part1/apply.sh delete mode 100755 old/part1/bootstrap.sh delete mode 100644 old/part1/cluster-compose.md delete mode 100644 old/part1/europa.yml delete mode 100644 old/part1/hello-kenzan/DockerFileEx.jpg delete mode 100644 old/part1/hello-kenzan/Dockerfile delete mode 100644 old/part1/hello-kenzan/Jenkinsfile delete mode 100644 old/part1/hello-kenzan/index.html delete mode 100644 old/part1/hello-kenzan/k8s/deployment.yaml delete mode 100644 old/part1/img/prefs.png delete mode 100644 old/part1/img/registry.png delete mode 100644 old/part1/ingress.yml delete mode 100644 old/part1/mysql.yml delete mode 100644 old/part1/notes.txt delete mode 100644 old/part1/registry.yml delete mode 100755 old/part1/start.sh delete mode 100755 old/part1/svc.sh delete mode 100644 old/part1/volumes.yml delete mode 100644 old/part3/Jenkinsfile delete mode 100644 old/part3/README.md delete mode 100644 old/part3/jenkins.yml delete mode 100755 old/part5/spinnaker/apply-config.sh delete mode 100644 old/part5/spinnaker/clouddriver.yml delete mode 100644 old/part5/spinnaker/config/clouddriver.yml delete mode 100644 old/part5/spinnaker/config/echo.yml delete mode 100644 old/part5/spinnaker/config/front50.yml delete mode 100644 old/part5/spinnaker/config/gate.yml delete mode 100644 old/part5/spinnaker/config/igor.yml delete mode 100644 old/part5/spinnaker/config/kube.config delete mode 100644 old/part5/spinnaker/config/orca.yml delete mode 100755 old/part5/spinnaker/config/run-apache2.sh delete mode 100644 old/part5/spinnaker/config/settings-old.js delete mode 100644 old/part5/spinnaker/config/settings.js delete mode 100644 old/part5/spinnaker/ctop.yml delete mode 100644 old/part5/spinnaker/deck.yml delete mode 100644 old/part5/spinnaker/echo.yml delete mode 100644 old/part5/spinnaker/front50.yml delete mode 100644 old/part5/spinnaker/gate.yml delete mode 100644 old/part5/spinnaker/igor.yml delete mode 100644 old/part5/spinnaker/ingress.yml delete mode 100755 old/part5/spinnaker/install.sh delete mode 100755 old/part5/spinnaker/ksh.sh delete mode 100644 old/part5/spinnaker/namespace.yml delete mode 100644 old/part5/spinnaker/orca.yml delete mode 100644 old/part5/spinnaker/redis.yml delete mode 100755 old/part5/spinnaker/rollout.sh delete mode 100644 steps.yml diff --git a/applications/kubescale/Dockerfile b/applications/kubescale/Dockerfile deleted file mode 100644 index 3cf94315f..000000000 --- a/applications/kubescale/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:6 - -RUN mkdir /app - -COPY . /app - -WORKDIR /app - -RUN apt-get update - -RUN apt-get install -y apache2 - -RUN npm install -g loadtest - -RUN npm install -g nodemon - -RUN npm install - -RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl - -RUN chmod +x ./kubectl; mv ./kubectl /usr/local/bin/kubectl - -CMD ["nodemon", "index.js"] \ No newline at end of file diff --git a/applications/kubescale/index.js b/applications/kubescale/index.js deleted file mode 100644 index c24d0d415..000000000 --- a/applications/kubescale/index.js +++ /dev/null @@ -1,95 +0,0 @@ -var express = require('express') -var app = express() - -var http = require('http').Server(app); -var io = require('socket.io')(http); -var path = require("path"); -var Etcd = require('node-etcd') -app.use(express.static('public')) -var exec = require('child_process').exec; - -var bodyParser = require("body-parser"); - -app.use(bodyParser.urlencoded({ extended: false })); -app.use(bodyParser.json()); - -//etcd = new Etcd("http://localhost:2379") -///tmp/test-etcd/etcdctl --endpoints "http://example-etcd-cluster-client-service:2379" mkdir pod-list -etcd = new Etcd("http://example-etcd-cluster-client-service:2379") - -//etcd.mkdir("pods"); - -watcher = etcd.watcher("pod-list", null, {recursive: true}) - -watcher.on("change", showVal); - -function showVal(val) { - pods = etcd.getSync("pod-list",{ recursive: true }) - io.emit('pods', { pods: pods.body.node.nodes }); - -} - -app.post('/scale', function (req, res) { - exec('kubectl scale --replicas=' + req.body.count + ' deployment/set', function(error, stdout, stderr) { - res.send("scaled to " + req.body.count); -}); -}) - -app.post('/loadtest/concurrent', function (req, res) { - //svc = "http://localhost:8001/api/v1/proxy/namespaces/default/services/set:80" - svc = "http://set:80/" -// exec('loadtest -c ' + req.body.count + ' -n ' + req.body.count + ' http://set', function(error, stdout, stderr) { - exec('ab -c ' + req.body.count + ' -n ' + req.body.count + ' ' + svc, function(error, stdout, stderr) { - console.log(stdout); - res.send(stdout); -}); -}) - -app.post('/loadtest/consecutive', function (req, res) { - svc = "http://set:80/" -// exec('loadtest -c ' + req.body.count + ' -n ' + req.body.count + ' http://set', function(error, stdout, stderr) { - exec('ab -c 1 -n ' + req.body.count + ' ' + svc, function(error, stdout, stderr) { - console.log(stdout); - res.send(stdout); -}); -}) - - - -app.get('/up/:podId', function (req, res) { - etcd.set("pod-list/" + req.params.podId, req.params.podId); - res.send('done'); -}) - -app.get('/down/:podId', function (req, res) { - etcd.del("pod-list/" + req.params.podId, req.params.podId); - res.send('done'); -}) - -app.get('/hit/:podId', function (req, res) { - -var d = new Date(); -var n = d.getTime(); - -io.emit('hit', { podId: req.params.podId, time: n }); -console.log('hit!'); -res.send('done') -}) - -io.on('connection', function(socket){ - - pods = etcd.getSync("pod-list",{ recursive: true }) - io.emit('pods', { pods: pods.body.node.nodes }); -}); - -app.get('/',function(req,res){ - - res.sendFile(path.join(__dirname+'/public/index.html')); - -}); - - -http.listen(3000, function () { - console.log('Example app listening on port 3000!') -}) - diff --git a/applications/kubescale/k8s/dashboard-ingress.yml b/applications/kubescale/k8s/dashboard-ingress.yml deleted file mode 100644 index e47fd82e7..000000000 --- a/applications/kubescale/k8s/dashboard-ingress.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: dashboard-ingress - namespace: kube-system -spec: - rules: - - host: dashboard.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubernetes-dashboard - servicePort: 80 \ No newline at end of file diff --git a/applications/kubescale/k8s/ing.yml b/applications/kubescale/k8s/ing.yml deleted file mode 100644 index b9ef1f906..000000000 --- a/applications/kubescale/k8s/ing.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - namespace: kube-system - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: dashboard.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubernetes-dashboard - servicePort: 80 - - - host: grafana.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: monitoring-grafana - servicePort: 80 ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: kubescale.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubescale - servicePort: 3000 \ No newline at end of file diff --git a/applications/kubescale/k8s/jenkins.yml b/applications/kubescale/k8s/jenkins.yml deleted file mode 100644 index 5a1a25170..000000000 --- a/applications/kubescale/k8s/jenkins.yml +++ /dev/null @@ -1,96 +0,0 @@ -kind: PersistentVolume -apiVersion: v1 -metadata: - name: jenkins - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/jenkins/" - ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: jenkins-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: jenkins - labels: - app: jenkins -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: jenkins - tier: jenkins - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: jenkins - labels: - app: jenkins -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: jenkins - tier: jenkins - spec: - containers: - - image: chadmoon/jenkins-docker-kubectl:latest - name: jenkins - securityContext: - privileged: true - ports: - - containerPort: 8080 - name: jenkins - volumeMounts: - - name: jenkins-persistent-storage - mountPath: /root/.jenkins - - name: docker - mountPath: /var/run/docker.sock - volumes: - - name: docker - hostPath: - path: /var/run/docker.sock - - name: jenkins-persistent-storage - persistentVolumeClaim: - claimName: jenkins-claim - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: jenkins-services - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: jenkins.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: jenkins - servicePort: 8080 \ No newline at end of file diff --git a/applications/kubescale/k8s/kubescale.yml b/applications/kubescale/k8s/kubescale.yml deleted file mode 100644 index b8040d501..000000000 --- a/applications/kubescale/k8s/kubescale.yml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: kubescale - labels: - app: kubescale -spec: - ports: - - port: 3000 - targetPort: 3000 - selector: - app: kubescale - tier: kubescale - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: kubescale - labels: - app: kubescale -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: kubescale - tier: kubescale - spec: - containers: - - image: 127.0.0.1:30400/kubescale:latest - imagePullPolicy: Always - name: kubescale - ports: - - containerPort: 3000 - name: kubescale \ No newline at end of file diff --git a/applications/kubescale/k8s/registry.yml b/applications/kubescale/k8s/registry.yml deleted file mode 100644 index 04413e967..000000000 --- a/applications/kubescale/k8s/registry.yml +++ /dev/null @@ -1,142 +0,0 @@ -kind: PersistentVolume -apiVersion: v1 -metadata: - name: registry - labels: - type: local -spec: - capacity: - storage: 4Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/registry/" - ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: registry-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- - -apiVersion: v1 -kind: Service -metadata: - name: registry - labels: - app: registry -spec: - ports: - - port: 5000 - targetPort: 5000 - nodePort: 30400 - name: registry - selector: - app: registry - tier: registry - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: registry - labels: - app: registry -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: registry - tier: registry - spec: - containers: - - image: registry:2 - name: registry - volumeMounts: - - name: docker - mountPath: /var/run/docker.sock - - name: registry-persistent-storage - mountPath: /var/lib/registry - ports: - - containerPort: 5000 - name: registry - - name: registryui - image: hyper/docker-registry-web - ports: - - containerPort: 8080 - env: - - name: REGISTRY_URL - value: http://localhost:5000/v2 - - name: REGISTRY_NAME - value: cluster-registry - volumes: - - name: docker - hostPath: - path: /var/run/docker.sock - - name: registry-persistent-storage - persistentVolumeClaim: - claimName: registry-claim - -# --- -# apiVersion: extensions/v1beta1 -# kind: Deployment -# metadata: -# name: registryui -# spec: -# replicas: 1 -# template: -# metadata: -# labels: -# app: registryui -# spec: -# containers: -# - name: registryui -# image: hyper/docker-registry-web -# ports: -# - containerPort: 8080 -# env: -# - name: REGISTRY_URL -# value: http://registry:5000/v2 -# - name: REGISTRY_NAME -# value: cluster-registry - -# --- -# apiVersion: v1 -# kind: Service -# metadata: -# name: registryui -# labels: -# app: registryui -# spec: -# ports: -# - port: 8080 -# targetPort: 8080 -# name: registry -# selector: -# app: registryui -# tier: registryui -# type: NodePort - - -# --- -# apiVersion: extensions/v1beta1 -# kind: Ingress -# metadata: -# name: registryui-ingress -# spec: -# rules: -# - host: registry.192.168.64.3.xip.io -# http: -# paths: -# - path: / -# backend: -# serviceName: registryui -# servicePort: 8080 \ No newline at end of file diff --git a/applications/kubescale/k8s/set.yml b/applications/kubescale/k8s/set.yml deleted file mode 100644 index 59d6be987..000000000 --- a/applications/kubescale/k8s/set.yml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: set - labels: - app: set -spec: - ports: - - port: 80 - targetPort: 80 - selector: - app: set - tier: set - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: set - labels: - app: set -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: set - tier: set - - spec: - containers: - - name: lifecycle-demo-container - image: 127.0.0.1:30400/set:latest - - lifecycle: - postStart: - exec: - command: ["/up.sh"] - preStop: - exec: - command: ["/down.sh"] \ No newline at end of file diff --git a/applications/kubescale/k8s/traefik.yml b/applications/kubescale/k8s/traefik.yml deleted file mode 100644 index 9bf9b6475..000000000 --- a/applications/kubescale/k8s/traefik.yml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: v1 -kind: Deployment -apiVersion: extensions/v1beta1 -metadata: - name: traefik-ingress-controller - namespace: kube-system - labels: - k8s-app: traefik-ingress-lb -spec: - replicas: 1 - selector: - matchLabels: - k8s-app: traefik-ingress-lb - template: - metadata: - labels: - k8s-app: traefik-ingress-lb - name: traefik-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - hostNetwork: true - containers: - - image: traefik - name: traefik-ingress-lb - ports: - - name: http - containerPort: 80 - hostPort: 80 - - name: admin - containerPort: 8081 - args: - - -d - - --web - - --web.address=:8081 - - --kubernetes diff --git a/applications/kubescale/ksh b/applications/kubescale/ksh deleted file mode 100755 index 98d9d6958..000000000 --- a/applications/kubescale/ksh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -if [ "$1" = "" ]; then - echo "Usage: ksh [flags_to_kubectl]" - exit 1 -fi -POD=$1 -shift - -COLUMNS=`tput cols` -LINES=`tput lines` -TERM=xterm -KUBE_SHELL=${KUBE_SHELL:-bash} -kubectl exec -i -t $POD "$@" -- env COLUMNS=$COLUMNS LINES=$LINES TERM=$TERM "$KUBE_SHELL" - -#$ ./ksh pod_name -#$ ./ksh pod_name --namespace=kube-system -#$ KUBE_SHELL=sh ./ksh pod_name \ No newline at end of file diff --git a/applications/kubescale/package.json b/applications/kubescale/package.json deleted file mode 100644 index 5299583d0..000000000 --- a/applications/kubescale/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "description": "", - "main": "index.js", - "dependencies": { - "@blueprintjs/core": "^1.12.0", - "body-parser": "^1.17.1", - "classnames": "^2.2.5", - "express": "^4.15.2", - "express-ws": "^3.0.0", - "node-etcd": "^5.0.3", - "node-serialize": "0.0.4", - "nodejs-etcd": "^0.1.1", - "react": "^15.4.2", - "react-addons-css-transition-group": "^15.4.2", - "react-dom": "^15.4.2", - "socket.io": "^1.7.3", - "tether": "^1.4.0", - "ws": "^2.2.1" - }, - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node index.js" - }, - "author": "", - "license": "ISC" -} diff --git a/applications/kubescale/public/index.html b/applications/kubescale/public/index.html deleted file mode 100644 index f16f1baa3..000000000 --- a/applications/kubescale/public/index.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - -Chat example - - - - - - - - - - - -
-
-
-
-
- -
- - \ No newline at end of file diff --git a/applications/kubescale/set/Dockerfile b/applications/kubescale/set/Dockerfile deleted file mode 100644 index f4714b1f0..000000000 --- a/applications/kubescale/set/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM node:6 -RUN apt-get update -RUN apt-get install -y curl - -COPY . /app - -WORKDIR /app - -COPY up.sh /up.sh - -COPY down.sh /down.sh - -RUN npm install - -RUN npm install -g nodemon - -CMD ["nodemon", "server.js"] \ No newline at end of file diff --git a/applications/kubescale/set/down.sh b/applications/kubescale/set/down.sh deleted file mode 100755 index 37c4a9a17..000000000 --- a/applications/kubescale/set/down.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -HOSTNAME=`hostname` -curl "http://kubescale:3000/down/$HOSTNAME" \ No newline at end of file diff --git a/applications/kubescale/set/package.json b/applications/kubescale/set/package.json deleted file mode 100644 index f515fcd46..000000000 --- a/applications/kubescale/set/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "set", - "version": "1.0.0", - "description": "", - "main": "server.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node server.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "express": "^4.15.2", - "sleep": "^5.1.0" - } -} diff --git a/applications/kubescale/set/server.js b/applications/kubescale/set/server.js deleted file mode 100644 index 084bccb6c..000000000 --- a/applications/kubescale/set/server.js +++ /dev/null @@ -1,23 +0,0 @@ -var express = require('express') -var app = express() - -var sleep = require('sleep') - -var exec = require('child_process').exec; - - - -app.get('/', function (req, res) { - - exec('export HOSTNAME=`hostname`; curl http://kubescale:3000/hit/$HOSTNAME', function(error, stdout, stderr) { - sleep.sleep(1); - res.send("hit"); -}); -}) - - - -app.listen(80, function () { - console.log('Example app listening on port 80!') -}) - diff --git a/applications/kubescale/set/up.sh b/applications/kubescale/set/up.sh deleted file mode 100755 index 36f2e0a3a..000000000 --- a/applications/kubescale/set/up.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -HOSTNAME=`hostname` -curl "http://kubescale:3000/up/$HOSTNAME" \ No newline at end of file diff --git a/docs.yml b/docs.yml deleted file mode 100644 index d77bf18e5..000000000 --- a/docs.yml +++ /dev/null @@ -1,59 +0,0 @@ -parts: - - - name: Part 1 - intro: In this part we will setup a local cluster with minikube, deploy a public image from dockerhub, customize that image, and then finally deploy it inside our local cluster. - steps: - - - cap: Start up the cluster with minikibe - com: minikube start --memory 4000 --cpus 2 --kubernetes-version v1.6.0 - - - cap: Enable addons - com: minikube addon enable heapster; minikune enable ingress - - - cap: Deploy the public nginx image from DockerHub - com: kubectl run nginx image=nginx:latest - - - cap: Use the kubectl tool find the deployed pod name. - com: kubectl get pods - - - cap: Port-forward into the pod to see the application at http://localhost:8888 - com: kubectl port-forward PODNAME 8888:80 - - - cap: We are now going to create an image registry that will live inside our cluster to replace DockerHub - com: kubectl apply -f manifests/registryl kubectl rollout status deployment/registry - - - cap: Edit the contents of applications/hello-kenzan/index.html - - - cap: We will now build the image with a special name that is pointing at our cluster registry. - com: cd applications/hello-kenzan; docker build -t 127.0.0.1:30400/hello-kenzan:latest - - - cap: Before we can push our image we need to set up a temporary proxy. This is a container that listens on 127.0.0..1:30400 and forwads to our cluster. By default the docker client can only push to non https via localhost. - com: docker run -d -e "MINIKUBEIP=$MINIKUBEIP" --name socat-minikube -p 80:80 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:80,fork,reuseaddr TCP4:$MINIKUBEIP:80" - - - cap: We can now push our image. - com: docker push 127.0.0.1:30400/hello-kenzan:latest - - - cap: Now that our image is on the cluster, we can deploy the manifests - com: kubectl apply -f applications/hello-kenzan/k8s/deployment.yml - - - cap: View the app - - cap: Open a webbrowser at http://hello-kenzan.127.0.0.1.xip.io to view. - - - name: Part 2 - intro: In this part we will Setup Jenkins, for the repo and setup an automated Jenkins job build, push and deploy our custom appliction. - steps: - - - cap: Install Jenkins - com: kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins - - - cap: View Jenkins at http://jenkins.127.0.0.1.xip.io and finish setting it up with the defaults. - - - cap: Create a new pipeline job through the ui - - - cap: Fork the kenzan repo, put your forked repo url in the the spot below. - - - cap: For Jenkinsfile put "jenkinsfiles/Part 2" - - - cap: Run the job and be sure evrything deploys. - - - namr: Part 4 \ No newline at end of file diff --git a/manifests/kubescale/Dockerfile b/manifests/kubescale/Dockerfile deleted file mode 100644 index 3cf94315f..000000000 --- a/manifests/kubescale/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM node:6 - -RUN mkdir /app - -COPY . /app - -WORKDIR /app - -RUN apt-get update - -RUN apt-get install -y apache2 - -RUN npm install -g loadtest - -RUN npm install -g nodemon - -RUN npm install - -RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl - -RUN chmod +x ./kubectl; mv ./kubectl /usr/local/bin/kubectl - -CMD ["nodemon", "index.js"] \ No newline at end of file diff --git a/manifests/kubescale/index.js b/manifests/kubescale/index.js deleted file mode 100644 index c24d0d415..000000000 --- a/manifests/kubescale/index.js +++ /dev/null @@ -1,95 +0,0 @@ -var express = require('express') -var app = express() - -var http = require('http').Server(app); -var io = require('socket.io')(http); -var path = require("path"); -var Etcd = require('node-etcd') -app.use(express.static('public')) -var exec = require('child_process').exec; - -var bodyParser = require("body-parser"); - -app.use(bodyParser.urlencoded({ extended: false })); -app.use(bodyParser.json()); - -//etcd = new Etcd("http://localhost:2379") -///tmp/test-etcd/etcdctl --endpoints "http://example-etcd-cluster-client-service:2379" mkdir pod-list -etcd = new Etcd("http://example-etcd-cluster-client-service:2379") - -//etcd.mkdir("pods"); - -watcher = etcd.watcher("pod-list", null, {recursive: true}) - -watcher.on("change", showVal); - -function showVal(val) { - pods = etcd.getSync("pod-list",{ recursive: true }) - io.emit('pods', { pods: pods.body.node.nodes }); - -} - -app.post('/scale', function (req, res) { - exec('kubectl scale --replicas=' + req.body.count + ' deployment/set', function(error, stdout, stderr) { - res.send("scaled to " + req.body.count); -}); -}) - -app.post('/loadtest/concurrent', function (req, res) { - //svc = "http://localhost:8001/api/v1/proxy/namespaces/default/services/set:80" - svc = "http://set:80/" -// exec('loadtest -c ' + req.body.count + ' -n ' + req.body.count + ' http://set', function(error, stdout, stderr) { - exec('ab -c ' + req.body.count + ' -n ' + req.body.count + ' ' + svc, function(error, stdout, stderr) { - console.log(stdout); - res.send(stdout); -}); -}) - -app.post('/loadtest/consecutive', function (req, res) { - svc = "http://set:80/" -// exec('loadtest -c ' + req.body.count + ' -n ' + req.body.count + ' http://set', function(error, stdout, stderr) { - exec('ab -c 1 -n ' + req.body.count + ' ' + svc, function(error, stdout, stderr) { - console.log(stdout); - res.send(stdout); -}); -}) - - - -app.get('/up/:podId', function (req, res) { - etcd.set("pod-list/" + req.params.podId, req.params.podId); - res.send('done'); -}) - -app.get('/down/:podId', function (req, res) { - etcd.del("pod-list/" + req.params.podId, req.params.podId); - res.send('done'); -}) - -app.get('/hit/:podId', function (req, res) { - -var d = new Date(); -var n = d.getTime(); - -io.emit('hit', { podId: req.params.podId, time: n }); -console.log('hit!'); -res.send('done') -}) - -io.on('connection', function(socket){ - - pods = etcd.getSync("pod-list",{ recursive: true }) - io.emit('pods', { pods: pods.body.node.nodes }); -}); - -app.get('/',function(req,res){ - - res.sendFile(path.join(__dirname+'/public/index.html')); - -}); - - -http.listen(3000, function () { - console.log('Example app listening on port 3000!') -}) - diff --git a/manifests/kubescale/k8s/dashboard-ingress.yml b/manifests/kubescale/k8s/dashboard-ingress.yml deleted file mode 100644 index e47fd82e7..000000000 --- a/manifests/kubescale/k8s/dashboard-ingress.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: dashboard-ingress - namespace: kube-system -spec: - rules: - - host: dashboard.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubernetes-dashboard - servicePort: 80 \ No newline at end of file diff --git a/manifests/kubescale/k8s/ing.yml b/manifests/kubescale/k8s/ing.yml deleted file mode 100644 index b9ef1f906..000000000 --- a/manifests/kubescale/k8s/ing.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - namespace: kube-system - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: dashboard.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubernetes-dashboard - servicePort: 80 - - - host: grafana.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: monitoring-grafana - servicePort: 80 ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: kubescale.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: kubescale - servicePort: 3000 \ No newline at end of file diff --git a/manifests/kubescale/k8s/jenkins.yml b/manifests/kubescale/k8s/jenkins.yml deleted file mode 100644 index 5a1a25170..000000000 --- a/manifests/kubescale/k8s/jenkins.yml +++ /dev/null @@ -1,96 +0,0 @@ -kind: PersistentVolume -apiVersion: v1 -metadata: - name: jenkins - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/jenkins/" - ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: jenkins-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: jenkins - labels: - app: jenkins -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: jenkins - tier: jenkins - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: jenkins - labels: - app: jenkins -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: jenkins - tier: jenkins - spec: - containers: - - image: chadmoon/jenkins-docker-kubectl:latest - name: jenkins - securityContext: - privileged: true - ports: - - containerPort: 8080 - name: jenkins - volumeMounts: - - name: jenkins-persistent-storage - mountPath: /root/.jenkins - - name: docker - mountPath: /var/run/docker.sock - volumes: - - name: docker - hostPath: - path: /var/run/docker.sock - - name: jenkins-persistent-storage - persistentVolumeClaim: - claimName: jenkins-claim - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: jenkins-services - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: jenkins.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: jenkins - servicePort: 8080 \ No newline at end of file diff --git a/manifests/kubescale/k8s/kubescale.yml b/manifests/kubescale/k8s/kubescale.yml deleted file mode 100644 index e1a0998e8..000000000 --- a/manifests/kubescale/k8s/kubescale.yml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: kubescale - labels: - app: kubescale -spec: - ports: - - port: 3000 - targetPort: 3000 - nodePort: 31980 - selector: - app: kubescale - tier: kubescale - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: kubescale - labels: - app: kubescale -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: kubescale - tier: kubescale - spec: - containers: - - image: 127.0.0.1:30400/kubescale:latest - imagePullPolicy: Always - name: kubescale - ports: - - containerPort: 3000 - name: kubescale \ No newline at end of file diff --git a/manifests/kubescale/k8s/registry.yml b/manifests/kubescale/k8s/registry.yml deleted file mode 100644 index 04413e967..000000000 --- a/manifests/kubescale/k8s/registry.yml +++ /dev/null @@ -1,142 +0,0 @@ -kind: PersistentVolume -apiVersion: v1 -metadata: - name: registry - labels: - type: local -spec: - capacity: - storage: 4Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/registry/" - ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: registry-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- - -apiVersion: v1 -kind: Service -metadata: - name: registry - labels: - app: registry -spec: - ports: - - port: 5000 - targetPort: 5000 - nodePort: 30400 - name: registry - selector: - app: registry - tier: registry - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: registry - labels: - app: registry -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: registry - tier: registry - spec: - containers: - - image: registry:2 - name: registry - volumeMounts: - - name: docker - mountPath: /var/run/docker.sock - - name: registry-persistent-storage - mountPath: /var/lib/registry - ports: - - containerPort: 5000 - name: registry - - name: registryui - image: hyper/docker-registry-web - ports: - - containerPort: 8080 - env: - - name: REGISTRY_URL - value: http://localhost:5000/v2 - - name: REGISTRY_NAME - value: cluster-registry - volumes: - - name: docker - hostPath: - path: /var/run/docker.sock - - name: registry-persistent-storage - persistentVolumeClaim: - claimName: registry-claim - -# --- -# apiVersion: extensions/v1beta1 -# kind: Deployment -# metadata: -# name: registryui -# spec: -# replicas: 1 -# template: -# metadata: -# labels: -# app: registryui -# spec: -# containers: -# - name: registryui -# image: hyper/docker-registry-web -# ports: -# - containerPort: 8080 -# env: -# - name: REGISTRY_URL -# value: http://registry:5000/v2 -# - name: REGISTRY_NAME -# value: cluster-registry - -# --- -# apiVersion: v1 -# kind: Service -# metadata: -# name: registryui -# labels: -# app: registryui -# spec: -# ports: -# - port: 8080 -# targetPort: 8080 -# name: registry -# selector: -# app: registryui -# tier: registryui -# type: NodePort - - -# --- -# apiVersion: extensions/v1beta1 -# kind: Ingress -# metadata: -# name: registryui-ingress -# spec: -# rules: -# - host: registry.192.168.64.3.xip.io -# http: -# paths: -# - path: / -# backend: -# serviceName: registryui -# servicePort: 8080 \ No newline at end of file diff --git a/manifests/kubescale/k8s/set.yml b/manifests/kubescale/k8s/set.yml deleted file mode 100644 index 59d6be987..000000000 --- a/manifests/kubescale/k8s/set.yml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: set - labels: - app: set -spec: - ports: - - port: 80 - targetPort: 80 - selector: - app: set - tier: set - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: set - labels: - app: set -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: set - tier: set - - spec: - containers: - - name: lifecycle-demo-container - image: 127.0.0.1:30400/set:latest - - lifecycle: - postStart: - exec: - command: ["/up.sh"] - preStop: - exec: - command: ["/down.sh"] \ No newline at end of file diff --git a/manifests/kubescale/k8s/traefik.yml b/manifests/kubescale/k8s/traefik.yml deleted file mode 100644 index 9bf9b6475..000000000 --- a/manifests/kubescale/k8s/traefik.yml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: v1 -kind: Deployment -apiVersion: extensions/v1beta1 -metadata: - name: traefik-ingress-controller - namespace: kube-system - labels: - k8s-app: traefik-ingress-lb -spec: - replicas: 1 - selector: - matchLabels: - k8s-app: traefik-ingress-lb - template: - metadata: - labels: - k8s-app: traefik-ingress-lb - name: traefik-ingress-lb - spec: - terminationGracePeriodSeconds: 60 - hostNetwork: true - containers: - - image: traefik - name: traefik-ingress-lb - ports: - - name: http - containerPort: 80 - hostPort: 80 - - name: admin - containerPort: 8081 - args: - - -d - - --web - - --web.address=:8081 - - --kubernetes diff --git a/manifests/kubescale/ksh b/manifests/kubescale/ksh deleted file mode 100755 index 98d9d6958..000000000 --- a/manifests/kubescale/ksh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -if [ "$1" = "" ]; then - echo "Usage: ksh [flags_to_kubectl]" - exit 1 -fi -POD=$1 -shift - -COLUMNS=`tput cols` -LINES=`tput lines` -TERM=xterm -KUBE_SHELL=${KUBE_SHELL:-bash} -kubectl exec -i -t $POD "$@" -- env COLUMNS=$COLUMNS LINES=$LINES TERM=$TERM "$KUBE_SHELL" - -#$ ./ksh pod_name -#$ ./ksh pod_name --namespace=kube-system -#$ KUBE_SHELL=sh ./ksh pod_name \ No newline at end of file diff --git a/manifests/kubescale/package.json b/manifests/kubescale/package.json deleted file mode 100644 index 5299583d0..000000000 --- a/manifests/kubescale/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "app", - "version": "1.0.0", - "description": "", - "main": "index.js", - "dependencies": { - "@blueprintjs/core": "^1.12.0", - "body-parser": "^1.17.1", - "classnames": "^2.2.5", - "express": "^4.15.2", - "express-ws": "^3.0.0", - "node-etcd": "^5.0.3", - "node-serialize": "0.0.4", - "nodejs-etcd": "^0.1.1", - "react": "^15.4.2", - "react-addons-css-transition-group": "^15.4.2", - "react-dom": "^15.4.2", - "socket.io": "^1.7.3", - "tether": "^1.4.0", - "ws": "^2.2.1" - }, - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node index.js" - }, - "author": "", - "license": "ISC" -} diff --git a/manifests/kubescale/public/index.html b/manifests/kubescale/public/index.html deleted file mode 100644 index f16f1baa3..000000000 --- a/manifests/kubescale/public/index.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - -Chat example - - - - - - - - - - - -
-
-
-
-
- -
- - \ No newline at end of file diff --git a/old/etcd.sh b/old/etcd.sh deleted file mode 100755 index ee2b163d5..000000000 --- a/old/etcd.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -echo "installing etcd operator" -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml -kubectl rollout status -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml - -until kubectl get thirdpartyresource cluster.etcd.coreos.com -do - echo "waiting for operator" - sleep 2 -done - -echo "pausing for 10 seconds for operator to settle" -sleep 10 - -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster.yaml - -echo "installing etcd cluster service" -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster-nodeport-service.json - -echo "waiting for etcd cluster to turnup" - -until kubectl get pod example-etcd-cluster-0002 -do - echo "waiting for etcd cluster to turnup" - sleep 2 -done diff --git a/old/part1/README.md b/old/part1/README.md deleted file mode 100644 index f36c915b2..000000000 --- a/old/part1/README.md +++ /dev/null @@ -1,104 +0,0 @@ -start minikube - -`minikube start --memory 4000` - -once finished test status - -`kubectl cluster-info` - -enable addons - -`minikube addon enable heapster; minikube enable ingress` - -wait for all pods to finish deploying - -`kubectl get pods --all-namespaces` - -Deploy public image from dockerhub: https://hub.docker.com/_/nginx/ - -`kubectl run nginx image=nginx:latest` - -get pod name - -`kubectl get pods` - -port forward to pod via name - -`kubectl port-forward PODNAME 8888:80` - -view running on http://localhost:8888 - -setup registry - -`kubectl apply -f volumes.yml` - -`kubectl apply -f mysql.yml` - -`kubectl apply -f europa.yml` - -wait for pods with `kubectl get pods` - -get registry pod with `kubectl get pods` - -`kubectl port-forward REGISTRYPOD 5000:80` - -setup registry at `http://localhost:5000` - -set /europa for storage. - -Generate token on settigs page - -### The following steps are for osx/windows - -Find minikube IP - -`minikube ip` - -open docker settings from the toolbar - -![alt text](img/prefs.png) - - -add the registry endpoint to your insecure registry list. It will be `MINIKUBEIP:30912` - -![alt text](img/registry.png) - -restart docker after making the change - -login to registry - -`docker login -u TOKEN -p TOKENHERE http://MINIKUBEIP:30912` - -### the following steps are for linux - -edit `/etc/default/docker` and add `--indecure-registries=http://MINIKUBEIP:30912` to DOCKER_OPTS - -restart docker - -### the next steps apply to all operating systems - -login on minikube as well so it can pull private images - -``` -minikube ssh -docker login -u TOKEN -p TOKENHERE localhost:30912` -exit -``` - -build custom image locally first - -`cd part1/hello-kenzan;` - -`docker build -t MINIKUBEIP:30912/hellokenzan:latest .` - -`docker push MINIKUBEIP:30912/hellokenzan:latest` - -ensure image is pushed by viewing ui at http://localhost:5000. - -In settings change private to public - -put minikube ip `minkube ip` in deployment.yaml - -`kubectl apply -f k8s/deployment.yaml` - -view at `http://hello-kenzan.MINIKUBEIP.xipio` \ No newline at end of file diff --git a/old/part1/apply.sh b/old/part1/apply.sh deleted file mode 100755 index 292c7d880..000000000 --- a/old/part1/apply.sh +++ /dev/null @@ -1,4 +0,0 @@ - -IP=`minikube ip` - -sed 's#MINIKUBE_IP#'$IP'#' $1 | kubectl apply -f - \ No newline at end of file diff --git a/old/part1/bootstrap.sh b/old/part1/bootstrap.sh deleted file mode 100755 index 000352a66..000000000 --- a/old/part1/bootstrap.sh +++ /dev/null @@ -1,17 +0,0 @@ -kubectl apply -f volumes.yml -sleep 2 -kubectl apply -f mysql.yml -kubectl rollout status deployment/mysql -sleep 2 -kubectl apply -f europa.yml -kubectl rollout status deployment/europa -sleep 2 - -kubectl apply -f jenkins.yml -kubectl rollout status deployment/jenkins -sleep 2 -./apply.sh ingress.yml - -sleep 2 - -./svc.sh jenkins \ No newline at end of file diff --git a/old/part1/cluster-compose.md b/old/part1/cluster-compose.md deleted file mode 100644 index 36b7e70fe..000000000 --- a/old/part1/cluster-compose.md +++ /dev/null @@ -1,63 +0,0 @@ -## Using cluster-compose instead of minikube - -The primary requirements are docker and kubectl. You'll also want to install wget and md5sha1sum if you don't have them (you can `brew install` both). - -### Increase Docker memory settings to 4gb - -Screenshot of settings for osx/windows here? Linux does not need this. - -### Download and install kubectl - -### Launch cluster - -``` -git clone https://github.com/moondev/cluster-compose.git; cd cluster-compose -sudo ./cluster-compose.sh up -``` - -### Start tutorial - -``` -git clone https://github.com/kenzanlabs/kubernetes-ci-cd.git; cd kubernetes-ci-cd/part1 -``` - -### setup registry - -`sudo kubectl apply -f volumes.yml` - -`sudo kubectl apply -f mysql.yml` - -`sudo kubectl apply -f europa.yml` - -wait for pods with `kubectl get pods` - -setup registry at `http://europa.127.0.0.1.xip.io` - -set /europa for storage. - -Generate token on settigs page - -login to registry - -``` -docker login -u TOKEN -p TOKENHERE 127.0.0.1:30912 -``` - -build custom image locally first - -`cd hello-kenzan;` - -`docker build -t 127.0.0.1:30912/hellokenzan:latest .` - -`docker push 127.0.0.1:30912/hellokenzan:latest` - -ensure image is pushed by viewing ui at `http://europa.127.0.0.1.xip.io`. - -In settings change private to public - - -`kubectl apply -f k8s/deployment.yaml` - -view at `http://hello-kenzan.127.0.0.1.xip.io` - -stop cluster with `./cluster-compose.sh down` \ No newline at end of file diff --git a/old/part1/europa.yml b/old/part1/europa.yml deleted file mode 100644 index 5e2d16ff5..000000000 --- a/old/part1/europa.yml +++ /dev/null @@ -1,76 +0,0 @@ -# kind: PersistentVolumeClaim -# apiVersion: v1 -# metadata: -# name: europa-claim -# spec: -# accessModes: -# - ReadWriteOnce -# resources: -# requests: -# storage: 10Gi -# --- -apiVersion: v1 -kind: Service -metadata: - name: europa - labels: - app: europa -spec: - ports: - - port: 80 - nodePort: 30912 - selector: - app: europa - tier: europa - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: europa - labels: - app: europa -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: europa - tier: europa - spec: - containers: - - image: distelli/europa:latest - name: europa - env: - - name: EUROPA_DB_ENDPOINT - value: mysql://mysql:3306/europa - - name: EUROPA_DB_USER - value: root - - name: EUROPA_DB_PASS - value: europa - ports: - - containerPort: 80 - name: europa - # volumeMounts: - # - name: europa-persistent-storage - # mountPath: /europa - # volumes: - # - name: europa-persistent-storage - # persistentVolumeClaim: - # claimName: europa-claim - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: europa-ingress -spec: - rules: - - host: europa.127.0.0.1.xip.io - http: - paths: - - path: / - backend: - serviceName: europa - servicePort: 80 \ No newline at end of file diff --git a/old/part1/hello-kenzan/DockerFileEx.jpg b/old/part1/hello-kenzan/DockerFileEx.jpg deleted file mode 100644 index d8d9029297c8b9a798fec47fea79081d4724bc14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62809 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 wV^*_Fi|in*$RG;cxCtR99qgEOt%yj5U9 commit-id" - - tag = readFile('commit-id').replace("\n", "").replace("\r", "") - appName = "hello-kenzan" - registryHost = "127.0.0.1:30912/" - imageName = "${registryHost}${appName}:${tag}" - env.BUILDIMG=imageName - - stage "Build" - - sh "docker build -t ${imageName} part1/hello-kenzan" - - stage "Push" - - sh "docker push ${imageName}" - - stage "Deploy" - - sh "sed 's#__IMAGE__#'$BUILDIMG'#' part1/hello-kenzan/k8s/deployment.yaml | kubectl apply -f -" -} \ No newline at end of file diff --git a/old/part1/hello-kenzan/index.html b/old/part1/hello-kenzan/index.html deleted file mode 100644 index 95545513b..000000000 --- a/old/part1/hello-kenzan/index.html +++ /dev/null @@ -1,4 +0,0 @@ -

Hello from Kenzan! You've successfully built and run the Hello-Kenzan app.

-

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

- - \ No newline at end of file diff --git a/old/part1/hello-kenzan/k8s/deployment.yaml b/old/part1/hello-kenzan/k8s/deployment.yaml deleted file mode 100644 index 67c7801d7..000000000 --- a/old/part1/hello-kenzan/k8s/deployment.yaml +++ /dev/null @@ -1,52 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: hello-kenzan - labels: - app: hello-kenzan -spec: - ports: - - port: 80 - targetPort: 80 - selector: - app: hello-kenzan - tier: hello-kenzan - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: hello-kenzan - labels: - app: hello-kenzan -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: hello-kenzan - tier: hello-kenzan - spec: - containers: - - image: 127.0.0.1:30912/hellokenzan:latest - name: hello-kenzan - ports: - - containerPort: 80 - name: hello-kenzan - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: hello-kenzan-ingress -spec: - rules: - - host: hello-kenzan.MINIKUBEIP.xip.io - http: - paths: - - path: / - backend: - serviceName: hello-kenzan - servicePort: 80 \ No newline at end of file diff --git a/old/part1/img/prefs.png b/old/part1/img/prefs.png deleted file mode 100644 index 02e84db6982f5c3d456fde20a0e0234a32d4b239..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163821 zcmbTdb95)cvpAY$V`F36_$1jR8{4*R+r}rhy-9Xs+qP}nHebH?-uHX=o%i3Hb7s1y zx~jShr@Fg(CR|=t3;`Ag76b$YK|)+u5d;Jb_Hq@X?9fr z#cid@-_``tpv9o01ABbs7dA1`q0<*QkbymZUG;d%dN~@)_PX+Rb2OWT2a#kuUtgzF z#`d=s=wzZ9PEC$W>nCyf0Urm7-wevaCYE%DhK&vRC+g8JHE#_h{+_*@tmf0@y(9I#>=1CPbay8PV_RhJ{fB#&vUp)pVF8aUU=F>vWInUrxV2n~crE#g3T#qca%bV-oh^mu&n@WsAX; zhO=Qe&rTbKoB(c^bB;s6 ze6>0Hox|2d(r5Arncy6hi_Om~o{^wOBJSO(zVbjshF}J&uZo zz{k96z;mdGt&@JF9uX4l`8#+7s{dw(S537`T5sZDr&Y9#wK+0@5E)s-=AxqsBY3zN z4~3x6f;yLg^m6>`U75H3K8%IUjt61Tjr9Bj1Gz5+%#j~*yXk@bzE7_ka zTe1@SAuKfpdYc{RXCNQ(F6c~JZk2Nq6zreRu{71k2C$OZ8L$#D3U^2cw#pE%-Ai|@ zch5f4(6;T$0$;j+GaBKb!hVKKfH-sB!Jr=+W<3<(?|ubvAv{Q?lshC?6FXYmy)1%I zJ1{#Kd6D)={Q*U@RE}jD?<6}&;~M&~$AL3o2P^-&(|iipnqiDD!rpcX;`sJsSRCl} zL%6!7z3my(GD+usr{uW@FV-|aIdX#^o?eC@oZ(svvP4Fg`S#dNAB=u>T`h*ey-gF+ z*Pt&eltXZZ>h#DOBKU`7_u$m1o+p9Fs`M&ZkVj2okRPPL>|Kl5SX)}ZTJwG}v1{>m z8FvW3wEuodnAlED7Gj)f<>_}r>s7=w$28P%ets7*rQkSG$kD`+j90W z1GT3Q7_GPCY$OJu%mMAjdM#w}{xRl54^p)H+t46Dn(}uHD5$(Y>N*!FcVs(JLfPk%Pi0iC#E0 zuWW|i9NiPSLToB;XciYEyLR;E(~Z^Zw%gu#2Kh|pCpAZ-gRu=p76c=X zX3CV8rXoEj$D`B^ek)965+*}U7gow=Sx*h`hu`JirP*aO#J{1d30fAyBa0W$Ad^af zq7Lk*I7p0;(2{_XFcZ)It2+x-OQI2LErv)&84s~f;)wkM^1|AZ_@2dG{-<2Oe7g`i zuUjRptXk9{Rxq*GB}6yGAOdzEX;&aT&saW1zER$i8j~7{+72BZ9pR@AdJ)YnIwq~H z0(ZH)Mvc}DsY2m$y2eN1#1S(L}rTcSW!ix%G~4}!5r^2wzHKd zbheb9aMhosIj)ncq@PJq$=*q(H0U(R)c7i`mGf2Qf2{M*i^f%Ti?#E-1z%!r|G)|j zsFDkkYnddEf+o|_Fe*!wQj~(0YA=|Swy8{&Ju)!?iTh%E4CqYG4YZB#OHmf27X;^- z=Oq^qOBzZLipxs5iib+36sqL;{%sEQr%{X}n_@U2+(F;5-OX`iJMiwg@2SR=;V=EZ z>=<-MutUfZ4HwNGq>q-%pql`hke+bKK*)%#x2K1zDABBIXtdIqKP9YU+w|c!^B#F7 z-Mg|XSjAXXSiP%vvud(LIz2uGKiNOEUie)#S2Z^OusAWjQS7DJBo~`^R5G-*R_rEv zg_OcM7MeV;+S}TVGrhEkw1|0jHETCV$j0<5>=zYtF^jvgIKUYo{cGKP*_uQDuNmur zd8b13jE@n75$2xr-ozmN;FXND%&tsICTm(d(*hF$fS$Di;A1Yza>qQzQpVh7AB-LwtR4PD=Oy#=fiK@-;`WxoLdeGPT|fP2aYSr+oxx(!w-MY z#MmjDyqidE{aUnI%vuTU{Qx7*sCKhC5A5>Em3V5rGK-qL|lfIJ>+j%zf?7kotMJ#tSa;t}DO`!PNLAVg!vyyiUnzM83J>io|Gj*a-FQYCRE=rP z?(!kWzvdH%1&6D>kG-WKH*#rd^*DQa1={%BL47keJp zi+4Fio_{OleBuw|8;L6zH)uQPI&!au7>~Lpp(mH)Z+KZqob(RGRlQYp*nV^UehcPT ziKA|gE68M_EFxWEZsKU7ouao>+Vp2qZdMBpGY!MJTiE_pq+(6+DY34zts$>)ZQ#0o zUf`sB2z^*T*^t)eczM^`-K%%FbH{O)adbAN$K2%=Fcqi+7au|mmx+nZpxIdL<}khc zAw?y{ocgY7tW@85yfORyPiD+HgvV&-h^>{J;?S>>no+g(bom}*g_t=3+>>6_-RX3y%{S^MIJUR7QS#@5;QmwMwyDPe_!l~`) zaTTAFOVZ7Ib!5xKO>MgJl_s&YcB6j-qAm9#d~NPFa*T1otKl)_@}pL+y2{FL{u6Ft za$y0g9;v)Uz^eb34^$DMHQ&Bpam`|>s~Ub?4)kxPSFRJI?m*TORRinWn znpl>Y)Opeer!y#=S=?3}G+ZuOY2KOj{Y~e0_Oq?W?0G&72g#55jJc$_G1=HGYHk*H zwkPYamU<_iiMkBJEIAIpyWV*?8%!Za-OiuxC*F~AW9efAsdBmwZH~L8V+%kl*`-r0 ze6858%jdTnwxY(@v&kjgHJ!CgP70T-%llJqx4y5zf0@MWRU5Ef3l3b5j~iTbSI!#; zn?4SVXPakl5Kp0mbiU&5>bK%A3M)nzLn>cPUt&6`N=qfSUzdxNGjas?_MW=D=sX|m zZRgk*8Y@m6M+=PSx>@IN=T=`vtArhlPI`z>m|rEgW(Tx&YD1s5pJgsY27jI!t{;Xo zRqTFkU3wi|S9&lxUf;++PG7$zAY~9f`Z>QW-%@|h-R-R8O5`?q1HNYOf8C$;#h=H= zYd6Nxcfjgb=arOzw68#c(4%bPuY&%WHnC$YA*y}K{~7QVY;wg?!U0-6h3mgO02188 zHR`$?MO@gc>-Z3J16kbhp`I8?wXi9R5eciu6pTblYUct%^b7P_goBy6-Ntx-j6nR6 z0L1Lh*p4?GdFR8or~$m;sS}KEln>Oy--fy?&N|?GqX1(suHgg%f>30F zG}}U1-C12mn$yV6hQYwt&d`Lx-NybK8w7;go%6eDW8!Q;%{5KL-Jo3oZt2T zfEh`M{tLy~iibp9MxIE>&e4SE7XvE;6A3RY5fKr$qp>NcqOj=ykbl4NkeE9=+jBB9 zy1BVAxUn$UIhrv7e*gZ>$i&RZ%uN4{LGR>Y>ulgoZ|g+*-%S2*KEftWMvfNt&K7pI zME~JyU})#!%tJ!*pN{^|_21((akuz?da`x;AF;j#Wc*JHBY=U4@&EAtCguJQlvCcq z-Nag5*uuud*6F(sUN%-X?*GF7|Frx+J^n9BjsHc-^#7v#UoHPb$<6p50sfaj|E;b6 zf_|%u7nYmx|EQi9*8hm9{o5LN7Q%AM-zC_8O!I9x#_tE!f0y5NP!;(y?X6!RAp9T_ z!UD?fpyxU;@2Y*TekApOAf8s2#zcfk{uxux~K8GY4hoccEc-M?qhQN&O7(&?!Q1DM_K7g`L+v6 zO@jKgpaSTcN&dnO+w~VsDRC|>LS9yhF7)USYr5SMF}njYdUfS0BAVMp?oO0aF< zA9*rK1%b$M>3}5i_b~~QEH_GXQr8O-8t9-fowm63tegUsw4cX4d#4fZLN)eWlSRAE zCU{j$yy>$hSK!!%HAer8p&-M0D000ZHTO{m$@(0S$v`P?EWIq_rL{ zLKKWukr`E=IL6ZMYh80XH&(@&IE-e4fH%;ueF6@ac)3osf2-3*iYApA^-FCvYGKHM z6*M|*Yv$-@mP!)E(+rgm-H&+Z)b4l_KO3+2EkYAv3;vMKV~SLn^vNu4Noo0$cKDC!Rq#P9jLKA=FwQ4C%yxtD|S#>`MW+ko?M zs((5Q&vk?+)0)02eRE%t4hkI+QRjDR`wyx?ns0$dH+c_utek%8Uii2=Xi(+EY1a%r zWoTjUrmd4PLuN8OH4E}WR0)~A!D?U>t;6ukuhm`kL@;zCs(z%-VWf}@r=X2A;PjvrCuPGSbi4f4FFW8H32eKPYo9;(|@--R0n893@j zfq+5=+&h~85G&h{d7kQzYenTcnnDqJh##90>>4LpuNyI6PvHF0_PGB|h&BX%d^*+7 zG`~gcQI6TbPl%*5UCIsjKVzKy|1(BrS+`XSN{-X!J^ij9NWg@)%M8g0&`dV#;9Sfv zXg!}-YU`ESkg|3O5kd9d$8SxZ_8L~D6-*}bGMF$ZWVyEgBl?r9+h@ zz_N485V|A1J3i-{+Hft$fh|?`^#HA!Iwz zp@0ufXcKopk4-F_(novLJD=miotocYAkO1|JSWS|@VTk$1Hp2!9A=2nk6XTF-1iOi zd>lt&KnBFh?-Szlp~|nPHw12H!)tW27KA-P0KZT)$$eAj5(SEyfdo^A#Gh!w~*Rpm|;GB@j zn`1>p+a(NtbM?U*d*S<_+b~ibEukpKT5m4?1@Tzs-bKGM-1C~F944pRvR>T}7#~gw z;860~HMY>D=zx@0l{U1DpF{gQ*tMnzlM$u-^N=`QAzyIQxe7=k>qRsw- z=c^!OonH{!^y&GiJZxgiHVY7)CMgtyUXy=MiV=b;dkwkyvE36tijW6KG#UqjR<)eJ z23A?DGEcdh0V_|z9gafX*O4N3SzOgf#ADH%@s&<-#@t-_&&F_y$0Iif~x60 zQf&!84H<4a0fiNwM}JXw-6f7U>pzYu74{dJ>eq|bY0tfPBnD)e`Td7=ziQ?6Lib1L znc5KC`rW+%@k@4Yojk15XusES+g>$vz-K#)ZaJUnA$!Q2lK>7Pg@2M#(p3P{$_${@Eaus7We;A%ttW9*4!5Ev`< zTX-iwRjx4Iai!Kk<#ag(kJf6KCR&ESe#!cMP0f3Djg4sW^?o;1?fGD--cZV~|F~`> zxBR0^|7pWbj{`Bcs95<#ouknd!9N>*pgE6Je>je~+Jhwlf^CCBr#gUJek&|b*eS_I zu1F?o6`je6#uKe?i90;c_25~2n-c9L=Jx`(YhE*2U&+-(6TbDHW>BKsi2H(QfG}Z< z?Grk=G!9JpQa$y2*Rvs&PNB4}GVWqk=n`c+Se0R5vjrMr;!#V;YO*&R&j+`{&Uw_5 z!`@h?&_YJTb;|suB;IBy*sbQWL%B{JB(M7sy>v!y(1gZoKU)*`-;nsiCCuifP&MeF}c(jO6dly^gGDN(VZdwp=KVmr$8`SOMwXYIuD zV2QjoQly~@IwG>1P1;_PiiYBq$ssU8Z%iagyRuQN@`g8%$dw#3O>l#)gOOl%aIo$R zMzkX7{0>$Z9F?OaFGJOod9&e^g@U+Q$fMw8|kbulUokW ziFRp3f5zJpyF2Wmgv02b)$_#&-^6&wR;%=e=)Zy+Qscpv<$h2uZl2Xf~2^*F7dg+F?`-pxSyVlGUC^;C@LD6?PC_8ZT`XuiYy=E zR|OQv6@$6CSr+ZIV6^ipi3iJ+8axJb4&awwG#2eOu?U8yu2Q!^6}FHn4TY3VZU_wb zIs{iYS8<5e4Ae*(UFl@$JBR3Q^^<e;^k$x#v1-IKZsiCZTe5|&M4jFDy#eU>i3`-R#xs;Jl*W%2KDS{BuZ2zvW#{7#nK{ZTK_dn z{a==N-@oFxDi~;r{g_0Oas0lRlIQ6){nL-BzK=?{8?@cg2~3|8qOG0L(a|io<^R%n zV0Sm0!QUd(=*5UbXk*(4v$Tv0cPXfgiIrYsPVl3DGH5=-IA1yPMETqy7^MCJB*`ih z*=8x8oggbuYy8}VPo$QpuWxnU&zyc;uD!k*>G<=o;aDGcPXaifDS(={R3>C&(1Dc6 zU`2t!EkZdcRuWDp2hxz?XE9JkucR{Q;OM3^f&SUexqdxP-OdXoK$RS^vsbRQaA!q* zDoDh#6c!#lD=p`sy=Y^pFE^DdZn07%USES2V_kWi&w8*wj3?i@?wHt5Z0cHpM&p~f zwNAesguWRrRS#w@rAn_38{bF#5`Fm3qBC}7v>vFQ+I9t$q|7$Prh7dm#R@#y#POD0 zY})}<7z#dfqg8=jU3Vu{?pZ7JetR5a+==J1i=EIsOtb%eX0GZ?!bGAMC7G>eC_Wg) z`c9|AjUfq-dl?sQu=uIM^E7m|l+yL{6~PVyUFs5ycJmUc>8XeCqQ&~AFEO$q#H1)F zj#7d0gl@K-)|T~k4+VRVGdHtfvK3tR{f(F74zi{Mm>3UjdfT3@&`~PfMkc(KO8Y;I1T1sI%%L z$)E2aPB}j4oso`UA$1iOt21Ug@I@a!c2wF>@~|GhujUxixo_E!EqM75ROOzkLd$T3 zPL7cImisj79!cGTFLY{du{??Zknc(1IVP7k71E@0^Stj#a(KZOQ^^lJi29 zrS3wf#1G-ISOP5;4#c&*g2G+20dpW|4?XH}k$dYF zbTtfx%G)qG>iNtOfo5a;f;2_ygo2EEQ(ilxQZdSAk^c5ex@O1kknb?Lhltt*Gaatk z3G7VoH~xv|tl-7Wan=x%V+QZyj6zv;SF3Ed=?SjQ<4u(1cdlCvD%m^9*9FP0V_znF zPJ+5Va{MA!a(Cr}Sjl~5UL7huoDah5^C{4Lu~YKX%bl?<^UaAfx&cx3E*hnO-Lv)<&NHUZ4tWCOqQC!QP2U!BSK%gs80_ zvL*kcpB+EyT04)NNv>76N{OaMlAv14e^B2a_l}EEN^ZBt1t`yDqSY9nCrLqwg}BN= z0r->%TeJX+&tu*OK7C?4CdT`Ugoythuo#?Xh;fz+&$a z85-mhf98>RZu4fYhBu2o7-d0E0Im1*!el<|6vM4E6#1tzIH;IR_I<`f{*MBT zm^s|Qy8pVVs%x!vX$x`Syq#S-gH@ubJI)dXBk9LwPjCrua8n@}FdCN~IQg^=^Y!^o z+gxiRg>RfCA>q!dm_iL8qspMMLVsw)0+6Xi@IZD8Hxu4;u0jG9n97PV8W=fSyP_-k@KvH<_ zx5r~P`kA~lXXQq;F2$BVX25fytesyDa5TfDO4k=^NT=&UI_bR(sXoqu;byU7U*S`D z84}cXyH2eIIaqYZb9>}z`=h{UG5jVLpKU34^c?wmwpD>p0>rM5S3B>rKy2zA-Jdze zza~pbmHB+X=qtxew`Pg86>tV1L;_{W59^`2^2?TG&cIse~~vcQ99lP3eBfJ z$8)!AX5d4i2h6^Zk}rew$vc(oxdE2kGXg49fc1G}BI)L`Mv9I0cd4|G*~sgi-h=9) zk?21=)R zpu#kj|KLNq_xWr;XS&eq-Ww+*dacxwy>EYr0j*$Du@;Zl`vlwFYDe=~DjGPw-@d2O z`-}iz;suC`6-7LI^jVT?HM!ioBth80i~v1-)$??BvOii-MuH&Je<@~pL=Kx&i+ zK$c1aaxsqr00IQT=kfOXi|NnNCDt1Ao#$sh+fcK!w-SKyD)k~}MaBuu-&l`mL6qhigO zuY6|ttK)=fn6>4XfnQ8-xF&tOBzCgaWC?iB>?8%**;t~mU`H(`lJM-dz|7SKG%K~i z4eOBaj2lvASCgCeLA-i6F>osLBEUNlIPu|U= z&onOEx$D}oopYe${(ZFC%_FN;g6NL4;WGCiI_C0+xaUA$P1$2RzN0j>57aS?qUi{q{YWEJ;5j=O`k7|Ic2 zl{VDUCKv5WcR|H^C!sU<7x=QvogCBKCj*mXXZCv=MG-d#f^8Y8*caO#_(=8*6pl?^ z|8;wwo!}eVDBSoVAw|yu<|f3L#*=lw!qjFJAEXKmH1s>`spavyT|hY*p5&IwS&)+9 zGa7^ahh}!qE}k3UC+x_44&I$(Hg*doPz#{Y`WkXG{VbliJae1hTwk)Th}vh;KS`^je?g!n=?2Tlel<}}mSzbNxp z0ATB)ysAIhY#j!T(1K3?$TOBYiGX(|pfLgX}DAUVMPCsGrJYpvu#>I)_Fc zmqG_5LigH`3Q^Ke)Z3jrA^jyCw;%?!#@lM~_!x>HJ%c=iza6YnY#1w|V8&l(z@F*F zp}mVI#+?Am2?N)8J5GSLd#RSvc<#H{sXmjMVKQ1Yy zg#|V}2MbjQ<{6hF;O)}F7n`1O9jvQ-6?W)-VHo=5(k*kRzE2uVymrcW1q^DpeBbe( z3=*A23p(32&PJ#zYpoz2^82<}i+xjshiwy&{*)qWooSyc$5U>Z!HVWMDuBXBLib!| zRgBJBESy*+(b}ePU(?bsOk(HX!>NFPK!DIs2y_XH`|F(|F^)9%WJ+L542EN4|D)Jw z5E37J>l2G!;r(KQExlG6M9BpO^y_~Aw2{9mYs*0=u}}qgyd9Q$j&Wlp{Va^)o$8N}(Sfgza#8!AJb9mQsZ0)sL!;VP-}BgbyqAjqLs!?2s)={iGxxml zo9I6)Auikgx3_RMcdL2^JN*hw4wvkB7_@{Qs#3*TZ)D42%QnFaQeO~o6g&|Hq_%$> zPaH6H;f_@KAV+uoR}UM;c7~=*dxsV5K*)i6On|=v00-KYL@e8tR?I995!zzK10t%> zL}hcWk2w-|tL1`feq-L*r$Jas{tr$+%mS7(jIJU|P3RwwW_>$FJt0N-Amoe5{(8Jv z2ymS;G1=1Wtk~d;TP{FxqRs&^P}|QUzkQ7shpM+<2U@+uOLmYvhcV%6BAA;c+ch7x zmKzQ~VKIv^GyX9hT#nc~R;l*#@&M?9)0eWqeqaiZz#1`b*pfw^%4>*+6{WY5+sG;a zQ$$K?--e;8Fgsp?QH6dTsIRjPw%Of2ItW*sI;$ZLS%yXC{EDIkHp*GpjF~Gxe7XUJ zlFiASN1{HbcRv%DJVnh`mZ-xGNb%^;k)ttepIz~^oliP?5#)gEd9k`IIf0f6f*)u5 zYulxlRdCupH|*ViQRwq$dIi%KDmb}WX?c^{{oW{dMjlm+(YA51>~{yQPh}haTyX{M z@4++&k5)8rMUdG&P~F`iD9%Uz$1G^pUIN`Izy0ol0_&p(66;u+x8!x2#{DaWM}+QF zE)>)LcEsXlgtDt@6O28}1UTFE<^#v-iDy?JjLXwna~;E@q7>rXoq4t$?#4zH_D@N0 zLz?qlL1g5a6WAKvJ6$QkU?D^XBbZ{I!gpNopDm|+fqZ*g?2@GS--twy*2{58x)?W`8homH^4c4 zG>IOL{k|3HarKC?+I7OxpbS-r9k`ArbW5>z?pVU1Y8c4sS}p-!6^1JGuZYJ7<}vFD zUODgTP39SItz^Pzs%9k(X(vais-8l?y7#DLb(<7Krt~#eNbBK-<9OlG_Bp4sex>p7 zImQ0#Bl}N8>&Aq$vUaCE9=!S7#;wS$i`Hp(Mb$c71LA#qeBriK+Vydp{N5uQ=Z?h* z8IaNq7wm$u5)^&+H)5?_Ah{iUAVU+cNTq(0>r}53zAUndIwx9XrC-M{Lke^d1hMf@ zw&Z=YRlBNnSp2K(eC3`G-6h^1a`h?eeB3_2)}M>trJt~$JF`^rLSe4Mj#XK)4M^;t zux)C(&IvF6=9_KW=Dae`N7WAN>7IbmLn;S4*f~$bIN#B(n8`aAXTba5YG(6)XoFNW z@FEbrjep+At*aV711NwOag+y+_t`C#Fd=_z$-7)1jWEa&kmO$}Lt(~?lX2MMIQ=>8 zw9D+sX?@@5{$ebna&CPA{5bH`9I3~fyMEmJy?p)IZpPK$4NGCxkP?Sq+O6}PYWFp| zFW;m{b6S$H|5ASatnbPjIqS?09h;#jrSpTTESnSIrm=VBbD~WXwZPR|4nnSpP8fqS zQ^2fJht*Jkd9W@I$J`iw_}dwP||2-4MJGD zGNhrLaXb_}j}0ZJ>IOWj<#unF_ja%;DHmFgHZov2+hMML%otp~85DgR{U zk2DHuUqc$!B}Qg)RtnZ-1m&q0`xOjV-BeSqs%^lO?-*NH%v647RIPUheZj{=Q!kBrSRgHt3<)0Ojx<{MdU;m>hv&MMXn* z@=p$qJWUsExEqh+m?Ski1Rgn zKg|nV^pR|$yu)GFo`c1ccf{RIQfe!}Yq@;&A#I(9yNd8Vo6^j^%NA|3YA+u_FB(W& z*{qhRp!nRK$&m>7cF_p_0MTl9!{(=jJ_Gx=#2@CQDI*)k>TNHI?(adD_SN$Ap(Pb^ zp?SG0A4<(FDDYW+e)kY(Ls+It-cJv*`10%78{BBU$D0rhpm2$ff`fyAx#$d zGrT(BFwvfk*jy-+e9{!dQiGe2Is{p}LA_h8v7x*&h>4Q`m=o0|G;e2h_OsBSWGqpG z#Y--9GsdxCzm27WJdHaj=^xd?FlI~C1v}$D`wDM|;k4U@lzeqeoe>r>EhN#>nsK7! zz`4m+N?jH_tAdc2c`8*H(u=9|6%8`r9Jd`Wz`9U4=S0%;Q|y9pA#ns_-mi=DYhAdL+PcGpp}(vva8LbeYeDc@pM{ zilMq(*ZFVDkU6Y@tFT`V@1sbhBUD!3Uq6s1`5iE^8j5>fwutr3+FPLCaU0l@0>2&P zXCIu+Xz$J2kY9F!tj+zq!N(A+e}ZU74X`% zrVE``6s?MKFBtI+Os2sh1@5aI;s+eb72oAP5DCI}jUdyhA@RX?0UQN{_@1 zBDPyAZrS#An7Pwd)frVfix~vhl8H>SR^NZk_;!KRLC8)T+_ml0`lP)kk*?*nRP^s& z_1t%4U=ttk_phwYKR3omyTBGXWufpLnCJ7W&AHle4|TTw4?j35Mt zJ)77#GgUe;Cfe>PhK7dJrG66sHO1H0t}kMt+REcZXlMR2btP8ds4}*!w2l!pRJjtK ze9;?z%a3#lexS<#o^J1s(Iw3GH)b!_hHQYC=>DPP#;@rw}Ry{x|!@##R}f0qpx}~$Ma^t`J^dnqWJ7_|Mj@vE)=2U zym%-;=%>nb26TSDX6<1XdtW$l{)$N{vOG*q03u9THav<58wI>T|)DY`nv6)G&Q8*uHq1+=GZs| zVsPv}V|RszS%hPDBmUn1zU>u7qA9(S0dx5DX z@uSCeEm+W8)rFm72jmX!?O!Zgx1;x)L>rD}K5TdFSd-wH*^)gc2NY$_GSyXSaU&+trf1%%2RNXFAPqmzOz5;QtCD^n zIX7p8d&5TIP@eI8@}jpLp|8B&9iHL5J~nLJxjvr$b&;%Ib5Xd%tq@Qv?=;C_1OAFs zK}8c3Y`c%SAgnLHJL;%GEafJct+kP!o~YUy4$~iFIM`{^M6l@@ic65m$mT^S2%d8J z8B!5Fo0a7xd*3BbBr}C}{AO4;*P;Zno<0q?cY4m-&HSOTUmCvhfUbUOAbq${?C#I= zt2n%7^TnI@G;Spbe?4e1oo@LmdM8Dj^fYI!=KvCHQTb~${R)ZakQ5_z`oZhY&pjn1 zn73C{7C< zyqRp>j+R(*qb{D9f+abIdaZ^R@0&nwnYv4_)zFeNpOv_y|;rvvYR6r(QXw|=F4M{ z<{GdD@zLnkxCJ#PxspQ_+YDQd;3-gEcj`Cx7>2P%QyL#Rku}2`5CO=fz(qI+yYh(2 zkx(3_C+lp^`s1`$0ipuxf*Li#IqG#0$BQ=t=&q<}S`2-`w@E=Cq`(l|rrtjqX9oT4 z51W;D52h*oahv)|_*?oyYf4BwsL`+3Y^@toYthe-h^xwN7ANU!P3vUF_eX`QHu>qp zgQ~Q1uo3gUBE4ag-;TQe0mBf=BxNXm*}M{yg*D3Ibe5S<2DBW!UEb-_pB%^D9VVj$ zTDD}2ZSzqB*25Ah=M^b%I|tUHQU}b;lxkh(tnBz@Zo+Iq+c#T*;*FCy&ydbBqMwUC zPdMB&JEHDd(yz!H2OmlpVuzx_q)z@#C!Sd=%#ZKH*o%Gf&1D7Y_1u8_1kT>mpshe# z%DD|Nyq=!^I9uE~&mf*HUlJUPzghzg+at%W%;aT3heov#Efj?zOuK&}nHCrI>vCsoXCT?RLUg)_P5JxCB)i%SV=e;Pzd}?%L>uBxL2D zm{fYh=A0<1(AXaucUgWfcypqraM2J za?7&-GCG-=7fMk*`{l`j!2k?pK^R;KR?ips-Ilt_H3KxE(+nrbF2to=k}39NtjFGd z`Dl^^=~%2%U|o!+P9BzyzAm!+`opJ&rtz8CccVg;!eBwU+il0pxx9FLA!q z=KbWgozqRn*)apL;qPA#J70i;iMV(Fg!6n5r;$VADDU(si+#gts6zU-mFZbbNPgnL#k|rL{Vjsjd2NKeLT6yCtQ*#ScqwQ9J9tNHgpH4Vj2-Y-YvjqaIeFaY z#CAkIuF>_}qVRV_rMh8cP_IaskQWr9`*j$Uz}Q z2`BKKL^>^($}?Rk$kQI!$WuC8j3F^-_QS4p zZ6>`Rjkj$e?2?NkA9rK@#c~+kehoRX*+c@K){PK~XTC0cJ|>X-`laov*R9JocmuH_ zm_?daE76^oa2f0p&%)b1gF*Pvl2xrSzU0a`5lgm&2l@g!z?~UI|My8S@4$jFS~^(* zTsV*0V@xL2;rEJAMp0*g)6#10^Lej4#a+8E6)Pe~-c`Njr{2yYr>C!itn~?u-w=6h ztDedjo|v}M-Q1C9Uq#TSqMn~{VrxycVvU5qanA9x7mTtHK4g()It?1Ja`G^dX%RT= zP}-*&YG0G>GTP(j#vEulW24%QYdbm5PGaDhDp{t7Gnw9oPfSg$_cL8!)WQZ(}7PK z?B2HW>N}c&Uee_ddcGOnisguGIxBGMXsp+sh-}tIKu~NAH|Qy`$KF?Ka< zZeO)w`pi`u4jo&$F!sgu*y$(|no`?$8fHuF5)I!%@uNkey-s!aF%Uk}S6LYmDUQGR@d-E^?nqX$;eNvpI}QT^t0% z)oZ_c>Y4kkiAM${WU7*e_J~-@@Zu$((~6SwbX}+aYr&aFwlSuGVh-QgpMx@-3^j}P z97JyE=O?}>h>|#tlO>A?BYl6Ag@0;)uOZTSv4ue~A2kFn52?Z&%h3&r;ll76UUq?5l|rzX zCSG7%7UpLRV5gG24*gO0X()o8CYF?eC7aDABh8V{Wg(d~FVXnD*FKH!EwWdH zu~8Fgiav>^Ff~RA-YA)oK9q96uoUQ_kw~~@pL6`R1^~d*s~J6THHPaEe20uwuCayj z{sT+hYdW<)pMTC~()2byW+L#V5HDoF`g7SnsmyRQ*sj-kf{(lrDwEMm28x2|zz){@ z=bLwr)!Z!a+uZLogIx~RZl;QAMZXvqYGbyfO>oE$&K}aePN5`e3)cay!lhqUAbxzO zM8(Z*S;Q6!+ktI9r@9bV29CpMedI=M-48ydn(`_dg9#itSd|QZaN}Iu+hKl~}+1&O9MozdI?X{PVXXzs7ate=` zjakrcr|ijeAuyQPFr;5{yoRJx=3mJQ@|E ztScfA435xCWVYbQyo(m{YDpVD(~tvEh z11TMv{{I5}Km)(4{#6V9Yi}h_zjhDtyq|8VQ^56`;oIM~!2ab+0KL^vHtXeDRM(>tE8xZ)uNvGyFt6T^eLj)uO?q&?uR?>PheK;P%zuxzUj z#Agg^*v}X$zyUYD3)W3{r1{ZzQ5#G7)453~%>p^I9({l=%x~Gx0OYUp~hwQp5 zY+kki1`ae6u(&ZLhCMJblu6eTc%g1R7>g4;)Y;r{(5rA&jf2pn02U7H20cg09~&#h z8i%d)@)?{nxm*aZw>kyaD=Z27Tumdwa^dQqFcI(k;OwC3S%cq%F5+1^eA04Md$_*u z{2-PTDt`VcVq{9n62n>p7$05H60H(Ir8ISk+1`mEEkW~)eoryZsK>>r{}C-t&D%%u z?u!#u)Qn=jj^SB-r$M(f_7Y9n{LRbI_)>g!SAK}eW=2FbtGV}VHLDq5(SW9K)5ygV z!+Ln**2-|tw5RkMmMd^sn=87Ffz`M+qgqIN!)L>wX)BufUIH2qn;9+8T>w*X#PU(L z;B`dq-MQ`af>MNKF)8ddXdoO@`FQvM*8#rs+Upz(>Qpq5%C zGY-#NG83OA?EK4$kJc}J2o0ktv^+6v#AXlwh_i>gImjl$sw4-Fb_{$VtyZs z8NHy@Efa(dy}s_%==F7!@W0-v7W7-Ni_nQb5mEV8kHK?Y@DU@i$y>wp`a8K9Z+ujd z7HPlsyqm;xs^V=Z(dg!{lY2p%yXl8&38-}2^YD;Z%4R8y#aHzW|DO4d*nKqeYZ?VrVUVjpnP~8wPDUnIA^PxUyPTc>bUAwQIP* z3{c|v{IV0xg4wuS#{BLlL!YTT|k-rlAa$Njqg&u*P5hq z;%%eh&WoZ^LG;fP!!riYgw7}LO=01!)d!({H+zKd^ao#oF8Y~A`&Kg9P;?hQw*an) z76m4m*zn8trux^3giMLj_LPM7WNRuepW7GOT{qk^quJ26PyHvH7EK4H(WA>Q>me`{ z%gRHp#l%oPBPfIzN4xWGz*lmK8XR+W9gwY+b^C82{QB1>aCf)!MDj=z5eD{n70BSz z88q>y1eCdQ7(AbE;>^uV6?#YHRC7iM4Og*8gN=mb4wSSOrw2cpKhTa6)1df zFkIZ>Dbcs`kL*ppoDIE`dCWz1Vfg>;B2p+mVp#Yw+P5Y95>RjOYdBN79F~iJ#BlQa z3q*Jgs-7aljQ(az3JHt{*_<*Khf(k|2_a6^GP1Z-B{GQFDS^TPoO16N=vDs^?5g>2 z^BLFb#|Hju6T^LQ;>j$WfMUA9bZ7sW>tOMUEx3|?8C)`E15ExLlf$;fml&?cJIC!t ztKbORiZufM&?RKbAy@sNO_4tg}T^-xQs^xM-Nh_iP_vPx+ z>e4oR9DVlxD~Tbs{gemIBn7H3U-UZ6p86rI-|r---mnfF93^6;6R~i4c>n1Gg!Ub0dPDnQ+1s6YCeBrSoZQEFtVFDZ;6L)vvvtQ?@0R4R{5@1 z;GQOjYc(w%J?)v7;ky-uu*;F>!ueO!hlBNyAFVfs3w`6Wd*)0o0cYMj7Op;>`U-C) z_wNJ`isv^qWn#gam5j%xd0U>;0Z^+|YdHOIbDsV_`yps`kqv#(z-7ca+0D<)pw03Kf51)dppRkUU$KKFQbJ%`tLa7(7|U5%;x5<`&` z4jcf-oKP9UBZZ0sBbOiOO2GC?;Y8w8nSsOQ*vIUYK;Zx`duFB>9sW0txVF9bvv09kR?q5 zxnksaxbRr>#p>E_E-ZwdaYULno*3G*N7)mSp%VVLs`>y2PHR)A%CU#jebxNvloirr%Rgnds;rgGg z{(%l%j{pa@8UT-WkxS7~4E}97yx#R9=r?N>s*Qho3&(ZipVOm`1s@HA%h>WxD&CrX zCczzb%%lnKL%w2fEEgq~<1L88-NZ1rq%h*6b0C*36j&Nf$d38GVAyN;`oePX)e|k@ z`X|5A8c$*T5S_g-)Z_!h8636}8#n+qGD;(a1q48t<)Swafv5dh{@hTbt!- zLTs8=Uy6LW8lx?~QvH+hSrR%WFr@gIkshZn5{t*GNIsez(xv;|Q0b(TEc4Gl{s^9U zs1FpbUTw+KD)g3M&DGi^AZ(F<)Pb@bwR^Do)H(s>q@^mn~HHWo?hX!D-;XR;!Wi=uhsc`MKFGlr&X$M>j*NbNxapv*GwP5J~#XtLM<09By z#3I-j=Ql6FWtZQl`Ke%zswECq>SJ53h_xkxV?WFqbUO@s`4eq#^YdQG%{R?lRlAoi>iQ?+GZ}P|V!LJ3o({-? z*|a<|vIK^^6fXLE$3Gs1{qVU+zR|OW6JK~9-olYqd289&a2%COV1ilWth1qU^XAqw zg``{l`)}|-x2~`@I zB+V*LwBhhN(Bk~6u+RFXuynV5aQ_p$Ir>@n6qf|jo0}M_gbV=`$7vU}fhtGu4a>eO zfQpCh0ZTuc3NKDFKNd7kQo$R#6qc>t5E}liG%R0N3Q8=V1k>lP@H6>4MPL(DnoA{y z7uP-$deiJM57eZp*KKm#Wy{DvbP_Lfw)A!$NSyI6YF$T0_j;S*WlnqY~BGVhOiJk!Ryk=-l`52yBn^-sG`&){!HexR~>RQ!n<;Cgz^woLrl& zT!N9XA{yKAaW)&rHNLXL<5Vp!tK#EImq`lSiAzgbo*0r|{5Hk{={R1>>AJ#^y2w3Y zRANZ)O6KwilDbniHqegS)`e;&E-!*7hE7uG#dD!QNRF_}R`{l(XpF=*3)aw3*#F>`Ig?cBmkxFe~vq}q_@5iRo97cUutb$_Nt85AAeqL!f z=V<f*gmVfd4 zufK+W-q$-g*~G^jjy)c)&pxY+{J4oB*@pc~W{M&WV~{pBzr>KW+i~nvxm#II`dcL9 zh&UWtl4sO0!xZGURhv$rXA|2$+zt*Zw?70&dg^p|ncTzmX(JH#`{X8aC z_XPCgeUUN_pBiNrmsJTEB#5QC?bAnD?}DacS*P(dVn`b$P?$K8rG;0Cl}f52T;qB2 zRx%}qaui(q>yi+XgJ0#W27l&)D{7WH7aB%fx+)vRPW#UDHz)NIGiK*B|KQIIn0ih z3(|>UU3Dut<}_-6kVlRvyeJkMt^!1TY5v;q+Jea1A3*5pQ~8$ezGsL7sza z8@8;r8&o-PXJF6Xy3V|HS`>TU_nYALFE_&UFE&|A(I^AE*{sHj3QPNdm_tNaCWfj_ zVJkN|B;&dGiaT1{aK#Eayk5S1d7!0fsz+}*i8@C$s0K$EMN zuW3`Lf6>KI8gDV@vu#+v9$ud?0Vd&X=uMk8=G+c{8^ST?6C>H&H~0xygwIkw_xNL) z!u6fx)x~NOQ81PY*SzDka5N^}cXx`f?`7LkP1*}vMZiEF5!2>VH1XzYU9?!xZ~m@x z4VB^TsFzo|4Hp7#t`kB5#N{da;9FZ3Wc(1^_RX+kR*lK#*Keyh_+Inr0@r3Q$H&b5 zhnhwV=}kf7PQi6#d6>#S$*7EbRaAA_H(4NWC7Z-h#mLE&EP1b7+NkV2(%!*q(r7x3 zN^ET>y6GD3=v7tZ!>W?Dk3vb~BpN$vyQb}RA?#R<7={rbW+va%F8(=adu0sTZxA8D zj#`>&V@7C-B4hADBChqD8^Vwe?|~!Gr10w(;p)pD63=Do#L!S}-x7@&`r_tMsC0QnQ~SXJy+^q&CW)sWx(obej}ovqjwtSf6H(}Ma`pPHum(p2SKu0i z^h&$0e%*}!x4=h>Hwzt)gO@eG5V9I8hVfhzFH>U3T7`fBX=EyID>sM}c_frL5}t3W z&$ujGIUz1a8vGR#aKcOjhy=fmMOhpvZG>-ssd4t%K;|eU5o6fzz=NU6X*J=^$rIt# z7t|}QI6hED2d)pd9 zC(~r}?$Bm4${A(%cs8H5O`1#1sS9ZquHJuJ)kmjpC67Dh5gaI_2^}h>WHD1w7}K9f z9?8OqA;rWvsG4!}#c53aoH{%Mv`V5?e$!Z#A^%D)XjH}W;yOSOio8(EPF8GdS+i`d zN<^TIWMT4q^F7SA=!;K2g&W(nv4plaO&SQE=@pAdM8>|5<0fd#fezP^IBGb6Mh$V> zynG4#vJ#Ibo~YbJac;N0nDpWV8h37|M5ND@7$UEvRt}<$j9M&r_?P#9f{Gw)>v&wY z#L$?M#m(Rh!KC5hA>-;9r3fp|ph8y~nvl}2T|1~=qlUh{tVw=f4s++sfuZ<@kj0Df z;djrb_&llzV5x3w zz*<~9{QY;{!ld~**o^P)P1jpJp1<^IvB#xz?vEz6Ln^}Y zm#?O{rH!gZNKT|xx?s_9sHM;qgD?z6CSj;?McSSU#*!BeL>e0kRg!kbIx5*}M!6OK zjx)G>wy&jML0RJLs?`)+`!j@*$T{d*ALW#~t{7sBN)g`+XpF$cnUg|kiX$;3E}e5z zAh9@%z?4)3_TFx?UGp7$2Vs+WYWXCF9-5p)X>AUZ1zHy%^oj+A;qhX^0c6r7awaMb zeMXouh)xD$XWGa>Q87suN4pZ^12u}u61o;xS9-*&VjQK&xW*^rdRZ2njF=S@{Ka{) zOR~ik;^Xm!Fgu*wX>zV@aLje{LUIk*28Fm!Uu%4_<#oh^H-mJ>M_k8uWRha$@OYXlgmUoU?i8e3&-Nq_^6aj zPOC;0|CSr7rEfQR9j%B4g?QaFoV|LY1VQ zu{I@6FQv)`M+@baLoeoVG)Nx?~9fGpbf*cDzPNZOBR!rqS1aBpKT9Rs46hQtx5NMf)&?Ax| zdj_(D*gP8<(#T z;V8T-vEP9QLCIZrO{R9V8#inakAct|o3^MWFEl2%Hfu91xG@@?%^AiS3o03$ZLd(S z)Zi6D?zvppaDo07S2n0bkOfhyOnWD)Bq9N|@kwyr8ow2j28kF(wI?Q$#vuv=Hzh@7 z_R`u#WKIlSLwQ7;#4r@0iNae7Ev9XJnvx<|?0Lpe=meA{h9u zrp4W4=`SH5?JynVjomBMq``u1X8X2vL5i3nyPfSXMwB2hKC*Kdn*?H1NnDthYkZtB z849?K^sXdE8M8|cGtw%asG6084Uj1}AyfZTsLG1%y#!8t3hou_d!7nq?Tv{kS%5%l zothX*I{eFdqsGJ8kR}>j;;gn3=l4%kN)zI<-dOmNAS*6zALy?DVL+TIF(ltX`*>hpiMH1TFN_HT?TZkZX}tJk z?kwNxx%y`f)18@(BP~|RZ2fp76NlWXTH$1^WaG#dZ?aG44oNcjkI{-|CiF-Vx*?6a zxEgFiOlXJYEQ~W;mVv3H0t{4@!Y0<)uHbp^jh}G)3^`(qffj2~77A@;3fkU?f~BHd z9m0>#8H-yLeXw9qLZK`jRPIC$fx~N6Gm<0BAT0v-qtfw>RfJ1h!w?6>K5~5!NyaqZ z#Ly1Uplvy;#o~$y3`tr^4A-XHFK+4?F-+seo@7x=v@2k)WswO|`3d0o;QSGl=C$gE zoSO(K3JxAe&lu*mg(8pfJG5zf2hOS?j|d5n2E=&ACvY*3R19)BIA2xRrV?b2CEs}L z5d8j%_iHEK8=gBQagZhP$H^hGUCB7R?c6$Bxv2KGm!w#ebT-Q$R*OP(K80jBMGU`) z=Kd~W2QSXglz!_->c_?TJS3Swwq24*l1{StW3@f-S{!ftV0v4@5)Q`4;7l4UI+Q`2 zR2cHy>?pxOTgwP5hAzc#k~%l832d1WX_!FmW)IC|b-4#sW|xX{Qvn)aF!a6JizI2J9d;UvN?u);OUH zpy>-!a&S)7>T{+GduJd~l%B+2U$8FRQ_t?pW9$><8AsAdk~gIO0f?qhu$>I(s3*F*@1@C%a+W^pO8$^xBnqeyH-reuf3>``IYI5K1(VWQ_~eD_fPI6k$U(C5B`=kjTD4b}x08n1f}c*t7&iLo#XPtn-< zN-?sSfKf)eP%05KjR|A~CJq;1F)J7gK#8QCQrJ?P^UuW4?vHrQ>T{-+y{r0|DPl$0 z|Ke{Jc+6gX$mVJ6;Y;|`_Mw?9979;c%!|92ms4hxbZHcKtpA04@$O@N8)~nBuxlcO zLwO<_Qjp$`A<;s3`ZF<%cev~|)_1&9Be4;glFh{IQDN6OGGrfN5)#9e_`-z0{N*p4 zOqbJ=zcjrjDnen0O$XKLBIs*jl>R+RlO{$_#4?A3>Cp2i-&gimcBn#sa3 zgf+~(xQlr?WkyMtMsdgbU&t5lKGwIP_6i8QCPFxrC$b?0>FpR2Erh2(6T^6i%U)xB z$2&C=8<8p5Ow1k?c8w!L_7Nr}F{Ba0P?8st6LXS|M^}{cAC?$~5fr-P$g;ErQvMnhBTVjyv!X-W8@(GrcZPRinI4SpO zeKONV*(c$iF^vg(@O7EjE0P&c(Py4ka z6jwC=b3E}bOgSK09k5k_*6W`&XkD2uGy5lrg)4@O5$>ZNGf?}Mn;!O7S5!&WA-sY zQe@jl7Y|8F;_XUKlr0{s5@$+onPqH2{Tf%w{Gp1~EUu(Va!Zpe13EXv0L&IA8zpOP zredq*<5V1gd<=^%>i-HN|9PC!uUhT5&Z%Q!6q-Dl1}C4mrq=c4Dt&C;2`mQar@;77 zkrt)j)^G<)7O}b$B+*Hn#>|w2l`>*tDN+hI5(Y$-U30M^4#J^jK)u3A3<>Q^^n5bH z(w3x?i2VO<_r%am@_6Vzohzd{C5HQytH@2mWzT_0KG0z*OQVmukImzh8%JuNCBb6W z7SO5)RwXfZrsU-lR`wsoVWdW4N=BQtl=9J)NMpA`LcOtgg^AR~rp)d-gbc||h!(=C z5XRR_#?~&yj4ica>q;YkkvMnnE}s=bZk4>L(hbuQxrLgF&g#(H;aQDSqxhc$Sfk&% ze*=B$6>FpX`cIpC$^D!H>icvhxWl9Q{Z!&J#4&M^L}5X!PIJ-e^~8`ON0z_nb1uow z;7v(HqKv#^rQ|W&K)c3qs+`W@eoQaN_h$Q^G4v&SKAHBsjczIL(21chDWnd`oEUnJ zSNcI#U7let$lPT;Jx)DT!qfxRqQpRr(v*0LpjotMCE<9j^cHNSUGo|Qh34bS`aK)O z=cFh~V3DH`h3YdEPY9><;eC>2l1?&O2&n^|bVMHUZc~&0yok4HcVr=tx-5SF=GvEWhIIGLN3Q0=)EKFfVKk*+9Lk6T9A2*S zmIX%!UtZ%BVUX4rIOp;hDicQ~#Y*Yt5GD%Z*mH|;SsB}i~ohX3_7J`Go*k~?fA%I?wIgT z`?$XtI1V96$ZyK+Wld(;E1#B7L$ehWM}&5&Hb=-$+(EE{|<5Y8+y#?T}(M zZfGlcVn`Y{!Aq+vHW#PlMcr@L#E>U}{g?V7}*FQ3>Y^49Y9gP?U6T|Sa z$b6pX(t#E>^9iG@Yy%UzDJf)pFKulGaXBM2i+!BYNLwS|z|G%t+^+4U8|zl)RN8=rU;(5}Wb8wS5<`o{XJ`SKd#mU(lmJQ$-DeElL@5zt{nXS`|t40H{akd26;4siDCFSBwugpASc*o?qtQ4$-oBN?(JHfPTJZG>RL~; zjkDPjmzA_6E1r)~?#qqT=b7V^52S^RRV;4d*pf)RM-(F}7C|14B9lBUbB@^fFeQtm zSQA6#!#x|&qf%MUi(1K#G|7r|p6H7jXc6p_qAddLe}k#jHSROwMQLE#8DKewz!dWGl#6lWVxn6C6UGp{BO%0`mW#_t3@mnAz zeX;%C211ciL$uxa+RFpj4?+uwlanc<{jo zVJ%Marj2eT|Fy#2q8$9=9FyQNbQO+WkUykw`9e4$x52h+yB4RBwl;%ANy{|*IHQ#K z7)e9&|E$C?)DqoJUl%1CNz;7(a$ez=3o;NgI4fo_%pGF$+cnK5#J&#H2u~rvWo3U3 zXUN3Eo?Vn5X~>Gpo#?ZNRP0C|Rk4%*=Mu)cn zolT>VVtYV83g> zRGpbN1LuyP?zT2m3o#mbaej=dC@9^O9zyMnkR}XeD)s@fg|RD+g>vhNZJQ$0yu4mv zs+0VzQfV!K?Zd7Kpe0hBXHf(ymLbD%xx*K!ID#4GQM8#HZ;5=irGavJE_{ZexJx{u z;^y9g_{LNUT9ZY3uqhN?4shlHOf3TK^w9sr#z7ME4gEO;e_6bz$_wxh5m*BBd9 z(uCfEecF2=kuZr->f~P@PZA%~De9nUDnODcn1`B)Qi>ju6pJFM6Wt{$V{UUp$ILSc zY#(+_6U4;91FKEcj~OOlMVBz*i^Q&$8Rk*U#^$yt$;#Eaws{0u1QR!!B2ew9rp4OC z>}2W3H64+B9pu~LoE+hN-^?LHvZ`kV?OGCU7Z71HM9!UE^UsLsYD zE1yo;S+2Kf#TUgkb@<1S7ke{vCk!9ku*P&&?*5GJA63fIuHuf3^^xCD^!eBYg0| z2e9wH`$CNxHDHfD_7J0Z^XAQiAAa~j$5E?REjZ|)gP>%|lCWaM3Ya!+ni%!dfT*An z!P8DV4GuZv5HT9K23G`s|NZx2$&w|&M+|vlD4sE_nDUGv`tThzaxD)W)3TyECqiG^ z92zwv!%kVnPZ_1*Bykki7GK%tJI*enF)?Mc(mcj6a6mYKtOEQD#){fadLcinbY2JH zapMs&qhu`uZu4S1lDI?!5fJAWV2BJyDnhFK97R^SlhPTPWR;`~oXtgQfo+`R-A4Y$ z*S1Mh^COKP*SI9y-}(6r^QCFh&fqlreD%5XiO)w;KZUrHY`Bk*Jz=tO6ouipg7`Cr zJh=;%DLSsBy4pf=rO#!bDKTu+s1ekyTUR7*ixw?{qmMosXmW_!D8XB>U;#{@J{@kn z@kTMqM>>`GZQi^YCQh6Pvu4dwCSp%BjyrYg1Qjb*6xc0Wwg@@x$8^rj*_nMe~`??;=!e+uN@jM^atIn1tD0x@`TF z7I6}bFEOOnspL-WxlFa5>y*rghA0k1WjHM)Ya1>l zx&P%ZxwRb|*KFIeibwiSi$bBJn9|@pbjvhkXo2(r3!yo^2HV1%Yfc1seugO$RAHl- zrf4ihvyKIW0>fxZc<%Fx&n#z|pV0KTdn9spzzqDpB!G1J`ATBd&NG2D+F!83D-J@x zn;lUqn!Zh%Ty#=-SgeDSp$nzoH1C`>4NFcr-UOkfSs0AfA5&7XX7{eXucc+~_I^*v zeWkr{m=;P#u5x`)V(5FukSBertoDk-t*6PAK9_x7iQ(5@e+@&24iz(o+qG*42OfB! z@JY!WC2`}%jRU&9T&-F)xbVUYMG{DWnKNg?gb5P_wsq^);`TIED2XK9lqpmGpS|k< zo1#eCg=A3yMFABMP&~63&YW`&m~%Ki5fw3KQ81ul1hb-;Q9Shw_@8(uidn&M<^Wjx5anKY|Q0aGgZeKkUk!;M25EX$C?jc7T zKV&WA&bIK4kFe<`2Bgtdwm!Ksh;D?CxXvAE$Sa!KGE7m^7BgZUcN7*tgg`@9_Cl&u z<*}u26h%cENa)~06|ol0#MGx2HbJEc7}+nsI*%l-M>Cd3$IO%vP+1d{aho5f(FTC! zObJ79KxkANaarSakd`LWqxZqek?7;em<1n{N3LTFBPI$)XDA&A0wzyk$Q@`gNZSG| z`QwvQo7i^l!tm>_zlN)>x=P_UZQ2wD3>W~-n>QCbez)Cr8+`Q9M@qlP9(%wRTWlfv zufF;!JoL~*!nS|^{^A-$zDqcA_FE;t(YP220h{BNLY4enH z^vOzu{J<13Z&wWygD!AXI7vX_poEctbTA%YZlbHGQzVaOmY@+B($p+zN5vo-Ssp1z zmSy-0pGM$r$9&KFV(`h`Od)9&64$E?Dj?;h8cJ2XK@y_DY8_WJc_|G*=B^~F!7=S| z=Vc7|#7-9g0U zJRLiBgyW7oPE^W#$B;h9F!Z<@*JPp0eaRAPC40;pR`&jRDgunYoIaO7b<7(( zBO>mk83fY8BgKc)DVeNn>}(4sJ_-|ej4dx(UVEgK$5?N)!zc}JRO{dcdpeljvmy0} zY<*ZF(Jc;3kcY)`4u_z$+|R+20hggx=;bs#Y>u!kK98$q*T4laLyaFo8A-7tvL!4c zMwNd5l))P}N@px_uJvrCNAAy4-+U7u zeDFb481kZ!zc}uhXPzleSMwc1zDtR?@~-5ionsBojZ>)$B|DjHCyVnd#A6vL=9GFU zagH?9-2T)#j!qVYDN$YorzZ+EF#Y*i{^&F(znM={FYb9s(H;{e2ZK^tr2B>$Cs&Bd z+?FVnYUoiZvDMJA^qw;Ih?Tx-4NmMBNg$qps^lo^j;Z9pONVpJP(h9|a+)`qGB}G3 zH*ciHSbSc{o@e~%qwPT$1a7?4(=gY%aaNj(ufxL-aPD|qZa@Ay)%xWVEbQ>e{jiNk z#4`KT7Hujy<|+(%(Kc+@FnIUfcNJ%BVaV^GQXK+tF5*Y7-Pqd71tzUL5Rnq zg&_y^PPtQ|3+2>iPq6N#(osJRwJ?j&XOC5&YG$!Tn;lP@Hx1A>WV4uM5&Fn*0J=rl zByK+@&F`AuLy}WJnL#B{4R4qkiZDP}n*r@qdk{ThCqz|*Jb-j{Dhfwj4v{i1w^4UY z<;Gn-G{+1TBr7AgG0{}cgDjOJ$y6bp-7AZMBkL@Z3;)LQWPJztaYF1Eg*?Vv>VCeS zKPKu?D-4qzLs}T})60h+ez@30T-^(?7OOs(S_NNQ2p=%sgx<|32Y5Kq`2G11D2gi18ddCc#g z-$RB({gUiaQO>w+Og})yGy>X#;t~6!sbh^1pV6&iFm=aN#X*z~?R*dCW+^MTS<#fm zlYWPlhlrTIG3ZR#^I6+dkY$O8wkMT1e~dyIWMgDSA))+MAqKw}1{m@N;DsUHm5jT8 z=8+@0WK@o9J{i^LY1hk+VfXIc;h1BN5ryHjY1821i!WA>s=*z@9zA-%!3Q5K5<^cV ztHN+8Phl9I4_PRxSyc^{GwGfI!mMpi1yNoj6ov}GG*SvJ4sMloSsyxNUuWs&K>w_x z^fu$xy`1hjk!Br*QTL2>G_Z;s**^wrmOf=@pf}%ufRRw5}Al zn7nR`S!Yzo;EU?!yZ@Eb8!xa>Vq>QE%E)dET}v4Dr`Z zH~=r!uD$kJ^)q*67lxdJ7oq%T^*9$V20#1kGZ-^w476#}Mm*kz|J)we@qf5uNFP@d zRTy%jz%0Ao7{c6JaB;x&r7x#c?rx=lq%D_a5>?oUIWhxZ0K!*SX2Q8bQ8Jgej;~B3 z8)X-Ut_WSBsHkHd1PC<_MUITr9%Z3pz}}&fA~li_u%UB+85Xpg&pL-^abQXk*DlCa z&@C<|uT}l9dc!H8;6GfzpD4lq@t;I3^JTC2`plOdO*+={;xbvvL*`!}44nd+WMV+} z`6H*9u$3ALndT&I@gKYR?z`{Uzi(kSyI~byem~0Sw?Z6x)FYxewiTD;L#G(|+OEQo zBhUg7`-ogGg&}`#;Hs;xDq`S;+TC~G4dcg;7kye7QaM-h-93C<4ZkayKd$Dt-+mK* z{14uh%0HX zbIh(;9ICg0Zw>L_lUIZZvrL0YTZrI0vZykR69Y2{%}-ZqDj&5|p2t(?biyS$aarbJ zLhQUgf;ZYpH%xo3=y^n`1;!UX2J9UwUF3_wWYoP(t*>9qi=zcR11et}70CzC2 z#MHU|n9~@Fw|G&=fAgOIlxekI>58xKT&0oNV=Xr}WGWYxM{Ru1Adwo7`ZiP&+OW(S zUY-~yPyQYzPMj#d=P9n;My5RIh(gb=AP(yAn97SVAWEKNs4(O>SOnsc%FH(Jpj>I;)+V6G-BU1Vid_x(&*Dx4m4)!$cYn* z37P4nNs~lzn2#f`H3pEzmbMTpUr~!*MUM+iVOVs4S$=<0*wq-#H4^)KZj#&5xR6*=Y zm65!WW{zlzdpf`tND;rLkUwpr?9<2YWYAq8w?*Ab@%^}LuAG7P{GTOroUacYHOvNLGr9}7J$cePRGI##PN#N}hg>g#)#2iuO) zhHV<=A}Z#rd+EJg^lI?Myp($t8^K)rc%z478tS>!;Z0jz>+ab;LSl;(_pfYYxhI&D$I(m+#qOd90MItW@mswIT4AcClt&CYyYV;_w7SLCLiAF;$3^B@>6Vhml$0FH5 z-x80GFw$%rvte|#C>%JNUUjHp2#`BaTLlnk*!J$XOBOFu*m$T39gBG}MCGU&A({d@ zbKLPf@s>Hl(m=IN4v;^asm#L$8*EU@BWdzvN39NXDwHA*nr>@C>RQ>0qVWMmIlEXR zWj-KLskGb-J=~e*<=Ye$xe7Bh@`yDA51q?ZGqntKf!;$#fM0M(M>+np01&rxr0?d zsA0tAw$>3SFUy4_>n!}n*W#xfAL}t3p(?NdV1t-{z6;XlYd<@s*i2|2@69$ zbYuE)!DwO>`ckDC`;3H~TE>=zi>%cOnjO^v7HPRi5ZhGFn?4U_-#HoPzLP#H(zL-o zjSFS`n2y|ML9MZ!dZ9!e11e>M4TI9>D$FdUF3@{OfX9T0@HJh04Y=;+bD@3nmhkeE zH^AUw&n3oTBt%S)1Qdk=B7_stNf4LC%3B`-_g;O9F!<`_5zy=S%aO67ql+sSpa6(R ziM32Ko3_%p;!s>xJdgKZbE<%vF!rHhc~rovk%qQVw$eP*M`6fQ9{<=W*LtFpmX5_) z&rs9Ic6@9Jpd-XIDrw^|p&#gxkufs@gd9W^kK?lxpb}BX$DZz3SA`+6mO54h&2g+1 zhK`G-@RTs-5&L-La%|HhwtYK>`ef@pEnM}Fk+5m!@I~gIzdaU)-*G#Pdig!~ z@CcpFBB_aqfe~AJbGHN~IkfDw1-$V1V1f7TtM|g5y{|E_E9g20LbK>G$e`?d<48DU zyu}ye$hs;Xc9K%tQwhN#9O9N{x!gCJb;>*0Ps8>wn;Yy-h2BE^XE~3 zYYYl+;cTS2sE@*Mkwx0UHA60nNd0X1=N&^}^qZeW*pj71)=!k9X_TZV7Ys2@vzr1F zwG_IHQgeSR0dl!p9DWqPCIQyZOzA!9tO`Re48%r#oNd>D9EPQg(Shp}ImmuwKM7dd zF*LG;1s;mAk4G-YHa%jS7ls`|zkGtgxWZJQHX>J$a&gSA($Pj3m+urd@7n%C+>G3y#BSPkYOpcVlo6Y>!~Vj>4dIc ziqNtnD-55Oh2f-EhO=Fx>s$`SWJX9vmtoqH7^2%IaT+$GO%l^+UOY_mN z3&Ug{W=(>D{jPwY*k`Bjm5zv5WWAw?sn&FWHG<~Q_tLAOYg=wP6$bV>&yI)jIb0RA z3MXWwtQ`#j&>T);add0L^;2QM33eQc#{rQkN@CMXK`C_MYK36}UU=s=GB2(;GRKwI zz(Z0i46C$b7*`nbS@g_I@U0g+`!4Ljs$|y`wzznO+^3Iy(eTsCGcK6G-q*%8hdcxt zn%VaOX2^MA_#`U~mrCsZ`0;y~^4m;kx@c3F{rhZKYMEuBJNxk5q7bhB0 z+11|sfz;{F(T19vEDWy}veFAfj+%t!j?OLB0(5kE&UZg(J80dkF?=-kad_=x`Q!63 zXmkl!v1v*Nu}>t3W7utgVqP{5j>Vzzh~~4O?sVtT<4_YvWgwl=1)?zIWBTze=zGDP zYIO8%kd8*F?FMzQwYtOsD0VrAUZm`DtHu;Yp3WZw+kMBQ6h~YglT#j$!>RhysUV8uO+cya;dGB${0mm=hR3pw%rJi;_H4WTf+pw9^~m3$uY zJU3o+Svc*Ib79%$Y1T&!It|87$hwg$wYOS%7D1XK0n?~aYq<8tOBLk6J|}8BhRQsP zgBfO-C=%At{sYeXB95VH90N|!=Ka9o9+XT+;El>Px$xk zu>UDHt3GWkzU(Tn%{Cjr3hl)C6_`778jOGK1sLEZzS%={=bAKYcfr$GX$Do4|5QEiUl?`1MD4dGxdJ-h>}T zU(4bA7O?W#e}To>q)+;IJWT$h8Em-i*0APEU7%Hq7Vzm?qv6Rh?^k@_E^K>kVMd9xFie=8b{p;N$9zt#TJE`zfFV>K23Aeb+xsibyM~n&DlS}JOBL}nzZW< z+i&$(=)QahXu|w{`sNFG`T3{d^PlEexXO1{tS^p>e-YYwlmzCO=fSG$ZVns$bv0Om z&C#5hf4~Rh#=>*2yl=%r1x?t0h<4m%OX#s&JGOpj!elm%H^)9F#<5t(?yzEezFwxo zN8>++8PsusZm0Qe2!)|<*UQ`;d;h7M;kGC3>z`XK(;c?jY<=j^b}=z4(|?-+Z@u&a zeDwAI+_RK?mUisA2K;rM)nIAiHy3{Vej<#2eGE+efvsVcqUO+PrEbuwaa-u!_h5y0 z-*q>@Z|qw0`Ln0Nho4STa?xni99CUteOPm~uCQ2hS=mmW^clQ0=0*7S5Ba&If1Edm zZmV_|pEuup@ge*;y(#qEWD{7m`*P5d`A>MCt>ag}NaHw(#BqHf4m~OvnnQ*nF=RDv zF2yJ{p^|co+=U^9PF@KeC?ytX*ShBpC}l6k{KcT#jve z#I`65jR#zd#b?ZjJ{8EOAN9xE*dDe-_m{nt7#|&t^)PB0Z`B%_A0%&2cOg_Fn|c2a zFz4U$Mik@=;u%J9V>EXRr@?OPZSdLZBme+F07*naR0EUE>vag&`iGnaLr>jDg>vGS zY}asVdc7h4vOaO(062K(4V8`F_z6zfZ4c))ij5kzf!@sbh@CgmU9dO(TR7p6ec<&k zQogJm!^6+N0s8E{F(SY<$M=EW&C|C?=p{k%#YmAPw?D7XdrCJuKDUF>jK3s8ozx3 zhwrdIyfdL0ipTzIS{=YmnUUk=}O+yRc`#XPyIVba72QBl`YBxZvWU z)^2384y(hJ7xosBx&F+V{2^R6;6||{*kb7oV9-T}xy+Po5IL>9-p&WZp=_=AUX$K< z3a+~IX`#kUb>46vIOXuIgzURF--M3qt*5)s`54X|_!hRlg<$GN8i8S$7b3uVk2&XvLqoQed9>JqTzfSRT!b%dsCcs_VAoPx*M@BId| zuK!MWBVQ&|Vwi-PY0eGI9mA}`ut}5d@SisxN{R@8JI_4~Zhra$!PTU3C%E^;e?T|B z6_)WDaMX_Q&v8E~D;~$K|MwKEi5EL6jos+C`zA1UlH8*S6^8q>n-fkwaB~H4{iz4R zz0ZFv`jYSIY`*EAz^&MO(2>h|MmE4KEB+U$pighn&(2hK>G080eUOAJh!#$9>a+nCJ1OXRj0L2`>#( zHy-gZ-*fqK=oUWC`w+J2d5~88Z+-N+a8=)Z!+u12%B~y13tv@m8k1l(oaTHer!dU= z^wK}A@)U-L^dAE2FC+13VaPGAWY_%h-Ri8@0CL*5Ns}%x_=YpGTmWW&27UWp11*+W zj}>G`2JNvhTxqL=;Dr4)3EFby*DpQ*SKj}Uvg@(+VbEva4OHK1OnV2;9Q<~6961U@ z&cU;)&5YJT3x2c|Tqyi$Vd%GVXtI`!U|@e7uE>ohnMcCqfwLfRqsUY=_`-0FHP(n7 zqdB&yJ{EH>V^c@_t~Sbk`Q;br(s4N#WKzHRro-W)mHi|YWD%sRN)sAjT$lJ07&K}* zpffDeL7omkSy{(<-_L~U=YOT(LQyIs*3gDd6`r>Ea%MN5v=jR59Ybz*+|>`kQCoEv z9(VUY9ELv5PH(c;E`6_r3y;`JwE3S`9=#Q=y769i>UJLdb%(uS$mR0cebQhG?6z)N zfNb0Q61eo(9hC1|Pu~rfTzv<8%}&*Bvdu1V%>cOrBniQ@E~uP_W1g&afj z?Wp)3yLkZIanJw3G*}$AKlErg=eS-<_vFx%;iB7L6n$4=`0Twm!HCEI1M^z7f~k&E z)e0zS_zFW&bies9v`Fk;ed;b4bm>r-^!r>`rt3Oz^({BTUzU;kdOyG8+nLlCs;e-3 z=AIk1c)$6%9Vza9VTGZ+YpfS>zpx!cY2zvkfBJ9?oOaegb}D`vtg-PnaMw)((-i#v z9&EeG;i3@JF{Q~*9~izj6W`z7RleLhPhmK;e_!~=Gh<*@t8Q>qztiD}-O?TH>rUJY z?tbA*5kQL$o50KeH&g~A{{9B19(oA;`<)454hCLx6|C27Numenw@Z=2P@g9auz_?c zE)4lYely3S=fNxteW#K|5qEuB#J&5(^=!vb{-i@*(TJnsVdpV-j&9e(<0y4(dNH>bdi$#DA(x4|c0eg{pK z?hb!H`4s5VRzbt{C-#NU=g7-0T!rDc@4gI=j~WZ}7F`s6`|e}-_UE~290N!k=j(B# z3y(G5tn=y24OoiI->*)2(Kg+p12Qw+M*T*bRaDme+S>cO%FAzZ5;F`t>?i7H$6jq0T%7dpI3OblAXTu zrtrdd)1B8C?tjKrY^QK5WlMJoxsVrNFTXKD>2Er1U$u*c!qxWZ1H<|sm2{`W0qbok zKCDGycxk$0c-h}~ghyZd0o|gGv@o2=cI@yGJI$8p2``ViLt*T)&U)$29h+FLA3ov= zXu~Ytd~O(=ch&vMR&S_PVC@)Q!isM*UcEqzD-5xC)O`Vd{^$wVcK-{ta28!@dwB7Y zL5VEIU!)P+Z5)p~mCW};kMBt0yY|*9C$WX$g$Hf|PyUzv{3MC$%)9;x`>!L5hr2E~ z1g?Kfo`&TAxfyWuc8TQ=u+e_==?LDYtKthg}5A&Ji- z`GI7AEa|y03q#k?in$~ztb z$M2C|K5{iH#3r&rY}Y;)!FH?5{~~|-%upEe#0Q$+_D7x!yZm(}A-iY5sqp5v@~nl3 znG}9>7m^!uecu7+zzR#UO@#SB!Jrc_Htt$(4%gk3ezuJm$Zn+hM(#kHh2gWe_J^m( z{g~EeBtkQH>NLEbV&dUx(n<3AqLJ6Yd5xim(H0{-YWy^4;XIl!P9r9a-%yc(xNvKQ zq2p9CCLDJFU45#t(! zl3ny{Jr@jtCXMmo2EN5;PlU1SH&+GA639hoc)<+W!&u|i`)mUL_vs(hRbH;3PD2Bnvctxrs27-|Fg&}L$Cucg!X5_B|3koEF@@peaUcA9wolBzgucD6a=5w+vAs_j z1Y4|xmj?X+gHO8zCjKsW?o{Xww5-C=;bMvQV%JM<*}18Z-_MH9*OH=BD-36S#7<$~ zVELk;j5rW0`^Yn*&zX|n5Mvs`n5U)MNSa94tFZU*e z;g`wviJWWH_-B*LDgaJozoatudpQ>LRPz#D}ZH`hk} z@`>b`@XBLw&G3IIQgb)(qqpCO#_X`Wtc7RS`XG^-Vc^;sD5$x$vrW zeQSTD(mnsbKKzr_(AL}F16#a z%J-gtFUK--pyTOm*PYr6?j8N5E@VAg+*wMG;GX_RvoVd+eD$JEcf>edbD|f9v{+-m zp|CvLHGDGNHPlgAZ{DwP!Ldie({I@0(rqPk)e6Jpl&&n?%))Sbx|hJV`LVd`kOYVY zAj;btayky%CcU07wlJhO_aL^fFnp2~hBD4?VW+iSyWR|erS`DPhQZ0Z_7rfn!Vt5X z^N4Q};+Cf{d~x{2@W`u^wT&ySkRrID=DUxxJDNu&ml7O(7Hq#>dVQklH|68kVd(Yu zXwNB(Dae|4UK_4B`xq0>*{>Cb&a{*&#HHu@d=^A#ps{+bh1JB`HHQ8K;i+NFC+)l1 zD2qCkjG+986DLB!4mGHLyGd0aS2I~Xt_DZq9%U-^&k7>gNAbm*qcG(5k23pZ6R3MH zIzkkIv@m>h@QHBwy)WBjOd_u{yk6@5_Xg~+-SN<2r(@NfzE2K4gWc#cT7KB4L({OR zI8+#NCp-mA0nEa1`meuHwbgF9L@O9@?4Iz%>yx4jLkolmT6SPNhNI+N$rHyWg&`Rf ze~ixd`|Sxw?7uIp)U6}&Oq;_lIEvl$Gd>kKTk}P{cvo^oJBHe>-_Nk~+VYYES-6qH zFu6mQu0^ydr!eHZit4Y!1paTl{7*Pvx2?PNghPAn4n4Xp;~fUx zZOjd_3d3fLvq#`u(c6m!d~-gze1RL)3PXRYqy|4-$cJW@OA);VkGyWMT47kLSg z>9*DPJQ41^@Nj|t6ML2)zxK}cT6~?oVDug52^Bw;yx%D|fIPK(l#u<%?zVOM8Ux3! zUKq}SV|O_M20e8zJK2Y?IdIteo4|+U3x4%IPhvNg93c!o9(5fYa@O5woOz^0WoXCH z0wSL&JZ7sfBo4xq4^T8(zzQp^3>$B`Eu4D7A;fA5yEAxu$90^V*!%i8GVKzD@I}IIiDw*1}?6`U6<7)6Uv7QyV zYn*i|dB72y!9U)frn|B^;Wt{n_VxoxUMmb$Dk^T6h2iD+9Khrazxe7q!X?Mc8{atD zzwf#n9(!$);$3;iquGrm>&X73G3+;tA5yxk26>Ar(?#1Z3q5+Q3YTw~W`;BULEtuUXya|n!jL*Cee*NyLS>Q%7yiY|&3B%YT& z%1R1Dc4z2YPpik(^jgpH%O^=3Emvfxfgc{MqWbpL2iY_G<;EJPsklP?mOqJ7htR1`>9{2Xtmm|@SpqGPJ?*; zq3$?N1nSVJWm{NgiDvA%Wz%5t6uC>a3Oi*!{L*8EjkhqQ3q+x%4PMZ^IOLzYT>|F-D{ zFz#19|2(HJJt<>m_YZq_4Es5r>1Xa3^1_f`ONfP`xsynTfHtnv&2q<3#)Q`ra$jD& z<8uu26o%Zl&)|FE=n_gl_9fSZd~tuVw)RDLuI!;8st1_e6% z@H_3sq0pI7p$-3BY}I31xU}D1N{e?KD?!p|)S@*k#eV~S4tu1`FY;!l`RtcOTC-oq zftkO;)EV}hc-z073%jqotVEdn3iR!NuV|Zvp~-pFMMGh&Wb^Ue$FGOmNAbt%NPJ!x zn*L=KhF7y^7fzgGZ!RP$sLFw64X-h@zpp4Y^`P=_n|kT^dM}I;q1E6htL;vbYl-`WN<)`nlS#q<$eEB7>Z~(r1c?2BZ zXOLFhtg_QlaQCHsRDc&9yt#Oc2tRfD@VMvH9l%pR9u4~*aHbYV`wjPlCvQGe`S#gz zWATeCv@qlki^fO4blc`gc!-_S#@9>t4-_}a@V+QE-hKv_PL%IFeGB~UoLkUT9C;Bu z=8?3xJa+R9;cZqd@uEW&hGSDc%{imvD+~p8vb#5H;&ZUk?x$-=O`EO>ufBP=k{!C< z2F~Ie4fq_d8nI(2^Zz__O_tD8H=WKN7xWy$h@YOj{DB8y+g0(@T6GFTEEp9rYhYoB z#Ur)hc^sQO;F=bIJdfsXAjRZupUo2M?gRfBCU>;C-Pnh3fYS%uA=fcWsQ5*c{_;Nt zT+d&%!cgX+jK7(MAtPzI+$J#Syn__od*tWv8nc^Mt|6zQ=S+MRPQCmdWy>2ax@-u8 z&N@`dZabqN{P*`I;9BDM^w6_l)cg8wF)a+~gQ(5IZbX0fxS7ea*yJSpo;4UY?ZOI9 z_WI@hXW)XNPqG$%0yl!4*maFNk?R`EDhx;TKb6HXL-5ws9~>3u3m1meGJkZ`+x^Yw zmc}w6zCsZVl)6!Bg<*p&4EcnqsdUdClhWzUwzgrYKi4){yA?F=-2oc0-^Z-vHJ|+y z-OQW5hq>d!*Sz^TvPP3ejxD_~1Q_??SeTytB;K4EGoWp!6=023SF$MYxbSGW<%#i{ zoPXKgrTr?%RJfAu@=cjJA2!}`KiF+sd9glsn)B83TH(`eo1udo>9+IA}`r`RJ*(vWK0!I{YxMNtTFq|*%N_OlR@}0~V?jNAyo%-cC zxOC7B@aebHVC8i-hRgc*Q@U9bM{D_03T<^KyJs1vlDRK`e&5AMZL473f8hxjcHc9w zXvZFK(MA2}B~Z+!J_|$r=997uL!N+3A9@aUT&11L1#kTJ%dfCln$=45WLEj7S6z`gI zZW@~0cqCQtzw|6T|I%9ki+6y%4mu1vwN0N~@bu6N;o0|p5{CTe_Xgj1DKt(X`C-h{ zqu}Q$6X5x=@4*V29SHpn+Ei(0fB!i=^303u!KAI>z=PA>O*AN47-q$R_|-h(_X_6- z7ly7VsJBb6%eZyA0(70b7jKP`=pHC_qfh*<_JC`5W|$OjCP4$*cePQ*Z$7Df#}HZd z=|m|%np2x?NiF6l{!}K>n{Lw@n(f!FaB;|s!dWAJf;ppqq2U&6oAH^WPV>NbWS(U^ zeQlzd=E1o~?g;-H|39b4A?)GOCy|FsJB{EwcHQ4z)^67xCtU*Pv7gEdzy8Ng{iY8c z4i$zRhkwa$w{rSR73Z-J=x0BWr-k|ND4)QdotO1GaCZ7qb!AO7&{ zS6;l6iURGQVb7lOk^{be_#Ka1>wD}Ti!5yL^9UJ8>6^oj7T@-zk^CrYmKCs__S7f5aY) z&0j5+T@S7}|40cC`aAheIH~_IVS%5t>+RhK4&825%ZuNn^8Ng_+AgMLWC-X3uC>SS zWIV2h!-V4ac5e7Alo3XuF8vgG=_OYDveFH6R0uH2iLypHBu4JYOtjR>)aYEb!mvT_ z81l(Vr&6D~v>>8#-8ww^A#Ibj7K3I-cgTHOdERtZ6y7O!3SIbmd^GanZRFu!f{(Jo zaJej~-+zK3g9pKge>|_99;R-Hx$2ht!rj-LMOCW(?7i2);KBE3r-_x4HM(!ICp0}m-CCG!8!Hs~tx_d>i{2zguAv`9ST$PHB(4S&r?Ekyk#{1NY##jI1Sw9Vsv^p>-Q;PsJL z`r~CV&6ep2ci(pt^k~noa@1b~dLIW{pK&E@(sgn6$eanV^E!KrdElp^hk6X_X z^4A`@!a3#@Ha{319U@QF`)tU#iZqn+$1Du-`au^sJ+;gAW)ZpC=6k~5*>8%wUO#;F8Vnn9pZEn5`VMNcWOq3I zw3DDC*&U?*{~38ZJo?-?DoVa>n#1l#oe0~k-&ND$ub?z;ye#xS?^IZ+gFK~7jb8c3 zo$yQN9bu>B`o;S%WDmIhL9X%TdhQBm9J`Y+pYiEvIP>a9sjH(Mj>F+lx=7}8zOiFi zjc+kCbUKr!&ezxDav`J^E^UfiD-5ev7%rP;S+&w>QKFaz{>F{r?weX^=F_HxSr+`7 z!=`(*gQlCdW?y`%pR2{wIGf*S^7v1g*A#O93^*5sSC%yn!N-jPq!xxDSZ;+?pk1rE zFm+ZFXx(fMeD%Sn-h$8!l=`-6HXT0y@0Z?!)LrhIh~fTnE3FFc7|+yME!o|NQ{jtG zzj5;!V+^CBHr|O^w(Hm(+ArA{e*0}6EVkHO`1XSdEPsfJM@xW;xTC|pU6&PMxy2R{ z^VVe65AfMUdCE)zIvf%vzs40xU|}iqe2B`e!Un$qh<|-gpJLtsB!R^a=sW3yuuo?< z(~O=dccHVX>t{^aaoHB7|MH1VQ74l2Y&|d8Y$i;b)ttSzr@^F&lhuQ&eY3%DPU*7z z(lCGebZFGFCCvYI3QYWAiZ@=mnp?DP!9LIDLyH!T*i9_5z~hdbYmt`ipxbh7VET0a z^L^7{B8$cUlBg8hZ)DDuSSo6Rf?8C%FZ+XA3g7}jZF$S1YH zqEfTWe2KdfTWclzmze#&78oqjrU^9e*$Ng}y%jWGrYUdKrEifeN6zRhJzTz>ouEDPK1XG?vIHa=R~8XJ{Lq#yrV_k|&k zBjxA4_~^q=_K-N36OL@ZYK38)7lwQi;-}d04rK13snsXk$Anf?k1~6iR9`~l$jj!8 z+bQ%QbMid)8jR^!$w&~`#6)?%qlID#V((k6V^KPj-zRHTjJWTw9-5!H2vExixc#9W?x|iOw{mYQxex;6;#q1g}MUejK z_^1xswZgDkg<%KdRI)akS_kLCee}&AD-LayEuo;46)mZZ+oGKMDWPes8I{+`OCw@V z{}c=)FDs{UW-H+@f`_4paM6Yw9p(-ZafoeJhEkb#MvN7M`vLr#jF{?L9TDh;?6<&g zyx{Qc$fkV?du(=qb`5ISDS|utU@PLGj`+o<+B$;|Oog=zctI z+%ZhYprfVo94(W^fOMCIDZXJY6e*-jD}AlXA$3yV6Th$Bm8_CsHt;TEl+(VejWTgp zvRN2%5N)os4pQhx$AnP>dFdhIWEc}i?m?|B1ga!{S`(c#q0upMVtf*aC{uK)*F^EIh!UxV&oA!A^gJ1P%88GN2N3s6ZirA8pU4!jT}LCU4I9- z`jYdZOULAn86*0;2cHMG-1VgUI#k0p?dAv|b*i`41{-X^e&vN-22*=gF#~zlg#2s_ ze?r=!=3&5Z2a2Ne>AloWXPM1@Y3kM2UQ_Dak?U{@$7&eiWEFO5XVO{MQ@|0_HrFGPVXbsP#p^Z>Sz@UBbn86kF&8v)v*=v%-=?~Yh$qv)Y>Tr$a zabx=4^lobhJr_AbaELt4S>obI#XYlPO7x`=xIx^~$hfL##^X|JqhOGWF4-Qsb?yi= z*e}tvU^k`A{pCmaaKbkQqAnOf0j9EC)?9NMSbq8C>xgY( zrioi0GDGPqNn3XA@*wKoK2OOO=1hIR{`zZ}Fku3L4tWx@6oLqo_pt}UcCjTISg_+E zAv+4f!a-3h4C}Hm>#70!_6w>==o@4aN@D?V2=DHLk5`kYL68$k znnk#i`iJfOT4P9lLqk(JGkcIi>(;R9Dyy)^s-(a8VbIjNrDP!QY!zJlKYIiRS)a~UaGq8*xxyoRr!qe1M4LGz8t4K=6hV2sRI8?D!uLq&`FwnX^#*U-xSi5xT z0-ZW_DwxN*%~3oX%~EV;W6>!#_ldq)_pzo_fh)*^=^xn-?i-9My=mS+i!qi^KNq+nb+&dBe|TZ;mBv?D60xGJ00Z z;KR*>pM`-~fujkb4NL0;K#Hp-Po6A_!dbIsCLjS$Gu9BT1%u9(B1O?mu#>9&Efdq> z>k!on!v<3r@~KTG(J@i}iFfRfsI}k&QU(s^5R<8s_ykQD_*hME*{9xlJgJ`>xwtew z4wt1CnQ6e3rYL`$1c5a3UQR(9vios6vLQ?ERzsh7K@v&JCn9&Xe$*U~x$mm_6i z$Ko)k9Hwdvie5F8s?r8Oef-^b--&;-X3Yx26^`BK=opV>ng|@G?qI2*1twh#@j_o1 z_UMs5;1y2=V{)X!`|LAO7gDq-`=+ zf`z`>(PvvQti;HSQ2Ck)bigoTjtVTsINqj8uqr1slIn0(2bIRn+d2#HC6lTvOt&ic z>yuLjHj3J@(pDB!U)!m@h2; zcpuxLaf;ma{0N5VGx8psGTIH`ba+qpMf9X z)phiezbLC2eLD1_h$(`vr6c+ z7)l`w(Y~vVGJYyKbH|YI z=o6Vjc`*YbkU%&QcT3Di=!QX@#u?ts*&b}$U5bp7f%I}v%z^-Ds$20GS=g% zz*Ps*dKI9?xEf2%alHaMPYFC@Oxb($jepJk% zjqB5d3q!>5d81zc?sCNE5T(AP#ff5Vm0NanT1}+*z)a5Du<_sAahEJUMZkLK3?x!9<}fBNw9EJ>Jso?~$@f$OwrTN>1_DZ$#|vW~N)rurfgiuZEY; zk-9dD-0{V^SBrpzQr)IKHjF>jpd^VTRivQ_6PE%_m_ed8(1gK4Ul?}o+!-?^j(9ql zcU*0h@uS)1cQQ?zHZ8fva6u{zwG?O_x@bbnOmnKk4vnu4X?3bxLF6*lc>=w{sD&K^ z!FW_|D!0@FQAlhusC8^Aa-fG@!`d7)HPbrD0G%(jI=nRjv2aF5(KG|g(QB!>73z?k zPK%aRJx*rZFi7n*cLIB0oB+Bl!URP}!U&2iXZ=)tmPCFp5-zk|dZ^ zVXRrIFau99$Wl>83w>c&y}OdjFAU{WrW2}W(P)I0gJBx%x|qts4iZNwU9oxHsBxJC zptxRgs>tm?owaspNF@OkgDK{vB_g8}WMIl7%OQv<;>oti2)m}P(+uEz8LI)s8L^;O zq`5>BPU*RhT)r9cfa{xH^T}Yt0ck#V$1=-+H4*eM5iJ119MHAu)9B9x8g( zP<3J+ZbFl@X|rG?sRktpG%5^n_NQBtA@nDa)(XR_J+3CZFtp~8OpL!7@8y_pKdhk% zu~dR<&=l&1VpD)oMu~OifDnurqDT>DHF7&>fR%Y`P-&+E&l;3fw)_l44DRQ z+-zypfU~J<76mfE=Zn0zIYJ#wp}OfMp)QA#fn@^e2Ap1(*y-RYF<&ZUma}Q8_l3D~ z<~prIj7?x>$3#AB;+Txb^rsfGtrdsDT>6AOWB6^RSc#5q#v!$a6kQB)cBX2Dp?6jq zH*W0J;i+OYpnYu9BY&nL|0nKBZf_KZZ1SvmL*QJ;cobYOx!{>`7DG|oym6TJS#b&b zC?gZu=vxCMp!$Dv4M$&>`1?#e^5UKzKol1MF5rS}#<4sk16b<@S%OLpra-5v;05BT zFP8-=55}9mPC}O?oLQqYLdiXQnV(S_n;SkdhOCDwAh?rJai|8Gv!ly{*(G9^2Rf&o zX$y6(qbd&hnL65c zwNb_k!{r@?p^2Zr@0vnCioV4BcBUqVr6{(^72D5@Dbpa9$z?~u^NyVQy0G1{VqR`6 zOIiTDfQv<&3d%)Gann|iA*f6-Dr?mVNo65c-FrdH0eNrNN$8OzB&^IS6OdUBCGkeW zcw^SW#7+Rz7#n(+_$fl#GHtXzyCH>R;rF+u%jo!G$Z(5NrxzNaxg1YCXUI~|jozyj zhQY;PE)?2#wNWMu!)0+c70zJuiz_k@}X?sxzW;!mSF*f|vvL-mbH-3lL>} z^e9N5p)$yxaUTTt%mL#i3gNq)1gGw#_h?vU1n3IFEi>bATg6MWqR+=?T4$jHEc8E# zx6CrjXtRaI9SUh5+w@4=zyJO_{PD*h;#BhT?H7*15c5~RPoz8Jia|3Y6FR_m_h z(h5V@42NdaSW`Jnm8XkRDa&q{WU&F8er3m{@O(rvP@gvT1DFoikEMbMH!23O;md_A z7tM}VN&=52^|{o6yl%!`2Ls7Lv4DIfh)ww3>M`$5DWbLKJWhri5bq3@uLG z345to+VVkGQ;zY3IO;b-8Ce=<+QOK>`u-bOeDNhjS6ze2dcHO{q&ne9{)BYIEV|if zjWyP&Y7QH8VHi7ddtS8!d({qnCGt9H(8W56B*I<9fex&L%?Q_WOhSadJ;9KV9TlcJ z(<{@!#;#OS9%Xq*!7(wKI${cj;a4{7==^aP(JX*t)k4O1W|6TM@zKbO062W;7z*Me zL_v2)P`U{5b*b!mISV3_DVH*%ou)o(Rjhk`-i77~SAEr$uWyTao4ySOi(_%mHJl(^EV=u5hqY zi@{~vXN^?Thp9Ew?2ZeJ#_dLMdD)h6R<>UiBrKE$6ir}&3r3WI0Ys`6z;Rk3XTMJ( zlM!L2lk2_IJ%2>#;X_QZ>!pR^QSzuzU5*?i%9*lNrENynFrrF_D&sSwl=_9fFrBUn4C&ikpZc?PTW*z-wEXo&ozonSxS>>ni`l+Y9y&i)mkQZ zO61q1Ho01*10s77V3}jTr(c7tb$(1j@<)c6^4AX{^D)PvQ;#~&R2>p7fa7$A95<^) z6RT6|y)4YQ$j~Yub{2O&J&(b|kKrMp#|+i!(RAdRXy+8B%B{f2tIQmRm)UdWkl%c= zke^D%V$PL9Q%C!*Hp=oBhMb*DP?>9+zzP-%TNlWl;berzyYVlEs3;t`nLx@pu`Gg- zN#Zduxl=R0Cbfxbl?LQuD-N!EV$OA`i?NWbB-k)aSQ{TV<|6fQA=_4|J$XY=;h(VW z%1i?uW-#3Fj20c0O=(MFuq%nqWXy}j{lh*~YqG_RE@VToxn0@#A?^iV=ld<0g}yLc zVhMSHC7og{@KA<*JaRd<>2b!48R1jO+)-P{T8C@pt4`Op+#_^Tdg8-4okus4ZW@d0 z!ix3P8L{U=L>(S|R}P{+1_Nz_$I^gYEXBc#d%EI?kmVrEVM>ULc@Y4knXbVQa%x50 zLmt$wyms9)^4L>WcOD|gm%>PgykMq(B(2{pZvcKIcW7>@AI11e2^l(cF19=)r2c+C zs-Yf^fO3l{Hg_%?KX*V2l!MHknZw$SAyn_?6UQ}%V#y?vV9!OmpmMKmbO?c_@Ole< zb!px8Trp?G{FkSv` zKa{#W(s2}PAvStfg9EYuoJTW*e3Z4v)l})XlC8(pxYm?wMsls|kg*Hg3?k%j+BT%V zJ~r1Vq=l~0d-XJ)st4gFa7*hc2b?wusCsc#4>=8AUx#Tnb?(@o4NLutwG^u_tYWY^ zy;KxA{Sx!M?&etY`bS1-(nvSAGz-!nqF)oj%o{~4OBSvV$L+_ZK9A7ovUHTK8u(fK ze@^{E|C4x2Ewz+3vv_J4g|v@t-;qDudiwO~?gv~WpzDZhJJ-67HAZlgIMzRXJNuAK zE-C7Ohzu)tGYPLcQC0_)j!|cztBYIdTH)sqQM@{7 zn_*Ukw1j~cg~0I@^{*%&NL~?0;#_P1SrHUN4WFXU!n9-Jk}NNG4$;evNqx|g%4+Q* z8Cd8GLoD)K$uo7d?`osW`IC4qg2J-AZvgt1%I9lZQ>4P-7j!gZiG{(Ki~0w7ssid} z%%;k=a3fbJWwiCgoCIE7_AolGE*=W8B+Ux5+c4eLuuB?fNig-7ER~Q7LMWC5%3KV= z9Wuo=E%Ndtzea4rWcGbLGBz_ppLG@u;@JMS#KuBzTeILwYK0+Q`{P`_gL@`U%r;uv zeCn-j+jh71v$bv8wzW04wzt^Ywr%V5_kP!R-gBM5U}iE&CduT!lP*ekuO$8-V4*?_ z@Gk^czs7`a9z_)AIeo6mh$@!OVBV(hxRRpntmQfk0KV(YtzhFMcm8~sP^1?`8rtXxit<9W9 zj%NW4{3tqtB!Tygks{2f3I8gVhQh~;z8e_>>^SJ|?L{oM79_N^LWmVOZ%ZY=y#Q<; zT)t}~L6Gj|ZPB;|FGc7)&$Ns`)25s*8-fs=8bv%&KA47}IeXw?DF$_q+hZ%0fVRfJy?!xk&+$X%gj>v9>a@WG@0F@@ z1MjhDwoTTt+2|JhlJ7*MxZgf1hI1@)CVw;Ac7v-*e63TK3`wo<=-$Bdk2989`G`7SnxAHHxK=UNFhDw+-NklO+dl=~sa7j7b^gw~R4mVY0b0 zP)HQ=w`ksjs-z~NOU9%A+C{-zNUOMtr($IcJL%-&EQ>j9;5P3MBg1;nH=&ewO=H&o ziO1X!Xul~a2%T2%y!{6mP_w{SK87`|1x0cbAe15@i2NH=o%12v;Mxbuedu`YOq^(1Q(&Ab%|e z=h2cu#e#22*PsS9^A8`9L9TV~jaGhMm`M=Bdu_v#n-Jl>hIDGjb)P?cQe{_98{LtS zW_M4Z49!~`8Zz7~D6Q@T+!B5-OMn&X?MRc={-PX3nF^lvb5lI%kvLc8Pl70~I;5%* z)iN`9QU-G|@Y;J3SaoVH9$Xxz#gotRjMCobE80AhpShD)jh<5=xYld6SN;p?+DFr% zGU`qv3UByO#-KQx*c#h_Q0qG_Rspu^zL|90DS3;`6(=`4<8pGyxG;8=?(Lrt^E^?* z|GY^ogLKweHW4|n~aWW5Rw*%F9RGW zDD?QbSG`f)cN&K+>_yv*3$YZEm1BkQep4gOPX4ewuPYvUEW4VW3TMOd_rnkM$#Jbj zSF@d8M{>#hjW+Um4^Brc$sVo^MKk7q*3lcL`O2FJ>gan{xjB55dPe&E`eyeHVZIdm zBZenV`k&4u@rDxk)LoJ&ri7aRBowc|^Yiih5CzL?5I z2A2{<7e;MT=Geibd>}GmqI=-13i+uh_zi%shSDDM&jtMy=vVa68}Ratu^A&T?xvMz zq6JtQQYV4fcvLg7MGEqyXdV|tKkC^eW6~fb1QTAo6l(kFR6}C>t48+tHW797Sk)yY&)`r40 zg*wKa{6eBKlj93zYWXQEdKAD!`cu`xn<5_*hP^Hswu}C|i5IbriA^Jh-)~h!b`lLw ze_omatzEV8p@teE9kM;k&hVwGGCLhEsC;^ZwH1X%&yLW|X5rQPc2pFVJHe5cOIZec zC^RMKK=b!(m=buENq#D5D(D@*c9R`KshbJ>7*GKw6BShM&I>Rx*h3{T!>k*k{R5}t#*u6Vzri3hQV zXjqcg+#-w8m{0-2ysbd_UjOt5ajxBEeK(&7zE<}ONqIMW3@2Mns}xn{8tGd9j${rE za{c|)JzHnv0YE$_@{~Q%^ZO@KzM4i$idrT|;WRJ2D)Ia)Vpa+7pGaoFx8Dp40pbvG zcnI9;d3(H{-SO{4&9RqwJG{ojFB&nl$^<&^9N^|78p=9?rrKKnHG+jx8QSlnt2suw zLpSvbhRVDkAn=?}GWn70V4`X@&!S|9vwih;`#mA%f2{VM<+CF(swRho=*77lgU&V&0o!>pkYA8UmctGXsxPf!mb1|gG4zyv6qtXULXU@Wu!!9 zw%Pxw{%JU7gcJyhWDi}VrbQA#vzy}#(H0&cXdMGWV&ZTKgs)cgMG{*{0^JOl;OKUw z`uKi}S#Mj`XiL5V4k2K&kSJ9lWB+!7`9rE{<7=1xFbr~~<>>vTkH~}S_qtub)dH^x z_X`V{5fr<_`csp-C#pe3j&&%y8%IRIb1p0CFL5iMMOjn-G}WiMW8JhU&VRN>+rTuQ zDHL5@PihjOqxr`hW94W7XTz1DoG@>Zbv(va2#UvS5I#QR0A#P;81f~f(726X_(bU%|T*aYmvR+`+q zU3>Pdx^L%vQ9W~T=fm^(T%E6C4@FF7qjTnU7_0+p7PnT2myF(^j)c2rckrKu0pU(DQ%|LxL7MMFa&}#fw#hHDo zML>*9MVYU`*D;0)e(fMBR=sIts>Ob=PD8VjX#xtd2}BGujVy3JDYQ4Gdi3&?=!m4jV$lL}?PY|vF#@`Xin*+0tz2v*Lj4R1G#)T2L zBP)-X62zq-#w?E<1s>A{7iowSAx&(MGQYf5^X);(mihV(G4RX$Mhs&p^|D72u3AG4e|6g3E$g+R98G&0ws)7B z_Ztjv!Gimndw=ffvI!Usa^6!ZtSJ2gP(ayQoW{_L^>trSU5g9_Pg@FirY*q@ z&|rp+(QoukdKHam&G6|pRN??~G?5~*LUPscS3j!@oQ}xFzb<>_3GM#I*d2&6nrC%aq3;(&D76`M+EMjrHTu6*|M?WhA#8?^HZl*#6YJ z^rBSk8(jot&3+ffCuB7-3NQOj>o)M5t?j&Y;(@&k%}v+5Pa)pTSgV+aj( z)4dTV7%ca4N;tybA{^_FKhl+twj9Zr{(Lo6W4(12X`LtU)S;s1?ae%M3&f&3erfOv ztaSWs%MdN*rMq5FuLKR%e_)UX0pd>|~!AKT}g;^!Mum=nv``#bEUTK(aOe&ag6v zPga#8x+fV6*hLyGe5heVE+D_rA}^o3n%)j=eRJW~<}a&!TotTAh$nJu>ApoAHmk>| z!|o}@L7Yj!+qxXzKYM{{8oDc2rt(N||8Qw`Uqs^hw5(-odZ78-hQ;B2U)AvM{H=9g zy81RtO3IJ|5yP0O=`wn|w{p3$#5bFK(J-uNUnuXduCA*SJSfDc-cQaxoGy;Y$g_Z~ z8h^>l9^~%2^1}Bhz>H?Ydr$~5*h^yIwt3ixO6-g9otI(07Pwdk$?&c+Cb05_EgnJD zXtg2Lf}Lx^xdI?V0k5hNIUD_VK{5Jc1{KkwJ-^;KTSkQJw^jg}fJG$OhO(3kDq4sr zix0j*eV+Fx&UbhHcz*=-^)G9>?d(7aS%x+;Q}R+P2Pcj1I>6n^L^e0N`pM?NLE^uv zQE9b{A^?j-Q20_?hQ`b~sUIxR7C+Q}0D) zCXe-xI`#r$xRXgZB_7%%67-uuFJQa3tZLTvKv@k}c%lc1RcYb`iGIrR_SfsUS$IL` zY*FNfpioa}JS!=r_+aY1&2NwWGqRbNK(^=QHXg7%9_8{?>zUxe3F{K3h#}Ya`>3e` zkGsQ?(&J$)-#@Mji3q@=;xzr$Se}7$m8RP5qE-gHvj>jOE!RhDA`%Ka+k!|?k0h&^M4xlPVz z#iyF-T<2QVaYY!m^F3qaY6l+QY_oKVmXWc(bDaInb3}-}l(&(sax}`KYPdf>3zf_BWT(du}E*PcXoS;g?8yWriPL+qTsZA}#nruI*BN6-Vg^6RCrPMy3y@7hkJI`44wG znR029WTXT^Z-{?;$vpPD4>kxTNge+OZw3&r6f4{2_7Sq|daep$=q zecN~}0dG5L+zo@FC_GB#d zlCMY7PWDG`_a`U6fCzsZ-dd=vsvaokt64(RsclZ1@j%5*B4oQ*k2$A-A@Ad5A9hXO zQSlW-R@Uvao2$Mj7*l)=T`zv~wMNwO*9U0#qrHe-pSImoD`8sGmMA2K9RmM`iEJFjbbh4e4snGWXs zgloGLe;TnJ@%ZV-hZ8_*;%QnHxfp)r`hj*P?hlU|^h4Wq!hN|!GnOz}kKJ~YjPd$q zaMHpOzs)tjW!5dcS_y}dW1DqRFqs`PUVrK^4vg&&Q8XS5H|KcuMqa!i^05ME@viFI zk{zCOUBopTJ&atx=``I*_U1b>cq0w8dEewygfUS~4&OL}3QKI=al+FdBLg{>5$Wzib0v_5`1;rg?y#c&@BO zPW}BnhhoRfH~Z^ZoB*;)aJANU1_MKv?Bg(z-##ru0@X0j4Y{~56*#%HX5!pP3BYK3 zSRt!_O%V|_@nowLq~n|mL!z4#Y!z-)j>|g+ahrdp`D?oWde-PE$S!RIH}qa`lEXML zp=uk~b5Ba`{a7MrC%wT-^eV`8_HP9z{3N%fAmCvrSga5VA*?=2;Pqiub42kMoN7nTbM=3^} z5gLTGnr`~{x4u5Oqo5hLfg7J%3a7C>0nk_c&Y=2&7{)C^MC@#5xK6Y4id#JQ$#u!e z1M0ABkkSnSh*WZiIKNXU4x$!isu_xbCg)=K)8uF|B2Q%W2JHq=vwVg{Bt6RFTXBEo z%Vi7uek{;`By!Vq`gk;ingRnCqVC$)VQs(t{!11TijfI^? zHR92?tULa}VF;{!X^rHw+@8&1**xM6rFFfO(Ti&0M^8&Z`4AMw5c8z*tLTTxaJ(B( z2(wZY)RekB_xo;yeQ96*;Gu0x*p2KhSJMXga$JII{yC}$Kj-^=dfBlrR2Q;uP}>Q> z4juR>%i-{NK=cpLW>Bn-1G)skul1U;aZ*B z!>qGDJL?@Ee|$bz*&oLaSL`yW0y4#S&J;Hg%(6X_XyA@Skz0-CnKbQQ{^HB2vO#}# z-?d-kQtx{pO>t{Zk~a-DYXM3sLFg;ItDO32;!2^eCjHMEW^FPQwXx5jjTmESkx@t` zeRDJTYF=0}=2l^Xht0$9d!72%3_(FM^Zm8TX*iZaE`p^EA_znqj#=OM$kL)iGmA@` z|6E9nG4^z_>;0MZxELpyx_3J%M_BV7u1oGm0sn!Xo`G=WP3pf_g0AYo0J@2I=>deO zO2sgtJg;x&f?RdI&;#D{gNut9bh3awazCm>EAY0XNT1*ArI_`Lavw`CkWVeQ>|c z`CRgvwqN3AGIO9z{|;)6Hu=6Rd@E^P`*PU$x$H(AU81>R*?2NgK({izoJE^1nJj-sOpAjc{yOBHJMxUn3T)dV| z)4H~Q7d@)H4%_lUzfy*j*D^U{hLk21#s?9s`oUy3Pnp6!J( zz-}xt{kb_FjxNjmjZtdu>QFPD%jtYXG|6IhIsulefZfllv%CH}uTo5Jroa2vV65oE z2=_0C{N-d67Wn4l$u=5Ws1kxd6wN;0Pgu`+S{f1=PY9WAC&CJ>9HG7PE*3*Ix)q7* zOt3;3WANc9A2<~sngWbok%Kq8I52JRN;)T8&tow{a2WMBeQCa%zy9zB673_8F6wV= zuS(j5(yMDrNNxFg!r;p*P|gO9(;>{=bij-LE&v3*o~L{rqDzo5C2rIRbTSR*FpYC2 zCK$C$JQ;=Tw29ne5nwZ(O6fD0A!lHDNJ9^L8|ycp&*;B4jDg;F>JGSWHDk4Nf4zYq zt?ddu3w_fjWq-}!kqg$DaS=AYLiG=60ctwQqlr9n9DQ#Ri0uiptS+qW!(z5`j%?LA z%<${U`K;DE=gZzqnLZsnPQW;SLsn}6awp%v*nK1W2SQV!Fx1~P8Gk?K<4OTs4H4zg z+}9vU9}YCOF(F-;U&D2qT^MN5bTdY&oqCy#s7W6IggiAYT-3R>^1HW63h$nY4NUvt zrUhn?@{4p`7DRL3BwNdQa@OIIL)!BRbbLH{4VFykf;dbe$c74i~ zqBj2UaO+a1w{>{7aKH6pS+7UBKqiVu8*pkA$A|!Z^iqs0vil7J)YMHHIH-!peX9K( zpZS7w-lfmzz>{`#P(j9+*X3=%#JES)lS>-0wACVi+fO8TKdX1@z->lQhZXH8!0-qB z9?u!cx^4FM`ppjAa2r^v`3;jEwu40WZQ!9jv=zerCWXOUzC66Bh(q+%>PIxgCuyHr z_YlZ-c|b3ljrH~pT46l6UJ@KpAfMW4lXl>Lk3?TF^46bzKW!2{Y!}!w{{fsggDY(H zv1_9{V!5qsRU7EjPKO~7-9{2%5Wx<%&xA~w4cgN*g}H>NrYykxO&QDbEAF6>IJr;u zX1tk{Lc&6($MQG?cr=+akv@@-y2$AULR}|o_OI^i?W!lO+eniP_7H7sNRvR{>qfDz!uV`xTMhmCPbAJT8+o+&kEJvAVA@&;~fZ(9%hHovTqHASN0D zN5Xz7prB72b(qDCZZvSWCjGPb(6?{7y4@4yP3L1I1t#r#cJDcq*53`Cv)#&*1UP+$ zEvZH_nEefXqH;qxpx*MTZ9_sjU(&$LV5}=-+Q3|dc0q}H8#hjKRN4yKIr;j8lijwN z9^p9CFz;Htw7=T^8M6OZa`xwOBU7hbbk@gJ0dZ&jPjyOVj(Db1<0_N*<4RV%Ke#WL z%&lPM;nBPuLI(iURg1n5^KCh4C2Ia`fC2}l=mrewPyyJtdh>Zlrn4j1o@0d+O~*#K zZk$iR52#l^-*IcQ?Ni?9`s78Ay^P&|m!&>AzB>sAWER0{D6<3Us%*2akmJafT0qyT zc`n1@zh@$t=xu_rK%0*1gI#u0Zp84|TJaBh>P=VXsdSX%y*uLO4UC!HfFx zYxn5ida`MqXA}uBeK;`P^N2Pusg~N$sNv%Y0Y~ zQyN2gaecFgh`qgdJKpT?U zV8_RTl&di`jY5wJ|x9X$e?<}dxbCZ+j488;rdx?Ppb-0@P1?FIgL8~$TOdV|X5P3KPY@~`{t&%=F!t!^6sF#Zxb|AD1Y!E_x~db4gpH(ly8JUTZ^ z;8i9*Lq_SOCuEevvN0MzOnB(LmiXI#-0 z;egTj*bQ$@>Rpzo)@+bK^fQX|h>$u@&)v~+qu^7p%$e++?cik8;s|~84o+M+bv;Fw zG6aa5$RUL)sRDR)eX;j#B^@K=yFU~(JitOTUGD9vJmd1vpA?iiEWRSV^^}W=c6QgF zlv3Ert-H&-<&L%X9Tudt1M{@Ix3M?hx_=egJ+;XU*(rL83GPC^EI$A0^TmX`GE^67 zW-teG9?zri3{W@Zi=*?Lewkg#Y`f5Ge)BDp)sWk!(#pQWSzK+Eh`$li_sEE=^q@u7 zhlpvZG!}@F*`&%)(_j=&BvwNvoD=_ZbzuCQ%62lHWOX{Mx^l!m`tZKwXPx3(<6}MQ z+;VF+a=M%U%)vA4ZkkK~cLdAiY@u^$)n5BDo1KKms67bGi&Y_myB}^@Dz0;(#@v-xtFc@AM%aKgmQ-qZ33BuBOCqRnN9?oqV3S7=0~)WqH}zzospE zS(Vm!WNWW{H2R>os{u>X925t;YN>NhSK_7hw)q7bgvPQr@+% zI)KZ+L&Opn3pp+mKS3;YI)00Si$cf<`Y;E!g)%PG#Z@xHF2??X*PWe_D#~u}gG{D1 z0_KM*p0tCCQVi|g5_u!;@GkQ3O4x;gTw7UDno;Q~p4Ijz<@PAELPOZSI5o->F{+y@|2y)|8OySK#SWgW_1xtB4DPtYi~L^J0BY z-R!AbbQQg({6|}%1)@rtdFBVdI(Oi6zj5MDoTcnyd8&${k)c#!UjPAd#P1rp;u~+0 z-s#Fe!K~d(Q-^Fn9mAAl9cZim0C&zU4}Z=1!aP!-)s^06{kZiFdcPY_m_0^^42=%x z^4Pbk7ZrC8?1;qnHm}w2?p;+|2b8KvKCzanAa5T=SzQD0oEn&u8jA)>Bub-?C*-!x zXxC@T%9lUnB+;Px*X6X1%w<%0-zbu=EKD1F?P0o)mRBM6+ExZs`##q;GuYq|i2CJ! zymHp1cRpmT!(1Vr*_d8`c^{PFV5MjL7NLHFQu zY{|_e9SP1YbB$KY3fn~YKV=mHul|5)cGPe5pR?8t#E_IAZ?8mtb-W@3O@6wV`=WV^ zPbM4t#$9Y}Qf;-LJDsrmiG-80C-R-h4faUa?hs@_bru%Y55ToJygaFq(!+KJ8~&+?0?v&W<(ECIioN zs(7<0v^Zw6(+qUoRKGf%vv|6=(jNeTTaI2@XxCt}#CDdHp*!V(0t2IrNr*kPSTBmI zSPddKJViFiN5F`suu!TxzGNPj_peKPlY^(6EzNU%^?;oKn;xOcGrJ^x7j?2bjA!$I zfHK>d$LiNheh0%xV)NkP<>;Wo)SV2w9uS|m9)-o)9j&N`sjv)pQ^GGf&u(-+c1xZq zT**y@`dHVM24BL)_Cj_Aw=S_khh_*RT4iXX2cE!5Kw19O)LU zg5K-TyX$2@`@outioh9J>szk+^eqK?u;a!gszmhItivzL>*yA9T{&b;-R?mr(igMc z_*fO)Ph`nwePU8?JsmwseQI+VJ#P(4!1{|VYl9o)x;a6bXg~qN^yyB(vE6_)Ry@Qq z7(GffZc#$0j=S9Cl$|DCItVA{LtyuSz&?Yv#@PfFdo0JTXvZcjX_ZkTnc;G76?63K zxGJ5jR!eAddSa4v5j9bmnxYD-CL^}$n|@~%U6mj3;cZ2+k+14Y!OIsno4o|X&q5Gs zp~$#~T-BxHAm~l%OrZ&KNvJq6E%oCUcd4X8WQ&hhX)fpT>k0sncYZK4`f=A9dVM_b zWMA)a;ky>%Ub5**I?>Jn&NM*O;(=tX11_qM56SyTv@SgOm530?8--xAQY3veDA0|5~di{IJYmxxl6z9SqhN9F zt4YhbeHyQ>sW3)BSO|YUY^AT8N{uar&9cvngE94J0ptzX}qOs-MprAXgf4Ye);m0;LGG}ww z;(QLip{>XGypDEZ*N)PyZyG4`&xyC@%4=MkRO*DU%k1Oo`YM5aN3&Ty5nL2^GkR{P z)K0>|)j?0pbzH@@PY4YIfL3pH8wbgnuXq%DjV`H*tALeu`Sd(otak_B=nzoVV7ORX zE6g2ZE0f6%gvpiX(vC+k48O89%@cOspWH3;9BN{68ULQrWcaU)a_6QmsmdE_ee;I- zcvc&9KX6UK+0Fyfn`H^=@A>=CunrqLz}ZzRz<_sowd*I4a9}fYT{h{UvLmF9yh8FM z9PB~4NpZ~iWFB82F3 z(0@?#)3JTjotc#06SgnR#H=aiQDese5}*IqWWJxZ3*2GYm3@kS7YKv3A+}qTB*ZC( zcSZ$*+ZkL%E$^hEs@h?H?ic9ZMVL&hnRAWyhwdYi^z03kq5Bi4n7CS+a-$;u4I&%p zysuX6!lXP|rK|JG?HAB4luiQbJ44%{-!n|RFGoOb0_uHT^>BucGh)DU8)9kXStkxU zP$_I_yZdP?u;hWJ4|F(Sio)t8RNfHgt}FNAO=EE-P*|Iois{{UsFcZf{frB(P2~AF zW!s@#dj==%1l_ro*=p7^3sU2~Sq7%uk>ywX8e}L;^ z>HzsM*laaZkl}UHi@(O_V}PMiMR>KJ_%|_xm$4-Tcw*v#nUE9la;sT+tbdm5dbiHE zb9!Jb^R=a9teH8LD86r+{~5Fxe|p5yETKnzRH&g7s4`Ic@OZB(nB`f1Eg+t99T-xg zFel0=_;E`0X6op5((qzrXg*9*ZiQgAR3`oXlVccDB$M%CpCeo=TA-2ws#io3$zk(7 zA;+dHw6>E6+sQx^T%whOVbv5;wby=E&>J*Q3LB5%9Y?-1*u;&1^5VZM>xW&AW) za^}#sksh-ngF5d636t|5;f3~m>}Q<8x02e!C1zK_)nn?B7Dx7(a<*FxC_?2WYmo6O z!&+bwgK{2d0mk={wMj7tHLcDe7 zCKP*Kx%oNB*Y8K)nVHCLwn=^e?-P6&4wNUZRD`hlQEL5+v@>6zq?&S^DWgJ$HuZ{Q z4&3-yo;{jG|5AY0VdVe%e%=EtBR`vYqy@Om!Z_J0m*k5X)+fRnwX;v3516jbI!yZ zG*fm#lx*!|TYVB7x)W7wxf&ElazTvIY4b-oH~CBQTzL%T@t7y|k7YG=7As4JVSnuL>gh`Bt)_9?tnyd)o!t$o#_n{L zh`4)v9-jU?cw-{ZFU?8`teNqocBljk6@|517Ug|1VOz#tH7b~1oe`~0(LR|0h!veI z11cK}!7Pr_JcS}YGOr&wuq+2Dvc3swl_?s&6~2Qn#^T>MP-ZYC->CmhF#V3+B<>9vJcaNb&MxJPy)UUO3lpCTdm2_>X7|g7YYAY z7sH@K`=b-6`uz)=A8ZP9Na{Cj!blwI4#zT-&N9xp#Ix4m0!PYD|xn(%&$`yO2ybM)UoxLKNr zWt4jSWmqujB_ZbsHo@p)h4cRPYvLjudsY^iKV`_M{k#Vpg3z{sFXt?Z$y!Wu2=oDO_Dbqh!{76A!==vKjL$eUNZ_D5Y}}s8$1FFpC~F zSk)?Bd2u#$w8EDV%*S3*T<71Ole#=8F^d`yxCy>c3LU3ae|k`ox3;rnyt4N?>)}#q zMB>8Ya>^zN8p4MwXJA~LoY|W^2{s_o}ZjS6v zb+jX>&6G$=WUqIHE2YG5v8GpIIQRzZ?FUGgqBDnx{ZOOdz0oCEgtui;bC7itbG}Hf zYCmzVe2`70SF>Ze6@E8!RZ)YU6L=s|^e3(+bQyyA6Z8X&=zHPFPLR;S*2qnZAeCm3 zOoh(&2rGMJ`ksKm6?=OJFpWK1DoxlW>}XzK4O^D%^45T;aD@)JRt~#hvqXhaS`E+H zDwUSY+==>G3Y|{Hrr4dZ_YsGR7PJu_HD@piTS{{<4!5v8Pyg-@nD3}OQfZ%^i7d9x zSfo^)w%xlSw`*8~2L`+eC3q{3@&$Lp<`!>ct)ysPSO{J>rGxnkEl1z4d>X%R9Ab|p zhO+3kpi&tIvVV{-;S_uEQAXn(Ey71ht0^W?jZ>}mRI&cN%rhzB=`Lqg%7tIfKAkc@ zUhQXfE(R{OXb{@>fK-VfMaZAHif8|+E_9yE;c80deEMZfsg(G*%n%*H=%4aA{26JI zRNU%8f7VfX&)|>-seWw|NB84|eTyM^>;u@GN0rk@Bv8hTd?YbgA*GFw97dcQWb~r` zMfH$lr1od1DKYx#5Rp$*=eeZ=7c8D~T4F7*E z7u(x#q~c=JLQKgU?XkM|C(y-_n@F^r;n3E-bxJFk7AcU58J(~lqBIYwFWo#4x1OL# zwG{G7g;KC|`IVcz8!AR{N6FKVr#LF`}V$~y{J8EvYaloN4v0uqM|$B5m#-L4AO}d zkanJ?4Qyl6WB{+P|A$+}yI2+A7YJJ%Pb-73a;%VBt{|~?ntgO5ANncUn=6kE<;ij4 zJ!;2>i%wWtCZPSK=HUO~R~sPzg|d+mldskgmH*t`vt22D)pzUHzb0d_9l_9OFK0E`ChHBky$YUuCb#=8PuJ_;{h8No>yP_72Y@pJgT(Y za?o@#*lassbFYfaq#u5cqEGz4^clXS6N0`Y8ig4l(Qpg)B!)L8YVsQh&^{|7Jg24% z7nPh)fv-rOWN-ifCcam22rh`^bl1UNMh>z2`tqf=XZ-j)Th6vW7OoKRV9>XG;nmv^ z7UnHh!6>??wT?ZT2V$NN^g!Z)@sGq4d!v_HR3b^u5LR0?oX}QV4x(LaODE3L{}Q*k zQy@zA`I!*34bo^#a>5LH2lU_`_K6AX0%r0)Dj4ULKKRG|$H!Hu+ORon95+WsEy~NZ z-@7;~@%8<3O5A#(8C_9Py-Ge1U%pn7LqC5(klk5p@(n#W%Wac_TE2z}{B)qFo}R%HlOI46@H7tu=ynk6$(=A*@Fl%=?`-$R#*3-^_f!h- zF*)1)*b$OJGo1o{;n*MBf(}Fsg!bOrtk?&euu@V&|I;W3ZP{D}qfw(H_F%cp2;1R) zjqg|xxaS;67f`vu@B^k8NSvMP~XIJEe1;$wXU9|i7az>F%0 z9F}twhu8|p5+|@E^8Wt>g#Rrdd?23*?3*(=9Kx0071{F)u#nc0Wu`NRq%>ICG3R`3bY6w{D`1vJaW?g7@$*C0SU<7Ob24lJr4ee~67T_Zal$+4k;z5t z<p-w~xTX310s5Wg$?Mr8 z=BrHR1s8F9ofTI&CsXZ*nH^Ha2J%=ML$F7~Q3MZ@j%jkkb~0K`O5`UdYg zh@)j5#C*?}*^vx*zv|~vW)e2_$`Kag1dG_iq#t6 z@@9h#!F#j=b)Lyc!0IOmJ@7h4Z$mw-zkSR zf+X?D;-t^c>YOD`$X?iED6;7nk|d!P*yqQYn`X_rsHp}r9^bH}Ak~ zQ%ljRH#2m8{$d>4^fmXAlwDTq#J~?Iit1r}mtP+c-i@uqEH?9U=wxiM)kKs%oE*A> zY%$}#usU=?tINgCSwJ~mC>Ki2Hb3rh-(m0${>z1h)EYQVUp2mcB1h# z1h^arXD~|#Bq!)bNFqpcan+HMCCvX%tU|!#Y-O`kl45UXpTSDPBu0Lq*o|fyi$^v8 zVC?`Ji+hX53IC1I16zomZJMsyS(u#{d3pVU4tf;?EnQ;e4o0KB8EYXL_?bhr1eRMt zX@FoC>rF^gpE8*_bssSR1lTrCE0_pjHJ-eJG}-`bsvRS*LTc#k0xX;~;DsO`7(>Lb z1kL`~hGpUDf{f(^N{#x1UMU9Bo)H-(Kl*J$vA_kncJMWsm(>KJj$p=O5f8-uyiR&H?O2a{z+5W z&*VPMuo*P)IPCHY)lYid=fhTqw2(?Up zB%ifUjopKcG|#4xC5nkdtuyVxaA{5}r-cEx#=p%ta0?Lw@M3G}%w^xB4g&CSkMrcs z7HeyknHpq|y!T(Nf8Cfod30cDSej@|eu?*@dp=IP{sKzm$9A>SUBe z^h1gzzL0R4Ouwc<=xd6N9VS@GzQc?y>*j&p&e`EFFOyQld*Va56#RD+B+Yb;77I1Q z+%|n(a{w|W)QWYBajNqs#6cpH$p&=-sk>*H5M5fp{bhud=<8KvAJzOxqC*Q z@F&qy1s?N$`@J?x{?zgx`-}2n9P6Yom!Qo7fj?sPhWAxZJI12FUY9?*CSymZ-@ zp9iBhENyEJGJzt25@{{|oOumyyiWQL?Oq#C_D7gc)Z5o$?njk>>;vmV6;e!IcDg>H zYvo=SY5oPG&TR%XSf)#|JB$0Xseu@h#5`!T1ufCyX|wg7U>3C!MrU&1DzxlJ1SgIM zyw&g_`sOS0L!d;NrVmR}jgy=~A$W8+4%PL>gX%4Ib7s3{7wmo%H2UDc?r~euvB98B z0af@AU7l+Rhg{g+^Xzm%ptcj(?2rLks#ZW~PM_g>@e zrK5R4B>g?Rpt>P(alVTN7uC*FEFBN6tg+ao_%%(5cmb=3^cH`O!MrGShw7m6BM}2o zZ#HL1X=%g2VpI7b!9Q<06dX)JH*c;cbzMi4(YX5vu((13XL?2rRh*BXsh=gead;x5=V3k3?sW(_0Wwa>Eu+6 z{vn@>J1omzBp`Hv!{6FL)gjiB1!U|ISW-S+rCcu;ZS0h`_4EtkWY`Z` z9Q9inf9%%Ty7h<0VQbM$1%>2g7MW21Dev9u=;?+AHX@TN!Q^YZQCGL-#_9UMh-idL zCVG{pA2V6cZcyKPg*r6483w7$QI4SGLue`8kwrJX-?*`CtRt)qWy9zCl2GTO=BtWiW}owI)=D}R&SO|ascNi>$4Z9(1R!9PDHm)K1D)L z>4`Lx9eR?p;P5mu1{jW(p(h9Z8|dpJ4hSvBMPTAVg-9jznrMTpf|2-8=^cUmZz52P zUi;k9J^hgKIX{r>tKe*#%5BLs6ZGt@) z?(Jh;B8h&ZtRfSyhy})%#H~$ZN%muH4~V%f4j2~ioRvExyC7c8H9>0c&$uk7!vIdp z-Gy~}{ok>nsP8RyXO=cw3kznG$t{M1XIH(UJ&(dKdw4=UX3!#f5KixNh-;w}O6gN% z{7mmsYaE9S5ul>Y%DcD+EAs=Z@eO`wSFvVuW!PR$ch`e9*n{PnWFd)pc;WmSkJ6m-WX{ zJH_!z@un&xzAk0FJPjMf|12cY^`1bS4vGH3m?HpYdv%?7!8jBK{{Qgx7G8O7vAZDd zQrw}q75H#>*FteC?(Xhh+}(=1yM4G7cXuf6Zu6b&y$EM zytz!4T)jn-@5EMhT+w9j%fT zq1uQ+nZXVrGXOIl2nFk!G&J{bYkm|mR9GwB3-^4Cp*F061h9|ou3o;ej|~-i2x-?# z%_MBa9DN9bG%?e{T9H{`hq|LB;ey||y29Bp5ji8_KeEVVl0X7-B<}g3G-OJP(vY7M@!+>1zG69W7S=`3`<6V9G_sijG zriXiYMJcL)JCxA)PjJrMO&$Ev{Q|2c?E))9mH4szjY+Q6C(vXmjU#W3yBWp9l>EMhqw=l=KF6L%9oBcv9HPS4 zUsrZgOJ4eS!?$9aa%nyxu{1F!UL>7Y)!bdOJ%t0{OZQ9zOg%UuF)Li`iv^EXKPojy zj`ZFli(^AviD0A;OFbD5a+kVYdV5_;;N7|D(0|(={-g8Y*h>8RP4}m;ORJ4QJ|Cj) zu1kk@XCV*78<$D2)mD*fTE7vDYhNOYK#OG`lcu|045sqo_+ckJ=f-1{(uhCeT(92~ zz>s>W*#VNKvnQS0muDMP9#WQkV7B(OZi-Ee(c_nY`{M~f(2EldNbFS|`^%~qP1dMZ{ z&-}iO7iQ&=-r7E>3$wtxc!cWd4HvE~|G3K7gq&`R?v@MLz8}?;M@rc{S51t%$f}RhRwy zBw#=#3>W;jR;7C~z&vdGrz4Xh2Ux1Rw9C5Do0K*g;xEE`6Ox=DH{_fkvklk4VJUq- zEwah4Q2M86J)#m=xZOJ|9JXNMFrl%Vs}#!(@I*$B&*QomEIMz_^Lx{Sdjcf0*RDZ! z=!~khshhYIkA6SCZLEmFKj8S*hzuRqx=)%b%^xpHXfVZ7!rz`#;b<%G?D&&%o1sY> z)C?Wz>Fd*Mq=KP(ftfm`?8^0L9uO==*ECVM^gmqJgUS@N%GPp9NplKM#BoVq8ah z4=0oN2>vWe{il)^CJDDbycn+O(6|BUwr~%%V7&0g?o;8kr(@kBU@C*&Ohb z6$UZp0z$5rEP$JUdwdQTp6B3k?cR+U#p-JpfbCTQ%(>NR8XS2LDjy1xQz4Vv(L`lUtW9VW6NwT$5>lNHj`n#+ZX;8q z8EVDP_d}|*=1YrX&EKC-&k<;#F z(#{sWPq;G%`Wjdx=JmP)%ucpv8?Kd%=Ka&{Gz0|wb%_<++)L_xoGyg3z-NQapb~B6 z;SYfc31%&q5tm(At&ZzJo;x z0u&^?xhjdz?myd?M-Fc&+Ge9m?PbcNXDjnJ35g-{99ZYC)*`m9xo$QF3WE=Jewjx; zAI*O2RXZ-W;MOkuG{wg43+{imqmfQ_HP>AJ;et~QHvndcR;u|FT) z;Q3F~v{yF=RCQVGy+u8>Vg3tdh1H@j{E*5v(V`Xi*cCYr4Bi~Yxk{xk>K&stfECY0 z-WS5_*cO*bDKF*)aO9M{&=2#X{ z;uO#-=AL1n5t(O*OyR8*eH%z*BOWWNKgdjws@>ID;IaQ}Kf(Yii&tKcqI#xD`14QE zz>zh7pMhQj2B6!@@Ega^_#_5jgWS#Eg9`PVMKH~Vfb`;nNzGl0`%!ckod3OV+8{BC zU4N*(KmI%Zfu0PQ3cACn@ea*4ue~j@6J{Lvi!&+C|C$BR&+YtIEZ)#z8)*NfI-5Xp zk!-e}vE`@#+zQ;!QMMbk<4(ajMiL*DKdq*I=);y@5e2TE!t)W3CW;Z4Crf`l6Jz7f zmZfqVwv=nu+*Z++d`1w}ywIh)GO;2|FrE2DDXrw)@KjL&8adAua|93lz}z+#WVLul zeyg0HW!n2JVYaf4P`WY@Fa znjIUijRL+_mo%69Hy`FQkG2GMK%~Wn<8mhgi_BoOt$q{ax0L~ZDzEOVk2AVLOsLJ? z$$hDBszB4yrkuUI@fsUz9#l>~lxnMjumpRn? z*jR`ksfBE-Xv#y*9w9>?TDIB4Fj!^4s|mc`;si>PHDL~@a)-$o6LF3QH&Hhl04W!+=LU=mick1QUW0fk2*E{i~j@s`iRpO4Mg-wU# z5rFEkSwk)QHIq5*!FjpW27Y*(UG)Sk0LES9HTsmiSeIuQb}s|tNc4U?&UpXRmNDk) zwcJwjSqq;4E#LaCVK=cI3Cw0^cBylBZ75!O3iPGBY$^`-6rF1tNyRMqPRNO7Yw3`v zKU2L$rsqkJI^mz=GbF6kjJ$N~1h)A3QovQp$MtljI0iA;JrW2eS}ZZw+52_{Bh<}< z9-VqP&I1P^T>b!2=8De>Np}i;mA^-c5 zvlVpHW%i!$AVd!t&J|)93o2sdMU|)~h;0r0N!RY5VwxCZXpQ_M&!gD*nMoi@p1?%c z;8|5c2we9@N%hu@Sc=^jF-VnNo}>^%94n4>+DSMS_P@8*_MCusYtH_1&3iR(>0X z%@G6`voucJzi7PP5ViRhc*~JnZ9P6!tNm%AKO|MkS+;%!yifpg8t6P&d)_Fy0i`&U3R@iVgDVkR<%dkb5s1{ zjkh|--!6U<1QYi$kt(nWJ5$A{Pf}#*#Afepw-Y$H>%PF0QluP;x+E~PIiXjq@kHOg zdWoK+bGXcWkD%fhqEQ%<534{kB9!yl*^zSB-w>kJ9dI#~-7!a!jzWyS`w8r!U5+z@MEYTts!eJv5BGLhQ9%JmWM05k=u2* zO@#rtUsu+2aD*J6mT9O-E_lIA{XWkCYeRZHd zcx<(*V^;8pZ7S|`vd0KntCr+2c`su(L9T_i?GO9Q6iW3q8Yhd$p_@fIorwwlGtaJSK{CcJCZQh!Rmf;l8?SCsz zQ4SHzbWj_H_)JF6!#biiN=#Euu3*k>fq>-(i&3OgVoCiGj)gjM|K)eUWIG85)2o~( ze`zU&EX`xvEBz(~tyAy{Pqq+*H4i4KppN291YqyzF|WR;UNC0l=2g7;2dcoU2f9jA zcsY^h6!)&IuUM-cn`30h`qZ6IJhzFhv6Uf%0iLue;IE38y*}>E$HJf%ihgO9IaNGh zFepQ5fD8gOwnZuIAH0jcHEJ7Yoi2P^yKbL=6))s|Wo9^3ccJ$l=DgcqT@m zFZ-6ycY1S=hPM9Hx#v)noTEAR7&K9nJ$OjlH!fU8*(tI@-ngkgw0w03=WxIF=FUlX z7ow?#Q}L%rH>uPPd34(^Z8JPSq3!oZyw|z^_%@T+9znb5ZrW>~g8O zz}=24BpL1N*!<+P%O>8oUN`A?f-V=8(Ti7tS}eS2t}&T6)2?{B@dmTX z6Hq4Q(E!##1;jtky<#1gtDJ)42XAfaFrIE5L>sTO?mqy`{=Jfczi?ZYBLGLKkN!-A z8h3*l?nqOZNij4AmsUC4TAek|E0TYlhSOT_C@H}kJ-L2I^8UiZWf92SdBDijvdd$R z#ll-%;8TNooa=jE%0b+sYe@OD@Z^({n{Yb#R!F~;Mc&!*h+Fa zcus?O7={RFY}DOs=Hy#z{$~{6P3Suuz9mt=;lL?Rs(Y8z?w}qX9v&{l8}p};`&0GB zY+I!N}wsI8<*l)=Pu&80qhSEoFKi0AIMW2rZ zN1^6|c-nx0S+4E&-0yx$-7t(68<3&fu@)Z|v69!`v_u#w&>KJ9@olMj>qWsuPo)Uw z&V0>_{$!=OZusZB=>76_g=&((*?gS1o#;A?qbC`8FRP(y|LPv%$z{O z8|qua&G7jUOY*_-<6O;UqUr?C_3QdFMyL#VVZMR@YK!Gs*Hk~g3PNktbA}^%IAESF z`+=1c`O)!Buf8R)HJOQyJ5BX9)LLu1j(MvR3jSFwv>R}vIV};I6z}MV%iHL7rA5LE z%wubznXlS{BewM7#Kam)E=$4$?`I$PU1+vbi#7_T=DS`dO0`0lz@u(ZIyYRVLM*$?im>GW%s>jSj?FoU`S&ebmm?wKg2 zQ^X747sQo$Oa;8#qs!;tJ>PU3zjL1_0s|dx~dWWN6p$iV#hbmS)IV;)x zCS-qfyHP%L_#nHpI#wM+&Iiqwvj0s(Y z*;u90JbK7FpwORAP3Y#}^nuC8O~?d*_F%U4Ts0s)^Y^NJC+0*q{cN3gcWw4*#87EA zHELZ^1WxlnjHFSSBGhyC%QAHbNVZ%C;~5Fo#z=#zRT%aUtcP2uvg*BPlre#8t9)S8 zi={x^=qU|vTO@qmM6)6^)zzh6?h2G)xXf%l{?=a7Qg}AP1Ou~p^GTxf%G15)I*xhs zv>>R>*Z)9lB}BM43i%d(O5iO}V=N8`NE;fo@3GHw`Tx))650OrbJyGNANl}_od=z3 zHPwhw89r{RgtKPuUmokzr^{FRci%*Vm`}f@vEQ?MN7g)=Ee4air)-$R&M^?Z0{5!y z?59=xL?;;iYf^V&j8ajx{T>-L^`6m))z*|fYpOTCgiUKdShZN4TIn{f?AvnbKEh{j z7M|MKpPay0os6Zx^wn0KRh3;&*jtc5rB|0b+?c#WGO!%H^ zO4l$p;BhitnMg1M+95Y#UPXuZ$ysL#!iT>Y7Uelkr%*O@-xaasTRcge4kZH>ID zVBcnJH?%8Lz;4-TPxQ1E|589CiojD!Kw7$==_IR&vy?lmv?4EPu5n-Fa3L~)G#2XT zf1S?n^niI6xLgUGWJCBQGrB;C{>x%Nh`r&im;wZP3Uu2Z zYD5=>kj--ve*#8sS!|=WGr#S0>W=;r5(`SLAZ+xghuTD@xV(U%@X(blzi8N!Ak}Mw^RL&=Tf9cee^ktpZ!^!e^`;3U&9|7 zeH+kPFOf5J!Y;*q5m=J+4&_c&8ebPrr}}r?k`O5rT z!Y6C=?B~i_e$S2d@4;_2n@8UZE-m4KCGLW0k8KTdvOBRsH1FaqDYcV$07pd;aXo15s6-t>+bj?|5fE*I?JzFveir&9e^GAt6!nXrPgdC<@?2ubO2o|R>Cn+E^cu?Eu=>NzF141? zuTlZX*!P#bG{| zUi!*1ZE;z>|J-zlv>eOXe&vMk7p^iA(z#+0F)oX?0J6yX^><5NQ7M8_(RCVWm&vX7 zJVM(AB)UuQ_G5~Ej;J1W4oTdNlq804yaW=--_qB!Vl#!KL&{>br2q{l-9Rh3XggE_Oj5?QA#r1K_m=+}!;$ve08PcyUH z!uKSxvhG}k6SZLHUkj2~G}xmJaKV3bdpTqFHEnK&?B@yS#Lgg9qh8~!y8@yljqAM` z&w$h6F{Ksw^tmv%Gy-P-9}uB$p(<-@OqVm;awQ48w0D;=JHmsg)w46}*_%XeXTEZ7hgMIh1V2E6>90c$$NwuBQ8>{2*_#Vol$f$3 z{S1>SvAQsglbK1c!xx#*C8>?HHvCS&Obk{gXY{YRPO3WI5xf^eLUMA^3!z#V_2;zO z5&`fkmw#pYaN%*sf1Gs5n=OtG)abb6H5^HblgQ_ZcK*$-=Im9@ionlJctNS4NH|Z| z=u@w(B|!l*b3}D2@z^p(5#-Revh94*Q^d^ut1X~W7qN8BB67;WB;571zkFA^+&U?f z7K{1Fw@}0_LF7Qu2qZ9sC^lk483bF};P1(?D%~CqKgj+?bv^IDzhRmT9=i!~@2;(v zbG?8wu#9|l9B+?jiFpVyZ`V^7KCcFSkFo|goq8aep{eROSQ{omSQJ9Q{d|oj@rl>= zwy;Lsv7Np;cHwTTvg>J2$M*C0BV7IXAc69KnEoQbxUJxM#pOoxGqAwWE@NC|{qf%4 zr>zQlS(vKv3bA7tRF`%$x#Us&Aa%IgVEVWczu1Ah@aFRj_YtGz>8=GaFwTm79h*q{ z<<2VjBVS$lpfJ92nW!36kx^22lk~3BRaG2uzu^aDeTujhM4%G$K@n|bLHOCer_P^$ zx$8duVXl+djT(e$meP~u87In28#-m^JY)s zCb5Na8jr~aT!$6Ws8h6Mes48u=a}QDk154y#x#mo2+T~bhB4B&m1fh$^Sk6TL|c{i zvr<5@-O@x~<-?KsO;^oAv;=YD$|K_Rw7T6gyh9Lh#UATPK3K(Dw=4G^)e{) z7jDbj7d_M>`dx~OKX`wYw~J?BOQ{?aOGAI8I5=$GB^vx>`R>wx6ts%D+~v2Y%Qakv zZ;LLQHV=!fLEm+mPql0I>Wm$r=?4u`S&tF7J{o4qBn=)JdAd9QiW}}_N z1fz^tR~(IDf23UTR9-<^H>+XN?0JDBDsz|z)I5C|Eewk*`^ijJ9%K~4DE>^0>nqqg zP6~6etinRXd}e>Z4U~i~`Sye*;lr(`l1j~mnn~tsJGKNcd(Q0~X(xtgr*C7o6&Mwd zD|@}NFx2`7rT(lu+Mcr1QW~T@e5mjE#hm?Ce05D!moljRyh^i#vNKpA5|-frhR^yH z^T24yn=dvJwE~XfMr!0#h|)8Wvg2Yt*Z5RHwK8O?y#Ke5AVBn;v@$8Hvhhlef((Vp z{YhHobVC9r+r1k$G?#DX;|s5X1av5WrY=&+V!5SCO0vyb*Dx+oVUr+4N%(jYokb;) z_j`p00Jop0B9?PVR_S+hpmwt-l#}|;`$@51j_m&bg!#E6M1CalB^?P(YP_`>?8sipA~&M zGWzBM2H4FPiv3F;RU-7hc6iDQi|JD8BI-1H zwh^hNM#3v7)bmtxbPu7yVS+DycD8$crBq74`C~5>rtIQG)c|Vw%N1|dg(tsE2EMag2jP6WuLm%7EMfvfxq3JAg_aH zga8udFCy@*z2YQ!_qV9GQB#l4E~giy3&Cbnto_8*#qIr+6_XK9 z>2f4}e-pgbpo>KK0V*1NTFkWK>!L09zTFahZwKwVE?o?fAm=*)}5il&7i-2|{{gNmPaFNi} z@EJ9DyJ{d1OU*@DFeqoOtSqOG=esA5A|}aIZ9?zRGGAd(1SB*OrHhZ<(%d%qlpvM42*B)LOyo$(C*S-|KLov=B$*h@ProCHnp0^F7Z#} zh@6j;ZKaX@TTVqmxSCNTB;Yi>wAE=CzL%sP&w1Xy{>$T31^3i|E>7QUE&`T?BwV_z zaWbtBorhouRq$2V`T1CpUdSahS=EIyp~N?M24let)e965y0>n7McL_1{MVeB306*> z?>%NKuFd5>H`|6a{LH&oV^WrnPq4;BUg;+TEV0IfuMMe$jEl70&O#rI1UNVfuV#d_ z5r$Wmxw-cHZ=vl5;#5Vd5zEwM5{{b=bwi}O#n5ja$nlDv=c|lW7%X^paVZ&+;AwB3 ze#%JMtp>l-#TCXBEAN@Dh6j)&Dmc&u9v#6p9Um!w(e>piBo{VleIxm*$tSktZj}iW5 zzvBTq3r9nE*f}PulpxsZCw7YmI57B3tdJQovRS(pJKvG^WxrC{@s@p?IJzjRKM8Od zW=0?^Z)Bmmr5z$#YI31FlgbMuFjLQlY~&NuDxp&Z0ZyD{M4vFz7RF(-(FJ<~|K85! zuNM6)?C--eR09{W`<4Df^@g6nf*78$tHN+cq`V9>IUf9)(ErJuS=^*rM8&U>skGfL zLO*w^cOb`TbTvYLzJa86cm9X7k4ObDZi-p$cSgG{E}HrQ;k%DR&0ikJ$=I%W?>@WV z!Q;+_iG#HYCw7`oyfaNZzfK%gXmmeqjcK8RcPG@op0=L!!i`b1J^{)Q=Ib5s(v zs&*d|U*w4{UjZ@zoCUMd;-r8YQ@`|{0Me~w!gr~RZL~w60(JiXOyUV3t?-!tSsa%O>v4b;=FqY~7AGenbPJwhm1n`+jbykAQSOqWshMlfY_{z=U* z!V@Cn_M<*jn}>NpFPrcPo~%av_fMI&8{?ml+%iZn&p2YaxhRH{Xa#_JmG8fgzur4G zpe>k<7t=EG0xG_O_3JI!1zcPz^w*9|b_~+eWrO;-o&WY`kdR!^k}Q;7>nkaB7;7hh zQ9EbULAi3iZ1=|NMKgbK|l-m;% z?j7k>(k<2KD~)Ek#H4x9sxI;dY7xpo{#f9RecPM%W}kK%Rx6Oezo$Pg0&I> zvOJQmgA>ucYq)f0Z?4+8mDzvzEoQ)4HTGQH(Ldqq*aD&&&FZd#idf5h5k=OB5yvyK zC2AektO-?8BJ~?82XDH!yWz8Xop)^uENR*L8LHL#?Hhbfv#Re3F@ciOu2Bd-p*r~# zJe^BLX0xSc$FrqO<_jwzh!S^`5?s6~+fGol@@{)&)m)?wkbh5ohg~Q;K_r*Gr$|uq zfvcb|oPz1-FP772@s*&s3{(uBh=*GVBf2qwk3SPfM>y4F`!KI&rhOhlHRaD}%4-g^P;dJ^-(S&O?#r|p zsFHHVg;m)8`kHa_x3FCu`bKZKkgM33oS%}fpbB&tLjS*q5gtHl0fln*zvf^V>C^O4 zp_9H=$H}sxjoMP=i}52<<^Ejyt(8c^V#|(Ltox7MOcWj^v(MIH1j!T$N>vL$jy3G*B%ls_z{Rq1*q-q*9PZ-pIbcPc>=V1@m^OK|CLFilM6 z2B9QPi>8uFL1BWv^tCK9DPmugB46r499yO;GQu2nw&l$7Rr?2b-*F2=Tan7Ut#=qC z|4JP{p<&7g4~#7(QNip+awW<*bah_&xP1B~gTX+)SW+5%Gyo_57nc%RYJCD2Ej*d* zau7wj45!ltv@jd__kVAMl?4Q?qj>nw_Ky7YM=B`YU=-MENWC(@S?{ASLU>uON0l#BFnOqRl#AO{g;cTWD*f7w31QfMZW0L4mKrW~CZ{C8D=77hT0TD0 z7ItBnrJF@;tHW>KK(HtvBR9biP$D~sO>4Rw&b~zl1qhW6xEf|p=PDB6qNH|=L#|h z6HKHMERv>@qKEC&>B&K;LD>ALY^+&&Dq3`2??o*=251}$#DCB#KFCnY%NK=_VphISi z#z_RyjrBj>=Ae<%oleNtIy!!xaG@uUB?sSH>N73+Xylp_c}t?WUcK|g_&1hrUTclr zAfK86<1%9dV3H$QAFrIg6#LeqUwp6(KS*NN9f!%E)S?0n=4Q)kXnIhU?P#07NPZO* z%M&rhd&={1;oAB8dmvjUjn9Ok@%dZk^x1y2d~C>(Ee)!PHTwS9I&y5!9d*=-RQNL& z9w;1f{r4jtVFBczAnq>R`5FZ#p>coF=&A=Kt}DE17){C*ie)S%VCB1+aB<|W zU2#>g>0JlRb9GlEepGvPR^-4>^Ur-ccee^z2LZBSU>qCFf5_2esL(&cALa^BFnkNu zjO%XR4oZ4G1I>b*{oE*pw8a^@Gtj<Oj$H_^5W18n~ zB3t(vQ&J0Q*r^`=@VD@quwMC5WH98vmq#_p)i70q_!*dgiwfLWQV(UNOAlhq^wUK| z4m)SVySe@Z8Pw3u{|-6bd650$w;cU{7{cNlRj#_X;qBvx+CCO48U(;CPj$$UW3({Xxon-grFLl z2SEV(U}W#`_oX1^7%{X4#Egd$hB#n2qHl)gY6cTb?ByFu5n)j>Jll}}6g zkXzyP2A5~563|&*R2MnD`pj?VY8k?OXARg3K*c({1wh~J~J#`U>k;e#aisu<$qXS%obj`yH$hiqPMVovd-Yz|G z)Po-FjOPXs00Wmr-24>~^y$~Vj;%JuT|36^EuPbzbTRmJUs*3L|Jrba0-3;nR*Pe; zpN9AyNdvr}GrU|jVwO^-uhF+@M{v=8ms8n3d+_KrUt@-RyB%5>|hGIMX171(>FJPt*GOr(Tgr@+cCU0Rh&@QGasR&)^S}adsZN z=1+Xi5goNXI2!e~Z+F9kU5DFmKiv%nB%Uy0{LzPE>bh8@#Ilk!<<0g;aBmxY$&uHT zOqVDLOl^Segh4Lc6@>E>UtK^}iGNM|qY;ixu!B!Wr-A~otOM~`wN*>7nbQTCa)gu5oON%H-un`0g^MVn8OX-HIJvwe3KJ70`UMWr_bbn4(ojx-27TP;X zqFUH)$i#ay3ZkLc|04*4M`w~0a`~dx;=jWJ6-wo|fk6+Phh;(Lv0g)H%2`M1cqbVx zp5=Q1IaqY}|C}KrE5I21_+CiY{V$Z$d>mxI9HGQ#-Dw>VX4$Q39j>4`DG23rm=qzA z$G`t#d>b0kzJ6vH6p-L2PBX2zaADuiR$oy0xZKI*)&?bjf0%yJGghD&)o^Fj(;m}s zZ~)m%MkP&~ZhBAZH`)Bgjf|$Jztb%B%U}~IgXr{dqcYag*Twqu88mIRds53naEPJ8Kfe-O zM5#Q;A}Jus>Bq%8|C(yHzzA!kWg^m#gzzEkDtCh55jfO!=+q<@LB1Vqx#;BlDWK6P zfD163Nz`UK175Wa$As}#71(frmTa~WdI!yQ*uK`$ z0KVz|#*{nOCBVO#ASWBMG-PtVc!Z5wF`n%Q>$m5yk0#@m$dgHq(svQocb`jM&|g-) zXgXwn@tM)$GAoP{%C+?CY}z^c`WBSg$tq(dM5^vThu!tU6sDdOzn=GCu+(GkP;-yY z#b$VCob7)OG&F`Bml;k9y7Wx%i3y2p7kfZyZ6D@I>)1+Js2gnLf|vxE*)(2aTEZk8 zQm@$^5h;g>=X0~of}Z^x^$GLRKu`G4rmq3{~;GDdZuWR1nRmM##K2mzYUZdG1A z9~d9b_^Z4O_O6-PKSOLT7E03K_c5de2CRYjV_`~bn z`X;&-`@UIe1zEN2@19&W*C}Qw)$f?{{S3HP;lP$r$6zMr{?!zOtcB-x=zvw|>i&GN z6@^=Od=&e-7^aLQ_6J9Q{F?u$vmAgnm2SLQ_3lBG_3+D-6N44qZx`-KLg@3`4OS!` zsHgH3;%M(MQF`$(@u!bEkUn$5j6~PyX<{F1+S*fK%kvB^6J+w+{|9Ii4shoMHKy0o z*A$b8wXtl$}f=mzI^A3m9F$SDA=s#F5Rj9%wSTxT7 zVFPrpD(OrhBfOtzd0EUTqgF($^ov<#NT3^F7aLKeH^N}Esxe`+e&|cZa^`8tq<({E zeOUciA_F*!T_3-Ce&L_8Z9d!y?`9K zJuO6ki*rYUL-so%Uv((MH#!BzE;4})B{}KU7=uiU^hf$~q4!{7d?7C`urZvq( zuk!%{WqwqBo579Oc>V;T(@`=MQnV5uUq!@U0Az%6=ea%p3jRUH^9${mDZMbl_>gT9%k~->s?)?q~)uqbp+O zQho(;?Q_6hLGl&wk@0-GFmxS7w3(nf`b3SS+GLmsH#g|&v}VoVuF_9`_3~AJu6x^8 z17TN|Fn~?$>lp?IGUFf>f({hKxlE3KM}k@ARy1^V;9q-CV5srb-1QPJvFPJ|e=jHZ42Z5tcQ^j=GGQcGQ*beswmmj8nK3NPZxVs&yrFAkAOBdEf z%y|$6;1V9XAY!t;s$PF<8fKjI&oEg&1d1wldE#+Ry1U&7Klv=!zL8olmVye`_KxR2 z4l}NFSFRRTb-aVV34A(Uv)9kH06VM_?`^VQ;QsMDY5(~h2vj6gLa2M=M6$tOefd7z zSL5}5J7p2tV6b6@-@oW<{9Z=85+=E!x3eJBQQqKAf6~MV>peFo4FDXV(iw@^)RJf^;r7z??;S_= zOaqGhp)YSunEnM*he1)3FejS6)cNIVExhGp3wY*Sb)w-VUGplqJCEklYSPycK!>vBx=njb#av&7i$<_68%E#<(phI5>*s?wTC;>Xg`{npZO?p|&qep}+I!HHFQbtH;;NTcg$o=ncxY5ld#J;_bag0dGtrC zc58E+Hm(U(PY8j7J!II0)3b$1eu@K(8cOH$9f`ET3W z&h1Ly2K4$IKnMtRKfY?y|BI`y42wfqw#6a1Gq}6ELkR8=+}$B)aF@X?cp$jDyAST} z?(Ptr$3Ex1Z{K(S&o@=wv#M%!RnO|6rw);T?Wou*y9k7M*W%`P~Oz8wLG9}z7xg2djuD)h>njy zf^xk(rw1aPq8^ZR$Nh|Qbz70VtOgZ$Aw5CrKdBHkv|$^Ramci*TXE~&9%WtSHE8mp z84jIodg(A8xgiU8^WjKz*1)$;CP+#W_v{9={xQ1_3!NdQ(P%~VW{jDxSux6QcTn|V zhZipXZ6}Zximy2K#RT7$E$dN|Pk4HX(=HZ}>E>w$Sla@a%aJ_Fad!jqke zcWej(4F3U8H4mYXE;`Fv1Cq61jBrLpO}IJtT(Cw|57JX&_=x-W{=W;-Sdr%2Iqw+b zu!3HfH?Tg6{>~%DuYIwmyvbu5W{)PT0(e|FLi(*5O9{NQ37=Py!`c5Quv}n)4B2)c zItZDl{xFMHpG_P4u~%62b4K{0c}B>T&l6nY_9+`ON$N>0j4wr%>MbNN-cEC{910p} z7R!KCm&uD<8m=Gs^{}YRXomSEn;@oM&r^n%CtR_JY;p~^Y|9$L0ps(tGD*G4q67_l zHQ(^Ns+M3b8Ha%INwT1ZqLiSMfeYSQk=afk5|hO9d0Zk~Up6bP5re-BjG%E>&gmj$`c`Jm>UJ4WbeRvt9XRi6m=xiJbf_`JnGzXD;UJH&Oq!KxyPCY7r-wf4n{r0!??ZyT_TM#KM-c-X~fpyKTd%B$bH zuG>(VxWVsktA~5A_SYLHZ?D8xz5bE&W2><(II~@%v$o!0i&Ggpx=%LM`7fLLr>z31 zi1DyC(1U~Vv_m)SRwr@0v-zzWAhM_y95K?feD*fn#k7h1 zwz-Np+c?A~rx8+XMxhh!=(8p*jIfvWf>wE%=# zj&3L63&YGO9D&zkrookdovK06I%cC=I(Lcv)^UgJIvpbn4>&6AAB#c?{r_|?Kg-=& z*nx%5VU`N?Msr2(Zu>&RD3?fr(JH}ghwX~HVY>EIZO*gYSjaWTM{ub5vc<=Yr|?E0 zvJ21f>pRP)6*Hv5NP3LRCnZb#w@=O-)~%$c->hL&E>b7Qn6jPpX^CuUuf6h z#nD>KOk0~u5+#+1INt=EBFj{1a*uM9<|ypNze_}zR_3Pxah(_SU&?(JR=my^JYk6vf3s(j+#E{!-I+pNrcZ6pk(F}@ z0|S2ejm2Y+RoLK_;i6HSvW2Dr{zOBWxJgM#DR>=L5k7c)j5}b@&QG80Dc<8Ja_qZ$ zScd3=2UZrJbdlqc*p(6*v9PWn@u>X^oESEE7J&rz8EJsV&Hpn@Gcg zr^9}9iZw7W%q?j#5mgLPWFLt$p7@2t<2$y6zu`GB>6P2i(sXZ$t?&Xz$qGifezK1ULBfTeFUZSoapt$z3y~Y(`u>aZg|Rl!D}EuH1XP zG8EVhQN;F*s*LG`Fm zMC6sjt=SdRRw8}{$E=w4H6~W zHKI%C@g!mTbO20JI3(5|AIjVK2!?T!%NO-3oRnK5YRQqTf_C=UtlVIwPl=YVu_Q2b z-Xm2;har=Dq@P4ka$fO>+%WcYJI`5f7zpCGRWl{q z8ECPBSeiI6QhJ(|;nQA}(d*mH2s6Z4UCAriR&4tj=@y3Q4~2hsTo^kn=exV@EHw9g z4T=G`P(TSnk9hiBvsGfG$iTSmV@NVJ)RKjY2VR}yjaE2$P;j|jC5)7>4o!ZcqgP+A>I$^os5G^7 zhy58-{tpnnjA_c2d_UFW85LUL8)^4$#Ehh@sFD>JD5Hu+G_bYf6Jc2QZeh!e8EqKr zesxKJGkB26<0&*~qmD`xE-MG-Gj6t&u1sKM$Vp$49OK75X0#8@ILqKjG@`=ybbo zLsX~qAz-=c`$>&TUgoV_teW>^FD%@yDMV!!s0TgL^z&K2T7QV6bjP=u8a5XzH zkNs5XWNRk)ctRY$L~G<&w3PQ~&lVW?P%{-_-$xEKoYGgVK0gBR@R6Jo=Ep6P7VO{q{_svdSZ%m&p5J60Sn=X?t*1|#9{SxY zsT?B*`zLJ}!ngaHTg+Z5zF{f(3X%OmXJw41vzQ)=m?6n;oTuY ziZcD*GN?Bm(BemK<>5vne5@R>aUc=hwhV}2TVzN0mKNdL(yyyR0UaR}3|MK4W(TB0 zAQv3tkSW^zJ5trLwqPL}@5G~~UHtv9Z47xpd2(PvyZZY!gkjRAoj$hg&Y-Gy%iLHt zDm1GiBDXxg|8MNbg&C&Nt+wAnN}7 zs`kpU<$&my+xitb{2kpTVsb7d3Js}+aKqw4oJb{~L_d|dWM9fwgH33p(?5|I)C#Ct ztPkED&{;mOLP9ImvSIyhc=_uQl*?(VcVllIHCrHicTT(2d2{jre$S0AZ!1Vw;wS;0m=D!$-%@0DqrjN6D>=ioJmj29E z^G*oMg6G18cCAOfDeySSK-O1k;D`5}HbL?(IS#_fqN6(h6rZji zGhU~GYqAC`u}>b!ndqmGe}aW@znX<^{|-BeS54fN>yP|mT)kuM^HIT8P-sA%Joa;{Da{z4`Ut=DFeP3a??SFX`r2{ z_YT;Se+LOr=HS@PRg!I)RdvX4yTrKtZJ$X7rmev$f}Jj7I|DEhigw*kqeYKdYxry^ zt4#ACKig`e{E#p=ahDZnz+%3nR6g;vV2FO%cU7R6oNf0 z2c|&Xp0Jd?x(3I9@12AAw|qOXR z!;R9adn)WVFbPCD1lhVt@PnDdZQ94h?#g=pL{!i{8U=8embO@q?8D`x2-?aAmU(`hP`&%UP zOJocB5hpf#gg*BPOw#|?x2jBLtc}6M?dxpsbnhhy^M?Vsh z9TjfUhT4xmh7@*iCtMNxJ>ZbV*;+)*IJAvP*I}Z29;e?3secO}6Q|ycSoa7ee-_(R z7+R~aJgkwzKj`_!`u+eiKb#+yi`=HhG<(RZj{2eLR~u{8^?kgT%!7w*eiFms9qw;Q zN!Vhd&ZJ0f%2$m!O;}F%li+kMPBMr|Ed~#{tvUknanj2_YCOaP(q^c})@G0)GXWAV zgDm?_XS(bu*y>lZ$WO7LKUAmWW4!RQ>+rnPt=|tHxbml$q874$si!p z?e$ow7I5fOuO$KlUv{Qo!@e4%$V3jMbV}-qPQlDggrU-bpe51 z%w$#Hq0?3##PP`mp}ObjYnq;`R6ZXxeMnp-FkS~7@|Yj zud4_XJzHhWk&}d=IfbRy3xpN-2;cPpey=-_>#~p8usn;$GyBoXL$AM&5DZ5b!75}& zDkU&qsO$xCJ~nLV0#F(UCG71f{K~K#(guvkBJgC?*Lg7k<1E8jhfPkhg8C`Mn&?k^ z2Kdp~JWn#li!iJA-9suDKnpTE@A;c9D~U3`i?JLAiD?DMkn13&c4ni=l|-g2p=m6~ z!CD2>mI#r$#;%k&0<`BSQye?m6wa6(_9_5Uw_fS+Ca>Pfmk2cgqwv zf4cDGsDos$79T3&oEFmhxY5Kz2CGeGEgo%0^%=W7$Z=C#EQ1~@(nWYJ%WXH`WSlNX zmc#zEd|<83{Y}C!mNIU%kCFku%-f6W7aA4CrnGdm;#Z~P3+Xh;BuOd4SDNHD7m6sb z`I{?~6!A!YDS7s);OE(ht?k%At)|dhCH&@p&TCV1&R_Ge_4WHytB;`PBe^hY!eD3d z71RQ=FLaw}urMIFkxU-ZrhrQ%ua#5!>>I(*G7P+y42Fx{CdA= zNO((^W3{8X2Qt-){PJ+`v-JjC1G^;|=0X0p#EfrOb`i2nKY~w^=9X1&>{H5-rbIb8 z<2Ccp-sKPE-{||MeBHLhzMD~GJQI2~d4tyBQD3u>tlnVOPMew$30F7c&}nF8n0uzhXhp<8rI&kQz$o|X$8Q`vAPaC%0O_0+*PdwrB77F$m&eQp za&2doT!CDne9c8ua+*Mf#^|QZ0i;)riKcnDk&}(>^PO1+8koz9r9~(VCfn0v_K!Im z5PkwHgN=~gZJ)#IRws@1I)c{U`|ToG8%08XC}!r(;`@FHI-r060qDhmIs&r8Cw*hE z>w=hZbDo0hP=5vb_D~MAeBxG0I&iXR@Rf_#FlS2ZVH#}J3o(J!c*Yd*cta$T`=pS= zyM8sQnAZHh`cviars`=^W3*`d61R>s2w|njD6Cs5k8H?Foo-f-8=@E=ejPsX&K{kG!;rx-Ub{M=SY57oe zMx}6+664umliWcFD%7j?7&$DRpzciOUe zE!f~~PstIKc8krmo`Q1TOb>OvpL>L%mUlpRGg!pVI<$sZu}s?_Mkp*TG7*nndU@-H zxk*iJt5Hn%EF%;przKdYMj}3|CJT`fqV98mzZgoD{9;{p;bzp6KW&`zOMg3leb4EG zk&IR0*#Dfks+wYq%EJTgGXs0!|?|i6Bb+#u+opJxTQ9`lNAP`BaYqO6jI9sm$m8o6RZEhr2ZmvD^?2D90Z9MEf_U~O z(r5DcNtRG^Z&F~w^}~Sh5}-~c9L{ZT$*fwL8l2a4xSP2wD^CoxQx9G*Fnzxow#l*s z@f-M%2cK+~VDV-+iL9-g6nh_c@cJMUjuyHVnxHm0QzA|og;E2@%%*QKYHa8E2;PFG z@(=7-oS!jP3N$g#L@r%Bf|;AaO}Wo{HvXjXAIOdLMZ`MC`LTUL(*F7NVNQ}`JvM!# z`y7%OMSp<2&0J?w&23yYZx_IQCS*&FGGC@t$5eUYiXnk?Qt-s=;cI(^Diw~)DmTDV ztHKktO6wv4pTt3Fxl|909w9Tuy~}!cF&A~<`*TFIz4IMbl{A)3z~hzVAx?Ic5{cjB z<>s(qCGG=*2#*z}ty4Hk1&O zyzc5ln#)cpfBO!fS=1bzqg=hvX8+jba`!#Jn6j^h?~7Z5sIdbH*txwXm?2!dwzlX)<8%J6l?}3iMLV z3;($N*M(caDtEJQ9kr=3Ws|RkFph4Q@Lt%dM$hqdcb+SJ%vrxEN(|^Aqsozi7y5kF zwXe&<)XJmK>~64pU#FoH2Wfb*2**lq&(PqGNmqb7+6PlGpbrT#{$lKxbT>QmTRX7KY5U3^r)5yVcOBdR(1N(H}g)1mT$$4g@9%9~|0kb?ZF2@P*r z`O;gaK^W{oRd-fVgk_9%(l3^p%?2sCu%^LzFr=AhBgY3Gz8Fpfs;z)82zuLv+zS|> zL72_30{l*#F&US=^Ul-e(e&Uo+c%cx(Nh9zi$s0+c6<1Y-@I-N5&m;w+sRyQs-)C`Kw0%>9@XnS;&N%GjHl< zU&%YuQ*Nxf4KFN0NdD-*QcN%Ou>#tHe;x4-DtNVqGFnp`J6*7v<<#-nchs?c_r*4*1@^s08XUnzL0NJLq0DE7-iolsCEllH|aPUDx z%h2@PKo5*(%de~0u|Rdf%}BUg zvfVd=872VkLcMy zlmx%g4`A;f;D)yUfSb5#LJ$*Q6sTr6x#Orhb8x*={e^a*N!A~Y#^SN=!{)wyM5hwD zJpG-j!H>5S%2qB{UMzJtpv4)XXGzNHJrMFAAT!hX2JA|A5E86*W6@m+2P;b zS+guyWIWpKC;ptjk-wjF|EAWkDs#Y3ZYrG&vx zzBlnlC&66gC&~-jswUMg8a_Yn^tI<$t(_`yMH`L^ljyCZGwJ?_8l}V;BX{o+c0>KQ zIJMsUjj{VxqxU8+t;P^nI>Z{0>7|dam#wjRVqm%*ze};gnjiZbHI(p)*$s@A;IM$t zu}_7HK#|p8+~hTPqw0|DM}2vto7_L&Z()j+j#gEf1%PgBkzrIF7&#WRC%?z56{3xf zH|iXmT`|6;qoz#sG8R~a#^TpGdlqRfka;eeC5;YirSX{e=a7pv3exsNSH)_vq2c^# z5mCD9pkhu{2J4O!sP-D9>Fi z`Pco7oac735hi$10lybK$Ikg4K0i(xllKWq)uGa_x zuv zCwxz{=Bn~T8$iVCgWW0ki2rI(l3VS)x*^wSY>5ptm>?LdiW@@T?>0dIx$%|wbvtfP zOVS`--`OU!VC&l}_4gn!b0L6aidizUztF~NG}J%d4l^K%_d}bsiF{nsi#0|z9`|&z zln29u!tpjragldXBh?`m<)&TSyjgL7|0K#A?7;*&7-hMLkBWEymf=7EaT`=X)-Ap< z1RL*tAv|#-g!r(zjiS0-Z--%6aZ*jk5zMM8y?!)S^at0~^bLj|U4_roeNy6AmHG?COZ(;blpO(E)tRp{sVg)+~95&kw40*@n<;+HrooFnq3}xDlqF ziJJ|uigD)SaXV%+F`qEI%F(94t;Y8hR!Q0NsG;PlCl(+F;Q$>S9rasf+m1sWbO7jQ zy4Cp2txnJ*YtFFsCF(-66@ZP?n;GWgrrCIA#POuB(=m*Qn>qAAM;2rQ z8TxDk84Nqs^YbJ0N7*BE9(`#YK5+wSo!#1@ed^R!mcC9euJBMZ{+QC|2mc%pM7!`vZr z(#9JJ;`t(BW{GNGt(ft`5)^>jm&i0*T#Qw0<-pIChF=ECZ$f-nI=I>@JsvIyX*_7e zf42H1trcoElCdV|Z3oxLND3o}>2bS2ygxK)Ujlmj>GMs4XF(ecpx2MlgkyNnT(e9y zNYf0oZvQvYT``%AHjFTc3A8<#<@Z}yG5())!KWonu+Sjr?e~nnH)O4#yG*0U=Z4vM z{)EMdD~!mmaY}F1rp`)lrJZ>5;oi>k2)1sb3A1hzCOr7pJ}A$DTEKmi5O_^#`P3&` zoz%rU5jTu1(5hz?X0q8}UJ6rdHf?EX zx5g}Fa%FSHvf%Q3LD2@H%?mNqC9#46zvUZjBg@&Ht>d}AZ1Une?ro;34Q6q(0YCA` zdSxuB4q)fydE@*6f>Zk0mwxPb8){6}E5a{kUH`hniLae(ilWAs*uP``_A14`A>|eO zoHn@jzH%P2B0-?JyrUQ9U}NZ@Uif9x2xxZ-%#~|FUbIJl1X+FiP-k)7XzHT_5$|`P z@Y%j+Am9lC+UtkKSZaVY0cPD+OK);|*s~RaHsrbz13pLyqUL?eJF!MK6!C((Ji;zv zRbVg3S^hs?`~tFkKOmjVCSj215`(?$C-bl(Z@Dl02_+{ZP`%Uf0TO$zhPVk*!>Tk8 zw^M>zAx>mmEvG|8o5K@;gkWn3bM&eHyNg64e!WfF4k?rF7z;&gGVq1a!o4 z5eWHEO$JaUMObOOhHRgq)$*F}(KV2aEw_RZ4OO75lv(!M3$`w!Pa-(cdUy*j3r0{h zqgOw@Xc?{RlbGVKu2LDy{?jo^K&j43@T*n%MU|9{Az%i z92seN+syrH4=m*B_u?Ou8bCGIHd2$3-Wa6W;!Y1*0Le^mwQ9w})ppzj-UBhL`qwwl z_2yAC3iB{Vn0cZpjT;4`XJl8azq(jr;ujD!wwNuKu2x}8qP|sw!~5+dbm#})hIOt> zztgosXH$4bYJjKpvV^R+E8l%tdRnF-gnjEWn|81F(&-|1mr>x+W&5* zP9Zv49rJM)kYQ*o=R=_zJT8+|foTj-uIrlafYk&XNHzf&*j)i8R~k0SQ}7(?@%JC? z`_?_JD4T_W4-JoMf_D9rOG#0Y4+F`Bv!2Yi$^C5+n`{p60p?glf#;SYtpdOEF1wZ$ zb`1n_HZp<^CnZ65PeDnJM$O<@$twe7s(@r}c#uX^AcpLc;#;MCPdC?3j^qLsvHq70 ztY?^l$h(K9qZJ|wUZ?zeCJ~LX430uIQ!Mc$@taiCH3}3+uh&+s@Lc= zA9ia*dO(B!lSS&q6y4~CRdXpd5I&(9zxoQsT1izF#L8sZseNV8Hrie847>QTDNF2 zb6{c)pkKxTJ}OfS8roJJ!06Mt{LqB%vzd10`P6DTc`3ejfqE7ih$Z@p)?oc9L%%Y)a+0`=%|O6FeSL0niY zBFOLzID58*(6wmRecix6aumP4!+tg~T`WW?wjIxyW+B-Yyod#QjR+z|7NL-W+ekLD z^w9&&qI$0?kSBW>w$VP-FFN3ek=X~Az60=BkDPCb-O;crbd;w@{H9*td|{4Ge}UBv z-t8V#RqCjwcf|r?3vlN_OC6JT0@C75jETYHk0{s&D%DP+njAG<1JdRn?jjjpBlE#e z#K?;iyH@0$Abu4b_T>0c-fB3!(yA^v5?qz{3==5au&5s}Y)XAR=ZhW6NBlQX*6rb>MQ<;va90H~L)r}$ zx7vf9COGl97Ge>zZh%13z_)1apV@St=HxFPZFYpIqicTH9!79VU$ERv(snMYHeE%H zcV4az_fNBxrqQQz-ekuh9+fSx{C$_zViB-7ybiNFN)8SqTZp@5?#71k?dido+vgzQ zaai0cVkN})G4G@Z&%JAC5n1u{DY8qma_6-*@V|TxXlx`TZ@aRy6Swu7D#Px}@T_SjQF!GvYFs@yysothA5u-ngz0lrn~NcBBQ{6-W)G z0h_KXGF8UE1_S8b-vK*=xU6L{8k5AKta-x0m^`p$MSc>*%)y73`P?f?o~U`FriqM6p%SjQGEO_AXiHG=6OKT{wO$h`*(pfh|`VOc4p<0^tEgQ zEn9d#`Vpa&M~+l$)E7pYZMN_o%y9{<(G6Kq!7*QEIbt5vqTxl`OI6YBh0xRyf7WTb zdp(=p0aCq?FkNt4skG;(nbg?26ZhDovicXR(%u<5jd~%oOQdrK4e?u5|3tIx_0{5n zw$FQJTd>$)2_$Q2p$Cck%myS+n*yYR_=bbx9A0u+b*hhXB7^l<1?oQ}n-7IL;V_V% z8_Ows!b2|dfS^cDBFuTKmz{9Pt0!*i9OZKvJe1A6M^0SgJJjp(bo1_L)m0gW^jlhi z`}TJdJDX43cBl#88JAdgW+o~g9k0N_=Xn}U(Y z?_T;f9dAlD4TrjYubxgWElV4!tW^O!+=>EG>U!T*QPN^)!DZFQ17BNQ`iK|GHhW2t zO}*RRS=xg->9|m_lxl@ei=lHEBRVQ5T$>#ro?XwO5EjqP+VW?Qz8^M5&yw(4|B=^* zjkamDfQKz>)ltaIjs5y<^T(B#makb{gF)L7IUt1x>fuX@P&l#uJ2*Sb2f|~(es~tw=4Eo|tzKOy1 zOQ};GJ{_&~q2>)`O8kGCp+GM`{ZS6|0`)five!qhp1gdrtF8_R>+cCO?dG92P8NRE z*^6?wq}sCieVEwhvr>XZ9xjb-_L`C8sOVT;?U9#qK9ZtGME?^Z;e!DPHVau#xAaG}6+_8Occevnrb+~e~{x(-%Wj&Mqop<{?5^m&g zB0p5)9i_7-(9e_)Aib7-@Z4TP^3;iwxX9mLa*5$NS9^y84(LBmVMgQeoO;M=f)1{a1AX|}J83=R)hzEZh= zU#>k4bztZ`G3COS)*NVYJGe0P;2#neQ z|8~AMMwT#EByCPxiIPOY_Gv`3u})!|A{oApl8eqRZGYm;MO?h_)|KI>J4{K` z@J}3W!&5SNkAWdM45Hw^UA!X8K0dt5Bi~R04_B&+i;obM*(VG%NYU{v%+yuT{Mo|_ zd&pWi!hiqH((LVxBSa2u*&;EIf46gSX}hpEkRS(5pPO-zA+vT^d}W5O(UV|8tT^o3 zCJzPa4VyL(AE3>c$Fijjk)MZgXI00T)&C?g)8*@b)`%bmrOxU_&aeqie{i8h??yk@d7_juNK_2XEZ^i zrfl(&E6U7>j=CqTX1Nj++`LF=CZln43g+KJxPlQ!CDv1h>QENC?FKdR#S@uS5oOh9 z?ZBLh7=G!Jzcv3bF54)DZGZ7(XB^s?8GL1-K`gmQ(i4&gOZZM+(9y@_iWwcmbG|FD z6FYtG>p2;=snbFXXR^t%NVqrt^3b*!p=aMIz$Umr)Qz z*>P69V$!H2f91xSMF`AH*oKg<7D-v&b3{U^HATav1H5=m!lNl%@Z*CTQ^3lVHeR*Q z^M=1rae<3lYVT_7CvflSs3+cS7aMcuI-(XSj#-^@w$e&fX`%hm-`)^|<+U3WxJw?u z9U>D(`2-Ix?Dr*B2AL64ve~JtuD_` z`5n#PS`nj$Hz>nzby8H^CQ3bhR3h=!k3^$R)_7K!%B;%*Vy*R3O7Mrs#v$`vF@)3b77~xk0a0>EDe)8E~sJVMAkqe*rTb@x3u@fNxY79{J}5ET)R)r&lcCVfi{{ z3*bEtHnMkmM0rrM%s<-@MJpu&6ZS=a0^V21>0n%~$Th;tKK@zMrfehC+H-}AeTf`2hj2>?lg+$d*X znKN~Sa=N}seHp(2RFtL?w5WHvE10|38N6Z8=Qf3D?^fY1H&C09=*m|^i(~ch{B))y z42WsLpLUIuzyD{=g)I5htdzy{Zo=<-tKA$4D(K#B$a@Y7x=lvB+o&Ff?od+6C_7{Q z@!bxk->IezL(upn;~4O+D!_@FWpQeKSiutyj#QVH)C_I2g7A8G7my#>T@4qP zih}Y+j*5*@0A^F$3zvbQprtC3$TV)aa~=8ZW@Po2QCgb-i-IelMrsWHD{M{g$!|l8 zj5+r|U*E~xPWy@eh}SH(Q&A~Xo#YESX-z5e@&n`Dx{=SN+-aBPSZL4WVx))vK^!?F zVvR-NE07QHbqu#bubJ6sF=h(ujekNqqvg~*i+ z8iz3QgrnKIiY!8Vc39HXi50oZ@))aWktb*thaFoLMogD=r~31GuW#`DKym3bxxM(t za+Z2RrSK`&E!z+d(?6&+9ZT>^KhmdN(By54-f4a4p%ud7hi8W?IF1aBuOoXEoG?K7 z`J`={$r?-0z2+v#V0>Ye*oy?G+EVem1m+TYe^AiGD~7wp12A{5PRKfT9`Gz2o{a|r zNBqO+B?z#AauQNTgVi*&3E=`W10hB|ZSYDulHXWYMtW4>DKf=unH$l0xXU>lazf(O zeWkLJ-V-5=asQa`wIsPxrE0$BRwu0WvCvu#85tEz$(kG2k!PjtxZ;<6+V-DoF;t$@ zMpR9d;zAZ?nqhYpzLxkwZq87Q7}ji@Z)7xN8jR_R82RfzrMaL+UY3|stR&~_EL82GT<7K5hn6qIihB}&T$ zb#bOtF|)(XNG5B_{uT+p{E^#2{eALhAzSO{GOhJZuJ{D!9~pjWkG9~%TUR?i_Q*^w zz4hU@M5oqdvytpX#D6xN643t5nn4VRj$p|mm;m=$I0n3?{Z*+P0EQ0KyUrH&Y|Qr* zv?Q!r^Kpnng%9vh6atr5^kPH_neH77vOMSSTI6BqWDqvE*dirllLlgArh#+2_l&{yi&3~X8A_S3yF_fuzu*=ur zu;tIn#QB;{AX8gByDp1;^5>hFjcF9vxmm-wphho>2h67Tv^7PUYHp9z1_rk0u}>w1 zzX>ag&q|DGD&e9!_6r67uf1SGv_cJ5iYiSU7Zk_0l1c)@%Og%ALb@Zy+L8GA>b{2h z=&~SrRkx$~H*o%UZ~L@h$rJydOmTw)Dm`Z^xswKs>IQm65l!Uv-(^+=!w zOF?9}+U3Cw2{zZd>YIcWHwP1Zc9Iiza?|rB?ATTh%Tijp$%;qSEEH*9CI5v$o;HB* z^VSqsVLVSd2eeA03+hMl-H+0bV${sp>+#P4+s26?cEj8^HN(N)8ki4=`r=0xTMf*3 z>|HqAg-mg{p;Y>sB!~eXc+<}qd!R_wBv2xwL0rz2UI7nCTSgFd?2p3)YA~M#6^#lJ zV*`8LCCiRk@*scG`_89tQNZg5ImioU&NPTKVu&(sJB}q=8p*6F7uvf$rx`?!YsPh0 zIGSm}e^MIye<_V*14|zoZ&WGMf1S?3@@GU8Cgeu<<@tlSh~J?oEgc~61mAr-$sM9& z-w|*Cg~1-`3PhV-bPzxiY$U<#;>5`iY=`|dQ%pl4qUj|`5l>vO^xb@~^9*&Sr$CQK zL1kuP0h8~JF1y#^B+Te)^-0#Dqj&v&xein!x@y?p+F@=P@O?*`7Thg|OuMGvUK0?p zyuB(kGYZ*kNn4nLAnQkWA`~y>j?}B>ksz$3HK??FLnLOJlvG?~y_#26&c>egf0y?3 z<^Nxr#Y6Aad<3OoU2ZD9N`;Ud;h(R!f#L7WeV`peN!m%P8RdQ&G^_2b+aAu`Ia)|A zBt4H4DHccGY$#Pgqj!BXZx^Air%a%Y8IHjX;XdsAUxj z`tOGjul4r)-c452{X2}Q*eeXTs{L$Adl%kuPS<1^0=`fW=SyH-D48N9;UVY+x1z{< zA62`;Jt)!^#YUOUWJ)~58>Y7?uZ?Cn1fr_jGqJrO%E(?u?w#>38e5ByZHB8S^1q|- zWWoV7Pg1xvf46-6xr59{yTx#bg<<{E15%%lNw8J;rjmgSb;~O%`Q4PseD%CV=^pg_<$@EnpAxo~@8%&b^!iQ^Fa-&q2Wze-|Dc3utGJZNX(uLT&8CIa&H) zoNc=wx}CEVQqP+X8U2(){I@%%N`wBgWk3F=xz1uz2PWI$crbfL^si_o{#EMjVdP?O zwZm~}j_t7Vz-t=>>|fiU@zX}WEU%;28$QWYrmvaJu-V2f=t@%jZYoN`??A{G*ItEw zkIMrhkibz}zJtD<8&ZB@MnDDA1f+PxvXakiW?`Z|b74+aCr>{B8))u38)-Z^GznPk zA2*Kl{9iSWgBH=zl#9G9yg8b>ymNj^#V9QMCeasu!J7k7GRNn+O9{6E@1$ReuCM1; zhwK)U{4c0`B2-tA0YNy?m!F~T^=!0n*~Yb!tLoKGqogH|)6a}XuiZ@Fm$@UUMZfJd zReRrK%6Ix)OVx)P;?4J`+j`=r+paA9fIs1 zJPAf~D65`MIx5fP|ALM&Aal7tqH>1@5PC$S@iXwvogn;MZUAThaD?y@rKaOszmqM0 zi9A)ZtdfCb^;&6#x z797?;``l!>TIEh0i(bobf%-PSf7l$v1U6Cs2vxHYn%X-!z<64u%wh-Yv_yv&-BIQs z^WJr*#=D&?iVa?a$l?gSvqWOY_7VM^oLA?AKdXPHF2@SseP#?})>#USd{7cS1pXxP zik@I;zn}g6&uH;!k6Y>T>6&FP$Sp@zS07;l}=X z>A@jY2Hbs%wC}iAcAv2b0P0oBY^vY;ZIT$V@F|sF>r+o9RE6_Nu!R04SPFH$aT3(j zSE@TgF4#(e5gph-ODk9yg)HO-qE-!%CQBs_MU+AAbTdmIcbjn7g=D+8%n~$i5R;01 zD)j502oA)Uqib(7&6d!Q0MAxEKld^pQ3XZYSKlqk=DZ_6&WFV;L=)Gl6XX0?O3ZMzjuFuFv>Qb*O0?Rf-? zZA9(UkJ!%U0nJ;}6ySn0%4EDW(*YdQSRXHh5)@Tli_Wy;1w?xYku-ax2Sv1=5e;?- zK6Z2{ksx(59sCm!f724FvK4({tc)N_XZn)q#M#d0%vNh)CfOoJQ4>&`Hi?ddV{rgX z5(}XEKWu$fSX@iDEv`*)cL)$%gS#gX2*D*lqm8=-cXxt21b267+=2#ocXz#=eg1Ry zz4tp0{n9V1R?WGpri?LWU#s0UlrxNU1+({=q_5OGM86yrS$^;?4?yKF7ap zL-za_ftCf3fuDDbG(nY+T}7-<`5tp|f~607dJI}KB3Ld(v|Mw8`mH;R@NmkEfGn{Z z;2w#_;+-uw!wUJ`+q1r|s}8fKs1A=5diiCpJa(;;kBi>EEx)TztM{2jD>)kOe{&9` zRFWq-=Pz5TLXE3k1MHLt!~6e8g^vTFg9dICTDFKNvvCtMN!`0T^r9p_-@bKWj|-v- z@pDm4RPBWi?aSB$thNO2IKztM=)C<-KfIo3cLa+V8sscX-~tbm;YtJ=OqG+{Ky>A* zsX4fVWN4*dAMzoCLLyT9S;e=`takXw92ZkzDPzJMKyYUCp?vX|GKueT$5 z;WSvujb85|%#xTY7NK-Med{v37#C+PP<+vi2!_`lb^p8oj?wR!&Kf^hY9CGa`k2Hz zo3oEywO6aui}Q_@#P^i9P-cQ0e!(D{jBGAQ@f#oQHQ1JR03tyV%}zcbOSUuh7`j;% zD$g(*GLdViLo?rMKotv)J?r!pgAMMA9(WBRwr#I zYI?#WcT8?@%-Byi83@?*cODnWsZ!Paf%Gm;2MDK!mY`+FJ=f4LJq;BG5%WwI|O6&dfV9V?FI)IK2eKD*6!|bCXmmD{z7n!PoE1HS0Yz(1C=*4Pa>TgLY zV<8olxZn$Cl8>-js;uQhue?=6S~Kor_L{XGFY3U{u3H>OAuV=G#VnVBN&sMc|8maSXZoR5=(3e3|BzK2$=OYUvG0en20>ic)=pO*b%P-hJK@DSD^|vmJA^}k!L^gju(iWW` zTkId}@FAzR^}n*S#o_&0%Xv1x758are{CwtV4Nh!?j?&n&^3`qbTNbBR6j1LHiOd& z)N3)vTOKQe;l~X+fq)(>dz+Q&7>-{?BituSo%C<{UygemjM~{{8s?AHxUo8)y_p(d zd-#nGG!1p3Odx)oSLIoM5t#K%J;Q@ir1C+OmF6liCoRM<_Qc?XgKO4WhGi#Lu1X-{ z34vYjg&X$;%f)I7i-!dOX=~YK*@+DO+Fqb;?OHD`WlKM&he2)p?cX~2;!l74>pU3| zxD<2%@|1dW6ceeq1fyn;RTWQcq+F(MP8ECR%nb&H%z8hQ(c9McpGmX)4EN9JnSQHo zvcEcIt5A1{Y&1gY&SOX@S}nnU-|^}8WDFgEo^I{&V{SVq0gV7Lp?G(vk)0fnl8x!gyR4c(Qa=eKZg zW2LKaULK=2nv>QNr863JNbetec#20W*o?wi%=Ix;wQqv#DtRWg)|iN_o~!B1hn8HU z%D8q1Kbu6U$Ry_hM*TrFt=w8eiJqrSr0DU%jx&;35pq80k(;s10K|4JToZEos4(Np zbQLHa9A{CfjrwOhZ`v!(8hMF-sx=%_p;1*W^V_`!M4@2FA+IbsZ5c@udxx#haoDQEu zu4;N4+p+%;hNyFI<&I_U~sdBorRB0wF zVQHp@)5hqhD#rze`-cfHUK3rRUaH4#megy7fYq@Qi?(i3;-0B?)5yEcZy&E=Hagc6 zztscP4A3K+6Ws-n@&;lrHDTG=G190JTN2WV?M=o|;K|CMA>TK*?U(^E=REkF+2m)a zlZ0CANX|%L@v%f={oL{a-wulO?0oiFv<-CD`@=hD$Y(hpKuSbH-JHPWi>DzE3{h`Y z+rMIY=*0tlD@4_4(_}r?%&RqZ=t_pK%^p4Zf&757_|PVdypyQOEGOLjv(XfW>*Qvn zczcWnZL+CTY+&USP5hCZGcZC`q7@vIRNXGh)uQT$^Zgz;@05(|E{2UeHp|B`oJ_69 z(TLh~=HKVvuaDYeM!g!?U)gDbvj|nHq%?m(#EN1UhhthTm;*>k@dK#S`LhC~@SRts zzAxV{$q}mUuBQ;%YZH9FloZ7|pf=#9{+nF*m)-w&!9GJBz|O=;5(b_3n-t0KeK32I zBz+gSO5gZ;Hy+uuZoeayuUA6~9JRUbX?PXt*oSfQ*{j`{+I9EhbIhLFQ8d%i_ZA39 zOJa##uM_=bB*j0bvbl^%W{+MMyCXeM?_E73AlT(wyNjwSftq;W2HeFqi*>bWyIHNwl35$F*9)fv(32duqks=Sp4rYNTeo?m2 zrpb3TJR74HEal$q1q)n>_!XYEe#gFQdGv6;`7CJYfYXum_4ZMaL*{cXAJtpO z;8ir@o#%vA-y0-sN%|!|Z9oGQ7;mH1b~XeiVce2n-aO+35%g#?Ib&*2WAVM+Hl&bd z*e7X=h5H~`#tBf-T6q8np8{08B@`g_y5N707;6Oe~8MW5z` zV@Sm&X*f~AO(J}yhFRum;_H&HcJu`qkvC;K7SD*SSXjsccI(0m3)jkPYEF22iG7kHH*=37B zpjV;X5S$h_ljQEHEXMYhwQcA({Xn2ta;+0I4m-<(7u&w^mWkc5tP%my-F|FFWRpvl zdUX`q94vz~{KBeix~dZIs7Z4pEb! zrqo9pUtrn0PsiDWm8N#GKYI>g^-WaCwa&w>NV67U8(U40?#>3@aL=Gu5PKrV*5ly}oH=3|=NUKE(SucvQ;_gqMSyF+qRq|KZ7e*v!cgy^!GnTSDf7=`)s zOUJf~+ONZCzz0ds+V~~#S5$(R;5P~i#vsR!(MTszA3EAC3e1UQZY%v>VNJnKd^>4s z^2v;#z01bOQVK(Iv0G)p)1Sf=@$Qnd47HP&mdQGMOh`n%D*Ewl80=!_L7j2;IcM5TC$ub=UY{rKsVx3%^ufUMAtu!g;)7&clKP;incUW|n;27q4maIkC zu_LYmbUSYMf=V_OE^g2S7z0-e5~4iWW@@QRM%Q9A1`$!*PyIRS|GgoKDp4>G%Zq|W z7Q*8^o;rz*vWCv%p6?~Hi~s>1ccgyKzckE*p~=zi)csl-cLBn3jGp7{e~D~TT!|d; z1e_GL%tdVLMX~Pn=iuf(e0}78S#7d=(FXUrX)~3$?nGD$BiFG>@~ud?lx6z-=qsUj z&>|E%vTajxb!7(F`F`wjm5(U|WArt;G9jO-TBt2i{eN@X^ zj^n1+G5zN@Qa=Q<+&%x(Gfo zKUDvmfUUZ5KZU{#8Ykj;ODYLmEn%;#EpWGgLn%@p_kgEF#Lxzm2-yZ#xad3VHj`6I9Ch& zvkXD2JtoPEWFGiI{mJ;lzxMLR!#_5e^42KGsk#C#O?upC$Ge>$&6{%<(<#%$d-tCB z7LqF0-W8ykmlmf45?TD3cJ&(N*hSo(#|^Taq^0^xh|(?nbyhGCEjKmJ?)5RwG6K`; zf`kx~YR)3QQeP@>DM>jqCf=!9pj=JBf-m+Q>aIE}8{+l6bs3ryp7A(E7IQTO2&xT; z52#(M*7e>fiLvh;X1_G{twGPy?t?K5N2u$<{h~wa+O#o7A{-o-5QPj(t%Mrm0NBc* zNQT(#X(^B{WR2MWbRnIMAomPCF#}OpAjRUP9Z!?wkQDHqq2p9(RpmPYsTq($tU~q z^a(2n;hHzzbJ|y@_u0tOn}GM#;fulRo!-{ihel8tyO7=lS&Y@NF;1reZ_}1Tzc$_I zf=a_|IGYuS$DG9SztDBAcQDXG)NW0~c?E1sezUiL0SreOmfT2pF?8>txVUZcVL@ZyaFTDHrST z$(SNtHr`=m&bcTy7XpWZC7M_u-k@P8|E4}svL^kzz&!7k&AO{J!L;KgK#x74{Pzam zB_*fKJQ(BaMJF`w8#@ArSE8ZIHPfKs3^vvI)7+eVo{bCP;x9^hy^HpO?g|3?aT!Ue zr-*tG9j_=0j-quKsi>+V9B z|GKs_uzGDVSC33~qOv-C;%rz5UdyoxQj42LQ#>mhc z#U;X^`SKak&>pn??rblFk01c9FseoT@tipD2NY5SS``QvW`V868}mT_2WdP057HL# z4tKEBZ1e4$VeS0DB7$4%W>EnB`bIG0BXD2z-g+)NChiK)wN0AYwHnx#gW9!f7?N^- zx!}6{)2J~1Ux2XfUx09r+^E75_1Dhi$8S7Nen@Spvz;jiE`7^pRVLG9O)$;bx2UY* z#v3nfV)#K6f+H9Mw+|8YRi{frwp&*4*`AGalvx)9cvvo4kQ=th$CPDylfWbjGHvyk z4~fra2=Sx&pFldspYL?RkK85BxwYPUQ^>?av29*ZpjlWd?$K-o!QcjCJZu1oU1-l@74iQ~=$ zzx7o0?|op17;7$N0mSmR%ygozgo&PN3kPuL)rqGmUFXKH-TQTGizxZI9ev5Sr(Sjx zNM6&}CY}QH4YM258dD_;ic6KU_1@3!A5*bYgA<6q82Cn;h?MDSw%6si-*$Ue-U!m*CckNTv+^FXx&%E;|$M)_aEV&0)*mqkG=L z1CA$g8yviEv7I~vbDF9R20Pl}I(yp zFDXkxd7K%HB)GTblj3f06|32L5q_jz-^+!Kv%mj6QL$$Qn&a#Mf$lVg z9eCS>T=`$@`dZv3Bs}K4uA?$iXayjuJSO;_A8V5Ant#8`$8Xtg4sf%|$YAjbx!R57 z{7P8#T9zz;zDYbghf@{^q+(#YNnaGIKv)~Or_fs2$TS2swPBb4D92H2?*$b^d!nbh zfby!T=>d8lS&|$I1NI{tBAeB(+2?N-T(x|@R*QOcdcAXWb;GD7+Wq5Ip&w1!D}JZc zvq59hr(zo(*7p}nT$s(SHP%c1YG2vB85}-*gUFIC-jIwWwlqXH`O>L6@zR;#k7N}k zUwFq>LnY2C;jm3_7!?voIa|C?f*9f2PN<|#)+YyU2&5G6R%E&dyGCFlyezvKVm!d& ziWCHU^tP?Lv^*tY&s_7S)+W6;Z&NGDg=B_`^X^VE70Hv)9~>WRSmBmO$p@Bc7v(dE z+!JTq^)=2oPsY2R!AA9!|6CQRNa{^6Onsp?i2n<&WT_~IAnejJFsxB~Y}8nTnmN~k zSsR}RccN_8O-sH6n@gSgTm|!p8D1~)-VT3HF~0$B7QqevChpEelLLaHGi^<=FNJqh zT%}rwnIg{%SSly)C>psqfW^!KGD?gKReWicdE-xk6K}<=XrEPQMTY)HOS>B3 zE)D}Ma>k-~`(d=k4*u`1n713>U*WS3@HD0OqC1Ohz-?^|>f-Ih-x)CE?Qbl{2H3xe zN`8*5#GpFBjddpz)~9`hrH^owu9f+j7K zBJv8p20Y?f3#7Ub6Xr? zN_r%vm6^jW2d6xe7&B!UEy~8e%*s?&g3PzZ^t{@|5~><=tlyo#*m_^aKYhFZZ!G}3 zX?LMg9qUlSf%gxwc|l2WW6wGgfjN9bgXzF2{kX7DBL-gO&mQkTsMPUpk2(|j8U@yZ zezAVK7qgX4ve=f1F4Zh^)rnjNZ!>ItRCQ&befN3UK|sgl!KNwoMq2iZFmfyU^YBrT z)_x@G-A*U2kh8R&dzz&nw$DjB&M8>jE#fOunqPfKcu-ftbIl?dSq!>BS zDG5qU-qZdPSGrkR_$H&WQ2HGB%m(XB7&9(#!=x;?Ej!=X1f~ri=vCbsJf0DZAi%*p z>XQTR&vq`j&&InimXrI*KBqX-N;!_^ReZ7J5?0zvE`Y~OONWHR4i{%EfaXjs;@KhK zjz;;i0~3Uf&58H)&Ztc2N7vE$pCFqJQ$w0;+Y6M5Y8mvR%dbF`{!{Y;d1A1P1|HWM z0U28Pp;{CTZx(>D#^^2$t>MqAG~XfB5V-_iR+x=a$=(b#ojVE+77&4iLtkWWoAb-> zdMZsmdpWld>tWeu<3-z>jw;VO`)A2b8W}2K;>Zv2^`WfOzw^r;Tezzyw!+a3NVIw*3gC1`)HbuF`IQo~!@O{JsH{OW@Vxg+ZDC`fy7 z+Arh_BtEQZMnaXKCY}v7*s%@0nih?TDw+z_fosW08%h%{KkGMZIAWIw8Sb@;Ckw`%iJOuc!$<4`%0x;5P%7O`LYtqdoOkob#tJh7yt*Tg(%hP|j$_2lFxq^Zdf zc1QO;m5JeBNYnpSO*AcoT#vqKv~`Nka3Y%bi5VG;gs=lKZN+mjKSc%0lo^o-{%)R| zQ^(GXBCEa2;2|r=@d#;9QW4ek80bQBHf`c@Ey-8bv}gsth)CO7s>xn}FKIsiY;a#` zAM@}HkvNH*i^qj`Yt0h3A;l)1qqa=ju0b-=FclBtZ5#)`wk_xM5c%p{;&S(bzqj?? z4v1ra*QtAnTwNCv=GmFZ%9V*XSiW{XxWv6je8CpU-#2_fU-d-X4sS+2&uQUA7qfOhGnVfeRIY za7H{3oMXM&Gr@w1l_G+^o0KNv{)qy*nnOzv+KDmXVa|wRiqQNH-aOi>-iWV_dCeex ze6i~JI{QR*#c7A-YKneg!zwn%O19&*!1(T0-1vYudEsfa zP7oLDKyFSUMd@4-5g0vMy+b@un`5T`EouY4V11VEHO!%uSi|<6C?PXhu&ub+yPiWM&yY7&p(nhtb*i zv|V{*po5w&`|S9qi8Y4m2R&Va*=_o!(-tP%ozD!{&#r_df?itFKy`r2>!ZN&;|;;% z#^=Cgh|UDV-5M%;^Nma72Gv=sUR2ja;86sa4Og1m9l^SlFG&sKHQpXxnn?>0Q8C@O z|L13L-dnr&w04Uzx@BSqvM=hSj0894s9(R^XI_h#Y*$5(@cnz?zozYJM*kxZ6)mcr zi;i1YBm*so)nO+{IQ(-*Cz{l@_;glXgP=toRD@^ZW72i9AcY1Hzd7kYbnC{uSY8Zs zE_;h{ex4NfmM`T1MfrS6Aym~&A+j!#S0>o}(_8`SJDXE}9L{!5X;LK}OjPZZ7qnd^ zn)eM8eDOzZD%@CIx-uVgdO{c5#JXZ8v;^{+{V~yKKBD^)U54WP&>8kMCq#GqSN0#U zdZ9cuFsIAQK{DsLc1DJmn@ROOc5c;?b>z7=n5;~IzKE(5CcU;B zEpuJRN(z?6AQlbOG<33p%cPP7Uw-3oGpn}TdFR8ukl!%IsH^avN5T~sta&h}eHU3> zfpWY3*bQvY>!nsz`>ijjEc5_}+(>3+-C}gjN!ldFL9$A2+8n>SZtA{|-Wq35d2}1) z4|?X#+nq}gPMVFNI+~j068r&g z8>&BMyN>xf>~x4185iYF4DT46wiuZJ?Is^*&^gz4M-6J%`#-c1w1=E+)CWA!vFy6#kUaV%A_B^U>u*I0TK${eDB;L-Iy zp9ZR(dI=V+(aGYR3;9;&$aUUdLB^_%Zk{}C^bH$>o_^j5=iSkm%U@?H16}1Ri1o!s zOeYbr9s16B>I`@ve`&?+^`~o9^Lk9qRXy>%vJV#*tJg=;uaVu;d`Fd7R(#^KWbM0s zuG`VpAiEgwQK2HHtclffWCpmYFnq)#)-Ji;F1ppx)98rUj(rNMIZKo}T#Zh)LRCrS zSRTkI00#aB0|*GuIV9RMwPW>L>u-qS=X_nldd^u(CaWZ&kMw}yszpMjXTc3uHvCvC z7iu1I(c*RI*xIzNQIxAcBU+u=cWRtJ5u9P{iafsrNCv6jAmqrkFQJptF#Rw>l{gX# zDrT$Nh__wKXtZGThX@@{m|U9LB0mfeD_VEbB&iYHX12pb5wzwbv)wM74h3(Vhl)&P zL%zV1yO83-5H0a1aio(EX+G(Gok7qRVlo>;RCW8B1cz)@C4l()bEtvTg{e$7A^N4} zKfW;jwRSrz!P6h+c~QS^3!Oq`1b+o0SaPmAIsXtUY+E0xT3H;iv=TTK+sEGexz2vMh%Hh-(^~$dHA>Gc2zEGB z(K{>0I2qc7@SI=ZC0)+ia}e@2o2$deE5_ZrBlHM8l||A$ znDAvhfy`<-5XlMk#os*L_FJ-nTm6amvE-Z{zCDNku?hWeKXZy{%TLO}2TPvOSCUxM6bUfN$G8J!? znPle3)q9wbyYJIc9t{dAbxjCNP&|U+QIFb(KnMLpAKxAhUFsg^%;1Pp(V@Z3cU%b= zOrt)r(4DnY<8IsiNhouX<-A18c($dDQD-4k6Ty%G*H8x2;=1=k##33%typnbzZvZ9l3BzT{8AH8Ig=P-4f)5V zl5$+Xg$r6Mo{I0V!NvjL*iotZywjf{gGLwRTFR=^ZB?C_)`l84BvkS$q@csgtBh5V zzFZ(lIM-d#9Ja!6MJ#Xr=$^^p`~v*Y@gOO0T8AppW-usRVe-3Rr3$okr$aE8GdqEw z>F3ny?W4SK9c> zmSEG&=JFL8VcboaKVU8?+V^+>Q|-jiVHFU&BxV5+LV* zB1#`gU1JnJiofWqLF0$4RtgnYzR!kdC~7q{LZn2srw$_BM#xoX_oWHDo%4aArS4gA z7&rO6kH;3OoviXx-_$wAj~TR%?TEFXBq~5qgfblB!gh5Q&OD(_Un3O~EtN9FfrGs7 zp>lK(fk)G7`-|{-AedAf>f28U{yT!?o$EaJdqXi8YI-z^lsiE+@8L%~Yo zAuAQ1M2{VfYCsPhwtZDa0!kG9K{y#IlGt)fj8JI5je#MgKW@bQj65*$97fLrfjT-m zhoyf;Bs_|#wC4XVo*n>wnKRO7lefusbfa0B!j%Fi-*6bXeCIuB02wpYuE6d>o7dt(eG-?&VQDn^_BCOTCd z#@1SvZ?>s6#vWQ&Xn@qlhYg@CQV1e;$>D4kJ~=`GNc?*!3{k|V{BOqbd#U!mHr)o# z?DVu6$rTfX@n?SM-xSc^Z$VerVagseVp+mv2LeNQp1UZ$jI~~be6h3rrPA_ zzw+X$5M3F2)@0%Eimry){IWwV5`Y*2LG?xw4sL6RPU&`gDW2m(Ux>d4lHaJ@rS^(D zJ7z|6lv22LUsDf;h?jXQA{?9IXTIDLmB_={u7aY_&Tyiz7zVI9I>}^xU<}wj^(FEw z6N_z&i@(AK#zmaKXq)uoLFTCbxY+|_(xXV2z02z|3KzlDrENWn(%xv$ww4?hZp$sl zITi8%{HD?KgQ(vG2j(PqK`ka8*Z}VxurMM-_6CRJy%mQqW0u9>ifN*Iw)wr4Qd%Z| zE#L6Bum|kFB?5TIX`OckEW+J@hbn|(~4{gCCgZj1Rr?LDTHfkh}7d>(a*;Fm6K z?bt4pt?k->YpE~2yE>yet=V&3S|A(rhscZ>xj@g1)M=k}%c#o@A+&aNLHsx)q-#*f zmvH#+YO-MuAS#X+!r7#PjJ*-m-1rG&9JmS{m8_4#*ev+Bt3-yDlCLr=ZWzwsQ05>SEQ$S1$;WAwBUO88)CH^%XLHc?!HU^Xtw((2jCE@ zx%IfT+%ExcDT{&{wR(yhwkAcNN5uG%g^Je1c><3hkfXb1e}o`2fd7|b-U zk%1dRRJZ{v#d$Rsrx}gskw@JV{w0{{Jg7E{9&ZncD@f<5lOXuHXpkhnfwTy$wJDT< z;>sc%uFz3h_ccxsopC?1TpX{50j2|t86x!|7V*O5JDGwkCD&nLA{h0T8s%^N*@Q^y z05gVj`wsq;e+b%;Of-&&!iX7?IGfPG|BXErDFQt=Lw5)#~lB)ScBDT?N8>$+jo$`YymK;sJyj{Ux20Bh`+Cc#l`b)zQMoMl?- zpwtYUYHrorgh1*}@^@K=vK-PV0{@Xjv0@F(nVxtgR>Nw}s9&u8`}Ff0YB778?xj{M z&2wfzqijJYir@9n3>W>+$l{IYFg%vfeiO0uBH5_dyi1!;;3{JHT*GLvPaM%->|7PS^U9a{Po4NWZ|R&T`Ym z|D#G^1>850wR2q-)ZcWXJz?5e{el{Ae<=~Otj$X~yo2X~Dq(Fppehz4JY=cL&GDVJ z4YUzQz~wQnAV`eif;p;<;)~Q8tAFG7>*bDro>#oC?zay_y#3HM=tm8T<>wKf2w6dR z9LXplQ%a;l1nK;a1wk!r8QwBApKj_8v|c<4vZ7iTn)}POJUbC2JrG?ITB(1*t){Qw ziI?{Vbb0QKscMP=@N3|6xI+3;ig~ZlA_iimaSH*hruXmA)@rfG5qe2qz_|dufEC$$ z7)Rsn&bf+piC=&;=xFLQr3`0*O|x>90Z6GVKM;>WBm z>+~3(uNXl;@uF(!4fiK}Aufp}`7dax{{tX{*4KmRKuw{6i+TA+lsn_}DyngJBU@W` zN()njAY%bbfrh6pmL?-)NepOfN!WVQ&^tq8Au(hKF4uEg>(9Zm2S1_Fsn5jzOr?bs z)JIn1DZlsCq#9cXaN~PDSw)L|)hySK7mo?03sBG~qn4JRhsf4&VD?ed9~-g!qgw+Z z2#@G*3y!z}ff(fM82B!=v%F~uaNbzXqB6ghkS_89<-k+t)b^WW^J(0n-voy{D5Wyi zm%4k&Jai}x>NwYd+d@TJxltf3YD4X{264F$DQVrbQ;MCM?s3Q>yuGvIvAydn5Qg;Q zP@@d-xA~#be;%7s%@z^L4D-fp8-C&0qcAb@fmD;yVwTDF^qSoEzDulPf=ZcaFQPtf zhwWP?#6}ZBI1tYNuHt^_$JK)wD3gj+@?wkMx*Lhp7t>!i5=+kER4N|{a5_6NbSk0s zeDkyJdgd(Dx^|renl7rYN;gW==LzjO?x0RT@*#@*X8`>^gpKJNL>u@}Iwo+e+i!m_ zq4&QQDF5EJr*=nZ<}*CVne6i=KTEjwHs8X_Hl#d@I<&iWt%~hB-X@wmzbZcE9|@4@ zPBur*?m?p&_a$B+jH7o&ZrKsu>cCcTS7EKNU)JO|lJL#`QutBW9zPr4zWyW=0GCDR zTD+XWU`@FKK|X^G#(JcA>jf-D3xAg zk#zH=Wpo}~rx!i$fRs^)V$FZlTQUeydxF|!L@V(#^Ix1K+7_DGNA=o+OIos=XL_-L z-E#!T2iX?S#3(&aB_I8o^KMiXc|H;OsY#oLGUipI_f-5*=DLzAY!F{zV5S&~ljPaw zAT^~hMI)>jG#pS*kg6n=Kb{O{m5fqDcu&m=lsaA+ubbVpwIGPhrapDTftvTYKj5?& z586WvuXj}$;;3v$!H|;DU!p+Jze*dUx&&VQUhki6`4^fjkz?ZGVB9Wo zefF|!P#RzN5K^(_J-Es^Ba%C$x0LG zw_V?bkiFV07@mng%pkDP5!+n6d*2rvVJuk@}1qI9*cnuM}Qlm9fGbb zLo?B)Zy-ADs?oOfAtO7TtqWm|6Gvn`I}=6COW6F5fI;WmS}X?K)9d{%o2iit>>*5D z8AOobXOs-GM!O5%vI$6mbOuj)OxGr;tDN9elrd-wMu)xETDG@9F0m%5Ce@isMDc{n zKLH-wJq9yS!z>Bf@H&qV`B~oLfE?_s8ES%f{9N!W;!FPAYfVE<^2#PANomJV>MID; zrKW8DqNca6uX&`LG)#^Va)uoKbJapD)bQ4cRTcZ)4GSAf8*jEE72&Z%&xcc_%;)i@ z<>0O=w52G6?i9L6qXG`6MSwhCM_w#l?z|_Hw908kO`Vu7#8a&2^-^SSqpKsM%3({P zxIGQbrkI16ZM&+YRaZ=Js(%!f6)t|(r>yHTz=hIOy zamxo6iSFmZgHdHQIl@`|KaiYlG!a|hnY(=W*2y0m)~~j*mp&{!;?OFQs(ty3u_?+v zK0+#CCE%Qp1-5@s#vR5rW0s4IHE8BTk1^l8kE{a3eddR$YI>9xQn+bpdUo9yxOC+# z57c_2IT0pt?8;95k}Z+{C0klU7;>jv$)~|_0f)1GccT>q{CGiws+m)Y-Ki-(A%O*NTRq-C`(tX^N&Y0*%+R&c@29e;4&ph#Hvjr*`uI{@ zV4vGqaJkQtWTC^At8L~=2qBbiXz-&P0qP2|%4C3{`^UhcaOcY~OGXF~Wi4KPD?eS} zojdyLyTFo15R}d+}o7SnGqvXT`0*Fv)#YGK#4V$qmQgmoVufcmOFvwVIs_ zHfWj&vAr#;eK*cq%U`ppHNw2}2nF?yN3^&JU%C zb=M8Swc zvZ9XQ{hMB4)=6%ywEROO=vMH8qPY$u)S$JA`->+!baC$=eKZ`e<}F7ofEp!gsL6bF zjHr~q-uT?0v}WAiIZux)7Hefa@q{NG8qz|v#h1Mxl!#(EIEVgQBm0qYBfY~hN}(FKiKd-YF{VC6j%RD=47(X8>>>!3BfrC>Y~^a_ z=Yt0Jv~?LGAfb!2&;Ojsf7SAxaM&poaB(R_%pltE*;bdyJi2Rqtrye431J|D)2zw9 z3h2(!ZBh5!i^`)$AD4vB8~L=O5$-*J5OBvPwRLnO*OdyZLV8}JIk#8xwf{0&x+mhl zDai>wJP7XsU>Y}3Gan0`>f@?zk`+o(BnopeHW|93jQ78lUGUlIa{`EX;k*QId6sQQ zGA44r)44W0N4bl*xUKJaxYi(7F8%u6$m_8_%+tJX3g$Z!=za zJ{!Xh-f}+r(_iUFhV2Y8%_o21X9A4rK>h2ma|#fW^={-@-Lw4 z@5ed^*koqm&+sVV)+;*kpHwcO+cnB3wV78XBb(y_sj12Ke;B+eXBL7B|FEHRJbcr* zp3MAp3+^^Qq4wme0tY<4O+b~s8F5|9xkfYA*aGJUG%l9f&G{XV1=HgVWg=r06eUd0 z7#d`2DhQk<0=MwxH;UlRugKjOxsUnb9_xQ-m9%^IXlXPXARo_HOSC#Nse>%B<9kggCXHrcrsQPNW>WK?KJ{AP&6okLxqeaCDM#qTOHhW!c2D@^ zpBgOHTy=I8THnR@tam)!r%H`R~ZlHS!6VQHS%%ouOhNhL;% zf|!X#RYm+rHF!WKj*!;IUO#_Z!f51s`eWXL$(X+?iF%BIl)Y*`Cq=wd!uZ}kkH$w9 zQc^c+?LgNgTB4`*e!}zRk=^zXY5p5nt@6bVpE9*y;L<;GV3WGTfyKAm6}qpj529bz z(x)DcI%`z~<;kX$;ypQ7poJy-s9zz2Okx^Tfw!@nRfd!odH8{(UzG+u4afqlhzp3L z_df-yPoTVy+Id@e!gDPzxPIG^IoeAKrr>gama2Y_ zrvsh)rJw3mh&pd{2LrRFvk4&2`7QG(gXq%OOvAyw=SK}YX5+Q3?Yst@7;@;2_2hG; zbB8;fcP}!6W25$lu4@wxzxcu*;N1Gf?z8jsvggRJ>)~~mnyc3iMr|IkZo(sL7&4if z@L8n@sat=q)^S%{&@hQLD^2~ZSmsT%bvx8!Sb-@R1AF_vP&<-{S8Uku^bTW6e3P*} z4*49ypH|XyQCYyge4#%(ABkdqJ;E~yo3K!X+FJU5sQSvVHoInB3dMt4@ZxU8y~SON zI}~?!hhPovQlPlIQ!Kc<6?ZMx;&SqCdB1&r%&eI;a^Eu^J!RVlO_0fRq`1x> zWTAcanh^UW+Maha?qObYs9^GqJMCM!j>|^NPI+naQSIQM-c%kC#H>!ED|nO)H}BW$|8A$2kc9~IVEoD!Ia>+#!a=kL zMEq%<(EGuJuzJk3P8ciXCdya-vORs<;~!STD8%W*t}kNRS*c_TSjo0jMu{7Ly)mS(=VEr>;wm6x%W?p@9?!t#DXr+rw5U9jvyMC#;+P>@r2K#9Sm+b4BTWS8iwC`cZUPX;dj6wY{juvn-9XBMdJC!CfR)J*wM3Bqmx0qc}kL1jw zY#yI+Ns(nYZkMDvZO3G-o>NZ#8W3IZ?fvo3c~gCU4OvD`kLXfc}%LX7x>26C*=Ql3PPrCg{j z2*RL?g*E-wUIgBD@?hD4Q-3WHjvn6K)2ZVhMtNuN0C4n|y*)69p7>W6-k^dd- zhHF!g6P|)JAZ89YT6qr{yy)=GQ@LK+kd=N>BN7)mlr4bp4@tj+&t_(?Tw#+eDbgCZ zbX46=Lu=&*2~F+Ia3~Wl3zd^_a4i+{;XiZT=T&Ud=&<`;d*7#G;ZfN#8~Jb9WJ|0Q zdp*=97n$!SE%+y_3maI(ko+yRDw6p}xp4m~SN{%7QBt*u+=oo#3I8@&3oj(_!m!LQ zbc%RqfFl~&hSTl*!_sTFKb-VR3SL!Cb_>I`i(25^PsF#DN0dc=_llkpBhj+|-~$t- z{zHnF{=*(z9K_i`Ir0o9&@wKQ5GZUT^{JN1^g`+a@6~hzx77wpY|}LJK&-i@dWL(M zx?Fj3?Cm?cVi^!MEsZx34~V{d@af79b1qfA70t|q&c&h;ofe(?Nnp2f{UCw$ zqPbLwOhaYQqBp$LTZu&dh2IL5^=seWKrUMdtzsXinuf;p^E}5?;T#2A7Mj0b3)V^vO1qjfYX#dPbu4OrURgL=t% zeN!_TWturqQs{7l=}kQDc2F17Lv@8u-Lqrw=d+cdmS{^j*vq+Uj5@)hP$a`x`(0ar zcj!X!W~qrWOA)om0~bh8{LSQNzGMUK<@t{1vUriBrK3vS^Vu+&{f*nbRn~&h)K_W1 zitWX;!4lAgSSg6h7bYfu&f(ldWRUUKX4A#HU1`vifM1G%*|MH1INyg+r;u_9xLEDQ z)`=|DyM&SSRJKvWr^~D^&|YC#cd(l&>QB2OHkwWh)LYI%qZW{D2z@I3fS-|D^n;~``smDAF@k|BB+f(Fmv_exxujVL_n_XZ?3mh9&=ucJs-vFQ zPsm06p8e!d%4pJ|Ys+&KG^ORYb9?y^y=36TYzqU4ZQ|`{xIHU?2->!7h7Yxbr0LM% zn*IhTD`&y{l5}Kjd;D{IIo~+2#&XplofT>_=T5}&;^Gz2xyY6_7*A@Dg-6=97sW6A z=r{B}BQ*k2DIF1Ul5zuGqj))a`KgzvUS|f4yVDx5kur|us%)LFqcL&&!j@U#}yX4=6s|JH9!n}1Q93|SG8zJDPb@lRdfb*!RjOLEf4~4Yt<3&dueJ8cEOgt;2~#5Fhz~n zpHMJq?6Ib$I+UGp0p8|EYzpBW_{Flr$W^fdr*sPa2~u?K0$E0EvGsbt@niJrCP3sd zV#9jHf2X_-^Zwd5_Ocf9lIHZxV!x(rwfGaG+V60=nk_wGJ9nT!h?-VwiDK$Xc=kN= zl*t=KDfQRSm}h!T*ZY41Ca9eTZdFa=_jdCj{$PaE=1mJO_*xIW~8%$>!) zHzTo#J@X|OVHQ|f)@LlNKbQ6N`<3Sw*-x7|W}LYH@HrW!PcEhS`8J*hAg?WwAL^qL z)LIg~x}y7!$*J=dZPKuBeM5&Wd3yKMBe?g++s6#4=jPiaae$!H9*#&wvLLC;>4~TedzB`j%T~qr`kVH8m7N(HLHSIY(0YP zGaV`1=>J@-lF?2s+~}J>RS;OqnM*ADXySAHn7u>{FvPB3IitR}|62E)}N=N7Uph(b41u%p2hmL5`La>%jD&@8zfG;g-PT z&dqLdf>X=J)5p{ursvQ_zBtbs!C;pAO^LtZ?ftmF4A(ZvWtsC`PnN4lNYj!%EM4vj zu}8(qmpwwkMmBv>k7!^ADaYP#p()6xi-Lg5#cefv3_&Z5VBg&$7yI!1u#gw|MF+)_ zvVfuz>0z?)gR~i`HZPWX=6z=&BY??rcQzHi}m7HVx?m%)z~2 zBd9uF>i(}faFd#mP&WeJA-oikcZNn>adjCyqJ_K@j+@gijV3KRDGVgI#QOOPE6#c% zmD6+`e&+7OHWj0Arfy;n$oRF`Es8)J8%11Wc|kg?B(97kvZQe)b1+V~LzS@_rtpxv zGzjswM8lWnXd@4N-Pt#Q6qM=wmOB96=ZhQ_im;!Iy0(rUAGQaS^uQ%q()nSWy2F1v z@-!9Oe2Tn(i0Sz*&A*$Wy7PGn`B3KSx%G5wmBOrus@rc;%j3yx%S0rF4Ga~{6mC1Jc^`@&k zeg|4M4(}XOjC0~^HP{yh2`d_8(5~HvbyJu->krgQzK-S~1{85nFANUGmWGu!lnIa= zt^h3z_Pk1Fpy^BY2T^EivEp-%!_x)BRNp<~@9@BrjmCWB<+h33t-*Y)Ud^l-Gs*nj z@cjh$6;8@9c+f8{5K~JqMA_OOC6T6PSQS?r( zwOTpNm@hrY$Nw1|H?!ASRMDg{7P=MPt&fCw(GkNDuxN|3U2Gz5vKsM6hQhrDWagU# z8~XS+PmV8(8+89XFg*?HgK>m>=y6K_03V8H)U*G>8dPHB&1SOe+O^$Td-ZHvV}|Wo ze1jZPu=;(5#*UU@>(0m@ums3N|QfE&i z;fKov@tWs@oFO%7FEceJoqVP5jKNF-Sg?L&j=Kc8H%&hOfgVH8VNJFSy-lBH&{!eVHBo0qr>eoU(xo|yX;zDu9| z*QqMCUfunP;!^l3cazG~9HVyq5uCQEH9Z`9JA+lR(t5}sCY_1_Tva(Qcq8+glUc7F zNksSFUiA%0ja8;VXJWGUN$HpP4GT}OWB1FuOzvO6)PN=={7zoPgA)9As@mOp257`p zdhiw9Piy)e#dedw-VhcakA3fpW(=RIGI

gfzdt`%VhW7`aQ1w>+M8K!%68hL3woU;#pwg|22nMpcE4;z5-H+n%ML? z^`oZLMO2UpV?-EGU|oC;Uu%1L-P3i)ndV(-jP%=uUGEM6q-f%r?TY%~O$k&k~(^4}n z)`8(Fml0e2HfZpK{jX5;Rm@7y%x5R5(cW{PzY&>M5EW8Kl7{0-l{)w7zYlhC89Uu8 za{W>EBSXevHV;XC;Zy3zqG6i%XcV&hXY`U+pKoO*C~2l|RMH7ES-kh`KLJz3xbp_a zdGOZY>jP{!Ht0HRtC^QYgr<4H$|gdXKiP5jPU@?miH_WV5*-CFMfJ~NAgZY+X2>h1 z3rW5lHG2_wFQLwpxh(Plyb#r~?{+=QUv^yhP#*ehVJ$YR%Jp!NPw)^H4>~zZhZ!X+ z(Z-~4?NlFU{8lk@6- z8)VMrfmy+x6-}L~^R; zB(;=SPn#-tTY5@Aq@E__~JC8p_2+`8rTU=dL)@2uPL zi%BBaZ8$u#KvMKg&ED;XL^`;Xn0Zk(D`VarPKcG3_^|5?MVyQIG=Wd*nx^eFbd^Bu#p28B= zHYF|bh>Ai#gj~P*5d|@-us+UxB)kL;<}ce{2t&p-$@UZTIzKJH_vR*k787XWNXD%@=eC1NWB@Oxh7DdYZx|%LZukbKiB!0Swm)W`@;ZtIUDS z$zB^MCXb&(kOMMN@%i|taOV0ugWj{$@q<}seAIX4vy?RI{R9MWb0p_zq$&zVOB^Z+ zE3uEI*P%BnqJB{)IwwtC%jRdBTXfokO^%=D>winNE4yh{3b0uk_Pa~gDWc!B59W8H zan^Etg0p~H$^e8aK!QdhM{!}hwKEnt`?J56pjJnXjl-H^xvGyvgZ)rT9P-V3Ut=c8 zj3J3j<`Mq~17#yfGh0zcY`WF*3m&WvoBbw+r}S3tN=H5EPr+h$D&+!w z4eb5bS)_GwxUHft>+k&R;TFT~(VI4pyiw=Nv9#jVv+^Tzp;Q-35SEWs$&h(pWr8Jp zFLs(KCc)o%vnG5_*r5G47fD#n;(Pn2+n(b?=GZ9x3yxtPF~I zoe9_0opQhIq~rp#)vs2nvwjVeaRuuW^L7k<*2LB~xoQ zx#P0DX`&WIK1Ooy<;>B@@RAv*)6jBZ#<}(&q8)73S;aD|K>r1=MLhXm4p+4uV*70ipCP|->7V-biC zTQhxMT${zL&t11EUU_^VyFG7hRo^0YF7$5Vj}RSbLIS@}4A$X<(I-SF(Y zEe%zOo9fHdej?xvc|64q-La~WKT+vs1lI4n*54>)aWe!_pQsqrxz%B}PJLiXXVMv^ zk+1$klSg=+)G!`r>6u9d$GfEk^&DaUdJeP0!RcCh$}%M+{59(Z?wKM7fV}jR! ztb^eQpN_byDS}0Ak67qetrFGXZ8>!EMkmncFy-{b86kxbTJDh}s68%9biDE7sIu9|AS=#43xrT9}7)Rbq7~@NzB-B5YniHHz zdPiIvSOhj<0SG?GEZfY1`(yiRAi5PcEUjK^4VMF+qSM%j9~~bTjY_bdn{G^Mw|!3g zzQO1A9;Fq_2NYQYay0dK@X$x|8IrBTIXTWUf^8SuM!oNciAMxKL}be%{cxtiUE+*% zLZix9lOWV4%fLLV$|nXP6aRgsf5l3#sI~7@1JH$seNBZ$-Bn4pimId#UnS9J2Ta#z z(vG5iQBv(sU@{Ys*AlQ^<{59))+r6L0Rio1o zE-UN+-pId&OK|KudmndDGk8IwZ~CZdLiZ$o*MB{u%nubeEr=apc-@|GxO6K}EZCl5 zLBhfs*Gvv(z^c}%K2DFij?PQ$s~>=!aRILm4Fc8HNrsZ7B*C=jt=ag*Q(}q2@HS=1 zUBb|z#6iWNq&$6o}tGsvS&i30ftkq}$hYVisAbt;3?uL@Ti8_uP~4e8?A>0a<;&Mnk2)=j*av=tKsjcR53_khDN;vEhOC**c1*g=9Lc( zzat!un#cEz8z%c~zMeItRwv^qXNAVb2-GkG1=bMqTp7Z3MV72Pj5|yTU-T18ah#%h z!)%yO{Mp$LmRh+N;udzaegS7+wkpN%LLqm{3`>KTwH|MA#hCSt__Lo{F+Vp%*nXk@ z6j`TdgN>Dxi)p!JvRc(1>E{;Ji7YAN{UsT@2+LYhgaSz&D~vr#k8#s~2CWGxi4o;1 zBokaLp+gthA-U*FMs} zRq`qj2b?VueT(Fo{_QDrkfRWS#U@LC?anOg!g z)`46G-;eAc+~n0=p|Din7VT1x1c5dXNvd_Fv6j zzZZ?pAKwy^<(lb7uHhtCiTdju0hViSIx6Qz0cGI#2V z*B_h?V;psaVCuO*-L+Y&d?m(XUjzKNr|iaC;yOQ)2CRA6x=vbs9zRX259QB5lMPwM z4GL<@$niF{y0XS+A8ant*Ka+olPJWTj@zY6wi>tBs{~+Ia}9&r;fF1&js?>v^XkJg#ZVUY_)`4M_;#|BY%rF+1+}w;990o+J>wE6lf$jGoE%B@ZNXP4qni{NoN`; z!fVgd*>)LN?3VwXCEDA7**9vSKiJGQteO^?#FULwmV5e)LC=o}o_|(k$4}oYOI4x~ zbGpUJPD1V%ty&2@-!j~|DU9Hr6hVuI=X%L?&bR1d^L&BrewVdqTwPdx+HzESjyAwZ z9a*^XR~bEY3Z0T~G;z&gBtKjr5vs{h znf|JoH6@M0~nZuPlB#Jj}D)kx1MSp}M(Q!dcmHyV^U`*DWG4(8>cfEABI&KGcgq{4TvZxh;o* zYVOW#?%E{Fad#VlcV0c20@cNO)6s_tNu_?7%z{tfh9Y}7j==|en(#6{{h2`CR8w06 zxs5qi*cH=vtMN`)%qCpMsOR*u$#GR)fl5W6fVR=E(%3n0~#6XADu776Mr&P+cDgz z{-iNHaA%?Xsh`HIRZFSV4r^eESGoi?i4(sKM}K-{ZStBEeFVJT?umi}bYg+8mLt4T z7M${C!?FW`m3_)~BDueixDhZ8$%77)dbOvARWg}9@M*HEbC4SF8_1B)!YES=tI-{# z(Oea+-$T?&$>Gg{Lf>(a>W@to878rHyQC(n9u$p{XpgRFxTMI#pV*tV?xtq-p&7hU zpS1pY!ejsY61RQhnAX6XREd`5unbgM?lw1O8^jV{&r(LQ2i!cF$-TbE=Af6lgja2M zjG8sa?g*itk9NJ%Hz47`)nMVJ5q~Ka!O)4R(l|(9A*Jf}=NHz>L`>~%=CKBrlX7VM zd|FOZ+$Mx?A<2JlAxSR_-u@&rSQU9Bo_y$b{=t}y#xsE6-~EeRxE_PHK|qRJbVHSg3)=$}>0dpss~)-_^xtdQ2@NTN-|TegEds2W+xQ zg<%|5WZnCn^d9w3+a1IGPRG52xgo|YZ4&C6o3Tn}l*5s(|R4|x!3@5WCaC4`(Lz{IQSa$lw#6x6b`JpYI~UXncb$GM`g3UL_XRX zGpS^tSKBYXpzK=HoGO|vw@bRFcO0Q=*ZC;+kQ0l)#ve10+VSW|rBlx+B>)H5PDoK!$Lw_6 z?``AVZAX*v*o0ZLKi6}N_k`hxhT+V}M1WlA(tuRy5xtp1Hh*LicUCWn#dTrai^^Eo z_)EgakZEgl7Cf_=_ve4JRDWV#9$6SE>(c7(%hiHO)9o;Vr`aL%u-%dhfW8y=C2+b+ zWOq-gwRg9Ay^?0Tyt&y=LoeHLXYO9lhff-!eZz-_p`Q56p!KXb5GjKY63;JsJCruz zDvrvHLgY2KM~+&2-$qPf?^K)TGto+SRNkW-^vZY)k}=JLbG;j44{>p@hE%u1{@H3>ej< zL?jKLK4w~vl-{Q%2hdT=2n5NdDbm5D_q`J*(41MALfLZByJLdPvukpv`I}k!&} zS#6aXl7`wMEy$MbHV(!=-3jl&@L4ULhYn)Kaa|RJF)dXFbN=>&y?;vMHRE?Yx}~#f z)WiciittAXS0C8lwq_=Bfx<6PPGS?_u}-T@^SfA^TR{Vp21>4jZN)Bf?w<B$ZS57vE;s<_>h!&ABR*OC}Lh#BaO<9H(K(6mEN0LS#MCtrFFb$XZK6+{Jt@I zJB=dPb=1(gyaHu;QMqMfV8?p5*EQAOOj}(&i6>&sCIXy;uJTVE4xJcc@6N7E`Wy2$ z>PH%WUtS{>ZMTo~hvkE9`^hQ2dtu4esqPtBIH@;dR2&qcy30A?PUq2^m^&h- zRH^oAD?jXngzVfi*Fr4^xR+20Sp}W*e4*pIMoVB*f5L{>AX84Kpg&M^zY1Zk)7765 zi+2uATdI}U{60#!7suBC$F-3=@FO_>2?h!^_1{lz89!RTAZF~k#XQ3|M9`XCBU0H2+hXi z4$~!U_G{5o#2|CobH=^23^FSDJb!Rsi3&NUSBC#>q3INZ`-(cL5OAmervH!3ri#H0 zQwcgU0ZX-^8qP1bM0AbAk~s|`NU4trL~Ctuy0f;fD1JbJwHA$KvTX25H~Bz%h{DVP zTS}tE+KFi6v&T{P_Spz-MYbLpvKCZI!eJ!&GMejMpU0(U;=s8r9M(MIIkZz!ZCz6P zswb7ch1C{ierlw9QcFilvcx%V044!-_-ht3A|ivHcvZCm%S=#Z97>b@)V`Wagq)36IXh$QM79XGN}8ydA$}^y$CRQPaf6%4n;|t*bbR$bUP)D? zd65W@Ao1I^cNX1Ou$`BK`iZhFj+hOqZkD^htraxW^CyvUrMg8V4>h0%D$=d^B2tD< zL3z#5UI6FGD^PYe&w)|+sr+S$b5dW-EJ`19e|3yXxE8fse`%IqI0`bAgmbt=}k|kyDBVBbr=- z!KCWYG56*RkrYvi5bB*Og^J$A64tBp+onXl$WUWg8F{n`b^lYTjcn}83KUt;V6ixF zeLY@DY?pWHa(|XkY^vj`1E%ed?)ri^?CEW1^(d@Z1GaP&|Mv4t4O(yf`=4UllE2we zhwYc%5je+)?rh91F%^Z?4?cgMR@lJkJAuzOL?oNlh|KdpikR@+81lrs^PSEKr4iddAG(EI)zB+$#-1Bba<)iv zh<<8;yN&Qnd?^Uaxa%1dz0k)t%%Mru{(_K+a?c9B(p!VYO?L}U1)?oPm&Y>2Pr0b# zt}9XG4wq~UWd75bO&R#Nj@iKtdL;cs?S@}}PHXdpU=}FCWAlF8s2zJTmakIh28ZjH ziyq%qe|7DE#i`u*pn)d^fcy!2t}HT9j}`6^Fd5r6&DcA>?v+_WsxzH`0Fy3!T#e~A z;5%LSH|jD$FFK4sj23W~N!_Jvu)y*>H8_1E*iaBm&dy8oqaD6+%@0ny*$SPR*;zd@ z8&9f~^>?#UBEF{_8vM`rqJ*vmmQVQV;tabr7Gw{VG|~yTWahYOoVk7+-<8Ut{UgSI zCBHk%4O;QQGQhP5Oo^1@buzrlj0v7X4JgFdv0ZmQ997Fr81{QkTe_^k*AZ^WhjDVM zp+v0l-T~mL3B4+jrIfCS7{mMh$ZZ9W{@ScvEb$PmIyswG3jGG9v&e0uDL%%_P7o=F z-yYsZzzG#>3Bt2{W)qiHPf~S>`k1*lF!FhVfq*KF$B`HPl+w=UnTG!+r??~JiE5Q%%pt}WyQQ{$x zx+OGn2;C`HZT;O^GaXKDO^gUl0LgkNgn1vwtP!3mJQS$b4uq7&xnO#F7*3aBz3 zI&Ti+u2^IzsxW!Y&R~B@IWAjjfqoqPb}W7Ck=1t5*WuV%0p2Vh_&x16hnD9t!KlsU z%ER0n#q?|Q_X1I7l{$Pynm_WzBv&Yini6g!|Fw3O4l(Fa7U!OR%lWl>A~D z%4uUkv63uIh8TJQcHwZaIXq>WJLLzB%tY*lL0ucX`WX(EFw`BjZ=J4AcH`;*yV0L~ zA1yB+B$j%7S(vhE9nfa*$qtt2|G-+ub7Rk~52Na4QDJYB#KTuf-+ zN!?6lZZ6)!mlT;zm|dZ?`e-$llzT6*&>BR<=laR<$koOxC&LN9Pwr^5097Hg`IA+t z3aZ}csdxVQ7iHV3bT+7aP^3@LjW491_dvebL2DB|@VB2z-l^+XCNFo2T=@L~MefTr z->J_xJ+>4i4Ns~&rG(vBC4snszpo7P4;2gY{x%aMe*d$S6Y2}GkLyIKTFr&Uhy{L9 z6eHt2GX?VBlA9`oSKSGcyasGuZqZ_vOFulmTK2VCzJejprACh47l z7MvrVE!}mkz)#-eSYtl(wY)r~-HRRzZ7=w~{yM5cfsw^$sS~nvau;}pDU`i>C58_t z8+M*0n%wo%8R~YiDFj{7F+w+e(n4KDZS~u(VRi}0($-%Eez8;8_*q~Mrc*)zays(= z!n^CbIJj7XWlZqdahHr9KMb23G1~4X1Vw5Df3*R$sm86~B7jLzht3-OG2iY~;f%LR z57WO9dW1%l#D;I$HyawaytMD0G;GHr*T}Or)pD+JTLaEEg;wHaW9`^09WA}+TLV}c z-Ht^`STB6M*pK}8$Yy4g_rhoX8#6U^aN3($vp-kXi4T11t_ch(&Webb=SXz8AabV5 zUbwI;mm3ym<4e6ta_qEP=wh;^Jy#?`^f_yOW#=ok{jzex!|p5R<-dhtv0ZdGYWla z)+X2V|Esitc(9z^7x^}Cm9o}`)H->g(Ts;$w= z7h8zqr2f;@$?g)wyO;cleJleaC7xRlz?Plc=}9egJ0DYfAF)uoj$UQFHBC_qXHE3v zZUfIYf%AJhg%tkr2KhY9bSJc>2X2=RTKR?H+Vu8p^||~|igndAeOfDQ?Bh16?EtuH zYz>MIYvl+_aoq-bz#)*)7l2KUIt^fn9sBD7{Ipk&uJ+Ym%6ob* zKgCvrPL4`*-d+;PMVLatR2}us9nRLh=kA`hxb7hCQwM}VKHbT;->9DT2Y>K;BX~fi z**7PyPP-E(Ihm5~s|6OEToC?qJvnLla0!KY3z$Z?X z+D^;Sn-2ko%aPKDK`w^;m>4ZWmUXqzU4T_pM2x1ZfJE(bTC{hZ<<6xTExB6N9N$nw zzy_63H2?InwU>bHtXkO|4B_(DMk?IV2ThVt@ME;h42*8$c^?sk2{wXoY900`D_Y#w zceZ{ON&sa~mt9N`i3=?*1k0xvvRRX9O3~S!6{V z&qHwHTRTUQ#`@p!*&R;2mThA$tSehWLQHv5x!A-A~cXX*gxsCxtIukOdgoOOiPh__Hp z%4J(P%rxT&`41U!P{?2mTexT9Kw+2YNkaz2OHp8mFhk{>NF~RgMtNl(uMS=K@cxhJqv6rQ}*kQ$x zMiWlRH}5 z9djwzPBTu;FBr3=J3FAWXF(5|Gr{NBaiY-@&qBGI1u+bu|+2j{_++7tvaeD8POzv zthlvf`s>E>mIdnXrO*d>X^EmiCvG=UC!^al(fam;)?XZ!Jp~X}Ko6))k$9-5SXNjq z;&>!A4~M0P$6hIDqyQ12oj`jxyrgm_>Ox)1-Ig2xRc`zN*EA84xFJ>ZW|%!o5ByM5 zax5*C$mTWGoPXSksEV-fl=*aE|6IO~4IuFAl+2zxisCcxWYp4eU8$1zyuiS32ka1R z$7gC=h5ic4Ovd;o2W?NB>S?QD;X`JApxN*z5218!j{?}n+^&pXrL^y4*|Fyz zjj4ULZ%u*&j@n4Kx3@TGG7DAES`;&35G9weZexFg4zALqua@qF7oY5b-aMf8Q@96( zBh_x#Wi-}pgEhBU5EMy|mh;zdS>Z-~yu_^&Nz*>NGuCAV%6dA0vYvi=nT-VaAo9+z z2Xlc$19Cc9F$Bp1GT+Js`wH5i6(mP5&STrfRkrkiLS2OTI zI58k;o94$Il$-dij>XMmp=J%()rI-@!t?#);9`rEvBIpECW4`IPaS0M9K5`S+0Mln zU;S|KmtNoGfmMpm^Za>BbIF(*Z+1&TKil0UY$i8;iW1 zS&?oAWKHF90F>Jxa{KKVa&d-5;QjZ)H-pP4d0U=C4EF(Do%S1i#mcYIw^OfaXVvi}d+a;D` zpB7SIQDg|KjwwiTv}R0E{n)!uQuRH#PVNLE#d?eO+8pOEA-77D8mawvON9sjN##s= zK-uvQT9^`?$lHI7({dh%J_rQF=97NQ1^HUZZ1x<3hiY&V&&)0s-P#MkqIf+=Im_fIm%8sAB%m%!=l#Fd;QV3(fRKjs zS_ObjP`%t9)obOw)EuI}r zV8nGZMh_K4s;P|TWfO}B><(2jY=g<=4-|u$5QSlExev5RMvXpSA6ed?y|nac4W^WG z>@9i6cHVzcJysS?N5=pM5_R352ts+S@XUIzEOu>Es_Z`k<9ei*ddx*kWny8w9>x{V ziVJHELjZUobCcU;-cjNP+@S2NPOoHp$=k|Ls`4W}>#qvM39&kZ*x(U5R7rrjfAh2^ z0Y3wTy&FvNmo+@Qh*I;loI@VAB&s56{)2+urFAV7V4xfPo1{4h3?{vtNN@`W@u zW(7#QsLejk80H({Xm;OmyS}}>ofcVm*nn_pqzVV6ENyzb^8&d|iZ7GG@!5m9)4IW# z@=#@!ef4RnBdH*i96*j0i#`ONRKJBekmh;M`E5Vys}jR}le=D4oGX*2YVPkL4_S8*N?|dLkKw z&1)i9jAC_zBcmVWS3-1IFmhDUmq6y~CyCx4X!`JejK)(zF-K}f|K5kXpBxI6iNo8J zxcK&?J6E|UPxGKKEvJ=pnh}gaSV~iV-Ww4SZME3J|*7*MHXl(oXD0Y5} z{_E1^L7GWsg!~OmK)Va&_gRhaX4>dL(9$w>T=bXBYQd*<`;ZaM?)JeoQ+P`yFAW*su*bMROR}T8gr9Fu+R^y zbjP)XvYJbr0MEhFU=3R|UbJg9>1bLh&H!Q^0T2%0&r@F$qm6T-D~I6~*V4FuO6{Xc zWYGU7Dq#B8Nw#W(^BcQDbVS6w`q}ONy9gvpb{i^*e9s%)6FjAAkF zP4DH%cISQ7o4}s_GZQSv^AA(W`yZy#owwbdq|?L^LECVEN9fXl5DGB}&f~8<4Mf)HH*fqWkjsanP**x9&%j5ggs3~PcPAqux>Iel2$MV{hYBiscP`*#xcFZK@#gSs7c1yppRLt+{eKUCFx zW$^n%43WIqj40Zy!Or_%7Sq8*QVm{5qpfecP*V4m*z1Gntw57tHJ>>Bl3xRi)P@jI zYSk-Y^NO|6(RxEt?YqjLIgC{!pGgwY6Fwe+6Chvx9iJWoFei$DQv^W=J7?=L|rB*K}^!$Tu=cX_4 zXiS}~%bxGqcQRtyD~VsXpM4FNP@pj}WK^(F@dPEpT;&FY?aXCxuxTd5ytqov)EwtK;@L8rFR{9 z$(3KpqTF0(!qbMH^_M{k=2N;&wuuv0VW)nXw5A-A6!}aWVr&45e5kWt{g1PT3_9sy z$%j`y;Z(B>jH(xd^HF~fId;Q@zRqH7B%tq(B>cm98uKBeW5OxW<*QK_yk8Rf`)&qC z`p+XOprcfeQcUBIa2H;ukn-X+Z-hRPfhE0O-^^X^WW)uLBjPU!jJ$)I{wHdey(!gB zN&&oc7w~r5{kP8ys$TQ<%2z?BtUD>b!Nh{50;f^GijdZgH*9yIQ3}G4wETnh7Sv}w z%UDWZOW|QndEon+4UzKu1EN=rxeRXX@)=|F(du4&xwwDS*T%63Rjx-i(Ngpc1Y z?_t*lds&sMW^T?~WGH?Y{|UlqVTd)4@|6`j>GE7qACw@?p+ziqreTPkBOi4?m)vfu zZB-aP=;X`<9Hh^q{V>2X$dvMx(qimFsU0e10n>kP%-0b6j6L(i@AaS^rwl!N zukvmI4|~97`Ze>nz%4_M{zFm5Fpp04EYV)Dcuj~sPr*=t*b)I5IhyCX7u9&0lG!Nx zuM1DUH5XxDw(En;`ynaFPtP?ZSG0-a?e(e9Q#Lg69tG7+A7>%`%{vFa(8T{1)bX5j&>t%V*mo( zgEloB0Q_=uIoo}xzT#7p+wNXmBhgS&mHQGph>o_KrbfuN*`jvos%k7d&HoW4+fO2w znzh0HCXlYDa7GI;UVIq~6475~ycSo!y=++0vlZhz+vvn&3mAa3S9pfL68sHTkF%zG zfT;u#R|{eM&Z;G{nD~j|wR<-&oEBv(ROZ@{YHzZa_iox}>0VUsssXuT8$>tQht=VL z_T1!2*RZs~QrH{32J6$HMR|MdVb`ZN7VBoXaRKY)bK;9k>?mj1>1;IpCE#x4i)+sP zFTLNSz<#4KrHmnWIWg1yM10BJv(kPIP}`Ret`EYniknRz!-S&gETdzEydZo%K^-78is+FdRz%cWOrm-`_r+q+t`UJ^;aq6f4b+gazUP0~Ey z8d18m|GZ<81f(6!B6DV?ck$zWT26EM{6wK;A*G+e_XwVU({dF zHZ0v;OG$Swurx|{ch}M-QUcPkbazU3gER;%E!{2MD5a$OuD|mW2@hK%X@EE=!XbGqET1@B=Ygq)!F7_iz-J9w`z6q@r1k~M6~`a8mS%<|3O}-+ntUZ> z=ivX!m|-^++CoMzeR%yIxvDFSf-_-XvO1~hV=A4My-nE5T%9?LT7?)WJGbCY74N;Z z{O|5lH)(giti*DhG(Pr0k5xq<|De*o1!Y(TFBLZL@_&lqxjjG+gYNyQ0taLD!9hjp zisxKS8}vE4Bh*s0#H#NW=B8p)sX@v7;?>G|!KaBh(a{bsZ~TVGQxjw5t?7%iLQ&^d zSgVR)S2xCsSk)DRNt3WUR;AHcx`5BKz$?ktr082HHx~jNZzZN9?75lYNEx;CAbII_ zcpE==ZA~u~{yTJ7RF+mT@r--GGsM#kKZ-4`kQqsY(s9+|KS_r3I2xvu)}Z#3@WBHO z(Ja2ymFD*3s1N+r8O_8rh3xQFv~ryT5#c@ue(Lb5YcFbf{L!Q3UNNIrSdZS2vS~^3 ztZB|`i48L@^LUU-(~M9Ye%F-Kqz~s$8GWCbj`pdH?@$*15GQ3cAH^M~SAdUg zlWxyh8RtqCB;@HddzlcYQ0b=U*2Kt3=5+4S`$quf?W?%L`0yH~b&l(m@B6VQ#eAxU zVagJQ^a=*_`YdvfeZvE9!ky$p?)pa8}9ewQ}fVrmOYKce5 zXvm3vHEHlhUze8DQUK{op?}+-88CX>Sb5E-Of%DvZ!To}lY~~b#)$IoC5sma2Lr8@ z<$r-%Xi05DAOl5srIG8j1nfM1co|MIRTJ_P~pFj;I4>var?TXI$OIC~Ha zP$o=uY(sp~he&%3Zr4xIr$gxv!#{mj;L3L9_sZ zY+lMSAh}^HGt1kr2x(gCCOTQ}OSI6ViB?y^77Tt`6 zPtg=Z6fnA3k0m7OHI`H{s=%kuO6{p7EXue_X116L>(Nma@ip9?YZWe8Bg2F7k(~SI zLa@Ao1@t#1fE5bYS?UKdf_KYnFt#xzyU)vp;>2*b_M?7CwvENcM`j^>zZZg@qzF2C zI`Py_%vsnzzTw?K8=pYgS-hFyTpc z<8X>%k>F*L=6+v{Vwovc8ZU=Mx6}H`3cjZV79vP&_-ADwRgHjXrz(k2@?zI%AL%Ky z+VK~TV1q;@6MwxF469Y_I8m`AO)(FCRv{)#lV#7lT}TU$dlnzz@nDrME?C)H05Zz_R$sjomWe` z&eO%`r~`yIlX-ld^ozPGA(DhWOopY2b_KGyX0(j72AQq#gFw;G4hS?;9npt$S*G?S zb9RS?8a_Mkg_Nu)=&VBo=ja$d{)y0}e?QdRC4k$^zGkGhE*y!VN3^;+i?~Ko7(SVVc8%l!^`yjZl!l+=DPO0iAo3lpo4NqSb7HC_@e!sy;Xd97}p~HSePtRwD56lxHS#RDeM`Gc5-n zQP^ExB$nFGomkSvLluc0)qKziOdZF{f5g>|mlh#FzTi|mi6 zKi#wtdm>&=N>qnp%+2OT7Q4&lSme-1N2C(OVy_vD2#xAAHYSVNCrfKfO7t|3|0?)} zXVCF5MCyYV+OZbUG1sjy&bRDqJq877*><()f{KT`PbY^QMp z++_l=zYYw|0m?o&@xNtJ=4xm8GMuGxk~cy@ubN0YN0DhP)?7cit2mci4+E`_|3Irh z>~S$SrM+doennc2#<1SYkTev`A&z7VR(ppPqJDtN!0nG{60rU|Q!22=NRg4!TQPDo z7mM2{HBaHCE*+PpYmG<0hx~X*<2YJDq7SL#H>^|20*=C1ORMrYj(ANQdYGN%vP^We zIK2vF#U2~t&sO+RNvT@S*a+Zb3*`*)78Va?d;}K3*5h4zy$Fdgh&s@lFa{Z=BDtL& zwaf~1Qx9`AkH3z##~xQGKZrQ*_P{AJ25trI52fK?P!7GB?u~QQ{4XLUx1mGWv*;;rPB< zh^0+%6XR#(Opb9ydXnNK5+HyzM=1bZQd85jC!=|SP2+~0y2uR)34@SxR30ro`OOJ3 zPc?Tvxd2ErKDwrgK#f`i!r~cFDD$k^$xS_o9@~ggCDV|BD?4Im(GbgGbbxo4(bF@B zGNmvGC{{lQRC13E&xYkr_58^XE&gUMKgp$f)gO_{lq&8}S=`9K6AhXmk+)+>DRfR3 zQf?=Ty$f1>)BS?08z>MdZMPGRPF`2cA;&xttI!7fBaEchbK1e$&}ArDcK6TQRUhkw zTk!Fj^S%tG<)<5@yIUp}F}ly|VxPN9vTflK6*ako#Fc0jl*7$VkgN_zP>Pwq0BD*{ zbG^mS0g#+$TGwLI1Ttjo#td|-enF>!QGfz=)LUyDpDS~Tb-HWVsCYQ0?0CIwt3x&y=1%6l-BoZf=E zpaDiMxZVrDTF{9nb1CoN^q9$c2TXuyub<;<%}*mN0f9I)J1eOQ<7kXpE@Y|uNek+M zITMb8551qzGH!$$$bRWzVh}dnjK4IXwpMCSO0gXM)zLt|oSE7}mhf0P&cg+}yZ$Ji z197~a4`6(EuJxS*%ECqV9?ni6Zj1l50w;E#zTlB*po1C;?0TB2R&2UQo zUemd=Mh;`I$+FD$`%S~!1)7eVI+zm#{BweCaw&-c>X}Wb{|Or4J+n?*a2xc42o-?& ziJ}9gyECx}|4TN)_U6$y`sg88dGW{P%lUI}J3a5~GNtf~&fbv$1g+hv2J~!6&+m`t zU0@=1gX`Bj89LnD6X+R2oMUvA5|?F*i+!vws?*uwOpv^>eh0V*dPG=|G?4WImem0~ zXf~$yuB&wOiOuVAxr9<>(_u^;45hXnK3%q1M(Q{0!E2iP2qkhXLtBM;+MJ4;xx1vm z>M4oI2?UDg3C>L5NiZ>})ZeMglPg}kCwaBw4L|aa5UZisjw8AgTc=^KBNLcX3(-HN zmVh`KwP1|Hu9>k-k|e|{J{oxgBok!Jh|gWWfR|q<$)L-gaTfDE7UPa!3-{m-LeuHr2DFAhg~zPi$5xQ*@Nq%@|8O z|8oE}t$x057TK~W_xubplO(0hME487lv&Tq?Fc`~cD?-*`cD7eI{5dnddU^>!sdYU zYB3+JzB8s#qp`;vI?*iU^;IGs&+LziASb|XF%;^eYKl&iy= zXe}I^-TF@jydv5664Yk_Xrg(In4Su~3Rn%rwap(su~~h(7CT;fl%8oFZh?I1tf^qs z3kHo-HHu4SUm}i#(PFw)79hVWD+2Iay zli!G<1a=DxTY7VdSl-J+=pZ5Dr0B3jDj-@`*zz7*#BznhXHY#a1HLdj22@wvGBuxc zuYe#H2K`!z6WfB#QgiivR(~`%)RzRFnur}ObwM63U83-P2vR4ua;I=4sqm-tc)8=m zeY91vTR=z*W|}a%dsY#c@fgohdFI%@Ny}fD>}7qiMsJf6v6*sj{0Xnh-5+dt{rBGX zG+``vN;d!1)s_--Bk&606cspd}!mD^9>FHw#W$Q-jP<_zv zDSs4G-#rs$Jf}9thxc~P(_b4-AkT+6A9kQZZw7MeCl*W*04Tc9d}psf(&&U2!-~6hk$42P+-60C? z2W{x81=e0SGsybkF8Jq4*vrehx;*`P(TN{__CaJu68fyZAVZ6~#e2+LtGC>nl<~M5&i) zx7-#dxD~3hl7t4Ie@+rd%Zlmrxa3Zx+zw1A#Ka6Ugkr?6jx14^x&LvkroUGN-U2My z#RHH(C-pMY+Gd-tb!ckY!FOQ-Bw#EPHHLSmcLMEIdMFas+oY7+V*;;;!JLS$60kMz zE>rHfFWF2`M_NUr^H@uTS(Gui0=y7&15N-yn@x&bp>0vYPiINeBr#M|-f(rD1ymEd zsyb4W65MAG>j)zmQ~-FK?oHIMq;C}{01DNg@=?Tu^ZRz+h2nvKBS&03!9=KqHdTX8 zqO?w5IE&ik_X?y2%AG;uJI4@98xo@ixDHvYbGIBcZPi25Nl>@)t0|(GBF~ z71qh#0`&e^@tk?T-H!Us79a-W*tJ~@Yv%8pgK~ZLdv`$bb~P>t&1GTBmp{9&QS`fj zuT?958*uM2+;g4xWe-r^VkKnH??VQbAL^kt)A}m!@wiy;2JM7Y2 zN@_k}VMxQVa8w+C$Nd8^xgB9zT#7~F;a3w=%o2kN8UQ09ndB}kF{g>imrY2G)*RCb z#GFjE#*V)Wue{V&vl%jC&B;2r-NwF#5V*Ta#P-}I@75@^Dqu|-!X8A>KP9==;Y0*v zB}+4sq-FX+rTklNNuv-uu=i4M?RL)3E-0c~i}Qj`&vrc88-^4O6`c*hKvjn;Usp#6 z72>)}MtZ}R+DF&j(!lU3lyiJ(QBlhmv4Ng&e5LE@i~m;(z%(N7$4_58KSHtIvh_Zr zo#d$t#8VR}XG9d2S}0NVaxn4x)?g7?V;ZLqQ{I@W7q8@VLy+bGMe`*nvi(2zK7^J! z@`t?6pCSFVQB9CN_#?ePqc1hXc0f&qAI8m@3ThUnVsr{U*_>A~g4Qe#M{<1*6nmoH zc>VQT!{yoU{!aEE+doDIO8r&w8})LxUgl^2AQhh{v-`_`dk>NRLA5=x*VU{wR`bG9 zcOcj2UOu}4(hUqF`qr}hU-GC1>S~_4o#0j?OfFypJM^kZu0ixb?-ej4u{3}$c|D9T~jkPuBuH1 zjk3VWT^v$r2X+=b*o`T~Q~fS!2B)%s`sOSTUq;3^R6Q8v%jcZ>t7HxzNLT$2I!0p; z@P_^$LD-gI?ibdMmZro>x@@CLc^6T4Q*m{b6vP{1lrI^ahx3>3$BUr|U)szlFv{_=(gc=Fj^9VpJYG_)08Gn$j8)dZX7tr&c;Rd? z#rIM?CU}!cm0no%AooQElp_jPKBSO+=GrOQ#8Kgwc{YeqiN3i%!_ktq)Z0)(-JwsEQ?1^l^y$n z*?O(!6tJV*zz}P9`mwvz`Mc0q#mV?6G5#Rh$}%~@bcFWsrPAA0n54-v{J)T~G^}ob zWX*iNinz(6706+usBQ>Gy=2H8C#zlM(~#t>0g8rG;+=f~iN=ZChNM{RzW;2#=b1)d zozc(u-YW>Dcz&b4;f!D!dPblCZZ~xIHxH8bD~lZFm8p59Wj9{@UoMhjvs;h)8e^=rmr9N^x_jb@iM6Jf|p_aEpPE&2g1`X-O3DA$+PU&PAZFA>@PYu?E?xz*T zX^~sWu_ciQK!CaKCZva=h|TCNzv{b^m!3>}PRf{m?d29}?--PcwjUY(R7KCNs{hVP#44{7JkH_o|2B2-&m>{KP4wMxk+$y~3h`5^7g zD=RyhE}nm8A7NyzF@_R$DWS$LVVHki`g=ux1PowNd_frcb&y2yA;hgmz=meV?J%q%EIS3VZM&6;n?nM6c|WK z7s*1yj2y;2n6wKuFb$#)Bx81Q=Yk`lvF1Uv63~y;D znEsv0`7-v~su(#%P>V#o%J)%iM*@9yq3R@`QPTNtr8a=QvenkF50aoQ(dMA20y;#z z?Px-|Q(8+l6kV}%T?qz!t2c{=kB!3Qln7K)UZPa=lqqw^x9opdC$Ih%?N-`=`wHh> znFTwyzq1h211`YojIcwusnA_Ld)WdyzCcuCD zXKD57$?Bk!v?*teX)nM=8fPxu<<+e59sn`rqTwrhLp?UtQ`LJw0auXA>Z{#|fPF10OC2h*dz%zYTh zo2mWA5ghx8A{}7z8EhmMcE;@NvtSIBtd00FUnXqtdaa!%m>2Hbm}OU;w@ufGikvKa z-&MFH5I1HttlMK*?SRJ@iTj?wnljqQy>%~b{rr3Qa`T@~li^0v@@^?kCzO(a#E>m6$iumtPalZ4{)R%vX4tHetdqq*A-3ScTZ z^d149AF^Yzx--f29BF}7-A~YEKkqcf(`5;VdB4_{EOJl${?9){B*kHFt5fC%GO9Wv(!Hj__pHlLYOf_h5l4%B>Q8^IZD}Kw1XSZmIo6&crec+Yd z?%kn4eIM7%8IA=4m1V~4n=Fs9$VH8{W~k>%NKxTRs`I~84aMMO6(!?rD)(%)-yXJ zp#Uy`ATNH8Y<0Tb>DWTXR=z2zijXm?7*Ssk1e(98?&yH=9?QLkM2}ZGwaVH)MA8r8 zQrwLpr*{J8$Kd8$0p~brletn}l+u(X3p1lJGPfi7P@i9$YTT%VO-lqknYOV7G4Zwf zgr`J?mB>BH>-70!&F#K=Q?L9cGhLXgGDz#aKWYetWx+a8m4Yv?{;zs7OpU{`sKrF; zQ!Ie;4FiP|Znif#avHz~f>89JyyqR0*`K7BTD?KtLmt}#TpuB*#=b;=Hvam4zQ^tS zi}v1XiSVAu(G~WTkFy>1{`BCFrSRc;{#O2RyREAw^(5?%&&sXo2Y}f{|{VTBf^(UJFh>;UUdHxoHSLG_EitAo! z`GD98ABHn2YWw^mT$-@52}-l4N@X?r6Y^}O2@S?&b#V*&o}>Ycw2RJ9d3qhz_?VF~ z`m4_1oD@%HxD2R33QkT}-wU-K7*+Z(oOXD%<2>vsSD0@jI?f%K<%T-@C))D-jkbRp zdaMc6jhsStO8ZtfGI|mdw5Sv+iB&KHaK~&{^7on3?~oV%!Yv_zNErx_ z@z(Y3Pmv+g^{K_IoJ#MArT*i?&3w{BS>yn|>~jh6iSPXwmRFS*p0GT7aD-ao6I%~V zt)}^)7*8%`j*}H|^YLwiM2JF7rs%J?c3&9$I82&=h=MiCMBLZA1bad9r~cBPw|_3| z8V(-|K`0l=mdu{D*s)@U0Tauq#G@6}kYSQhXsXm~4oej#;+8kmG%TK{vB~p0nsjIOUV^ zFR>TVxIEiiHtYnSpKldf|MZdn6~WFI0dpXlCuBS%6i)SbW99%vLHfu@P3aB568x4v ztlUX`@@jQq)L0Yz1;GjE#!-O>C$?Wo_MKo?rmv2(Ip{;h+8Q?0wl zT1l{VnT7j)H(&F4wFX8|{}KUm`gFF`0Lz%y$eNzYb|&D&c0yc66ajvhKlLyyjtkhf zziDl$u8d3KWeAZ7GYW1VjqK-OBtcL$n?i=7EXUdkI*IOv3V!t}``s8_(xnVRyW$!w zW(}UkPIF^Yh7t(A>pp1YsCeZ?kbWWRA1>l_PD3$HIR*diaCpLWfaku#CItzF?EOh0 zr<|x|XjusJLA-0B0uZN(5ItxWgVL=)7WbJ~S4)^p966FgfMEwkZ~mRdrQcAjK`8fo zmUG>tHrTB5nwykT|+2fh#6E1(OuU= zcn$1<{4{EO#>o7=b0m8wEU@xfvK8lKMD1 zk5zxIte2f;+$}a*8uB(MKxkWdTvX#YTqZoD!BSI#4%xJHbOYukv z2ZH+cm3q!+(JRSR>-fK8N~K+KwLF?p4zdp~wT!!A?I)2Z{AmM){cQtH6~mr2PYj1O zB1DZGb@c|Ub{D5>57(0FY_8XXn!EI#hA+nq;8=fg-<@|L5bK7{&9T_Dw)~7-tjs*Y z(1-Zh9fWH3@nIHXpIJsK>wR`lm$gbvgA0}~-`(%e+D|x5UHi=9IJ7{25=Zm<%xPTr zS#gY1S#-c)wf1!4t+733BfeA2Ut?6AF%LY6gy?Au)jDf9E$|`24e+jXlV!*m)B3Nm zdiclItmBc{6`Y|-6e)y?C1Ytab>`tD1uY)YS(B|)GM=n9kMQZVRE7@)gxpw4%m(DD zDVQ7**k#^RjfCNNGD{wa1HnpCUSqlv8LbV!_#l4%KhMHSQGAOdOQ8j zXyIH2>8@TXYxe3xkQ!oMjs3C`v>0IDi|wT+SmO9Yz=*;wbp^?GFL6n*c2v9oK5o`* zN@l=Hiq9=X>3DD7okD)%TGjLH>iu z41@Alz11uC*olmEE;6oEIb~-bqNPxuS8RvL>KsW*u_z*Xg41c=&DC*COkxfNLFBnl z*X!!a(%K$hGmu8YzE$hp>sMyR*(fC^Bx|@`_9wvymLh!d4gV-mAHl9*s!E2lVRE&NDKULmYhCKkN)=49*_Z4wV3e;&ZUEF8hm6YzH^{d@b@P-? zr{0Zn5A!BZhM3PPS+^2*eNhBU#r6(N#q;(^3wBhK{~CY~{E)Jt+ZCV(?#rDbRAjh9 z4|`0SVBu9lw~t)WVp6HhC#l)Phe5nH4bsYtEb(R7nuh{O!i>LvuXka4vqe`2=4&7< zMKlH-*f$iwr$>GORrDhgglaSnLXa4Wn2`yH=%TUu5oIKtD)1VDD9M=}`iPN=;m$RR zXAzw=#3gXI1bDl6-`o69UhR4Rtt+$VwfFnO)ZZ+;cU$gltqo5Uo;8w#@N*w~-NQ)j zG{c?P^Bs?(FsTpnmqmtJGCL1ph`>Oesf8g!(Xk6MSn*SLcvy^t#7q$X$21#}O_trs zkD*1bE8O_Xk)i~T)Fz|@%o^J=ef3=rU(&j$qte>25&8gW zOj9vCgEwl(f~Rv9P6oM)gQqnSHyy$Ppp&*rTUSai4N`TULiOUR=aV6K6tPF`DV}PW z9C=ZtZi}XF?qwqDf_5F-;8o7@loo3`_41FkuE`5c5lj3+7ZrnJvZ&ISWI-P%lXhdq zMj;c5073j4Dz+GTvH^Ai4vN>)g%x_cG!#J5^y?(=imIkYDRvo6o)o5$kB*qdLo^wY zo@*?@e43<(bj*NpO4;S&VSI%r+>-n^pG7s`G;LTiSdg1|#N%i**%S9a={W9I^kvdj zFgyGbsIuR-b=-OD+DB9$Vu2T7Kg64;=~esPvYh6iQ{OvGS43^pUK+W>Yk33PB4bq0 zcr@yx3fpX=_b-m&aqzcmb;|Qg=B&W7T=(&Ej{sHZNbwtpbXo$A_^S z2^Gea^C?Ky0oS;fVPzzUN9I^We2ndqYlM#bWh(k+>|c>bZ1Wf<1bKMH$-@o}$pOTu zxJeMrLZ}T83Ubr6+aGQMv$V4sHJlM{MCrwjiv1El1mW{qpL}OUTv*_5<7e2S-$3f$EZH;AB|^3EiRqy zDiaSgd^8bBm-TC=MYYoo93ZID8`H-hyIJm{Wt0zPXeyPrZXm|Y=nd<$vdhWi94?>U z0|=F1)nyWNp^4BsER`$s7Kls-l%WWIRiLypvV?1o%eDM19D;gd0vqP`{dc`=reJ0g zgOwr;nKAM9JAAhShlhCg6qZNJrGXjbMh1Av5}Z~|A1o7V3?dZSRE(I(Z!aaqa=uZl z8Hx&>yXRPW=CZ2tzo>4NNp#B)(a5kku6*K*W#>_9GN8Ubw((NZdySQH7#7Afdt(sc zUD1j?U9fU2HS6~tL+b4uQF3!~dWql$T4nx-2wJL}0n9Y||7DsBn0X${NK|wEV_bTj zGaSj$2vO*dLQ4!8_!3DTQq&hobKQpPWSws1xMcFi{3<5o`mfG5w%F3iXtZNV5Y;QR z5N$YB=l~^I^71ychp8yKdQ*amUG-&cg6)Sb%dr-6r-g+!UbZMpg|`~%uz8Z_B?Hk~ zKxg5{0y3z&(L087_xz?kY=!TlNr~bt8P?!PMOt!^K}~uFULUvaT>%K|MJB3|a+ywx zlXHv!RoMxhU+k_py?uRn8CIsR(>atn_y*{>TcxOq$j()W^rgn77d_m_U;q_mw923z zDlV?Ol4=vZqgqDho&rRq>&wMM62a1q-7OlRq2`X^X$)mJc}i%f?_@Zrf00j+<5k6C z6}|M7zAm2Y_vA1$;oVT;AWuxDDN5bXHv|hX2mb=hudg6T6Xq`@2GGOOPm6RcjJ?D1 zS#q=_`h4Pi3Tis(tKr?3G^$shI%*tz5JHG7dZ9BNspspjdD82RZ2>o*dGJF!Myw0+13O? z``waB?0s&Cxtd5&5;l;pEG&t0v-8Gwz;yz^N;T2}DXEc6l}27y4p#J=A2pMir?sO< zevg}I#1cbpgtYN8I>jaml(Jm)A|e=KZ#`Z%l@_Iw+JTydl?%eN6J!l%4?zp$dk$yt%O7|AR^ncAjqbi>i35v zS*D0*FEvlAgf8ltnOu^QdHB0eq%r3sdW@B*E;&nSX=&w8G(X}!HZ>N<{ug>q`5~gh zJ@jMD0ZoW$FZz|v@uStHYFz!^DHU_^?H3@^e+G$e3ce(L;{`zcYrU!)1gt3*F#JX_9%^lJzpH2Z9Eg zF+3~BDX>l2ZR~2YDB8H~bT({R#cR_z*jTh^cv#*O+!h+pw(dS&)<8Tt`gG)Zv{Pw| z=wm7Mvv_z5GC3|p2r4Rby^0*oGZZCxKGsumXj_k>|19hsP7H;p zB)HY1`lB7w#gc`*F=S(UIS`RIoJR4XbmT3KC2eHbuUt9qyYL`yc!t43 zmq~mAbsgLA;cS*fNr~oA>$cHU6H3opU^5LB!ggPrK{y+ zR|XhYY7^ebK&L5aTw5Ulg1bjnG)Te5V4U3)Vs{FQOXDy%V zXh|NIAo@pqtsR!YGQ^CfZru@2lh`7idQ!T1MHc|m?`1`jgYV$Ns#eAuFUIG-*p*QO=vuR}ndC zx11S&!P@L)qZ=`RSv_h5sF!s8l}4RKsuMy);Tpqo?X*WwA{rIlnK?9u+lKNAlZ8v( zb)%8?2Z7UPtv(1(scTRZFcq{{>cNNg$IIVdkV~Z^(wck@GUOlSBVbwYN1Z8 zZS`fg2E2(vnrjKsY;{<4U1to4tjz^iY5>Y+ee&!PJ+4~8^)E=Uzcn)dAIrcimUs!{ zxWyFhWhShISPihfV)~|O>}<^BB0|GPe@^Z`uo}pxoB9TBx2P4-L;-A9b{hHRhTlV< zu?X`kZSe$hRK0`7t&HZ1(S6$2l`6YV*3xR!7Fw`I{y1KAog3(ir*|)R=q)-gg9c*q zL=9?MR`lv9#wdV=*1Z8_D~IZV=UJk>+EF$!MZzJNqAn;Z!`kd|};S_AB9 zDNX*1T{+36bXtY!Rz!ll3A{s7zfH%sW_>A;rOw*0*5s$qu|Ix;PB-#>hK$&>HyVx& zdGzB#bqiq?X3k!o4M)9BB3lIQjJKD}_P%1Dtrc>*EvqtSg4zyk1QlA&Y#yIds}CH{ z$OL8smsP^5f;nFJg0hCM6C5iHKC%9TPiq2@!*f|BXq&h)TbdJNh~$;e)P4cHH7$S0 zfoIG+Td=QRVLSi%4s7M>5CO4gCTJS+5fDlP<1hMM9eCpJI zU^vaOVmUK?mWhTpYhMv6MJ6UcVa}@M4KD8vZ8a5Q?jjXW+^Fb_j$Lcn6_SBICkpMu z>3P1yAU1L-zO#QZp&RJLQ>WOvV77C_bUr#OELlC~YT3p|SSv*yvRO`4r5?<|c{oVZ z1i>v&IdDY@Pite{O6)<`=36{k1cUXBD~;uy%1kV6Pu$7N)MKO+C6@8%M!KTeF~@3{ zr;Bi{Au>Bj3U6IcBDE{vQywO=Q_wZ=R`q4zft_;7!?@*i z$~PmV+}sjGHF?H(abN0^Gz${FnnR!pO&Z`S7F2Y2riJ7#NxP zazK@_=T!=8meKycgH~3|d7@M{gp462gDm;HPUYN4I-at2TB8ULUj-mKTy2XIc^nvy zxerJ}Ut~b6%6KlW5Si_ykHdW{G?m7YF(AwFY%9AH zA@~VxrOfUl%|5rS7z!cDJ#Vb^UEfd2uTAzt8df&Y2-rKzzD<#)C zE6$M8G*8G9elGfz6LpD*1bP`c)|dFDh)n7$N`JD8N*Tzbx=*^|tDuq;Go1l!b8??0 zO4XRKHrNP-Mw^Z!EbE3+yLfe_bhX|<*x=MDnU~GF==@?YPpk2N`*D1?8Ls+`U*kXs8>H>W?*Rqak3X0ZvA z)z5NCjb`DdNh@MOrRp-)-!YM$_(;PKp=~APvuv>fkA@cSmS)kW^}WU?Vt}n|nn%=3 zvJ?HLd7=z52gtrey*R?8f9sX5gK>96ZoE7P<0wIb88>DnCP(sl(m#*l~-o=mf>dM zy#Ok`tV662KMN#;Kg!LW|9eiI4MTDMvvi5Ixv>3s%uN* zqfh;|6ZxzC(Br{0n!b?!r@V3E-*OUSdjTQ^F zkkAL%AgP=YN28HS!M?hpQTFGpYpe%4rBhNIFlWlK(?Zh?wII>_%DCXqVTC6$JL_Tk zAnp)cW=uAFtSy9)!N^qksalVe#VIs03RtyyD@}!8fejA0?U?_Qy9I((&)X zydc&qN6XTIC_u0S@!7zN3`9d=(OXhxIJsIJgk6C8PGd4S|BA__-jPJOf}L9sY8;X#*Td9Q_Y~F9NE*Z=dd_wc$$A2&c`P^?7wk z<8zgT6+Yow=BVq%$vzM>g~OJPM*>iZTdyJ;9VYFJ^Qwk3ZV<4)_=cU*&EYcWy zUx?&TiJNh>-F;Xkbv*!SQwFW+1(E2302vZm?iSjOY*4)-mPs(A7bNL`|Ma$_*gP7Q zrdo|Po_J?98AlT`I`8Ln9}Jc+Vn zx-U8j@fZ0H`c=vG1t&gbWzx|{jE4NCw285_s+Q+>uJSrurYI#C#)x51R`QuBa;X!+ zP98E9s>RmuV3wIQ)*&M|LW|)HnZ)Vm8usiw)v5fzrSDKnAS7bYi1UFBy;$>3;+3;% zNNi;V#_sCw?q%Sd@E3?aUP2i)Jg)-3Mq2+xxKu?emsxw9bB=kfPS#TL!)5;l z*TyNUzD)afEt7V+p6K0%NN9^6Rich^G3!jQf$epkiv~{?+d&l{KRPAeA~Sr*yQCr5 zdbgg-$8f}$*W1QXT~>`$bClr;ge;ApiPC8R6RPuYs{9u-XiH|zAU-Y=OsZZU^20I> zOjV=fZs_ogLmKjrx6i=mpObf39kzgx1Fenvf0|;y(4M&ahR+D z_A}f!;kMhW_Bha*cYf6=BP5^rP?EExX@%UncBVdsu(X-dM$FX9*=GKTr{LipU%0fu zENxulZ{0+1-LP^7sYbpb?ck~Dc0*vlf9AcvoO~DL&JQ7pks4X_*8T>C zTmOpl?a|KxDH(y4jY{45fJd`S?-Qf}OS}20l1ssJPC6&dCVeb+G*7&3X+t@93H7jZD!X*(($klkFvP2$b`+v0lvAka^$!FcvO* zQK9373-$J=wSG6|)|;)LBDsr4^4>cLan6)ZSAkD`Z&Zb`ea{!e7am4(NnN3!<-QUo zn?$!Pp1RO{R&tBNV9o!3n)A^aQzz03p6i9Pr@4gXRvlOm;6ItxFy#A1Efewk_I>sC z+GiKU?j?}7lT>Gu1N3k+9`YoYUyBRL^P-Lo40#6us!P$eIIl;?kwA?*-c7)ck0_l! z9^l9EywgDSxzJt2Yr)#}?xL-~t3s-z=oN37GU(5nFgx?A9_rv-r7)(@vA3eAIxhJl}X#P8(+n&Ln9bTx6ENrZ3z_R}buWSLDq8g^d zuXO}1>U@YoSzfIC+)mkkjCn$dnCU)75d5`m)~CEc$?6@I>_x}mlrtA^mGcd$nTmqw z%pa@A>kE=8am;IY5%WIv_S-=-^oJpToS>-r)nCAUlq8_6ulq{hj_WVr<~%&gQOJA% z)}1I&&Q70p#6mDJnwTNZ;%2#i;Fk$D&KpcANi-HaRMl`{3kyU$qzY|-1I-}^Ipb!* zzDkV~rW7lQf0gt&H9@irBe)LVCh}8G!{~@Ltb|p1E1K;ky zpq|NhV1Iwy{1E#Eea*Q8>sI8#<9N*)qvVc=qB+881Gjr&W>em!+mo==`TcRrR|oFj zP@&7SBg3-(r+yxNXiA60ef!_5f?%HdYwI_WD-~1XrmLQdl$`jf&E6gN8|Dh z4XsGFyXZsl&(UDLfrpXb$}2aozkL#>{Kb7qn|XB@NSHw2oZT84V2d48e7A0J^*Z~8 znZon(+d@Y|-Ebm#)B>gA!AmI}!&d0nTM?Z9^7J)uJDOxVZ(;L*oLhgHuA3lYCCl5a zh6_&av#6XIqZ1{;hk}=v=Q+1NVecv5qQ{ag=oP;5Uv@nfxhDpy%0z82BgDxY*v(lb zzW8qS9usBcJtmjf!;AKmZ$RmKX#yY?z5t}>-8V$8ibE~EXN|UeZm<1tvYTAGKxCYr z>o?l<@)Wyz2&_)H4I>Q)A#CiQ8wf>VXKc|={6hP6A*5H%SwT-Ig%zr0p!3CA+x?fo zAD^#L_bH=#5V!IMkH$8&FZxBI-RP%SM$P5tHUE6!^yyIXvTaPDKj~+EWcmw&Hyhu% zGldV~flFl2)~f2EClZdU#`8Iv)79Y)e8JYr!Pze%EGg}&7h=tzc)J@ee?fS z^_5X^b<4JBaF+m$2MO+O!2`iHK+r~lyEg6)L4reo0Kwhe-QC?n;|>kH{?2{po_qEf z``=z(YwW6;v#LhwR)6{BP?b!p2c~XeI8VZ+^c2uj{E<2&d**6-evIq;YASv(XvG*j z6Ric6WgUu!kliHgHGPP$UGijUn^aZKHuW&&}y6cyex-Z{1tktBsc40g<01526M$S26{HD zv%oewA#3SMhm=%EgG(v|&e0NC1Z~+S9{C|B|^TOHSnQ*tPeRQjuoLH4ybzLx(XX`C4RXQ(h-8Qywb_P^pNLHKVW4mG)N*`9!^y3!eOtc%L z->g^z0v0L{JJ?+@pD}?uu5LmI*{!z{-C}odf^iF-mK1iT^QPx3H3{^?f|7yC9j?hxqx&*T6pOvk2!*(cbd=pMgyy)aF4yN;U^kcp^g4+)TNR@%R6R~d9 z8PL$Aw9F4ny-UMwyE*Y;!5LfIi{!>a+mBxi%mA0X1j0{~V@P3KhK*AaK^esyrVX}k z4+6qI&lChB0RF}ep)!_B1L+&2XnBzy^wA1 z_e}EO!L?>{SRjrr`xewwC%}w5t9L9sVfxF!q0nf{x>qH0X{e~e*t*)2xqJuN(bUl8R6lHlQss8W)0#HRE^^VR91U`{k&WdImi5izl@Cfk$5I5Yt*-5 zEz#l80@P%2Ky%cjMbjNa zzsNx~bBBWakE*8mAJ0uw>HvGTnzOm5R3G^2kPXjZE9c&BWvLACEFHqdz9cJa;@n1@xLPAdIY5I(&0XWgL*g zyZ?b322l+er&7^}VQ`417Q2!Kmb$jO6A%?6|HMRC|EZ1;wd!+YLo@SCSnZA{*)kko z7S037Xjo8^ZOP~Uo7e$DYcv4yfGHQ`&uYL$t9o2m%tC}Ozx|Y*enG?cSGd%-c|H?} zPeWL_WBGSwYKyVw$)dowehZ53hZET@ef0;`rlXL`=dD9#QO8|Gi7KPB%{;vroZ)FI zzHlX z8_wv!Uw2?d;p3J+s$KzP)aNW%KLF4Vz*P@ff2*3J^F&(7x?QWz7XYZCbt&}l6ay9V zfVq<*iH3*WWiaID2erdA90pIRQ6MwW*~lL5^t0nS;b9D8|7_v zD`hIKy_gsEt3}4HG+8i;`dII7#v9Rra1wV}5yg@!Pn|i?<6W)aTHX6g&10NU=D?IQmL-zakbH)O zXK{_%5Be*O!5;$68sliG3qMxHEKdX!1K*)^U+N3>Tss5FTw=GS!8?hoF=*5wT3|rY zkUOui7clt#fy~cDcF|6*MZnw?i!b5goMV}2Ll7MOVD%kL70cFJ2sOv6|6`6rE41%2 z{l3imtjJS6^uXD}%Lps|TLp$Mlx@d+FyJ>y?}M7RXZH3m7%s`;asQcsJ5)8eY&va% z_0r;yZAT=O69cNK&rc{Okw7^i$hPRxA8t)u!rLBC{^0ngG_N$?ecU)|GzOXFzi%C~pz!^H1-QHx&QYGYhP>ov8C{X0<7gHTuk_f5WubxWn>oDe zFLE5@Dq)KU94-ghdOE;Ak&!SuNG62aGT@E}Cm0}6f<^2m*LrNx3&-azc>?=?- z4{6YK*j{eVc^?h7vrS^4U zTQm?gC36`Rw+Z?2zba^j4sa+RXdRU91p=im48&}6tq6GCnWb@uf(x@NH(&vM$&7Uz z(UTnbG22Q{7#WW0+Oq@k=OQ3>!MToyMB=~M8s7GskAqU6=QR-fY7bB1c|d#mLvkBT z=P|h<#<-}4xpKr^o9{Kp?OuZE1}-CO%MuL;{k+Ov}vT*pi;6cU10te%#BxJWRK(Fkpx1~!TD|9PS>8Pj~ zHh>TK*66c`OF;VwSBZjsXR%jz&&vqrcpLB@k^R45bZUSkDZE^5{f}&|Mc>{!UOV)n z*w%2Cv50D>=NgTeT*r^i^sP8Yt7|RcB2b?^P4?cj8uT0oFC1N#^fQaxmp1b3I@;s- z?`E;U2+Eh&=#QFf>Uq8Ovvf3_Pcyas`YLO`Iq=1QiQUJL!UV}Ei)RLNPqHb{xQ#3j z87#0h?@ZX~{|aW547hmA1)l?i%wK5K#eNXYmq-|C`fG?==p)WYOC!=o$Y(y{)*2Np z@sdjZP~*}t)ws<;Fn)Vgo_5Bp_}+uh${FuxphvY!T^u(}`W`+QcSMf8mj{mMvAB#0K!nWlhm_paKD`s22 zY`U2eT(al*x2>&d+W5V-N}NaUxF*Xzk=d@q@kq zkkzP6D;YwfeaF`=QBlI2Lx!)hVosu`F;sl7FF0Z$vdb9Fx7wtQ_g1FsR&>x@pywRS zP@jYn)6VCL!j`CZ`2Yfplh?jF?fN5raJGpYEvAp0Zk4(XAU5}NF)`zriyTa3TIli2 z?pGo)$i1aF=EOw+eRm8*34g4fP;8aq;$U|Xt&bMWz$D@x>0W{GXmron7PmfH1=P#+ zk=rz^Ufpg3R?oHRx=_1$ek4wo{SP?e{SP?8$SyOb2$&g~A#&m}$(j|7?(YuswkK#I zX<%zzcD_l?L8x0l$mrE&s$_=y#(l2n_`zy}XlHf4?Gk+IK;5d>+C-Pi6MAK}Z`sCC zwt<4KH?*hjtp3ni#!X0MMWk!|c1T92vJpGo){?qy8Ik8`57j zpj(c+zYnunGd+?w5A=W_^gh%(yi$J!Vz?!9?!4Sp?IE?a*v0y2(>0dLiSdN=)}LH_ zSaJ&DLAa`s&grV8cEo*SSd5+rkOj1_UcR z?8B1C&4&F_XqF+rD)fEwt^)vgLgV5Z&tZl9c{C)wWa%dsK)@!&djp5XWQ*dK8#9cp zSx5MAEZR777jB;*HRIuPp<5W2aO-js$&N!;Czn{NE^P;d))kM2D}0F|kx+=FHF>M< zBRx1TX@dRqR%m`!m(UNw$8S>!oFYHG!h(Sz)sT}C*J#JO)tg5@b@$(0q$3OJghB;W zF$V{cv+sXLR!7r5`?>0+?Ee}4bwi*g6+SRnan{Ab*wYBV!8U^D|AQHkN&{Iu(#$Br zUtQkIFf5T;qxx%6b7c}N!6%aedoi~I@mA!4i-4l4cAx1G*J;h+>51swRyPxE+QBZc zkg_Q5c|ymq#c_pA?VL~Ns?lW;$<8o#$n+W`0IXS71{8>IZnX&ncT;y=i*gj z;tk#OkbUERF|MzC;MJi|G>|R(cVsRd7L;Wsjgv3-A5=~U3bJ;+%tvT(Q8#CC z?3K-VO;yhlIt|i@N{tv#ocO>9UqC>a(FWij4z<~B(k~C`+y|T<#~Cc!J?dCLNGK^H z=!uT7uT6Y|tQO+Ee{s{|7=~BNxlqY846xsrU>!5H_lMUM&yiKn1o3__gLxEC``c;EnCHMdD3k;3j49X)sXEOdrj$nrlI^SUMJfN+yo2?@w1@&AyPzxdW8$Njkw}oeI7c8D>#POtao}o59 z)MV6Km^2(;08`yI>;De*WHFz8u}d#8a({94BXWL~vx2k&{nCU5*|LjrZUpfv$UWMo zEMFO$^)cTl@%RudVsanLOsk8WrD}?eY7$oe7~H#jY|#oKh(h|hv`iHCU0l8Q-rS#)n zC7N}Vaf|Ub-i`;CCj&|0#CeHyc1HRny&%OjID!cCL(N|trk_ZDnwoE@i95vq=750L z>5blAo=PX3I`H-l?v}?5>1zhq1y3V0z))XvOzhJ)5p1!AiXS4g59F5$y9L*W;bEVo zK(`1|5Lv%74vP)v^?ipI0^l@e@*NmO6KEWF7qi4(xJzHyCmm5!vwu+e4Qh(vj{dJH zc0J&bAL9^3(0!z+iym|ES+USoG(-+E9}d=tPxy4#qP$~GuwA#DD+D6EaEPF8$nm=% zS##Lse>jSgz7YA2m=Z@?GGP%P=^gjWGdyARsYd^@=#_JYU~+JlyakQi_o{NLWcp z(;&BOOL>wONA4?^U{aFD zCuGcxLZLPSEG)7I`rEz4+%i?=Y*&`sWnKmxlLPt)%}fd##0KW3vVKho#8A=jz^UZi znV-m(5o*JVru|9Pdv4+AwNEmI2*iOhQWPfUUO;wn^Xi0S98jtyB$gZyd>AI^>DgzeAr3HECgT?KO$3lc`_l-`D z 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 Ri;jRFxRRzK`qo4L{{xt7HR%8V diff --git a/old/part1/ingress.yml b/old/part1/ingress.yml deleted file mode 100644 index ce83401cb..000000000 --- a/old/part1/ingress.yml +++ /dev/null @@ -1,78 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - namespace: kube-system - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: minikube dashboard - http: - paths: - - path: / - backend: - serviceName: kubernetes-dashboard - servicePort: 80 - - - host: grafana.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: monitoring-grafana - servicePort: 80 ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: europa.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: europa - servicePort: 80 - - - host: jenkins.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: jenkins - servicePort: 80 - - - host: gogs.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: gogs - servicePort: 80 - - # - host: nginx.MINIKUBE_IP.xip.io - # http: - # paths: - # - path: / - # backend: - # serviceName: nginx - # servicePort: 80 - - # - host: gogs.MINIKUBE_IP.xip.io - # http: - # paths: - # - path: / - # backend: - # serviceName: gogs - # servicePort: 80 \ No newline at end of file diff --git a/old/part1/mysql.yml b/old/part1/mysql.yml deleted file mode 100644 index f9d3a3a2d..000000000 --- a/old/part1/mysql.yml +++ /dev/null @@ -1,58 +0,0 @@ -# kind: PersistentVolumeClaim -# apiVersion: v1 -# metadata: -# name: mysql-claim -# spec: -# accessModes: -# - ReadWriteOnce -# resources: -# requests: -# storage: 5Gi -# --- -apiVersion: v1 -kind: Service -metadata: - name: mysql - labels: - app: mysql -spec: - ports: - - port: 3306 - selector: - app: mysql - tier: mysql - clusterIP: None ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: mysql - labels: - app: mysql -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: mysql - tier: mysql - spec: - containers: - - image: mysql:5.7 - name: mysql - env: - - name: MYSQL_ROOT_PASSWORD - value: europa - - name: MYSQL_DATABASE - value: europa - ports: - - containerPort: 3306 - name: mysql - # volumeMounts: - # - name: mysql-persistent-storage - # mountPath: /var/lib/mysql - # volumes: - # - name: mysql-persistent-storage - # persistentVolumeClaim: - # claimName: mysql-claim diff --git a/old/part1/notes.txt b/old/part1/notes.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/old/part1/registry.yml b/old/part1/registry.yml deleted file mode 100644 index b60ff11ac..000000000 --- a/old/part1/registry.yml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: ReplicationController -metadata: - name: kube-registry-v0 - namespace: kube-system - labels: - k8s-app: kube-registry - version: v0 -spec: - replicas: 1 - selector: - k8s-app: kube-registry - version: v0 - template: - metadata: - labels: - k8s-app: kube-registry - version: v0 - spec: - containers: - - name: registry - image: registry:2 - resources: - limits: - cpu: 100m - memory: 100Mi - env: - - name: REGISTRY_HTTP_ADDR - value: :5000 - - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY - value: /var/lib/registry - volumeMounts: - - name: registry-volume - mountPath: /var/lib/registry - ports: - - containerPort: 5000 - name: registry - protocol: TCP - volumes: - - name: registry-volume - hostPath: - path: /data/registry ---- -apiVersion: v1 -kind: Service -metadata: - name: kube-registry - namespace: kube-system - labels: - k8s-app: kube-registry - kubernetes.io/name: "KubeRegistry" -spec: - selector: - k8s-app: kube-registry - type: NodePort - ports: - - name: registry - port: 5000 - nodePort: 30900 - protocol: TCP ---- -apiVersion: v1 -kind: Pod -metadata: - name: kube-registry-proxy - namespace: kube-system -spec: - containers: - - name: kube-registry-proxy - image: gcr.io/google_containers/kube-registry-proxy:0.3 - resources: - limits: - cpu: 100m - memory: 50Mi - env: - - name: REGISTRY_HOST - value: kube-registry.kube-system.svc.cluster.local - - name: REGISTRY_PORT - value: "5000" - - name: FORWARD_PORT - value: "5000" - ports: - - name: registry - containerPort: 5000 - hostPort: 5000 \ No newline at end of file diff --git a/old/part1/start.sh b/old/part1/start.sh deleted file mode 100755 index 68b1bcb35..000000000 --- a/old/part1/start.sh +++ /dev/null @@ -1,29 +0,0 @@ -#minikube start --memory 10000 --cpus 2 --disk-size 50g - -#docker login -u TOKEN -p 0u5gzdtjn3m8102lmjxnt8t87u 192.168.42.134:30861 - -# docker push 192.168.42.134:30861/nginx:latest - -# sudo vim /usr/lib/systemd/system/docker.service # --insecure-registry="192.168.42.134:30861" - -# deploy europa.192.168.42.134.xip.io:80/nginx:latest - -#sudo virsh net-start default -#sudo virsh net-start docker-machines - -minikube delete - -rm -rf ~/.minikube - -minikube start --vm-driver kvm --memory 8000 --cpus 4 --disk-size 50g - - -minikube addons enable heapster; minikube addons enable ingress; kubectl --namespace spinnaker rollout status pods - -kubectl get pods --all-namespaces - -kubectl cluster-info - -#minikube start --vm-driver kvm --memory 10000 --cpus 4 --disk-size 50g - -#curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl \ No newline at end of file diff --git a/old/part1/svc.sh b/old/part1/svc.sh deleted file mode 100755 index 90e288e20..000000000 --- a/old/part1/svc.sh +++ /dev/null @@ -1 +0,0 @@ -xdg-open "http://$1.`minikube ip`.xip.io" \ No newline at end of file diff --git a/old/part1/volumes.yml b/old/part1/volumes.yml deleted file mode 100644 index d026efcd5..000000000 --- a/old/part1/volumes.yml +++ /dev/null @@ -1,57 +0,0 @@ -kind: PersistentVolume -apiVersion: v1 -metadata: - name: mysql - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/mysql/" ---- -kind: PersistentVolume -apiVersion: v1 -metadata: - name: europa - labels: - type: local -spec: - capacity: - storage: 10Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/europa/" - ---- -kind: PersistentVolume -apiVersion: v1 -metadata: - name: jenkins - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/jenkins/" - -# --- -# kind: PersistentVolume -# apiVersion: v1 -# metadata: -# name: gogs -# labels: -# type: local -# spec: -# capacity: -# storage: 2Gi -# accessModes: -# - ReadWriteOnce -# hostPath: -# path: "/data/gogs/" \ No newline at end of file diff --git a/old/part3/Jenkinsfile b/old/part3/Jenkinsfile deleted file mode 100644 index 4741b8d07..000000000 --- a/old/part3/Jenkinsfile +++ /dev/null @@ -1,26 +0,0 @@ -node { - - checkout scm - - env.DOCKER_API_VERSION="1.23" - - sh "git rev-parse --short HEAD > commit-id" - - tag = readFile('commit-id').replace("\n", "").replace("\r", "") - appName = "hellokenzan" - registryHost = "127.0.0.1:30912/" - imageName = "${registryHost}${appName}:${tag}" - env.BUILDIMG=imageName - - stage "Build" - - sh "docker build -t ${imageName} part1/hello-kenzan" - - stage "Push" - - sh "docker push ${imageName}" - - stage "Deploy" - - sh "sed 's#127.0.0.1:30912/hellokenzan:latest#'$BUILDIMG'#' part1/hello-kenzan/k8s/deployment.yaml | kubectl apply -f -" -} \ No newline at end of file diff --git a/old/part3/README.md b/old/part3/README.md deleted file mode 100644 index 222e70dbf..000000000 --- a/old/part3/README.md +++ /dev/null @@ -1,40 +0,0 @@ -## Part 3 - -``` -cd part3 -``` - -### Edit jenkins.yml with minikube ip - -### Install jenkins - -``` -kubectl apply -f jenkins.yml; kubectl rollout status deployment/jenkins -``` - -### Get jenkins pod name - -``` -kubectl get pods -``` - -### Get jenkins admin token -``` -kubectl exec JENKINSPOD cat /root/.jenkins/secrets/initialAdminPassword -``` - -### Setup Jenkins with defaults -``` -open http://jenkins.MINIKUBEIP.xip.io -``` - -### Create a new Jenkins Pipeline Job - -Choose "Jenkinsfile from SCM" and put `https://github.com/kenzanlabs/kubernetes-ci-cd.git` for the target repository (or your fork). For `Jenkinsfile path` put `part3/Jenkinsfile` - -### Run Job - - -Ensure job finishes correctly and new version of hello-kenzan has been deployed i nthe dashboard - -If you have pointed the targer repo in the job at your fork, try to make some changes to the application and run your job to see the changes deployed \ No newline at end of file diff --git a/old/part3/jenkins.yml b/old/part3/jenkins.yml deleted file mode 100644 index b70883b37..000000000 --- a/old/part3/jenkins.yml +++ /dev/null @@ -1,92 +0,0 @@ - -kind: PersistentVolume -apiVersion: v1 -metadata: - name: jenkins - labels: - type: local -spec: - capacity: - storage: 2Gi - accessModes: - - ReadWriteOnce - hostPath: - path: "/data/jenkins/" - ---- -kind: PersistentVolumeClaim -apiVersion: v1 -metadata: - name: jenkins-claim -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: Service -metadata: - name: jenkins - labels: - app: jenkins -spec: - ports: - - port: 80 - targetPort: 8080 - selector: - app: jenkins - tier: jenkins - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: jenkins - labels: - app: jenkins -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: jenkins - tier: jenkins - spec: - containers: - - image: chadmoon/jenkins-docker-kubectl:latest - name: jenkins - securityContext: - privileged: true - ports: - - containerPort: 8080 - name: jenkins - volumeMounts: - - name: jenkins-persistent-storage - mountPath: /root/.jenkins - - name: docker - mountPath: /var/run/docker.sock - volumes: - - name: docker - hostPath: - path: /var/run/docker.sock - - name: jenkins-persistent-storage - persistentVolumeClaim: - claimName: jenkins-claim - ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: jenkins-ingress -spec: - rules: - - host: jenkins.192.168.99.100.xip.io - http: - paths: - - path: / - backend: - serviceName: jenkins - servicePort: 8080 \ No newline at end of file diff --git a/old/part5/spinnaker/apply-config.sh b/old/part5/spinnaker/apply-config.sh deleted file mode 100755 index 4062eba8d..000000000 --- a/old/part5/spinnaker/apply-config.sh +++ /dev/null @@ -1,10 +0,0 @@ -kubectl apply -f namespace.yml -sleep 2 -kubectl delete --namespace spinnaker configmap spinnaker-config -sleep 2 -kubectl create --namespace spinnaker configmap spinnaker-config --from-file=config/front50.yml --from-file=config/clouddriver.yml --from-file=config/orca.yml --from-file=config/gate.yml --from-file=config/settings.js --from-file=config/run-apache2.sh --from-file=config/kube.config --from-file=config/igor.yml --from-file=config/echo.yml - -sleep 2 -kubectl delete --namespace spinnaker secret spinnaker-config -sleep 2 -kubectl create --namespace spinnaker secret generic spinnaker-config --from-file=config/front50.yml --from-file=config/clouddriver.yml --from-file=config/orca.yml --from-file=config/gate.yml --from-file=config/settings.js --from-file=config/run-apache2.sh --from-file=config/kube.config --from-file=config/igor.yml --from-file=config/echo.yml \ No newline at end of file diff --git a/old/part5/spinnaker/clouddriver.yml b/old/part5/spinnaker/clouddriver.yml deleted file mode 100644 index 6e66bcb7b..000000000 --- a/old/part5/spinnaker/clouddriver.yml +++ /dev/null @@ -1,63 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: clouddriver - labels: - app: clouddriver -spec: - ports: - - port: 7002 - targetPort: 7002 - selector: - app: clouddriver - tier: clouddriver - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: clouddriver - labels: - app: clouddriver -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: clouddriver - tier: clouddriver - spec: - containers: - - image: quay.io/spinnaker/clouddriver:v1.490.0 - name: clouddriver - - ports: - - containerPort: 7002 - name: clouddriver - volumeMounts: - - name: spinnaker-config - mountPath: /opt/clouddriver/config - - name: spinnaker-config - mountPath: /root/.kube/config - subPath: kube.config - command: ["bash"] - args: ["-c", "cd /usr/local/bin; curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl; chmod +x kubectl; /opt/clouddriver/bin/clouddriver"] - - - image: lachlanevenson/k8s-kubectl:latest - name: kubectl - ports: - - containerPort: 8001 - name: kubectl - args: ["proxy"] - - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config - # - name: kube-config - # configMap: - # name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/config/clouddriver.yml b/old/part5/spinnaker/config/clouddriver.yml deleted file mode 100644 index 8af20c35a..000000000 --- a/old/part5/spinnaker/config/clouddriver.yml +++ /dev/null @@ -1,85 +0,0 @@ -aws: - enabled: false - defaults: - iamRole: BaseIAMRole - defaultRegions: - - name: us-east-1 - defaultFront50Template: http://front50-service:8080 - defaultKeyPairTemplate: keypair - migration: - infrastructureApplications: null - # an empty list means we are directly managing the AWS account we have credentials for (named default.account.env) - # see prod profile section below for an example configuration to manage other accounts via STS assume role - accounts: [] - - -azure: - enabled: false -cf: - accounts: - enabled: false -credentials: - challengeDestructiveActionsEnvironments: k8s - primaryAccountTypes: k8s -default: - account: - env: k8s - -kubernetes: - enabled: true - accounts: - - name: k8s - # kubeconfigFile: /root/kube.config - namespaces: - - default - - spinnaker - # user: # optional user to authenticate as that must exist in the provided kube config file - # cluster: # optional cluster to connect to that must exist in the provided kube config file - dockerRegistries: - - accountName: quay - # namespaces: # optional list of namespaces this docker registry can deploy to - -dockerRegistry: - enabled: true - accounts: - - name: quay - address: https://quay.io - username: # optional username for authenticating with the registry - password: # optional password for authenticating with the registry - email: # optional email for authenticating with the registry - repositories: - - spinnaker/deck - - spinnaker/gate - - spinnaker/orca - - spinnaker/echo - - spinnaker/igor - - spinnaker/front50 - - spinnaker/clouddriver - # - moondev/nginx - # cacheThreads: # optional (default is 1) number of threads to cache registry contents across - # clientTimeoutMillis: # optional (default is 1 minute) time before the registry connection times out - # paginateSize: # optional (default is 100) number of entries to request from /_catalog at a time - - # repositories: - # - nginx - # cacheThreads: # optional (default is 1) number of threads to cache registry contents across - # clientTimeoutMillis: # optional (default is 1 minute) time before the registry connection times out - # paginateSize: # optional (default is 100) number of entries to request from /_catalog at a time - - -google: - enabled: false - -redis: - enabled: true - connection: redis://redis:6379 - scheduler: default - parallelism: -1 -server: - port: 7002 - address: 0.0.0.0 -services: - front50: - baseUrl: http://front50:8080 -udf: - enabled: false \ No newline at end of file diff --git a/old/part5/spinnaker/config/echo.yml b/old/part5/spinnaker/config/echo.yml deleted file mode 100644 index 341059292..000000000 --- a/old/part5/spinnaker/config/echo.yml +++ /dev/null @@ -1,67 +0,0 @@ -server: - port: 8089 - address: 0.0.0.0 - -# cassandra: -# enabled: true -# embedded: true -# # host: ${services.cassandra.host:localhost} - -spinnaker: - baseUrl: http://localhost:9000 - cassandra: - enabled: false - - inMemory: - enabled: true - - - -front50: - baseUrl: http://front50:8080 - -orca: - baseUrl: http://orca:8083 - -endpoints.health.sensitive: false - -slack: - enabled: false - -# spring: -# mail: -# host: ${mail.host} - -mail: - enabled: false - host: ${services.echo.notifications.mail.host} - from: ${services.echo.notifications.mail.fromAddress} - -hipchat: - enabled: false - baseUrl: ${services.echo.notifications.hipchat.url} - token: ${services.echo.notifications.hipchat.token} - -twilio: - enabled: false - baseUrl: ${services.echo.notifications.sms.url:https://api.twilio.com/} - account: ${services.echo.notifications.sms.account} - token: ${services.echo.notifications.sms.token} - from: ${services.echo.notifications.sms.from} - -scheduler: - compensationJob: - enabled: true - windowMs: 1800000 # optional - -spectator: - applicationName: ${spring.application.name} - webEndpoint: - enabled: false - prototypeFilter: - path: ${services.spectator.webEndpoint.prototypeFilter.path:} - - stackdriver: - enabled: false - projectName: ${services.stackdriver.projectName} - credentialsPath: ${services.stackdriver.credentialsPath} \ No newline at end of file diff --git a/old/part5/spinnaker/config/front50.yml b/old/part5/spinnaker/config/front50.yml deleted file mode 100644 index 486f733ca..000000000 --- a/old/part5/spinnaker/config/front50.yml +++ /dev/null @@ -1,44 +0,0 @@ -server: - port: 8080 - address: 0.0.0.0 -redis: - enabled: true - connection: redis://redis:6379 - host: redis - port: 6379 - scheduler: default - parallelism: -1 - secure: false - - -cassandra: - enabled: false - -spinnaker: - - redis: - enabled: true - secure: false - connection: redis://redis:6379 - host: redis - port: 6379 - scheduler: default - parallelism: -1 - - cassandra: - enabled: false - - -swagger: - enabled: true - title: Spinnaker Front50 API - description: - contact: - patterns: - - /default/.* - - /credentials.* - - /global/.* - - /notifications.* - - /pipelines.* - - /strategies.* - - /v2/.* \ No newline at end of file diff --git a/old/part5/spinnaker/config/gate.yml b/old/part5/spinnaker/config/gate.yml deleted file mode 100644 index 68d07be45..000000000 --- a/old/part5/spinnaker/config/gate.yml +++ /dev/null @@ -1,203 +0,0 @@ -server: - port: 8084 - address: 0.0.0.0 - -spinnaker: - redis: - enabled: true - connection: redis://redis:6379 - scheduler: default - parallelism: -1 - -services: - deck: - baseUrl: http://spinnaker.192.168.42.74.xip.io - auth: - enabled: false - orca: - baseUrl: http://orca:8083 - front50: - baseUrl: http://front50:8080 - clouddriver: - baseUrl: http://clouddriver:7002 -# semi-optional services (Everybody except Netflix needs these): - rosco: - enabled: false - baseUrl: http://rosco:8087 - # These are here only for Netflix, whose bakery does not support dynamically fetching these properties. - # Modifying the details below when rosco.enabled is true will have no effect (do it in the Rosco config). - # defaults: - # bakeOptions: - # - cloudProvider: aws - # baseImages: - # - id: trusty - # shortDescription: v14.04 - # detailedDescription: Ubuntu Trusty Tahr v14.04 - # packageType: DEB - # - id: ubuntu - # shortDescription: v12.04 - # detailedDescription: Ubuntu Precise Pangolin v12.04 - # packageType: DEB - # - id: centos - # shortDescription: deprecated - # detailedDescription: CentOS v5.11 - # packageType: RPM -# optional services: - echo: - enabled: false - fiat: - enabled: false - autoConfig: false - flapjack: - enabled: false - igor: - enabled: true - baseUrl: http://igor:8088 - mahe: - enabled: false - -redis: - enabled: true - connection: redis://redis:6379 - scheduler: default - parallelism: -1 - -swagger: - enabled: true - title: Spinnaker API - description: - contact: - patterns: - - .*tasks.* - - .*applications.* - - .*securityGroups.* - - /search - - .*pipelines.* - - .*loadBalancers.* - - .*instances.* - - .*images.* - - .*elasticIps.* - - .*credentials.* - - .*events.* - - .*builds.* - - .*instanceTypes.* - - .*vpcs.* - - .*subnets.* - - .*networks.* - - .*bakery.* - - .*executions.* - -hystrix: - command: -## Hystrix Global Defaults - default: - execution.isolation.thread.timeoutInMilliseconds: 60000 -## Command-specific overrides - fetchGlobalAccounts: - execution.isolation.thread.timeoutInMilliseconds: 2000 - -spring: - jackson: - mapper: - SORT_PROPERTIES_ALPHABETICALLY: true - serialization: - ORDER_MAP_ENTRIES_BY_KEYS: true - ---- - -# spring: -# profiles: googleOAuth -# oauth2: -# client: -# # Set these values in your own config file (e.g. spinnaker-local.yml or gate-googleOAuth.yml). -# # clientId: -# # clientSecret: -# accessTokenUri: https://www.googleapis.com/oauth2/v4/token -# userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth -# scope: "profile email" -# resource: -# userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo -# userInfoMapping: -# email: email -# firstName: given_name -# lastName: family_name - -# --- - -# spring: -# profiles: azureOAuth -# oauth2: -# client: -# # Set these values in your own config file (e.g. spinnaker-local.yml or gate-azureOAuth.yml). -# # clientId: -# # clientSecret: -# accessTokenUri: https://login.microsoftonline.com/${azureTenantId}/oauth2/token -# userAuthorizationUri: https://login.microsoftonline.com/${azureTenantId}/oauth2/authorize?resource=https://graph.windows.net -# scope: "profile" -# clientAuthenticationScheme: query -# resource: -# userInfoUri: https://graph.windows.net/me?api-version=1.6 -# userInfoMapping: -# email: userPrincipalName -# firstName: givenName -# lastName: surname - -# --- - -# spring: -# profiles: githubOAuth -# oauth2: -# client: -# # Set these values in your own config file (e.g. spinnaker-local.yml or gate-githubOAuth.yml). -# # clientId: -# # clientSecret: -# userAuthorizationUri: https://github.com/login/oauth/authorize -# accessTokenUri: https://github.com/login/oauth/access_token -# scope: user:email -# resource: -# userInfoUri: https://api.github.com/user -# userInfoMapping: -# email: email -# firstName: -# lastName: name -# username: login - - - - - - -# redis: -# enabled: true -# connection: redis://redis:6379 -# scheduler: default -# parallelism: -1 -# server: -# port: 8084 -# address: 0.0.0.0 -# services: -# clouddriver: -# baseUrl: http://clouddriver:7002 -# deck: -# baseUrl: http://deck.192.168.42.74.xip.io -# front50: -# baseUrl: http://front50:8080 -# orca: -# baseUrl: http://orca:8083 -# igor: -# enabled: false -# baseUrl: http://igor:8088 -# rosco: -# enabled: false -# baseUrl: http://rosco:8087 -# echo: -# enabled: false -# baseUrl: http://echo:8089 - -# fiat: -# enabled: false -# autoConfig: false -# flapjack: -# enabled: false -# mahe: -# enabled: false \ No newline at end of file diff --git a/old/part5/spinnaker/config/igor.yml b/old/part5/spinnaker/config/igor.yml deleted file mode 100644 index bc4385ae7..000000000 --- a/old/part5/spinnaker/config/igor.yml +++ /dev/null @@ -1,45 +0,0 @@ -server: - port: 8088 - address: 0.0.0.0 - -jenkins: - enabled: true - masters: - - name: jenkins - address: http://jenkins.default:80 - username: jenkins - password: jenkins - -travis: - enabled: false - masters: - - name: ${services.travis.defaultMaster.name} - baseUrl: ${services.travis.defaultMaster.baseUrl} - address: ${services.travis.defaultMaster.address} - githubToken: ${services.travis.defaultMaster.githubToken} - -dockerRegistry: - enabled: false - -redis: - connection: redis://redis:6379 - -# Igor depends on Clouddriver and Echo. These are normally configured -# in spinnaker[-local].yml (if present), otherwise, uncomment this. -# services: - clouddriver: - baseUrl: http://clouddriver:7002 - echo: - baseUrl: http://echo - -# spectator: -# applicationName: ${spring.application.name} -# webEndpoint: -# enabled: ${services.spectator.webEndpoint.enabled:false} -# prototypeFilter: -# path: ${services.spectator.webEndpoint.prototypeFilter.path:} - -# stackdriver: -# enabled: ${services.stackdriver.enabled} -# projectName: ${services.stackdriver.projectName} -# credentialsPath: ${services.stackdriver.credentialsPath} \ No newline at end of file diff --git a/old/part5/spinnaker/config/kube.config b/old/part5/spinnaker/config/kube.config deleted file mode 100644 index bff01bbe5..000000000 --- a/old/part5/spinnaker/config/kube.config +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -clusters: -- cluster: - insecure-skip-tls-verify: true - server: http://localhost:8001 - name: minikube -contexts: -- context: - cluster: minikube - name: minikube -current-context: minikube -kind: Config -preferences: {} -users: -- name: minikube \ No newline at end of file diff --git a/old/part5/spinnaker/config/orca.yml b/old/part5/spinnaker/config/orca.yml deleted file mode 100644 index 33d6abba4..000000000 --- a/old/part5/spinnaker/config/orca.yml +++ /dev/null @@ -1,54 +0,0 @@ -bakery: - allowMissingPackageInstallation: true - baseUrl: http://rosco:8087 - extractBuildDetails: true - roscoApisEnabled: true - propagateCloudProviderType: true - -rosco: - baseUrl: http://rosco:8007 - roscoApisEnabled: true - enabled: false - allowMissingPackageInstallation: true - -default: - bake: - account: docker - - securityGroups: null - vpc: - securityGroups: null -echo: - baseUrl: http://echo:8089 - enabled: false -flex: - baseUrl: http://not-a-host -front50: - baseUrl: http://front50:8080 - -igor: - enabled: true - baseUrl: http://igor:8088 -kato: - baseUrl: http://clouddriver:7002 -mort: - baseUrl: http://clouddriver:7002 -oort: - baseUrl: http://clouddriver:7002 -redis: - enabled: true - connection: redis://redis:6379 - scheduler: default - parallelism: -1 -server: - port: 8083 - address: 0.0.0.0 -services: - orca: - timezone: west -tasks: - executionWindow: - timezone: west -tide: - baseUrl: http://not-a-host - enabled: false \ No newline at end of file diff --git a/old/part5/spinnaker/config/run-apache2.sh b/old/part5/spinnaker/config/run-apache2.sh deleted file mode 100755 index 825c0343d..000000000 --- a/old/part5/spinnaker/config/run-apache2.sh +++ /dev/null @@ -1,59 +0,0 @@ -# Set any missing env variables used to configure deck - -_DECK_HOST=0.0.0.0 -_DECK_PORT=9000 -_API_HOST=http://gate:8084 -_DECK_CERT_PATH=$DECK_CERT -_DECK_KEY_PATH=$DECK_KEY - -if [ -z "$_DECK_HOST" ]; -then - _DECK_HOST=0.0.0.0 -fi - -if [ -z "$_DECK_PORT" ]; -then - _DECK_PORT=9000 -fi - -if [ -z "$_API_HOST" ]; -then - _API_HOST=http://localhost:8084 -fi - -if [ -z "$_DECK_CERT_PATH" ]; -then - # SSL not enabled - cp docker/spinnaker.conf.gen spinnaker.conf -else - service apache2 stop - a2enmod ssl - cp docker/spinnaker.conf.ssl spinnaker.conf - sed -ie 's|{%DECK_CERT_PATH%}|'$_DECK_CERT_PATH'|g' spinnaker.conf - sed -ie 's|{%DECK_KEY_PATH%}|'$_DECK_KEY_PATH'|g' spinnaker.conf -fi - -# Generate spinnaker.conf site & enable it - -sed -ie 's|{%DECK_HOST%}|'$_DECK_HOST'|g' spinnaker.conf -sed -ie 's|{%DECK_PORT%}|'$_DECK_PORT'|g' spinnaker.conf -sed -ie 's|{%API_HOST%}|'$_API_HOST'|g' spinnaker.conf - -mkdir -p /etc/apache2/sites-available -mv spinnaker.conf /etc/apache2/sites-available - -a2ensite spinnaker - -# Update ports.conf to reflect desired deck host - -cp docker/ports.conf.gen ports.conf - -sed -ie "s/{%DECK_HOST%}/$_DECK_HOST/g" ports.conf -sed -ie "s/{%DECK_PORT%}/$_DECK_PORT/g" ports.conf - -mv ports.conf /etc/apache2/ports.conf - - -cp /settings.js /opt/deck/html/settings.js - -apache2ctl -D FOREGROUND \ No newline at end of file diff --git a/old/part5/spinnaker/config/settings-old.js b/old/part5/spinnaker/config/settings-old.js deleted file mode 100644 index dccb4aab9..000000000 --- a/old/part5/spinnaker/config/settings-old.js +++ /dev/null @@ -1,132 +0,0 @@ -webpackJsonp([2,3],{ - -/***/ 3022: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -var feedbackUrl = '/feedback'; -var gateHost = '/gate'; -var bakeryDetailUrl = gateHost + '/bakery/logs/{{context.region}}/{{context.status.resourceId}}'; -var authEndpoint = gateHost + '/auth/user'; -var authEnabled = false; -var netflixMode = false; -var chaosEnabled = false; -var fiatEnabled = false; -var entityTagsEnabled = false; -var debugEnabled = true; - -window.spinnakerSettings = { - checkForUpdates: false, - debugEnabled: debugEnabled, - defaultProviders: ['aws', 'gce', 'azure', 'cf', 'kubernetes', 'titus', 'openstack'], - feedbackUrl: feedbackUrl, - gateUrl: gateHost, - bakeryDetailUrl: bakeryDetailUrl, - authEndpoint: authEndpoint, - pollSchedule: 30000, - defaultTimeZone: process.env.TIMEZONE || 'America/Los_Angeles', // see http://momentjs.com/timezone/docs/#/data-utilities/ - defaultCategory: 'serverGroup', - defaultInstancePort: 80, - providers: { - azure: { - defaults: { - account: 'azure-test', - region: 'westus' - } - }, - aws: { - defaults: { - account: 'test', - region: 'us-east-1', - iamRole: 'BaseIAMRole' - }, - defaultSecurityGroups: [], - loadBalancers: { - // if true, VPC load balancers will be created as internal load balancers if the selected subnet has a purpose - // tag that starts with "internal" - inferInternalFlagFromSubnet: false - }, - useAmiBlockDeviceMappings: false - }, - gce: { - defaults: { - account: 'my-google-account', - region: 'us-central1', - zone: 'us-central1-f' - } - }, - titus: { - defaults: { - account: 'titustestvpc', - region: 'us-east-1', - iamProfile: '{{application}}InstanceProfile' - } - }, - openstack: { - defaults: { - account: 'test', - region: 'us-west-1' - } - }, - kubernetes: { - defaults: { - account: 'my-kubernetes-account', - namespace: 'default', - proxy: 'localhost:8080' - } - }, - appengine: { - defaults: { - account: 'my-appengine-account', - editLoadBalancerStageEnabled: false - } - } - }, - whatsNew: { - gistId: '32526cd608db3d811b38', - fileName: 'news.md' - }, - notifications: { - email: { - enabled: true - }, - hipchat: { - enabled: true, - botName: 'Skynet T-800' - }, - sms: { - enabled: true - }, - slack: { - enabled: true, - botName: 'spinnakerbot' - } - }, - authEnabled: authEnabled, - authTtl: 600000, - gitSources: ['stash', 'github', 'bitbucket'], - triggerTypes: ['git', 'pipeline', 'docker', 'cron', 'jenkins'], - feature: { - entityTags: entityTagsEnabled, - fiatEnabled: fiatEnabled, - pipelines: true, - notifications: false, - fastProperty: true, - vpcMigrator: true, - clusterDiff: false, - roscoMode: false, - netflixMode: netflixMode, - chaosMonkey: chaosEnabled, - // whether stages affecting infrastructure (like "Create Load Balancer") should be enabled or not - infrastructureStages: process.env.INFRA_STAGES === 'enabled', - jobs: false, - snapshots: false - } -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(180))) - -/***/ }) - -},[3022]); \ No newline at end of file diff --git a/old/part5/spinnaker/config/settings.js b/old/part5/spinnaker/config/settings.js deleted file mode 100644 index ca5f8f057..000000000 --- a/old/part5/spinnaker/config/settings.js +++ /dev/null @@ -1,132 +0,0 @@ -webpackJsonp([2,3],{ - -/***/ 3304: -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -var feedbackUrl = process.env.FEEDBACK_URL; -var gateHost = process.env.API_HOST || '/gate'; -var bakeryDetailUrl = process.env.BAKERY_DETAIL_URL || gateHost + '/bakery/logs/{{context.region}}/{{context.status.resourceId}}'; -var authEndpoint = process.env.AUTH_ENDPOINT || gateHost + '/auth/user'; -var authEnabled = false; -var netflixMode = false; -var chaosEnabled = netflixMode || process.env.CHAOS_ENABLED === 'true' ? true : false; -var fiatEnabled = false; -var entityTagsEnabled = false; -var debugEnabled = process.env.DEBUG_ENABLED === 'false' ? false : true; - -window.spinnakerSettings = { - checkForUpdates: false, - debugEnabled: debugEnabled, - defaultProviders: ['aws', 'gce', 'azure', 'cf', 'kubernetes', 'titus', 'openstack'], - feedbackUrl: feedbackUrl, - gateUrl: gateHost, - bakeryDetailUrl: bakeryDetailUrl, - authEndpoint: authEndpoint, - pollSchedule: 30000, - defaultTimeZone: process.env.TIMEZONE || 'America/Los_Angeles', // see http://momentjs.com/timezone/docs/#/data-utilities/ - defaultCategory: 'serverGroup', - defaultInstancePort: 80, - providers: { - azure: { - defaults: { - account: 'azure-test', - region: 'westus' - } - }, - aws: { - defaults: { - account: 'test', - region: 'us-east-1', - iamRole: 'BaseIAMRole' - }, - defaultSecurityGroups: [], - loadBalancers: { - // if true, VPC load balancers will be created as internal load balancers if the selected subnet has a purpose - // tag that starts with "internal" - inferInternalFlagFromSubnet: false - }, - useAmiBlockDeviceMappings: false - }, - gce: { - defaults: { - account: 'my-google-account', - region: 'us-central1', - zone: 'us-central1-f' - } - }, - titus: { - defaults: { - account: 'titustestvpc', - region: 'us-east-1', - iamProfile: '{{application}}InstanceProfile' - } - }, - openstack: { - defaults: { - account: 'test', - region: 'us-west-1' - } - }, - kubernetes: { - defaults: { - account: 'default', - namespace: 'default', - proxy: 'localhost:8001' - } - }, - appengine: { - defaults: { - account: 'my-appengine-account', - editLoadBalancerStageEnabled: false - } - } - }, - whatsNew: { - gistId: '32526cd608db3d811b38', - fileName: 'news.md' - }, - notifications: { - email: { - enabled: true - }, - hipchat: { - enabled: true, - botName: 'Skynet T-800' - }, - sms: { - enabled: true - }, - slack: { - enabled: true, - botName: 'spinnakerbot' - } - }, - authEnabled: authEnabled, - authTtl: 600000, - gitSources: ['stash', 'github', 'bitbucket'], - triggerTypes: ['git', 'pipeline', 'docker', 'cron', 'jenkins'], - feature: { - entityTags: entityTagsEnabled, - fiatEnabled: fiatEnabled, - pipelines: true, - notifications: false, - fastProperty: true, - vpcMigrator: true, - clusterDiff: false, - roscoMode: false, - netflixMode: netflixMode, - chaosMonkey: chaosEnabled, - // whether stages affecting infrastructure (like "Create Load Balancer") should be enabled or not - infrastructureStages: process.env.INFRA_STAGES === 'enabled', - jobs: false, - snapshots: false - } -}; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(224))) - -/***/ }) - -},[3304]); \ No newline at end of file diff --git a/old/part5/spinnaker/ctop.yml b/old/part5/spinnaker/ctop.yml deleted file mode 100644 index f3fed0e9a..000000000 --- a/old/part5/spinnaker/ctop.yml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: ctop - labels: - app: ctop -spec: - ports: - - port: 2376 - targetPort: 2376 - selector: - app: ctop - tier: ctop - type: NodePort ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: ctop - labels: - app: ctop -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: ctop - tier: ctop - spec: - containers: - - image: chadmoon/docksock - name: ctop - securityContext: - privileged: true - ports: - - containerPort: 2376 - name: ctop diff --git a/old/part5/spinnaker/deck.yml b/old/part5/spinnaker/deck.yml deleted file mode 100644 index e202152ea..000000000 --- a/old/part5/spinnaker/deck.yml +++ /dev/null @@ -1,51 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: deck - labels: - app: deck -spec: - ports: - - port: 80 - targetPort: 9000 - selector: - app: deck - tier: deck - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: deck - labels: - app: deck -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: deck - tier: deck - spec: - containers: - - image: quay.io/spinnaker/deck:v2.1028.0 - name: deck - ports: - - containerPort: 9000 - name: deck - volumeMounts: - - name: spinnaker-config - mountPath: /settings.js - subPath: settings.js - - name: spinnaker-config - mountPath: /opt/deck/docker/run-apache2.sh - subPath: run-apache2.sh - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config - defaultMode: 0777 \ No newline at end of file diff --git a/old/part5/spinnaker/echo.yml b/old/part5/spinnaker/echo.yml deleted file mode 100644 index 1f8c6c6ac..000000000 --- a/old/part5/spinnaker/echo.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: echo - labels: - app: echo -spec: - ports: - - port: 8089 - targetPort: 8089 - selector: - app: echo - tier: echo - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: echo - labels: - app: echo -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: echo - tier: echo - spec: - containers: - - image: quay.io/spinnaker/echo:v1.132.0 - name: echo - ports: - - containerPort: 8089 - name: echo - volumeMounts: - - name: spinnaker-config - mountPath: /opt/echo/config - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/front50.yml b/old/part5/spinnaker/front50.yml deleted file mode 100644 index 39e42a307..000000000 --- a/old/part5/spinnaker/front50.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: front50 - labels: - app: front50 -spec: - ports: - - port: 8080 - targetPort: 8080 - selector: - app: front50 - tier: front50 - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: front50 - labels: - app: front50 -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: front50 - tier: front50 - spec: - containers: - - image: quay.io/spinnaker/front50:v1.69.0 - name: front50 - ports: - - containerPort: 8080 - name: front50 - volumeMounts: - - name: spinnaker-config - mountPath: /opt/front50/config - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/gate.yml b/old/part5/spinnaker/gate.yml deleted file mode 100644 index 63beedd51..000000000 --- a/old/part5/spinnaker/gate.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: gate - labels: - app: gate -spec: - ports: - - port: 8084 - targetPort: 8084 - selector: - app: gate - tier: gate - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: gate - labels: - app: gate -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: gate - tier: gate - spec: - containers: - - image: quay.io/spinnaker/gate:v3.1.0 - name: gate - ports: - - containerPort: 8084 - name: gate - volumeMounts: - - name: spinnaker-config - mountPath: /opt/gate/config - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/igor.yml b/old/part5/spinnaker/igor.yml deleted file mode 100644 index f97078c92..000000000 --- a/old/part5/spinnaker/igor.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: igor - labels: - app: igor -spec: - ports: - - port: 8088 - targetPort: 8088 - selector: - app: igor - tier: igor - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: igor - labels: - app: igor -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: igor - tier: igor - spec: - containers: - - image: quay.io/spinnaker/igor:v1.64.0 - name: igor - ports: - - containerPort: 8084 - name: igor - volumeMounts: - - name: spinnaker-config - mountPath: /opt/igor/config - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/ingress.yml b/old/part5/spinnaker/ingress.yml deleted file mode 100644 index 8108934ef..000000000 --- a/old/part5/spinnaker/ingress.yml +++ /dev/null @@ -1,71 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: ingress-services - namespace: spinnaker - annotations: - ingress.kubernetes.io/rewrite-target: / -spec: - backend: - serviceName: default-http-backend - servicePort: 80 - rules: - - host: front50.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: front50 - servicePort: 8080 - - - host: clouddriver.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: clouddriver - servicePort: 7002 - - - host: orca.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: orca - servicePort: 8083 - - - host: gate.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: gate - servicePort: 8084 - - - host: spinnaker.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: deck - servicePort: 80 - - path: /gate - backend: - serviceName: gate - servicePort: 8084 - - - host: igor.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: igor - servicePort: 8088 - - - host: echo.MINIKUBE_IP.xip.io - http: - paths: - - path: / - backend: - serviceName: echo - servicePort: 8089 diff --git a/old/part5/spinnaker/install.sh b/old/part5/spinnaker/install.sh deleted file mode 100755 index dfd715a45..000000000 --- a/old/part5/spinnaker/install.sh +++ /dev/null @@ -1,11 +0,0 @@ -./rollout.sh redis -./rollout.sh front50 -./rollout.sh clouddriver -./rollout.sh orca -./rollout.sh gate -./rollout.sh deck -./rollout.sh igor - -#IP=`minikube ip` - -#sed 's#MINIKUBE_IP#'$IP'#' ingress.yml | kubectl apply -f - \ No newline at end of file diff --git a/old/part5/spinnaker/ksh.sh b/old/part5/spinnaker/ksh.sh deleted file mode 100755 index 74328c75d..000000000 --- a/old/part5/spinnaker/ksh.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -if [ "$1" = "" ]; then - echo "Usage: ksh [flags_to_kubectl]" - exit 1 -fi -POD=$1 -shift - -COLUMNS=`tput cols` -LINES=`tput lines` -TERM=xterm -KUBE_SHELL=${KUBE_SHELL:-bash} -kubectl exec -i -t $POD "$@" -- env COLUMNS=$COLUMNS LINES=$LINES TERM=$TERM "$KUBE_SHELL" \ No newline at end of file diff --git a/old/part5/spinnaker/namespace.yml b/old/part5/spinnaker/namespace.yml deleted file mode 100644 index 05a0209e2..000000000 --- a/old/part5/spinnaker/namespace.yml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: spinnaker \ No newline at end of file diff --git a/old/part5/spinnaker/orca.yml b/old/part5/spinnaker/orca.yml deleted file mode 100644 index 32f69c444..000000000 --- a/old/part5/spinnaker/orca.yml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: orca - labels: - app: orca -spec: - ports: - - port: 8083 - targetPort: 8083 - selector: - app: orca - tier: orca - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: orca - labels: - app: orca -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: orca - tier: orca - spec: - containers: - - image: quay.io/spinnaker/orca:v1.304.0 - name: orca - ports: - - containerPort: 8083 - name: orca - volumeMounts: - - name: spinnaker-config - mountPath: /opt/orca/config - volumes: - - name: spinnaker-config - configMap: - name: spinnaker-config \ No newline at end of file diff --git a/old/part5/spinnaker/redis.yml b/old/part5/spinnaker/redis.yml deleted file mode 100644 index fef3fa23b..000000000 --- a/old/part5/spinnaker/redis.yml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: spinnaker - name: redis - labels: - app: redis -spec: - ports: - - port: 6379 - selector: - app: redis - tier: redis - type: NodePort - ---- -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - namespace: spinnaker - name: redis - labels: - app: redis -spec: - strategy: - type: Recreate - template: - metadata: - labels: - app: redis - tier: redis - spec: - containers: - - image: redis:latest - name: redis - ports: - - containerPort: 6379 - name: redis \ No newline at end of file diff --git a/old/part5/spinnaker/rollout.sh b/old/part5/spinnaker/rollout.sh deleted file mode 100755 index 0ec4c93fa..000000000 --- a/old/part5/spinnaker/rollout.sh +++ /dev/null @@ -1,10 +0,0 @@ -./apply-config.sh -kubectl --namespace spinnaker delete -f $1.yml - -kubectl --namespace spinnaker apply -f $1.yml -kubectl --namespace spinnaker rollout status deployment/$1 - - -IP=`minikube ip` - -#sed 's#MINIKUBE_IP#'$IP'#' ingress.yml | kubectl apply -f - \ No newline at end of file diff --git a/steps.yml b/steps.yml deleted file mode 100644 index 01916976a..000000000 --- a/steps.yml +++ /dev/null @@ -1,213 +0,0 @@ -parts: - - - name: Part 1 - intro: In this part we will setup a local cluster with minikube, deploy a public image from dockerhub, customize that image, and then finally deploy it inside our local cluster. - steps: - - - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources. - com: minikube start --memory 8000 --cpus 2 - - - cap: Enable the Minikube add-ons Heapster and Ingress. - com: minikube addons enable heapster; minikube addons enable ingress - - - cap: Wait 20 seconds, and then view the Minikube Dashboard, a web UI for managing deployments. - com: sleep 20; minikube service kubernetes-dashboard --namespace kube-system - - - cap: Deploy the public nginx image from DockerHub into a pod. Nginx is an open source web server that will automatically download from Docker Hub if it’s not available locally. - com: kubectl run nginx --image nginx --port 80 - - - cap: Create a service for deployment. This will expose the nginx pod so you can access it with a web browser. - com: kubectl expose deployment nginx --type NodePort --port 80 - - - cap: Launch a web browser to test the service. The nginx welcome page displays, which means the service is up and running. - com: minikube service nginx - - - cap: Set up the cluster registry by applying a .yml manifest file. - com: kubectl apply -f manifests/registry.yml - - - cap: Wait for the registry to finish deploying. Note that this may take several minutes. - com: kubectl rollout status deployments/registry - - - cap: View the registry user interface in a web browser. - com: minikube service registry-ui - - - cap: Let’s make a change to an HTML file in the cloned project. Running the command below will open /applications/hello-kenzan/index.html in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. - com: nano applications/hello-kenzan/index.html - - - cap: Now let’s build an image, giving it a special name that points to our local cluster registry. - com: docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan - - - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" - - - cap: With our proxy container up and running, we can now push our image to the local repository. - com: docker push 127.0.0.1:30400/hello-kenzan:latest - - - cap: The proxy’s work is done, so you can go ahead and stop it. - com: docker stop socat-registry; - - - cap: With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan pod based on the image. - com: kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml - - - cap: Launch a web browser and view the service. - com: minikube service hello-kenzan - - - name: Part 2 - intro: In this part we will Setup Jenkins, and setup an automated pipeline to build, push and deploy our custom appliction. - steps: - - - cap: Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. - com: kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins - - - cap: Open the Jenkins UI in a web browser. - com: minikube service jenkins - - - cap: Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT. - com: kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /root/.jenkins/secrets/initialAdminPassword - - - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins and wait for the process to complete. - com: echo '' - - - cap: Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. - com: echo '' - - - cap: We now want to create a new pipeline for use with our Hello-Kenzan app. On the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. - com: echo '' - - - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". - com: echo '' - - - cap: Change the SCM to Git. - com: echo '' - - - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. - com: echo '' - - - cap: Now view the Hello-Kenzan application. - com: minikube service hello-kenzan - - - cap: Push a change to your fork. Run job again. View the changes. - com: minikube service hello-kenzan - - - name: Part 3 - intro: This part will have us setup the various applications that will present the crossword puzzle. We will run a sample etcd cluster as a cache, a pages application containing the front-end, a crossword server using mongodb, and a monitoring and scaling server application. - steps: - - - cap: Start the etcd operator and service on the cluster. You may notice errors showing up as it is waiting to start up the cluster. This is normal until it starts. - com: scripts/etcd.sh - - - cap: Now that we have an etcd service, we need an etcd client. The following command will set up a directory within etcd for storing key-value pairs, and then run the etcd client. - com: kubectl create -f manifests/etcd-job.yml - - - cap: Check the status of the job in step 2 to make sure it deployed. - com: kubectl describe jobs/etcd-job - - - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. - com: kubectl apply -f manifests/all-services.yml - - - cap: Now we're going to walk through an initial build of the monitor-scale service. - com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale - - - cap: Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" - - - cap: Push the monitor-scale image to the registry. - com: docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` - - - cap: The proxy’s work is done, so go ahead and stop it. - com: docker stop socat-registry - - - cap: Open the registry UI and verify that the monitor-scale image is in our local registry. - com: minikube service registry-ui - - - cap: Create the monitor-scale deployment and service. - com: sed 's#127.0.0.1:30400/monitor-scale:latest#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - - - - cap: Wait for the monitor-scale deployment to finish. - com: kubectl rollout status deployment/monitor-scale - - - cap: View pods to see the monitor-scale pod running. - com: kubectl get pods - - - cap: View services to see the monitor-scale service. - com: kubectl get services - - - cap: View ingress rules to see the monitor-scale ingress rule. - com: kubectl get ingress - - - cap: View deployments to see the monitor-scale deployment. - com: kubectl get deployments - - - cap: We will run a script to bootstrap the puzzle and mongo services, creating Docker images and storing them in the local registry. The puzzle.sh script runs through the same build, proxy, push, and deploy steps we just ran through manually for both services. - com: scripts/puzzle.sh - - - cap: Check to see if the puzzle and mongo services have been deployed. - com: kubectl rollout status deployment/puzzle - - - cap: Bootstrap the kr8sswordz frontend web application. This script follows the same build proxy, push, and deploy steps that the other services followed. - com: scripts/kr8sswordz-pages.sh - - - cap: Check to see if the frontend has been deployed. - com: kubectl rollout status deployment/kr8sswordz - - - cap: Check out all the pods that are running. - com: kubectl get pods - - - cap: Start the web application in your default browser. You may have to refresh your browser so that the puzzle appears properly. - com: minikube service kr8sswordz - - - name: Part 4 - intro: In this part we will return to our Jenkins instance and setup a pipeline for the kr8sswordz application. - steps: - - - cap: Enter the following command to open the Jenkins UI in a web browser. Log in to Jenkins using the username and password you previously set up. - com: minikube service jenkins - - - cap: We’ll want to create a new pipeline for the puzzle service that we previously deployed. On the left in Jenkins, click New Item. - com: echo '' - - - cap: Enter the item name as "Puzzle-Service", click Pipeline, and click OK. - com: echo '' - - - cap: Under the Build Triggers section, select Poll SCM. For the Schedule, enter the the string H/5 * * * * which will poll the Git repo every 5 minutes for changes. - com: echo '' - - - cap: In the Pipeline section, change the Definition to "Pipeline script from SCM". Set the SCM property to GIT. Set the Repository URL to your forked repo (created in Part 2), such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd.git. Set the Script Path to applications/puzzle/Jenkinsfile - com: echo '' - - - cap: When you are finished, click Save. On the left, click Build Now to run the new pipeline. You should see it successfully run through the build, push, and deploy steps in a few minutes. - com: echo '' - - - cap: View the Kr8sswordz application. - com: minikube service kr8sswordz - - - cap: Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. - com: echo '' - - - cap: Edit applications/puzzle/common/models/crossword.js in the nano editor. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. Press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. - com: nano applications/puzzle/common/models/crossword.js - - - cap: Commit and push the change to your forked Git repo. - com: echo '' - - - cap: In Jenkins, open up the Puzzle-Service pipeline and wait until it triggers a build. It should trigger every 5 minutes. - com: echo '' - - - cap: After it triggers, observe how the puzzle services disappear in the Kr8sswordz Puzzle app, and how new ones take their place. - com: echo '' - - - cap: Try clicking Submit to test that hits now register as light green. - com: echo '' - - # - name: Part 5 - # intro: Spinnaker - # steps: - - # - cap: Initialize Helm - # com: helm init; sleep 10; kubectl --namespace kube-system rollout status deployment/tiller-deploy - - # - cap: Install Chart - # com: helm install --name spinnaker applications/spinnaker-helm/spinnaker-chart - - # - cap: Launch Deck - # com: minikube service deck \ No newline at end of file From 75ad99487db2c756bfeb2ea59406574ca3ca04c4 Mon Sep 17 00:00:00 2001 From: Mason Traylor Date: Mon, 12 Jun 2017 11:37:53 -0600 Subject: [PATCH 06/89] updated readme.js --- README.md | 34 +++++++++------------------------- readme.js | 5 ++--- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index ed4a9730f..367977f48 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan -[Linux.com Part 1](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview) - -[Linux.com Part 2](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/6/set-cicd-pipeline-jenkins-pod-kubernetes-part-2) - To generate this readme: `node readme.js` ## Interactive Tutorial Version @@ -30,18 +26,15 @@ Begin the desired section: To complete the tutorial manually, follow the steps below. -## Part 1 - - -### Part 1 +## Part 1 #### Step1 Start up the Kubernetes cluster with Minikube, giving it some extra resources. -`minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0` +`minikube start --memory 8000 --cpus 2` #### Step2 @@ -131,12 +124,9 @@ With the image in our cluster registry, the last thing to do is apply the manife Launch a web browser and view the service. -`minikube service hello-kenzan`## Part 2 - - -### Part 2 - +`minikube service hello-kenzan` +## Part 2 #### Step1 @@ -202,12 +192,9 @@ Now view the Hello-Kenzan application. Push a change to your fork. Run job again. View the changes. -`minikube service hello-kenzan`## Part 3 - - -### Part 3 - +`minikube service hello-kenzan` +## Part 3 #### Step1 @@ -333,12 +320,9 @@ Check out all the pods that are running. Start the web application in your default browser. You may have to refresh your browser so that the puzzle appears properly. -`minikube service kr8sswordz`## Part 4 - - -### Part 4 - +`minikube service kr8sswordz` +## Part 4 #### Step1 @@ -416,4 +400,4 @@ After it triggers, observe how the puzzle services disappear in the Kr8sswordz P Try clicking Submit to test that hits now register as light green. -`echo ''` +`echo ''` \ No newline at end of file diff --git a/readme.js b/readme.js index 3c2da408e..ff9f4a0b7 100755 --- a/readme.js +++ b/readme.js @@ -24,13 +24,12 @@ YAML.load('steps.yml', function(docs) var parts = docs.parts; parts.forEach(function (item) { - markdown = markdown + "## " + item.name + "\n" var part = item.name; - markdown = markdown + "\n\n### " + item.name + "\n\n" var stepNum = 0; var stepList = item.steps; + + markdown = markdown + "\n\n## " + part; - // console.log(item.steps); stepList.forEach(function (step) { stepNum++; markdown = markdown + "\n\n#### Step" + stepNum From f0410cb6d2789a39d367e65951d1dc7b6c29dff2 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Thu, 15 Jun 2017 14:24:02 -0600 Subject: [PATCH 07/89] Added Part 3 link to README, some other text for intro --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ed4a9730f..eb047542c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan +The kubernetes-ci-cd project is [Kenzan's](http://techblog.kenzan.com/) crossword puzzle application that runs as several containers in Kubernetes (we call it the Kr8sswordz Puzzle). It showcases Kubernetes features like spinning up multiple pods and running a load test at scale. It also features Jenkins running on its own a container and a JenkinsFile script to demonstrate how Kubernetes can be integrated into a full CI/CD pipeline. + +To get it up and running, see the following week-by-week Linux.com blog posts, or simply follow the directions below. + [Linux.com Part 1](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview) [Linux.com Part 2](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/6/set-cicd-pipeline-jenkins-pod-kubernetes-part-2) - To generate this readme: `node readme.js` +[Linux.com Part 3](https://www.linux.com/blog/learn/chapter/intro-to-kubernetes/2017/6/run-and-scale-distributed-crossword-puzzle-app-cicd-kubernetes-part-3) + +To generate this readme: `node readme.js` ## Interactive Tutorial Version To complete the tutorial using the interactive script: @@ -28,10 +34,7 @@ Begin the desired section: ## Manual Tutorial Version - To complete the tutorial manually, follow the steps below. -## Part 1 - ### Part 1 From 703f8d27fe7f1a76d7cab70b3d2f4305bd3d39b0 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 23 Jun 2017 15:28:43 -0600 Subject: [PATCH 08/89] Change nano wording for scripts --- README.md | 4 ++-- part1.yml | 2 +- part4.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 87423285e..e81f360ff 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ View the registry user interface in a web browser. #### Step10 -Let’s make a change to an HTML file in the cloned project. Running the command below will open /applications/hello-kenzan/index.html in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. +Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor, or run the command below to open it in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. `nano applications/hello-kenzan/index.html` @@ -383,7 +383,7 @@ Spin up several instances of the puzzle service by moving the slider to the righ #### Step9 -Edit applications/puzzle/common/models/crossword.js in the nano editor. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. Press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. +Edit applications/puzzle/common/models/crossword.js in your favorite text editor, or edit it in nano using the command below. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. To save in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. `nano applications/puzzle/common/models/crossword.js` diff --git a/part1.yml b/part1.yml index 408fdb33f..40f1023cc 100644 --- a/part1.yml +++ b/part1.yml @@ -31,7 +31,7 @@ parts: - cap: View the registry user interface in a web browser. com: minikube service registry-ui - - cap: Let’s make a change to an HTML file in the cloned project. Running the command below will open /applications/hello-kenzan/index.html in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. + - cap: Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor, or run the command below to open it in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. com: nano applications/hello-kenzan/index.html - cap: Now let’s build an image, giving it a special name that points to our local cluster registry. diff --git a/part4.yml b/part4.yml index d191a9364..e6728ed60 100644 --- a/part4.yml +++ b/part4.yml @@ -28,7 +28,7 @@ parts: - cap: Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. com: echo '' - - cap: Edit applications/puzzle/common/models/crossword.js in the nano editor. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. Press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. + - cap: Edit applications/puzzle/common/models/crossword.js in your favorite text editor, or edit it in nano using the command below. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. To save in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. com: nano applications/puzzle/common/models/crossword.js - cap: Commit and push the change to your forked Git repo. From 6c68964fb81ed6d3bd1e8148b0ad1ef3d95533ac Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 23 Jun 2017 16:40:51 -0600 Subject: [PATCH 09/89] More changes for nano commands to scripts --- README.md | 8 ++++---- part1.yml | 4 ++-- part4.yml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e81f360ff..2e7c6020b 100644 --- a/README.md +++ b/README.md @@ -95,9 +95,9 @@ View the registry user interface in a web browser. #### Step10 -Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor, or run the command below to open it in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. +Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor (for example, you can use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. -`nano applications/hello-kenzan/index.html` +`echo ''` #### Step11 @@ -383,9 +383,9 @@ Spin up several instances of the puzzle service by moving the slider to the righ #### Step9 -Edit applications/puzzle/common/models/crossword.js in your favorite text editor, or edit it in nano using the command below. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. To save in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. +Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. -`nano applications/puzzle/common/models/crossword.js` +`echo ''` #### Step10 diff --git a/part1.yml b/part1.yml index 40f1023cc..b8a44cdd4 100644 --- a/part1.yml +++ b/part1.yml @@ -31,8 +31,8 @@ parts: - cap: View the registry user interface in a web browser. com: minikube service registry-ui - - cap: Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor, or run the command below to open it in the nano text editor. Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. When you’re done in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. - com: nano applications/hello-kenzan/index.html + - cap: Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor (for example, you can use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. + com: echo '' - cap: Now let’s build an image, giving it a special name that points to our local cluster registry. com: docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan diff --git a/part4.yml b/part4.yml index e6728ed60..49c110512 100644 --- a/part4.yml +++ b/part4.yml @@ -28,8 +28,8 @@ parts: - cap: Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. com: echo '' - - cap: Edit applications/puzzle/common/models/crossword.js in your favorite text editor, or edit it in nano using the command below. You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes. To save in nano, press Ctrl+X to close the file, type Y to confirm the filename, and press Enter to write the changes to the file. - com: nano applications/puzzle/common/models/crossword.js + - cap: Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. + com: echo '' - cap: Commit and push the change to your forked Git repo. com: echo '' From 7cc73f42c7061bfbdbb83f72414fec716b7d3adb Mon Sep 17 00:00:00 2001 From: Patrick McCarty Date: Wed, 5 Jul 2017 15:10:52 -0400 Subject: [PATCH 10/89] Issue 25 add apache 2 license 1 (#28) * Add LICENSE.md * Issue-25: update README.md and LICENSE.md --- LICENSE.md | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 17 ++++- 2 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..572a1e9ca --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Kenzan, LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 2e7c6020b..b3cab8d5e 100644 --- a/README.md +++ b/README.md @@ -409,4 +409,19 @@ After it triggers, observe how the puzzle services disappear in the Kr8sswordz P Try clicking Submit to test that hits now register as light green. -`echo ''` \ No newline at end of file +`echo ''` + + ## LICENSE +Copyright 2017 Kenzan, LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file From 203314ee9a84f6cd5905fe2ae38a63286bd27d6a Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 4 Aug 2017 10:44:02 -0600 Subject: [PATCH 11/89] Added part 4 link to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b3cab8d5e..fa94349e7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ To get it up and running, see the following week-by-week Linux.com blog posts, o [Linux.com Part 3](https://www.linux.com/blog/learn/chapter/intro-to-kubernetes/2017/6/run-and-scale-distributed-crossword-puzzle-app-cicd-kubernetes-part-3) +[Linux.com Part 4](https://www.linux.com/blog/learn/chapter/intro-to-kubernetes/2017/6/set-cicd-distributed-crossword-puzzle-app-kubernetes-part-4) + To generate this readme: `node readme.js` ## Interactive Tutorial Version From c3f48a47048385fa9a6390cb4e8218c015b549c7 Mon Sep 17 00:00:00 2001 From: Chad Moon Date: Thu, 10 Aug 2017 11:42:53 -0600 Subject: [PATCH 12/89] save tpr resources to repo --- manifests/deployment.yaml | 23 +++++++++++++++++++++++ manifests/example-etcd-cluster.yaml | 7 +++++++ manifests/service.json | 22 ++++++++++++++++++++++ scripts/etcd-crd.sh | 27 +++++++++++++++++++++++++++ scripts/etcd.sh | 8 ++++---- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 manifests/deployment.yaml create mode 100644 manifests/example-etcd-cluster.yaml create mode 100644 manifests/service.json create mode 100755 scripts/etcd-crd.sh diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml new file mode 100644 index 000000000..41fceed19 --- /dev/null +++ b/manifests/deployment.yaml @@ -0,0 +1,23 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: etcd-operator +spec: + replicas: 1 + template: + metadata: + labels: + name: etcd-operator + spec: + containers: + - name: etcd-operator + image: quay.io/coreos/etcd-operator:v0.4.2 + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name \ No newline at end of file diff --git a/manifests/example-etcd-cluster.yaml b/manifests/example-etcd-cluster.yaml new file mode 100644 index 000000000..28dc4ad01 --- /dev/null +++ b/manifests/example-etcd-cluster.yaml @@ -0,0 +1,7 @@ +apiVersion: "etcd.coreos.com/v1beta1" +kind: "Cluster" +metadata: + name: "example-etcd-cluster" +spec: + size: 3 + version: "3.1.8" \ No newline at end of file diff --git a/manifests/service.json b/manifests/service.json new file mode 100644 index 000000000..1f5c3c438 --- /dev/null +++ b/manifests/service.json @@ -0,0 +1,22 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "example-etcd-cluster-client-service" + }, + "spec": { + "selector": { + "etcd_cluster": "example-etcd-cluster", + "app": "etcd" + }, + "ports": [ + { + "protocol": "TCP", + "port": 2379, + "targetPort": 2379, + "nodePort": 32379 + } + ], + "type": "NodePort" + } +} \ No newline at end of file diff --git a/scripts/etcd-crd.sh b/scripts/etcd-crd.sh new file mode 100755 index 000000000..ee2b163d5 --- /dev/null +++ b/scripts/etcd-crd.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +echo "installing etcd operator" +kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml +kubectl rollout status -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml + +until kubectl get thirdpartyresource cluster.etcd.coreos.com +do + echo "waiting for operator" + sleep 2 +done + +echo "pausing for 10 seconds for operator to settle" +sleep 10 + +kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster.yaml + +echo "installing etcd cluster service" +kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster-nodeport-service.json + +echo "waiting for etcd cluster to turnup" + +until kubectl get pod example-etcd-cluster-0002 +do + echo "waiting for etcd cluster to turnup" + sleep 2 +done diff --git a/scripts/etcd.sh b/scripts/etcd.sh index ee2b163d5..f03fd5d96 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash echo "installing etcd operator" -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml -kubectl rollout status -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/deployment.yaml +kubectl create -f manifests/deployment.yaml +kubectl rollout status -f manifests/deployment.yaml until kubectl get thirdpartyresource cluster.etcd.coreos.com do @@ -13,10 +13,10 @@ done echo "pausing for 10 seconds for operator to settle" sleep 10 -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster.yaml +kubectl create -f manifests/example-etcd-cluster.yaml echo "installing etcd cluster service" -kubectl create -f https://raw.githubusercontent.com/coreos/etcd-operator/master/example/example-etcd-cluster-nodeport-service.json +kubectl create -f manifests/service.json echo "waiting for etcd cluster to turnup" From 2060de4608397ef567b96e5a37c0134f221c1f73 Mon Sep 17 00:00:00 2001 From: s7aesis Date: Mon, 7 May 2018 16:37:49 -0400 Subject: [PATCH 13/89] Updating etcd cluster --- manifests/deployment.yaml | 8 ++++++-- manifests/example-etcd-cluster.yaml | 11 ++++++++--- scripts/etcd.sh | 13 +------------ 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml index 41fceed19..f355504d1 100644 --- a/manifests/deployment.yaml +++ b/manifests/deployment.yaml @@ -11,7 +11,11 @@ spec: spec: containers: - name: etcd-operator - image: quay.io/coreos/etcd-operator:v0.4.2 + image: quay.io/coreos/etcd-operator:v0.9.2 + command: + - etcd-operator + # Uncomment to act for resources in all namespaces. More information in doc/clusterwide.md + #- -cluster-wide env: - name: MY_POD_NAMESPACE valueFrom: @@ -20,4 +24,4 @@ spec: - name: MY_POD_NAME valueFrom: fieldRef: - fieldPath: metadata.name \ No newline at end of file + fieldPath: metadata.name diff --git a/manifests/example-etcd-cluster.yaml b/manifests/example-etcd-cluster.yaml index 28dc4ad01..262f7af20 100644 --- a/manifests/example-etcd-cluster.yaml +++ b/manifests/example-etcd-cluster.yaml @@ -1,7 +1,12 @@ -apiVersion: "etcd.coreos.com/v1beta1" -kind: "Cluster" +apiVersion: "etcd.database.coreos.com/v1beta2" +kind: "EtcdCluster" metadata: name: "example-etcd-cluster" + ## Adding this annotation make this cluster managed by clusterwide operators + ## namespaced operators ignore it + # annotations: + # etcd.database.coreos.com/scope: clusterwide spec: size: 3 - version: "3.1.8" \ No newline at end of file + version: "3.2.13" + diff --git a/scripts/etcd.sh b/scripts/etcd.sh index f03fd5d96..cfd859683 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -4,12 +4,6 @@ echo "installing etcd operator" kubectl create -f manifests/deployment.yaml kubectl rollout status -f manifests/deployment.yaml -until kubectl get thirdpartyresource cluster.etcd.coreos.com -do - echo "waiting for operator" - sleep 2 -done - echo "pausing for 10 seconds for operator to settle" sleep 10 @@ -19,9 +13,4 @@ echo "installing etcd cluster service" kubectl create -f manifests/service.json echo "waiting for etcd cluster to turnup" - -until kubectl get pod example-etcd-cluster-0002 -do - echo "waiting for etcd cluster to turnup" - sleep 2 -done +sleep 10 From 21778f146fb578f424d2de1f58896c08d48c53e1 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 3 Jul 2018 09:16:19 -0600 Subject: [PATCH 14/89] change in hello-kenzan index --- applications/hello-kenzan/index.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/applications/hello-kenzan/index.html b/applications/hello-kenzan/index.html index 1e9046561..72acc2f9c 100644 --- a/applications/hello-kenzan/index.html +++ b/applications/hello-kenzan/index.html @@ -1,3 +1,10 @@ +<<<<<<< Updated upstream

Hello from Kenzan! You've successfully built and run the Hello-Kenzan app.

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

+======= +

HELLO FROM MINIKUBE!

+

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, + you will note several things:

+>>>>>>> Stashed changes From ca0a0470afdf10389ed777e22590f7ad700d5fb3 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 3 Jul 2018 09:27:40 -0600 Subject: [PATCH 15/89] conflict --- applications/hello-kenzan/index.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/applications/hello-kenzan/index.html b/applications/hello-kenzan/index.html index 72acc2f9c..25ac4b4ca 100644 --- a/applications/hello-kenzan/index.html +++ b/applications/hello-kenzan/index.html @@ -1,10 +1,6 @@ -<<<<<<< Updated upstream -

Hello from Kenzan! You've successfully built and run the Hello-Kenzan app.

-

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

-======= +

HELLO FROM MINIKUBE!

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

->>>>>>> Stashed changes From bbc27c2ea73d610eced690b76ff96d91df0423d8 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 19 Jul 2018 15:11:26 -0600 Subject: [PATCH 16/89] Enabled hit highlighting on Submit --- applications/puzzle/common/models/crossword.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/puzzle/common/models/crossword.js b/applications/puzzle/common/models/crossword.js index 096880f6e..0efcd0817 100644 --- a/applications/puzzle/common/models/crossword.js +++ b/applications/puzzle/common/models/crossword.js @@ -7,9 +7,9 @@ module.exports = function(Crossword) { var etcd = new Etcd("http://example-etcd-cluster-client-service:2379"); fireHit(); Crossword.get = function(cb) { - + var etcdPuzzleResp = etcd.getSync("puzzle"); - + if (etcdPuzzleResp && !etcdPuzzleResp.err) { console.log(`Responding with cache`); @@ -38,9 +38,9 @@ module.exports = function(Crossword) { if(words) { etcd.delSync("puzzle"); Crossword.findOne(function (err, crossword) { - + // Part 4: Uncomment the next line to enable puzzle pod highlighting when clicking the Submit button - //fireHit(); + fireHit(); if (err) handleError(err.message, cb); for (var j = 0; j < words.length; j++) { var word = words[j]; @@ -64,10 +64,10 @@ module.exports = function(Crossword) { } Crossword.clear = function(cb) { - + Crossword.findOne(function(err, crossword) { console.log("Calling hit from clear."); - fireHit(); + fireHit(); if(err) handleError(err.message, cb); var updatedWords = []; for (var i = 0; i < crossword.words.length; i++) { From 5c69d27bfe4c2b69d199f72b0dbefe4226a89062 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Wed, 25 Jul 2018 11:42:53 -0600 Subject: [PATCH 17/89] gitignore idea folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0aebdcff5..f39167562 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store .vscode +.idea node_modules node_modules/ node_modules/* \ No newline at end of file From e833be09fb5d7e4bbda5c0355dde295e2b1840ac Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 2 Aug 2018 10:10:44 -0600 Subject: [PATCH 18/89] error handling on monitor-scale app for scale endpoint --- applications/monitor-scale/index.js | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/applications/monitor-scale/index.js b/applications/monitor-scale/index.js index c21db390a..8b326d336 100644 --- a/applications/monitor-scale/index.js +++ b/applications/monitor-scale/index.js @@ -1,15 +1,14 @@ -var express = require('express') -var app = express() - +var express = require('express'); +var app = express(); var http = require('http').Server(app); var request = require('request'); var async = require('async'); var io = require('socket.io')(http); -var path = require("path"); -var Etcd = require('node-etcd') +var path = require("path"); +var Etcd = require('node-etcd'); var cors = require('cors'); -app.use(express.static('public')) +app.use(express.static('public')); var bodyParser = require("body-parser"); @@ -17,9 +16,9 @@ app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(cors()); -etcd = new Etcd("http://example-etcd-cluster-client-service:2379") +etcd = new Etcd("http://example-etcd-cluster-client-service:2379"); -var watcher = etcd.watcher("pod-list", null, {recursive: true}) +var watcher = etcd.watcher("pod-list", null, {recursive: true}); watcher.on("change", function(val) { var podChange = { pods: val.node.key, action: val.action }; @@ -27,7 +26,7 @@ watcher.on("change", function(val) { io.emit('pods', podChange); }); -app.post('/scale', function (req, res) { +app.post('/scale', function (req, res, next) { var scale = req.body.count; console.log('Count requested is: %s', scale); var url = "http://127.0.0.1:2345/apis/extensions/v1beta1/namespaces/default/deployments/puzzle/scale"; @@ -47,10 +46,11 @@ app.post('/scale', function (req, res) { request({ url: url, method: 'PUT', json: putBody}, function (err, httpResponse, body) { if (err) { - return console.error('Failed to scale:', err); + console.error('Failed to scale:', err); + next(err); } - console.log('Scale success!'); - res.send('success'); + console.log('Response: ' + JSON.stringify(httpResponse)); + res.status(httpResponse.statusCode).json(body); }); }); @@ -104,13 +104,13 @@ app.get('/up/:podId', function (req, res) { console.log('Server UP: %s', req.params.podId); etcd.setSync("pod-list/" + req.params.podId, req.params.podId); res.send('up done'); -}) +}); app.get('/down/:podId', function (req, res) { console.log('Server DOWN: %s', req.params.podId); etcd.delSync("pod-list/" + req.params.podId, req.params.podId); res.send('down done'); -}) +}); app.get('/hit/:podId', function (req, res) { @@ -120,19 +120,19 @@ app.get('/hit/:podId', function (req, res) { console.log("Emitting hit from %s", req.params.podId); io.emit('hit', { podId: req.params.podId, time: n }); res.send('hit done') -}) +}); app.get('/pods', function (req, res) { var pods = etcd.getSync("pod-list",{ recursive: true }); res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify({pods: pods.body.node.nodes})); -}) +}); app.delete('/pods', function (req, res) { var pods = etcd.delSync("pod-list/",{ recursive: true }); res.send('pods deleted') -}) +}); io.on('connection', function(socket){ From 2203b72bd51bfa2d26f76af7df98c76bc8fb2122 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 2 Aug 2018 12:43:04 -0600 Subject: [PATCH 19/89] replaced etcd job with in-application etcd dir creation, renamed files and updated scripts --- applications/monitor-scale/index.js | 3 ++- ...mple-etcd-cluster.yaml => etcd-cluster.yaml} | 0 manifests/etcd-job.yml | 17 ----------------- part3.yml | 6 ------ scripts/etcd.sh | 2 +- 5 files changed, 3 insertions(+), 25 deletions(-) rename manifests/{example-etcd-cluster.yaml => etcd-cluster.yaml} (100%) delete mode 100644 manifests/etcd-job.yml diff --git a/applications/monitor-scale/index.js b/applications/monitor-scale/index.js index c21db390a..edf751737 100644 --- a/applications/monitor-scale/index.js +++ b/applications/monitor-scale/index.js @@ -17,7 +17,8 @@ app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.use(cors()); -etcd = new Etcd("http://example-etcd-cluster-client-service:2379") +etcd = new Etcd("http://example-etcd-cluster-client-service:2379"); +etcd.mkdirSync('pod-list'); var watcher = etcd.watcher("pod-list", null, {recursive: true}) watcher.on("change", function(val) { diff --git a/manifests/example-etcd-cluster.yaml b/manifests/etcd-cluster.yaml similarity index 100% rename from manifests/example-etcd-cluster.yaml rename to manifests/etcd-cluster.yaml diff --git a/manifests/etcd-job.yml b/manifests/etcd-job.yml deleted file mode 100644 index 79f2e6b49..000000000 --- a/manifests/etcd-job.yml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: etcd-job -spec: - template: - metadata: - name: etcd-job - spec: - containers: - - name: etcd-job - image: tenstartups/etcdctl - env: - - name: ETCDCTL_ENDPOINT - value: 'http://example-etcd-cluster-client-service:2379' - command: ["etcdctl", "mkdir", "pod-list"] - restartPolicy: Never \ No newline at end of file diff --git a/part3.yml b/part3.yml index 35a716eae..ab5c19796 100644 --- a/part3.yml +++ b/part3.yml @@ -6,12 +6,6 @@ parts: - cap: Start the etcd operator and service on the cluster. You may notice errors showing up as it is waiting to start up the cluster. This is normal until it starts. com: scripts/etcd.sh - - - cap: Now that we have an etcd service, we need an etcd client. The following command will set up a directory within etcd for storing key-value pairs, and then run the etcd client. - com: kubectl create -f manifests/etcd-job.yml - - - cap: Check the status of the job in step 2 to make sure it deployed. - com: kubectl describe jobs/etcd-job - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. com: kubectl apply -f manifests/all-services.yml diff --git a/scripts/etcd.sh b/scripts/etcd.sh index cfd859683..51e088873 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -7,7 +7,7 @@ kubectl rollout status -f manifests/deployment.yaml echo "pausing for 10 seconds for operator to settle" sleep 10 -kubectl create -f manifests/example-etcd-cluster.yaml +kubectl create -f manifests/etcd-cluster.yaml echo "installing etcd cluster service" kubectl create -f manifests/service.json From 5df1618472b2f03c84e552b2172ff510f2f718cd Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 3 Aug 2018 16:00:10 -0600 Subject: [PATCH 20/89] socat service definition added to applications --- applications/socat/Dockerfile | 6 ++++++ applications/socat/entrypoint.sh | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 applications/socat/Dockerfile create mode 100644 applications/socat/entrypoint.sh diff --git a/applications/socat/Dockerfile b/applications/socat/Dockerfile new file mode 100644 index 000000000..f5b789511 --- /dev/null +++ b/applications/socat/Dockerfile @@ -0,0 +1,6 @@ +FROM alpine:latest +#USER root +#Installing socat +RUN apk update && apk upgrade && apk add bash socat +COPY entrypoint.sh entrypoint.sh +ENTRYPOINT ["sh", "./entrypoint.sh"] \ No newline at end of file diff --git a/applications/socat/entrypoint.sh b/applications/socat/entrypoint.sh new file mode 100644 index 000000000..f6f7ecbca --- /dev/null +++ b/applications/socat/entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:$REG_IP:$REG_PORT From 5fdf0be8d9d85f208f81f1f520d8d2c9dc6cbc29 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 6 Aug 2018 11:02:27 -0600 Subject: [PATCH 21/89] provided jenkins Dockerfile and updated jenkins manifest --- applications/jenkins/Dockerfile | 15 +++++++++++++++ manifests/jenkins.yml | 16 ++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 applications/jenkins/Dockerfile diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile new file mode 100644 index 000000000..27ea2123f --- /dev/null +++ b/applications/jenkins/Dockerfile @@ -0,0 +1,15 @@ +FROM jenkins/jenkins:latest +USER root +#Installing Docker +RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ +curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -;\ +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable";\ +apt-get update && apt-get install docker-ce -y + +#Installing kubectl from Docker +#RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ +#touch /etc/apt/sources.list.d/kubernetes.list;\ +#echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ +#apt-get update && apt-get install -y kubectl + +USER jenkins \ No newline at end of file diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 0e9148006..329f24f6a 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -13,6 +13,7 @@ spec: path: "/data/jenkins/" --- + kind: PersistentVolumeClaim apiVersion: v1 metadata: @@ -24,6 +25,7 @@ spec: requests: storage: 2Gi --- + apiVersion: v1 kind: Service metadata: @@ -38,7 +40,9 @@ spec: app: jenkins tier: jenkins type: NodePort + --- + apiVersion: extensions/v1beta1 kind: Deployment metadata: @@ -55,18 +59,18 @@ spec: tier: jenkins spec: containers: - - image: chadmoon/jenkins-docker-kubectl:latest + - image: 127.0.0.1:30400/jenkins:latest name: jenkins securityContext: privileged: true - ports: - - containerPort: 8080 - name: jenkins volumeMounts: - - name: jenkins-persistent-storage - mountPath: /root/.jenkins - name: docker mountPath: /var/run/docker.sock + - name: jenkins-persistent-storage + mountPath: /root/.jenkins + ports: + - containerPort: 8080 + name: jenkins volumes: - name: docker hostPath: From bb8b0ebd8b1e5d5f78ed98fbc3a406bc784cef1e Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 6 Aug 2018 16:21:29 -0600 Subject: [PATCH 22/89] pinned version of jenkins base image --- applications/jenkins/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index 27ea2123f..de347b484 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -1,4 +1,4 @@ -FROM jenkins/jenkins:latest +FROM jenkins/jenkins:2.136 USER root #Installing Docker RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ From b150c06d332d9d9a9f51c9708dd1d99aa372565b Mon Sep 17 00:00:00 2001 From: Michael Durand Date: Tue, 7 Aug 2018 10:05:03 -0400 Subject: [PATCH 23/89] Updated to kubernetes 1.11.0 --- README.md | 4 ++-- part1.yml | 2 +- steps.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fa94349e7..47e12f558 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ To complete the tutorial manually, follow the steps below. Start up the Kubernetes cluster with Minikube, giving it some extra resources. -`minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0` +`minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0` #### Step2 @@ -426,4 +426,4 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +limitations under the License. diff --git a/part1.yml b/part1.yml index b8a44cdd4..f6693a2d0 100644 --- a/part1.yml +++ b/part1.yml @@ -5,7 +5,7 @@ parts: steps: - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources. - com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0 + com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 - cap: Enable the Minikube add-ons Heapster and Ingress. com: minikube addons enable heapster; minikube addons enable ingress diff --git a/steps.yml b/steps.yml index b8f3c7bd1..a604c5a30 100644 --- a/steps.yml +++ b/steps.yml @@ -5,7 +5,7 @@ parts: steps: - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources. - com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.6.0 + com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 - cap: Enable the Minikube add-ons Heapster and Ingress. com: minikube addons enable heapster; minikube addons enable ingress From 54538ce2760e21cf68a0889f27568d9c6c31adc3 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 6 Aug 2018 11:02:27 -0600 Subject: [PATCH 24/89] provided jenkins Dockerfile and updated jenkins manifest --- applications/jenkins/Dockerfile | 15 +++++++++++++++ manifests/jenkins.yml | 16 ++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 applications/jenkins/Dockerfile diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile new file mode 100644 index 000000000..27ea2123f --- /dev/null +++ b/applications/jenkins/Dockerfile @@ -0,0 +1,15 @@ +FROM jenkins/jenkins:latest +USER root +#Installing Docker +RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ +curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -;\ +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable";\ +apt-get update && apt-get install docker-ce -y + +#Installing kubectl from Docker +#RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ +#touch /etc/apt/sources.list.d/kubernetes.list;\ +#echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ +#apt-get update && apt-get install -y kubectl + +USER jenkins \ No newline at end of file diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 0e9148006..329f24f6a 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -13,6 +13,7 @@ spec: path: "/data/jenkins/" --- + kind: PersistentVolumeClaim apiVersion: v1 metadata: @@ -24,6 +25,7 @@ spec: requests: storage: 2Gi --- + apiVersion: v1 kind: Service metadata: @@ -38,7 +40,9 @@ spec: app: jenkins tier: jenkins type: NodePort + --- + apiVersion: extensions/v1beta1 kind: Deployment metadata: @@ -55,18 +59,18 @@ spec: tier: jenkins spec: containers: - - image: chadmoon/jenkins-docker-kubectl:latest + - image: 127.0.0.1:30400/jenkins:latest name: jenkins securityContext: privileged: true - ports: - - containerPort: 8080 - name: jenkins volumeMounts: - - name: jenkins-persistent-storage - mountPath: /root/.jenkins - name: docker mountPath: /var/run/docker.sock + - name: jenkins-persistent-storage + mountPath: /root/.jenkins + ports: + - containerPort: 8080 + name: jenkins volumes: - name: docker hostPath: From f09489cccb4f0c562f4fff66e0487d0c2aaee5f7 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 6 Aug 2018 16:21:29 -0600 Subject: [PATCH 25/89] pinned version of jenkins base image --- applications/jenkins/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index 27ea2123f..de347b484 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -1,4 +1,4 @@ -FROM jenkins/jenkins:latest +FROM jenkins/jenkins:2.136 USER root #Installing Docker RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ From d3c312e70867f4feccf2f98baeead620d4694aee Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 9 Aug 2018 15:10:02 -0600 Subject: [PATCH 26/89] provide Jenkins with access to k8s cluster through kubectl context --- applications/jenkins/Dockerfile | 8 ++-- manifests/jenkins.yml | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index de347b484..b6c7c7e50 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -7,9 +7,9 @@ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian apt-get update && apt-get install docker-ce -y #Installing kubectl from Docker -#RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ -#touch /etc/apt/sources.list.d/kubernetes.list;\ -#echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ -#apt-get update && apt-get install -y kubectl +RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ +touch /etc/apt/sources.list.d/kubernetes.list;\ +echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ +apt-get update && apt-get install -y kubectl USER jenkins \ No newline at end of file diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 329f24f6a..219657c21 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -26,6 +26,47 @@ spec: storage: 2Gi --- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: jenkins + namespace: default +automountServiceAccountToken: true + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: Jenkins-cluster-admin +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: jenkins + namespace: default + +--- + +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: null + name: kubectl-jenkins-context +data: + kubectl-config-context.sh: |- + #!/bin/bash -v + + kubectl config set-credentials jenkins --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + kubectl config set-cluster minikube --server="https://192.168.99.100:8443" --certificate-authority="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + kubectl config set-context jenkins-minikube --cluster=minikube --user=jenkins --namespace=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + kubectl config use-context jenkins-minikube + cat ~/.kube/config + +--- + apiVersion: v1 kind: Service metadata: @@ -58,12 +99,30 @@ spec: app: jenkins tier: jenkins spec: + serviceAccount: jenkins + initContainers: + - image: lachlanevenson/k8s-kubectl:v1.11.2 + name: kubectl-config + command: + - "sh" + - "/kubectl-config-context.sh" + volumeMounts: + - name: kube-config + mountPath: "~/.kube" + - name: kubectl-jenkins-context + mountPath: "/kubectl-config-context.sh" + subPath: "kubectl-config-context.sh" containers: - image: 127.0.0.1:30400/jenkins:latest name: jenkins securityContext: privileged: true volumeMounts: + - name: kubectl-jenkins-context + mountPath: "/kubectl-config-context.sh" + subPath: "kubectl-config-context.sh" + - name: kube-config + mountPath: "/var/jenkins_home/.kube" - name: docker mountPath: /var/run/docker.sock - name: jenkins-persistent-storage @@ -72,6 +131,14 @@ spec: - containerPort: 8080 name: jenkins volumes: + - name: kubectl-jenkins-context + configMap: + name: kubectl-jenkins-context + items: + - key: kubectl-config-context.sh + path: kubectl-config-context.sh + - name: kube-config + emptyDir: {} - name: docker hostPath: path: /var/run/docker.sock From d76af3e07c9ae2777f74c3f2709fc71e27168912 Mon Sep 17 00:00:00 2001 From: Michael Durand Date: Fri, 10 Aug 2018 10:41:22 -0400 Subject: [PATCH 27/89] Resolved docker.sock issue with jenkins --- applications/jenkins/Dockerfile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 applications/jenkins/Dockerfile diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile new file mode 100644 index 000000000..f28a6a843 --- /dev/null +++ b/applications/jenkins/Dockerfile @@ -0,0 +1,23 @@ +FROM jenkins/jenkins:2.136 +USER root +#Installing Docker +RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ +curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -;\ +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable";\ +apt-get update && apt-get install docker-ce -y + +#Installing kubernetes kubelet +RUN add-apt-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main";\ +apt-get update && apt-get install kubectl kubelet -y --allow-unauthenticated + + +#Installing kubectl from Docker +#RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ +#touch /etc/apt/sources.list.d/kubernetes.list;\ +#echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ +#apt-get update && apt-get install -y kubectl + +# Make sure jenkins user has docker.sock privlidges +RUN addgroup --gid 1001 dsock +RUN gpasswd -a jenkins dsock +USER jenkins From 83eda8fbee0d394476aae13861d1584823ddc44c Mon Sep 17 00:00:00 2001 From: Michael Durand Date: Fri, 10 Aug 2018 11:05:11 -0400 Subject: [PATCH 28/89] Added privileges for jenkins to access /var/run/docker.sock Issue 53 --- applications/jenkins/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index f28a6a843..3011594b4 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -10,14 +10,13 @@ apt-get update && apt-get install docker-ce -y RUN add-apt-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main";\ apt-get update && apt-get install kubectl kubelet -y --allow-unauthenticated - #Installing kubectl from Docker #RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ #touch /etc/apt/sources.list.d/kubernetes.list;\ #echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ #apt-get update && apt-get install -y kubectl -# Make sure jenkins user has docker.sock privlidges +# Make sure jenkins user has docker.sock privileges RUN addgroup --gid 1001 dsock RUN gpasswd -a jenkins dsock USER jenkins From 341764e9ce32f8b0222dfd5d68ccf2b229c82216 Mon Sep 17 00:00:00 2001 From: Michael Durand Date: Fri, 10 Aug 2018 13:45:01 -0400 Subject: [PATCH 29/89] Granted jenkins access to /var/run/docker.sock group --- applications/jenkins/Dockerfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index 3011594b4..2307904d2 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -6,17 +6,13 @@ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -;\ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable";\ apt-get update && apt-get install docker-ce -y -#Installing kubernetes kubelet -RUN add-apt-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main";\ -apt-get update && apt-get install kubectl kubelet -y --allow-unauthenticated - #Installing kubectl from Docker #RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ #touch /etc/apt/sources.list.d/kubernetes.list;\ #echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ #apt-get update && apt-get install -y kubectl -# Make sure jenkins user has docker.sock privileges +# Grant jenkins user group access to /var/run/docker.sock RUN addgroup --gid 1001 dsock RUN gpasswd -a jenkins dsock USER jenkins From 3f9db235abfce0a0df04a287e45b4b32b914a50e Mon Sep 17 00:00:00 2001 From: Michael Durand Date: Fri, 10 Aug 2018 13:53:12 -0400 Subject: [PATCH 30/89] Granted user jenkins permission to group id 1001 --- applications/jenkins/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index 2307904d2..6d2748a33 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -12,6 +12,7 @@ apt-get update && apt-get install docker-ce -y #echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ #apt-get update && apt-get install -y kubectl + # Grant jenkins user group access to /var/run/docker.sock RUN addgroup --gid 1001 dsock RUN gpasswd -a jenkins dsock From 21569677e937b75e86f7b47529149b198a5d2be6 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 10 Aug 2018 13:43:56 -0600 Subject: [PATCH 31/89] master resync --- applications/hello-kenzan/index.html | 7 ++----- applications/puzzle/common/models/crossword.js | 12 ++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/applications/hello-kenzan/index.html b/applications/hello-kenzan/index.html index 25ac4b4ca..1e9046561 100644 --- a/applications/hello-kenzan/index.html +++ b/applications/hello-kenzan/index.html @@ -1,6 +1,3 @@ - -

HELLO FROM MINIKUBE!

-

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, - you will note several things:

+

Hello from Kenzan! You've successfully built and run the Hello-Kenzan app.

+

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

diff --git a/applications/puzzle/common/models/crossword.js b/applications/puzzle/common/models/crossword.js index 0efcd0817..096880f6e 100644 --- a/applications/puzzle/common/models/crossword.js +++ b/applications/puzzle/common/models/crossword.js @@ -7,9 +7,9 @@ module.exports = function(Crossword) { var etcd = new Etcd("http://example-etcd-cluster-client-service:2379"); fireHit(); Crossword.get = function(cb) { - + var etcdPuzzleResp = etcd.getSync("puzzle"); - + if (etcdPuzzleResp && !etcdPuzzleResp.err) { console.log(`Responding with cache`); @@ -38,9 +38,9 @@ module.exports = function(Crossword) { if(words) { etcd.delSync("puzzle"); Crossword.findOne(function (err, crossword) { - + // Part 4: Uncomment the next line to enable puzzle pod highlighting when clicking the Submit button - fireHit(); + //fireHit(); if (err) handleError(err.message, cb); for (var j = 0; j < words.length; j++) { var word = words[j]; @@ -64,10 +64,10 @@ module.exports = function(Crossword) { } Crossword.clear = function(cb) { - + Crossword.findOne(function(err, crossword) { console.log("Calling hit from clear."); - fireHit(); + fireHit(); if(err) handleError(err.message, cb); var updatedWords = []; for (var i = 0; i < crossword.words.length; i++) { From ab2fbc440fda77d0c1a898db085dc68daf25a164 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 10 Aug 2018 13:48:09 -0600 Subject: [PATCH 32/89] provided jenkins with a serviceaccount bound to cluster admin role --- manifests/jenkins.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 329f24f6a..7b3bf8809 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -26,6 +26,30 @@ spec: storage: 2Gi --- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: jenkins + namespace: default +automountServiceAccountToken: true + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: Jenkins-cluster-admin +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: jenkins + namespace: default + +--- + apiVersion: v1 kind: Service metadata: @@ -58,6 +82,7 @@ spec: app: jenkins tier: jenkins spec: + serviceAccount: jenkins containers: - image: 127.0.0.1:30400/jenkins:latest name: jenkins From 16f1e0906fb3649513339ee8b44be5dd906b9aaf Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 6 Aug 2018 11:02:27 -0600 Subject: [PATCH 33/89] provided jenkins Dockerfile and updated jenkins manifest --- applications/jenkins/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index 2307904d2..e4becc333 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -12,7 +12,7 @@ apt-get update && apt-get install docker-ce -y #echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ #apt-get update && apt-get install -y kubectl -# Grant jenkins user group access to /var/run/docker.sock +# Grant jenkins user group access to /var/run/docker.sock RUN addgroup --gid 1001 dsock RUN gpasswd -a jenkins dsock USER jenkins From 30dfb0641ca1cf787617dabecbe24e9aec847ffe Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 9 Aug 2018 15:10:02 -0600 Subject: [PATCH 34/89] provide Jenkins with access to k8s cluster through kubectl context --- applications/jenkins/Dockerfile | 8 +++---- manifests/jenkins.yml | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index e4becc333..abbccd0b1 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -7,10 +7,10 @@ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian apt-get update && apt-get install docker-ce -y #Installing kubectl from Docker -#RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ -#touch /etc/apt/sources.list.d/kubernetes.list;\ -#echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ -#apt-get update && apt-get install -y kubectl +RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -;\ +touch /etc/apt/sources.list.d/kubernetes.list;\ +echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list;\ +apt-get update && apt-get install -y kubectl # Grant jenkins user group access to /var/run/docker.sock RUN addgroup --gid 1001 dsock diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 7b3bf8809..219657c21 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -50,6 +50,23 @@ subjects: --- +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: null + name: kubectl-jenkins-context +data: + kubectl-config-context.sh: |- + #!/bin/bash -v + + kubectl config set-credentials jenkins --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + kubectl config set-cluster minikube --server="https://192.168.99.100:8443" --certificate-authority="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + kubectl config set-context jenkins-minikube --cluster=minikube --user=jenkins --namespace=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) + kubectl config use-context jenkins-minikube + cat ~/.kube/config + +--- + apiVersion: v1 kind: Service metadata: @@ -83,12 +100,29 @@ spec: tier: jenkins spec: serviceAccount: jenkins + initContainers: + - image: lachlanevenson/k8s-kubectl:v1.11.2 + name: kubectl-config + command: + - "sh" + - "/kubectl-config-context.sh" + volumeMounts: + - name: kube-config + mountPath: "~/.kube" + - name: kubectl-jenkins-context + mountPath: "/kubectl-config-context.sh" + subPath: "kubectl-config-context.sh" containers: - image: 127.0.0.1:30400/jenkins:latest name: jenkins securityContext: privileged: true volumeMounts: + - name: kubectl-jenkins-context + mountPath: "/kubectl-config-context.sh" + subPath: "kubectl-config-context.sh" + - name: kube-config + mountPath: "/var/jenkins_home/.kube" - name: docker mountPath: /var/run/docker.sock - name: jenkins-persistent-storage @@ -97,6 +131,14 @@ spec: - containerPort: 8080 name: jenkins volumes: + - name: kubectl-jenkins-context + configMap: + name: kubectl-jenkins-context + items: + - key: kubectl-config-context.sh + path: kubectl-config-context.sh + - name: kube-config + emptyDir: {} - name: docker hostPath: path: /var/run/docker.sock From 382d2fc7aca0653cbde9e0e0f5559a662a00f3c2 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 14 Aug 2018 14:59:40 -0600 Subject: [PATCH 35/89] fixed kubeconfig paths --- manifests/jenkins.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 219657c21..9586348ad 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -63,7 +63,7 @@ data: kubectl config set-cluster minikube --server="https://192.168.99.100:8443" --certificate-authority="/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" kubectl config set-context jenkins-minikube --cluster=minikube --user=jenkins --namespace=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace) kubectl config use-context jenkins-minikube - cat ~/.kube/config + chmod 755 ~/.kube/config --- @@ -104,11 +104,12 @@ spec: - image: lachlanevenson/k8s-kubectl:v1.11.2 name: kubectl-config command: - - "sh" + - "/bin/sh" + args: - "/kubectl-config-context.sh" volumeMounts: - - name: kube-config - mountPath: "~/.kube" + - name: kubeconfig + mountPath: "/root/.kube" - name: kubectl-jenkins-context mountPath: "/kubectl-config-context.sh" subPath: "kubectl-config-context.sh" @@ -118,11 +119,8 @@ spec: securityContext: privileged: true volumeMounts: - - name: kubectl-jenkins-context - mountPath: "/kubectl-config-context.sh" - subPath: "kubectl-config-context.sh" - - name: kube-config - mountPath: "/var/jenkins_home/.kube" + - name: kubeconfig + mountPath: /var/jenkins_home/.kube - name: docker mountPath: /var/run/docker.sock - name: jenkins-persistent-storage @@ -137,7 +135,7 @@ spec: items: - key: kubectl-config-context.sh path: kubectl-config-context.sh - - name: kube-config + - name: kubeconfig emptyDir: {} - name: docker hostPath: From 1746ab471be34c7ace37f25f383d10a4ec58365b Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 14 Aug 2018 15:36:55 -0600 Subject: [PATCH 36/89] added jenkins plugins list with latest versions locked, updated dockerfile to pre-download plugins --- applications/jenkins/Dockerfile | 5 +++ applications/jenkins/plugins.txt | 72 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 applications/jenkins/plugins.txt diff --git a/applications/jenkins/Dockerfile b/applications/jenkins/Dockerfile index abbccd0b1..094df52b4 100644 --- a/applications/jenkins/Dockerfile +++ b/applications/jenkins/Dockerfile @@ -1,5 +1,10 @@ FROM jenkins/jenkins:2.136 USER root + +#Pre-Install Jenkins Plugins +COPY plugins.txt /usr/share/jenkins/ref/plugins.txt +RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt + #Installing Docker RUN apt-get update && apt-get install software-properties-common apt-transport-https ca-certificates -y; \ curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -;\ diff --git a/applications/jenkins/plugins.txt b/applications/jenkins/plugins.txt new file mode 100644 index 000000000..4715ecbea --- /dev/null +++ b/applications/jenkins/plugins.txt @@ -0,0 +1,72 @@ +jdk-tool:1.1 +script-security:1.44 +command-launcher:1.2 +cloudbees-folder:6.5.1 +bouncycastle-api:2.16.3 +structs:1.14 +workflow-step-api:2.16 +scm-api:2.2.7 +workflow-api:2.29 +junit:1.24 +antisamy-markup-formatter:1.5 +token-macro:2.5 +build-timeout:1.19 +credentials:2.1.18 +ssh-credentials:1.14 +plain-credentials:1.4 +credentials-binding:1.16 +timestamper:1.8.10 +workflow-support:2.20 +durable-task:1.25 +workflow-durable-task-step:2.20 +matrix-project:1.13 +resource-disposer:0.12 +ws-cleanup:0.34 +ant:1.8 +gradle:1.29 +pipeline-milestone-step:1.3.1 +jquery-detached:1.2.1 +jackson2-api:2.8.11.3 +ace-editor:1.1 +workflow-scm-step:2.6 +workflow-cps:2.54 +pipeline-input-step:2.8 +pipeline-stage-step:2.3 +workflow-job:2.24 +pipeline-graph-analysis:1.7 +pipeline-rest-api:2.10 +handlebars:1.1.1 +momentjs:1.1.1 +pipeline-stage-view:2.10 +pipeline-build-step:2.7 +pipeline-model-api:1.3.1 +pipeline-model-extensions:1.3.1 +apache-httpcomponents-client-4-api:4.5.5-3.0 +jsch:0.1.54.2 +git-client:2.7.3 +git-server:1.7 +workflow-cps-global-lib:2.9 +display-url-api:2.2.0 +mailer:1.21 +branch-api:2.0.20 +workflow-multibranch:2.20 +authentication-tokens:1.3 +docker-commons:1.13 +workflow-basic-steps:2.9 +docker-workflow:1.17 +pipeline-stage-tags-metadata:1.3.1 +pipeline-model-declarative-agent:1.1.1 +pipeline-model-definition:1.3.1 +workflow-aggregator:2.5 +github-api:1.92 +git:3.9.1 +github:1.29.2 +github-branch-source:2.3.6 +pipeline-github-lib:1.0 +mapdb-api:1.0.9.0 +subversion:2.11.1 +ssh-slaves:1.26 +matrix-auth:2.3 +pam-auth:1.3 +ldap:1.20 +email-ext:2.63 \ No newline at end of file From 71bba7c22834fb0d5289ebad4b57d85f1fed2d5c Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Wed, 15 Aug 2018 15:34:13 -0600 Subject: [PATCH 37/89] updated plugins list with kubernetes CD, updated pipeline to use the plugin --- Jenkinsfile | 4 +- applications/jenkins/plugins.txt | 116 ++++++++++++++++--------------- 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 204dab990..540f5ef09 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,6 +22,6 @@ node { stage "Deploy" - sh "sed 's#127.0.0.1:30400/hello-kenzan:latest#'$BUILDIMG'#' applications/hello-kenzan/k8s/deployment.yaml | kubectl apply -f -" - sh "kubectl rollout status deployment/hello-kenzan" + kubernetesDeploy configs: 'applications/${appName}/k8s/*.yaml', kubeconfigId: 'kubeconfig' + } \ No newline at end of file diff --git a/applications/jenkins/plugins.txt b/applications/jenkins/plugins.txt index 4715ecbea..6119fabb6 100644 --- a/applications/jenkins/plugins.txt +++ b/applications/jenkins/plugins.txt @@ -1,72 +1,74 @@ -jdk-tool:1.1 -script-security:1.44 -command-launcher:1.2 -cloudbees-folder:6.5.1 -bouncycastle-api:2.16.3 -structs:1.14 -workflow-step-api:2.16 -scm-api:2.2.7 -workflow-api:2.29 -junit:1.24 -antisamy-markup-formatter:1.5 -token-macro:2.5 -build-timeout:1.19 -credentials:2.1.18 -ssh-credentials:1.14 -plain-credentials:1.4 -credentials-binding:1.16 +pipeline-model-api:1.3.1 timestamper:1.8.10 -workflow-support:2.20 -durable-task:1.25 -workflow-durable-task-step:2.20 matrix-project:1.13 -resource-disposer:0.12 -ws-cleanup:0.34 -ant:1.8 -gradle:1.29 -pipeline-milestone-step:1.3.1 -jquery-detached:1.2.1 +github-api:1.92 +workflow-scm-step:2.6 jackson2-api:2.8.11.3 +pipeline-github-lib:1.0 ace-editor:1.1 -workflow-scm-step:2.6 -workflow-cps:2.54 -pipeline-input-step:2.8 +workflow-multibranch:2.20 pipeline-stage-step:2.3 -workflow-job:2.24 -pipeline-graph-analysis:1.7 +token-macro:2.5 pipeline-rest-api:2.10 -handlebars:1.1.1 -momentjs:1.1.1 -pipeline-stage-view:2.10 +scm-api:2.2.7 +authentication-tokens:1.3 +git-server:1.7 +ssh-credentials:1.14 +workflow-basic-steps:2.9 +ant:1.8 +branch-api:2.0.20 +antisamy-markup-formatter:1.5 +workflow-durable-task-step:2.20 +jsch:0.1.54.2 +workflow-step-api:2.16 pipeline-build-step:2.7 -pipeline-model-api:1.3.1 -pipeline-model-extensions:1.3.1 +cloudbees-folder:6.5.1 +jquery-detached:1.2.1 apache-httpcomponents-client-4-api:4.5.5-3.0 -jsch:0.1.54.2 -git-client:2.7.3 -git-server:1.7 -workflow-cps-global-lib:2.9 +ssh-slaves:1.26 +pipeline-model-definition:1.3.1 +workflow-cps:2.54 +pipeline-input-step:2.8 display-url-api:2.2.0 -mailer:1.21 -branch-api:2.0.20 -workflow-multibranch:2.20 -authentication-tokens:1.3 -docker-commons:1.13 -workflow-basic-steps:2.9 docker-workflow:1.17 -pipeline-stage-tags-metadata:1.3.1 +bouncycastle-api:2.16.3 +credentials:2.1.18 +github-branch-source:2.3.6 +workflow-support:2.20 pipeline-model-declarative-agent:1.1.1 -pipeline-model-definition:1.3.1 +credentials-binding:1.16 +workflow-job:2.24 +plain-credentials:1.4 +structs:1.14 +command-launcher:1.2 +script-security:1.44 +subversion:2.11.1 +ws-cleanup:0.34 +kubernetes-cd:0.2.3 +resource-disposer:0.12 +pipeline-model-extensions:1.3.1 +durable-task:1.25 +mapdb-api:1.0.9.0 +gradle:1.29 +github:1.29.2 +git-client:2.7.3 +jdk-tool:1.1 +pipeline-stage-tags-metadata:1.3.1 workflow-aggregator:2.5 -github-api:1.92 +junit:1.24 +docker-commons:1.13 +momentjs:1.1.1 +pipeline-stage-view:2.10 git:3.9.1 -github:1.29.2 -github-branch-source:2.3.6 -pipeline-github-lib:1.0 -mapdb-api:1.0.9.0 -subversion:2.11.1 -ssh-slaves:1.26 +ldap:1.20 +azure-commons:0.2.6 +email-ext:2.63 +handlebars:1.1.1 matrix-auth:2.3 +workflow-cps-global-lib:2.9 +pipeline-milestone-step:1.3.1 +workflow-api:2.29 +mailer:1.21 pam-auth:1.3 -ldap:1.20 -email-ext:2.63 \ No newline at end of file +build-timeout:1.19 +pipeline-graph-analysis:1.7 \ No newline at end of file From f824ee7a400f0ef3bb643a26c411eea0c045f160 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 16 Aug 2018 09:15:51 -0600 Subject: [PATCH 38/89] updated Jenkinsfile with kubernetes manifest paths --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 540f5ef09..83975e24b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,6 +22,6 @@ node { stage "Deploy" - kubernetesDeploy configs: 'applications/${appName}/k8s/*.yaml', kubeconfigId: 'kubeconfig' + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kubeconfig' } \ No newline at end of file From bc1584a043ae26fa9793f6eab1f8ed96939cf352 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 16 Aug 2018 09:47:03 -0600 Subject: [PATCH 39/89] updated kubeconfig id on jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 83975e24b..1f068f725 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,6 +22,6 @@ node { stage "Deploy" - kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kubeconfig' + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' } \ No newline at end of file From 91ebeb668d87ad4a170fcad95b2dc2f089018d58 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 16 Aug 2018 11:00:05 -0600 Subject: [PATCH 40/89] updated instructions on readme to include the new kuberenetes plugin --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 47e12f558..e110d07de 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ Display the Jenkins admin password with the following command, and right-click t #### Step4 -Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins and wait for the process to complete. +Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click "Install Suggested Plugins" button and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). `echo ''` @@ -171,7 +171,19 @@ Create an admin user and credentials, and click Save and Finish. (Make sure to r #### Step6 -We now want to create a new pipeline for use with our Hello-Kenzan app. On the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. +Before we create a pipeline, we first need to provision Kubernetes Continuous Deployment Plugin in Jenkins with a kubeconfig file that will allow access to our kubernetes cluster. Click on Credentials, then Jenkins store, then select the Global credentials Domain and add a new credential. + +`echo ''` + +#### Step7 + +The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. + +`echo ''` + +#### Step6 + +We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. `echo ''` From d591ac4e90cf9584273b3b35e9e47d05101e3f20 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 16 Aug 2018 13:19:48 -0600 Subject: [PATCH 41/89] arranged plugins for better visualization of branches diffs --- applications/jenkins/plugins.txt | 118 +++++++++++++++---------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/applications/jenkins/plugins.txt b/applications/jenkins/plugins.txt index 6119fabb6..2825b9d73 100644 --- a/applications/jenkins/plugins.txt +++ b/applications/jenkins/plugins.txt @@ -1,74 +1,74 @@ -pipeline-model-api:1.3.1 +jdk-tool:1.1 +script-security:1.44 +command-launcher:1.2 +cloudbees-folder:6.5.1 +bouncycastle-api:2.16.3 +structs:1.14 +workflow-step-api:2.16 +scm-api:2.2.7 +workflow-api:2.29 +junit:1.24 +antisamy-markup-formatter:1.5 +token-macro:2.5 +build-timeout:1.19 +credentials:2.1.18 +ssh-credentials:1.14 +plain-credentials:1.4 +credentials-binding:1.16 timestamper:1.8.10 +workflow-support:2.20 +durable-task:1.25 +workflow-durable-task-step:2.20 matrix-project:1.13 -github-api:1.92 -workflow-scm-step:2.6 +resource-disposer:0.12 +ws-cleanup:0.34 +ant:1.8 +gradle:1.29 +pipeline-milestone-step:1.3.1 +jquery-detached:1.2.1 jackson2-api:2.8.11.3 -pipeline-github-lib:1.0 ace-editor:1.1 -workflow-multibranch:2.20 +workflow-scm-step:2.6 +workflow-cps:2.54 +pipeline-input-step:2.8 pipeline-stage-step:2.3 -token-macro:2.5 +workflow-job:2.24 +pipeline-graph-analysis:1.7 pipeline-rest-api:2.10 -scm-api:2.2.7 -authentication-tokens:1.3 -git-server:1.7 -ssh-credentials:1.14 -workflow-basic-steps:2.9 -ant:1.8 -branch-api:2.0.20 -antisamy-markup-formatter:1.5 -workflow-durable-task-step:2.20 -jsch:0.1.54.2 -workflow-step-api:2.16 +handlebars:1.1.1 +momentjs:1.1.1 +pipeline-stage-view:2.10 pipeline-build-step:2.7 -cloudbees-folder:6.5.1 -jquery-detached:1.2.1 +pipeline-model-api:1.3.1 +pipeline-model-extensions:1.3.1 apache-httpcomponents-client-4-api:4.5.5-3.0 -ssh-slaves:1.26 -pipeline-model-definition:1.3.1 -workflow-cps:2.54 -pipeline-input-step:2.8 +jsch:0.1.54.2 +git-client:2.7.3 +git-server:1.7 +workflow-cps-global-lib:2.9 display-url-api:2.2.0 +mailer:1.21 +branch-api:2.0.20 +workflow-multibranch:2.20 +authentication-tokens:1.3 +docker-commons:1.13 +workflow-basic-steps:2.9 docker-workflow:1.17 -bouncycastle-api:2.16.3 -credentials:2.1.18 -github-branch-source:2.3.6 -workflow-support:2.20 -pipeline-model-declarative-agent:1.1.1 -credentials-binding:1.16 -workflow-job:2.24 -plain-credentials:1.4 -structs:1.14 -command-launcher:1.2 -script-security:1.44 -subversion:2.11.1 -ws-cleanup:0.34 -kubernetes-cd:0.2.3 -resource-disposer:0.12 -pipeline-model-extensions:1.3.1 -durable-task:1.25 -mapdb-api:1.0.9.0 -gradle:1.29 -github:1.29.2 -git-client:2.7.3 -jdk-tool:1.1 pipeline-stage-tags-metadata:1.3.1 +pipeline-model-declarative-agent:1.1.1 +pipeline-model-definition:1.3.1 workflow-aggregator:2.5 -junit:1.24 -docker-commons:1.13 -momentjs:1.1.1 -pipeline-stage-view:2.10 +github-api:1.92 git:3.9.1 -ldap:1.20 -azure-commons:0.2.6 -email-ext:2.63 -handlebars:1.1.1 +github:1.29.2 +github-branch-source:2.3.6 +pipeline-github-lib:1.0 +mapdb-api:1.0.9.0 +subversion:2.11.1 +ssh-slaves:1.26 matrix-auth:2.3 -workflow-cps-global-lib:2.9 -pipeline-milestone-step:1.3.1 -workflow-api:2.29 -mailer:1.21 pam-auth:1.3 -build-timeout:1.19 -pipeline-graph-analysis:1.7 \ No newline at end of file +ldap:1.20 +email-ext:2.63 +kubernetes-cd:0.2.3 +azure-commons:0.2.6 \ No newline at end of file From f6f05301fffdeee42273f4a71dd21cc6e6d40faf Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 16 Aug 2018 13:59:02 -0600 Subject: [PATCH 42/89] fixed steps numbers --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e110d07de..05c44f25f 100644 --- a/README.md +++ b/README.md @@ -181,37 +181,37 @@ The following values must be entered precisely as indicated: For the Kind field `echo ''` -#### Step6 +#### Step8 We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. `echo ''` -#### Step7 +#### Step9 Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". `echo ''` -#### Step8 +#### Step10 Change the SCM to Git. `echo ''` -#### Step9 +#### Step11 Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. `echo ''` -#### Step10 +#### Step12 Now view the Hello-Kenzan application. `minikube service hello-kenzan` -#### Step11 +#### Step13 Push a change to your fork. Run job again. View the changes. From 8a57219744c6a10fe4d4e4acd28e9e842f8186a7 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:30:28 -0600 Subject: [PATCH 43/89] updated etcd script with helm commands --- manifests/service.json | 22 ---------------------- manifests/service.yaml | 14 ++++++++++++++ scripts/etcd.sh | 10 +++++----- 3 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 manifests/service.json create mode 100644 manifests/service.yaml diff --git a/manifests/service.json b/manifests/service.json deleted file mode 100644 index 1f5c3c438..000000000 --- a/manifests/service.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "example-etcd-cluster-client-service" - }, - "spec": { - "selector": { - "etcd_cluster": "example-etcd-cluster", - "app": "etcd" - }, - "ports": [ - { - "protocol": "TCP", - "port": 2379, - "targetPort": 2379, - "nodePort": 32379 - } - ], - "type": "NodePort" - } -} \ No newline at end of file diff --git a/manifests/service.yaml b/manifests/service.yaml new file mode 100644 index 000000000..b28a9aa43 --- /dev/null +++ b/manifests/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: example-etcd-cluster-client-service +spec: + selector: + etcd_cluster: example-etcd-cluster + app: etcd + ports: + - protocol: TCP + port: 2379 + targetPort: 2379 + nodePort: 32379 + type: NodePort \ No newline at end of file diff --git a/scripts/etcd.sh b/scripts/etcd.sh index 51e088873..75dd2fc45 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -echo "installing etcd operator" -kubectl create -f manifests/deployment.yaml -kubectl rollout status -f manifests/deployment.yaml +echo "initializing Helm" +helm init --wait --debug -echo "pausing for 10 seconds for operator to settle" -sleep 10 +echo "installing etcd operator (Helm Chart)" +helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug +kubectl rollout status deploy/tiller-deploy -n kube-system kubectl create -f manifests/etcd-cluster.yaml From cad54d293bf12a10a6ccbe2e3d5946b080625265 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:31:41 -0600 Subject: [PATCH 44/89] deleted unnecesary etcd-operator deploy manifest --- manifests/deployment.yaml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 manifests/deployment.yaml diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml deleted file mode 100644 index f355504d1..000000000 --- a/manifests/deployment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: etcd-operator -spec: - replicas: 1 - template: - metadata: - labels: - name: etcd-operator - spec: - containers: - - name: etcd-operator - image: quay.io/coreos/etcd-operator:v0.9.2 - command: - - etcd-operator - # Uncomment to act for resources in all namespaces. More information in doc/clusterwide.md - #- -cluster-wide - env: - - name: MY_POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: MY_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name From 09584d36b52607431e4a912454bdae477f54d8a1 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:44:00 -0600 Subject: [PATCH 45/89] renamed etcd service manifest and references --- manifests/{service.yaml => etcd-service.yaml} | 0 scripts/etcd.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename manifests/{service.yaml => etcd-service.yaml} (100%) diff --git a/manifests/service.yaml b/manifests/etcd-service.yaml similarity index 100% rename from manifests/service.yaml rename to manifests/etcd-service.yaml diff --git a/scripts/etcd.sh b/scripts/etcd.sh index 75dd2fc45..68f3970e1 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -10,7 +10,7 @@ kubectl rollout status deploy/tiller-deploy -n kube-system kubectl create -f manifests/etcd-cluster.yaml echo "installing etcd cluster service" -kubectl create -f manifests/service.json +kubectl create -f manifests/etcd-service.yaml echo "waiting for etcd cluster to turnup" sleep 10 From bf96cc0553fee659ad251a1f42fd515a5624672d Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:04:25 -0600 Subject: [PATCH 46/89] added service account, role with least required rights, and roleBinding to monitor-scale app --- .../monitor-scale/k8s/deployment.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index 1678c8266..c642d64ff 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -14,6 +14,53 @@ spec: type: NodePort --- + + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: monitor-scale + namespace: default +#automountServiceAccountToken: true + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: default + name: puzzle-scaler +rules: +- apiGroups: + - "" + - "extensions" + - "extensions/v1beta1" + resources: + - deployments + - deployments/scale + resourceNames: + - "puzzle" + verbs: + - update + - get +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: monitor-scale-puzzle-scaler + namespace: default +roleRef: + kind: Role + name: puzzle-scaler + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: monitor-scale + namespace: default + +--- + apiVersion: extensions/v1beta1 kind: Deployment metadata: @@ -29,6 +76,7 @@ spec: app: monitor-scale tier: monitor-scale spec: + serviceAccountName: monitor-scale containers: - image: 127.0.0.1:30400/monitor-scale:latest name: monitor-scale From c211500a2b3de4673779cb6540a570c51ed08a4d Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:09:04 -0600 Subject: [PATCH 47/89] added hotfix for deprecated deployment attribute serviceAccount in jenkins deployment manifest --- manifests/jenkins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 9586348ad..371f6e6cb 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -99,7 +99,7 @@ spec: app: jenkins tier: jenkins spec: - serviceAccount: jenkins + serviceAccountName: jenkins initContainers: - image: lachlanevenson/k8s-kubectl:v1.11.2 name: kubectl-config From 1a5cdf5b6a6d54119ecc27f1321fa44b11092c74 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:13:46 -0600 Subject: [PATCH 48/89] removed unnecessary values from monitor-scale manifests --- applications/monitor-scale/k8s/deployment.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index c642d64ff..c2e9754f0 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -15,13 +15,11 @@ spec: --- - apiVersion: v1 kind: ServiceAccount metadata: name: monitor-scale namespace: default -#automountServiceAccountToken: true --- @@ -32,9 +30,7 @@ metadata: name: puzzle-scaler rules: - apiGroups: - - "" - "extensions" - - "extensions/v1beta1" resources: - deployments - deployments/scale @@ -43,6 +39,7 @@ rules: verbs: - update - get + --- apiVersion: rbac.authorization.k8s.io/v1 @@ -92,6 +89,7 @@ spec: name: kubectl-api --- + apiVersion: extensions/v1beta1 kind: Ingress metadata: From 22c61e94fa488ef9a16b1c138a0eea08831b6817 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:30:28 -0600 Subject: [PATCH 49/89] updated etcd script with helm commands --- manifests/service.json | 22 ---------------------- manifests/service.yaml | 14 ++++++++++++++ scripts/etcd.sh | 10 +++++----- 3 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 manifests/service.json create mode 100644 manifests/service.yaml diff --git a/manifests/service.json b/manifests/service.json deleted file mode 100644 index 1f5c3c438..000000000 --- a/manifests/service.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "example-etcd-cluster-client-service" - }, - "spec": { - "selector": { - "etcd_cluster": "example-etcd-cluster", - "app": "etcd" - }, - "ports": [ - { - "protocol": "TCP", - "port": 2379, - "targetPort": 2379, - "nodePort": 32379 - } - ], - "type": "NodePort" - } -} \ No newline at end of file diff --git a/manifests/service.yaml b/manifests/service.yaml new file mode 100644 index 000000000..b28a9aa43 --- /dev/null +++ b/manifests/service.yaml @@ -0,0 +1,14 @@ +kind: Service +apiVersion: v1 +metadata: + name: example-etcd-cluster-client-service +spec: + selector: + etcd_cluster: example-etcd-cluster + app: etcd + ports: + - protocol: TCP + port: 2379 + targetPort: 2379 + nodePort: 32379 + type: NodePort \ No newline at end of file diff --git a/scripts/etcd.sh b/scripts/etcd.sh index 51e088873..75dd2fc45 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -echo "installing etcd operator" -kubectl create -f manifests/deployment.yaml -kubectl rollout status -f manifests/deployment.yaml +echo "initializing Helm" +helm init --wait --debug -echo "pausing for 10 seconds for operator to settle" -sleep 10 +echo "installing etcd operator (Helm Chart)" +helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug +kubectl rollout status deploy/tiller-deploy -n kube-system kubectl create -f manifests/etcd-cluster.yaml From 897c371741797992b61bc0fe8950841cbc7f2e62 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:31:41 -0600 Subject: [PATCH 50/89] deleted unnecesary etcd-operator deploy manifest --- manifests/deployment.yaml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 manifests/deployment.yaml diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml deleted file mode 100644 index f355504d1..000000000 --- a/manifests/deployment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: etcd-operator -spec: - replicas: 1 - template: - metadata: - labels: - name: etcd-operator - spec: - containers: - - name: etcd-operator - image: quay.io/coreos/etcd-operator:v0.9.2 - command: - - etcd-operator - # Uncomment to act for resources in all namespaces. More information in doc/clusterwide.md - #- -cluster-wide - env: - - name: MY_POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: MY_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name From 5180c0ea44255b974efe18cfe3cadd0966165e83 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 17 Aug 2018 13:44:00 -0600 Subject: [PATCH 51/89] renamed etcd service manifest and references --- manifests/{service.yaml => etcd-service.yaml} | 0 scripts/etcd.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename manifests/{service.yaml => etcd-service.yaml} (100%) diff --git a/manifests/service.yaml b/manifests/etcd-service.yaml similarity index 100% rename from manifests/service.yaml rename to manifests/etcd-service.yaml diff --git a/scripts/etcd.sh b/scripts/etcd.sh index 75dd2fc45..68f3970e1 100755 --- a/scripts/etcd.sh +++ b/scripts/etcd.sh @@ -10,7 +10,7 @@ kubectl rollout status deploy/tiller-deploy -n kube-system kubectl create -f manifests/etcd-cluster.yaml echo "installing etcd cluster service" -kubectl create -f manifests/service.json +kubectl create -f manifests/etcd-service.yaml echo "waiting for etcd cluster to turnup" sleep 10 From b401aa7feca05e50cea3afc82ebdb6f2be0784c0 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:04:25 -0600 Subject: [PATCH 52/89] added service account, role with least required rights, and roleBinding to monitor-scale app --- .../monitor-scale/k8s/deployment.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index 1678c8266..c642d64ff 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -14,6 +14,53 @@ spec: type: NodePort --- + + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: monitor-scale + namespace: default +#automountServiceAccountToken: true + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: default + name: puzzle-scaler +rules: +- apiGroups: + - "" + - "extensions" + - "extensions/v1beta1" + resources: + - deployments + - deployments/scale + resourceNames: + - "puzzle" + verbs: + - update + - get +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: monitor-scale-puzzle-scaler + namespace: default +roleRef: + kind: Role + name: puzzle-scaler + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: monitor-scale + namespace: default + +--- + apiVersion: extensions/v1beta1 kind: Deployment metadata: @@ -29,6 +76,7 @@ spec: app: monitor-scale tier: monitor-scale spec: + serviceAccountName: monitor-scale containers: - image: 127.0.0.1:30400/monitor-scale:latest name: monitor-scale From 7efeefdf810a5166db7cdefd0811aa1fe88d2c4e Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:09:04 -0600 Subject: [PATCH 53/89] added hotfix for deprecated deployment attribute serviceAccount in jenkins deployment manifest --- manifests/jenkins.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/jenkins.yml b/manifests/jenkins.yml index 9586348ad..371f6e6cb 100644 --- a/manifests/jenkins.yml +++ b/manifests/jenkins.yml @@ -99,7 +99,7 @@ spec: app: jenkins tier: jenkins spec: - serviceAccount: jenkins + serviceAccountName: jenkins initContainers: - image: lachlanevenson/k8s-kubectl:v1.11.2 name: kubectl-config From bc441140011d6ea59013ffd1c1b8b1d3c2b156d8 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 20 Aug 2018 15:13:46 -0600 Subject: [PATCH 54/89] removed unnecessary values from monitor-scale manifests --- applications/monitor-scale/k8s/deployment.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index c642d64ff..c2e9754f0 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -15,13 +15,11 @@ spec: --- - apiVersion: v1 kind: ServiceAccount metadata: name: monitor-scale namespace: default -#automountServiceAccountToken: true --- @@ -32,9 +30,7 @@ metadata: name: puzzle-scaler rules: - apiGroups: - - "" - "extensions" - - "extensions/v1beta1" resources: - deployments - deployments/scale @@ -43,6 +39,7 @@ rules: verbs: - update - get + --- apiVersion: rbac.authorization.k8s.io/v1 @@ -92,6 +89,7 @@ spec: name: kubectl-api --- + apiVersion: extensions/v1beta1 kind: Ingress metadata: From 93dd5d2b65717459262bcb9dea0ebb60cd87d252 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 10:46:22 -0600 Subject: [PATCH 55/89] Puzzle app update with tag var --- applications/puzzle/Jenkinsfile | 13 +++++++------ applications/puzzle/k8s/deployment.yaml | 4 ++-- scripts/puzzle.sh | 9 +++++---- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/applications/puzzle/Jenkinsfile b/applications/puzzle/Jenkinsfile index 7071b5f27..365182217 100644 --- a/applications/puzzle/Jenkinsfile +++ b/applications/puzzle/Jenkinsfile @@ -3,7 +3,7 @@ node { checkout scm env.DOCKER_API_VERSION="1.23" - + sh "git rev-parse --short HEAD > commit-id" tag = readFile('commit-id').replace("\n", "").replace("\r", "") @@ -11,16 +11,17 @@ node { registryHost = "127.0.0.1:30400/" imageName = "${registryHost}${appName}:${tag}" env.BUILDIMG=imageName + env.BUILD_TAG=tag stage "Build" - + sh "docker build -t ${imageName} applications/puzzle" - + stage "Push" sh "docker push ${imageName}" stage "Deploy" - - sh "sed 's#127.0.0.1:30400/puzzle:latest#'$BUILDIMG'#' applications/puzzle/k8s/deployment.yaml | kubectl apply -f -" -} \ No newline at end of file + + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' +} diff --git a/applications/puzzle/k8s/deployment.yaml b/applications/puzzle/k8s/deployment.yaml index 750cf81bb..23109d176 100644 --- a/applications/puzzle/k8s/deployment.yaml +++ b/applications/puzzle/k8s/deployment.yaml @@ -14,7 +14,7 @@ spec: tier: puzzle spec: containers: - - image: 127.0.0.1:30400/puzzle:latest + - image: 127.0.0.1:30400/puzzle:$BUILD_TAG name: puzzle imagePullPolicy: Always lifecycle: @@ -23,7 +23,7 @@ spec: command: ["/up.sh"] preStop: exec: - command: ["/down.sh"] + command: ["/down.sh"] ports: - containerPort: 3000 name: puzzle diff --git a/scripts/puzzle.sh b/scripts/puzzle.sh index c54a1a555..896146f82 100755 --- a/scripts/puzzle.sh +++ b/scripts/puzzle.sh @@ -1,10 +1,10 @@ #!/bin/bash #Retrieve the latest git commit hash -TAG=`git rev-parse --short HEAD` +BUILD_TAG=`git rev-parse --short HEAD` #Build the docker image -docker build -t 127.0.0.1:30400/puzzle:$TAG -f applications/puzzle/Dockerfile applications/puzzle +docker build -t 127.0.0.1:30400/puzzle:$BUILD_TAG -f applications/puzzle/Dockerfile applications/puzzle #Setup the proxy for the registry docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" @@ -13,10 +13,11 @@ echo "5 second sleep to make sure the registry is ready" sleep 5; #Push the images -docker push 127.0.0.1:30400/puzzle:$TAG +docker push 127.0.0.1:30400/puzzle:$BUILD_TAG #Stop the registry proxy docker stop socat-registry # Create the deployment and service for the puzzle server aka puzzle -sed 's#127.0.0.1:30400/puzzle:latest#127.0.0.1:30400/puzzle:'$TAG'#' applications/puzzle/k8s/deployment.yaml | kubectl apply -f - +sed 's#127.0.0.1:30400/puzzle:$BUILD_TAG#127.0.0.1:30400/puzzle:'$BUILD_TAG'#' applications/puzzle/k8s/deployment.yaml | kubectl apply -f - + From 22b51c0d855cde7111b539b8df6c8b53a342d963 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 15:30:32 -0600 Subject: [PATCH 56/89] kr8sswordz app update with tag var --- applications/kr8sswordz-pages/Jenkinsfile | 3 ++- applications/kr8sswordz-pages/k8s/deployment.yaml | 2 +- scripts/kr8sswordz-pages.sh | 14 +++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/applications/kr8sswordz-pages/Jenkinsfile b/applications/kr8sswordz-pages/Jenkinsfile index 093cd283d..6cd326fc4 100644 --- a/applications/kr8sswordz-pages/Jenkinsfile +++ b/applications/kr8sswordz-pages/Jenkinsfile @@ -11,6 +11,7 @@ node { registryHost = "127.0.0.1:30400/" imageName = "${registryHost}${appName}:${tag}" env.BUILDIMG=imageName + env.BUILD_TAG=tag stage "Build" @@ -22,5 +23,5 @@ node { stage "Deploy" - sh "sed 's#127.0.0.1:30400/kr8sswordz:latest#'$BUILDIMG'#' applications/kr8sswordz-pages/k8s/deployment.yaml | kubectl apply -f -" + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' } \ No newline at end of file diff --git a/applications/kr8sswordz-pages/k8s/deployment.yaml b/applications/kr8sswordz-pages/k8s/deployment.yaml index 16c1baa2a..4805dcca1 100644 --- a/applications/kr8sswordz-pages/k8s/deployment.yaml +++ b/applications/kr8sswordz-pages/k8s/deployment.yaml @@ -30,7 +30,7 @@ spec: tier: kr8sswordz spec: containers: - - image: 127.0.0.1:30400/kr8sswordz:latest + - image: 127.0.0.1:30400/kr8sswordz:$BUILD_TAG name: kr8sswordz imagePullPolicy: Always ports: diff --git a/scripts/kr8sswordz-pages.sh b/scripts/kr8sswordz-pages.sh index 75e0856e4..8f96745f9 100755 --- a/scripts/kr8sswordz-pages.sh +++ b/scripts/kr8sswordz-pages.sh @@ -1,22 +1,22 @@ #!/bin/bash #Retrieve the latest git commit hash -TAG=`git rev-parse --short HEAD` +BUILD_TAG=`git rev-parse --short HEAD` #Build the docker image -docker build -t 127.0.0.1:30400/kr8sswordz:$TAG -f applications/kr8sswordz-pages/Dockerfile applications/kr8sswordz-pages +docker build -t 127.0.0.1:30400/kr8sswordz:$BUILD_TAG -f applications/kr8sswordz-pages/Dockerfile applications/kr8sswordz-pages #Setup the proxy for the registry -docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" +#docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" echo "5 second sleep to make sure the registry is ready" -sleep 5; +#sleep 5; #Push the images -docker push 127.0.0.1:30400/kr8sswordz:$TAG +docker push 127.0.0.1:30400/kr8sswordz:$BUILD_TAG #Stop the registry proxy -docker stop socat-registry +#docker stop socat-registry # Create the deployment and service for the front end aka kr8sswordz -sed 's#127.0.0.1:30400/kr8sswordz:latest#127.0.0.1:30400/kr8sswordz:'$TAG'#' applications/kr8sswordz-pages/k8s/deployment.yaml | kubectl apply -f - +sed 's#127.0.0.1:30400/kr8sswordz:$BUILD_TAG#127.0.0.1:30400/kr8sswordz:'$BUILD_TAG'#' applications/kr8sswordz-pages/k8s/deployment.yaml | kubectl apply -f - From 1cbc7e8dbd6f9773e889f15fa9677f965907fd70 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 15:38:31 -0600 Subject: [PATCH 57/89] fixed path error --- applications/kr8sswordz-pages/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/kr8sswordz-pages/Jenkinsfile b/applications/kr8sswordz-pages/Jenkinsfile index 6cd326fc4..cb1f506c1 100644 --- a/applications/kr8sswordz-pages/Jenkinsfile +++ b/applications/kr8sswordz-pages/Jenkinsfile @@ -23,5 +23,5 @@ node { stage "Deploy" - kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' + kubernetesDeploy configs: "applications/kr8sswordz-pages/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' } \ No newline at end of file From c1776a63e8f2611ef1bdc492194e3960dcf7a841 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 15:49:19 -0600 Subject: [PATCH 58/89] monitor-scale app update with tag var --- applications/monitor-scale/Jenkinsfile | 3 ++- applications/monitor-scale/k8s/deployment.yaml | 2 +- scripts/monitor-scale.sh | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/monitor-scale/Jenkinsfile b/applications/monitor-scale/Jenkinsfile index 2783d6c9f..936a2ddf8 100644 --- a/applications/monitor-scale/Jenkinsfile +++ b/applications/monitor-scale/Jenkinsfile @@ -11,6 +11,7 @@ node { registryHost = "127.0.0.1:30400/" imageName = "${registryHost}${appName}:${tag}" env.BUILDIMG=imageName + env.BUILD_TAG=tag stage "Build" @@ -22,5 +23,5 @@ node { stage "Deploy" - sh "sed 's#127.0.0.1:30400/monitor-scale:latest#'$BUILDIMG'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f -" + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' } \ No newline at end of file diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index c2e9754f0..6157aa707 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -75,7 +75,7 @@ spec: spec: serviceAccountName: monitor-scale containers: - - image: 127.0.0.1:30400/monitor-scale:latest + - image: 127.0.0.1:30400/monitor-scale:$BUILD_TAG name: monitor-scale imagePullPolicy: Always ports: diff --git a/scripts/monitor-scale.sh b/scripts/monitor-scale.sh index 9762212e2..fff33fa6f 100755 --- a/scripts/monitor-scale.sh +++ b/scripts/monitor-scale.sh @@ -1,10 +1,10 @@ #!/bin/bash #Retrieve the latest git commit hash -TAG=`git rev-parse --short HEAD` +BUILD_TAG=`git rev-parse --short HEAD` #Build the docker image -docker build -t 127.0.0.1:30400/monitor-scale:$TAG -f applications/monitor-scale/Dockerfile applications/monitor-scale +docker build -t 127.0.0.1:30400/monitor-scale:$BUILD_TAG -f applications/monitor-scale/Dockerfile applications/monitor-scale #Setup the proxy for the registry docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" @@ -13,10 +13,10 @@ echo "5 second sleep to make sure the registry is ready" sleep 5; #Push the images -docker push 127.0.0.1:30400/monitor-scale:$TAG +docker push 127.0.0.1:30400/monitor-scale:$BUILD_TAG #Stop the registry proxy docker stop socat-registry # Create the deployment and service for the monitor-scale node server -sed 's#127.0.0.1:30400/monitor-scale:latest#127.0.0.1:30400/monitor-scale:'$TAG'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - +sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'$BUILD_TAG'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - From 0b40f47f97c78525610c7317b15fd82337a55e78 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 16:03:10 -0600 Subject: [PATCH 59/89] monitor-scale service account config should not be part of the continuous deployment pipeline --- .../monitor-scale/k8s/deployment.yaml | 43 ------------------- manifests/monitor-scale-serviceaccount.yaml | 41 ++++++++++++++++++ 2 files changed, 41 insertions(+), 43 deletions(-) create mode 100644 manifests/monitor-scale-serviceaccount.yaml diff --git a/applications/monitor-scale/k8s/deployment.yaml b/applications/monitor-scale/k8s/deployment.yaml index 6157aa707..e5566c8b7 100644 --- a/applications/monitor-scale/k8s/deployment.yaml +++ b/applications/monitor-scale/k8s/deployment.yaml @@ -15,49 +15,6 @@ spec: --- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: monitor-scale - namespace: default - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - namespace: default - name: puzzle-scaler -rules: -- apiGroups: - - "extensions" - resources: - - deployments - - deployments/scale - resourceNames: - - "puzzle" - verbs: - - update - - get - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: monitor-scale-puzzle-scaler - namespace: default -roleRef: - kind: Role - name: puzzle-scaler - apiGroup: rbac.authorization.k8s.io -subjects: -- kind: ServiceAccount - name: monitor-scale - namespace: default - ---- - apiVersion: extensions/v1beta1 kind: Deployment metadata: diff --git a/manifests/monitor-scale-serviceaccount.yaml b/manifests/monitor-scale-serviceaccount.yaml new file mode 100644 index 000000000..962931a19 --- /dev/null +++ b/manifests/monitor-scale-serviceaccount.yaml @@ -0,0 +1,41 @@ + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: monitor-scale + namespace: default + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: default + name: puzzle-scaler +rules: +- apiGroups: + - "extensions" + resources: + - deployments + - deployments/scale + resourceNames: + - "puzzle" + verbs: + - update + - get + +--- + +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: monitor-scale-puzzle-scaler + namespace: default +roleRef: + kind: Role + name: puzzle-scaler + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: monitor-scale + namespace: default From b0514de9f0523170f96ba48d19507eab8b67df6e Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 21 Aug 2018 16:15:03 -0600 Subject: [PATCH 60/89] uncommented code on script --- scripts/kr8sswordz-pages.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/kr8sswordz-pages.sh b/scripts/kr8sswordz-pages.sh index 8f96745f9..42ce43f59 100755 --- a/scripts/kr8sswordz-pages.sh +++ b/scripts/kr8sswordz-pages.sh @@ -7,16 +7,16 @@ BUILD_TAG=`git rev-parse --short HEAD` docker build -t 127.0.0.1:30400/kr8sswordz:$BUILD_TAG -f applications/kr8sswordz-pages/Dockerfile applications/kr8sswordz-pages #Setup the proxy for the registry -#docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" +docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" echo "5 second sleep to make sure the registry is ready" -#sleep 5; +sleep 5; #Push the images docker push 127.0.0.1:30400/kr8sswordz:$BUILD_TAG #Stop the registry proxy -#docker stop socat-registry +docker stop socat-registry # Create the deployment and service for the front end aka kr8sswordz sed 's#127.0.0.1:30400/kr8sswordz:$BUILD_TAG#127.0.0.1:30400/kr8sswordz:'$BUILD_TAG'#' applications/kr8sswordz-pages/k8s/deployment.yaml | kubectl apply -f - From a6c8b14ad860f736fce6b61f046c60f40614af6a Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 23 Aug 2018 14:54:11 -0600 Subject: [PATCH 61/89] updated readme and scripts for part 1 --- README.md | 16 ++++++++++------ part1.yml | 7 +++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 05c44f25f..a487e9c02 100644 --- a/README.md +++ b/README.md @@ -109,29 +109,33 @@ Now let’s build an image, giving it a special name that points to our local cl #### Step12 -We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. - -`docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400"` +We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. so let's first build the image for such container: +`docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step13 +And run the proxy container from the newly created image: +``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` + +#### Step14 + With our proxy container up and running, we can now push our image to the local repository. `docker push 127.0.0.1:30400/hello-kenzan:latest` -#### Step14 +#### Step15 The proxy’s work is done, so you can go ahead and stop it. `docker stop socat-registry;` -#### Step15 +#### Step16 With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan pod based on the image. `kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml` -#### Step16 +#### Step17 Launch a web browser and view the service. diff --git a/part1.yml b/part1.yml index f6693a2d0..e2c8a4634 100644 --- a/part1.yml +++ b/part1.yml @@ -37,8 +37,11 @@ parts: - cap: Now let’s build an image, giving it a special name that points to our local cluster registry. com: docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan - - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" + - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. so let's first build the image for such container: + com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat + + - cap: And run the proxy container from the newly created image: + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry - cap: With our proxy container up and running, we can now push our image to the local repository. com: docker push 127.0.0.1:30400/hello-kenzan:latest From d57f54757d9f5ede1af2403fa789a6a242c9b1a4 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Thu, 23 Aug 2018 14:56:46 -0600 Subject: [PATCH 62/89] standardizing yaml file extensions --- README.md | 4 ++-- manifests/{registry.yml => registry.yaml} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename manifests/{registry.yml => registry.yaml} (100%) diff --git a/README.md b/README.md index a487e9c02..9592764f9 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,9 @@ Launch a web browser to test the service. The nginx welcome page displays, which #### Step7 -Set up the cluster registry by applying a .yml manifest file. +Set up the cluster registry by applying a .yaml manifest file. -`kubectl apply -f manifests/registry.yml` +`kubectl apply -f manifests/registry.yaml` #### Step8 diff --git a/manifests/registry.yml b/manifests/registry.yaml similarity index 100% rename from manifests/registry.yml rename to manifests/registry.yaml From d84bd81c0f2adf6908d67b065ee2213fb540f528 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 24 Aug 2018 16:05:24 -0600 Subject: [PATCH 63/89] updated readme and part 2 script with new instructions --- README.md | 92 +++++++++++++++++++---------------------- manifests/registry.yaml | 2 +- part2.yml | 50 ++++++++++++++++------ 3 files changed, 81 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 9592764f9..9df906ff9 100644 --- a/README.md +++ b/README.md @@ -99,8 +99,6 @@ View the registry user interface in a web browser. Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor (for example, you can use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. -`echo ''` - #### Step11 Now let’s build an image, giving it a special name that points to our local cluster registry. @@ -110,11 +108,13 @@ Now let’s build an image, giving it a special name that points to our local cl #### Step12 We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. so let's first build the image for such container: + `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step13 And run the proxy container from the newly created image: + ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` #### Step14 @@ -143,79 +143,94 @@ Launch a web browser and view the service. ## Part 2 + #### Step1 -Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. +First, Let's build the Jenkins docker image we'll use in our kubernetes cluster -`kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins` +`docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins` #### Step2 -Open the Jenkins UI in a web browser. +Once again we're going to need to set up the proxy container "Socat Registry" we used in part 1, so let's first build it in case it's not present in your local machine from part 1 anymore -`minikube service jenkins` +`docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step3 -Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT. +And run the proxy container from the newly created image -`kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /root/.jenkins/secrets/initialAdminPassword` +``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` #### Step4 -Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click "Install Suggested Plugins" button and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). +With our proxy container up and running, we can now push our Jenkins image to the local repository. -`echo ''` +`docker push 127.0.0.1:30400/hello-kenzan:latest` #### Step5 -Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. +The proxy’s work is done, so you can go ahead and stop it. -`echo ''` +`docker stop socat-registry;` #### Step6 -Before we create a pipeline, we first need to provision Kubernetes Continuous Deployment Plugin in Jenkins with a kubeconfig file that will allow access to our kubernetes cluster. Click on Credentials, then Jenkins store, then select the Global credentials Domain and add a new credential. +Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. -`echo ''` +`kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins` #### Step7 -The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. +Open the Jenkins UI in a web browser. -`echo ''` +`minikube service jenkins` #### Step8 -We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. +Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT. -`echo ''` +``kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword`` #### Step9 -Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". - -`echo ''` +Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click "Install Suggested Plugins" button and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). #### Step10 -Change the SCM to Git. - -`echo ''` +Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. #### Step11 -Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. - -`echo ''` +Before we create a pipeline, we first need to provision Kubernetes Continuous Deployment Plugin in Jenkins with a kubeconfig file that will allow access to our kubernetes cluster. On the left, click on Credentials, select Jenkins Store, then Global credentials (unrestricted), and Add Credentials on the left menu. #### Step12 +The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. + +#### Step13 + +We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. + +#### Step14 + +Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". + +#### Step15 + +Change the SCM to Git. + +#### Step16 + +Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. + +#### Step17 + Now view the Hello-Kenzan application. `minikube service hello-kenzan` -#### Step13 +#### Step18 Push a change to your fork. Run job again. View the changes. @@ -361,32 +376,22 @@ Enter the following command to open the Jenkins UI in a web browser. Log in to J We’ll want to create a new pipeline for the puzzle service that we previously deployed. On the left in Jenkins, click New Item. -`echo ''` - #### Step3 Enter the item name as "Puzzle-Service", click Pipeline, and click OK. -`echo ''` - #### Step4 Under the Build Triggers section, select Poll SCM. For the Schedule, enter the the string H/5 * * * * which will poll the Git repo every 5 minutes for changes. -`echo ''` - #### Step5 In the Pipeline section, change the Definition to "Pipeline script from SCM". Set the SCM property to GIT. Set the Repository URL to your forked repo (created in Part 2), such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd.git. Set the Script Path to applications/puzzle/Jenkinsfile -`echo ''` - #### Step6 When you are finished, click Save. On the left, click Build Now to run the new pipeline. You should see it successfully run through the build, push, and deploy steps in a few minutes. -`echo ''` - #### Step7 View the Kr8sswordz application. @@ -397,37 +402,26 @@ View the Kr8sswordz application. Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. -`echo ''` - #### Step9 Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. -`echo ''` - #### Step10 Commit and push the change to your forked Git repo. -`echo ''` - #### Step11 In Jenkins, open up the Puzzle-Service pipeline and wait until it triggers a build. It should trigger every 5 minutes. -`echo ''` - #### Step12 After it triggers, observe how the puzzle services disappear in the Kr8sswordz Puzzle app, and how new ones take their place. -`echo ''` - #### Step13 Try clicking Submit to test that hits now register as light green. -`echo ''` ## LICENSE Copyright 2017 Kenzan, LLC diff --git a/manifests/registry.yaml b/manifests/registry.yaml index c55092c91..d151919e8 100644 --- a/manifests/registry.yaml +++ b/manifests/registry.yaml @@ -87,7 +87,7 @@ spec: - containerPort: 5000 name: registry - name: registryui - image: hyper/docker-registry-web + image: hyper/docker-registry-web:latest ports: - containerPort: 8080 env: diff --git a/part2.yml b/part2.yml index e86d8b41e..dd17552a1 100644 --- a/part2.yml +++ b/part2.yml @@ -4,35 +4,59 @@ parts: intro: In this part we will Setup Jenkins, and setup an automated pipeline to build, push and deploy our custom appliction. steps: - - cap: Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. - com: kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins + - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources + com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 - - cap: Open the Jenkins UI in a web browser. + - cap: Let's build the Jenkins docker image we'll use in our kubernetes cluster + com: docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins + + - cap: Once again we're going to need to set up the proxy container "Socat Registry" we used in part 1, so let's first build it in case it's not present in your local machine from part 1 anymore + com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat + + - cap: And run the proxy container from the newly created image + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry + + - cap: With our proxy container up and running, we can now push our Jenkins image to the local repository. + com: docker push 127.0.0.1:30400/jenkins:latest + + - cap: The proxy’s work is done, so you can go ahead and stop it. + com: docker stop socat-registry; + + - cap: Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out + com: kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins + + - cap: Open the Jenkins UI in a web browser com: minikube service jenkins - - cap: Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT. - com: kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /root/.jenkins/secrets/initialAdminPassword + - cap: Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT + com: kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword - - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins and wait for the process to complete. + - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). com: echo '' - - cap: Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. + - cap: Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins + com: echo '' + + - cap: Before we create a pipeline, let's make the kubernetes cluster accessible from jenkins: On the left, click on Credentials, select Jenkins Store, then Global credentials (unrestricted), and Add Credentials on the left menu. + com: echo '' + + - cap: The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. com: echo '' - - cap: We now want to create a new pipeline for use with our Hello-Kenzan app. On the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. + - cap: We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, On the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK com: echo '' - - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". + - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM" com: echo '' - - cap: Change the SCM to Git. + - cap: Change the SCM to Git com: echo '' - - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. + - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline com: echo '' - - cap: Now view the Hello-Kenzan application. + - cap: Now view the Hello-Kenzan application com: minikube service hello-kenzan - - cap: Push a change to your fork. Run job again. View the changes. + - cap: Push a change to your fork. Run job again. View the changes com: minikube service hello-kenzan From 7a7e74f07124382ee033c2259b744834e0d0437c Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Mon, 27 Aug 2018 11:35:22 -0600 Subject: [PATCH 64/89] added sleep times to script to ensure services are available --- manifests/{jenkins.yml => jenkins.yaml} | 0 part2.yml | 9 ++++++--- steps.yml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) rename manifests/{jenkins.yml => jenkins.yaml} (100%) diff --git a/manifests/jenkins.yml b/manifests/jenkins.yaml similarity index 100% rename from manifests/jenkins.yml rename to manifests/jenkins.yaml diff --git a/part2.yml b/part2.yml index dd17552a1..e51afd274 100644 --- a/part2.yml +++ b/part2.yml @@ -4,8 +4,11 @@ parts: intro: In this part we will Setup Jenkins, and setup an automated pipeline to build, push and deploy our custom appliction. steps: - - cap: Start up the Kubernetes cluster with Minikube, giving it some extra resources - com: minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 + - cap: Start up the Kubernetes cluster with Minikube + com: minikube stop; minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 + + - cap: Before we do anything, let's make sure the private registry deployment we've setup in the previous part is available + com: kubectl rollout status deployment/registry; sleep 10 - cap: Let's build the Jenkins docker image we'll use in our kubernetes cluster com: docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins @@ -14,7 +17,7 @@ parts: com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - cap: And run the proxy container from the newly created image - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 10 - cap: With our proxy container up and running, we can now push our Jenkins image to the local repository. com: docker push 127.0.0.1:30400/jenkins:latest diff --git a/steps.yml b/steps.yml index a604c5a30..35ca6397a 100644 --- a/steps.yml +++ b/steps.yml @@ -57,7 +57,7 @@ parts: steps: - cap: Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. - com: kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins + com: kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins - cap: Open the Jenkins UI in a web browser. com: minikube service jenkins From fdce6dc3cf7f2309c143ba022fffae4fd9f7aa61 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Mon, 27 Aug 2018 14:15:39 -0600 Subject: [PATCH 65/89] go for it dude because fork that shit --- README.md | 51 +++++++++++++++------------- applications/hello-kenzan/index.html | 6 ++-- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 9592764f9..fb2c4d3ca 100644 --- a/README.md +++ b/README.md @@ -14,30 +14,14 @@ To get it up and running, see the following week-by-week Linux.com blog posts, o To generate this readme: `node readme.js` -## Interactive Tutorial Version -To complete the tutorial using the interactive script: - -* Clone this repository. +## Prerequisites +* Install VirtualBox +* Install the latest versions of Docker, Kubectl, and Minikube +* Clone this repository * To ensure you are starting with a clean slate: `minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` -* To run: `npm install` - -Begin the desired section: - -* `npm run part1` - -* `npm run part2` - -* `npm run part3` - -* `npm run part4` - - -## Manual Tutorial Version - -To complete the tutorial manually, follow the steps below. - +## Tutorial Steps ## Part 1 @@ -97,7 +81,7 @@ View the registry user interface in a web browser. #### Step10 -Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor (for example, you can use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. +Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor. (For example, you could use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. `echo ''` @@ -109,12 +93,14 @@ Now let’s build an image, giving it a special name that points to our local cl #### Step12 -We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. so let's first build the image for such container: +We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. + `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step13 -And run the proxy container from the newly created image: +Now run the proxy container from the newly created image. (Note that you may see some errors; this is normal as the commands are first making sure there are no previous instances running.) + ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` #### Step14 @@ -429,6 +415,23 @@ Try clicking Submit to test that hits now register as light green. `echo ''` + +## Automated Scripts to Run Tutorial +If you need to walk through the steps in the tutorial again (or more quickly), we’ve provided npm scripts that automate running the same commands in the separate parts of the Tutorial. + +- Install NodeJS. +- Install the scripts. + - `cd ~/kubernetes-ci-cd` + - `npm install` + +Begin the desired section: + +- `npm run part1` +- `npm run part2` +- `npm run part3` +- `npm run part4` + + ## LICENSE Copyright 2017 Kenzan, LLC diff --git a/applications/hello-kenzan/index.html b/applications/hello-kenzan/index.html index 1e9046561..d29d5307d 100644 --- a/applications/hello-kenzan/index.html +++ b/applications/hello-kenzan/index.html @@ -1,3 +1,3 @@ -

Hello from Kenzan! You've successfully built and run the Hello-Kenzan app.

-

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/part1/hello-kenzan/DockerFile, you will note several things:

- +

Hello from Ryan Patrick Daugherty! You've successfully built and run the Hello-Kenzan app.

+

The Hello-Kenzan app is a modified version of the nginx web server image. If you open up the kubernetes-ci-cd/hello-kenzan/DockerFile, you will note several things:

+ \ No newline at end of file From e830b9ca0c31a8b094f92e1bce521a09b1b231d6 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Tue, 28 Aug 2018 09:05:43 -0600 Subject: [PATCH 66/89] solved conflicts --- README.md | 37 +++++++++++++++++++++++-------------- part1.yml | 6 ++++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index fb2c4d3ca..610248966 100644 --- a/README.md +++ b/README.md @@ -61,77 +61,88 @@ Launch a web browser to test the service. The nginx welcome page displays, which `minikube service nginx` -#### Step7 +#### Step7 +Delete the nginx deployment and service you created. +`kubectl delete service nginx` +`kubectl delete deployment nginx` + +#### Step8 Set up the cluster registry by applying a .yaml manifest file. `kubectl apply -f manifests/registry.yaml` -#### Step8 +#### Step9 Wait for the registry to finish deploying. Note that this may take several minutes. `kubectl rollout status deployments/registry` -#### Step9 +#### Step10 View the registry user interface in a web browser. `minikube service registry-ui` -#### Step10 +#### Step11 Let’s make a change to an HTML file in the cloned project. Open the /applications/hello-kenzan/index.html file in your favorite text editor. (For example, you could use nano by running the command 'nano applications/hello-kenzan/index.html' in a separate terminal). Change some text inside one of the

tags. For example, change “Hello from Kenzan!” to “Hello from Me!”. Save the file. `echo ''` -#### Step11 +#### Step12 Now let’s build an image, giving it a special name that points to our local cluster registry. `docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan` -#### Step12 +#### Step13 We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` -#### Step13 +#### Step14 Now run the proxy container from the newly created image. (Note that you may see some errors; this is normal as the commands are first making sure there are no previous instances running.) ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` -#### Step14 +#### Step15 With our proxy container up and running, we can now push our image to the local repository. `docker push 127.0.0.1:30400/hello-kenzan:latest` -#### Step15 +#### Step16 The proxy’s work is done, so you can go ahead and stop it. `docker stop socat-registry;` -#### Step16 +#### Step17 With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan pod based on the image. `kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml` -#### Step17 +#### Step18 Launch a web browser and view the service. `minikube service hello-kenzan` +#### Step19 + +Delete the hello-kenzan deployment and service you created. +`kubectl delete service hello-kenzan` +`kubectl delete deployment hello-kenzan` + ## Part 2 #### Step1 -Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. +Deploy Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. `kubectl apply -f manifests/jenkins.yml; kubectl rollout status deployment/jenkins` @@ -151,8 +162,6 @@ Display the Jenkins admin password with the following command, and right-click t Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click "Install Suggested Plugins" button and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). -`echo ''` - #### Step5 Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. diff --git a/part1.yml b/part1.yml index e2c8a4634..e07f3242c 100644 --- a/part1.yml +++ b/part1.yml @@ -21,6 +21,9 @@ parts: - cap: Launch a web browser to test the service. The nginx welcome page displays, which means the service is up and running. com: minikube service nginx + + - cap: Delete the nginx deployment and service you created. + com: kubectl delete service nginx; kubectl delete deployment nginx - cap: Set up the cluster registry by applying a .yml manifest file. com: kubectl apply -f manifests/registry.yml @@ -54,3 +57,6 @@ parts: - cap: Launch a web browser and view the service. com: minikube service hello-kenzan + + - cap: Delete the hello-kenzan deployment and service you created. + com: kubectl delete service hello-kenzan; kubectl delete deployment hello-kenzan \ No newline at end of file From 9b28f6de10e9ea66d0e7c84a29b031889d6997bc Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 28 Aug 2018 14:37:23 -0600 Subject: [PATCH 67/89] updated step 3 with the latest commands --- README.md | 34 +++++++++++-------- .../{all-services.yml => all-services.yaml} | 0 part3.yml | 11 +++--- steps.yml | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) rename manifests/{all-services.yml => all-services.yaml} (100%) diff --git a/README.md b/README.md index 9df906ff9..980146d02 100644 --- a/README.md +++ b/README.md @@ -238,47 +238,53 @@ Push a change to your fork. Run job again. View the changes. ## Part 3 +### Initializing Helm will install Tiller (Helm's server) in our kubernetes cluster + +`helm init --wait --debug` +`kubectl rollout status deploy/tiller-deploy -n kube-system` + #### Step1 -Start the etcd operator and service on the cluster. You may notice errors showing up as it is waiting to start up the cluster. This is normal until it starts. +setup the etcd operator on the cluster using a Helm Chart -`scripts/etcd.sh` +`helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug --wait` #### Step2 -Now that we have an etcd service, we need an etcd client. The following command will set up a directory within etcd for storing key-value pairs, and then run the etcd client. +Create the etcd cluster -`kubectl create -f manifests/etcd-job.yml` +* `kubectl create -f manifests/etcd-cluster.yaml` +* `kubectl create -f manifests/etcd-service.yaml` #### Step3 -Check the status of the job in step 2 to make sure it deployed. +The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. -`kubectl describe jobs/etcd-job` +`kubectl apply -f manifests/all-services.yaml` #### Step4 -The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. +Now we're going to walk through an initial build of the monitor-scale service. -`kubectl apply -f manifests/all-services.yml` +``docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale`` #### Step5 -Now we're going to walk through an initial build of the monitor-scale service. +Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. so let's first build socat in case it's not present in your local machine from part 1 or 2 anymore -`docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale` +`docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step6 -Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. +And run the proxy container from the newly created image -`docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400"` +``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` #### Step7 Push the monitor-scale image to the registry. -`docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD`` +``docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` `` #### Step8 @@ -296,7 +302,7 @@ Open the registry UI and verify that the monitor-scale image is in our local reg Create the monitor-scale deployment and service. -`sed 's#127.0.0.1:30400/monitor-scale:latest#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f -` +``sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f -`` #### Step11 diff --git a/manifests/all-services.yml b/manifests/all-services.yaml similarity index 100% rename from manifests/all-services.yml rename to manifests/all-services.yaml diff --git a/part3.yml b/part3.yml index ab5c19796..c381f0ea3 100644 --- a/part3.yml +++ b/part3.yml @@ -8,13 +8,16 @@ parts: com: scripts/etcd.sh - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. - com: kubectl apply -f manifests/all-services.yml + com: kubectl apply -f manifests/all-services.yaml - cap: Now we're going to walk through an initial build of the monitor-scale service. com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale - - cap: Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" + - cap: Set up the Socat proxy once again, so we can push the monitor-scale Docker image we just built to our cluster's registry. So let's first build it in case it's not present in your local machine from part 1 anymore + com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat + + - cap: Run the proxy container from the newly created image + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 10 - cap: Push the monitor-scale image to the registry. com: docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` @@ -26,7 +29,7 @@ parts: com: minikube service registry-ui - cap: Create the monitor-scale deployment and service. - com: sed 's#127.0.0.1:30400/monitor-scale:latest#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - + com: sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - - cap: Wait for the monitor-scale deployment to finish. com: kubectl rollout status deployment/monitor-scale diff --git a/steps.yml b/steps.yml index 35ca6397a..24269a54c 100644 --- a/steps.yml +++ b/steps.yml @@ -103,7 +103,7 @@ parts: com: kubectl describe jobs/etcd-job - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. - com: kubectl apply -f manifests/all-services.yml + com: kubectl apply -f manifests/all-services.yaml - cap: Now we're going to walk through an initial build of the monitor-scale service. com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale From 22b35d7eab30e8369ada0e5c8f85edf111733aca Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 29 Aug 2018 10:35:31 -0600 Subject: [PATCH 68/89] changes to Readme Part 1 and 2 --- README.md | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0740cc3dd..b9ad4b7bc 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ Enable the Minikube add-ons Heapster and Ingress. #### Step3 -Wait 20 seconds, and then view the Minikube Dashboard, a web UI for managing deployments. +View the Minikube Dashboard, a web UI for managing deployments. -`sleep 20; minikube service kubernetes-dashboard --namespace kube-system` +`minikube service kubernetes-dashboard --namespace kube-system` #### Step4 @@ -141,19 +141,19 @@ Delete the hello-kenzan deployment and service you created. #### Step1 -First, Let's build the Jenkins docker image we'll use in our kubernetes cluster +First, let's build the Jenkins image we'll use in our Kubernetes cluster. `docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins` #### Step2 -Once again we're going to need to set up the proxy container "Socat Registry" we used in part 1, so let's first build it in case it's not present in your local machine from part 1 anymore +Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it (feel free to skip this step in case it already exists from Part 1). `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step3 -And run the proxy container from the newly created image +Run the proxy container from the image. ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` @@ -161,17 +161,17 @@ And run the proxy container from the newly created image With our proxy container up and running, we can now push our Jenkins image to the local repository. -`docker push 127.0.0.1:30400/hello-kenzan:latest` +`docker push 127.0.0.1:30400/jenkins:latest` #### Step5 The proxy’s work is done, so you can go ahead and stop it. -`docker stop socat-registry;` +`docker stop socat-registry` #### Step6 -Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. +Deploy Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. `kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins` @@ -183,41 +183,47 @@ Open the Jenkins UI in a web browser. #### Step8 -Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT. +Display the Jenkins admin password with the following command, and right-click to copy it. ``kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword`` #### Step9 -Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click "Install Suggested Plugins" button and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). +Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click **Install Suggested Plugins** and wait for the process to complete. Plugins have been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. #### Step10 -Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins. +Create an admin user and credentials, and click **Save and Continue**. (Make sure to remember these credentials as you will need them for repeated logins.) On the Instance Configuration page, click **Save and Finish**. On the next page, click **Restart** (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. #### Step11 -Before we create a pipeline, we first need to provision Kubernetes Continuous Deployment Plugin in Jenkins with a kubeconfig file that will allow access to our kubernetes cluster. On the left, click on Credentials, select Jenkins Store, then Global credentials (unrestricted), and Add Credentials on the left menu. +Before we create a pipeline, we first need to provision the Kubernetes Continuous Deploy plugin with a kubeconfig file that will allow access to our Kubernetes cluster. In Jenkins on the left, click on **Credentials**, select the **Jenkins** store, then **Global credentials (unrestricted)**, and **Add Credentials** on the left menu. #### Step12 -The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. +The following values must be entered precisely as indicated: +- Kind: `Kubernetes configuration (kubeconfig)` +- ID: `kenzan_kubeconfig` +- Kubeconfig: `From a file on the Jenkins master` +- specify the file path: `/var/jenkins_home/.kube/config` + +Finally click *Ok*. #### Step13 -We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. +We now want to create a new pipeline for use with our Hello-Kenzan app. Back on Jenkins home, on the left, click **New Item**. Enter the item name as "Hello-Kenzan Pipeline", select **Pipeline**, and click **OK**. #### Step14 -Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". +Under the Pipeline section at the bottom, change the **Definition** to be **Pipeline script from SCM**. #### Step15 -Change the SCM to Git. +Change the **SCM** to **Git**. #### Step16 -Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. +Change the **Repository URL** to be the URL of your forked Git repository, such as `https://github.com/[GIT USERNAME]/kubernetes-ci-cd`. Click **Save**. On the left, click **Build Now** to run the new pipeline. #### Step17 From 47194ad8188e1d782f2f43b799df69dfb899c96f Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Wed, 29 Aug 2018 15:07:07 -0600 Subject: [PATCH 69/89] replaced all references of chads socat image --- scripts/kr8sswordz-pages.sh | 2 +- scripts/kubescale.sh | 4 ++-- scripts/monitor-scale.sh | 2 +- scripts/puzzle.sh | 2 +- steps.yml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/kr8sswordz-pages.sh b/scripts/kr8sswordz-pages.sh index 42ce43f59..53ba0a1c1 100755 --- a/scripts/kr8sswordz-pages.sh +++ b/scripts/kr8sswordz-pages.sh @@ -7,7 +7,7 @@ BUILD_TAG=`git rev-parse --short HEAD` docker build -t 127.0.0.1:30400/kr8sswordz:$BUILD_TAG -f applications/kr8sswordz-pages/Dockerfile applications/kr8sswordz-pages #Setup the proxy for the registry -docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" +docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry echo "5 second sleep to make sure the registry is ready" sleep 5; diff --git a/scripts/kubescale.sh b/scripts/kubescale.sh index 65789f2af..d4d639ee7 100755 --- a/scripts/kubescale.sh +++ b/scripts/kubescale.sh @@ -30,7 +30,7 @@ kubectl exec -it example-etcd-cluster-0000 cat /mkd.sh # export MINIKUBEIP=`minikube ip` # #temp container for forwarding to registry -# docker run -d -e "MINIKUBEIP=$MINIKUBEIP" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:$MINIKUBEIP:30400" +# docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry # sleep 5 @@ -65,7 +65,7 @@ kubectl exec -it example-etcd-cluster-0000 cat /mkd.sh # proxy container for ingress -# docker run -d -e "MINIKUBEIP=$MINIKUBEIP" --name socat-minikube -p 80:80 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:80,fork,reuseaddr TCP4:$MINIKUBEIP:80" +# docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry # # kubectl apply -f k8s/ing.yml diff --git a/scripts/monitor-scale.sh b/scripts/monitor-scale.sh index fff33fa6f..d49d50d3f 100755 --- a/scripts/monitor-scale.sh +++ b/scripts/monitor-scale.sh @@ -7,7 +7,7 @@ BUILD_TAG=`git rev-parse --short HEAD` docker build -t 127.0.0.1:30400/monitor-scale:$BUILD_TAG -f applications/monitor-scale/Dockerfile applications/monitor-scale #Setup the proxy for the registry -docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" +docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry echo "5 second sleep to make sure the registry is ready" sleep 5; diff --git a/scripts/puzzle.sh b/scripts/puzzle.sh index 896146f82..827902afa 100755 --- a/scripts/puzzle.sh +++ b/scripts/puzzle.sh @@ -7,7 +7,7 @@ BUILD_TAG=`git rev-parse --short HEAD` docker build -t 127.0.0.1:30400/puzzle:$BUILD_TAG -f applications/puzzle/Dockerfile applications/puzzle #Setup the proxy for the registry -docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" +docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry echo "5 second sleep to make sure the registry is ready" sleep 5; diff --git a/steps.yml b/steps.yml index 24269a54c..b2b65c831 100644 --- a/steps.yml +++ b/steps.yml @@ -38,7 +38,7 @@ parts: com: docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 5 - cap: With our proxy container up and running, we can now push our image to the local repository. com: docker push 127.0.0.1:30400/hello-kenzan:latest @@ -109,7 +109,7 @@ parts: com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale - cap: Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. - com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REGIP=`minikube ip`" --name socat-registry -p 30400:5000 chadmoon/socat:latest bash -c "socat TCP4-LISTEN:5000,fork,reuseaddr TCP4:`minikube ip`:30400" + com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 5 - cap: Push the monitor-scale image to the registry. com: docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` From b93dd14fc67f1ef38ae3d8e36ef82239b469b3c2 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Fri, 31 Aug 2018 11:39:45 -0600 Subject: [PATCH 70/89] added missing step to monitor-scale script and fixed bad yaml indentation --- manifests/etcd-service.yaml | 2 +- scripts/monitor-scale.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/manifests/etcd-service.yaml b/manifests/etcd-service.yaml index b28a9aa43..fb49a4632 100644 --- a/manifests/etcd-service.yaml +++ b/manifests/etcd-service.yaml @@ -10,5 +10,5 @@ spec: - protocol: TCP port: 2379 targetPort: 2379 - nodePort: 32379 + nodePort: 32379 type: NodePort \ No newline at end of file diff --git a/scripts/monitor-scale.sh b/scripts/monitor-scale.sh index d49d50d3f..3474bfcb6 100755 --- a/scripts/monitor-scale.sh +++ b/scripts/monitor-scale.sh @@ -18,5 +18,8 @@ docker push 127.0.0.1:30400/monitor-scale:$BUILD_TAG #Stop the registry proxy docker stop socat-registry +# Setup RBAC auth for monitor-scale +kubectl apply -f manifests/monitor-scale-serviceaccount.yaml + # Create the deployment and service for the monitor-scale node server sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'$BUILD_TAG'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - From 8c53d85a3d7d1ba2db896d458e5d33bf3b477934 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 31 Aug 2018 15:24:31 -0600 Subject: [PATCH 71/89] updates to part 3 --- README.md | 73 +++++++++++++++++++++---------------- manifests/etcd-service.yaml | 2 +- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 769db38a4..0603580b1 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,9 @@ Launch a web browser to test the service. The nginx welcome page displays, which #### Step7 Delete the nginx deployment and service you created. + `kubectl delete service nginx` + `kubectl delete deployment nginx` #### Step8 @@ -133,7 +135,9 @@ Launch a web browser and view the service. #### Step19 Delete the hello-kenzan deployment and service you created. + `kubectl delete service hello-kenzan` + `kubectl delete deployment hello-kenzan` ## Part 2 @@ -239,133 +243,140 @@ Push a change to your fork. Run job again. View the changes. ## Part 3 -### Initializing Helm will install Tiller (Helm's server) in our kubernetes cluster +### Step1 -`helm init --wait --debug` -`kubectl rollout status deploy/tiller-deploy -n kube-system` +Initialize Helm. This will install Tiller (Helm's server) into our Kubernetes cluster. -#### Step1 +`helm init --wait --debug; kubectl rollout status deploy/tiller-deploy -n kube-system` + +#### Step2 -setup the etcd operator on the cluster using a Helm Chart +We will deploy the etcd operator onto the cluster using a Helm Chart. `helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug --wait` -#### Step2 +#### Step3 -Create the etcd cluster +Deploy the etcd cluster and K8s Services for accessing the cluster. * `kubectl create -f manifests/etcd-cluster.yaml` * `kubectl create -f manifests/etcd-service.yaml` -#### Step3 +#### Step4 -The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. +The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services ahead of time, so that the deployments are aware of them. `kubectl apply -f manifests/all-services.yaml` -#### Step4 +#### Step5 -Now we're going to walk through an initial build of the monitor-scale service. +Now we're going to walk through an initial build of the monitor-scale application. ``docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale`` -#### Step5 +#### Step6 -Set up a proxy so we can push the monitor-scale Docker image we just built to our cluster's registry. so let's first build socat in case it's not present in your local machine from part 1 or 2 anymore +Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it (feel free to skip this step in case it already exists from Parts 1 or 2). `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` -#### Step6 +#### Step7 -And run the proxy container from the newly created image +Run the proxy container from the newly created image. ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` -#### Step7 +#### Step8 Push the monitor-scale image to the registry. ``docker push 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` `` -#### Step8 +#### Step9 The proxy’s work is done, so go ahead and stop it. `docker stop socat-registry` -#### Step9 +#### Step10 Open the registry UI and verify that the monitor-scale image is in our local registry. `minikube service registry-ui` -#### Step10 +#### Step11 +The monitor-scale application is a used to scale instances of our puzzle application up and down, sending commands to our Kubernetes cluster. Because of this, we need to create a Service Account and Role (RBAC) so that monitor-scale has access to interact with the cluster. + + +`kubectl apply -f manifests/monitor-scale-serviceaccount.yaml` + +#### Step12 Create the monitor-scale deployment and service. ``sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f -`` -#### Step11 +#### Step13 Wait for the monitor-scale deployment to finish. `kubectl rollout status deployment/monitor-scale` -#### Step12 +#### Step14 View pods to see the monitor-scale pod running. `kubectl get pods` -#### Step13 +#### Step15 View services to see the monitor-scale service. `kubectl get services` -#### Step14 +#### Step16 View ingress rules to see the monitor-scale ingress rule. `kubectl get ingress` -#### Step15 +#### Step17 View deployments to see the monitor-scale deployment. `kubectl get deployments` -#### Step16 +#### Step18 We will run a script to bootstrap the puzzle and mongo services, creating Docker images and storing them in the local registry. The puzzle.sh script runs through the same build, proxy, push, and deploy steps we just ran through manually for both services. `scripts/puzzle.sh` -#### Step17 +#### Step19 Check to see if the puzzle and mongo services have been deployed. `kubectl rollout status deployment/puzzle` -#### Step18 +#### Step20 Bootstrap the kr8sswordz frontend web application. This script follows the same build proxy, push, and deploy steps that the other services followed. `scripts/kr8sswordz-pages.sh` -#### Step19 +#### Step21 Check to see if the frontend has been deployed. `kubectl rollout status deployment/kr8sswordz` -#### Step20 +#### Step22 -Check out all the pods that are running. +Check to see that all the pods are running. `kubectl get pods` -#### Step21 +#### Step23 Start the web application in your default browser. You may have to refresh your browser so that the puzzle appears properly. diff --git a/manifests/etcd-service.yaml b/manifests/etcd-service.yaml index b28a9aa43..fb49a4632 100644 --- a/manifests/etcd-service.yaml +++ b/manifests/etcd-service.yaml @@ -10,5 +10,5 @@ spec: - protocol: TCP port: 2379 targetPort: 2379 - nodePort: 32379 + nodePort: 32379 type: NodePort \ No newline at end of file From 42b7feef90f5b4a32449673059180cc1b9a7afe5 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 31 Aug 2018 15:35:00 -0600 Subject: [PATCH 72/89] change to kenzan.com --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0603580b1..cbf35d095 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan -The kubernetes-ci-cd project is [Kenzan's](http://techblog.kenzan.com/) crossword puzzle application that runs as several containers in Kubernetes (we call it the Kr8sswordz Puzzle). It showcases Kubernetes features like spinning up multiple pods and running a load test at scale. It also features Jenkins running on its own a container and a JenkinsFile script to demonstrate how Kubernetes can be integrated into a full CI/CD pipeline. +The kubernetes-ci-cd project is [Kenzan's](https://kenzan.com/) crossword puzzle application that runs as several containers in Kubernetes (we call it the Kr8sswordz Puzzle). It showcases Kubernetes features like spinning up multiple pods and running a load test at scale. It also features Jenkins running on its own a container and a JenkinsFile script to demonstrate how Kubernetes can be integrated into a full CI/CD pipeline. To get it up and running, see the following week-by-week Linux.com blog posts, or simply follow the directions below. From de86684fe1b7488f4822bc18c5c4827f45666481 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Tue, 4 Sep 2018 14:47:08 -0600 Subject: [PATCH 73/89] a few more changes to readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cbf35d095..9e2ac3441 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Deploy the public nginx image from DockerHub into a pod. Nginx is an open source #### Step5 -Create a service for deployment. This will expose the nginx pod so you can access it with a web browser. +Create a K8s Service for the deployment. This will expose the nginx pod so you can access it with a web browser. `kubectl expose deployment nginx --type NodePort --port 80` @@ -76,7 +76,7 @@ Set up the cluster registry by applying a .yaml manifest file. #### Step9 -Wait for the registry to finish deploying. Note that this may take several minutes. +Wait for the registry to finish deploying using the following command. Note that this may take several minutes. `kubectl rollout status deployments/registry` @@ -98,7 +98,7 @@ Now let’s build an image, giving it a special name that points to our local cl #### Step13 -We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. +We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a Docker container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` @@ -110,7 +110,7 @@ Now run the proxy container from the newly created image. (Note that you may see #### Step15 -With our proxy container up and running, we can now push our image to the local repository. +With our proxy container up and running, we can now push our hello-kenzan image to the local repository. `docker push 127.0.0.1:30400/hello-kenzan:latest` @@ -118,7 +118,7 @@ With our proxy container up and running, we can now push our image to the local The proxy’s work is done, so you can go ahead and stop it. -`docker stop socat-registry;` +`docker stop socat-registry` #### Step17 @@ -134,7 +134,7 @@ Launch a web browser and view the service. #### Step19 -Delete the hello-kenzan deployment and service you created. +Delete the hello-kenzan deployment and service you created. We are going to keep the registry deployment in our cluster as we will need it for the next few parts in our series. `kubectl delete service hello-kenzan` From 299bceecfbbe145a555df07dfa0119d2d4653c5a Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Tue, 4 Sep 2018 15:05:47 -0600 Subject: [PATCH 74/89] and more changes to readme --- README.md | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9e2ac3441..b797128e6 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,25 @@ To generate this readme: `node readme.js` ## Prerequisites -* Install VirtualBox -* Install the latest versions of Docker, Kubectl, and Minikube -* Clone this repository -* To ensure you are starting with a clean slate: `minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` +- Install VirtualBox + + https://www.virtualbox.org/wiki/Downloads + +- Install the latest versions of Docker, Minikube, and Kubectl + + https://docs.docker.com/docker-for-mac/install/ + https://github.com/kubernetes/minikube/releases + https://kubernetes.io/docs/tasks/tools/install-kubectl/ + +- Install Helm + + `curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh; chmod 700 get_helm.sh; ./get_helm.sh` + + +- Clone this repository +- To ensure you are starting with a clean slate, delete any previous minikube contexts. + + `minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` ## Tutorial Steps @@ -356,7 +371,8 @@ We will run a script to bootstrap the puzzle and mongo services, creating Docker Check to see if the puzzle and mongo services have been deployed. -`kubectl rollout status deployment/puzzle` +- `kubectl rollout status deployment/puzzle` +- `kubectl rollout status deployment/mongo` #### Step20 @@ -368,7 +384,7 @@ Bootstrap the kr8sswordz frontend web application. This script follows the same Check to see if the frontend has been deployed. -`kubectl rollout status deployment/kr8sswordz` +- `kubectl rollout status deployment/kr8sswordz` #### Step22 @@ -418,7 +434,7 @@ View the Kr8sswordz application. #### Step8 -Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. +Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the white hit does not register on the puzzle services. #### Step9 @@ -438,7 +454,7 @@ After it triggers, observe how the puzzle services disappear in the Kr8sswordz P #### Step13 -Try clicking Submit to test that hits now register as light green. +Try clicking Submit to test that hits now register as white. From c570a2685a6045a8bd53f87aca3d10f85bccf3fb Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 5 Sep 2018 09:21:45 -0600 Subject: [PATCH 75/89] slight wording change --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b797128e6..0f5f317b2 100644 --- a/README.md +++ b/README.md @@ -320,8 +320,7 @@ Open the registry UI and verify that the monitor-scale image is in our local reg `minikube service registry-ui` #### Step11 -The monitor-scale application is a used to scale instances of our puzzle application up and down, sending commands to our Kubernetes cluster. Because of this, we need to create a Service Account and Role (RBAC) so that monitor-scale has access to interact with the cluster. - +Monitor-scale has the functionality to let us scale our puzzle app up and down through the Kr8sswordz UI, therefore we'll need to do some RBAC work in order to provide monitor-scale with the proper rights. `kubectl apply -f manifests/monitor-scale-serviceaccount.yaml` From 37a48d4aa5421452844da94d6cd201e1fa1b7f55 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 5 Sep 2018 14:13:35 -0600 Subject: [PATCH 76/89] changes to scripts yo --- README.md | 4 ++-- part1.yml | 12 ++++++------ part2.yml | 36 ++++++++++++++++++------------------ part3.yml | 18 ++++++++++++------ part4.yml | 4 ++-- 5 files changed, 40 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 0f5f317b2..8bd55bb86 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Delete the hello-kenzan deployment and service you created. We are going to keep #### Step1 -First, let's build the Jenkins image we'll use in our Kubernetes cluster. +First, let's build the Jenkins Docker image we'll use in our Kubernetes cluster. `docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins` @@ -252,7 +252,7 @@ Now view the Hello-Kenzan application. #### Step18 -Push a change to your fork. Run job again. View the changes. +Push a change to your fork. Run the job again. View the changes. `minikube service hello-kenzan` diff --git a/part1.yml b/part1.yml index e07f3242c..48e759a32 100644 --- a/part1.yml +++ b/part1.yml @@ -16,7 +16,7 @@ parts: - cap: Deploy the public nginx image from DockerHub into a pod. Nginx is an open source web server that will automatically download from Docker Hub if it’s not available locally. com: kubectl run nginx --image nginx --port 80 - - cap: Create a service for deployment. This will expose the nginx pod so you can access it with a web browser. + - cap: Create a K8s Service for the deployment. This will expose the nginx pod so you can access it with a web browser. com: kubectl expose deployment nginx --type NodePort --port 80 - cap: Launch a web browser to test the service. The nginx welcome page displays, which means the service is up and running. @@ -25,8 +25,8 @@ parts: - cap: Delete the nginx deployment and service you created. com: kubectl delete service nginx; kubectl delete deployment nginx - - cap: Set up the cluster registry by applying a .yml manifest file. - com: kubectl apply -f manifests/registry.yml + - cap: Set up the cluster registry by applying a .yaml manifest file. + com: kubectl apply -f manifests/registry.yaml - cap: Wait for the registry to finish deploying. Note that this may take several minutes. com: kubectl rollout status deployments/registry @@ -40,13 +40,13 @@ parts: - cap: Now let’s build an image, giving it a special name that points to our local cluster registry. com: docker build -t 127.0.0.1:30400/hello-kenzan:latest -f applications/hello-kenzan/Dockerfile applications/hello-kenzan - - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a container that listens on 127.0.0.1:30400 and forwards to our cluster. so let's first build the image for such container: + - cap: We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a Docker container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - - cap: And run the proxy container from the newly created image: + - cap: Now run the proxy container from the newly created image. (Note that you may see some errors; this is normal as the commands are first making sure there are no previous instances running.) com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry - - cap: With our proxy container up and running, we can now push our image to the local repository. + - cap: With our proxy container up and running, we can now push our hello-kenzan image to the local repository. com: docker push 127.0.0.1:30400/hello-kenzan:latest - cap: The proxy’s work is done, so you can go ahead and stop it. diff --git a/part2.yml b/part2.yml index e51afd274..726a8690a 100644 --- a/part2.yml +++ b/part2.yml @@ -4,62 +4,62 @@ parts: intro: In this part we will Setup Jenkins, and setup an automated pipeline to build, push and deploy our custom appliction. steps: - - cap: Start up the Kubernetes cluster with Minikube + - cap: Start up the Kubernetes cluster with Minikube. com: minikube stop; minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 - - cap: Before we do anything, let's make sure the private registry deployment we've setup in the previous part is available + - cap: Before we do anything, let's make sure the private registry deployment we've setup in the previous part is available. com: kubectl rollout status deployment/registry; sleep 10 - - cap: Let's build the Jenkins docker image we'll use in our kubernetes cluster + - cap: Let's build the Jenkins Docker image we'll use in our Kubernetes cluster. com: docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins - - cap: Once again we're going to need to set up the proxy container "Socat Registry" we used in part 1, so let's first build it in case it's not present in your local machine from part 1 anymore + - cap: Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it in case it's not there from Part 1. com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - - cap: And run the proxy container from the newly created image + - cap: Run the proxy container from the image. com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 10 - cap: With our proxy container up and running, we can now push our Jenkins image to the local repository. com: docker push 127.0.0.1:30400/jenkins:latest - cap: The proxy’s work is done, so you can go ahead and stop it. - com: docker stop socat-registry; + com: docker stop socat-registry - - cap: Install Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out + - cap: Deploy Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. com: kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins - - cap: Open the Jenkins UI in a web browser + - cap: Open the Jenkins UI in a web browser. com: minikube service jenkins - cap: Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT com: kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword - - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins and wait for the process to complete (Plugins have been pre-downloaded during jenkins docker image built, so this step should finish almost immediately). + - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install Suggested Plugins and wait for the process to complete. Plugins have been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. com: echo '' - - cap: Create an admin user and credentials, and click Save and Finish. (Make sure to remember these credentials as you will need them for repeated logins.) Click Start using Jenkins + - cap: Create an admin user and credentials, and click Save and Continue. (Make sure to remember these credentials as you will need them for repeated logins.) On the Instance Configuration page, click Save and Finish. On the next page, click Restart (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. com: echo '' - - cap: Before we create a pipeline, let's make the kubernetes cluster accessible from jenkins: On the left, click on Credentials, select Jenkins Store, then Global credentials (unrestricted), and Add Credentials on the left menu. + - cap: Before we create a pipeline, we first need to provision the Kubernetes Continuous Deploy plugin with a kubeconfig file that will allow access to our Kubernetes cluster. In Jenkins on the left, click on **Credentials**, select the **Jenkins** store, then **Global credentials (unrestricted)**, and **Add Credentials** on the left menu. com: echo '' - - cap: The following values must be entered precisely as indicated: For the Kind field select the option "Kubernetes configuration (kubeconfig)", set the ID as `kenzan_kubeconfig`, select Kubeconfig From a file on the Jenkins master, and specify the the file path `/var/jenkins_home/.kube/config`. finally click the OK button. + - cap: The following values must be entered precisely as indicated: for the Kind field select the option `Kubernetes configuration (kubeconfig)`, set the ID as `kenzan_kubeconfig`, set Kubeconfig to `From a file on the Jenkins master`, and specify the the file path as `/var/jenkins_home/.kube/config`. Click the OK button. com: echo '' - - cap: We now want to create a new pipeline for use with our Hello-Kenzan app. Back from Jenkins home, On the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK + - cap: We now want to create a new pipeline for use with our Hello-Kenzan app. Back on Jenkins home, on the left, click New Item. Enter the item name as "Hello-Kenzan Pipeline", select Pipeline, and click OK. com: echo '' - - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM" + - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". com: echo '' - - cap: Change the SCM to Git + - cap: Change the SCM to Git. com: echo '' - - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline + - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. com: echo '' - - cap: Now view the Hello-Kenzan application + - cap: Now view the Hello-Kenzan application. com: minikube service hello-kenzan - - cap: Push a change to your fork. Run job again. View the changes + - cap: Push a change to your fork. Run the job again. View the changes. com: minikube service hello-kenzan diff --git a/part3.yml b/part3.yml index c381f0ea3..6d4797d61 100644 --- a/part3.yml +++ b/part3.yml @@ -3,20 +3,26 @@ parts: - name: Part 3 intro: This part will have us setup the various applications that will present the crossword puzzle. We will run a sample etcd cluster as a cache, a pages application containing the front-end, a crossword server using mongodb, and a monitoring and scaling server application. steps: + + - cap: Initialize Helm. This will install Tiller (Helm's server) into our Kubernetes cluster. + com: helm init --wait --debug; kubectl rollout status deploy/tiller-deploy -n kube-system - - cap: Start the etcd operator and service on the cluster. You may notice errors showing up as it is waiting to start up the cluster. This is normal until it starts. - com: scripts/etcd.sh + - cap: We will deploy the etcd operator onto the cluster using a Helm Chart. + com: helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug --wait + + - cap: Deploy the etcd cluster and K8s Services for accessing the cluster. + com: kubectl create -f manifests/etcd-cluster.yaml; kubectl create -f manifests/etcd-service.yaml - - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three services in Kubernetes ahead of time, so that the deployments are aware of them. + - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services ahead of time, so that the deployments are aware of them. com: kubectl apply -f manifests/all-services.yaml - cap: Now we're going to walk through an initial build of the monitor-scale service. com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale - - cap: Set up the Socat proxy once again, so we can push the monitor-scale Docker image we just built to our cluster's registry. So let's first build it in case it's not present in your local machine from part 1 anymore + - cap: Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it in case it's not there from Part 1. com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - - cap: Run the proxy container from the newly created image + - cap: Run the proxy container from the newly created image. com: docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry; sleep 10 - cap: Push the monitor-scale image to the registry. @@ -50,7 +56,7 @@ parts: com: scripts/puzzle.sh - cap: Check to see if the puzzle and mongo services have been deployed. - com: kubectl rollout status deployment/puzzle + com: kubectl rollout status deployment/puzzle; kubectl rollout status deployment/mongo - cap: Bootstrap the kr8sswordz frontend web application. This script follows the same build proxy, push, and deploy steps that the other services followed. com: scripts/kr8sswordz-pages.sh diff --git a/part4.yml b/part4.yml index 49c110512..ce7eda27f 100644 --- a/part4.yml +++ b/part4.yml @@ -25,7 +25,7 @@ parts: - cap: View the Kr8sswordz application. com: minikube service kr8sswordz - - cap: Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the green hit does not register on the puzzle services. + - cap: Spin up several instances of the puzzle service by moving the slider to the right and clicking Scale. For reference, click on the Submit button, noting that the white hit does not register on the puzzle services. com: echo '' - cap: Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. @@ -40,5 +40,5 @@ parts: - cap: After it triggers, observe how the puzzle services disappear in the Kr8sswordz Puzzle app, and how new ones take their place. com: echo '' - - cap: Try clicking Submit to test that hits now register as light green. + - cap: Try clicking Submit to test that hits now register as white. com: echo '' From 4bd52316fa9564d4da81a2f115a58c999ab737a9 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 5 Sep 2018 14:14:14 -0600 Subject: [PATCH 77/89] oops forgot to save --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bd55bb86..96540fdd8 100644 --- a/README.md +++ b/README.md @@ -274,8 +274,8 @@ We will deploy the etcd operator onto the cluster using a Helm Chart. Deploy the etcd cluster and K8s Services for accessing the cluster. -* `kubectl create -f manifests/etcd-cluster.yaml` -* `kubectl create -f manifests/etcd-service.yaml` +* `kubectl create -f manifests/etcd-cluster.yaml` +* `kubectl create -f manifests/etcd-service.yaml` #### Step4 From 09d4ab7a0ef99528fe9b5d737de7cac992948cf1 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 5 Sep 2018 16:44:14 -0600 Subject: [PATCH 78/89] even more changes --- README.md | 4 ++-- part2.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 96540fdd8..0b5052bc7 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ First, let's build the Jenkins Docker image we'll use in our Kubernetes cluster. #### Step2 -Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it (feel free to skip this step in case it already exists from Part 1). +Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 1 (to check, run `docker images`). `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` @@ -208,7 +208,7 @@ Display the Jenkins admin password with the following command, and right-click t #### Step9 -Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click **Install Suggested Plugins** and wait for the process to complete. Plugins have been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. +Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click **Install suggested plugins**. Plugins have actually been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. #### Step10 diff --git a/part2.yml b/part2.yml index 726a8690a..3f9484794 100644 --- a/part2.yml +++ b/part2.yml @@ -34,13 +34,13 @@ parts: - cap: Display the Jenkins admin password with the following command, and right-click to copy it. IMPORTANT: BE CAREFUL NOT TO PRESS CTRL-C TO COPY THE PASSWORD AS THIS WILL STOP THE SCRIPT com: kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword - - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install Suggested Plugins and wait for the process to complete. Plugins have been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. + - cap: Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click Install suggested plugins. Plugins have actually been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. com: echo '' - cap: Create an admin user and credentials, and click Save and Continue. (Make sure to remember these credentials as you will need them for repeated logins.) On the Instance Configuration page, click Save and Finish. On the next page, click Restart (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. com: echo '' - - cap: Before we create a pipeline, we first need to provision the Kubernetes Continuous Deploy plugin with a kubeconfig file that will allow access to our Kubernetes cluster. In Jenkins on the left, click on **Credentials**, select the **Jenkins** store, then **Global credentials (unrestricted)**, and **Add Credentials** on the left menu. + - cap: Before we create a pipeline, we first need to provision the Kubernetes Continuous Deploy plugin with a kubeconfig file that will allow access to our Kubernetes cluster. In Jenkins on the left, click on Credentials, select the Jenkins store, then Global credentials (unrestricted), and Add Credentials on the left menu. com: echo '' - cap: The following values must be entered precisely as indicated: for the Kind field select the option `Kubernetes configuration (kubeconfig)`, set the ID as `kenzan_kubeconfig`, set Kubeconfig to `From a file on the Jenkins master`, and specify the the file path as `/var/jenkins_home/.kube/config`. Click the OK button. From b9671fc7ea31a67ec07ede20792b2dd472d38578 Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Thu, 6 Sep 2018 12:42:58 -0600 Subject: [PATCH 79/89] more more --- README.md | 2 +- part3.yml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b5052bc7..0798d5980 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ To generate this readme: `node readme.js` - Clone this repository - To ensure you are starting with a clean slate, delete any previous minikube contexts. - `minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` + `minikube stop; minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` ## Tutorial Steps diff --git a/part3.yml b/part3.yml index 6d4797d61..284e6a007 100644 --- a/part3.yml +++ b/part3.yml @@ -33,6 +33,9 @@ parts: - cap: Open the registry UI and verify that the monitor-scale image is in our local registry. com: minikube service registry-ui + + - cap: Monitor-scale has the functionality to let us scale our puzzle app up and down through the Kr8sswordz UI, therefore we'll need to do some RBAC work in order to provide monitor-scale with the proper rights. + com: kubectl apply -f manifests/monitor-scale-serviceaccount.yaml - cap: Create the monitor-scale deployment and service. com: sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - From 79fd7de2050e03c0e84fc0b6cd1325a5cc0bea5f Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Fri, 7 Sep 2018 14:50:34 -0600 Subject: [PATCH 80/89] ILOVEU --- README.md | 6 +++--- part2.yml | 2 +- part3.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0798d5980..43283366b 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ Deploy the etcd cluster and K8s Services for accessing the cluster. #### Step4 -The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services ahead of time, so that the deployments are aware of them. +The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services so that the applications can communicate with one another. `kubectl apply -f manifests/all-services.yaml` @@ -291,7 +291,7 @@ Now we're going to walk through an initial build of the monitor-scale applicatio #### Step6 -Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it (feel free to skip this step in case it already exists from Parts 1 or 2). +Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 2 (to check, run `docker images`). `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` @@ -326,7 +326,7 @@ Monitor-scale has the functionality to let us scale our puzzle app up and down t #### Step12 -Create the monitor-scale deployment and service. +Create the monitor-scale deployment and the Ingress defining the hostname by which this service will be accessible to the other services. ``sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f -`` diff --git a/part2.yml b/part2.yml index 3f9484794..b25f4903c 100644 --- a/part2.yml +++ b/part2.yml @@ -13,7 +13,7 @@ parts: - cap: Let's build the Jenkins Docker image we'll use in our Kubernetes cluster. com: docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins - - cap: Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it in case it's not there from Part 1. + - cap: Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 1 (to check, run `docker images` in a separate terminal). com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - cap: Run the proxy container from the image. diff --git a/part3.yml b/part3.yml index 284e6a007..d0191de8e 100644 --- a/part3.yml +++ b/part3.yml @@ -13,13 +13,13 @@ parts: - cap: Deploy the etcd cluster and K8s Services for accessing the cluster. com: kubectl create -f manifests/etcd-cluster.yaml; kubectl create -f manifests/etcd-service.yaml - - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services ahead of time, so that the deployments are aware of them. + - cap: The crossword application is a multi-tier application whose services depend on each other. We will create three K8s Services so that the applications can communicate with one another. com: kubectl apply -f manifests/all-services.yaml - cap: Now we're going to walk through an initial build of the monitor-scale service. com: docker build -t 127.0.0.1:30400/monitor-scale:`git rev-parse --short HEAD` -f applications/monitor-scale/Dockerfile applications/monitor-scale - - cap: Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it in case it's not there from Part 1. + - cap: Once again we'll need to set up the Socat Registry proxy container to push the monitor-scale image to our registry, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 2 (to check, run `docker images` in a separate terminal). com: docker build -t socat-registry -f applications/socat/Dockerfile applications/socat - cap: Run the proxy container from the newly created image. @@ -37,7 +37,7 @@ parts: - cap: Monitor-scale has the functionality to let us scale our puzzle app up and down through the Kr8sswordz UI, therefore we'll need to do some RBAC work in order to provide monitor-scale with the proper rights. com: kubectl apply -f manifests/monitor-scale-serviceaccount.yaml - - cap: Create the monitor-scale deployment and service. + - cap: Create the monitor-scale deployment and the Ingress defining the hostname by which this service will be accessible to the other services. com: sed 's#127.0.0.1:30400/monitor-scale:$BUILD_TAG#127.0.0.1:30400/monitor-scale:'`git rev-parse --short HEAD`'#' applications/monitor-scale/k8s/deployment.yaml | kubectl apply -f - - cap: Wait for the monitor-scale deployment to finish. From 4d1f65da6cb5af62cbf3de1aca3847a9f3b117a6 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 11 Sep 2018 11:25:36 -0600 Subject: [PATCH 81/89] updated mountPath for Jenkins volume to point to the right Jenkins_home folder --- manifests/jenkins.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/jenkins.yaml b/manifests/jenkins.yaml index 371f6e6cb..15d37c49f 100644 --- a/manifests/jenkins.yaml +++ b/manifests/jenkins.yaml @@ -124,7 +124,7 @@ spec: - name: docker mountPath: /var/run/docker.sock - name: jenkins-persistent-storage - mountPath: /root/.jenkins + mountPath: /var/jenkins_home ports: - containerPort: 8080 name: jenkins From cc18aa908dbc9418fc0e2fcf72b8044223508ebf Mon Sep 17 00:00:00 2001 From: Ryan Daugherty Date: Wed, 12 Sep 2018 10:53:15 -0600 Subject: [PATCH 82/89] Updated readme and scripts --- README.md | 12 ++++-------- part1.yml | 4 ++-- part2.yml | 9 +++------ part4.yml | 2 +- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 43283366b..e6afcd719 100644 --- a/README.md +++ b/README.md @@ -238,19 +238,15 @@ Under the Pipeline section at the bottom, change the **Definition** to be **Pipe #### Step15 -Change the **SCM** to **Git**. +Change the **SCM** to **Git**. Change the **Repository URL** to be the URL of your forked Git repository, such as `https://github.com/[GIT USERNAME]/kubernetes-ci-cd`. Click **Save**. On the left, click **Build Now** to run the new pipeline. #### Step16 -Change the **Repository URL** to be the URL of your forked Git repository, such as `https://github.com/[GIT USERNAME]/kubernetes-ci-cd`. Click **Save**. On the left, click **Build Now** to run the new pipeline. - -#### Step17 - -Now view the Hello-Kenzan application. +After all pipeline stages are colored green as complete, view the Hello-Kenzan application. `minikube service hello-kenzan` -#### Step18 +#### Step17 Push a change to your fork. Run the job again. View the changes. @@ -423,7 +419,7 @@ In the Pipeline section, change the Definition to "Pipeline script from SCM". Se #### Step6 -When you are finished, click Save. On the left, click Build Now to run the new pipeline. You should see it successfully run through the build, push, and deploy steps in a few minutes. +When you are finished, click Save. On the left, click Build Now to run the new pipeline. This will rebuild the image from the registry, and redeploy the puzzle pod. You should see it successfully run through the build, push, and deploy steps in a few minutes. #### Step7 diff --git a/part1.yml b/part1.yml index 48e759a32..aefa94bab 100644 --- a/part1.yml +++ b/part1.yml @@ -10,8 +10,8 @@ parts: - cap: Enable the Minikube add-ons Heapster and Ingress. com: minikube addons enable heapster; minikube addons enable ingress - - cap: Wait 20 seconds, and then view the Minikube Dashboard, a web UI for managing deployments. - com: sleep 20; minikube service kubernetes-dashboard --namespace kube-system + - cap: View the Minikube Dashboard, a web UI for managing deployments. + com: minikube service kubernetes-dashboard --namespace kube-system - cap: Deploy the public nginx image from DockerHub into a pod. Nginx is an open source web server that will automatically download from Docker Hub if it’s not available locally. com: kubectl run nginx --image nginx --port 80 diff --git a/part2.yml b/part2.yml index b25f4903c..a156fc27f 100644 --- a/part2.yml +++ b/part2.yml @@ -8,7 +8,7 @@ parts: com: minikube stop; minikube start --memory 8000 --cpus 2 --kubernetes-version v1.11.0 - cap: Before we do anything, let's make sure the private registry deployment we've setup in the previous part is available. - com: kubectl rollout status deployment/registry; sleep 10 + com: kubectl rollout status deployment/registry - cap: Let's build the Jenkins Docker image we'll use in our Kubernetes cluster. com: docker build -t 127.0.0.1:30400/jenkins:latest -f applications/jenkins/Dockerfile applications/jenkins @@ -52,13 +52,10 @@ parts: - cap: Under the Pipeline section at the bottom, change the Definition to be "Pipeline script from SCM". com: echo '' - - cap: Change the SCM to Git. + - cap: Change the SCM to Git. Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. com: echo '' - - cap: Change the Repository URL to be the URL of your forked Git repository, such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd. Click Save. On the left, click Build Now to run the new pipeline. - com: echo '' - - - cap: Now view the Hello-Kenzan application. + - cap: After all pipeline stages are colored green as complete, view the Hello-Kenzan application. com: minikube service hello-kenzan - cap: Push a change to your fork. Run the job again. View the changes. diff --git a/part4.yml b/part4.yml index ce7eda27f..cf6d21bb3 100644 --- a/part4.yml +++ b/part4.yml @@ -19,7 +19,7 @@ parts: - cap: In the Pipeline section, change the Definition to "Pipeline script from SCM". Set the SCM property to GIT. Set the Repository URL to your forked repo (created in Part 2), such as https://github.com/[GIT USERNAME]/kubernetes-ci-cd.git. Set the Script Path to applications/puzzle/Jenkinsfile com: echo '' - - cap: When you are finished, click Save. On the left, click Build Now to run the new pipeline. You should see it successfully run through the build, push, and deploy steps in a few minutes. + - cap: When you are finished, click Save. On the left, click Build Now to run the new pipeline. This will rebuild the image from the registry, and redeploy the puzzle pod. You should see it successfully run through the build, push, and deploy steps in a few minutes. com: echo '' - cap: View the Kr8sswordz application. From c607f34decb05f16bfae8e91120237430f3e86eb Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Wed, 12 Sep 2018 13:18:55 -0600 Subject: [PATCH 83/89] standardize readme formatting --- README.md | 68 +++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index e6afcd719..0e2d345e9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Linux.com Kubernetes CI/CD Blog Series by Kenzan -The kubernetes-ci-cd project is [Kenzan's](https://kenzan.com/) crossword puzzle application that runs as several containers in Kubernetes (we call it the Kr8sswordz Puzzle). It showcases Kubernetes features like spinning up multiple pods and running a load test at scale. It also features Jenkins running on its own a container and a JenkinsFile script to demonstrate how Kubernetes can be integrated into a full CI/CD pipeline. +The kubernetes-ci-cd project is [Kenzan's](https://kenzan.com/) crossword puzzle application that runs as several containers in Kubernetes (we call it the Kr8sswordz Puzzle). It showcases Kubernetes features like spinning up multiple pods and running a load test at scale. It also features Jenkins running on its own a container and a JenkinsFile script to demonstrate how Kubernetes can be integrated into a full CI/CD pipeline. -To get it up and running, see the following week-by-week Linux.com blog posts, or simply follow the directions below. +To get it up and running, see the following week-by-week Linux.com blog posts, or simply follow the directions below. [Linux.com Part 1](https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview) @@ -14,9 +14,9 @@ To get it up and running, see the following week-by-week Linux.com blog posts, o To generate this readme: `node readme.js` -## Prerequisites +## Prerequisites -- Install VirtualBox +- Install VirtualBox https://www.virtualbox.org/wiki/Downloads @@ -26,13 +26,12 @@ To generate this readme: `node readme.js` https://github.com/kubernetes/minikube/releases https://kubernetes.io/docs/tasks/tools/install-kubectl/ -- Install Helm +- Install Helm `curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh; chmod 700 get_helm.sh; ./get_helm.sh` - - Clone this repository -- To ensure you are starting with a clean slate, delete any previous minikube contexts. +- To ensure you are starting with a clean slate, delete any previous minikube contexts. `minikube stop; minikube delete; sudo rm -rf ~/.minikube; sudo rm -rf ~/.kube` @@ -76,8 +75,9 @@ Launch a web browser to test the service. The nginx welcome page displays, which `minikube service nginx` -#### Step7 -Delete the nginx deployment and service you created. +#### Step7 + +Delete the nginx deployment and service you created. `kubectl delete service nginx` @@ -113,7 +113,7 @@ Now let’s build an image, giving it a special name that points to our local cl #### Step13 -We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a Docker container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. +We’ve built the image, but before we can push it to the registry, we need to set up a temporary proxy. By default the Docker client can only push to HTTP (not HTTPS) via localhost. To work around this, we’ll set up a Docker container that listens on 127.0.0.1:30400 and forwards to our cluster. First, build the image for our proxy container. `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` @@ -157,7 +157,6 @@ Delete the hello-kenzan deployment and service you created. We are going to keep ## Part 2 - #### Step1 First, let's build the Jenkins Docker image we'll use in our Kubernetes cluster. @@ -166,13 +165,13 @@ First, let's build the Jenkins Docker image we'll use in our Kubernetes cluster. #### Step2 -Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 1 (to check, run `docker images`). +Once again we'll need to set up the Socat Registry proxy container to push images, so let's build it. Feel free to skip this step in case the socat-registry image already exists from Part 1 (to check, run `docker images`). `docker build -t socat-registry -f applications/socat/Dockerfile applications/socat` #### Step3 -Run the proxy container from the image. +Run the proxy container from the image. ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` @@ -202,17 +201,17 @@ Open the Jenkins UI in a web browser. #### Step8 -Display the Jenkins admin password with the following command, and right-click to copy it. +Display the Jenkins admin password with the following command, and right-click to copy it. ``kubectl exec -it `kubectl get pods --selector=app=jenkins --output=jsonpath={.items..metadata.name}` cat /var/jenkins_home/secrets/initialAdminPassword`` #### Step9 -Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click **Install suggested plugins**. Plugins have actually been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. +Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click Continue. Click **Install suggested plugins**. Plugins have actually been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly. #### Step10 -Create an admin user and credentials, and click **Save and Continue**. (Make sure to remember these credentials as you will need them for repeated logins.) On the Instance Configuration page, click **Save and Finish**. On the next page, click **Restart** (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. +Create an admin user and credentials, and click **Save and Continue**. (Make sure to remember these credentials as you will need them for repeated logins.) On the Instance Configuration page, click **Save and Finish**. On the next page, click **Restart** (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. #### Step11 @@ -220,7 +219,7 @@ Before we create a pipeline, we first need to provision the Kubernetes Continuou #### Step12 -The following values must be entered precisely as indicated: +The following values must be entered precisely as indicated: - Kind: `Kubernetes configuration (kubeconfig)` - ID: `kenzan_kubeconfig` - Kubeconfig: `From a file on the Jenkins master` @@ -254,24 +253,24 @@ Push a change to your fork. Run the job again. View the changes. ## Part 3 -### Step1 +### Step1 -Initialize Helm. This will install Tiller (Helm's server) into our Kubernetes cluster. +Initialize Helm. This will install Tiller (Helm's server) into our Kubernetes cluster. `helm init --wait --debug; kubectl rollout status deploy/tiller-deploy -n kube-system` #### Step2 -We will deploy the etcd operator onto the cluster using a Helm Chart. +We will deploy the etcd operator onto the cluster using a Helm Chart. `helm install stable/etcd-operator --version 0.8.0 --name etcd-operator --debug --wait` #### Step3 -Deploy the etcd cluster and K8s Services for accessing the cluster. +Deploy the etcd cluster and K8s Services for accessing the cluster. -* `kubectl create -f manifests/etcd-cluster.yaml` -* `kubectl create -f manifests/etcd-service.yaml` +- `kubectl create -f manifests/etcd-cluster.yaml` +- `kubectl create -f manifests/etcd-service.yaml` #### Step4 @@ -293,7 +292,7 @@ Once again we'll need to set up the Socat Registry proxy container to push the m #### Step7 -Run the proxy container from the newly created image. +Run the proxy container from the newly created image. ``docker stop socat-registry; docker rm socat-registry; docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" --name socat-registry -p 30400:5000 socat-registry`` @@ -316,7 +315,8 @@ Open the registry UI and verify that the monitor-scale image is in our local reg `minikube service registry-ui` #### Step11 -Monitor-scale has the functionality to let us scale our puzzle app up and down through the Kr8sswordz UI, therefore we'll need to do some RBAC work in order to provide monitor-scale with the proper rights. + +Monitor-scale has the functionality to let us scale our puzzle app up and down through the Kr8sswordz UI, therefore we'll need to do some RBAC work in order to provide monitor-scale with the proper rights. `kubectl apply -f manifests/monitor-scale-serviceaccount.yaml` @@ -379,7 +379,7 @@ Bootstrap the kr8sswordz frontend web application. This script follows the same Check to see if the frontend has been deployed. -- `kubectl rollout status deployment/kr8sswordz` +`kubectl rollout status deployment/kr8sswordz` #### Step22 @@ -433,7 +433,7 @@ Spin up several instances of the puzzle service by moving the slider to the righ #### Step9 -Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. +Edit applications/puzzle/common/models/crossword.js in your favorite text editor (for example, you can use nano by running the command 'nano applications/puzzle/common/models/crossword.js' in a separate terminal). You'll see a commented section on lines 42-43 that indicates to uncomment a specific line. Uncomment line 43 by deleting the forward slashes and save the file. #### Step10 @@ -452,12 +452,12 @@ After it triggers, observe how the puzzle services disappear in the Kr8sswordz P Try clicking Submit to test that hits now register as white. - ## Automated Scripts to Run Tutorial + If you need to walk through the steps in the tutorial again (or more quickly), we’ve provided npm scripts that automate running the same commands in the separate parts of the Tutorial. -- Install NodeJS. -- Install the scripts. +- Install NodeJS. +- Install the scripts. - `cd ~/kubernetes-ci-cd` - `npm install` @@ -468,18 +468,18 @@ Begin the desired section: - `npm run part3` - `npm run part4` +## LICENSE - ## LICENSE Copyright 2017 Kenzan, LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. +limitations under the License. \ No newline at end of file From 5ef254035ca51d403c846734ad0f9ec83c4f5aa3 Mon Sep 17 00:00:00 2001 From: David Zuluaga Date: Tue, 27 Nov 2018 15:38:45 -0700 Subject: [PATCH 84/89] duplicate deploy manifest for part1 and update existing manifest with tag for part2 --- README.md | 2 +- applications/hello-kenzan/k8s/deployment.yaml | 2 +- .../hello-kenzan/k8s/manual-deployment.yaml | 37 +++++++++++++++++++ part1.yml | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 applications/hello-kenzan/k8s/manual-deployment.yaml diff --git a/README.md b/README.md index 0e2d345e9..02ba74889 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ The proxy’s work is done, so you can go ahead and stop it. With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan pod based on the image. -`kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml` +`kubectl apply -f applications/hello-kenzan/k8s/manual-deployment.yaml` #### Step18 diff --git a/applications/hello-kenzan/k8s/deployment.yaml b/applications/hello-kenzan/k8s/deployment.yaml index c80ce0367..9ffd6cae5 100644 --- a/applications/hello-kenzan/k8s/deployment.yaml +++ b/applications/hello-kenzan/k8s/deployment.yaml @@ -30,7 +30,7 @@ spec: tier: hello-kenzan spec: containers: - - image: 127.0.0.1:30400/hello-kenzan:latest + - image: 127.0.0.1:30400/hello-kenzan:$BUILD_TAG name: hello-kenzan ports: - containerPort: 80 diff --git a/applications/hello-kenzan/k8s/manual-deployment.yaml b/applications/hello-kenzan/k8s/manual-deployment.yaml new file mode 100644 index 000000000..c80ce0367 --- /dev/null +++ b/applications/hello-kenzan/k8s/manual-deployment.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Service +metadata: + name: hello-kenzan + labels: + app: hello-kenzan +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: hello-kenzan + tier: hello-kenzan + type: NodePort + +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: hello-kenzan + labels: + app: hello-kenzan +spec: + strategy: + type: Recreate + template: + metadata: + labels: + app: hello-kenzan + tier: hello-kenzan + spec: + containers: + - image: 127.0.0.1:30400/hello-kenzan:latest + name: hello-kenzan + ports: + - containerPort: 80 + name: hello-kenzan \ No newline at end of file diff --git a/part1.yml b/part1.yml index aefa94bab..bf1a99424 100644 --- a/part1.yml +++ b/part1.yml @@ -53,7 +53,7 @@ parts: com: docker stop socat-registry; - cap: With the image in our cluster registry, the last thing to do is apply the manifest to create and deploy the hello-kenzan pod based on the image. - com: kubectl apply -f applications/hello-kenzan/k8s/deployment.yaml + com: kubectl apply -f applications/hello-kenzan/k8s/manual-deployment.yaml - cap: Launch a web browser and view the service. com: minikube service hello-kenzan From f40019c35a1a5a7be9bd17403369406e48d45843 Mon Sep 17 00:00:00 2001 From: lifuzu Date: Tue, 5 Feb 2019 08:46:09 -0800 Subject: [PATCH 85/89] Update Jenkinsfile --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1f068f725..f4802dc8f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,6 +22,6 @@ node { stage "Deploy" - kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'kenzan_kubeconfig' + kubernetesDeploy configs: "applications/${appName}/k8s/*.yaml", kubeconfigId: 'app_kubeconfig' -} \ No newline at end of file +} From 91a99132ef00cb5a1b2ab2d7591b4c872692e89f Mon Sep 17 00:00:00 2001 From: lifuzu Date: Tue, 5 Feb 2019 22:11:09 -0800 Subject: [PATCH 86/89] Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index f4802dc8f..730e965ae 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ node { sh "git rev-parse --short HEAD > commit-id" tag = readFile('commit-id').replace("\n", "").replace("\r", "") - appName = "hello-kenzan" + appName = "hello-cicd" registryHost = "127.0.0.1:30400/" imageName = "${registryHost}${appName}:${tag}" env.BUILDIMG=imageName From f06356dcb664ae6c9218afa90dc28384f9fb052c Mon Sep 17 00:00:00 2001 From: lifuzu Date: Tue, 5 Feb 2019 22:12:29 -0800 Subject: [PATCH 87/89] Update deployment.yaml --- applications/hello-kenzan/k8s/deployment.yaml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/applications/hello-kenzan/k8s/deployment.yaml b/applications/hello-kenzan/k8s/deployment.yaml index 9ffd6cae5..c2140623c 100644 --- a/applications/hello-kenzan/k8s/deployment.yaml +++ b/applications/hello-kenzan/k8s/deployment.yaml @@ -1,37 +1,37 @@ apiVersion: v1 kind: Service metadata: - name: hello-kenzan + name: hello-cicd labels: - app: hello-kenzan + app: hello-cicd spec: ports: - port: 80 targetPort: 80 selector: - app: hello-kenzan - tier: hello-kenzan + app: hello-cicd + tier: hello-cicd type: NodePort --- apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: hello-kenzan + name: hello-cicd labels: - app: hello-kenzan + app: hello-cicd spec: strategy: type: Recreate template: metadata: labels: - app: hello-kenzan - tier: hello-kenzan + app: hello-cicd + tier: hello-cicd spec: containers: - - image: 127.0.0.1:30400/hello-kenzan:$BUILD_TAG - name: hello-kenzan + - image: 127.0.0.1:30400/hello-cicd:$BUILD_TAG + name: hello-cicd ports: - containerPort: 80 - name: hello-kenzan \ No newline at end of file + name: hello-cicd From 23569941a288a6a6cae7116b38ad5387bcfabb33 Mon Sep 17 00:00:00 2001 From: lifuzu Date: Tue, 5 Feb 2019 22:14:17 -0800 Subject: [PATCH 88/89] Update Jenkinsfile --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 730e965ae..6fa106a4c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,7 +14,7 @@ node { stage "Build" - sh "docker build -t ${imageName} -f applications/hello-kenzan/Dockerfile applications/hello-kenzan" + sh "docker build -t ${imageName} -f applications/${appName}/Dockerfile applications/${appName}" stage "Push" From 442bd81dc74cba33f508ab69de8a6459633a7148 Mon Sep 17 00:00:00 2001 From: Richard Li Date: Tue, 5 Feb 2019 22:16:13 -0800 Subject: [PATCH 89/89] Rename the folder --- .../{hello-kenzan => hello-cicd}/DockerFileEx.jpg | Bin .../{hello-kenzan => hello-cicd}/Dockerfile | 0 .../{hello-kenzan => hello-cicd}/Jenkinsfile | 0 .../{hello-kenzan => hello-cicd}/index.html | 0 .../k8s/deployment.yaml | 0 .../k8s/manual-deployment.yaml | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename applications/{hello-kenzan => hello-cicd}/DockerFileEx.jpg (100%) rename applications/{hello-kenzan => hello-cicd}/Dockerfile (100%) rename applications/{hello-kenzan => hello-cicd}/Jenkinsfile (100%) rename applications/{hello-kenzan => hello-cicd}/index.html (100%) rename applications/{hello-kenzan => hello-cicd}/k8s/deployment.yaml (100%) rename applications/{hello-kenzan => hello-cicd}/k8s/manual-deployment.yaml (100%) diff --git a/applications/hello-kenzan/DockerFileEx.jpg b/applications/hello-cicd/DockerFileEx.jpg similarity index 100% rename from applications/hello-kenzan/DockerFileEx.jpg rename to applications/hello-cicd/DockerFileEx.jpg diff --git a/applications/hello-kenzan/Dockerfile b/applications/hello-cicd/Dockerfile similarity index 100% rename from applications/hello-kenzan/Dockerfile rename to applications/hello-cicd/Dockerfile diff --git a/applications/hello-kenzan/Jenkinsfile b/applications/hello-cicd/Jenkinsfile similarity index 100% rename from applications/hello-kenzan/Jenkinsfile rename to applications/hello-cicd/Jenkinsfile diff --git a/applications/hello-kenzan/index.html b/applications/hello-cicd/index.html similarity index 100% rename from applications/hello-kenzan/index.html rename to applications/hello-cicd/index.html diff --git a/applications/hello-kenzan/k8s/deployment.yaml b/applications/hello-cicd/k8s/deployment.yaml similarity index 100% rename from applications/hello-kenzan/k8s/deployment.yaml rename to applications/hello-cicd/k8s/deployment.yaml diff --git a/applications/hello-kenzan/k8s/manual-deployment.yaml b/applications/hello-cicd/k8s/manual-deployment.yaml similarity index 100% rename from applications/hello-kenzan/k8s/manual-deployment.yaml rename to applications/hello-cicd/k8s/manual-deployment.yaml