From c402cfb18c1cbbe56f03c59419bf7cb19d5f5bd7 Mon Sep 17 00:00:00 2001 From: Tobias Jordine <jordine@hdm-stuttgart.de> Date: Fri, 10 Jun 2022 22:58:06 +0200 Subject: [PATCH] Concurrency VL Vorbereitung fertig --- website/assignments/Concurrency.md | 17 + website/assignments/bewertungsbogen.xlsx | Bin 19741 -> 19732 bytes website/concurrency.html | 384 +++++++++-------------- website/img/concurrency/Amdahl.png | Bin 0 -> 30505 bytes website/index.html | 3 + website/lecturenotes/20220613.md | 4 + 6 files changed, 170 insertions(+), 238 deletions(-) create mode 100644 website/assignments/Concurrency.md create mode 100644 website/img/concurrency/Amdahl.png create mode 100644 website/lecturenotes/20220613.md diff --git a/website/assignments/Concurrency.md b/website/assignments/Concurrency.md new file mode 100644 index 0000000..12ca029 --- /dev/null +++ b/website/assignments/Concurrency.md @@ -0,0 +1,17 @@ +# Ãœbungen Software-Entwicklung 3: Parallele Programmierung + +## Ausgangslage +In der Vorlesungen haben wir besprochen, wie Sie Teile Ihrer Anwendung parallelisieren können. Bei der Umsetzung müssen jedoch einige Dinge beachtet werden, insbesondere wenn auf _shared state_, sprich Variablen und Objekte, die von mehreren Threads gleichzeitig verarbeitet werden, zugegriffen wird. + +## Aufgabe +* Ãœberlegen Sie sich, welche Teile Ihrer Anwendung parallelisierbar sind. Kann dadurch Wartezeit verhindert oder währenddessen andere Aufgaben abgearbeitet werden? Gibt es Hintergrundaufgaben? +* Identifizieren Sie _shared state_ und überlegen sich wie Sie diesen schützen können. Dokumentieren Sie dies. +* Nutzen Sie geeignete Mittel, damit es weder zu Konsistenzproblemen (z.B. _lost update_) noch zu Programmflussproblemen (z.B. _dead lock_) kommt. +* Setzen Sie mindestens einen Anwendungsfall für parallele Programmierung inkl. Schutmaßnahmen in Ihrem Projekt vollständig um. + +## Tipps +* Nutzen Sie `log`-Ausgaben um das Verhalten Ihrer Threads zur Laufzeit nachvollziehen zu können. +* `ParallelStream`s können in Java eine Möglichkeit sein, große Datenmengen effektiv zu verarbeiten. + +## Ziele +* Ihr Projekt besitzt nebenläufige Programmanteile, die gegen die besprochenen Concurrency-Probleme geschützt sind. \ No newline at end of file diff --git a/website/assignments/bewertungsbogen.xlsx b/website/assignments/bewertungsbogen.xlsx index 1936851b814da32e84308bccbb79fd9641006984..5865010136be66a79a6aad33b1c4122ce7c2441e 100644 GIT binary patch delta 3101 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 delta 3107 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 diff --git a/website/concurrency.html b/website/concurrency.html index 65094a3..245efaf 100644 --- a/website/concurrency.html +++ b/website/concurrency.html @@ -94,320 +94,228 @@ class: center, middle, first 1. Recap 2. Parallele Programmierung -3. https://www.vogella.com/tutorials/JavaConcurrency/article.html -4. https://www.baeldung.com/java-concurrency - -* Warum wird parallele Programmierung benötigt? -* Prozesse <-> Threads -* Amdahls Law -* Wie funktioniert parallele Programmierung? -* Wie funktioniert parallele Programmierung in Java? - * `Thread` - * `Runnable` - * `wait()`, `join()`, `notify()` - * `volatile` - * `Executor`-Framework -* Probleme bei paralleler Programmierung - * `shared state` - * Lost Update/Race conditions/Dirty Read - * Dead Lock -> https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html -* Möglichkeiten, Concurrency-Probleme in Java zu beheben - * Locks/Monitor-Objekte/`synchronized` - * `Atmoic`-Klassen - * `Concurrent`-Collections - * `Future`s, `Callable` - * Funktionale Programmierung -> Java Streams - * Was bedeutet funktionale Programmierung? -* Was ist Skalierung? Horizontale Skalierung <-> vertikale Skalierung --- # Recap: Was haben wir in der letzten Vorlesung besprochen? -* SQL -* NoSQL +* Client-/Server-Kommunikation +* Synchrone & asynchrone Schnittstellen +* REST-APIs + > Blick ins [Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022projekt) --- class: center, middle -# Welche Formen der Kommunikationsbeziehungen kennen Sie in der (objektorientierten) Programmierung? +# Warum und wofür wird parallele Programmierung benötigt? --- -# Kommunikationsbeziehungen +# Prozesse <-> Threads -Beispiele: +## Prozess +* Eigener Speicherbereich +* Schwergewichtig +* Wird vom Betriebssystem verwaltet -* lokale Schnittstellen - * API (lokal) -* Remote Schnittstellen - * RPC - * RESTful-APIs - * SOAP-APIs - * Messaging-APIs/Event-based APIs +## Thread +* "Leichtgewichtiger Prozess" +* Programmteil, der parallel ausgeführt werden kann +* Wird aus einem Prozess heraus gestartet +* Kann auf Speicherbereich anderer Threads zugreifen --- -# Gruppierung der Schnittstellenarten - -## Synchrone Schnittstellen +# Amdahls Law -## Asynchrone Schnittstellen - ---- -# Definition synchrone Schnittstelle +> Anwendungen lassen sich **nicht** unendlich durch Parallelisierung beschleunigen -> Der Sender **blockiert** bis vom Empfänger eine Antwort geschickt wurde. +**Ursachen**: -## Beispiele für synchrone Kommunikation - -* HTTP -* SOAP -* GraphQL -* RPC (z.B. RMI, gRPC) -* REST - ---- +* Programmanteile, die synchron ablaufen müssen +* Verwaltungsaufwand (-> Overhead) steigt mit steigender Anzahl CPUs/Prozesse/Threads -# Ablauf synchrone Schnittstelle (vereinfacht) +<img src="img/concurrency/Amdahl.png" alt="Amdahl's Law" width="30%"> -## Sender -1. Verfassen einer Nachricht -2. Verpacken der Nachricht (_Marshalling_) -3. Absenden der Nachricht -4. _Warten auf Antwort_ -5. Empfangen der Antwort-Nachricht -6. Auspacken der Antwort-Nachricht -7. Verarbeiten der Antwort-Nachricht +_Quelle: Frank Klemm, 2017, [Wikipedia](https://commons.wikimedia.org/wiki/File:Amdahl.png), [Creative Commons Share Alike](https://creativecommons.org/licenses/by-sa/4.0/deed.en)_ --- -# Ablauf synchrone Schnittstelle (vereinfacht) +# Schritte der parallelen Programmierung -## Empfänger -1. _Warten auf eingehende Nachrichten_ -2. Empfangen der Nachricht -3. Auspacken der Nachricht -4. Verarbeiten der Nachricht -5. Verfassen der Antwort-Nachricht -6. Verpacken der Antwort-Nachricht -7. Verschicken der Antwort-Nachricht +1. Identifikation des parallellaufenden Anteils +2. Herauslösen und auslagern des parallellaufenden Anteils +3. Starten des parallelen Anteils +4. Ggf. zusammenführen mit anderen Programmteilen --- -# Ablauf synchrone Schnittstelle +# Schritte der parallelen Programmierung mit Java-`Threads` (I) -**Neu!** +* Identifikation des parallellaufenden Anteils +* Herauslösen und auslagern des parallellaufenden Anteils in einen `Thread` -> Blick ins [Vorlesungs-Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung) +```java +class MyThread extends Thread {...} ---- -# Was ist REST? +class MyRunnable implements Runnable {...} +``` -> REST: Representational State Transfer +* Implementieren der `run()`-Methode -Softwarearchitekturstil +```java +public void run(){ + // do stuff +} +``` --- -# Grundprinzipien - -_nach [Wikipedia, 2022](https://de.wikipedia.org/wiki/Representational_State_Transfer)_ - -* Client/Server -* Zustandslosigkeit -* Caching -* Einheitliche Schnittstelle - * Adressierbarkeit von Ressourcen - * Repräsentationen zur Veränderung von Ressourcen - * Selbstbeschreibende Nachrichten - * „Hypermedia as the Engine of Application State“ (HATEOAS) -* Mehrschichtige Systeme -* Code on Demand (optional) ---- -# REST-URIs +# Schritte der parallelen Programmierung mit Java-`Threads` (II) -> URI: Uniform Resource Identifier +* Starten des parallelen Anteils -> `Thread` & `start()` -Mögliche URI-Muster: -* `<protocol>://<service-name>/<resource-type>/<resource-id>` -* `<resource-type>/<resource-id>` -* `<protocol>://<service-name>/<resource-type>/<resource-id>/<resource-details>` -* `<protocol>://<service-name>/<api-version>/<resource-type>/<resource-id>` +```java +MyThread t0 = new MyThread(); +t0.start(); -Beispiele: -* `https://music-mamager.app/songs/112233` -* `https://music-mamager.app/songs/112233/play` -* `https://music-mamager.app/songs/112233/artist` -* `/v3/songs/112233/artist/json` +Thread t1 = new Thread(new MyRunnable()); +t1.start(); +``` ---- -# REST im Einsatz - -* Verwendung auf Basis von HTTP/HTTPS -* Nutzen der [HTTP-Verben](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) - * `POST` - * `GET` - * `DELETE` - * `PUT` (entspricht einem Update) - * ... -* Nutzen der HTTP-Status-Codes für Antworten - * [Ãœbersicht der HTTP-Status-Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) +* Ggf. zusammenführen mit anderen Programmteilen +```java +t0.join(); +t1.join(); +``` --- -# REST-APIs mit OpenAPI 3/Swagger +# `volatile` -* API-Spezifikation -* API-Dokumentation -* API-Generierung -* Testumgebung - -[Petstore Demo Projekt](https://petstore.swagger.io/) - ---- -# REST mit Spring Boot (I) - -* Alternative zu `JAX-WS` -* Maven-Dependency hinzufügen (`spring-boot-starter-web`) - -```xml -<dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - <version>2.7.0</version> - <!-- ... --> -</dependency> +```java +private volatile int value = 10; ``` -* Erstellen einer Klasse, die mit `@RestController` annotiert wird -* Annotieren der Methoden mit geeigneter HTTP-Verb Annotation (z.B. `@GetMapping`) und zuweisen des Resource-Pfads (z.B. `/songs`) -* Mapping der URL-Parameter zu Java-Parametern mit der `@RequestParam(value = "name", defaultValue = "Song 2")` ---- -# REST mit Spring Boot (II) +* Garantiert dass alle Threads Änderungen an einer Variable umgehend mitbekommen +* Variable wird **nicht** von Threads gecacht -Start der Anwendung: +--- +# Thread-relevante Methoden (I) +## `join()` ```java -@SpringBootApplication -public class RestServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(RestServiceApplication.class, args); - } - -} +Thread t0 = new Thread(); +... +t0.join(); // warten bis t0 fertig ist ``` --- -# REST mit Spring Boot (III) - -_Quelle: ["Building a RESTful Web Service", spring.io, 2022](https://spring.io/guides/gs/rest-service/)_ +# Thread-relevante Methoden (II) ```java -package com.example.restservice; - -public class Greeting { - - private final long id; - private final String content; - - public Greeting(long id, String content) { - this.id = id; - this.content = content; - } - - public long getId() { - return id; - } - - public String getContent() { - return content; - } +public class BlockingQueue<T> { + private Queue<T> queue = new LinkedList<T>(); + private int capacity; + + public BlockingQueue(int capacity) { + this.capacity = capacity; + } + public synchronized void put(T element) throws InterruptedException { + while(queue.size() == capacity) { + wait(); + } + + queue.add(element); + notify(); // notifyAll() for multiple producer/consumer threads + } + public synchronized T take() throws InterruptedException { + while(queue.isEmpty()) { + wait(); + } + T item = queue.remove(); + notify(); // notifyAll() for multiple producer/consumer threads + return item; + } } ``` - +_Quelle: https://stackoverflow.com/a/2537117_ --- -# REST mit Spring Boot (IV) +# `ExecutorService` ```java -package com.example.restservice; - -import java.util.concurrent.atomic.AtomicLong; +ExecutorService executor = Executors.newFixedThreadPool(10); + +Runnable runnableTask = () -> { + try { + TimeUnit.MILLISECONDS.sleep(300); + } catch (InterruptedException e) { + e.printStackTrace(); + } +}; + +Callable<String> callableTask = () -> { + TimeUnit.MILLISECONDS.sleep(300); + return "Task's execution"; +}; + +executorService.execute(runnableTask); +Future<String> future = executorService.submit(callableTask); + +List<Callable<String>> callableTasks = new ArrayList<>(); +callableTasks.add(callableTask); +callableTasks.add(callableTask); +callableTasks.add(callableTask); + +List<Future<String>> futures = executorService.invokeAll(callableTasks); +String result = executorService.invokeAny(callableTasks); +``` +_Quelle: https://www.baeldung.com/java-executor-service-tutorial_ -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +--- +# Probleme bei paralleler Programmierung -@RestController -public class GreetingController { +> **Shared state!** - private static final String template = "Hello, %s!"; - private final AtomicLong counter = new AtomicLong(); +### Konsistenzprobleme +### Programmflussprobleme - @GetMapping("/greeting") - public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) { - return new Greeting(counter.incrementAndGet(), String.format(template, name)); - } -} -``` --- -# REST-Demo im Projekt +# Konsistenzprobleme -> Blick ins [Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022projekt) +> Ungeschützer Zugriff aufgeteilte Ressourcen ---- -class: center, middle +* "Lost update" +* "Race condition" +* "Dirty read" -# Asynchrone Kommunikationsbeziehungen +> Blick ins [Vorlesungs-Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung) --- -# Definition asynchrone Schnittstelle +# Programmflussprobleme -> Sender **blockiert nicht** bis vom Empfänger eine Antwort geschickt wurde. +> Gegenseitige Blockade parallellaufender Programmteile -## Beispiele asynchrone Kommunikation +## Dead lock -* Chats -* E-Mail -* Message Broker/Queues (implementierungsabhängig) +* Ãœberkreuzzugriff auf Locks ---- -# Message Broker +> Blick ins [Vorlesungs-Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung) -_nach: "Learn Microservices with Spring Boot", Moisés Macero GarcÃa, apress, 2020, S. 216_ +--- +# Möglichkeiten, Concurrency-Probleme in Java zu beheben -<img alt="Schematische Darstellung Message Broker" src="img/schnittstellen/message_broker.png" width="100%"/> +* Locks/Monitor-Objekte/`synchronized` +* `Atmoic`-Klassen +* `Concurrent`-Collections +* Funktionale Programmierung -> Java Streams + +> Blick ins [Vorlesungs-Repository](https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung) --- -# Ablauf asynchrone Schnittstelle (vereinfacht) +# Skalierung -## Sender -1. Verfassen einer Nachricht -2. Verpacken der Nachricht (_Marshalling_) -3. Absenden der Nachricht -4. _Weiter im Programmfluss_ -5. _Ggf. Empfangen der Antwort-Nachricht (nach Zeitraum X)_ -6. _Ggf. Auspacken der Antwort-Nachricht_ -7. _Ggf. Verarbeiten der Antwort-Nachricht_ +## Vertikale Skalierung ---- -# Ablauf asynchrone Schnittstelle (vereinfacht) +> Erhöhung der Hardwareressourcen einer Maschine -## Empfänger -1. _Warten auf eingehende Nachrichten_ -2. Empfangen der Nachricht -3. Auspacken der Nachricht -4. Verarbeiten der Nachricht -5. _Ggf. Verfassen der Antwort-Nachricht_ -6. _Ggf. Verpacken der Antwort-Nachricht_ -7. _Ggf. Verschicken der Antwort-Nachricht_ +## Horizontale Skalierung ---- -# Backup Themen: Software im Betrieb - -* Eventual consistency -* Monitoring -* Logging -* Security -* Patching -* Releaseplanung -* Downtimes -* Dokumentation/Schulungen +> Erhöhen der Maschinenanzahl </textarea> <script src="js/remark.min.js"> diff --git a/website/img/concurrency/Amdahl.png b/website/img/concurrency/Amdahl.png new file mode 100644 index 0000000000000000000000000000000000000000..5b255e2620c314eda26eafe84621dd5a1957cc4e GIT binary patch literal 30505 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⩔DRTI=zWBROWy^%<oj8RfyIyI1B(v@T!>z#$=#;gq^azFm@VC? zd#FnQr6B2p=xPF-#?c*Ds{N~{cC*}d$v+Pq@G^hGzd_Jy9+ICa@C`1yGx}kmtB-vc zpn&TYupL*LawwAo6Wx7gL5@YPO9Z80AUga}j+A;q)a`|EwbmTsQG$sSh-=vBBoqvv zeq{H-orL1KhaZhUKu5Evwyxec&2Z7x)E@I|Xa-C~AQMu+4DI~t%j@A={;>ez_9&Uf zQ@cI2TuS6kRvy9;`*6J_Efa)aQ-DkXyl=>1B)WK8jS>#-JPgGSZGRAfb`Qf%@QLW_ zlh4K5r8%3#$2-wh8y7?nt170TaQ5v?*@bCEUFv7>c`_~N_PQ!6&T;kqTOX80Of)Hk zt9L9fKm9XX6FTiBN{w*!u9Ee=Xu?0{>zx@0G0BXSYB>yQ?N_>@vea2gu-O99FVK%& z0RM;J0onnw0nww?3u*<is8ZE73kww)yht`Vo>NRrjPLKKs;Y_!@re!d=n;$&K6t<R zZTSVhj$29V;|_?2AUKVZ7tTt)prWQ0Dw#Diqjy1Ips5+8jPmg){d5ro9N`lC(w*~a zl!z0gR#8G2(b3fnj!6RYAZA*dfVjB0h=>R;uUU=0lA_}3T_VO3p(`%e)NhADA^`ec zIt=@rDL3b;=sC=|bNRB^;Gy3<U(5ZNLBZ?pY4tTK<(ue)l?$d|n3lHowhIl@e6S>) z5iErm+0G0NFz=D<JLVG^ai91Hi2)9MwAbI)*JovAmBeNAsz%>IAdM21a7xkM9<{VT z4PJ<zF>F1180qB}7#MKeBHx!a30s(IE)5UY8|wm5E9J_O3K9OUHwUigG3mrJ9N`hi z0r?9h{Z7kg*$S$&M4@jKD|E0*F2`e8`OZ#CTI<{3PCq*_?FV!ehs2ts4@ij_DI|M# zc1q?snF!dq;!Yp+#BCke4t6+lOkqH5VA<Zy-$fR9@RmFnAE7UQ&~NC671~a(hE+o3 zp9?A@V8aI!hL{1Yn5rZg=SslM`&BwhAULK$cw4cAt%yr_MCZE0@e;M!rCSk22{}MC z$SIy-{Q`+w_%m{rhsG8xyFNlxhH;UNQ1ZP&9Hxvgk?#VvvAJPI^Gn_dJb?ySSx_52 z^*z9KCALrQml=C|lm?za5`NF?*#yRzp3{?587y2%?pm=*qCTe$1~nV`ID@Nykd?Rz z9WX&&VFb{{{*Nt;J~I_-yrgQR02$EmF`{7y{Qa(8HYL8~`#DY-@dQ`=d#KNco+I~T zTL#+j$$fT&9@yo2ON-J!3I(8UH+hctfC74eR+Wd#LrL2$&SHJ_`WxIh)u;Tk{nv=} zSdZDZVX6)l&s5SCBF|K-wFZ?)_5lrKC7f-)5=%lGS}8z30f?9=1-QbMaeRZC!PYp4 zmIi)CheCNNJ!~n3*+3ijmS&hr-EctHoRpYcqNGtAp7L<AAjjQ_SK3tXc{=U=&!P7P zFR*DXQnxg;zt!BhczeERr~olnT(X`wz}@i98=qya`q7v@gOHXd<Byb7%j{8EQ`_`E z=0cPYJln>3ZLw%w55{wVcfu{ffDTF9qL5UZR8oshn#^iGJ2^7lRlm*F#O9xk6*`O) zjQz&}%qVWR2IJ$~pS!Xvc$;#3VhCiXvM)%kgAc6=MmF$DSQC5x!Fg+(<|2d{yPDNL zS`{}(wWN1nuR_guO4j8YmWID^+&pg`BtMsf6Fu=wZqjW^sBwK)7!67x)rVnch(3Q* z$(3<^SCn{>z|KG3{)GKh10N&Iwp7n_9$z9H08{|r*+KzXU@+|1dCUrM$@jM;4=2sr zV=YpXC&ueRX8FEjUxSNC_bE*6-TD11N|GnZVZbs;mO|0WJpiXQeP)z_H`EsjQoP?6 zr2u4f0g!Q_S_fkT<wT!04YG)|_qgQdLW>H;>w(=ZNF*#FR3-1CjB}gKzfQ^?X>r-^ zMQDB`!!Hj|=W+90dVNB>991B|wXX{U?o*xY7)!7>9&eQrlo?@J5oFUoc4LeUo!2I) z<??$LutC~okldqBp+IO-$uPDby-LmoPl`zOk)Zdy9&gn7-jjKAKmo>X6s|esABw7a z4xNv_meQ9WBD?AaptY_dqXZg+!v2mQm>?clHS9<(ICHOY#8Uu#{(-A<2g-aw>cKcv z>_~my@zVkca?4e!&l393tJz4Xi!-Q1vcJ6HKpOW6V8}P95CaHM?X>1l&m*I@D3F{p z&T{9*Dy;vTc=rr`%U86l5yl@yZ(T*;-2HGhVSCY$_s=_^Oc5h1B|!8JCMeqaefags zK%SK91;i{c%eO85V7JA1w8DJ6Pz5o}cZ$hQ7Mmnyf&ZYj)eCX3VVGJ0W(cGptf959 z=8}#K%87U(OR4YsoJ_z2^p?nN&o{Ud(1^dx0C<l&nq_<plP;K*cv&hdhD(sY3WI?9 zr+w|!*?w|T(yV>$*qCPVq`szR_Obdy17ly`W@AUYq?FpG0U9HZN22G?2+%{{j(XqH zoJetpzNhv#9~T!izifGJ^%XCgON`kcCLF&6XSTBIcH3QQF>%c=E-r3p5RPvnQLO*? z`LplgY8clUf9Yhg4gnrssa{o=RTZaRWrtOjUa5BR<f}NRm9wi8FN3NdD+hny`PoDI z(@r!#Jq)g|??095Y!sYw)o{=CuCzTzDeWW8XAly4%~&T&RfH;uqJ~hyH&}!`!+0pY za-o3%_s#<2vNC|s*~`=_ksx{b3@3|$(?8M@Z~v<WzzNFyoYN_*W;&UME1h9GZ;|k+ zn(2+TYQP2H{-31zISRLQf*_emwt94m6Uh!&>Me+P-J8aEbTBE*WX52?UnZ}bdVifd zyR{4Tqx`d9GW<!;6(xU+MEMHlcNeTll}uwm4Y4e9+!960#3s6{Y?7Gm9UWp0545^C z6_QbH_ssvg_3$og&nhQr3i;TL`VGB(zBMPQX>>$eVbjB1(u6md4bwPta(T}i8Rea4 zn1$;Y?}aOt+n6)XlGw$QaexeAlWK!%t=!KVK?NWzI6RcADv$Mpg-6mqXbU25A2bAg z$imr6d6_%Rv(|fvA5I^%%FI~n2|O1F1N7N=xt6ay6q}1wJYRT%EFI-HQb4vjcr&fk zp+QxOxKtlJg`!vm^?6K-K&2+Vz5}fm*zh{qH9yoTpdQ|M#}?>gn41Dq3McnL^}7ra zQ^O(w!7ipl{=vTDF`lnHa#$Rk>P_!$P}m;+!T>yCq7-foQUK+6-Wu}{+9|_<q&|bH z_I5P_Y9E`5&6B0g@4nnuS1Ts+PKQ__bLyYIc>1FX<Oiy}4pds)GeY=it9K2*Vn{+} zp#XS!MFdhh)l(87Z|!c1@AXdbtsifl3ji+1A*c)EpTisq4rF@h0Lp||+#&5|u`Hrd zi?Z^Nlmpa?O9;c|SvlGE8=iri4U&7-t0>|KiLiz<rtUKfZ#CFRp*~OfMqZPa^?oj@ zi{icO(TED@Hq@R+14Gr`N|*ocM2SwqQhD7GHkQv!<*2J^WYp<gu|ednz$rTr?i*)7 z>|4oqMsqmR9DnAc<I`t`GaZx#@cjGhMIk=584(d3F^`yqY57tm#Uv-DPd$|aaQSuu zAY*8#VICt)aN?w7H3sBGUG#!BzTHzh1h--;2B{B>IX0LX_BGa$soM)24ML<pe;%|V zD;>qXNq4^v_r(uSH7L~uhSC9VecH)m4WRes_uo}N^e#q>tpTf4T)~7S!7J6TLKhBJ zj2hPN)D*8hh%!BZ%EH(<9CXRp8OGJy)@SlQ3{IG{Z@QH0t|>h4@ybHa=pzCX#7fn( zNgtI>C_9^{DBW(Y>X;(g$Xf!`?e%34*xqmVDGC791H``tRq0-#X0n1(OdbA$CO*3X zJCzYx6dHs+?y#clIcUIffUYho`6I^bOVlLH0Z;(u-N?j{DUZ>2JT~^(a8a4}PuEQ! z3Q52lSDN@hPD%+At*OYaX#=|vvb?<gkf&c~G9;Y(`UWXeJ@Pct>x1`SPzwlWg#Amz z=Am19dhtRe`5-I#{?@lIt9j`A)&w&!ZAg8bZ(jOLE3$g3=l7E75RXLGJwU@WECE)D z=ZpdxkV-E6g<QPto$aBaY$n1G4{&SayqsR2)0;Qi$rPzG5v1Ihbb%7Be?3=jb@c=Q zm8IJMu;Az5Ozi%}uLWOs5AwPJUzFG$lJSIN;rm4E^5FIS`-Xl#SBH-IwJd@7_NV^= zuNm3cg8fOH6ciN2U%te&M-5u>Y1JQG-FP*Z&ip#MP&P=v90kO)=PmQoiTui%%H6wH zd`=+=2q=8E^c0XQA1_A#Q)O6cBi(wQ?5NOpio+!<riJa=hJ-x?5K#eeMbV{i?B>WB z;sN6=dFiL4>F{{XT%K{$w3b97u-^S}5y3Ll@4bEf6U=}zt6fzdp)G{1WJ;U4c;+qB z9j^U-5;5~}z1#L|4NMqSd50gGGGyDd$e387_PWeTTF4GS+==AGf@sO9&XOtzI30+0 zKS_S&egDXsS&!vus!6rZUsq{$fMc&56N_Mzm$}#P+=O%)hn=IXc$WdqgIJuDP(Mz= z_x#Ls!nQbr#Nv%iA+24tH9fy&*&TIv?jt}Y&?x{f$^%khg}%>ce~4Bd1$?|M7aG31 zxIlP8!iak)0liy-2H3G(B#ax>#`Hy~lFr!?bVU0k3GAN`fY`I0b&p<+O{bnIO#Nk$ z?`MWl^nKR~EHtS)0-4ZRQ(kk3=h=-uY*}ueFtGDaq@k-4(P#)UhRi*B%)@W=MnsH~ zyx%5ExhG(<4Q<agq~qpiudq3yY+iht@1Ext<xY^|ki~`83trUU(^U!@%;j%>XiC@z zrwy)OAPTdjSawqH{hCRM&xC~)M7u!?f_RY4i(udu_dhokPzq4n7&chsfxQOhN+#bA z-+1~|`U5@4YZBD}@WzZwBg7q3$5AHmza6Z&WwAbKq`TQ(+%5B0*ZD5&!eN`<@HSh% z@5K>$a?dzFdl}0>eH$fHd3EMqcMyHn3{_QAAtjY26hrD}+W-VqX7#A;%4_IIBj+97 z^4$O+-^(yQKfiqrQYb(pq`nSWH4}P;)jjb=d@!u&2OI$RL)1c>VTPv^5kXe&10XRs z2b0x<GjpTO)UeV8gXmUX7%%LTdkAy*OE_m!DkOL=dSiBXqYtB6yow8xr3n0-_Lk`| zxS&GOBJjxQpwPYB9<E<b#tTR{Un?bE<?JV648-na$5u8?3m(~xB?{dXvr5HF`kgY- zT63nsz=1Pp2005HEPsvpbZl5n7eqVoWLV=H`J>0d7}(>0>noM2OK9(lN(3Yu!Vj2g z9M9bU<lI1p)Bk8rT<%#L?F4G7@z!<cI!1%H*mJ@j!=7A_o-lfDIvr#8?ta)W2`~A{ zqV^~mkVq35(;t2ZN`l1bZTs^Ji{b^v8<cnWY)}t_mv6hd;Q{*s<5LV_Qu4h)nMEuR z#^2x@WN*P!?_aTozU`=<;^2W{98Lp79>Rso77AD&Pre5X=m9?28;%wgpXnOW(|XjW zP*+6F1s}FPSbYczK~E@{c_`KHg)QYoVm;8^WeU^YaaEr%WRBy)(!_2yjET+<Dd=Fx zcBuzd-picdi1E?lH3kF49!tdi(Vf^gJ27>{@<OdrE@RcL9jd!*ryoTt(qu=Q+VA6c z!%}Dogp<xUMcV7lxfQC(css*fO{9-diQ91!^QDS*mD4H^CilE0iNZa|vkjR-g$X%L z^?R%iMy>~G#+T0l%hD%m|6FuC$8uAo=wIpWXwBNOswyA98|7|0)qJNgPA8L*$*#|i z$a-kSp2Ava*{;|Rt3Nq1))`!cZJK9`K)I@fsG#UWpS*mIk0HbPDw_|I1|@>O6imrh ziLF;lZ@mlP#gpF|{gCm4IfWR6520EMrR)1N>g}YgN{g@~NnnFi1ypGIX>z2np~F-^ zb`tjf86Zt!v=Qs=eANk5e!C?!knRYmXmu|{CrVwS8Z8Es1B)+n)7$8Jt`SU%O23iT zGhu;2C%i`$2gH7iix}qO|F`(mIFXBMhxJafaeicgTGYd|YGw~WS$+LiRWpi8N~PL% z3JPJ5n`V9<ZvXy`z^WZz4z1*@_iyMMMXWr%FZ!SP7jkv2Mh^|t0OI?<s5l4Y3~%^I zhO3Hbj7eJ3=*O4@>Eg!Ocq#M3MfK<jj8!d0TmQF2^}C9?m<VQNZJi<NncXj@Vt2AV zDJ3OkH&s$GW3QCN0e&Lja!o4Z{P~Sv^Wv2K9}iL4#ObSu#hHz&!)}m>U3KoJT2X+K z6-tJ|BS3G4{3{Iv)vGVV*qtOS;lb%?<TAXta9bR1f7Nh5`Gc8l9>AHf6Ydz|mFuSB z7lITl8!^qFVJP8RA_@^)(}q2!hGxz%qB^UOLN`4)ld+qx8lf1X!8l*Q7*i1NBY3(1 zu4CJVux>ztG(>mu2rlK3$9>Bgu|X;K*e2JkeMMm<k0fC>Qm`ibO}e5|5mxIirQZ1W zy8Pm}@gQztW#eN+AQ*`dpW`+p%H14_bomv7Wp9;6$I7NaJ<R7W<n9l0JZb7F;+!6L zQ?S^%?nJ<;sef@Z*pQu((^xc1C1vO*vaTf$dc%!0_y$QqJZb^yG08&4qpw>kE@PO{ z?=k_hvFCX#g^g%udOUys6CqKrfUDggk8<|fHSKTnGsS5}l0n(+*)FbLg{mM*3Zuw; z&~`6uPJ;3<`mEZ$+WMuibSMc#LI%>jx7mQ;xc4~OVO^U&X&zHRm}Ng()k9+jk6~1M zi-emQwxikd7MFPZ_`wVZ<*xY!9^$os+^_^EU?Jg=-dUa}s<<$PHdVC-CgHOV)rbP2 z(N4lJ_k5vRkuC2BVFD=$N&6#oXb_rO28`_j<IA;~n`$k{EhCojkRHd`{8q=1$@|Xq z?QJ&EYo@=E2twT5DN)BO=xX7u<@<nyg$t(U*n{smJSN|5rbsFm7ekAAD4q*E`j))| zQhpHA6{sj!+TDAW(hVe!S1H~A(iscd|C}oam_RG7n7%u1m05bybUl+b+qO<)H~cx~ zisn0Y1jwhFVT*KrC#+~{i&V_`0CEG%8#`kCnPTvvA9i48H5?U2-B@T*Nf(T3M7AyR zQx4>waF6gFPEJ=4T{Mb5Kc+w0MiW@Sd13U+{C#U>5TGlb4q`jLx*gr2L-<=((?&J4 z=vd2Z*$Plz0&pFa)h|%Oi8nw(PTh8J6zLuQzc~L53_q!dIDP1Jc|4N^(G`te4j|7< zEbvrl{*(6VfP}g#k0?`Z<Pz3oUtC+`#5ub1vlCC|gFI0fR~6ata}7of?8JXVOJ*c~ z!5hApMN%HEB*5)fh9*qHWDqM}YaiY4Bghd8Xk@Pc{2*{W^8#*X67}Y#jP_1^=zArY zAl-IK5!EzG{>f%rP8N<-AKlYjDD&4pQ!d2hpXd%>R+bW$|4M^10*&-&X$z5&vqH@B zShQ8Acpv=zXQy`$8m=?9Vv7FPBf8Livw*eQ{2L-{rr95W!gKXe(~1rvKFq)B1gI#r zEEz``Flit+KkVL&K@OnLQmP{Xe2Ho_#q)Jkfj7$!SFj^^RUYGZi`Y(zIt?m2NoJP{ zY{!$ZG&16_`_nOpY=p+{-FqGS5@$Ml-;^7IToqf^WK9#<euQ-qu`JZyt5lj3BcqYz zfANFZFwXL#bF*}GE(HUmxf>5KX@g@xarHkb3MBj%#um`#cJ<Q%u>#JDEe7GBLViGl z9DoI&y13Adgs|b+kH+vRY{W+IVX|+DNdZ*snz-WhFknd$oCGPiF`*=KV8Ec2L8YaF zt!*Ljb^4`>1bL%q+o!cwVa99kg0d){HD^(3!%9l-Jbgn11&?z6Mb{r21kCpi)zf<E z<{7p1^a}fZ!ynDReEBjmDoX3+%N{tO96mn!AGdko<CW-s)js#*N2W{tnxH|EadGO# zB^p50Tj%qYNYPvlh|&+Ja0Z|Ie4lTM@w0$sQxLF8y|1Ww$@^F#flVK%v(i_n*UB$! zT;1ffpn&B}1oHDF2+_rDAK;8amdVV`mHuoW<LJUof?H@U50sK!JN+OJp>*3y3NHy{ z52uttooaiO;iOJ-uUz>VU9c`k(%9HodOCFuPH$42aE~DRA?4X$0WyV}14o60EF(lh z1^f;mb5|70kFnNTiEe@iZX%Z&U;iHX`#C;72H!h7I|BpCtR!(5Yq@@PU`|0rfWxkn zE49-+mM==Qjaht&c6n9Sl-B7i+5Io~`*o{?x11V+axC2?oabQ?ojv9i0CrtiH_g`q zu6~W*qC$5yuq&cZFc0yuBFFl=N|v`KJ0z&s!Q0qMKL#q90%YWMu(B%0%~?}>F$j_! zU9)Cv=L!Btk8YIyHu$4;cNcv&Bg8b5kdQDiH1sI6Ff=Wh+k{K6k};x&D`ZTR0plUD z>Kzx+;`rj<S_P=0B8sm7o{-6BphG~K$iY#3%^2aAI}=^8$vP+icdF0L4JIVQ4^>i9 z;(VaQN>Zs`nx+1pgL#HfGKoXaJl#p^Wt8A{IveiyUZ%mRB|L8m?LA#vkWNEgW5w=o zfpucl+H>q#=Hy>T>gYcK{Qbk;kQDCun4d#zuj_dmznW)l#bm3EbOH9wlmpCst3E38 zj$%2^+tpm#F!sI39R5W@Nkv7)gabjilkQeLeMFd$6(AgaXooRhoGE0@Fk=Ae)p7k* zg-bn9fBu_ILu9ID8L`MpA~J)<qp?Y!%<%>8ZTm>AyR@2z&a#$h7kjovDPQFDItWNV zQNZqHF6O7w{QtyR@=d<XlohtX4cn=#>QRtgtuslo8gp!0QM~gSN_dRT(rnPXqJPY( z#+~ZiAulkqF21hqc+-3^A!`A)9S@4{Lr`iW!BRPjT~BNHAxP#%EQQ6t%^bx~|3TQA z&Q`mI*X-Rp>s)U{djGfAfC@*fLP{{KnZorVr1noRA!=Gj0?mbDz5)Yk3g0{{(CE;O z?o^ipg!&&Qs#WxuvXM90F}Ft*H^z_|t91b0RsHTh^}+l1z_$kkk1e>%)?n19HhJfF z6h9;96QhJ43r>lg0^P%!6Oap)p9n$$^lAc=5tfA=!V0FGJ(}vGU>-nBN{tryOE%2p zQow+8rGRxj3+SmnRAVyHg8C*q&(|KiFi}wIoc*}^DggPH@ZJHzd1AXtfq>a>M+kaS z<*!EaANrO!3Lg7OmCmYGxYKBrjs8HDe@VhDbu&X9OcyAz0mUN%Y_|r3h#eQNIz>f7 zl@_n<9!rZE?EFrK3qG}s$V)+$<g@pe1zaY7DhZ^<*PBU|<C0*;a@gU|@SuR~e3Skt zgD~DvW4geoQx;qIbVaO{)B*z~K-B~bQC2uSO=y3P>HKY!4-HMO>O>Gk42WpV@lieF zU?)~sfh~PFB~!yfUyvZ8#06>w4_c7qF=}to1CArrJi7~;$QLb{Nhq<8tvuojmc$*H z@7UVYawS`wa!O`dgl$tvxfCeZk{H{ZTvB7}Y(}0fsK3k~Jp8|~mwZvc8z9<2!*o!% zzHnv05o>h3-4#>}eQB#=dvT|qUiIulFJN5l0QG8MEZRt#CC4opO=QeNk^b=Wmf8U< z9{vo?D)d3q&eqQ0%%7LrGO6Qghb;47q;Tm-x_L#}8=jE%F32>-GYZm?bCT8j-}w!G z{QC9ly4BH8>B-eiKIbrk^abip!OD>wZ#THcuQQ~zKO%PrB2jlw-6<?n5llxJ<&T{H z0OM#bArbLwNs7lrwU(k@2i+gld2aEg0vCffehh$R0u<+{?8hDwW(>MnpLi)yZh<av z4E&`=$K2l8#P!*GD2{6^`!2>;&9)+L2RLlmQ@iF+ymLSQy<4x!`&BnZT)9H}Xh5mI zCG6czGEaqpL<XGkfW}*=mek26Mx}2KB0hHKEa9^zXXQz|->+><%_}8e%&qSD{%XdZ zuc>#uK#i|SD*Sliz9F@yGB2)%zzCz}u~hg{shu}A;4cV+m5Ain&Jqhke_u;NAwQ;; zOkET$6imHzds(Afn#n(rvpkKGd{XKu*`A#(@mlZ2YrXNH<Vnss`#SAme^9$DD=ASv zc<nmO_c6!$rPm%d^?G(_Y}gVgiZw74hAwk&H>c%`Dt=sAnWvih^1^h@SERy$g#^|9 z1`l1cE&TAuOB+cTthcOZ>{zj2UHM(<o|bpSy5->56t;oUb#k{Hc07R&a`yh$U#}wB zDbufnm`^x9SUFSDjh*BT3}g%O?f})|m=MVgiNtOD)KZLAd;HChkIqbmqIio~$^^vY zk%nxX6@o9_SVIrO7{x#2j@2S{(i*^JS+*k+dY?cS)<CrYmSlaEjsr|1YJTY2DCg*# z<cd$)W9p+C`sT^c{HhK)FHls1G{(Yuzv;BDjuHGd|8P>752^kKX4QER$HUs&5SiHS zjlMf}cj~qL4SBK6+^p>OS8NQyKb4Aq_X+m1#Gjl%mWjOvFep3$R1=O>ABFz3MIu?; z5Zfk<ccLOSV$Cu9o#ep9UPxb*8@CMULOHoKu$RrxH_4Dk;z4qJVZ&E@%cTme>({`! zdZx~vYFuc~riZ_0Zt3GBnLVPhV`8LLhU$4JB?8>tRM_-xT=jQA8^f@Coa?}!2tOkM zl(=3jS(tCEf#E8QLHQyO8OYX5x!gawPf%$B+Hr(V%Oio6@8B@&`gutIRIg{JvA)qa zxA?<~$A8c=e*(!-N{{qi2OyFY5Cz(QgY?Kd(OP$p$~)UXs_Pp0V9dt)&A{^3ZW)5f z0z9@tD0&My<eLZwl91&m5wu8Y%kJw_JR^$8Qj9SMg2NN>eNW05S(EVXX0!(~)U9*s zqZI?%20Gu#`Jy4sgqtJ^`y<qthx@ksRg2bra3JV#m;{x9zzMYc&`^_O0yHn0=JS=! zI+QKEWLvMis>YJSSG{Q}Wp3GG=(NOJA!(@JIO{!m-^`%|)|4Z+o3Wz?yc_&51Vn#{ z2=xJwE(4$XfS+WO3j0_b``VdxBuzF|Lyml)1brl#3n*j9*%*J0ggJ+as>r=T!vK<y z+dl`#=hfF0rL(nw$+h?$=n=SO#ssAAZ-c<rd!l4umkg6kK<YvI7a1uCl*q=-2ZPBQ zSQ&jMN1UO|8Vb~$e?xD8`SBdm{!zO3@U!>=>w?>Nuloh26CJ;n^OyRbaGulxO(6<k zRsiMqyhiYh5~Q2K<~-}@rqn=HynIhX_<!gMS|S_j%a&vD{aC>`WtoM_LA?7^HA;e$ z91dEwSzYJ~P{;_=y!yP1ai*tuqo6xU7wC=JU-yp7E4~KSph56JZ#%HdSbqV`KUlsr z<1Ohq+<?MOeuMDkjz4?#Gw>8tP!|O%dmx-f6cIE>_03GhWSDrweB7H1U|9+k{R*&j zy_%hG;N5*8v5=|2Q&qHS<xHT93l7Rk3xz!j1<~?fa4uucI^u1;v+|92fo)H4=2&qf zEzvQ{6P-5N^qo1>{-y4gi;dk@WZcSL3{4r93wk%R5VnVQmd?Rh(H{t`Op06#2zR9G zoZ@|Ymz#Dz9bVnYCiBqnC5O&x@}FMuo=h#V-!6p5)iC83sSj4ai}kcS^1T{9yUy@1 zxrVLI85}JE7rCf@+Z=MZ-(0cd|Hb6ex^Q0f=n&U>eHJj}QVz@oYV~>@R=A#R1H_aA zqIYc@M;~hiUWnDH^BfQRUk&$}O|BQE`kPp!AMz`oZ1NM`CQ^`na{;3YtYF6x7~_BG zR?XqBv**$$>*;y6Ie-G{l0dH?Oqem8oJKmvG~e^$dkqc=io|2E0k2U;m%akM<Z<p! zSl|gs2nnCcyHc3Z$%h&($Fkx@vpVgK5>cp!e4#N998d)crAN${ETY|FeP&0a>i`&J zco4$I63p`p4Qf4&Ch@l?#eP;{W&YZ#dr$L#9$o%9D<bDDK**2koH)^^;#*dgSJKai zxx3R@zJXP5{`zQ4{_RaQQh2Cp#JMx>aAiqMC_^ZcOTX(p-zd$3ZPu=`L0EG~tJmSs z!U1e+rt@OXb|-JLwBNm!!@utJ#gO3?I>ekc*Yz=&FtA3K$VY(NS_#Rr9k`1HlSM6j zotBoy{HiX{zUPnS-Qeib`yA4BJ#n&+=%9?^@CggT*%J9FNbxE0S?%=97IAgONs5W7 zSN&b@Oj=G0`OO>JnI}E`P-d1=y_q4rocauj)zXCK?je<CA#sLrz3^q)x0Qunt{6TQ zaFFJ7W5Q&uk_WKoCF-~_I6#i^w=4<dVBn+!UP*VgYzx)-%8E&t8aE?_W{xf5;3^h3 zN`N`=hA}vsF{w++tgPbAP8O><SrU$IIEqR;iupg#)gYdh<8}bKb)OqIsDYppb1aF= z8e$Igv%Wy0D{K$U6`|{jE(B1>G1AA)ch#*jKQ$!$11I}Zj>$rVG71pc^y5jq0XjCI z;C1;~UWY`bSqZE~P*z+~peVmhTW)%1;c(U)I1yJvGHCT1c;71$UUU)^MnFN}c_L3l z#YT4(G+}Y;>NH!t7*yNRIa{ygf><eS8jyOj!OjE<#y&dVAg*F|zH({{JTx!Rk%_xi z`?g^~V1v71Wp|m4C2R%%AW8fHC%Ai(0E+>VZ6I$0#~?u813L;xzaQSXoXhyP4Nq}6 zEEwM*$xZ^<0)oH>4zv~x<2^$B>gA(<`%~M&?(Y_DU>Od)JdEYjBbZp9#<$nIFqV>$ zgZ)MhKrZNiXbvz?u)L^4?C6l;S6vR_4ddwmQVe->a0qH;ue&cRr(feGmFAC`gJ;)U z=Vg~V{yul6Kqp#0dGjmkYs-z!clYT}K-~i^Y!M;gb!a<CY(N2fg4a5oeEAZgd>|G- zyo7_p1RhVXxN&&6RYG5?SgVX*sdOdAzX;rd52Ht47x|xTEKx=*VH9m84rP>x+|}Ln zoi$HKo2S8`9wJ{Ie;v&s!=ZaWOVBBMw@83qG4eEo7m(oenDT<AjIR-#3uhdD;Q`xz z_Zh+M!ky02ZxQkq8$3|-IQu?+HjZav`j7;&G)O`RCxZqzirnRa%Qr0{ND0Z83KxI= zSJS74kBjEj0_OJDOyap(V$x5+mN$@VCPbTjJR8F1`ClynE+Tn|;@2}tOZo4y2T!`* zhR|fpPFGzb@<<JPDoubHOvGKhGR`{ui`um7{#o-juv?NlBZgK}K2+t=yF9fG|3Bv- zf)xx*SplbskT4pko#LvU`d{>XEU(FLEV1>z!ALU^2`F4Zl!Q$-z##$|pjM3&9SVUz zNV6aMEOPb-E_Fg4(P_S38uI%;xV-;|D}~6j{Jof>i_CTSQRu2?kx4pt^xnnJP1=tZ z3a^WA=j_SJu%GIu`-_H$7LT9rso}2Yivo>Ckbfz8YmQQMZ-&9pCJ`)QmlSXg*rE<_ zhKwFRcEw!wNN_CN5=CvwTyMS~!FT^hx}mqBcmgyTDhBD@E4&U4Gk!2|@O1cK^DJSO zs%BSi?#10<lZV^Ni$!i4;j8YUE|YN(R1Avi^L3uO8m56V<&TyrTyVSsApl?HA=wr| zkU=@Fl?s-s9uKUQusDE#hC5`9qrHB0I`LdgcL&`?r8)E^oO6aWh5EL`dsFA8ctudn z#w+irfa3f4RtUFChCRrQ`eyA54LP1LU?S5Y^l9?#^@fq}?jta@*(%;@AHYi3uL%lU zkDZ2B?rx@jJ{t%QN>wAD)JFl{q+}?m@7AqQTC4u=k&0e)7bYIUdf%N|7u|0;wFeS8 zfhU_xLL!U5MJ^KelMgELVKeJ>+Rnh~KGY<GTCV|bL!|4u@>aew?2YO_!ZV<3V|$s& zLrUpVMk|u*6{>a%>^?dAQ>x{QI{Tya_5S@)Um#F6)xWHnCmU6iayI|@L;vR{p%oFi z!KW3;Ob=ghp5rgqfxH>>knG#xOgqB?g``&U6R;P#O1Kf##C>}<2C~a#b%b6CafI9K zySqFdu&2{M^4H-$Wj`Ob+=aLv*<s**!GcT=+|oGnX3`AMzUfMuVWUZ*jngryg<Ni$ z%<}gFZ+Etm|KjdV^LvD#S2_b$c%Ib(p$)svzksMT`Lce|+`3&yNBif^Y*&I%t>Nx* z^_%8r>7-xF(w9R}pUE6P#Zjf6qn2>~xS3IZ)&H%}45;yac4CM?^>7Cs+j?BS?(;kR zv!h^ot9CLJQ{YCSUZMv>&kV4An!EG*%_XXXy+XtjlFb`%bCyKex(~ojh?~crKrz$* zCT~EWf_i`+-bS_Y85}cOD+f`K`n5cOp3l5Jq<y@eyM70wn0f@W+r0{Ti3Vjd7`5Sn z+#N0TpLg?W=omdU;8f%ZwPx{>$zM_AZ-oVA)}JCikNvhDp8R>3^9ltT(P)G-j}n@P zfuL#lssmXFnxS)-|0@H#7^8db-gH&<g8}3vHbWL3KwY2CvCE03o&tzqf7++7zaXNr z(b9tT35(hhwZ|J7SL${<C{sP}FB9R~sEus;21En`)o1Ge8-X<sLZ4AZ?}t_<Yu{yN z;rwlowT4d11O#+~rwi)%gG+RY_TmUvehpkOw!vpQEhK0a9G;U<1ROd!<%e4Tlm@9+ z%p})`u}1{{PrnMAR8^mJs}zh7AZh~z`$KW@wYoM1)g!_IP5d5jMt}f{Qh>%mz#(*E z;b1SiLqMexq-1yC;TeuiQDF5uC6b*Ogh3G<I9{X76mT#<p+lsihGey_RpQrFmO&pJ zoDSwRj0ikoB>qHocYgcBzv<|MmEuI>HdV{d>tEhwG*60nAfV-8ny+VKgJXAsOqxC@ zzzyX>sfw%u2x(pXBCteq_ddAa-3;R0s0|gVY5&|l<u|z%<jgP+1`~TfvH>Y28dQ@( zwF#gk3SG6P*5f}QXpDC}l$4jdfrE{wn@j+O$8fa-JjRt`^oxGu5w$wst`wY2>D7cT zu@`mnVZnJ(17D?H#Of}-%HLmU&U9RT^nh=BdoGFvoG-`}+8TFh2md$0AK>n4GQudr z;#sc2@laCo?t!)Y$`0W4&}_OLkcf<aUw`(scRK^7A?Po#w&m$FL2>^1($Y4pIcMF* zdvGbHe8^GyM^kBo_4?s}AwrA%WpLGPI|(Gi16U>Rw4%#^x?rFm6w(VzO86UtbN@YL zcHxs>>QFIUy8rAL4I{_3rS96Q|1e}t?+d%RMl=_E%m)DX{jb6=s;aflX8-6Q7-w6+ zu|xysN!PJ)#OV`DeN5@vUf*U$<%nVW3CPy*(y3nJ8`M9DAGo2;IJ`aG6CWJ&IUU>H zJ)tobCxHT#GZbimEqpO>K%Jtu;C+F8I1CPEuV<zGUC_V9ak<gE)g3wWH0GI-;>Clb zs5&6zhe#T$=jD@8fiy$5_BQELb(}3~(wlY1B@&VxAk4H_iUP9bixF)HzV`Wjuu32% zFH-GmXH+L^w=8&=BfQTeY^XIC6ymzz?-|Lq;%M)MlLFxIvy)JvKKMyEU9`=*-#Cj+ z`-WeH8u#^0>Hn+ktHYv-{x`=0L>dGH0cmNFR8mTiZYcpJ1cvS$m2L?EN$GB-8KgnF z85kJp2I+=9<M-M9?X$c8?Jj?CXJGD`bI(2JbKXz9@5N0rr5Buff`CBUM}1N$(I<2= z3Qln2NWJM%!b-Az!UZx0g{!`T)F1d<ciik<FROxH@$ohd8v{Eo{-4y_pLnbcIz(Xd zW(FvRZFwg6g$5)glz#4>py&K94UQsyk%~am$XTq*YQ+LKpsf8T;G<sRm}Q#W4aboa z{6YrO$^|D^bD%z|WZGPg@jfLKfKR)U1#WwCi1EvFX9cyCwV0&>HK1t|7u})!ay{cV z_fIe8U2qbpOpJFkb<j%o05F5g)76p!T3Hha>TKqRZTgfx%b>xNljkhW6E9%70nL&v z2r!yU8hLm!ErM_Mqcwama0MWcuz(2Oj46=Rux==2x$p&SB@h>IG?L{OIk#TVOX7zP zfh+!kaizWcCFO@qm2>(pJ@y~2!b%XQI>0u9J*j`#3&=x`;wN6lTfdnHQGj{~7LIsU zDIFMF_ITxaSz``9nuK@c7@NqCb?EtHR|Qx(4&!rLb?nB#q=20^(_*rB$Z6RW1eyl( zi&AmDIoSY{mK<GTuuh`6c`Wn%U+H($BxJ}C<P0{4IF`#B3%o&9Drf>kBIql&&lg8G zVh@YFP#4NZ0E_->fT2Dd6q~3o=&Hrt8U59g%_n73?7BH|pzl=IFL^mI_a+q|B0+|r zQVo~6{PhF;SHRh(8-d*Qr<56wvz=QMiXsF9^lfzcL=%)*{Oa6>aH36?2|3d|+4^fl zph2KoAGdhFYBC5b0FGmSzXFPC_xj&nw*m~*)j{YDWe*_mk)8iQ0?y@o6WuUI$H!N} z4t13&HfV+rQAe0bF)0>H2#r;2RUIlF=Cp;ju3{P{MP6?G-(1Fp0qNh?3J5E?d%7s_ zl-j>B=HMw23};K(Hl?q@Q)_%mhmd$pg!i+jMc@GdzF}#GNj-C$g>H=vD>wq7w;@9b zY42@`*ws^PKF6v&i+}WlRw{5B2|Bsm<O4!xM?Ex+!vQWqw;+|Y%{os3L5d)>^^2KY z1g(?}k*mzMB|N-m4g%4Qng96ilNN_u@!M>nASo{@Ji)Nx_VVxYgQk%|(;$8Z<FFZJ zNCw^Yg|7?5fEjpfI_5~M+ZdH>VI09=5F^B@&?Fl(ql88HhM6nSP&1n$X~i<^NAUdr zT>rpxur}}?=Iy|AtH!+DF)Rz`CkqRk?pg2Ge>7WYQ>NYd$<6K(Du0rS$sekBUW3=$ zOw%YRNz_#SoQA5!s1A+y{(Id+tbA=W=Y67#)7gq)8UFA$jw5{O{m#T5FULQ;3vK9r zz{iDkTiylx{QByG-=e<0J}Eibg<Z`EfQ=u^9wO9E6BBOby8){Kj%z|YZ+gv({>T3J zK5R4e*>)B^0KB*Ui(?2Nruhg52z7%RtyoMlP<Dkt`qIwd?%tQLq4d$<?(&*WuF4Pq zcol`b7OT&MKycz_J65Q4Z7M?~B0rr0#%#zd>1FOBDI1K=Qg4Q8%M~y5h6x+pFPPO! z%>jf|NQ7dm60$mxgt>DkWj($!Sr`yBrhU4WA88)&KYh8ENRd_#->vu5O14S2?d>cS z0FcVU?-i$~Yr(3Q&eVpltYL?@9oRH`8IY=YuNV{<Xt8eh>>NM%->F*?pq3aE@G&>V z{{F_XS_6a`)~+QTbu`O%v(FjOoez&ut04i&HLL*!jk4w0+{(tE=&Uap{hpK4knSgk zfC>X1!1@3QeRRQs_hQ*xK1#Rjq6kdB$lXxSi+<uYFh99pn}?nDc)ey!^yIKRl_pJO zE+xLBEsHS<g7CxtqK-hL<fv<M^P2U|cYKftd1jcAh>px1NIDnwO{rw!-oxP@79Vyi zS9#8E$7<J%q-J<YWkiQ~t0u1NMvb;_oxi=SLC@yPyR9X07O{h>nr)aQ8i5nsKamK^ z?vJRXMF1dNGva3Zw}DKfqhH*4gC&q>PwdW1sHKsvxo82HNUmXF@BIV2$bSFKZHa$< z{|f49i6zjrs{aC&An&BJZJ0CJZz0(NtUpQmTh(+Za2}X92f)}LdOn0ex(R@gL?p1@ zxQ68FctEsag!x00t=ReYFT34sO5fo!u`}SJUIXae^cJYcIRk?2y?219(nRE7X1xsR z91rWyeocJ^t!r`(S#Xv30wXc8EPUh%MAU{JfVMva^aQGIe`l0TPwZI+ary;=&I|@c zT9U36=}y;MTrGou<u?=!Xd8$tcmSvVd_!0VlxcqD1!Dm;A$XgeTF>Ty9fdWXlbFkZ zvPeKC2D(v)PeDP`sBY|;%`QMx$8%yXI+~UtSD1FrE@M;!mn%T5LljH!3ktwg&!~X^ zaCvN2YPKIOG<z>;rnjJ{oj14~k3O&IBE);zgLO3!06@*nx`9xl50L`?9mo=)KV`QL z0IwVCYWvg=7>~nAXQ|V+n%5BgV#`|Tmo1crD6gvzOf~lai(9hxQzIXs&+b+j7gYmE z75%``tn>7gD^O0@bXeZ>!*lSw7lee(9fA5@HxFo790X9Cb`J~lUj0n9Ec#F)cM<rX z)ln)gRw9M~G0?oTXYte+kZxgc9WX$$od>Kzblmo8;QYs~fY|cY_N-6R*&Oh@VGVoI zmLZ~7thXS)o`6qVw9_x3BO7RM<mlC8o{u1i@P--fj`W>eJB$|emr-?R%RwOA1ZZ)P zX4rgK`1_UpO1+sZBXM<=sKWEALYJG>`Y|Ilr{!^GL!I>YEu5p!l0BH`BJ%ZxtW=u) zFudf^vwsD=|4WI1C6G}&yYd~4Up+Xh)R_TP_1X6zpAHmuY;FdtD<^-eUpgK+DF~q& zTsj6oScS(5?xsy+7#Mn7X0Y;KrCE}}gR8y$4``7RzKJ0Ds1j8<U4otu8|q2|R`*xE zntz6FLjUk`5`%S*o;SuL!iWpyvKS~9E%;cGfKHA>(PoqiOu+r_LDMY=HaSrA0m5U# zLXRWp5AS;dp^dPnLB*%1dsjC@H%rCm3@cuDASBfOl-z)W?2M+@w(kNuVQz)j*lFBJ zYa5X7YRVA{IRksoz5DYRiY0&o>1oslwpq(9YJP6l<;4q3{(~lzp;Mr*OPQF~ZOF%O zPmmuy(B3S%>;)aC1(6TVW2XPwQmcNrfH?u;Y%Wg;A&@>y(5w~6F9W_e+H#<d*Q;f= z!yctjf%&%VGnXZ1xdrAdr27`=WEO~l|10Hg<XXvO@&y?PfVO~3IL?gnJ&=AiYcgAS z7Xr}$N+_d`)~V~NH<KJc{M4`Uskc$Pcz2AKetDVve&cKoWa^rsr(G*wVWk!sKtty> zmY^{wsNq0U8n`U0mM`N$SXbk6|IgMbz_)lJ4VhvrgC}^H3G2E~LGt?{7*sjqCx6FJ zngKyudjR_4C(994a}e_d%*zc0@*x|sR7XK5TalModzcj{Y>0#!5G1KeJXC(`vs(B9 z%~b~MuAI|l;0*aLh-T}0p3d@H=q2oq)hL6>`5atmz<-$BR)AxhVkt5-^*fJG-|HVl zldC$k2hOs%t`{}>4u=9mMvk@~K<FsRbksGM<7*k!mFu6HlVjZGH86um+8~e)pk9C@ zAS!l+?lG8F1KDX%B2Lju5CZ`5r|({=z-VxhRxl(X?iT|I6Tk>Jc4quid1?y8tY|w- z4-kK%0ifA11@6g_XgxkaQs28DDgq4>y0N9?Q&WwGEP=14#EH~!U?E7>w9>PUW-k`U z^U47SA3`G6i{?Q2g9_ZN2cI+<6$QXVB|{p|@3^0!P}AR)1#%dVYfvJ40Gp%zkB|RO z0KOdwESgq1OW{*ob}Dqit);kp9H1bi>TvW|NkFB?e<)c?m;#uUbgu}V6_@>PnwuK% zZ5R3u?q0_lnRT^eCqBW%Bv~Mc(&t@7Fn&*MoJ!sznR{RQk&1z-E}3NtAuhRN)@C?v zmS2>TJ<ICl=*DkqzRKA*+t28vBO{SY_QuM#|1Fg@mnl8@GjeSkXxGQBsS1Z*Sf-|k z%94vk!foxMqwBeIUn{HMRzI^};YW=ciQA>>RjNG>eI|mea69N)D+jVi1q=9sjUBDA z2$SV~LjpNztDa7uvXj$Q6Q`h%e4nPDSv~PNj<@5!=M)tD`eS@~(AqDY`m$O4+CyIN z&6_ucg)!8+6jX-J4ZPPcS@I9hI!g_DI%@`kzj>2A3ACca#&G)kvIFq$8&a7E%$43( z_77*h0zWyg_$d1S{<W`{=}qeF?3Cnu8(zsVt50z;pLkQa<QqRYDY{QX^XL&}$X?)$ z(1{M`4OjN7A4!20n|R_IGfA4FB<@XWeTBVcx6A4!Ig^Vw_=t&<LhdhXtgiB3UHw)O zRdqdk)<4L+UzZdRP`j(G#7A)v?w#E0b}N&G{&&aGqY+i)JQE+H^Q(4EKU-NNo$$!) zY?H^qiZgb+*4wfg<1j%Hk;f&_TPlBIo6_ZCm5^e|h+ktt^jr;BO(TARLBjCKOJBnr zF+}A<$A3L(kSwhapVS}PO?L~7@WsHuOvueO&Er5dJ}QZAL(Q;Vi?m&9-usAT-LP+) zvAHdq9V&^PrAD8Y7CU(|h|$W)N*?;T)-;RZ!PQkSb<f9@OK&>FJxHh?PY`9=YRL91 zneSBQFu^yfm+UxP1U*d29cD0;KUGntM3O?bI3}kNDU9<k0>2~2psWlkf9?v^vav}z zKMyA}H!;az^&U_PXi+ucHof#y=N1!#uQ#ALMjtMyW0XxcSdABYC(sq9;L?#f)$#~0 zjmEf#b+*z^ki?nBMl3XCCb^_eb;?qa&e}RC=TCJIHF~+tx7>|3y-*9aK9<@#RGpop zzE~b-ij_@XqZ<7|MOC5lbSYYubt~*}|F69X6D7ezr`k`SSDh|6x8PsgE9=}3y4NfG z!g|?Y0XlJ(MxKo`*)Y*fvw*{3Q8u<cnP-r=oO}ET)$s|Y23xJ_A8{r6%)%v#c|}&% z8s3<ecUhL$_&$b$4XFAQ30JxPOT69$f6qX96SKN>bmhm(oQ+9or3dZ~9Ikyvbi0m0 zmXuVZ9ZqVgqDcG2MW_2*l1^BeE(-^e|FOPRX-VSYQqSyl1DUIl95<qN_sCahzY@A* zKQrw!BS_t;syV>!CBj}-ep)HS_k)k0k-ATG{caexUxxQ$XZNBs-|^IYkm9}#@yIB( zzY{R8y<762f$Ofwtv#%UNjK9<wG?3kwcJ?~cTB;P0Sr>@_U=miYww}mLEYUj*`gAG zfLwotgHWMJ;`hbOg}3LHFd+LtEcY37VX8gnDk1(-VIdm#Lg4A#=EVf^PtWFsnVaU2 z_}Fn1Gs-Ss-m?couA;<T>PGxU{hDiD^%?YYc1HHJY37C%T_MzxWpa~coL>k6VUeo+ zq?mMe)HhyQG(xWezs}w(=h^S;u4|Jvwer5o$=wO9l%Dj1h$i-I?rxhM7*~?Kn?jOA zXzTy9p_K0ojL~ZbZapPHFFd7wrO9@vIBLsnTc3?Cl^*3}T*cHzIIMk?Ui6Jl0jh3& z*4)ryLP580C3V0o%3^Na^f^;in|v`$CY+1Czns92Q5>RbKw$giPW)AG!m$yBxBw?L z%Va!kG1U$_RrAs{cLCnkUq6tVJf}1tiOt&iIjp%R0hhI>2BGv&f!pkb;j&<}JpKf! zNe2NWA84^;v;DbmFy#YAo?}n0uG)LEOP^-jThnuTq4MT%swGS?N)BH;&a%c%sL^b; z=sBx(Mv~i$Ua_k&r^B_@vjYVUjdd>7ceJ@+*|?uu?pY{$-}*=d(5GbxGPg`!=WGil zs*fVArn)#SJ^=HpW~FuIGvD|(S6k1TyQ_FrggF7%*T0r~KefCRkjaf%vqkE#nzZE9 zH>H-yNCw}6NYs8Bld(0|sDoE78oVmW(Dt0J<ARL{nk4j7`R-KEG#|RVMPeuEKxdB{ zM|(0AUo<^~Ugl4mj*LyxcL5O>Kl?i@Nju-*r~5MN<^n}ZMU>ZtFO#4oWL|<}KemvE zrJ;78>V{B*=kHf8&eh?Id=EIm!Z+KT&`MSeaO#zSd~5|MtiYbe!AQ(r*E8EeXEFYy zCOkYM_|<u{=dR$+ok~1PtsUXVuXz)=28B}#W~B=%bIg3Vr(eDGj*j5zXj-NPaj%c| zcjTR@oDID$k`9BRyp-cy$MJZ)XI@^hKF>G576^P}P4lg9H8xf=cXxjiG=l~BZ?{`< z8EF69_dedY5cFyls5)B_M)5UT5zrjNj^@DnzwRh^=>>Osm%rJlkxBsS_U#M~_sHW7 z;M1^qruFlumdKT}mOiCx6HqA=@TZiETWHNMp|P`B`(TW3aYv)63MSyOT70NAjXise z8x*!Dt5)n~K7V-znkW#3A)2t>bSY}->yHR30LXXv1Sug&w;P~qoqy%meCAgl|KgZi zFGz`Sdw}flLbt0AOoi*Yx%RvP{}Dwm;jm|kXAdA>jIaa=P(N$R>hS8bUuh?6Ctr7J z78GSa<%Ndkw3%C4y;kH6;Tka){;gS4Q?<wB>IIPdQvz_3!jjL!;I$B)bZ%;ac+1{= zAz|okKfi^$N$p+9tonMuMrzGegF7^32!P5LTIACM&!#g@N%lIHG`lJ0%Yr{mmHWEO z)B7tsD@WpbFmZdBx$Eg+0w&X{FPo3N7NQN74+|T;s`{SZczwIDt%FU6bTG96w)gJO z7GgPBaIyJga4>5+48Bme%9`epyYS6|@90RHgkhiftV-i10J))B9rw_254#SkIn^PB zz<%5sQ7H+>bhNb{7IA<s?0@PVkr&Wwaz!sD9#Kg(0V>-G7vI#m%g#mAfGdLN#}I0F zcRO`=^Wfx|$$e73x(jDBtw3PeIk}~$r{}YcOMth|U&&HI$?=?9S_w(u6<tzFN?$)F zE%GC>5{7UYa#`%gU2hrB9oHA1(<>>XPItNP^fBJ>ojN3O2t)$|+Xrl2JK5XfKGUd~ z<UbR?pk~C$5`J~RAP`nC8BNSFEx5Mef2eRa$4z6Q@kON9D6*gdpEF{F!oFCWIbx9z zlw>)5C{$vakjmO#dpi1Xb4M7+7XpPt?eHc+*X3Vd8E<0Tv(<GhMWD!XySCuG)umt8 z2#GgFa)vp+UBtUTL@L=<85!x4HrGw0ln<0Gkg@!FHXXc!WAM|=>a066YquczK<tlz z@Se!6$(NH;UhhZzj%<$f=TMR=1JpO(Cx80xgWfnM<p28f$3O*tGdrXKU+J4Nv+JN{ zvf@245}=0u4G3vE1NE|nUNRrs^us@~W#WkGS<jY(131tfeZBh_#TaTMvncN4S(?YZ z!$%RJU9`QHZ);b!zSTYf#v<qbeC`<TG)B;t)Cm38`rmd<7bRz8LDv`EyS+?!#KTTe zSG54cWwJN4y?EJdlp-73J?9C<i*UVgMXFFjAOyCr69%_0ww4FYQ+P-GfPK-A6ioXD zv-w--{rLA^`!2jTVO)M)WV7w?_Hn9E%L~heGy}wl`Y593g(Y_o2Cz_Af{a#MO+1q? z6Pzh2>81}m1J_~mr*;~4y#nP0MPq0Kcf6DHD|fi>=&;>zQ!{sT+}X8~nu2`>oGk;+ zW(EfQxxI|*t9vDH^-qkLuU!|5s*HX!|4gJXvNN*lKW(4SDPXCHW!f1t7FhDP<O99{ zmVffdvsqpr%NxcU%{Pher%|lpHxFh^zs0tmJLKz5*7>x}_eDx^9G+Y#rz8q{Jlj#E z2!8?0u@$)Dj!KxvpP^r1VawykTlbP)Z+A4`<iTi#>oRi9E&|&g8Q?Rzj<DCy@+gmf z_z4{=$gLvI0)EdI3jgF7AjY;ja;;G56V#i$8U(#DseTSEh^v-7fi6-qU2U$H1?eRv zy^FQ<W>#*eb}!^6Z&&nFrhq`?h+8AheXe5%(YMMcD5Se;_i!rx+N#d#rKf#wz0S;} z{%B*gq_O=MT#=4hq1tKFLPTAa>tyNgc=pm?z=Wy$*=LzQ^;af?KuG)0&j<j8L7X(T z-ZeL+hkr(hc_(kK^iLv8s008ut+o>>E>rTU-!V`bME1mL<th6-=OJ9=16z87HQ8o1 z%jD{|t0q_u@2~_nery?0SK{N|Nc%?Ze511HL<!Mtm&>nStM*dk_wqT3ih?7dWoAkb zMw*rDPVsu*FuW58_g99BA+cPuhM9u#`y;=%rF1Qj`1cUU>fjkfbA;#_IJs^0r_b_U zDT}D9<@!|bMXXX^I8=^W0~pCO+AdaASQ3FNVsanIku51Y1W~rw^6i`J40R9^650*F zVW-IIU#@iY;M7g)!yBl_tG7Ky#!;ms9LyJvj5tc_xu|(c&#sRnf?|{2wrM+DMAAex zjZ^FIwS!6d7x>q8I>`CJs`}3pUxUnp+KMawUSfX!%J$Ql`0riWIf}aDV}3;Yd<TD8 zg&>S`yL?!DtlFo|q^*tWKD?^AX437_9jS#}_Vn2<HRLtA@jS3DV>ATB;*WhSJNCpG zUl)VP{BLE(U<>Zh@6cX+fj$lm&V`*0_tSVkb)6d1+5oq*rr3*rhZ5t;x0*L%xBb4r zH>RZDK)AxN!Rlnk?2bxJ;Bu8W1OjnXG@Cb<AP5#J<wq@de?t!+zTsCJV=3vkqd6gd z&HHvZv+px96?@}7y5M1w3$d19>wrGPt)9N~v3342^Ub>naWn7w<KDtz*lR0q`2O^? zHyK_1-uiTZveVwn4QxS?L1Kp$(VQV0UXOQ<-C_*-D@xK2B1RYO9!Ez?{VbV18Cjg= z$(_85fw@Z~OnMTJwZOUqy7}Ar5qz8^?sioA`SJ;;LiZnzq$DlhjpJ>8Yq(;bDxYTp zvci*jwDO0h{@XO9!g*dd@v6D?x0u*4#SQJ{1_%!y`WK1)4_Z2_^VPxSh4*75|9rq_ z`mrfW-iK?$!^3Lpgb}j52EW?a9;Rzuwi#Xf-4tFn!xV~kRBrxcmBC@J4c40q&Q-#v zVP``N=UjG3`g&$zBc~&)vo4y1RMDb3U(wF4dz2KPxf;t4M-+Mo#X;FA6J1hT?)v(N zRWj%}zkmQK6p<KCvb&LLW%p!b+1Xcq6vlSFQ2St%e<Wyp{3o!p-J=+y(_RnESV*2_ zO)ND)Di|NxK%Nkf5!<?l4KsZ~L?6EXtMk@F#x=X4!OO|^#Xt;6Nljp|?M=^m0S(oI z;<`5K>XO+>_*`L;fOHyIBw*#UD|MXHC(YJWy6(<d#j@-X;o;+xnU51jPi}I2sgyaE zI;>wm-k!0Z=q?)#O~t;Jag6N6H#hop^BfCOF3C7ATTaO#;vkTqCs_B$%MQ9!65U<L zFYR1&bvYIl*>3}Hp=Rw&`i|l<Pnsh3=lRA|U7$<R`0!kp$J7AMLZh+f!hAY+Z|=@5 z)w_yH+5OjM{i_G#q#Nz=fDN;68YJn|y?U^`!o|q%pFAYyYaVo7U88%<g%WaHJRdB* zKw|sd9(kjomdjsy24|lD{?9^Y-c(I#@$Ao{Y}efA6(WT6mxhCV58C^A#KBT|In{B~ z2`^t!ZhlQy-`ab9+>fi9EE(UbRj#B`pMn&v{&Jxk(!F_9s;BjR)HX1v>p}HK<6EPa z2}(j-{HRs)N}atRN`c2Y^~#j#GlJ*6!<4UV?}~itwlJ$O2X-;t##<`oS<0Wxyl1JA z+toS^)(O}<9UT2n7eYglPjp`B?F>#{yFL>)>&>Z6*f@^ZLuI!S9CJ@Utk3y$=+Z;N z`5-XJ&Th`2Hude>UG-Z=A0V1V-E9#<k8?7WlR=HjB+S+4GI75+6qr8vv{z_HQvK^I zfva>o-4j;*KTQByyUv6)trZxQk?|@C{7!dx*A+spo6V~hv#!k&T&ibt?;D-AUSiUR ziL9YJ8D&}V7y*JkN~i`boez+woE=oQ?hQ&$=vvIjrn0-jc(&Ou61t)yjBXGv9cQgA zg}?gT29cL7L10NrXT$PsX6nW5^c%R=P6ksq>VOW7fr`r3{nm#VcPPC^T%AqV*%%Za zQxXXqwnxUtP2yN+nT~PutGRegwRQJJ8xyenrN#n86m{f$=N1;mfnng`84?~{Bik7j z!4@e2>?X|XWWDS-4ZFAw++G{~s$FXr@u{U5z7vzd!yfU-hM6=d=DdNUm*f@O0-S1< zS<;ZpBfWzT_wk4cg|4^SmKl)Yz71?^?v&Ew<kN*oBk8%-m~SW{hl3y*Pq>q9omB?d zLN~20H10&*i%M&_f#E5(&kzJ~cowd26+<n1BwM7~OUbIMJ$yq3a0JJFld_Z~&Dt9? z%d+w&31p;+OXnJn32{mxkbIg}CF=5?*7v(Wvko`3ZpQbzs434JHmC*WrPYgOSCgv^ z4Z#)9>z}ReU+*SANkLHg(=Ub{X2jr>?Gfj7vC770GyU*<I5B(&@)4UBXy9#?CIO2N z?y~Lnj_!vP+Y~Ry8I<VB)D1aj^YNrKAK8^C;+IDMK&t$9HFI0FoypDMgygF6L>Re& z9>s@QDe0KGgp`s%kXk!>3B=G4EeI~(E1B?8in8^QzDQm-xKs7SjjFZLEOD8})f#`M z_3)f()_A2dkPsipcAa^DVEiW7q{=O)VZ@AdQ+rr@sQO4cMpQYo1On1G-2l+AzkBdq z7WVwbVv3r`%W18ub;UEmxoqa^U7yU0;koj{5~Z18Lht#2@dmf9>kp*wrfvdl%bfd6 z;}dnJ4>gUH&R-NBL<#cq_qfV~uwFN#e{yl{V&md<j@RYXX(dc|?`}m=u5TRtnuq@; z(8`vJC9S7Ar@+>ZtOo!1HB(gia~>#G$o6#%f`Go0ta?Rv%Q>XF(ZhYJ2Jxjr1rs2c zTdhh={VM%YG?dN0rtN~+B9{!V<8eAlcBfwF$LYg*3H$n%!Y`)sV{83qn&m8J`S=xd z;Kgu&-VlnMuiq5}C{3G*=QV1G0a12eTBK>`Qb-S1WF2#q$}8b{+Y66Dn$(6#Usov_ z(GvliH4UM>${d+KJ|B%~Ral?AqnCDdC@o!PVO(zy5l(|f6!{14I{-nB-JNIR5Ubhk zjJ6h>YpUieQ4=xAa5z8S8RZoo;KO#S74ux+D)6S=@_&{(a3Z;y%CWtgw$WJqo7+9? zJgD30`RwP406F&d;QLIwHMh{W;+B81X8E^PznkR|q>QUX8uYW)Ct=icFR*s>D6Fn= zT`s>^*#@O@*XJCx5^uw<+*c7nGr_^}A%W`bib1qL=t3A1i{}=|0lfMP*qs)x_Qy0g z2YI8HqV;(OE@F#+`^2ADjX53{G&eOLDHX;d13e{B6O+hwz8@$2Zn?+nR2U<c>(){1 zP~RWFzqgr#5H$oFNE229oOWr{+;rU=or9{#pz>(qDBVNah{J9=G&V6i)5VpKvN9GI zU-*%K*s+XVQ{&-}R&E%fp{LT^_gvK}dF?X|9FC9mw8(ZIkG=C>T%5>@;NOk>(%7-u zjkyX{+ZN8w$NDs*8&Sc*@WRpbXRhTEyrsPDS6CCbM&Ud^B<{z)2R#}2WS<4KH9xKa z-+O$+&UTUcDL<Ee!9SqW((dB<_H<gF*tdyhnS+OVc^O${P7R|&Jl~@{Z)^l;JIADt z#!anSFTu!s?31chE59Dwveb_<pC9g4l#)){O<_aX=UQ&LHQx{#dW<<2pM7*P3K|`v z6^@uiMVIJ2<Bx{p%>d{LS-RaC@%db(MwZ&(L&`Di;_wCPTT&5jy1Uz@U0brxO{o){ zjxVD|N#*>-bhX&nBfkPTIP2`QJu&LaF1^V6RKxB2Uh9b4MXga>Q?2d6#&UmA!i|#6 z-#R8#ebDD*oma^Bv=Va?q+twAcce02BGk3Jft!r}&9+pjW<rK<#%7NtsK&vkguD`6 z)v=~=a}u|@oPb$bez({N7A$A(4f!4NG`0V;#>$bWPKn;vi$SIKr6tpr_>wQ15vnc) ztV^EsnuZkM6$^Nk37qCrW;66vMc=W|Z#G9(-|+j)TAy(~0R3jboR@8BU9`SFHQMfV zV*!78@-TGs6F5RbL81p7^8fQ>t^eCYD0sSt-LTx7Q||<@+#&n<Q*Ge=2lhq;p{apD zWX*?gS6b9ESRx-q01&31+D1c^w#P4i=|;^65kXy@QQ)k&{7gK-R?J3;6c2pn=bhU; zPSPS#&fviSs!5^Gkytc;Z>w3ek-5fM+c0K+x)rVnOjTU=J3QbAfM*8)m%`q_8Xksz zb1$0?bx$tg2@Zk7-eB0y+He;58KI|$$Zcp4ZgK?YNhBsECG{r@uKw`@CrZ<%hY+{@ z_fWpi+E4~gLO$R34fVi61>6k|v;6wFj1Bepsz|?g)bZ+RFW7N#jLX53*uFc1@HA}| zLXqJwjofI&$i6-J@~2cXRJPsFpAHOD$DzVR2c%g_f1q6@-JnPS!dTe7inQ0(DId?Q zAm^_hBCMi+x}yW6$RRm--EFvp(Fj7El?L>C)u*9eZ&(!oU-7`u|6M?#!lOb?{`?wr zKR~B+2MU!($HxO0ZNNvr<IT>_uGN97f@uAFc-sHFL&%e<2#N^V_wxsaUozYE`6x7v zME0hq{Pb{mrUOz)%RVw{^5)E9Nkwel@?h*vi+mf!IEMB9S}br<DrF=5f~}-g;L%l4 zN9hZXWfm<Zy@>LnA~r1iS}4*llt*~qFp+MFJL`NQWVCZ?G^PLRMa;umY3tl<%8cGl z`J&))nK!9*Py?hMdyXvm!AbOZy1T(!u03nvtw&nbJs*rXl*fDUr3LB^DNJ;9$XfeD zF_lJ57RRQrss_y#gZuD;9*vVJH44Ocf6e1#)Z_i&KmXV~#~Nstv1iDVU!16A&>2*4 z;Sv69+NX2**WTN4mhtyf$=Nel4fXZh?2HQ@X?>C3d#96jV@Q}=;FC=D0!7cS3mDnn zQZ8-_eCpF?%e!>GuTXA2gte^qJW`GTg9s*bpTBjgIqE;NIO+#ot*CiqlXA4WO;N3q z?3I;6kuBP1<1C)julu^nJB-CP;$HGQk*dWQ-mBUU@ZKLNC)=wHO3i^pA)D~kvtX3_ zlh?K23+SJM2ePsL8wj=2k7U7pCG(Ryr9Z#Qk&_bylW;a-|14P$cyv^hqwZodh;N!n zn7NAa>{HE~Q=&6#t{FXjO!k7o42>#xem`0A5Sg!k#WO<W%H_=+SrwP0=@sQo(f!N4 z8DF9bEist#%9+6;w0+|9d3GT7h45P^d2;e6baU@kv#WOQCaXm#u*by6^?xUnCE9XL zGbMX6Kp_y-V!|{>cVFm(ze&uxXmGL3!<wE`BM$TNZzTepaZ%cH4rLs1Z=a2#n>Eb% zG`VPXxygXvhd23J$#G(_`px@GMn-LPlM5WO$$yQjE%?k|4Vf@4Y@5JHvj_tj#PnGz ztF@3!#Aj9&MUhqY)OR<(G@1SkXfmviAehG((Ud&EuL`%;I@JiGdQARw-Q-g(xYDQ0 zQxT+TLdk6Az?np_zu{|@{_#6E_UU+a=#1$LBPDg0`LG-VZKAu!-sTjvAR!PWW4ZoT zA^z(fMnr5XlYwMr$XoQhx!Vx!LSL)i_#=~0wjmMw&YgWivgK)Qhve{!aiY@t?i&8& z4);V?`gSov!Ud=q#3A27I7l&Uq?4q&M|JLb))Iq0Zw?YGYnL%kZjMx;f{^t_jMaO) zds~O73_Vi8W$~)x0rz1qwq=8rE=g#S*{?d9+a3{@MD(~VYhGzFn#fNm_6W4PU(~<o zdp)^Qp2XTBOTK)<W2?mQGprO`%#w~mDPadHT?io?Y)}8t462tJ!IP|cDV$R3KmF!Z zKEL~+{Fq{aK<fuyXsg{Lf}3XhoM9~DGoNrRVz8nXpf1`u`#K7_8*v+qsj^e!<2maa z8!w#KzU+&GG6s<2U*Fm3^nZsoOb>xj|NqB>T(GgA6(6ZsXRK@k!K$dc0-ePzNH(aW z_+Gn58X-$8>XNUuW?d#>ej7pvD#z6pJ<^0C>C?C>oTa2w`XAyrB;HG|SR$f^NP|p_ zYM*-=bJbC89p7j_c2%26E>YPX2mw%^C*f+bUG0GiIC;^HMu0C2cYXQHm;O<0H2#KM zmvi<YOT^JrxQTOxN`h}<Hj0t2`Bgb3@%4A@NO}r#f_L!Cmgr#oa4p(l>_^wGBg~nP zqt4gWupehRW?uJ#ei6F3xZJz-oxBeEI2u8F{q#}peX0!1!652D>TcBg<p4aV(>py1 z@8Bj&tFIc{{3h9&VW*VRX>6<9y=f6wY738s;f6o3L*B~CZ&!_GGs{p%ovmZvi!^%f zaBX($wKm$?;Yw6sH-yS&hXvmubokTKvPRZfZt)(T@vioMb6@XZj5wQ5ALrC?R>b8@ z_kfP4hqOtYwX`-Z4|c(u^x?>^v%}!qT_q{CH<b|Z=%=CwZR!x2*J!)4sE43Oo0UJ} zSTyM$Y?ifsSA>ZCKb6;%&zuc8Ka?qX%q&iHf!l_Q6>~c@AdVCT6$lc4M4|Hzv(IaZ zhDNzulzfF}x_bq?zIf!I&4~J~ehe3Zw%I;*h*mcky%zIuaw7E?X+wDm*pHhXW6pyh zPoIMa3v`4Sa_N)?0hv_V*>-Qti?_+Y5XI(*;jbaIvidKap8J2Qot!Bz;FK?O!QRZT z?8K9lCP~A3Dq>A2Q}pFSz*2GP_cnGW_Pvk~U5h@R{)eoX-?P!TnQ{Kk+b_q4{+uxR zY|1%XVxgJ6a#gUY6%#YWkwfn@1m-WiZF-2&PW1aJORTGps`R;f;TNHRI2@8aQhA7) z2=&D%{W4JP0<Hqack&8f%7EvbA-R-u@8)};xXlK?z5GT<cns*8(q7^GFeR($dd%a> z`$P_2@-BekjoiS7W8y<)k|>Qvm4s#!TQ*Dy7w}|*Py)M}`-D0RL-&y8QR1Iz0Tz<M z`&Awyj9=Q)$k=4UqD?(Vv{6g2)meVRt8bHH%v<X0_BS3{YKg~%6KyQ`dPFe}J4CI! ze55iV`NSUF%<DtB=cSJ!KMT6uK=FvB$e_lQ_b7pF)VHep;PsM|I#e+XDjTug!e+yn z@Rh!*&5W0VgF<O7(Jwrn?{|-`Atw=Pa0{y*BfPU*o~?vbX-&5R2SIluv;ZwNUOULt zmOGS8qAI=he(6jts_XPn`gQX1?^~*mlyr0^Go*s{4bgz*BhDHy5#=P{<^L_1{69j{ r(3L##s{+*Spc@bP3dl2wqVa1OR`zU9!4KyK^k3v<l%-20jX(c4HMb!Q literal 0 HcmV?d00001 diff --git a/website/index.html b/website/index.html index a6d4499..0af7d67 100644 --- a/website/index.html +++ b/website/index.html @@ -18,6 +18,7 @@ <li><a href="container-ci-cd.html" target="_blank">Container & CI/CD</a></li> <li><a href="sql-nosql.html" target="_blank">SQL, NoSQL</a></li> <li><a href="schnittstellen.html" target="_blank">Schnittstellen</a></li> + <li><a href="concurrency.html" target="_blank">Parallele Programmierung</a></li> </ul> <h3>Vorlesungnotizen</h3> @@ -29,6 +30,7 @@ <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/lecturenotes/20220509.md" target="_blank">Vorlesungsnotizen - 09.05.2022</a></li> <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/lecturenotes/20220516.md" target="_blank">Vorlesungsnotizen - 16.05.2022</a></li> <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/lecturenotes/20220523.md" target="_blank">Vorlesungsnotizen - 23.05.2022</a></li> + <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/lecturenotes/20220523.md" target="_blank">Vorlesungsnotizen - 13.06.2022</a></li> </ul> <h3>Projekt</h3> @@ -45,6 +47,7 @@ <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/assignments/Container-CI_CD.md" target="_blank">Ãœbung: Container & CI/CD</a> </li> <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/assignments/sql-nosql.md" target="_blank">Ãœbung: SQL, NoSQL</a> </li> <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/assignments/Schnittstellen.md" target="_blank">Ãœbung: Schnittstellen</a> </li> + <li><a href="https://gitlab.mi.hdm-stuttgart.de/jordine/se3sose2022vorlesung/-/blob/main/website/assignments/Schnittstellen.md" target="_blank">Ãœbung: Parallele Programmierung</a> </li> </ul> <h3>Organisatorisches</h3> diff --git a/website/lecturenotes/20220613.md b/website/lecturenotes/20220613.md new file mode 100644 index 0000000..203f9d2 --- /dev/null +++ b/website/lecturenotes/20220613.md @@ -0,0 +1,4 @@ +# Vorlesungsnotizen - 13.06.2022 + +## Parallele Programmierung + -- GitLab