From 7c5c40db2a8d71a857ae63b6238cfac6e257da6d Mon Sep 17 00:00:00 2001 From: Jakub Grajciar Date: Wed, 30 Aug 2017 10:13:25 +0200 Subject: [PATCH] Shared memory packet interface (memif) library Change-Id: I5097462ae85acd705f19e92517c01094dba7565f Signed-off-by: Jakub Grajciar --- extras/libmemif/Makefile.am | 80 + extras/libmemif/README.md | 72 + extras/libmemif/bootstrap | 3 + extras/libmemif/configure.ac | 13 + extras/libmemif/dockerfile | 19 + extras/libmemif/docs/BuildInstructions.md | 54 + extras/libmemif/docs/GettingStarted.md | 215 ++ extras/libmemif/docs/architecture.png | Bin 0 -> 18805 bytes extras/libmemif/doxygen.conf | 2427 ++++++++++++++++++++ extras/libmemif/examples/ExampleSetup.md | 206 ++ extras/libmemif/examples/README.md | 16 + .../libmemif/examples/icmp_responder-epoll/main.c | 791 +++++++ extras/libmemif/examples/icmp_responder-mt/main.c | 921 ++++++++ .../libmemif/examples/icmp_responder/icmp_proto.c | 246 ++ .../libmemif/examples/icmp_responder/icmp_proto.h | 26 + extras/libmemif/examples/icmp_responder/main.c | 416 ++++ extras/libmemif/src/libmemif.h | 442 ++++ extras/libmemif/src/main.c | 1810 +++++++++++++++ extras/libmemif/src/memif.h | 185 ++ extras/libmemif/src/memif_private.h | 265 +++ extras/libmemif/src/socket.c | 883 +++++++ extras/libmemif/src/socket.h | 89 + extras/libmemif/test/main_test.c | 1079 +++++++++ extras/libmemif/test/main_test.h | 25 + extras/libmemif/test/socket_test.c | 625 +++++ extras/libmemif/test/socket_test.h | 25 + extras/libmemif/test/unit_test.c | 63 + extras/libmemif/test/unit_test.h | 38 + 28 files changed, 11034 insertions(+) create mode 100644 extras/libmemif/Makefile.am create mode 100644 extras/libmemif/README.md create mode 100755 extras/libmemif/bootstrap create mode 100644 extras/libmemif/configure.ac create mode 100644 extras/libmemif/dockerfile create mode 100644 extras/libmemif/docs/BuildInstructions.md create mode 100644 extras/libmemif/docs/GettingStarted.md create mode 100644 extras/libmemif/docs/architecture.png create mode 100644 extras/libmemif/doxygen.conf create mode 100644 extras/libmemif/examples/ExampleSetup.md create mode 100644 extras/libmemif/examples/README.md create mode 100644 extras/libmemif/examples/icmp_responder-epoll/main.c create mode 100644 extras/libmemif/examples/icmp_responder-mt/main.c create mode 100644 extras/libmemif/examples/icmp_responder/icmp_proto.c create mode 100644 extras/libmemif/examples/icmp_responder/icmp_proto.h create mode 100644 extras/libmemif/examples/icmp_responder/main.c create mode 100644 extras/libmemif/src/libmemif.h create mode 100644 extras/libmemif/src/main.c create mode 100644 extras/libmemif/src/memif.h create mode 100644 extras/libmemif/src/memif_private.h create mode 100644 extras/libmemif/src/socket.c create mode 100644 extras/libmemif/src/socket.h create mode 100644 extras/libmemif/test/main_test.c create mode 100644 extras/libmemif/test/main_test.h create mode 100644 extras/libmemif/test/socket_test.c create mode 100644 extras/libmemif/test/socket_test.h create mode 100644 extras/libmemif/test/unit_test.c create mode 100644 extras/libmemif/test/unit_test.h diff --git a/extras/libmemif/Makefile.am b/extras/libmemif/Makefile.am new file mode 100644 index 00000000000..48e4bb89b86 --- /dev/null +++ b/extras/libmemif/Makefile.am @@ -0,0 +1,80 @@ +# Copyright (c) 2017 Cisco and/or its affiliates. +# 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. + +AUTOMAKE_OPTIONS = foreign subdir-objects + +ACLOCAL_AMFLAGS = -I m4 + +AM_CPPFLAGS = -g -DMEMIF_DBG -DICMP_DBG + +.PHONY: release +release: + $(MAKE) AM_CPPFLAGS="-O3" + +.PHONY: doc +doc: + @echo Building doxygen documentation... + doxygen doxygen.conf + @echo Doxygen documentation built in docs directory. + +# +# unit_test +# +unit_test_SOURCES = test/unit_test.c \ + test/main_test.c \ + test/socket_test.c \ + src/main.c \ + src/socket.c +# macro MEMIF_UNIT_TEST -> compile functions without static keyword +# and declare them in header files, so they can be called from unit tests +unit_test_CPPFLAGS = $(AM_CPPFLAGS) -Itest -Isrc -DMEMIF_UNIT_TEST -g $(CHECK_CFLAGS) +unit_test_LDADD = $(CHECK_LIBS) + +# +# main lib +# +libmemif_la_SOURCES = src/main.c src/socket.c +libmemif_la_CPPFLAGS = $(AM_CPPFLAGS) -Isrc + +# +# ICMP responder example +# +icmpr_SOURCES = examples/icmp_responder/main.c examples/icmp_responder/icmp_proto.c +icmpr_LDADD = libmemif.la +icmpr_CPPFLAGS = $(AM_CPPFLAGS) -Isrc -Iexamples/icmp_responder + +# +# ICMP responder libmemif event polling example +# +icmpr_epoll_SOURCES = examples/icmp_responder-epoll/main.c \ + examples/icmp_responder/icmp_proto.c +icmpr_epoll_LDADD = libmemif.la +icmpr_epoll_CPPFLAGS = $(AM_CPPFLAGS) -Isrc -Iexamples/icmp_responder + +# +# ICMP responder multi-thread example +# +icmpr_mt_SOURCES = examples/icmp_responder-mt/main.c \ + examples/icmp_responder/icmp_proto.c +icmpr_mt_LDADD = libmemif.la -lpthread +icmpr_mt_CPPFLAGS = $(AM_CPPFLAGS) -Isrc -Iexamples/icmp_responder + +noinst_PROGRAMS = icmpr icmpr-epoll icmpr-mt + +check_PROGRAMS = unit_test + +include_HEADERS = src/libmemif.h + +lib_LTLIBRARIES = libmemif.la + +TESTS = $(check_PROGRAMS) diff --git a/extras/libmemif/README.md b/extras/libmemif/README.md new file mode 100644 index 00000000000..0cccfb373b5 --- /dev/null +++ b/extras/libmemif/README.md @@ -0,0 +1,72 @@ +Shared Memory Packet Interface (memif) Library +============================================== +## Introduction + +Shared memory packet interface (memif) provides high performance packet transmit and receive between user application and Vector Packet Processing (VPP) or multiple user applications. Using libmemif, user application can create shared memory interface in master or slave mode and connect to VPP or another application using libmemif. Once the connection is established, user application can receive or transmit packets using libmemif API. + +![Architecture](docs/architecture.png) + +## Features + +- [x] Slave mode + - [x] Connect to VPP over memif + - [x] ICMP responder example app +- [x] Transmit/receive packets +- [x] Interrupt mode support +- [x] File descriptor event polling in libmemif (optional) + - [x] Simplify file descriptor event polling (one handler for control and interrupt channel) +- [x] Multiple connections +- [x] Multiple queues + - [x] Multi-thread support +- [x] Master mode + - [ ] Multiple regions (TODO) +- [ ] Performance testing (TODO) + +## Quickstart + +This setup will run libmemif ICMP responder example app in container. Install [docker](https://docs.docker.com/engine/installation) engine. +Useful link: [Docker documentation](https://docs.docker.com/get-started). + +Pull image: +``` +# docker pull ligato/libmemif-sample-service +``` + +Now you should be able to see ligato/libmemif-sample-service image on your local machine (IMAGE ID in this README may be outdated): +``` +# docker images +REPOSITORY TAG IMAGE ID CREATED SIZE +ligato/libmemif-sample-service latest 32ecc2f9d013 About a minute ago 468MB +... +``` + +Run container: +``` +# docker run -it --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service +``` +Example application will start in debug mode. Output should look like this: +``` +ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll +MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder +ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll +LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) +============================== +libmemif version: 1.0 (debug) +memif version: 256 +commands: + help - prints this help + exit - exit app + conn - create memif (slave-mode) + del - delete memif + show - show connection details + ip-set - set interface ip address + rx-mode - set queue rx mode +``` + +Continue with [Example setup](examples/ExampleSetup.md) which contains instructions on how to set up conenction between icmpr-epoll example app and VPP-memif. + +#### Next steps + +- [Build instructions](docs/BuildInstructions.md) Instructions on how to build/install libmemif. +- [Examples](examples/README.md) More example apps presenting different features. +- [Getting started](docs/GettingStarted.md) Introduction to libmemif API. Explaining library usage in custom app. diff --git a/extras/libmemif/bootstrap b/extras/libmemif/bootstrap new file mode 100755 index 00000000000..5613c2b4bdb --- /dev/null +++ b/extras/libmemif/bootstrap @@ -0,0 +1,3 @@ +#!/bin/bash + +autoreconf -fis diff --git a/extras/libmemif/configure.ac b/extras/libmemif/configure.ac new file mode 100644 index 00000000000..30fd3ddacdc --- /dev/null +++ b/extras/libmemif/configure.ac @@ -0,0 +1,13 @@ +AC_INIT(libmemif, 1.0) +LT_INIT +AM_INIT_AUTOMAKE +AM_SILENT_RULES([yes]) +AC_PREFIX_DEFAULT([/usr]) + +PKG_CHECK_MODULES([CHECK], [check]) + +AC_PROG_CC + +AC_OUTPUT([Makefile]) + +AC_CONFIG_MACRO_DIR([m4]) diff --git a/extras/libmemif/dockerfile b/extras/libmemif/dockerfile new file mode 100644 index 00000000000..92b2d2a11e5 --- /dev/null +++ b/extras/libmemif/dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:xenial + +RUN apt-get update && \ + apt-get install -y git build-essential autoconf pkg-config libtool sudo check +RUN rm -rf /var/lib/apt/lists/* + +RUN git clone https://github.com/JakubGrajciar/libmemif.git /libmemif +WORKDIR /libmemif +RUN git checkout dev +RUN ./bootstrap +RUN ./configure +RUN make +RUN make install + +RUN mkdir /var/vpp + +RUN ulimit -c unlimited + +CMD ./.libs/icmpr-epoll diff --git a/extras/libmemif/docs/BuildInstructions.md b/extras/libmemif/docs/BuildInstructions.md new file mode 100644 index 00000000000..9bb59b94c11 --- /dev/null +++ b/extras/libmemif/docs/BuildInstructions.md @@ -0,0 +1,54 @@ +## Build Instructions + +Install dependencies +``` +# sudo apt-get install -y git autoconf pkg_config libtool check +``` + +Clone repository to your local machine. +``` +# git clone https://github.com/JakubGrajciar/libmemif.git +``` + +From root directory execute: +For debug build: +``` +# ./bootstrap +# ./configure +# make +# make install +``` + +For release build: +``` +# ./bootstrap +# ./configure +# make release +# make install +``` +Verify installation: +``` +# ./.libs/icmpr-epoll +``` +> Make sure to run the binary file from ./.libs. File ./icmp\_responder in libmemif root directory is script that links the library, so it only verifies successful build. Default install path is /usr/lib. +Use _help_ command to display build information and commands: +``` +ICMP_Responder:add_epoll_fd:204: fd 0 added to epoll +MEMIF_DEBUG:src/main.c:memif_init:383: app name: ICMP_Responder +ICMP_Responder:add_epoll_fd:204: fd 4 added to epoll +LIBMEMIF EXAMPLE APP: ICMP_Responder (debug) +============================== +libmemif version: 1.0 (debug) +memif version: 256 +commands: + help - prints this help + exit - exit app + conn - create memif (slave-mode) + del - delete memif + show - show connection details + ip-set - set interface ip address + rx-mode - set queue rx mode +``` +#### Examples + +Once the library is build/installed, refer to [Examples](../examples/README.md) and [Getting started](GettingStarted.md) for additional information on basic use cases and API usage. diff --git a/extras/libmemif/docs/GettingStarted.md b/extras/libmemif/docs/GettingStarted.md new file mode 100644 index 00000000000..3cc0ceb0db1 --- /dev/null +++ b/extras/libmemif/docs/GettingStarted.md @@ -0,0 +1,215 @@ +## Getting started + +#### Concept (Connecting to VPP) + +For detailed information on api calls and structures please refer to [libmemif.h](../src/libmemif.h) + +1. Initialize memif + - Declare callback function handling file descriptor event polling. +```C +int +control_fd_update (int fd, uint8_t events) +{ +... +} +``` + - Call memif initialization function. memif\_init +```C +err = memif_init (control_fd_update, APP_NAME); +``` + +> If event occurres on any file descriptor returned by this callback, call memif\_control\_fd\_handler function. +```C +memif_err = memif_control_fd_handler (evt.data.fd, events); +``` +> If callback function parameter for memif\_init function is set to NULL, libmemif will handle file descriptor event polling. + Api call memif\_poll\_event will call epoll\_pwait with user defined timeout to poll event on file descriptors opened by libmemif. +```C +/* main loop */ + while (1) + { + if (memif_poll_event (-1) < 0) + { + DBG ("poll_event error!"); + } + } +``` + +> Memif initialization function will initialize internal structures and create timer file descriptor, which will be used for sending periodic connection requests. Timer is disarmed if no memif interface is created. + +2. Creating interface + - Declare memif connction handle. +```C +memif_conn_handle_t c; +``` +> example app uses struct that contains connection handle, rx/tx buffers and other connection specific information. + + - Specify connection arguments. +```C +memif_conn_args_t args; +memset (&args, 0, sizeof (args)); +args.is_master = is_master; +args.log2_ring_size = 10; +args.buffer_size = 2048; +args.num_s2m_rings = 2; +args.num_m2s_rings = 2; +strncpy ((char *) args.interface_name, IF_NAME, strlen (IF_NAME)); +strncpy ((char *) args.instance_name, APP_NAME, strlen (APP_NAME)); +args.mode = 0; +args.interface_id = 0; +``` + - Declare callback functions called on connected/disconnected/interrupted status changed. +```C +int +on_connect (memif_conn_handle_t conn, void *private_ctx) +{ +... +} + +int +on_disconnect (memif_conn_handle_t conn, void *private_ctx) +{ + INFO ("memif connected!"); + return 0; +} +``` + - Call memif interface create function. memif\_create +```C +err = memif_create (&c->conn, + &args, on_connect, on_disconnect, on_interrupt, &ctx[index]); +``` +> If connection is in slave mode, arms timer file descriptor. +> If on interrupt callback is set to NULL, user will not be notified about interrupt. Use memif\_get\_queue\_efd call to get interrupt file descriptor for specific queue. +```C +int fd = -1; +err = memif_get_queue_efd (c->conn, data->qid, &fd); +``` + +3. Connection establishment + - User application will poll events on all file descriptors returned in memif\_control\_fd\_update\_t callback. + - On event call memif\_control\_fd\_handler. + - Everything else regarding connection establishment will be done internally. + - Once connection has been established, a callback will inform the user about connection status change. + +4. Interrupt packet receive + - If event is polled on interrupt file descriptor, libmemif will call memif\_interrupt\_t callback specified for every connection instance. +```C +int +on_interrupt (memif_conn_handle_t conn, void *private_ctx, uint16_t qid) +{ +... +} +``` + +6. Memif buffers + - Packet data are stored in memif\_buffer\_t. Pointer _data_ points to shared memory buffer, and unsigned integer *data\_len* contains packet data length. +```C +typedef struct +{ + uint16_t desc_index; + uint32_t buffer_len; + uint32_t data_len; + void *data; +} memif_buffer_t; +``` + +5. Packet receive + - Api call memif\_rx\_burst will set all required fields in memif buffers provided by user application. +```C +err = memif_rx_burst (c->conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &rx); +``` + - User application can then process packets. + - Api call memif\_buffer\_free will make supplied memif buffers ready for next receive and mark shared memory buffers as free. +```C +err = memif_buffer_free (c->conn, qid, c->rx_bufs, rx, &fb); +``` + +6. Packet transmit + - Api call memif\_buffer\_alloc will set all required fields in memif buffers provided by user application. +```C +err = memif_buffer_alloc (c->conn, qid, c->tx_bufs, n, &r); +``` + - User application can populate shared memory buffers with packets. + - Api call memif\_tx\_burst will inform peer interface (master memif on VPP) that there are packets ready to receive and mark memif buffers as free. +```C +err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &r); +``` + +7. Helper functions + - Memif details + - Api call memif\_get\_details will return details about connection. +```C +err = memif_get_details (c->conn, &md, buf, buflen); +``` + - Memif error messages + - Every api call returns error code (integer value) mapped to error string. + - Call memif\_strerror will return error message assigned to specific error code. +```C +if (err != MEMIF_ERR_SUCCESS) + INFO ("memif_get_details: %s", memif_strerror (err)); +``` + - Not all syscall errors are translated to memif error codes. If error code 1 (MEMIF\_ERR\_SYSCALL) is returned then libmemif needs to be compiled with -DMEMIF_DBG flag to print error message. Use _make -B_ to rebuild libmemif in debug mode. + +#### Example app (libmemif fd event polling): + +- [ICMP Responder](../examples/icmp_responder/main.c) +> Optional argument: transmit queue id. +``` +icmpr 1 +``` +> Set transmit queue id to 1. Default is 0. +> Application will create memif interface in slave mode and try to connect to VPP. Exit using Ctrl+C. Application will handle SIGINT signal, free allocated memory and exit with EXIT_SUCCESS. + +#### Example app: + +- [ICMP Responder custom fd event polling](../examples/icmp_responder-epoll/main.c) + +#### Example app (multi-thread queue polling) + +- [ICMP Responder multi-thread](../examples/icmp_responder-mt/main.c) + +> Simple example of libmemif multi-thread usage. Connection establishment is handled by main thread. There are two rx queues in this example. One in polling mode and second in interrupt mode. + +VPP config: +``` +# create memif id 0 master +# set int state memif0 up +# set int ip address memif0 192.168.1.1/24 +# ping 192.168.1.2 +``` +For multiple rings (queues) support run VPP with worker threads: +example startup.conf: +``` +unix { + interactive + nodaemon + full-coredump +} + +cpu { + workers 2 +} +``` +VPP config: +``` +# create memif id 0 master +# set int state memif0 up +# set int ip address memif0 192.168.1.1/24 +# ping 192.168.1.2 +``` +> Master mode queue number is limited by worker threads. Slave mode interface needs to specify number of queues. +``` +# create memif id 0 slave rx-queues 2 tx-queues 2 +``` +> Example applications use VPP default socket file for memif: /run/vpp/memif.sock +> For master mode, socket directory must exist prior to memif\_create call. + +#### Unit tests + +Unit tests use [Check](https://libcheck.github.io/check/index.html) framework. This framework must be installed in order to build *unit\_test* binary. +Ubuntu/Debian: +``` +sudo apt-get install check +``` +[More platforms](https://libcheck.github.io/check/web/install.html) + diff --git a/extras/libmemif/docs/architecture.png b/extras/libmemif/docs/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..b196c25c5aa6d965ce194f7e5c6b8a20fe88cf2a GIT binary patch literal 18805 zcmbun1z6Ng+c&%-pbH4P2uP!#2na}bEFdMYNFycPp`diQgaRTZBHi5$QVIgn-7Nyr z-Sy3aUiW=p&-Fa-_dc(O9xm+sXU;k2oZlJqo4>EToWwOO5-bP=a!pE7OaTJ9Yz~23 zV!Db3eiJuN&I10sWUC+{0?F+lTL3?x8^dMc5J*8F_OUJo_!(*=scs8_!0b@}E=?Fw zIzS*&SW;qeB?s-5aqMU^%BZ!LHFJN%nuG^#mR-%`ol$k8$ zB?-Q;@jxejVo}99OlCfuajcXZ#C+3V+)vC49ehVC8FZte(VQlj!Z%F`Xd?fk0c>}N-j-x%%g-g;`BU7c0Nz}Y7hEtx{Qg+X&ZALRLbw8zIq z17JUMtE;sHL{CJ0f9})d!olKuu+e;fTL?>bytX-&n=5$!$of?Gh!|DTflccaPAkU~h}J<$!} zH2=q`{5AgQ$R%CxX-sCDXfeMP8)~@tO&E>Cn~XaO567l3-iJySkXr%eiXhR~9x6jT z&%fA-s_K<4L0}&+fSul_kzB`B#DGZ36QWie=$uc6073;<_u$H>d7Y{{lf;E> zAtV_zg^`K{35tIJfhB(o=!qF}d3FRxqAZfq0r~Usbq9+oBl`RE#Aj^1+KRz}D_5W} z2u*n@Is`Ua=z*R=%&Fbm`zVRvai3ob3`6kaz3MchgeUxStCV=U`!eBq|jU*-o)_0wBweOC;p&|2xC?P zDrl5;>$?wM9T{C>K2S%^Shci-`k`4%@o@GFi)tPzi@3vsTcc*SO>shJ86$#ka05<$ zX3eSCqNPXC(rb7djSn7lU)pZOHLbZWmX5>t2CS)aGos&(3QH|u1{gpJQ!)>#8UkzJK>D!pZPP*Oz1j>Q8l&`GCQmGn8frD^{hy= zK}%^82F%jDtn3WyR_h@Owl$;m3ASfScZHOXUf+M1rD2oi*Rr;qt(=+9;XYJ6(u!H4 zT(jGQR9ZEk_x;=oQ(i@N|B8RhTUf-o)Y1b+ukl&bgSCK zx%EdiuV=8o_Br}%zKx-Oxe|uC!24S5sxxIFnyr|w>9g}eiNY}YL1ai_taGaH<4PD9?7-*5)6L%4{q?oM&8!9zPp5>LG8EWG zM30Q2TAExi$q@Sz>F<5*MZ(t7IFrC-apg_L5=xKyw!@dTBR@?=t*o}hR>+sI1agXV z1^TMQ8%fVb5#bVeOuPICXdbD+CiM^iGST_rBh^Zlnc5F-PUgQg50VVJE>J>*nY;&6 zrgu)+xMO9)k9fORn2Ihs&JQ=6_Z%TgBcl)~A5xsfhKz_9%D)vr)X3l1MjxI^e719U zIg;TmYNB*wv*e+re}sZuB}VP!M43)>(<6~rch8#L*Y5lj8CALF56tS_xmiK3vq}a* zsJhwVBUM3`XE4s^ZQdMf$=m-j4B_OrH*vTeUeC}dSiI5jL|5MvdF2_NFXgFevK3Oi z7kep*{vcxnPwY~vpX65?Pa%h%nhX5|23l(SIUD@lo=# z@~_xrw846OV^3+mM-mmrnQp^4;Ycy07vYx+bnc>t`?=q>6LUSKG zUJ7|r`@2#5sm7IHs$i-FjNj01Cl%CBRH$C$2#unG-+_x@Kg$F`Qwy3&C{+qk;fg*b zj0Q$i47q@D4?!qQ=EAff5MlJ&aI=eL1RB%SK!f;NstY6g{zE}=v)Bk9qrF+S%fzDSw8}WI!-&YPxXR{94AE$ zV+y)VtPkszZqOx=TLGh%Cqyk&Fcru70wS(Qq#V^4^R*SWw^k^BGatZuR3i>R-&QoK zdZE)X^H~!tQab=oJ2{^9{;Ve9Tf6TGrrrBfj-Kc4O)>~qO(5+>dsg*D7X_7?xgbIhmN>rq@O7_Vyu@}2wF7;%6z_4>EKQ!I@? zimi_H&J*IBqDUNK%CJjN1vZPSASzPWW3I~f{K+G4y7+1KZXhz!fzR&zY1MmC`iy*G zaV-R!-g@1i7)WGp-tJm<3}~6cgt8j^n-t%(XTpAT`teTBMlo*X3^Zarcg1&prtxj` zM*aJ{HIUa$e+y*DbzKQSyDW1Vm~Yh%k3AHxm1`~&~eP(Z%UKErI}*`W^Ip+zwB zh9%moJd_ogaf;#aecV4+Q|xJXY)!Y?ncAAXiw%32q~X0Zlf;K}z9nTbYc7^j5Nwz)tpDA|M~fmVMm+!SkKDc-PMV~$#Fhb?hxseqUA9OB>LSy zV`D=V+)=8&%{^4`4XhuCxPQHkn0Nbo7%h((250U7D}#!Z{w1XPydXy;?W>iQunt!m zNqMxt8fCMHBfWS;9qVo@Tui4T_6P)V-nQyg={Qc$b8#etbf@?mC4;)Kz^5NhtJENf zkqo*$qe%?b_lx5@04xOH)3+UzxXeLRqKy@-RB)fyTeqm;A`IXYw8K>%gu%bpdjFQb zM&|BJ$Fa0eOVfJhGdD47D#3)o>4^Jh8N*x}WT|naP*$0_)iHaYmiTYeSz!FzGfALF zv&N=dqY5Q)exF0s={^LQXG|(A)}m)IO$6-CbB1#q$tVeJ-MbC<@m;i?B&HV)c&Lm? z^F3(e2@sQGM*p2<#zJ8S1lvQg;vn3}ct5R0O# zMdg`FT~hF(JO1;OiU(^pAAuUh4l35#_z4+k-xPeolUhoBemU&5b=LJ)ZAz4U4^gZ7 zA8OPOW_XaNqjHVYT4?}Qpy-;xX{}P3&llxPrzvKRSE)23{)tK}a zk8$^=y}awYMc$4@x`~v{v1DU~@qn+I8bvWzTYumeSq<`QRFaq8I^VppOBH$hy)G6A zD)Xrr+$g?G$Xuib*u?4+6&mtHN4N)yJHuqEUe0q-= z`|*IRt$UTk%gQRsqazZopICI`p=+_Hfdk!~i&ojJYYpxfKvu1n;|2Hwi!>ihJ4J3M#Bi|NERsi({$4-)6@}CDYZ{F z4_-OO&E+POD-mXqKTttTgZ`yX6m!P4dy_slYc^Y9o$yf@=P5}EIr|r!0~6TEe)u#( zYUa3)m*T?$cR}~fRZ%OKtlbH1P`#HJON5G{b+i7GEE7m}r@^zE_j^iG_4M%T7I|A{ z&x-0oi#eFV1{)~g2_7+3iRZ7HFwzmQLeqg&BXj=>geXOzlgi_j|!TM6B;w+l>r z@4013U7%X$J&*{Pq&+fx{qMTyltnHtFKd=s5bHo(v(<|lCoNtBumDo5q5HPPClQ8W zATO*7#5f)L{8yl?;jP^?1$GMxH8_Xy8F~{{j-sNXF2kU5@o>X+l@Bbwl7Gv&Ko_2h zQs1I=&yCY!DF4N*bQ?ZzVg_=$H5LV9YbY4=Om%o7uSIy3-c$R+RifbYbhikI9(nuK z^3ZEX5earFi{V1=)9Qn{r~`UyWH41Isdf2TcF7)dt*&#MD@(pb9IXxySLftp#Trf+ zT!)b!8$B$6_^Api06_I8xXZ@Q-ZwBHUXq%Yc4f=!{gBev#^*}|IW9R@UdsfHa~0Hm z-d!-ZD8>A^U3{%`Og~#!R&(->UB@MkeZiaGIl%GV*qMSN`ZH zT6RNO0)u*=Yd{qJGGkxz$1Vxp(Z*<6bG}Y4v1(;>&8o#}Md#g&Uvx9v9sfrPGczHL zGAm1S^Q48>jC!$MAGnqCYoo`@pHpi@UjruMO&DT?Z1lf8Iv5eAN?)^l_qKj}Y1;6B z*_%TSv^Rqxk(0*lz3(lZ+7|0a$TY2O1oo=kBk|}(uNGejyi2_O2UDybA!Sk&*cskZ z-V)#XR^_;5g*o2E{ZtWSVR26P z`lMI(=jQenSP^}l3N2vMQlOGv?(=alnPtO4M1wM}F+cPQx06Hj+zOv@Ba^wQk}G!l zT1HJ6dL{`zG($ zHG;e2oUWr-;lEuhHKm=k`HAWYu}BgD%JBQv65M2Gnc#W9oqh{GO<0Iw>&Nz*55mv1 z+zw_*IW4BJYfy1QaZsA0NP6w@o|ygQL;fGkGda*@%hsZrbxd9h4TI?gob zQK7IrapbVE>lF}nv^&1*zbEOJo1D|2o1o=<+I`o7FZr^tJf+Jz@N1U7k7(^0gVs5P-`OFcK%UG+2m zU@ADrJd4UFstlVkx1*IRF0b*Aj2a)Av_^heT9VwA)DPGe-;sW_tJBNC7SOClSFJPA zDVRmh{urpGnl~7Zm2zu;e~^%8%1Y zsa!4<^kdMT3ZHTc#_PC64^Z1T!gWBv3->$#7i=8*7=B_gQ8heGB!4yFF?02{(U!&n zN%ws?Nx#be7j5$pDz`c4WgXL!;gzD(+du^Lu-jNh>HthrB(QpoE?;0N3c7~96pmKwQgv>YtxdJQ@dR~oj<7+#FRT(uzDS!jnB&bDxWu^8#w2w3u6C)~S0C~4M^ZmwESZqm*CBTSvrY5KpC@x(Ter%X z;HhoQ6?)#7TVAQz8A$Q`oE+KyvYx*jsVvwWm>2kmS2jtAUH`LbLNE z6-ER6=F{Ka3gtexsrR}Xzaj4)@0e$i+t=+kti`!aKbkPbpYzZ(PjpFnNW0!fpOb7*$%C@xY8*{IVU>rmsE&QqtmyDOcRq_^u7uUyeD$Q zzPhZq%-=pnV9rllDJZ~TeYPE4_ZbYk6yG0eW*S>iwPo>LeN@VHNv&iySa1WB&m z>{H^2pnthaXK^aKnh+=BHZ!nI5GNC}*8voSZ6LBeb!iRgXpSv{L*y^91&Q}g%Wu=%ye-p>*p>n7*z zK&s`tRI$bfhbdvMTzHQQd&rHJnRDCDTL3cdKc~HAc`D_5@EC^u@!p7>+ynlKCpN{A z&#!HUv>F{=**A2E=_)Yl@n2)*Astc7#9YleS!Fu~A$XC8UVZ|c>pkv0IP@Y{6gd?9{=#uFj`EiC%<~O> z#9PXuPkK7X0ZmU%TV19fXDFK|2VOzMJdfSD!hVy1NL7`@vN=N>S^Q(p*V-2>R>|Ry z`W+s@-)ZCDr(NtWr6_lgO{biR5U3sL0Ps*`dI%w{0qi>dA zDEBP;OiXZNTwk=oF-rh3S*SIS>v7`aP;0(W@9+B?w0Ao{KXYoeJ-&pC4?@Vt{cezp zjcc=7KPG%$2f03iF4YntlTn>iT(q_*J)aWT_GaP=1t`T)eg+hn|Edxc9k5eE zut8)Bc8XwoQ;_@qWB`{~;b1CJY&7?(*YVl#w=!9T;#k{BYapBZ2^YR~S4^l+3FTg}ShP(yRC%1^iLP*HER$v%%@Dxs}|f-_F$lh>^Wne`yl38vCr z{R^cfgW}Q8RVCVoZ@?2H7wf2foQ{!Ut3u>f=AHLasbiK^r`&4!ZIa@A^_Gq6jnZ!y zm6g9`G_WcgCgA>26`tFhP}a}{be`SGIYa9MT%FlW&Dg4G^G0JSCPBj=igAo3l&5F% z=Zeii8F}tJP=^CZUs%Dj($GS+NMiCR;#<+gWIrq&lKaL(KTm0G2=NHI&K@cZx+Qs* zD4U&Jo^?R}pkATdJ2{$>Af7~;XjW;Kq?YT`I(yYO{B!9?j0#TZ-^*+fbG$hDzIM;^ z!>-wgH&Kd84eiEU8EM=l$DUDz`D(V3L%j+-YofadA+9}UAwj$EZ{-#D#z=)W9d-|b zH}r|pI(UU#51NX~-1D}b`20WFw*566`n=$M)HDR?MIB&2+ormHs#?oLAMbuU4*k*e zAhFok<)K3f<9kYbh9@{sH#9w&t zi}5%lEjH|AmwZ;K9)V_d<6=WmVS#eYzl|jcGsvL*c={`>k*K+tkwZ`K?)rhr2P)dy z?J&^_vXxh0H~QXfeTPR8{+ZFKXoG8fYlL;sB_mogfBqrYKO>i}WDuM0&u==Kc&2sykJh~SwzFR-~t*CW^(8XCcD^-v+>O?bnM`-|hBlWr$n zZSM|xi=!{54)MbM7!eV%u%LG@ic~7u`A~vycW({Q50a?Gn{GXQsF7q#88>%16KvTb z3kK2aLhZ&zN{I%&fh5wXv$Hs5VkmG*WfoDN%$!xwCS_#y7S7kVQ7k|SruUV=kjwjxFxD6o*$HX zsBL{S;1q%(_O=6Fy~0}_vt8$~jg8mGVGLpvzuY&`U&f50I>@9H0U#ix_l#{%WkqL! z%LyH!dFL0LxfmROKiHrS+#8z`tth$4wN-r5(NPB-`EM9YPT zX1rjfD-%nMZYHBAJSe)YB-qqwBrf6j#@F}9`;(&Lis(sZbryhN@;?}+#lgfS^W_Bx6O&1wDYq$NP?&L`%iiq>|qSaJ?iwl1+NQM zCvNbjccG2$Hu&sPlBG%|THj}hlr%1^KvUM&^hAFNVtR|xuxYAAU@Lh6x%k}8v#^r zK`#&?ZM+Z<4i1wN5*A+j(6L1%N!67@)LG?@89+4z-Jaq+QOp`v!JJ9))xc9kJ|JIi zx7d%HSv#8AKN8|UJ#CG$prml0G>qufQ615D>66RI6WU72>x%q2+F^G{8u=)V2BFRA zcybnbxT-b0Hm2TNYPo@kr<7d3z z6Z6{qDpRKCJ`f4UP3|flUE5y;hCw>B@UB>UPdt>DBl5OMpGio3Z>&#`Gpon_Er)2Y za@MLE^F8Ib!|g5Rs{1*3@T@$XQfAqK_?JuNK9k{TT~RdW+2E?24ex%wWx{BXWC9yN!lQKHg;9k+P5t=C5>kvKwlI zlJ^BhlFex1}w5ANao&P)Gtg%P@)+JIZ(K^)56pg)zWp6xpE$5p9&{RgA667 zYJszFq29Ey^v8+K;`RrDwElU^+)588t<>lV>{kvr@r$}K&$GI<<<#|7 zox4DsvFW`0Ky`M<8QGpmyTHIep{=%}m6cWN!tFl;OUe>Z^d^|MpkFPM48vGk=;AT- zk)eVaIO^T8Kf|Lv8yuvq-IYbGtXZML$C`lRNA#=S*OUKuJTk?TnYb-wm=rAr?0!4VP1?86x-i`~$Azul)DPe-XQP z-fcWh8CM~(l&(G7jF`UR_Qub0v~=9AmuszhPkUkTgNxwVm~H3ei`E?X4WhWyZ?uBX zcluS`*PJJv4`##te-P0-T~IBAx%Zh4r=8CflXDp_aj&0f=oQtz$BeU7zbb}ovpyc& zk0YZL($hY6CmR*xd*PO7nekyIo%m}vPIxn0CqiepJEL+fhB&uIquc+OT8QnmtFn8t zt4p-X^t8{urqvmn!trN!S?x(Np8Ni$uP?M_u`5CB&hw?5vYI8WHSHRg26babp|z^5 zPVSkuqE7AS8x8JGgIe|oIk`=@i3`xWjs}kA_HIa!60GovCb8RhuX7h*|u|7 zJJgekZ255lVjHTKJV{R{XqC~xHJYF!=17Zw_dBS~t_&4;S`VlL1`|(2Kexz9_XYup-##WDNHyEEY~5AE0RHUs%NPwEC)gwAjPh#s0O# zeTPZcGk!tA4waCCf&#wP@=%eVkBGF6H(QyvN+^B{tHQ3#O(W^X@D8w5NOWtNHoc#2 z^BHj0CFXS9{Vw`uGb;As1eU3mPjoF!$uUx)iK1qh-8P@ud2}+cc0QzUGc2QMe1wPS z9ztV!{jg+1&GK>D>4J96-cto+bVS6#W_X^^%sVzNi*i8?dk#B0yPu0$XJ!q4wyRZJ zay2c#xiWQtZ3&@~47$?*EwrOjaX7T^tsQ4QsbuU$oVgty2z{Vsbs@DJpR~+2)-WF5 z6gsM%A*vPXHgYNC^0x<}W2eh=QT2U>k9B!*ayd^!xlhHmMsFb4C+;i^yhGd|qSm)e zib?L!(lT3@^-(~Qk&|nct+o_(3LZ_Ku1u<3Y4*eubU0ivcG)db4d-`}!2L~Cg0oX& zz-T-?O(+1N_)Zw8+u)Oe{i$!w&vcrKv5`dhEif8U!RXvtHf;Z+ZF?_J=Y={bmu%(~ zS#J^EBfOf&5v6)%E0Di27KiTmM|g8ttd)yr=@RX!gM~kW#Vyg=&0k2EoDSZoSHO^~ zR_U~}m=^2g_cG{s*;q)Uba^Fi{~Pa``-hwh;uM@c4GVBVuXOXv1yMbs$2Zt$$Pv%y zbJ9H?YRC?#-Wb|Wq11zhl-~RJfbDedb74tFPfL8P-htUq)19)I&T29pfurH9iTX0megNN&BRmQQ*{1%8 zgrAWIQF)t9(y2X^)jj)?HW^WCuYPC*SeKac@tl3{91=>7ekqz2>u<4C=Nk;U4}scM-EQw6h| zAhI&9k}7!eRx_UlWCb_fHXiR%Ra|j1uzR)d`RQKN24S;4k#X(TIEeWDv?@p9TsAWV zoHKQ_Y3@pH{tQLrYM*o{XE9Z+)f_3*(fTX6Bu_a^IL_UD>MGU)#N~vVyY4vg(z-+T+$8Pft&a*`&ahxGOvy96LLC?)qS}FoC$o=NhTo zVecCN9NS5hmQ{0+wSoY9(#Ky8YVGq&UIm*NMFEB-gQJ1?)Ef8Nja}(!@{b%VpB@22 zHK=ur>MqgjaNA>=X~mi6__dr7^X&A=u9Ucuz(x)}p;*-lelZza+s$3agbK4s>&f^9fyOU>L^RwzKpXq9gL8g1w zs`qaas$>uh*eXgU17X9{xvUIZCK)YEm7$wWaP zrb!}N@kTGAIAejc{?u)(U*?2Vfc(jsg6|J?+dbGtLULUN#dm}wZ<>ZsC5T**H}m~0 zkniS7?n0RFL{V9`qWz)LUAmf8As3|IIbpxmz9+!fNQ4JS+aBV$fF~w?e)4{ihSs$h zBiUQ4Q+z*9ZgB6oN1rKcQ^)eQ!(cSR)N`gQ3~)1T6s<`3_h6e5RNm576WhFs4xhUo z(yCIU5IR9Ia^3qW6I5aA{ABcZT3pbNEkExKu#vvvc6qKDdWR_|*^e-*(A zU90Ic)fgK3(T1Z>qzp%y57KY8Px}}>+Tu=N3j(5aKo#~{p7D*H6Tn}NUuM?coATFj zdA3x7ce)XIrPOuxwW{FOlzH6gbS~l~|Aan?*tLos(CP0)DthOko2tCP&ibMEvdn7m z!*L6`-m}nm`E_4ZRA_Mun#N=ZARz#I=XmC+;buC-7H>#@Q|@$`9@%EDhf#k+~6gwtt=23c`_c8T_Li{&DTw4Wun3!h(F`96->1Q(wX{za|R;fcsGpJZLfvd zt?ZJ@lleaU)a^*I^A_|) z>%gv%#bnXS&dI2~q6@!pLVg6Ha}M>uf7C^QrF~$R4&n$KtMjXUvKvR>#~a1|uEa$p zy^W-}rQCGfe_cyuwQg6w=(0zJ4?5j*aHeoRmhOz9rt7gl33;u{T#1g**&&}vI?SR=-1bVLB z*pbae#m*|}jptjod~v7sx$~tjPd7?V@>bukjEx>0PE2TNxlU*}t5P;J{g;x2yf+F7 z(S?y8sNf=91sjL`wtVg<{3U~Nr=mw}%r7lmOP2a~V|Q~;1+HN3QQTTyB;K6(U0c{6 z;`(q)HkoZ$Q};7qI#Y?DIzgj?O9S5DuOWvMH}j*9LJCU`tFv-`fqWy*yn8!}Sj*&O zOQi4i@a{&M)JvIpCeir?X80~E<;t_8{lszS_eckE7a-XtUp=3jwu50OW$BvZMnBV5 zgE_U}?smYnfcJrSX<->MFI;+@AEy-EBx|BAjA$lnkeESBK7esD!9~73;)IKDjlevJ zf@OnB4KH|~+9MV2qf18tLNUYS=4-6Ef(kBV2xHo`%@1g{2MeiBYo4*UyniGeIEOuS z{1tKs=XZc}PCI24+M`{7d~)DTZ}C(^S z==3PfVcFh!$jqd+zpR^EYy|W0@HJ9@Hh*6yJ!OvBv^W#B@!&|WiZ|$VPlBj?Uq1O- zbz4U=YGRG=MhkgZ{Dnbj{ch2O& zM4f=Zk_}!#dp^Cs#d+;hmJJlf?g?7FL>e4%{!$=zKoyN|!|ODGm8LrqkO~`vK@9Ws zmM%jTT7A%=U1q=C2l30GJ56nEZQFJ%q3r=QJpw05;6|DKD~hr18%fDX!ZuW61z=d+ zRi)@tj|}jWE!ESdfKtuCgj}DA* zuczR&TVVV$;M0=aE@az%N_*l@ST%4X>C#Abp7q&RUFo3aZG#%{NIcHPm7z!caE0Y~ zbRM3tz%h?025HEH6`VcL8#4BuU(N5@?|pcpmfj z^I_&evo8viB3lR)79KPN4}DRyUz1ery#DmrXw6X9sb~F7$|E0GlCRypD26WPOW+1j z{MFx&R^fu7*MpgFxyyv!iX-z4#CxB7_y+%^zWFo({poemYwb26KLi_^`ouo=xOZO- zVzUswbkol$8Sv_DuD8#Cc`N03-ULS?Ke2m5hh2EtI0S=bQ)m?zEMB<47(D`fe2~=F z6pdIVHoD6prZrvxkAncXr(sF^X)G3(lxm}Gi}#jllD60P7wRPnP}1; z$+6A6_Qd~?S*IrYCH}bU-Z)6pEZ&TM#x&LRiH@Kn^1thM=RkxdJWd?jA*mb@P)Hp> z(jd_iXu*D|59>q;h3-t1g&nX0#Y02jo$?=#4|9Mk-$-*fBDwuHG9&4~z&#f$w4 z43(gC{m@~~JM0L{Hc=vcQ8BhsHrc@!F_5Q&@V;g^1B~NTw#xq9{|yyxyk8N7UT{UmSI9sQD_UY_NwG1JHST)Jh0hTU7Fgc zH?!AgO60q|c&uEeAWv^&fi9jR2;vq6b#|Y%eq;oHN2?s!bTHq(d;0<7u-yhw&v5f3 z`;saFC&q33^UH~~#Egfvlw^<(Z@(+S(|;(Ar!B6{B7X#MO_Uq8MfZjWB7^PkjSD+ zB_e_kM*5}$oB}%J>>=Wp_up<3_IL%iB1mm9SZVH~c%K)Y9oO?G5OHb)R1W3SLfAM+8fx= zgh?9%ZyQ2<8=N=qqKHLLQ92N2xoDq6U7D0MU(%uGtZJ=lk?zhNERC20R~1nQC)%2T z;z9$t@8c-KY*BT7>vql;T;Q#A@;Q71Yu=CoryJgX_4ozvjU=F(G7s?UYMXMGXJz3* zVaLw}!PUXvLxKhwXj@*|n)6T)+kQXbM$vA~&vhw8mWl=Bc^*Rxu8mU9&!A4QbI(`e z*ya;GP;|q~*m(5jN;Gbf|5ziRT1T{a3cw!QN8JNBHwpIRc6`Xrzm^HuWx}*|EF}F6 zIO9GAL@gRfIpBv}bKgQ27C^CXFHAxR48OsJfUskOp)Z>4zX7w+o`cStKZanF>`G$@D;+o zJ+UXQZ<7C#JhKTD7N*O246aN7*qNq=H*yMybI6%-S*LNrPp_NDx%uQh`)tkX z?k7#IiVKC={a^-^X?9=*km6Ztc%g#Eq>+w+F$coJd8B*|+{wgUCn$Z0fRt~B1BPkj z8!#o^pZticDWwVq<7UMSZTLl~bu$5{p}b&iuZzdd`z~gw4lt{A+zk?WBvpGnXa_g@zyDv+kvRf~^bY?rLd{*|OW1iIuT~#YG zRoU{|3Vc=@7Re#&7wR=c(upr8q;*1l7zOMWWeph%sPq(UuDmTT<*oygq;#m^X9Xk! zN5KpGtg8xd4jt=uw8Iq41%lKgy>WMk+(%izYR^T;aORtRC5+GE zWMPq_`~4FC>vM9+r!pzYbKAW?$B*daI%tT*(nfcb&F<5zbTZx<`@UpkNS`_O*yZXg z$D|R7S^nEuCpUi5Bg}Y}Qm;)9j|{pl)Jo07<@VGbQhxLK)2W)7JG$1z7N2vCP0!Qe zbR`++qF>PN&(x|=bY@Si5N24HQT2K7C6V2pyImF;uvdlwvb#oYKz*fs9En` zSLv+=ylRxS2G=>pnjC8|Gn*-F2_obXuToxqXDb>P1jLMqM5GDgu3ZGBj^ z3Je(B-KB`62Z1tYbRa%ZpRzQ3#nBQ=!H~Nv{db3o-kpw#xzYoDUDC3}jE*9m($jN+ zbwrlNL~_&o)5j>eIBgSV_@_^MIk*tu&U9PI`7SX%2bM4ZEF4>294wNLN}qNGaAe!c zmgFoqWykL9-DzwwTgYZuEj@0-4{$@TF-eb+OqP0Y%`q_4iJvQ^mExJ^h?b{UZ^1)J zn~uY);-d;Yq%h-~jJkRLCmA6MSt|X~1cXuT{I``mr3*er%JZ62ls%E!VMml7UsVX> z>J!{reDg_CHuq?NLeq_xV+;K*c+tU^CyxP%upT6)xPw%d=gKcPfg@@9dCl$EXfX>i zr475C0>m>*Rk$)VpUT#xQ?&^PXzy)sBCfxo{OTG@^+O5X8G43c2yWR^bH_tXiA-fdN={%B04@P^ZZ`fdM+Aj3j=-(3F@|( z?(YAHl;;q53VJX~0QmPWzt_;pKkWiS1ndg{bcw{f@Dk?$c223fz$ic6a~Qg?VHAL( zWYhZ#wO|)c5A5#vTYo_AoCbB_c=o5S)BS~(f#((i+#L#n*6VdMzx)AL{ulqZPUb#* zGZ*syf1LS0`3O|lupdPWSwvmGs67W^CU6t19)*y2fNgvMkL!5A6`-6@y9faNi)N=N zJ^TxIP@aAtkmLT}yv9E|qV@XQ3K!T9lumJOx~S1m&hbsX63RdSFP)4$@~74%vj1`B z=T?QX7AF*&HSc_}v1z_{tpmT>_iw>f`8`SYY7!VtTWmPGZ>p*&65XSMnt+O(5&W(= z^87X|0MTc1Pjmr|CnA=~sIVef>~orXvA+8m>TL+TdP;#^$YHVz*GvISbBIJ46J> z;SXCNe`nv|^J;C$dTlXfSWi`z@+kyW2$F@xj9>pYi6u^~x$&?}`JMb2j@oH-DdJ~h^mPdM`M|ilsG~It{Kd)1r{_siy&Yi;k zGzs1PSMt8iMDNPlXd7uIe$04MXPi!po!Jz+-+xW`OWZSw- zz#R!9?e_q6Po8?V)RLO42uPvBoOKqLpVuDA}LHh zv4-+Q(!6WMnR`4m%L<~E9~-DRE{h`*M-|*afkN7CW9WxSV~vbjwnym+qFoX`wIY%* zs=AZq0*tPba75CWe0-L)z(Oqi&5;MhhA3*xSJc&MkO1K;VwkfvK2|j$DF&1?EC-n>KD`tS0EAt-FoCa3i{(>|GW3c{PorrTSgR+NoUgi z@83o9S6^%%Ts<55|L2$2{PjT5fAg*ze_ZmzGd_sc%nnY&EO;jiMCy^8Sgy!3