From 68b711e66b5fa3f76745e5b0d28808fb63eb6416 Mon Sep 17 00:00:00 2001 From: Thomas Porzelt Date: Thu, 10 Sep 2009 20:09:56 +0200 Subject: [PATCH] initial commit --- .gitignore | 6 + COPYING | 23 +++ README | 46 ++++++ TODO | 6 + src/client.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++ src/client.h | 46 ++++++ src/weighttp.c | 342 +++++++++++++++++++++++++++++++++++++++++++ src/weighttp.h | 60 ++++++++ src/worker.c | 58 ++++++++ src/worker.h | 40 +++++ waf | Bin 0 -> 86338 bytes wscript | 70 +++++++++ 12 files changed, 1085 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 README create mode 100644 TODO create mode 100644 src/client.c create mode 100644 src/client.h create mode 100644 src/weighttp.c create mode 100644 src/weighttp.h create mode 100644 src/worker.c create mode 100644 src/worker.h create mode 100755 waf create mode 100644 wscript diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..343001e --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.waf-* +.lock-wscript +.DS_Store +*~ +build +weighttp diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..01daff8 --- /dev/null +++ b/COPYING @@ -0,0 +1,23 @@ + +The MIT License + +Copyright (c) 2009 Thomas Porzelt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/README b/README new file mode 100644 index 0000000..e116e9e --- /dev/null +++ b/README @@ -0,0 +1,46 @@ +weighttp - a lightweight and simple webserver benchmarking tool +----------------------------------------- + +Please see http://weighttp.lighttpd.net/ for current info. + + +BUILD +===== + +Make sure you have libev* and python (for waf) installed, then: + +$ ./waf configure +$ ./waf build + +See ./waf --help for available configure options and other commands available. + + +INSTALL +======= + +$ ./waf install +or +$ sudo ./waf install + + +USAGE +===== + +$ weighttp -h + + +UNINSTALL +========= + +$ ./waf uninstall +or +$ sudo ./waf uninstall + + +You can also chain commands: + +$ ./waf configure clean build install + +---- + +* libev can be found in your distro's repository or at http://software.schmorp.de/pkg/libev.html \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..84d08a3 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +- timing statistics +- generally better statistics +- chunked encoding support +- ssl support +- better error reporting +- ipv6 support \ No newline at end of file diff --git a/src/client.c b/src/client.c new file mode 100644 index 0000000..864013a --- /dev/null +++ b/src/client.c @@ -0,0 +1,388 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +#include "weighttp.h" + +static uint8_t client_parse(Client *client); +static void client_io_cb(struct ev_loop *loop, ev_io *w, int revents); +static void client_set_events(Client *client, int events); +/* +static void client_add_events(Client *client, int events); +static void client_rem_events(Client *client, int events); + +static void client_add_events(Client *client, int events) { + struct ev_loop *loop = client->worker->loop; + ev_io *watcher = &client->sock_watcher; + + if ((watcher->events & events) == events) + return; + + ev_io_stop(loop, watcher); + ev_io_set(watcher, watcher->fd, watcher->events | events); + ev_io_start(loop, watcher); +} + +static void client_rem_events(Client *client, int events) { + struct ev_loop *loop = client->worker->loop; + ev_io *watcher = &client->sock_watcher; + + if (0 == (watcher->events & events)) + return; + + ev_io_stop(loop, watcher); + ev_io_set(watcher, watcher->fd, watcher->events & ~events); + ev_io_start(loop, watcher); +} +*/ + +static void client_set_events(Client *client, int events) { + struct ev_loop *loop = client->worker->loop; + ev_io *watcher = &client->sock_watcher; + + if (events == (watcher->events & (EV_READ | EV_WRITE))) + return; + + ev_io_stop(loop, watcher); + ev_io_set(watcher, watcher->fd, (watcher->events & ~(EV_READ | EV_WRITE)) | events); + ev_io_start(loop, watcher); +} + +Client *client_new(Worker *worker) { + Client *client; + + client = W_MALLOC(Client, 1); + client->state = CLIENT_START; + client->worker = worker; + client->sock_watcher.fd = -1; + client->sock_watcher.data = client; + client->content_length = -1; + client->buffer_offset = 0; + client->request_offset = 0; + client->keepalive = client->worker->config->keep_alive; + + return client; +} + +void client_free(Client *client) { + if (client->sock_watcher.fd != -1) { + ev_io_stop(client->worker->loop, &client->sock_watcher); + shutdown(client->sock_watcher.fd, SHUT_WR); + close(client->sock_watcher.fd); + } + + free(client); +} + +static void client_reset(Client *client) { + //printf("keep alive: %d\n", client->keepalive); + if (!client->keepalive) { + ev_io_stop(client->worker->loop, &client->sock_watcher); + + if (client->sock_watcher.fd != -1) { + shutdown(client->sock_watcher.fd, SHUT_WR); + close(client->sock_watcher.fd); + } + + client->sock_watcher.fd = -1; + client->state = CLIENT_START; + } else { + client_set_events(client, EV_WRITE); + client->worker->stats.req_started++; + client->state = CLIENT_WRITING; + } + + client->parser_state = PARSER_START; + client->buffer_offset = 0; + client->parser_offset = 0; + client->request_offset = 0; + client->ts_start = 0; + client->ts_end = 0; + client->status_200 = 0; + client->success = 0; + client->content_length = -1; + client->bytes_received = 0; + client->header_size = 0; + client->keepalive = client->worker->config->keep_alive; +} + +static uint8_t client_connect(Client *client) { + //printf("connecting...\n"); + start: + + if (-1 == connect(client->sock_watcher.fd, client->worker->config->saddr->ai_addr, client->worker->config->saddr->ai_addrlen)) { + switch (errno) { + case EINPROGRESS: + case EALREADY: + /* async connect now in progress */ + client->state = CLIENT_CONNECTING; + return 1; + case EISCONN: + break; + case EINTR: + goto start; + default: + { + strerror_r(errno, client->buffer, sizeof(client->buffer)); + W_ERROR("connect() failed: %s (%d)", client->buffer, errno); + return 0; + } + } + } + + /* successfully connected */ + client->state = CLIENT_WRITING; + return 1; +} + +static void client_io_cb(struct ev_loop *loop, ev_io *w, int revents) { + Client *client = w->data; + + UNUSED(loop); + UNUSED(revents); + + client_state_machine(client); +} + +void client_state_machine(Client *client) { + int r; + Config *config = client->worker->config; + + start: + //printf("state: %d\n", client->state); + switch (client->state) { + case CLIENT_START: + do { + r = socket(config->saddr->ai_family, config->saddr->ai_socktype, config->saddr->ai_protocol); + } while (-1 == r && errno == EINTR); + + if (-1 == r) { + client->state = CLIENT_ERROR; + goto start; + } + + /* set non-blocking */ + fcntl(r, F_SETFL, O_NONBLOCK | O_RDWR); + + ev_init(&client->sock_watcher, client_io_cb); + ev_io_set(&client->sock_watcher, r, EV_WRITE); + ev_io_start(client->worker->loop, &client->sock_watcher); + + client->worker->stats.req_started++; + + if (!client_connect(client)) { + client->state = CLIENT_ERROR; + goto start; + } else { + client_set_events(client, EV_WRITE); + return; + } + case CLIENT_CONNECTING: + if (!client_connect(client)) { + client->state = CLIENT_ERROR; + goto start; + } + case CLIENT_WRITING: + while (1) { + r = write(client->sock_watcher.fd, &config->request[client->request_offset], config->request_size - client->request_offset); + //printf("write(%d - %d = %d): %d\n", config->request_size, client->request_offset, config->request_size - client->request_offset, r); + if (r == -1) { + /* error */ + if (errno == EINTR) + continue; + strerror_r(errno, client->buffer, sizeof(client->buffer)); + W_ERROR("write() failed: %s (%d)", client->buffer, errno); + client->state = CLIENT_ERROR; + goto start; + } else if (r != 0) { + /* success */ + client->request_offset += r; + if (client->request_offset == config->request_size) { + /* whole request was sent, start reading */ + client->state = CLIENT_READING; + client_set_events(client, EV_READ); + } + + return; + } else { + /* disconnect */ + client->state = CLIENT_END; + goto start; + } + } + case CLIENT_READING: + while (1) { + r = read(client->sock_watcher.fd, &client->buffer[client->buffer_offset], sizeof(client->buffer) - client->buffer_offset); + //printf("read(): %d\n", r); + if (r == -1) { + /* error */ + if (errno == EINTR) + continue; + strerror_r(errno, client->buffer, sizeof(client->buffer)); + W_ERROR("read() failed: %s (%d)", client->buffer, errno); + client->state = CLIENT_ERROR; + } else if (r != 0) { + /* success */ + client->bytes_received += r; + client->buffer_offset += r; + client->worker->stats.bytes_total += r; + + if (client->buffer_offset >= sizeof(client->buffer)) { + /* too big response header */ + client->state = CLIENT_ERROR; + break; + } + client->buffer[client->buffer_offset] = '\0'; + //printf("buffer:\n==========\n%s\n==========\n", client->buffer); + if (!client_parse(client)) { + client->state = CLIENT_ERROR; + //printf("parser failed\n"); + break; + } else { + if (client->state == CLIENT_END) + goto start; + else + break; + } + } else { + /* disconnect */ + client->state = CLIENT_ERROR; + break; + } + } + + break; + case CLIENT_ERROR: + //printf("client error\n"); + client->worker->stats.req_error++; + client->keepalive = 0; + client->success = 0; + client->state = CLIENT_END; + case CLIENT_END: + /* update worker stats */ + client->worker->stats.req_done++; + + if (client->success) { + client->worker->stats.req_success++; + client->worker->stats.bytes_body += client->bytes_received - client->header_size; + } else { + client->worker->stats.req_failed++; + } + + if (client->worker->stats.req_started == client->worker->stats.req_todo) { + /* this worker has started all requests */ + ev_io_stop(client->worker->loop, &client->sock_watcher); + + if (client->worker->stats.req_done == client->worker->stats.req_todo) { + /* this worker has finished all requests */ + ev_unref(client->worker->loop); + } + } else { + client_reset(client); + goto start; + } + } +} + + +static uint8_t client_parse(Client *client) { + char *end, *str; + + switch (client->parser_state) { + case PARSER_START: + //printf("parse (START):\n%s\n", &client->buffer[client->parser_offset]); + /* look for HTTP/1.1 200 OK */ + if (client->buffer_offset < sizeof("HTTP/1.1 200 OK\r\n")) + return 1; + + if (strncmp(client->buffer, "HTTP/1.1 200 OK\r\n", sizeof("HTTP/1.1 200 OK\r\n")-1) == 0) { + client->status_200 = 1; + client->parser_offset = sizeof("HTTP/1.1 200 ok\r\n") - 1; + } else { + client->status_200 = 0; + end = strchr(client->buffer, '\r'); + + if (!end || *(end+1) != '\n') + return 0; + + client->parser_offset = end + 2 - client->buffer; + } + + client->parser_state = PARSER_HEADER; + case PARSER_HEADER: + //printf("parse (HEADER)\n"); + /* look for Content-Length and Connection header */ + while (NULL != (end = strchr(&client->buffer[client->parser_offset], '\r'))) { + if (*(end+1) != '\n') + return 0; + + if (end == &client->buffer[client->parser_offset]) { + /* body reached */ + client->parser_state = PARSER_BODY; + client->header_size = end + 2 - client->buffer; + //printf("body reached\n"); + + return client_parse(client); + } + + *end = '\0'; + str = &client->buffer[client->parser_offset]; + //printf("checking header: '%s'\n", str); + + if (strncmp(str, "Content-Length: ", sizeof("Content-Length: ")-1) == 0) { + /* content length header */ + client->content_length = atoi(str + sizeof("Content-Length: ") - 1); + } else if (strncmp(str, "Connection: ", sizeof("Connection: ")-1) == 0) { + /* connection header */ + str += sizeof("Connection: ") - 1; + + if (strncmp(str, "close", sizeof("close")-1) == 0) + client->keepalive = 0; + else if (strncmp(str, "Keep-Alive", sizeof("Keep-Alive")-1) == 0) + client->keepalive = client->worker->config->keep_alive; + else if (strncmp(str, "keep-alive", sizeof("keep-alive")-1) == 0) + client->keepalive = client->worker->config->keep_alive; + else + return 0; + } + + if (*(end+2) == '\r' && *(end+3) == '\n') { + /* body reached */ + client->parser_state = PARSER_BODY; + client->header_size = end + 4 - client->buffer; + //printf("body reached\n"); + + return client_parse(client); + } + + client->parser_offset = end - client->buffer + 2; + } + + return 1; + case PARSER_BODY: + //printf("parse (BODY)\n"); + /* do nothing, just consume the data */ + /*printf("content-l: %"PRIu64", header: %d, recevied: %"PRIu64"\n", + client->content_length, client->header_size, client->bytes_received); + client->buffer_offset = 0;*/ + + if (client->content_length == -1) + return 0; + + if (client->bytes_received == (uint64_t) (client->header_size + client->content_length)) { + /* full response received */ + client->state = CLIENT_END; + client->success = client->status_200 ? 1 : 0; + } + + return 1; + } + + return 1; +} \ No newline at end of file diff --git a/src/client.h b/src/client.h new file mode 100644 index 0000000..4b83b13 --- /dev/null +++ b/src/client.h @@ -0,0 +1,46 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +struct Client { + enum { + CLIENT_START, + CLIENT_CONNECTING, + CLIENT_WRITING, + CLIENT_READING, + CLIENT_ERROR, + CLIENT_END + } state; + + enum { + PARSER_START, + PARSER_HEADER, + PARSER_BODY + } parser_state; + + Worker *worker; + ev_io sock_watcher; + uint32_t buffer_offset; + uint32_t parser_offset; + uint32_t request_offset; + ev_tstamp ts_start; + ev_tstamp ts_end; + uint8_t keepalive; + uint8_t success; + uint8_t status_200; + int64_t content_length; + uint64_t bytes_received; /* including http header */ + uint16_t header_size; + + char buffer[CLIENT_BUFFER_SIZE]; +}; + +Client *client_new(Worker *worker); +void client_free(Client *client); +void client_state_machine(Client *client); \ No newline at end of file diff --git a/src/weighttp.c b/src/weighttp.c new file mode 100644 index 0000000..1e56e40 --- /dev/null +++ b/src/weighttp.c @@ -0,0 +1,342 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +#define VERSION "0.1" + +#include "weighttp.h" + +extern int optind, optopt; /* getopt */ + +static void show_help(void) { + printf("weighttp \n"); + printf(" -n num number of requests (mandatory)\n"); + printf(" -k keep alive (default: no)\n"); + printf(" -t num threadcount (default: 1)\n"); + printf(" -c num concurrent clients (default: 1)\n"); + printf(" -h show help and exit\n"); + printf(" -v show version and exit\n\n"); +} + +static struct addrinfo *resolve_host(char *hostname, uint16_t port) { + int err; + char port_str[6]; + struct addrinfo hints, *res, *res_first, *res_last; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + sprintf(port_str, "%d", port); + + err = getaddrinfo(hostname, port_str, &hints, &res_first); + + if (err) { + W_ERROR("could not resolve hostname: %s", hostname); + return NULL; + } + + /* search for an ipv4 address, no ipv6 yet */ + res_last = NULL; + for (res = res_first; res != NULL; res = res->ai_next) { + if (res->ai_family == AF_INET) + break; + + res_last = res; + } + + if (!res) { + freeaddrinfo(res_first); + W_ERROR("could not resolve hostname: %s", hostname); + return NULL; + } + + if (res != res_first) { + /* unlink from list and free rest */ + res_last->ai_next = res->ai_next; + freeaddrinfo(res_first); + res->ai_next = NULL; + } + + return res; +} + +static char *forge_request(char *url, char keep_alive, char **host, uint16_t *port) { + char *c, *end; + char *req; + uint32_t len; + + *host = NULL; + *port = 0; + + if (strncmp(url, "http://", 7) == 0) + url += 7; + else if (strncmp(url, "https://", 8) == 0) { + W_ERROR("%s", "no ssl support yet"); + url += 8; + return NULL; + } + + len = strlen(url); + + if ((c = strchr(url, ':'))) { + /* found ':' => host:port */ + *host = W_MALLOC(char, c - url + 1); + memcpy(*host, url, c - url); + (*host)[c - url] = '\0'; + + if ((end = strchr(c+1, '/'))) { + *end = '\0'; + *port = atoi(c+1); + *end = '/'; + url = end; + } else { + *port = atoi(c+1); + url += len; + } + } else { + *port = 80; + + if ((c = strchr(url, '/'))) { + *host = W_MALLOC(char, c - url + 1); + memcpy(*host, url, c - url); + (*host)[c - url] = '\0'; + url = c; + } else { + *host = W_MALLOC(char, len + 1); + memcpy(*host, url, len); + (*host)[len] = '\0'; + url += len; + } + } + + if (*port == 0) { + W_ERROR("%s", "could not parse url"); + free(*host); + return NULL; + } + + if (*url == '\0') + url = "/"; + + req = W_MALLOC(char, sizeof("GET HTTP/1.1\r\nHost: :65536\r\nConnection: keep-alive\r\n\r\n") + strlen(*host) + strlen(url)); + + strcpy(req, "GET "); + strcat(req, url); + strcat(req, " HTTP/1.1\r\nHost: "); + strcat(req, *host); + if (*port != 80) + sprintf(req + strlen(req), ":%"PRIu16, *port); + if (keep_alive) + strcat(req, "\r\nConnection: keep-alive\r\n\r\n"); + else + strcat(req, "\r\nConnection: close\r\n\r\n"); + + return req; +} + +int main(int argc, char *argv[]) { + Worker **workers; + pthread_t *threads; + int i; + char c; + int err; + struct ev_loop *loop; + Config config; + Worker *worker; + char *host; + uint16_t port; + uint16_t rest_concur, rest_req; + Stats stats; + ev_tstamp duration; + int sec, millisec, microsec; + uint64_t rps; + uint64_t kbps; + + + printf("weighttp - a lightweight and simple webserver benchmarking tool\n\n"); + + /* default settings */ + config.thread_count = 1; + config.concur_count = 1; + config.req_count = 0; + config.keep_alive = 0; + + while ((c = getopt(argc, argv, ":hvkn:t:c:")) != -1) { + switch (c) { + case 'h': + show_help(); + return 0; + case 'v': + printf("version: " VERSION "\n"); + printf("build-date: " __DATE__ " " __TIME__ "\n\n"); + return 0; + case 'k': + config.keep_alive = 1; + break; + case 'n': + config.req_count = atoi(optarg); + break; + case 't': + config.thread_count = atoi(optarg); + break; + case 'c': + config.concur_count = atoi(optarg); + break; + case '?': + W_ERROR("unkown option: -%c", optopt); + show_help(); + return 1; + } + } + + if ((argc - optind) < 1) { + W_ERROR("%s", "missing url argument\n"); + show_help(); + return 1; + } else if ((argc - optind) > 1) { + W_ERROR("%s", "too many arguments\n"); + show_help(); + return 1; + } + + /* check for sane arguments */ + if (!config.thread_count) { + W_ERROR("%s", "thread count has to be > 0\n"); + show_help(); + return 1; + } + if (!config.concur_count) { + W_ERROR("%s", "number of concurrent clients has to be > 0\n"); + show_help(); + return 1; + } + if (!config.req_count) { + W_ERROR("%s", "number of requests has to be > 0\n"); + show_help(); + return 1; + } + if (config.thread_count > config.req_count || config.thread_count > config.concur_count || config.concur_count > config.req_count) { + W_ERROR("%s", "insane arguments\n"); + show_help(); + return 1; + } + + + loop = ev_default_loop(0); + if (!loop) { + W_ERROR("%s", "could not initialize libev\n"); + return 2; + } + + if (NULL == (config.request = forge_request(argv[optind], config.keep_alive, &host, &port)) { + return 1; + } + + config.request_size = strlen(config.request); + //printf("Request (%d):\n==========\n%s==========\n", config.request_size, config.request); + //printf("host: '%s', port: %d\n", host, port); + + /* resolve hostname */ + if(!(config.saddr = resolve_host(host, port))) { + return 1; + } + + /* spawn threads */ + threads = W_MALLOC(pthread_t, config.thread_count); + workers = W_MALLOC(Worker*, config.thread_count); + + rest_concur = config.concur_count % config.thread_count; + rest_req = config.req_count % config.thread_count; + + printf("starting benchmark...\n"); + + memset(&stats, 0, sizeof(stats)); + stats.ts_start = ev_time(); + + for (i = 0; i < config.thread_count; i++) { + uint16_t reqs = config.req_count / config.thread_count; + uint16_t concur = config.concur_count / config.thread_count; + uint16_t diff; + + if (rest_concur) { + diff = (i == config.thread_count) ? rest_concur : (rest_concur / config.thread_count); + diff = diff ? diff : 1; + concur += diff; + rest_concur -= diff; + } + + if (rest_req) { + diff = (i == config.thread_count) ? rest_req : (rest_req / config.thread_count); + diff = diff ? diff : 1; + reqs += diff; + rest_req -= diff; + } + + workers[i] = worker = worker_new(i+1, &config, concur, reqs); + + if (!worker) { + W_ERROR("%s", "failed to allocate worker or client"); + return 1; + } + + err = pthread_create(&threads[i], NULL, worker_thread, (void*)worker); + + if (err != 0) { + W_ERROR("failed spawning thread (%d)", err); + return 2; + } + } + + for (i = 0; i < config.thread_count; i++) { + err = pthread_join(threads[i], NULL); + worker = workers[i]; + + if (err != 0) { + W_ERROR("failed joining thread (%d)", err); + return 3; + } + + stats.req_started += worker->stats.req_started; + stats.req_done += worker->stats.req_done; + stats.req_success += worker->stats.req_success; + stats.req_failed += worker->stats.req_failed; + stats.bytes_total += worker->stats.bytes_total; + stats.bytes_body += worker->stats.bytes_body; + + worker_free(worker); + } + + stats.ts_end = ev_time(); + duration = stats.ts_end - stats.ts_start; + sec = duration; + duration -= sec; + duration = duration * 1000; + millisec = duration; + duration -= millisec; + microsec = duration * 1000; + rps = stats.req_done / (stats.ts_end - stats.ts_start); + kbps = stats.bytes_total / (stats.ts_end - stats.ts_start) / 1024; + printf("\nfinished in %d sec, %d millisec and %d microsec, %"PRIu64" req/s, %"PRIu64" kbyte/s\n", sec, millisec, microsec, rps, kbps); + printf("requests: %"PRIu64" total, %"PRIu64" started, %"PRIu64" done, %"PRIu64" succeeded, %"PRIu64" failed, %"PRIu64" errored\n", + config.req_count, stats.req_started, stats.req_done, stats.req_success, stats.req_failed, stats.req_error + ); + printf("traffic: %"PRIu64" bytes total, %"PRIu64" bytes http, %"PRIu64" bytes data\n", + stats.bytes_total, stats.bytes_total - stats.bytes_body, stats.bytes_body + ); + + ev_default_destroy(); + + free(threads); + free(workers); + free(config.request); + freeaddrinfo(config.saddr); + + return 0; +} \ No newline at end of file diff --git a/src/weighttp.h b/src/weighttp.h new file mode 100644 index 0000000..ad47465 --- /dev/null +++ b/src/weighttp.h @@ -0,0 +1,60 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +#ifndef WEIGHTTP_H +#define WEIGHTTP_H 1 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CLIENT_BUFFER_SIZE 32 * 1024 + +#define W_MALLOC(t, n) ((t*) calloc((n), sizeof(t))) +#define W_ERROR(f, ...) fprintf(stderr, "error: " f "\n", __VA_ARGS__) +#define UNUSED(x) ( (void)(x) ) + +struct Config; +typedef struct Config Config; +struct Stats; +typedef struct Stats Stats; +struct Worker; +typedef struct Worker Worker; +struct Client; +typedef struct Client Client; + +#include "client.h" +#include "worker.h" + + +struct Config { + uint64_t req_count; + uint8_t thread_count; + uint16_t concur_count; + uint8_t keep_alive; + + char *request; + uint32_t request_size; + struct addrinfo *saddr; +}; + +#endif diff --git a/src/worker.c b/src/worker.c new file mode 100644 index 0000000..255deeb --- /dev/null +++ b/src/worker.c @@ -0,0 +1,58 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +#include "weighttp.h" + +Worker *worker_new(uint8_t id, Config *config, uint16_t num_clients, uint64_t num_requests) { + Worker *worker; + uint16_t i; + + worker = W_MALLOC(Worker, 1); + worker->id = id; + worker->loop = ev_loop_new(0); + ev_ref(worker->loop); + worker->config = config; + worker->num_clients = num_clients; + worker->stats.req_todo = num_requests; + worker->clients = W_MALLOC(Client*, num_clients); + + for (i = 0; i < num_clients; i++) { + if (NULL == (worker->clients[i] = client_new(worker))) + return NULL; + } + + return worker; +} + +void worker_free(Worker *worker) { + uint16_t i; + + for (i = 0; i < worker->num_clients; i++) + client_free(worker->clients[i]); + + free(worker->clients); + free(worker); +} + +void *worker_thread(void* arg) { + uint16_t i; + Worker *worker = (Worker*)arg; + + /* start all clients */ + for (i = 0; i < worker->num_clients; i++) { + client_state_machine(worker->clients[i]); + } + + ev_loop(worker->loop, 0); + + ev_loop_destroy(worker->loop); + + return NULL; +} \ No newline at end of file diff --git a/src/worker.h b/src/worker.h new file mode 100644 index 0000000..add16ba --- /dev/null +++ b/src/worker.h @@ -0,0 +1,40 @@ +/* + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file + */ + +struct Stats { + ev_tstamp ts_start; /* start of requests */ + ev_tstamp ts_end; /* end of requests */ + ev_tstamp req_ts_min; /* minimum time taken for a request */ + ev_tstamp req_ts_max; /* maximum time taken for a request */ + ev_tstamp req_ts_total; /* total time taken for all requests (this is not ts_end - ts_start!) */ + uint64_t req_todo; /* total number of requests to do */ + uint64_t req_started; /* total number of requests started */ + uint64_t req_done; /* total number of requests done */ + uint64_t req_success; /* total number of successful requests */ + uint64_t req_failed; /* total number of failed requests */ + uint64_t req_error; /* total number of error'd requests */ + uint64_t bytes_total; /* total number of bytes received (html+body) */ + uint64_t bytes_body; /* total number of bytes received (body) */ +}; + +struct Worker { + uint8_t id; + Config *config; + struct ev_loop *loop; + char *request; + Client **clients; + uint16_t num_clients; + Stats stats; +}; + + +Worker *worker_new(uint8_t id, Config *config, uint16_t num_clients, uint64_t num_requests); +void worker_free(Worker *worker); +void *worker_thread(void* arg); \ No newline at end of file diff --git a/waf b/waf new file mode 100755 index 0000000000000000000000000000000000000000..65ab0a8e387f84b3765ad21b1e37c7657490182c GIT binary patch literal 86338 zcmcG#by!qw_Xa9TDi@N9ATUh8(A_yOL-!0)(%r}mT}p$5goq%L5(A2~vm?>gtN!v(YVJh9?l>$%sn0|>i-57t}2#@R!_-oqE<6@YW{^tcQG z*?ZV}+BthTN`riG4t$b83&zRQ-5Lwhv33mL1qllZitzy-QkO4-!QjgV_IA!#oVT-$ z56;=s17z)C2lBz%gPc7;SWh2sTl@1CK!>$=0La19+a1db@^i*Hfjqs>kDflb%kF?W z2WMMrf&gBSwYNRU%ii1F8HcmC19^FS`a0VICpaf-9PnWe2yt`s^aJbz*?M}|ITI#f zFB2xY+vB7!Ul!sA{ijJ-kf+1nwg8R+<9x6}|)r!4>owr#i0Qen zIPAGafKp#zqyy0R2V|_L1I~{SMS^-DDL_~+ds{+Q0P~y)x#CU82ai9QfyDwr2Ta1K zsiQ$?T@{QG!T<#V&h-p*Z>b|uNRW~V2&0AqAq+8Ux&|OH0uA(nK?ofr@Mi)-8S5FK z&}fjZ!DV%AJuP)$0wBQvp@UIJp?N{-I?7sxNOc`mUXYR@2Bf2l0cojgt7Cv+7+v0T z!GBG={I6*sT@{cv%0O8Skb+QB*HXuroa<9j$LJ7rsQ`8$KzaxRjJmR+7Qz6eXK0|O ziw0~oKwUe?tIKcF4Z2twUL>0m%;HH4Pdzk8yD0!%?DX`%ke1AIZM8=#ai zyqDE={yHO=4`2XTp~VYA>!Fm@2`4CH6yPbsz=Rj@8lKH=|3Z$y5i#&%DjWW2Uu8cyf&F&!JJ*!JrHb4D~STx;k8!)pU&j=K&iLz*IuKkRV;1^RNLC z)ip372qj=}4lystNDT$F8xUXvyuuhD2w=q z(osectkES%F;YjPxPXYL1D2@*ke;hGLI65}JOK0(atg5O&*{JA9)K?pFOa$l2!Xr> z$N)?}AAA{zFk1buYyg_jhRSMx!Oefpo|m27y*#}EdI4w=8-Ts+3{X`7mfy+V-`C!o zkma(1{=$MHf`Wn$(jaeZXJARGpU*&fdwY7r!A8~&0F~YGarU;yg7nTA93(FX66O~H zb6qA##IM-zg zdw*MdFPyZOH5PmMG7u0n5FI(N5Wg6|6u|l@z|HdpJ0W{P5m6}zTS+Mq32_l2YjH7g z2OCLyYYBTPDM4`&FaRSO$VDwVPR`59LUNoC7;qE@j!@3awtjXXIf7M=_Bh}iQ0w9e zn0emhWsP&!2KNny=z~DaK9w7g7H~$kfc|m^yWCYMI zQ~W(yg!3}RzfJ#VK7a_JEC9OCrQ3UZ!`%t;0p9Vz!Qq^@1w};6q=ekh5tjzRu;&ee z?wlYP$ejxSilE!x-x&uN`b&h5hnKajt0iEtowGL__#=pOAb90v?*S(axAu1QH4`-F z<@C1U1SHr3ePCNpZ*LzjLd^pvg5WSaF7RavKPP85dyo(?pTf=A!yXvt!0&BuZAbV* z2oePlVgmINzDt7$wu8NWJO~o_+z7?&55rm$il!Yv_dp3Fls!W61cq4KxjTCRd2%l0 zk9au%T~3IcocwJMPJ-1G6gYp}|JC}pTA=ffR$BlJzvt$Sy|^C@Uv-F7Vt! z!dT(+u{MA!u9yF(FcDzDAJxF8nUFM}kU8MEmz%Y%J=_MaEX2i2u#_N_>)+dj|7!OJ z+Ajl=|Ew;o6Ri}c01l!I3XX=6FA3sdb(i=n*Uln|B`ba8D(n^LahFz$9a_9oNa(* z3DipnkRKu5?Yz%{@eTPNWBFT-)}UO<>Q zar`)&Kw%)$2|+tgH=u);)9*aZaQuWSY7YkxC7{c1>*k3)&--%+f#4A){e=<#-;)V} z0`_en|MLxnGzbUeI?mhL76+_C!jylc{7o1@<3F|mYx;Z;z%>68?*D_+AG|5f;W7fC zu>Av>4Y0E~UsU#XydYaAds|mv*8uDXZ33OWgh5yzuX7Rw_G(@L4+1+K0{Q*10@z#r ziPpab>hC!5f<&c&JUbuh;{hxHS2%#ydEWdt4gUwDoUeESJppi;{jXHuG6(UT^EhD; zfXCk~8zAE9;OuXY1)9A6KIaEo{t4s1h4mb|b4J41V{zwE2G%2ivk94q1vYd4GYh%6 zWC(j(0y6@`&NVw$X`(n?p2A}{51KSgT&*aX%0jB&_hX~9M=ls)6SVHHk z2jCDtpxpg&!w(1$1Xvb-2<`GYTL2mW0d`ozW)V(^?4Qm*l;uarVghCadkN|HU*ahK zq}M;Q{#8JMrt`H7;*$s2`=963AIszf{t)PSUIBgs8o&YoR01$8-}$cqVP(RB!Mvcq zN+mDo?-~i1Kv+P|gau^wS25(}BwTxO{y7M^dD>dL5x#hO;W*6+wEK?_&OCs+|KY^n zm=IRq@1fqwIw z`pg-ht8x2+Uz^uX+qAA?Q29X6$4jGa%@w+BpIH;px*i+b>r}P4OZbcF#IplWBM@pt ziV#>SNFzQH4%NFfG^|crnit3j2v};Z)M_qw708wj=raqH`ZQgSq;DpDgrEJsKbMmo zvS7c{I%hGrsVn*_N4s_D({{@d_sXj8PS97G?X8dn-_?2Uo{;^@mYs%4xi(L~kkydZ z4`Su@W$~Ni+-XC07h`;#E9HtgG%nz$`|_FX3l;T!=2+LCA!+kj;C6|uESDVClZ&_T z{dIM_9cgpBZTofGCs#|RFR)saj9UdYG|w<<2eOEFPtmNmoI+p+FE;gGcHgJlUZQlJ z+g_1JSNf0KeX%56I2q*ev~fyw*w<5{xlM5HwAp-ie0x?dNG7}4-#tRkeAFppm1Aos zz^@Lw;}NkY_T0gDB56Ikp~7$Ihs?X4tSMj5y!BJjQ!UTzzNHIur*k{#N!G!KEDg^? zwq}mzCg1WM$r=?yx?kN);8C+u z-t>j%(M}L3MokaWc4Se;gmG{133`@oZaAmew82iHZjoaVB{#9QR=n8f$AD=OrNXz? z?BGsL+b)oKwtf40;bRD|B`&CWco6N^+;-$~6ta(%ZK)45D+vtpn_8F{#9kUdWJ8v3 z?IYYwn)JYj)|1axpO`eXOw9YVKw#HRZnd5A&&^C=XItfrmp0ZnokHG)SZnti_Rp-W zt?@m-y|u06F(crY-4rx;YP<5oxQ%)~WFCkfkMFluJZVQ6k6A;*9mBaJzQeWr)z<+R zTr_fyvQg%Xa(F&-=kASmtYTN2sJ_0Pojq!pII8sdzPW1dI304- zvEx}THW@PLb8wK(w503foAU&(s%cvf_a2emYL*DWUKrAW&uyD9bEx$36CScR*f$~GfQLpfxB0O=9(Ky zv75(ma=(V_#_Dx(6GZbt&l`Lvn`~oxkLuRvZJ)b)wI(k4R?)Q{)((v#FWkLLlSl5H zN8B~4UaSS7rda2oD9ZvtpqCVxYyuN>_17u1FH+yV%aKN%B}_aL=mLSFN43x#2U?2m z+C+Io>!f!99-$zPy+^F2O(Y0`v8HL0=-Q2P#Rupr9$Xk3Js_6TF1^88tU?h>6zLpJ zn@X*%b(iC@XxgZ1L1OwFmjGQ7(NRRoIs{6}5gna%PDL zr`lp7XlP(e`lq`WL;-zbG{nS2qC}z>qI8{xY)Zapi)d?;I*aGm3ETA+Dgq-e5Uu_` zI_xrHD*o+s;TZ%5fiWt8c{-`}4VU9LQ;_<68hX&#Zap?~eA~Q-#fE9{3!^tLk5jAM z6Ds6yy}=*8opIRHfj~1H@Xb$L1A`S-6^1R1-iO;LeOFSyd)4Q{{(jf#vx6k9_d{zT z!&py0r(kY|t40jrD^*-`7PH0M^W+U>MsYz!mG$o`*pG(4BUPOgA<#Ot3e-$|2a!2> z-dHKwYuTF|dKb1pS3Sr-8~&{3r?Jp@rT2@Xn6wTW}SWfDsc zfyIG}FEYi!3&_dua*%^z&&V}wjLA8;v+k9V$H9xr%D^tLERLu=JZU6{wNt!5 zJlIAF0=rwlZmMn*&kYZckF&XmFGw%Tbc%++pv8DtdK`?MJl-_@B8eIlucR2K28KV* zi&H911r^1rGp1&8$AO}v?c=PAGr{UMnc){5?v`ez;4=$g;JnzfEG7snuK)rIkB*Is zw*uRcI#}WJ;_whytW&BJJU=d;JCmZ6%fu<317K$>Ft-NW0S3!V&n(U?=H`xzjW4+9 zV&Ie)4=M%67LiA$#>2z&%8IzSilPg+^K3xjd8u|;j2apmDp?R191kw#0LO(pq!z^D z^NIk@Rf9j{&Pc(-9SY)$qwz4jDR(>^lo1CHFDT$(#A_54r&_}yu(BIA1y)%aOirco z8S!915CuH;F)$JzegO~X!gD)6EZ~kSj?Dr?V1QZi8cOPUS0&rM-XJ_R9F(6|%AU_{_1LA%2?BGD&vK5< z3`gXb!9kC~c^cHu;4TG9S=TZi#5p+uI53go!|{=2nILc}6knEJT99QIUJQZZ^UApL zxG2cuA8 zA+SD7?KlzjJwts4Vl7I_H_FQN759{Bi_%l5snvz3JCOIFk=is+#ZKa`heW)T{b))k zi8i!L429IDL80{!#7Jf8Az@(#F$6S)8jVyZq3vcDHs~W}z=#?eqUdS0P=+)JS{fR9 zeMP;oF4`^#lt|N15W&Z;OiV{Zf~lcQfp!aG`qhvK8XB!G(HaUm;$Z_CE@Uk+J&H(p zTvJpu0j}%0kf69w6bL2EsFGef9SKTnYz!u-r&R?&ppVo_Ez;0qpwZLoCxRg{^v~!~2n0f} z%0Np)4XI5>A4LcF!p?xvOQA#vDWhmH=}@3u1p1H$Fi}idRBr@LLoGV0NgPFUv5$mZ z6Eg}#iJo3r8%Fs)1&PumMhl4ns>J9-A8Mj$5OmaNZ3vVBO(*(BUsUAc_!W(D60jZu zrcO*loF>}!L0?EPg~R|OB#h+J&{n6zXp->0(^u?*BI&g{i8R^i=#)l8Md>3E#QF>* z^n9WTv{AI$40@UA4gcG=^!r?y2*lXoS<_G*Gm)rG^k#SDrSS z%aDgYk+>HjXh@4PB%!&2f~Epnj;;hlMI?e=RFGB^#!iP3Q%80h3SrP%-J%^NL>Lmi zAsQ0Ci@fo}Fij*Hp)N!`@B(x%^|=0aV3 zDaxQ`cm)BY!x)mFh}CH*keUoYaA=4P4A6?y2x_qadbF~kzCIm_#6S!A+w#!dl~zSC zEKN3x!*ZLZGv=h~*EHUNZS%M5#?lzWuN!yRi4pSpi=t$F4M$#z^0e*yY|nB}W!bjT z!|g|YVS5V@sKhE4=LrPrPd$1uGqXQfhF4ODR_ewyEIx!6II@3Q_N0 zitDHgr-jpRzISxheBpKliPu|xW15MlDF|nGkZW%o?7(r+`_}5b-3_ylq?-_-rPr&? zQRR8qtdg`_tY^c`^g~a>-JCXMi-`^b_14|+Dh;d2A~rj#i`kcmC#$~iPV7kYb)iS7 zR4}N$>icikye*;CM4|e}+~zfT$6h^gv=uLEePT>$qNiO%v@F`m*`kkQc5S3{;iGZj zX)>qLcK|mvfwjc_P1tz&9bKN#O+C{wRN1xk`fXoR*Z_e=(=Cd_Bce*4m$f|}7VBTT zdB289Zfdx!(^STASp+Zoxyj#_e8s|6%t!@Rlkp_ zh6{TaBKA6CA+TV?82XLIde?1pym3OdIweSBk)5pP;FW)lD)lXT2bPApXJ)*6)$P|L zwjJAJ8^&V#e>ZUNOc-`SU_YO#@=cR%&C~5JT4lx+fBonl*?co>$kDv?vooR~L_+VD z9E;uo_;s;$+FgA_-jBv4gzL4vRZyYVK<({tj!|!=lMg%`EO~J@_doTT%sxK|EJ^$P zc-6%A>{?Qkw|`aV+x7QLhT7b`qGh*63Kr{`>kFx$X?(3H>bDjhz{X#MK&$*eHJcQ( z$CgS9Vx!?(ey@xY9Pl!4*8^YeGm5ho-Y$)QGp;gor)k-MN265bELY|Sn`2OY55w{; ztm?zYPVdwW=MAUw(Lt{QF6oa~i!G~lb^Sa<^){Iz4<{_6{3ht{B#vFyfv{S-{W!fgEoe>nSS_F(FfHH z<7TT71aN6~kjCk)cefgcr&bYxd(WHo8IqiBXt#4;N*v<ec@__f5zpSp^~Hx(yxAstN<#cpd_{0>irMpdoPlh--t^P# zx~&4ChBEOk7l+dMDP-M9c&f{KA7x(rM7Qis6O8 z<;KXzI5rIhW-hsh7rLT0TpcRDat?&u+-5p1p<(u6q4tXVS|9T;xpmp^p{t!j&xv2l zwDbI;n!D&1RY&Pk7!@?qWsW!$0z-$fmc99TDPzPK(&L%dXR2CPKT2&HMqJ)t#B5k_ z#P=a5R}As?AmYJ;65+VKy2T3N)VoU_Ul#3@WA9z!QAbWXcn|%yu>B$WY_?}=GOT__ zR;G^5QPi!p56|k~T3-`U{ktZY>c-dCQ-YuMt(!HJ?Qrj-PK&1=qS-eqKD#yzL#BhI zkB9shZ&4(v^h(%P3pj7XY?+T=u_nn&*1RxG&Cmomyt?Z!m+Eq5cm#ORMN#yv_f-Xr`9* z5CYR)XKBv7AKAH+C)H4mPG1dhK}N3n5J|?TozhU^ecn4UH^-DT@JOApqVHb; z54`o*73k^>=lasQxomfHR<}VY#-2lyZ{Z>S4bvH8JeMp^ViM-CI8}u{;0(JOUn`>chJm?oH?qTs%rP2JYUwyuR^PqqO z#g{DWg|0G}e)FMvjmn$)kqZkt#q2g4=G9;LNn425zYTJlNjkKqkupCBuJ-8OZ!yZ& zZk$6*(q!Il@k!m{khP>>Q~#tMnd#*-FbC_}Fmiv&diE*?DaHU}S(uxW2#J%s!7>hk zbtH-l70d7QTCCg;s6lJPR6hAH-8khq)RG*$Z8_~I5IO~ot65HgK;yaZF2=f~hPu&* z`MuwhBwn88Q)+8_m5Ju}D@ZUnuKk$Wlu(3lyq8@wJkb?$Hjq%GQTs z{@XUf#~jw2@|J2WqW)ud^b`{6`o5g#E@-po$Q1N!+Uxev|I)n*uReq;$#A+Yb9i};rP_U5yMfpv!`Yxpg$J71ULk$e7HzgwDk z3))Ao=`1VX;d~NMcuQ)j4+2eobqhNqoB{p*;mu>JLov&SxKzHRw>r~>g=s9_KIO9e z^5z!%0!AHuTN1i|s`>J_E#l($9f5)|RbaxFCVY2_| zktUu@A)%Z0w&dg7En*5K_wQ$^Ok%6{Y8CJwk#0WsEoIF+axKm@yhJ2!znQ>MN0e)U zms9TY8*1{E3%$^O0fCvB*o>CHP5W*uMO3t}(P$YtdT68d!Z7y}djwi$4ac$InBCPl zJGYvXc!^O^ZZMi-*gt&x-FR;~i#B7pn$BY=?`gBW8GG%0#p+-A-2$c9rM(C`O-V;C z2y}ht*t%awwp9ZL6=I;bGnR$(2vpWCOO1+h9n>^(WWsM3NpYh|!dkxZUxwkjjpx4UTXVT8Bs8;^+zgQu?mA*4qvrdX3J9pn@ zcyPUn8A5084Q~W9dmnSm!i!8|T0Xt9&$A58tm7$9W_foNRqFLa{#~Rg^}Wd_K>^vu zsV7~I3O)g@xvUR+hh+i|t`yTv?`=lir>B>dmq$ek=B#zB?8l-w`A=Wr975n6WFc83 zsslG{4eUw92i%waANjGlyS^YR7atvC2YZW)%lnx<&;IeH5duAu8MGBCd%Mp(O&?d% zbB*b_&B`o~lizHLbvM@=Y4+}_1hO0hut)Rk+0j&jwGppt(3Pe4A4>L?wXQ|yvkt$v zTPe8x>1L6SwvYx3%dqJk<{3nZs>O0Ku5`rJG$m2!nZQbw{CDnuaW9#0t7mA)^zZ>s4LD4FP@#Z*1dT^6x-F*Akt4Bw^Z2IH;TD_i5(_> zJ=yeC>%3G?)L!l5r~4wjtu%ta!{>Ck-acg+1-oHhPj?p?49fA=1{7zVVtHol+{!kv zFMji_E>%OIxs{+>5sl_x+8m(Vx`yu>$iRF0u%Zm?%whM-14-FeO zKV9#51J57ZDx!lnffpt5Hr71f$00uBHHqHVp1OS&9wj+ZA36_~zvXx&WBf;VQ%P&e zERV|Hklo5Y8I@*hh~>{YNPDhc#e^kyUQ$7ER(Db)zAC-@xInL>Wu`2ZVoSU?L4^TB zR(53f&0M%AjFqYhn+WX|qD88uFbSX&luO^&7)?szZ6V^6BsY;glr+xMG875ceVmo5 z&p#a=Z6{GT8zMMh{`**o2`6z1>YnR@9*-Kw*dxaUg%8_~B(xxV>_=hG-**lVE9Zsc zi~Wx$Z`XZ=)f(QQ=rlQr@f_RjeKG`w_&ZLyoMyaMv0~)hwO5nrTJ`>2__b(~^~TFj zs)fE8$H>aa&$tVsu;sw(8`7=6gN&0!10IXxG`L06KXi7L9!ZY|E=_v8+Tz=*x(&H@ zv$Zm#Lsq14BZ`so3Tw?B#=>{1jls(niqSs3-5LvQdVj;BoyReUUkPM%-kuLoz*vCtDvAt(COu!hmV?E*kN@0lgz?B)45aO z-}7`!~+Kzr65JMC>7lxzrb+GWXwl;lhZny zeMd!5314gtk_`x=gInA5SE&OBlcIk zE_p7Hi*j$FiXTfl(yQ+mM!@LQ?muz}d{P_Z?Z3b1nYjLZ%Fo)+*RZUI9&AezMpr26 z_>J@1mXgdCX2Wn@$L-D6&pB`Ud|k~7e$GxvbwSz0z&D&nIungJ)~{<0*m3!UC_+U? zn;h_~WH6_?D3`}Yogy#FA&>#gr6sGMEd~9CqlNkNBJwY~xS-EgpBfZ22Zi!Cg=g41 zI~Ql+$s-pr2`{da*+O6`#uvH0s=td^kiZLwJq?%0Rj`+mK(mu6dQ-&^qjoiIMLjK$!Mvywl+qx!{bu|MVYCYco8* zEjG+a`0IaXs_$OCrEcup!~K5LLYO%y7-^JI;8VtyUFWr$$`tlBtYVkPTwR1!=W_*Z z*31OYg}&H=ec`xtC~HqO_I5!UX4ZIi&9UjIDlq<+rN@k)#&OBO8(w```N&sI$}dvK zS0bqrIBo{KM?1Rb-v^ zV=LcLl~&kpW`q5IB&(&hB}61K2>65Lw2 zE`JqY5W02gDiH)aCl?Y|INPhU*mPw7y_L+y<|62aE#rZl@S*H#Oy%fj!=PePy`IRk z+&8*1`h9Ef+E*^ji4kFt1+StYFi!_MueUnEvB;R)N*rc)esi`@39d)&`D0jHPd7_0 zCeyy7Vk(z$IhvN08nS(Dht5u!pBnw;S>rL26?sD-@G5wXAso1I9oxkSP5{S)d9QJY z1`ZCt{_sE+Qgib;3F>N9%+k}X-=3ioJ>+U`45&eflhn^MY*gE1y8mSAz59XUe}L z9A*&QV6qUsP-253$D*CAQ!UB9pr+%2hG8SOj%qM%DtSWM6+`$-7Pe>wB}NbG{+=Uw zSsh3M+s#%dpa$yQ{lX%a2Gi+Ee%WCDSn}+o+AH>G{B`IHNS>I-DCAg>IYES+vQ#U*v5srr)R+3r4LZv>0*%?BTEGx zM5*gFk0)&9XM?g9Z@t|C0+E)nTY32q6O!RzL)P#yu&ahrwMdvfa9K~(R!Y>7ZSWD2 z+~|H#I`VsyH~TxScMn-~L=(UNdT66sSbXpM)T2AQC-qzG?W=2z^>07kn^A^#-t1>f zupr9~T+PPW^Szu>h|(St`JMVsP)pou=I8I2gapekKa#s@CV0;U=L~{;^MBw^f!uCp3>CRYk`OGrCEeq*)8^MW9`uI#C!=iYmD-5c zy)&V2e(M`5KVp3U#6!2oQVzH~&}r;bsph22yunfEoadEQsQG>}URMnQYi$!7$aq-B z$~>#!BET1k%&&CZTgBd|ap#wX3k_{k)7_H#+Lx5OGEblR)(D2_r01h6r4K0)!z`PW zPU_v1ezlBKY7a{)8Z{&$qmE;l<;$RVY|Qy!5z)fu8j!O7v(Y!`u$(uUN!<)_b+CWA zO)$T{Wl?sAA*P)Dep2U|v9N8)pvZm!X1SR>D8v4-`*ZQeL65TgGi;aSB$}kl7?*V3 zJbakB-@kb$Ie6o$6Tc?c&7X3hvjh=|`9cV^Q!;0uLtiG0;g!!UQ&pn48c>onOz%}i zktjW{Ej^PtDM%sLxN=a3AlIJ6yW!vNN@%rSlwO&-TaUf?5T{Z(c(10kfi#a-DaxKG zMQi+0ZA24`263KD&@1my(-&x5d(ZQmr>gZ|6hERMo1Z`a&IsTRAz?ol4R}8f>&c9v zr-18+)ZnCa$1A#fGi|29jCUTF7s$@9jyyL`HwgRoZmvA^_IJ?O9t3Juoa8INi&%r`2v@`gKGtrFUjo>eVUJ)8}|3*Kgpdw(KkZ+}E`| zV#(^IRi7gjAH&uPi&R|4`VRdhKku0*-Aer4`8=gK;UzZuXV=pciiPX8%ucBZH1^Og zor%VKRk2?^q-5?upkn4hlXrj8L|Qt^^wWE|KFMUDqG;ZiTGXIv-HS7pISMjuUfMQF zT-W=#>#M(LU`WOjOS|p07w5SCb|1K-D?1aJ41uvFHT%pOCF@*I-;7{fa^BOvxU3PZ zF0}7ty^emoqdoMb)<36rOK*n1R(-y~MaXGtkX3hJo@8uy5BW(+c2I&H=DdHMWgss1 zB)EoXK8>cQA#uHVP*_wuZ_`*(_0hf2hpt>lLpv`*LmCY&dwY~JYM!Bu^5o8*n=aLdsMBC;;iFtIfeY8*Lxmo2CC--hwN4Js= z1*ymp$TQlR567$;T4cOZ`A~_Q{HEMhIh^S-74*@y&cKtDgxw>eJ1vJ0m~tvp%5`d0 z+M?@fV#ZCu*N(qsIm%8jK}#Ju%QORSe}@SRPI*0GCf=#lXUm&Kk-Yv90eaD@{}D#y zZ*ElZgUXM*{{zbORDnWOEUnJ8r3Q7?z4>51Elj_yn^VV?u_QT0)MP5#J>HP~eV8}t zCASY4q%ZZ@+Iy2^ig1igm_mr+d+YdiUqci`J#$l!d!U1wTqk z6ibbXO`1cX>R_b}yO#VoMmsBOu8eNjChUT7X9R840|+c_STWJ1`$yfb)0uqMf(TeC zM?&WL=x0m&*=N2^>`qCvyKYE$tgz{mua^Xio@VIm_tHJMnVuiGR=rFnN^6pJ_hqqq zIyug&#KCAxnw%sIy>|OwFE5$k!A$<#o6s;e z$He^h%3yht7bc!cp-pUtTW{_&t#{zuoG4B2o4#!4sDJr(peFvEZhh(X%?Z!jyo@$Z z2~+opdJhcmtOSrIdanK~A;n(XI4vpt@SZ7ofx~OfRJBydsPWp>EHwERmur%AWy*Dm zCoaly8dfeNq&InZ?ZZOVwMKE48|y#U8qKnwx`~MV#4V{0ioM4@NMZIBdEsdMrun{Z ztISC7D)VhCCi{(JznCj#LCnf-cl_<+l??*raIt3tnx%Z$RimeMfo!jlUOXJiEoOyU za_O|ss6SD;0Q)-n99WC;dK*>2kxAy2!zsx4qf%BAQ});E*KX^DNH~OPVYOK5RFKRx zE&HGiIn4Fx@%sJA@TX6BS&X6i`3DEH#IuO|ZYi`-VLV#INZs!4G^y)*2=bA{gb01n0*=z!uOAe({ML$XyObbM z6eCnkslXPMIC6Y6{({3iYC9s2T{4m+?(;R#0Ovaxr&m!VDfemW*Xo~N;yH4B`}O0u zjb^X=3=NSA*rX$|DO?(Zpct51T3kzNzKi#_>XEUtP-MsEw$erRLqY$JrWAwbT^FdT zb3_c5r$gto>I&qfEreDlVRBfjnlz$YY0pZ$>6Js>=JE)o>8F-!A7_8iBMao3ZEx;V zMBS?wA30O*xA>NQ5<`LHpbMfOMK7)}k*q2iUdkpmW@FiqEAGvq68Pyar4y)f+&=8E<{SX}9eQ>E9odz)%t zPxI1PTTlg_o-OLhH&Wv}Hn(eTO$YRw;;bdpO87*DyQ;&+f*QZX)LP*d{d`hbzRuB) z0dKcCW_9R}fX~<_qIqD``2<=@-qLmEzAN8BiBFvh97NURANM zE~kuht}w1gelrx=JU`r2_g<3T)=5P)-AW~noW5XUY>Dx^bT|7z9dpJAOKYN>pb-US zdLH~8N3b6=r33EhLzDKmaVqDAA3dm_r8Kk|o~*38b$fq@^^qUKjNVjI(q`?yLrH+CESI51mr596$8Isda=*7IK{eX9HZb}m?C3pLX^db4| zAyf2rqNyoti(k^yZ+kG?v81O~-4{_Ov*PU>I>-#VnG}Eb^;r9rYs7HyRgk2djVy4N z_@VN?r+iiL*cTdM(iVvFEfY5*gooGl1PDx@0s>W_U~1*rdvLWn;a6yI!-OFFd(qkW zW30b4>jUaL&ANPG$o@sH9awndj-;JLA67C1vr=Qgiz~Arr8+P|a z{D#K_1SZECKPOpQ+`0aXMNV*Uw#CJdzp`?^@-X1nG#7V3)9bwwjM7^Oboz~d6Zokm zXl0bDQq|SxVCPs9Z!Xb^CegO_zB_Nd*=%}T6jT{}@fbuW2)1TK4PG_n4Hh&%OBH~m z2uiB>n3`Kyk-@pX2`i)$x5FcDZ#`9&T^MURm2s5NCp(Z64}U;5fl}2K5NvK#?SD3* z>xOOkf>owge7*SocAfzQw#qGGRdlCb!X4#P+O=$ZYp`$X3{@jV(W-dzj=AZ03j&oF zK9f^^o$K{N)xX1dv7O7R>p|1Fp$8SBDp7z_1k~Eu|FVzH8##8;kRAki@OAY?yKo_? zx8&%(>k#O*YGTITYf}(?Z+}Fm8FXXdbIM#4_p@RKL-*(_S8|^mp5f(kmk(`db<*{J zmoc=yILq;?f+n>)pS=7f_nR`&i~<6)PKqwyV&4jUs{8)<#|O5nqwA9^My&TwnAo)J zc#mVThK6u*aQ5=H2ZbKim3FQ4K|#s%4RAb%3#hW7mw`cyo<=Pw`daBFTbS;AE^Q!U zggSN)c<)Gt6nJNHsy*#EIK@vw@wL&m_QxW{r~%+LP5H1_#;13Z+S$Z9-8`8el8J*K z7i1R10gvaKReLzm$I_#Q-t!*a)L5#$fm3m{{RF7fulB_LLwG>1=%bD2bG(Ug>c>nN%?K1D8mS)`5 z<_5>#65DGGEt(_v0XubD8VF2H&^h%@q8Od<7-a&)YAP}P*Zy0g)dT$$as^Ax^5Qzj zGvyH`<=;U_g|_5Pzn{!$ufN?p97W{4&QEaRQonjk8cZd7VHcH?u-##h_8AoVsnji8 zy4wEI@K_Kjqp|=;T{g&+wW#pmJxH58bE`+Wh9_i+s?idmEtp)D*P`;|OG#~SO0Dv> zy)1P7z|Y}VFo(ywvi)K3tRAE1Bi}saTXbCZCp3ucRM^0r??;KCJ`tSvK5@fJUwrJ? z&+L#R4|?|9^7L*%9t0NAnw}~eNKNb+^z*^O^6;Lw_PoambDGkx)eXpJ#~RBiZoy=H zK#F@V$%%)8oY(5=?PQ7&bJlxb=;MRV+@?q?+DX5sGg<7+KCwBA3k~Z~d0v2iv{o{l zyHkut^X}v7_vZQD-g(FTZsgl_<`v*^;0c#=7x@GF&t8zHP5w>TqdB%4%f6JVTk-6b z*!yFVlG3@iE_n?eD%f>oJ$V@|vpvKB@nImoMwT@9jcrvV^E5QK=G_KmBUEB}{@Dms zl7eNOBTE!8GSQPgeKmHf!H#AD5)`KbZbubCuJ#ih@yV=hrZ| zg5%t>MD(?fmHWXej78GMbQy6yCc1T2NXd0D|CQ$^CTR#(qoZ0io$WW&Dc;F_VdG?< zP?fE|62)0EDddbKSEEth%8(yk)a#=S|j~!M=ffXYS z3N#=v16pbywrbb*nodduFDuF~W>dpe;bhV>*zC7=s#w$`Z^HyvdLGq{UDabDfwqUW z+&p{=yuW=d7F^aW{7RPpy`~e?|l>2`I>hb@vaifBE|DOaBm$Wu8xo_O!Ko%Un=BYvRwE zU%TtqBOZB3OTSs@J!nDNcupC7q;L#cSbLGd2CRJW;}dVm;PxPyRU2GlNO0(f&4aarm26m#Kr-d@*gY?`eC70-LoWrzF=yd%~4A3X)Tgtc@p9KyeU^6 z754-G2*i+|%ikiz6A&lG`_3zxh{YuBY#Ic--vJQ`z#%M7~nCaQgN-gfb~T zw=$s$N1D*Sc<4I+?&fo9kwBNdSSs@$OM}ZSwhC$0mYr7qS!VlDHbX9$lr^2J&Z?bZ1o<^Kuq9pUpFL!TvZLyV_ zhFBPGKReTXeww?n{LA~&E*-q&!p)~4ZhNe{8&eWGOg77`3~C{%_n0EG_sl7#F6`a4 zH2u64DJ2qG6egRc_jYsfY(9cj%s3<^_31FB5D7Jv>ct2d2(4J=zbH8&Z{r1ZP?vk;}}l-bxw` z{vr2N1bDi!(}cKqNVO*b><+|!Ww%ItSFPEeI`~q4T>9;zLV3&+YI0V@&t$d-E387F zAP*ZO0MRaGbGRZ(s9_o+J;{w`NDWv7VOlqsY=JAjjMX2#T z_*YM@pkD(&dKwhJ$eF&l^8?p2iYSrai)6oWdTseq^s5r0#zhJ!^kRq~CG$ckqmTLh z72U6U$Fi+AID_q)0!cFkmp@o@Zn)$m-GD%GMkU*wk-8ag0REc_GiuIjI}Lu_SFUQO zlDN#*iLRM?##d|;I$$+L_Bz$I1-PG5R$g8m_*+FOj91KKK_1b*eqxq(n|!4wy6@2f z#m=vrP`T`ndX@&k$RPz8&_8{&Izn4m-nZJyxJHZ8viNCRo(sh@?#m zEs=7F2R&whe`BjT91)3M&YL!qbg2kax=LO&_&|dV0_B+$)xE(KyO+cqGspXA>0z-- zaQ#neBAZL^h-I#;w)lGO(#L79J`NIWjS&#MNu5JZ4yDSGec|5WLv{#Pc;?eMSn6}^-SLBn&baL6uSd~sm3c0 zFI-KVd1>gW`!!PvoZxAM+Y7iYljb7+i0D-9yUC@dnXIKsqfdUp&>5=k&ZLHy0k1W&C?h*VpFSn~ z(p<8awe4jKfzpmUWmdq45Rq;-^U2>tfv(-tn*xeg2J?qb+FGcChBdXI?E~w?NWGVJ zloi0O>6}f&r<0TZ9korh8nFq?wi^Ay1$iAAMWdckwgUSv8%WhlDBmU;%ue$`*hh zZT8dl&N}DUAHl!AFPDJ2_W~6Z+IJJBr0fbEsdi!p*j8JwnVTf5K5q#=*?)YMnew-S z{r>~bKrz49Jsskc{FYic_B*70+yab1lBbcC96@0;?@r$~qQI%@?mYh|&Gs!e>d%g( z(g@&1?EpRQ39Qj;_wjg*j?aYf{Lkds$;*c5XGm#-1x75vN962>@BN)#FCU}y_kKS_ zkAOUfzfO$CpGOaq-J{3n)}kA!*W-h}BkJSmw^gOikRv4{B;7h&`OYIGdV5#I{y4p9 z3nvmFw%^p@Ssz$Ue?(!`##TI)j1d|mB~r#vbtUFps~A>q2Mo*=LN`_ev~nXP2M)#( zGuIPTu4t4xcU*dct-Elf0Y+pxMdNezt#7HbmN-~T{YRenEbkOY4#Dkkq zPUJLjr(0&#=m1oZII{*EV+3A?-g|_F39fIR>aHLOW|mE85YB zz#z)~2b;t6zhZI8E@s>I`ztPZ{9>uFA4lJdd+!UETz@rGOZVh2_WV8-p#E2-ZL{M? zY9M=X*(uaisM(sn{SNV8bBZG*ExD7rY6q~58oz(mGGD1iRoOAFYRn&hSRQ{pZM3XI z|8|}oS0g2^zG3Kda>rHA1GF|oX>yO&9uzjd(WGKGfc@J;db~AXq0Z;zwx61UnD&U% zY&gA7TBlEiyz=u$8>;r}p9G*UO!kLN5MCd9YaUGeau*0z<{Y(P z-$Lgeh}W64&t8%DOfG)bmP-B8NZnTYw=YE_B`EvV)0`Izt{fA;QVw?1s!1f0Ox1fg z%6Q%7?N^Qh;jdwKVt=Ky;feK0{#gl!ks-Ws5#5hnGIOP~remBs{?9W_cijb+AHzOt7s`w)$ zxyA6+y@vXF;x^&TV@?>iqFONvKopfCnF?dZZuC{ zr}@9l{`dF4o3HVlJAaST&*$w4NdvV4go>jXAfhn{AeUp~;iu*3{j;N{qKJ@~j<$PD zEO4^6QKuU%dZq|@367Nhs7oq5S#s*6yPi#|Aux{{yGEia(H}hK9&YjHs#u zD^GN&xEHRJc1~0!2*g3n+LUS={F>iWLf~z%hf`5-(gorz8KB(D>6-x~BmzK?laY%yS(_*`jG96v*2t0ZjDv8$uJ{lis za3KuWQRBy}8dk>u>mckAcG%2DKkl`pXBt@BdYa*4FKCKh%_?YdvEx2#Kbs46-@Z~z z=`k_uR<@fK#tdVW^kf*Qeat028oV|U$ zK0cw@*hf|!N8RrZO{!F(BKBlrP!b{1jVY;=^ZYa|54o*tOP9m5@AUk~$DA}5v);gl zSD#SxdX2*$XTue_>%p(8TuIr}#13$I&X9Twk5x?~GBHdBOVBVHPqhpSY(AD#nhdeh zZ;o(KaM{lCxLhoT<|xuy(q!_wxKWLwP2SAMYozRL&||jlqYO;tkl13i#+=oZIH^*# zqC_r<7Xar7qD&UIWd=NQWK|5wfeapQ<`&d7v=BqKr{As2T$xZBH?b*5F#6%H?d#frh?MO=&ZMPf#GbJR9W$ zn&g(ng|;IkH*0XSqdo5iv9YMZlT4p7$cq=tsGc1oBrL(AWO1;xqil=Gh@$~JgVe*X zjdElq*8?@CK(waX6llha05N01QcAnU$A;cYIT8OMz7%mawm^IcYF$`(2*$J{ha3BTk-k9+(`(%IRmM5ht?KK;jRqbq~JdQDxym6kRlX$Pg5lBbu!wCW-zH+>b4!gCDx*P15p-K~-M4P6*S-Pqv1>_}5dmAJY$wCI zLQXrR<>9sO+}jyTI)#C{jOQd2)5@oOTFh-*M%xpr%ydNa%ora5EzFUoDBeqAYPEYi z!66)>pO%cx)$3V#x9MHEm96iFMoAmt{eEaWBP1_F^oS>S7U!$UH$9*7&eK?wM)$#~ z&&IR;b&HnWySmX0GO&LbtJl@)hhh|wi-DMndIstJJP zw^p)el5P@@y70Pwe5;^#wOxgEysJqGV5n=bD6F~#`qFOcBKo#uC<%8XTe1< zT0R%gi@b?!{KvVD^}i3)+>beWUU6H_(JB!B5=_2}b}esi(Vnu?_NQEt$2Z+l631%d zvuwLokaIm+%gwUR4IY<<4&KJ3pPBLe9Ur&t@fpK6%T67;-@8Q~L`+B70wW|B z^>_V5_S1v!ll(tlnd)!)0m-B~p~-Q^{5X1}r<3+D?dS+b43V(Q=LIk`6#oxDGhcpj z%2-Vphna(y&YP6q1fw&hCb|Sq^KgpX!HmZpq+im12r{Vd`)*T8!(lyPov);w3%2_ZZgmY$bCPD^*$KaN3*%q z-g8$8qoIXYS|X~VH0Go7M!OR`Ke|jyp6cyfb>d1=>UU=rg}!eX+Zeno^JVi}ZR?(U z29InUp8uS=G#_H1;fyDdn;>nM>!o(gqxg#Xvx%WJ3MO*Ze0c9L0T6Ff8 zv)%oAkrHJr!gD6O+fs#M1fe4&=YirxXNhD|fup?dgHM!FR6`${;%-Y0Q+T?8Y;v8_2 zMk@fk5iX|yq9W!gi2mjK(0;V40W33d+cz-HmHVmjVS8=zI9hvF}lppw{C=- z^~mB#Ki2%Y?x@YX2##aazbbU?FIEs3#i|-5xa3!!(MAXbOvi4OYJtB7i@9P62Rdk; zMkFgZ=f10zq(;b7Q+RUB}0obaGs z4}P5+C4px>-TR{Na}ed_Vcg>KLPJS2Qa8-c*JA-$DGavRqC>9#FzWVl5%2kv%SSF+ zKH=`_+nsJsaeR}-j_N$Fb_)_VIW;ARZ(%~jt$j?FWYD05o3uxnHv!Po@UX!ik+*Ys zZp5OjSX~U-Wg{daA)xk?=U%HJ(5_uMDYGBXkrLYEz4yH)mvMxUl4eb9v{KBW&cwd? z`RI|7U_h&QU1B8g+{oAH4;38XGKV) zv^sDd0H-79`0zxC{?TeCh#;#4Kj$25)*C}4@sK*c=d_n&g&!w9B7u0$u<#Q-F$7&B zB!%WTOwaRlfSoG3CMRruoPh7 zyFNSXGZNYx9N5IhuzT~X>sgu1S1u)1AuzmOR8dK{A(VY~W9z;(r);mUtavYHvgE*y zL!64Ecl3nktxhJRii&v3q-d-v{@monky(SPt(0jgG3#`dl`WyWr=ExH@nZRf8CmKSN&+g#o5 zY>GmVym2_vo6y@g0vD{A!Lokn+q|0JtvNpZrb#*{<1Ni;Zj6Y&xG@rPpzDo_HWuiH zMwi#pB$wrxwcT>Tlwn}-By&~NR#j|j#4tG&MZs0Zu&T-9E2ERrR?|HY^$!t+`Fy-i zlSnZADsvBhc6GPuaL?0}(^COw+tJpp*8H;~@rrI?%Lrpl^ zzkN{_6GVcNi#pdhljD02snR;{H-~V3kXZ;NQ`-EFoYO)=&Jqu7k`Eir5I`VK7XZHW zx;*fo1-eo(pds3_cAp~^3?v?lT)n)a_T9(b;6x$N@bNoFk`Ot>Fz6ec_^-aG9Q*gv zy8iExjODub)p!N;r=9aYc|J2oZPs>l?TthW$WQ3}VA=s8$p@Xz>u_W?HRd5wiHp=g zFDA5DKHsC(a4z_<8 zgDI=t-;+_bw=A(uKP=~>9F#l!N{3eFJ#C)_-r)YZ_aL&YkLURM-=>ps8tjre2G6>< z5hA}SloMV|^Ch8HwFEtDoV6NSZ#UtV=OZPyc2Yy9S^1m-k}9EazROItWgq}53{bm= z(yk|x5d?N!&`2#{m<;2#2x(L#x(_bIA0)TKHTQ=S?!p(MAINdgPVU%?yW8^j#&vO_ z;pQA}0PysZGTBXsoY4l}6I_fNgmMuj0J2IbCA&)cJSz)qD^bHPSk+yDaAN^{)?NrK z1N8YixyPTEQyYPZ>TkYA6c-~UN*t~pH%B8U6`dVnqR)=1*=GBvYD-H{>B3IYIQB#J z!vlQt9a=DaF(X;MrYz2eAekNLoX%Up{E^j z68?{pqYt_(Zb0{A3CE_Vgs_w|mc1%HBbm*H$uM!#%HDHsYzA>P;<43Mb}=Xdfw5-91EXo+da6(!isS*L0ex_z{|6bT*q&oih8D<`gviMV`CMK zOkaap!#H-j<66^}%jL^Oduv)@Fwsz7dj-;F8`T!M-Md3J#kV%v!ds(P`{wf_BoAp} zea{XkdKJ^FP8*qEbhJ5FHwS8lsq{g5IMO;aL=ldsqV-(JmpDzM73ey#Q&_fcUCX8; zCA$^2J4{yFA{ux@6I{MdM+x*T#{%U&t*b@=oOxObI=pAbEwu~F#f7ai**YfMMDVq zo0hO_a3|88coox^Xfa$;m%pjMG32DSnp4-2x!R*xevgu3h9f1^UdD0I6bC_M&lcug zlrohW`ycm1o%Ag=tmiU$#K*CSEu|`HJ)-UNSiZgLdtX<1&a*hz59J+_Q-;XL73ONP zx=CE0A{_oE=_~irW-n2E)GU-&w>zh&I~jrUnmw$KT=dSvrH3Uf+gc^>!VhfO`X>_0%I&y5JhfKNVq6@Jg1ck2^ueDxNy8BLwisWG`AD5*T`c}19Xcho z){vy-e4+??K;*|CTWh|oDK4XGriK|rUi^}c4u|2f@P*P>+2N89YB00gUTL-1yk>RI zn7W$Pi*UbWfh33oXhGIhytp(p7K8hGdR*tM`taQchd1`+2CMhynK@@}i?6*{kDiAQ zD#rZntoZw@93s6VBy#ZDEDSL4u}NJm?vc{+^LnDdi zroE>^HkF4VZEvQB=K(3#0m5|I{5Hw<2D75Oq8kp`JmlchMs?Z2<}s6^*z4UV(BNb( zJu4QTH_KTUNo7L=zrjd2*K&-tU!n47+RxBLTq;StIUkRs1GdZW);u++R!8WF`(Uf> zY5Drprt}>0wRi5FL|&Q!*c@WVvKIj%bRn_ftnG1UbekX>CY8!Mlk z{%^C~=`v1rSXo;G@gE~4Eo9Nh$jtVt%%=BTrzK~LFP722+6XbXx5>;^>l)sa?^$wc zJ8dsGM$<5mXBQTpTzTb-r%CmBkM6gr-)?Hfz8~!qCd2sgGdf2hXuSF79zDK-E~?Ty zRS`-=g~aQFvm=G@6;~jeYFR@(hZYxd*Ik&urv?=zGsU25PF9M_SvltHVA~+)#`)>P zv7VSh)LZ7QNMEXRaA$5U*{afh^=(S(Up996%Tv+@@*J^rH()#wtl%d~6yFvh>dta- z>yz#$bG9`1#4c`PKqk-2#&@2bAeBC(INLeO4y3yCdPE4;r9`h(1C}FY;ZjbE66M1V zYBCgk@W$(MUv#dZx%-RZBP2%|s!rmz(#G{+yuU1cf)L>nD%(`0(jeu&jDnqw| zFd^dkS})41*vo^b3B*0pVSM&q3!j8SKILX+uNb|;PgEUB7l6z|B<|!K-)Y1ART16$ z@t!T}D^CfcxQYIVz>EW};Hf+y7c3`0tQ9uZN}(U#3q-LoyO?by!rDhb}M2e+a# z;laWKSF@A9&!2+*_izOBU2>b=HU4iGdOn(fI?v88?YhI1J2}t}o$VW7ik%?m_bJeW zs|Su-_U|k{(PL|+Ff&wGQJL%9&^^ZojBy~8s)ZvGprC?>_in^Xc>8IG0bPTB`OL*# zT~~zGuvAiokpM};Koi#;|9L_5e*b6Yx(WJm#=qb0)yE{f6Dw2w@F%ZY4vk%X9)0Y? znmj2ExDFJXXM*<1bm^l?FcnXbj%z5sL2Tg{RYV@I1g03@N3MRV(f)=}Mazo%X?*jP z6iLE;*TiJ=XvoOAW5);Wc8_3v)?ZX3CCSAdbc?UPH>^jtj%On!WaXHmvgL(oghLdF zQhOx=c_0=e7@sTb?@p6-)y`abOg=EH6*q2|?!+S{S#qCVFsLmz6oq$c9%S0 zJxtZa5a;+jGiS`m3!Xkr4t^Kj;y1e|V)VJ!ZlqzF`eTJ^uPE(Ce>EU4i1@mXT?8!G zZtbGa(C((SVF1EMoixL(!d9zXT_YqAc8GG{g#;rTH7AThp~5jw)s9!j@mjA}zoOZD zW^=mMMaUo#-xF=bz_4BM0gPI19w_+D0C=4VQuB0EGbe@tT>^3-IlHAHSHtQ>dz?tF6)tlI)5)vpl4qO;< z!%roKju4WPpr9QzNKoNo@~ijBPCLA6IU8<=;1MG?Va>+7-^NTFc8pIW89;R zb}O0wiRZpXpRv-GO#xWx#QP0kN-fM^4BP36BlS^`gD?|msiPFy-gtWXV(+^{YWhul=68sRA(^rB zny)73*Zh{pm*bqY^B?Y-l3SJjNIG1-bWKN7@LPLVs>Gwq;ODV=UL+eX2{y*?)lw3> zJ8+^1qqg$qoEKNe+VEjG=Y_)9e$Z47{e7R%lY1YNx=Y0w zXT*v|*i7~7N8mz;@fVZeOXZq0)}GVe+9RB%f((9dz0mrNeFz5{>mzrS zb$a@?k*xJn+-x`;+#_QXL|cU@Kqb5`vZui)B!J?lmp>~B5X*A?rg%9<$mcqOMQbN_ zW|TCpiJ!%Hr%H7WA_p$Fi|6T%Q+;tGC5L{=kIp99*{27a_|4?!1Xfk3gumT)I!pJR z$L(T~0U%L9*syLK*F_SsYvSp)iwygnBPG^kpecHQ5zT@6Z*n|Y>^!&ytGe>EVj$*CB1$W%Mp1vb<`9EmEx=5W7 z%WIj)^$vSEozYfG{O0x9tIPR4D<5%_Z}#~t>xz}X!0#4H9_MM$;irp5kX)%pIg}V0 zn?`=#ZpdsGEV`%}BP9h@53+|8sS@!*F>;DYnZ#nV1dMlA+2nsrbR#4>eLX^hX$t}< z2*85CjRbSS7CLQc!SnA=HZyD1bEP`+zI#^=wb!yCrM$_u z0y4o}ALzrYtv{#lU&OaC193!ae9D8&QIQfZF5ILJkV!ThNPyq0W|($)oYB5;h(3f&d>zRZa`XexbZPNBR4WwU z2u;Q1*&?DvJOuY4k4|bpgD@?Z>Kj?mE6J$E=W*yV?5QstPEq(dp&(+S~C*C6@ zA|oZy@+`i#&1j6f#?QW=BP6S0Dhw7Xl2TUTAgi<}uqF^@_cC$wKQ!2~*)WVEUy(WS zZE8$*{jPlbJ)My0lkiz9ADlLq^R0+Xh$c=Z!9TpLUNPsyBjnEahCCWiE62nEL^P1^Wf&eHivD!8A zq0D+-CF?G>Mz(N%L|*!bjiAWo1rP*!rmpN=K#HTmBPEn0CA@Yk8h^{%X*&2%#T;#T znN5TwB+PRc`CY?Cc}D$QFF5O<&ouk+IFR_8bH;^t^4ZUPjG<126uuF{0)`(%klF2W zmI(>@6O;NA{S=edAe`h`67USt0j?{g6yX)@f^3ojNFT;BYQ+iPD4?VxBu!eFZJ!4s z8lN)|7!bu<$}k|{WW@FX#=B<+Y*<WB4$OVJ3sN}-S9)+SPzIq{4m}2 zCs*ni&q; z!ST3lVN;Kvb#kf%E?QSJaD2oz%AluaXidX@zUSKsSYA67$|rfNIegQf-RZwvIq4rG zC5UXh_$FvTHp!Wt1jUe$YHqXD97J7PI4(6hU5&&yqq1H-kFZrA zQzInopzo^93E8F$VIj$rF9t|#+an|t>dHRueUmwij#o_n!nCk|=1nDzk$CXs9MD2$X~#Jc#urs?ezeu%FT@CG`5I9*{YP#=Uj;kbTf} zQ8bbWC3f85)(IiS0N{Kikd%_$QX?hgrFrdJLf<>%=pD`MVr%>f$J|5%uBJPMh>Vy# zhD^5HyIbWZJTT%2)o}ymBDma))g7ez$@^G^rN_Hnsk`LVOgiZh)9@9-CSYSo^ZeY` z*4eBVL)o3ShBvK^`ffDffMw!l*#a!X$I z5=(|f8}$^-WvS;8a2yqJD4|zQ?GbdAdkCxjLKg-^Vu3P5Nplx3N0&NdG+njr{wBMy zdi*(1$ZiKGWaP7XvXpVwJ(%f{A#HAB*|j9KUw*mUqqhO0skZ}uo9T26V!=UHJaJp; zjXDM+CFGmP`{)P|z~F}dH&&6XP%Q9KI&&{8mpV9v%%#LZPBypW#O@&@mIh3dHvB+u zfbGW6{1y*zy%5Je;D~E&sr2#FB<_3eaCCAx1#i`ssyWx(#-{KT6*@>85%6g!`4>3l zC?sLHsUtKPFvSFfQ)K5#WG%7mZ;NF-+?=DlYPKUBwOnAzVDj@HB%5pxE|Vn9Z^81A zj(ql9{uWl_duK#XtMlqQQH6BRDkT(Fhz`2fbWohT$yh_++Vs z+UqYy56~_T0Af>lMjK%q@ESw|nlB(g!T4Vwq=I!WlePKHJebb>fXXtg0GU*-fWs76 z6@p;!#_QNdQ6AhuC_9;Bf*INRE^-?vBbgrYa6Vac4xew|^>)vP&Mer^Lvjg!c_a|S z_(AZ4{eP3`xel0f!MEGq(N4Lkq0#17DLf+f>FsSoV2uuWiJI-%ynL2#^>*!pZJX1S zhFETJZJf9uQD{ue+cKR%3aE1h9j9h@?fK1rIQ@t__e zB9XiZ^gb-eIcf)4!{H=iwu}b1K8=Bn=Dl~uw?Kq8Z1#^jkE5732X2_pfd6t15heUN zBP96GXgBehx#K?suG17@Xs8q@9wQ|@XhvTqz@&Lc0HZPI9HJRcrvHXj#yb=2Veo!w z?o6h^x^5(RaPQTcdFpfgHjLhOt?gFRbjBs=I)%5b%9LBXp1u7p()B5ydBKC?Xcap5 zeIv$NH%V?TavO_vVfN73=Bovm^CC89yyCoh@qQJ47p+bwzgg39fbvNs%#)$elTKy- zMQ2>WBP5pl@h3)ojy{q(_U(gu-9qZ)=&qL4#rfg1c1H+&9gd23-u7%vSAfz^GU{Oa z`~(sMw@KBsYZwRDBP399)IhkjbW=lQuWJ>@f4&s`f8W+gtM^PoW)@r$mC`WBi#7MR z<~j-UX@b0dMq4$(*IFekuhu|T9j}SUxwnZ+tQqaJO$I!+lR0Yg#A{k3B(r}rXqrG{ zDDsEgp8--S4nj3AV9QW#F zWkt~^F(v?UtT#lDTBg|EKrkkhR02WgBGJcRW;)D{m&?agAt3miIdR)}Ac9h+;6)N> zL7I$PBogwl83K5!#c4Jw$8a>rCE!IlWO+fLJ))c zA_w1JS@i1NJM& zgUiVtRTmR?oHP8BORi9s5W0!Gl@c`pOjNsZB^}c=xy~o`A;OMI6pMKpxSis+Yq*e!;J1M!g2gYSY$*N6J9BLYlA9wXg-}8u*5D>k=j0tH z+ugZ>XxCl_BP5I)xI=>u{@>kHQZrzc$ddDxDH(4#QY zEEXsWC+|3XnT7y@a-jN>{QoNyPI$jomLnvCJBD#;!msoE^uKMJ=o<1z;$P|hrEl=H ztlYyt;6_Q-YNA`X~7E*3Kr7m@T#hAz2HAy&YbZY?LfbrJ6@Ut}|C56Y9Z(DnD-;htI%+ zaWCMU+-hXx6cTKi;QKho$=C36((Xt^wNHbMAYU_ok$;|Yu$r1Qyu$Em6ZX+oFyCkG z8<8N~fZmBt8y+IB58P9!Vq|eX85*;Ds9$YN4D9Jra7_kQJT78oq9BSzle1cq^r=XU z)x9XyA(+jok;-m_vENz7vg-P46Y9unskh||LkHv_N0IbiXgJ9v2XWj$e0&H(s`bUO z*!ID$!@u&d=fWL*hj}~dltj>`TWqT(DqSIAR!1Z_$;jgba@?eiIIZuB<#HcSV%9|< zC$b@p{O!pt2j@F)K63pfFtpiT&2f5ya6M(ndxxjLx5}F8hbM~27%Bo{#C2Y`1b5wAWRQiyjvc`xC3YhvplSeTaDLtf4> zOwKE+UW`%Sw_#xyNQ15iOAzSJy=XebJ?xyPpP6RDgBCT&Eb=I$W7$S-M^#&U#`i+v zCIpf|ubi#qN*zH)5s3*a-P49rXSEQhd@99o(kNot;lcRtpfqkI#tX^p5Sdx8 zDcV5E(v61tx$YUZmphfWJ)?F_L$?d0ig3Iuo#P`Ul+g!p`n!oRS^mLn4Imt_zXYfL`6*r%reDo+BgzIiAsmag?3_nI`FnNG$=|Y%Df)%)quZ zS{?DHmzQ^y5cLNJ`ElxCP8764Y?Kc3Vi2lBC|jRi?fUpbJ#pO*&W-*qNNm%mdRwIE z-63*`5e>Li$fDf5TQri^jQl;jw(>ZNT(zy zbeQA7?%{JIB%3sanrK5sN5xz5 z>45Xt^Ii7#Vkxzt-iKT(qZH`_4%Ww5=OZMoNwI_|ijrldih@EN*b}v#QAxV&raN^` z-*kLy9XG+63GxuqOnW(#6Vb#r&P1r+HK2&kNLJnH;BP7OYi;7(`s$h>*XQJLo zAd%{aY1BYi)7qUbGU>$?-Z(q4I7Vq7D(P*c?X<=REh5hvBP9&gW|p#F8=NLHadT}P z7g3g@ zvlcoC?$fiw$X2o<&6T_qY?*qn;F<}N?*#|p=0SnboPnVOpFD_#Ylf)WJ2SEz%+-Jt ztKU~^X{NwrDyW8?N4! z4}L!-9O|*};W&g_n}a0xd1WIdr8PcMCi1Wp(C1*c#q9Q`mnp!rqhZ|n0&5uUdTBgB z+lTuvWvnI{3s44-ZOf?`>^Pj>JvJEKQglK&GGcAq$bkAK=4@tq96N7VgSh7%=f)j_ z#dY!UVYW>JH@a4bNDMP_O%axZzhEVgpp7PL8k?HFw83-B5{Z9QaDcJcO}L!FCFpw* zPhvoMBPDg;pix~8SfREnAO?BsE1GK@q=*JOjEf^A&?iKc!-K`k>q?sS&DsZgW=S|h zaadUb51%<5kCpNxBuKzJaw~u`$8+`iU-e5PSnZQR5J{I=XH&RU;)%W}b>Eqs$Pdx%OHS2o?so#_`W(UM|RC z+){@v)M!z>OC&-@Fj*2K60H(Z?W!lTaL<(zp3gj^hN3}0@rPOmg+(MXZou<8PIWDn zc3aOJxRyFHsByQA?|p^N=CI&y=7S)oJrvD*xkx$iypSE;#`=r7YJhG5a&dfH4Axo? zecOz`e?r@vrD_8}gR`@A^qGVM#?VA2^>s`%W?bDjt>*JC=#QSR_vV1x?qXkfukwEn z*QGA z(3{A1+J^@sXzEas=&Klg+z|c8wu;nY!$iNA^x$0TR8M>qRD?tv1Qo$2?)Q5r1Y)Dn z%I`I-U&;{?GlWkZ12Q;btp2SY%bM_nlQTXGN3x%b+d8!L<~);#u4Hrm^So8IcVa4@ z-#Kz8HT$H%h5SpKp}i0(-;~t!T%yEoe*xm9zJ&K#g<-8_WZfMS)8>Zy?>kTsXgBd+N@YbYxn;{`ra<$ zs{b1K$VoBrXtC*pGYrS>e$tH@hLK8SH>y-oKE1Af#&DxLanSWU`TP9vS#1gZG5v7- zQ;Q=dfmK9mwr`qIhoi-+ghDA0lXJyTN%OMHf3NY|kPD1d zLt2olK_Q$sVaVIVmIZRem>6z&RX<1cu;?`2xZJ@Oo>go$sH(1OSx7{*Dns_wPsz`N z|3|a!ec_!NpV0^GKNAqRaCL9|(E@I3=CL=9aT@1{Qip%?V2DJy0OP;;e);}{dd3VR zB*u+GZPXz0C+uRjx1X~Huj({~_2jOCCpRFQ#(56Eq2C7rj&SDc&7t6rgR5Y@l)TS= zChWclulw)IJZ3=%g8TpNnqLd&gn78-gO@C$X~oMnW{lTdSW*%%1U}T$UArNGFJg#E zA5Wqlu@0ZqzfJRpta2I^e-~VyKYW=G7Ag_}D6kes4$lvRvYll*I{@*I56$T3~gb}70L-^uPS_k(S7wbKie19+WZ&sgOe$cDW`aBm+AF+xv8ujt_(6^W-N>HKu z{+~a)mC&ATE7e86!*IHj6S8k0EnFicg0*(2Z#~ii-=scn5y!Mxbl)5zbF4wq2q6)? zBZ$w!CW9pVcmgY>Ju-nt@U(ggI-cVP0UK>sZgwYZDDd6&fLDYtIZn#MR zYimFS-jToK=k&Lq!{hD30+wp?+IzWvXW8qbcYQa19t%9b=kE3F?d|fFR2?`j`Dfts zz4Hbyzi!$0ua!KmP4Hdt?Hxn0N8aB3E_d(DL)_+y?$fHDwfo8ZV0|lt@I?H?0riw1 zfSu{9!@bA_{)Yg<8=@;36`$QNsaaW zvu{5(8Z_^J#KZakevx$tS|2@fhA}ynWjJaN(5%Cy2q}E(e#!&C3Hf#O!_nKZMRlRs zrB`gJg$9w|BP82uIwozu>Kd7SoWPj5SP7jw#vSSjCA8NRoyf~G_WSp~as?wKL1>b| zsE9$EIDvx~-u~Y&mZP?na!ab+3s3+ z7Fel3^#Qz)v!8;c$#aVl`FpmXA@9fhJgka(U$PvPvU7PIaFQ@L^;Mnc*s@jnymiwA z)S3<%edj7f(u(ICx&4$M%a2dp;Ae$vXCoxHtt7wA`{Xci<3%Vam34xq*&@+RY?v&aG;dXkr+Za*>#ZTDIsXQ{3yVU zK9-cM57<${<;6m>V5!RS6Dq56OP_S~ciT1L?|&PQy7A9JFSGAPIeA53BPAwobA!s$ zT$~?`GVGm*kjjiVkxR)VC5lD$MI4IhBP88HxtM;^kuv_f5Zp_znsc!)g)hMeFE{*tZ;8Y%?}npAx;^^F_;aZ*qYjciTW$16+VgS$A80UL9QGxDiBIQ$s}$AM zIC8xk1t^g`KBvm?e|AbeUQ<%}*v)!E8r|ypzBeK2Q&4$mdGpM|tL=Us8c3x`+O&jzWD&rp)s{%r@@p zxicNBrm8BGUS~Gy*K-6wj6(Q%9^RLO=^IIiPVT2^?Dj^>*UvGX;km8ibV;|z-e`_B zruI}(&h=QQFP`@@{=YtvT@}o>{Fm72So`_8u1U?CqH~Fl8Zi^QyqT}0X6xD8Wu9bt zc)bH2X0V`f3uA@|-ONK!Es^IHfbb}3`XBWA&jvFaruWy;T+tlxdC@U5Gx=9OydN!i zBVJj(iTcbwr|0=Z6@*7wXk?Jc5OsJ)P3+Lm*C_SOU_0#e6FHG9Tb7SvOW8%vwd5>CZQ_b1pFnLp{G2Q^!H`Vou0U7BdB*`)AiA+(uwL`~d^M)-k z$!@n07>I@sk^*d9f-!GhxLv9Av^AchJqs{O}b0R+5A}}=J;6OS1fd`vFi~?WYyIq zw9z}NyDFiS>w8?)!y&(=1*a~%V3D;0obT{Z(s?aQ3}SI4z%K8h&S8$~=T_ZlXVc$;Rqc&Y8S3lFj;h#4GKsK?CKs;w zfrawpbVewE2T3m*BPG?w^xyMJQI5=J93VUu498UG?Yo_z^Cr>lTqDnl@ICcBxx?=` z{W}P`B2GEX%n|D|tN0K&4w$S4DvDh`ThhRHzc}X!&C7YJj4pN*K!}@tG#fm7ybD)~ z{(<~_1b#e_-?nrv=vmDcxUnKb!I@w^o%3#pQhnQ ziT!Z@iL=eM?HT-6uCZvbo?6H;)+iYS;k{{zmf134#bB^B4BP8SQ2zX(K(|(_U zFX^5KI)(H3r*aO&XZZp8ozTP2JL^S@h+yi7%8qAbdyG0oH+iQ%A?iCP*f1(F3^2-6 z0(t{##98x(!D%z*s&oq_9FWA8k#Q%nMR4xt$h!y5Qbabq@Y&Vq@FrtXdXETEAz}Xy z)61qKB?icF`2hJq2ET=~PxbPe__zkCU1rT^6`JFDM0Y^IOjRxh%adolsrN-Es>Uy$LO9He08W4(E&POD`RBR5<;J z*Y z6p%9l@h0ydO@;TWZ`7d_2&3+*52O1uC)eIIYOwYq3F3$P`(5aAJc%PEKU|+gk+2ral+Lk8~W{@0Bk5g%61Blph0|1A)9P%2^e z6d{LVeL-`K7S(UE(GC|%+dnh|53(xJZ+ETl4nV%zxP$JJ2nMNSya53DRaGkD(&P10 zEd8<`DctuXC95yVJ?Gpk@WOJ3dxPIx_GTv~0N|jMn7oa#!8CdSvyd*4a#q$(mWy1c#{Y;>BI2Iu=a(fCFQr<$|@Mw*Pr zex0XH50CkbI4kjIlMh*%0a~CuStBKr=;IR8>oFcKa)-n@jp0+SnOa3i0`G!^II-21qroHrQnbAL~f=-7R~rGv4EmvHrZIr@hla65rLodvrVA3Gubv-m@bI8@dtAnQXcVqZy^rn3D zi9>GB?40EgQtsvziAjaa5}E>#L;r_kk)xzRSJ$K;e3(7fE7do?(~vC$4^G%dE?Wcb z>yaKp0pSsLgYr*CiK(m}lG&)X^$*d6M4(9LkE_4Fy?3SY?|vYO%&FEPUO#>R3F@y2 zoEen&ci|BezV8DP=;DXVa#P{ZX2OLYHQ;Hhn%=WS+Ja_CcTpTK zRquYie5cDai@j|gud#Pf{*e6VH-~t=9zKU<_A6cT&m$z|)=i$MhdH}EP)oS(DIsT_ za_5PN?5J!s#-rh8CAMrjDqw;|gU0f89yyYNp*ie}_ToZni!{EpBQ z%lh-r#onUh`CZK;BtR5F1yoW^`{f)~y0jIGmwf|-1SKOSIIrza*z)-aoI{8%J1pwW ziSe%$wv8sqrhU(SzA;vw*;Bjxcr)`s#ag`{8b&O5jV)=PT#HEW&tsMZfns5`aEg;j z1vuZ+Y>t z(~lcAQ$Hgmxo#278>eQ~G({sMSfcC1g9+yh2AFCYe@aFp9@>^RG+TU+m$#gS)RI!X4L>iU|TxOv)}OPAGwS8_ME+K|Z-oe7MuP=oKPADOeE zykiK_!at|?e*gSG(qzV3+p9b`RLU7Ze&1#zB{*YoAJwB*&%Sa`9p7{=@q($Zbnvt4 z2p07DJ@^c+Oqf<;h&OsUxCx0y7-7tz?|pGKL-(xmqxktdNM~mKah=ZIa@O1E^2IS- z4@5yxyPTvn;cJ*tBP7XiXQg!n0CmD4&Qy;1ym#o*=fq(9wTo^UdV*EeiK0W@eKHRPdHfQy2uSnYXTIs?9o7~Vb z^H@pGhXu1?0No=cpg^WtCo57&B5TTJuKapY#>JQ7eano?#AiP1M9V$y|0N}lWqExj z^L@SZO^Ux6=3BR2pi8@HM{`b>lufh~l4Ku$2974Lqj^cqfgNOiM11|T%Z9=+ylL;i zr@r4lO?s_`r;C;I)fB7tMUjS)dnQn|MBgAWjHlDPV!7AC18jAStROV{^@9ahU`DgO zgn?`BU9VhJL4&hf)lvi_B!&YMpl0i;$OWHJO0b5vW16`Fyq2wcL;ps0qrYjKBW zjOI9@HQk(a`pSg@-ynO;>8K znqhQHZ@8zR{29wM&!^E8$7(EyzTCA&U}JP79Q3XMnp_z~Wc=Kh%9yS~LNQd3^bq9S zBPFp%)SdCul-N&H7&+ln8eAft&bU9BQxSuPwp?ax{x{#JD9*r6KO-bC7LEQRBoiT^ zx{o`MA30PKt{y7cb9G=fAw|I_u@GmbIlx z>9JDkris|ev%!VE6XjO3v0W|9%Z9T1SC5KgXfuB=h>FiIa!5WOV}3yDo|)kYUk+IW zvY8O>~gN%%~zFPdJ*r_oKf2XTXhszmGdy?kB!;P zziHTySABULt)%Vd@ytkEwuyk!y<-ewfyz-{7kaFOS1GJ`tKrK;`8T==a-?i`jc%jM z(&44Z9CaRSLg8==6D3{XB^caxPUE&&9$7z#@DjeraV9Hlckr{KJR$kZ_+i*P2giNH zlPx19rvJ~QG-s={cI%acpS@(PzVuhh<9BJ0sy3n_T_YsTN;)WtIh0M5F9M_rdkJ5;L zNywId>$o&B)vz>hRvLL2lfk4xw{o; zhXNIXiX6a>vwe^qZTwz!4+otiB)}e>YIYjlW9hNoa8mv#zW(6qC4w;%TBVox5Bu}a zwC5h+h-gc0=M?fPa_~nE46y|2$_S{oG+?a?Pm1()& zkJe@#q1gRM)S`B{TgO{5AbQ;-%?7?J5amb)3(HWCj%9$zkE>*z zI9(6VFvI)Z$800#M+J3`a6^Gq0kR`TqgN8VYp`4ZdoS`2_zRQ7XGDS?+S>LNde zr_Qky{Ba{CRZzODUm}mFPqejo9{d939-AclfA^P))* zi)QTB2iE#{uJdRU+o|6RRMtJ_3;iC<7&V?|JWXqGgCiwKWSE765`5o}%df~NsyiUm4??UZ9={Yh z|35c}hi|X$#4(C)sq|HyIaJx<|u=P<-S3ofOFK=K{lU zv^_BOhnBl;h{iC8qOvM8>Pq%gBO;6;1`&e4p7+`Gr}_Q|%Wo6tf3!Xa)&Ga+447Xo z|D7myp98ppe8?XX1TB91zcR%Zuj23O>+)v6DERbC?gsAZTg& z;VD9c?GNO@bWcEG{X?6s>36ffGB+&7V$2topR>y#HwL3Jz-;jXwE$oE;20uw>4UoJ zo$x?2>-aKsY(DR#>$9KpDe@Jt--p^g7$ETupHEzX?;rxILa)FEST21a4m+QmFr&f+ z34}wQNXMYWaQKXXdNE6$N1`4Od1tOZ|Iljqo@aAGK|Aq2P~5H6ZN(Z$ABPZ-4z6I> zn^V?$IR@&Is3_9j{P&aT+0TEYsQl*BJj#J1B}2=&P7Br@z;q)_BmvZ5hY;*J`v_!o zj%GF>L{a-XbSCp?1-teA6>8QDkXI4McSrGj{u|Z$j0<*_`VZv6F(>ROxLE$M_=!)H z2t|a#C#~r<>+$tyS=3zvU~j6WVR~zm4JLSd2b67A8|Xt)(Nfk0R&USBgkd} z!eFh&iUjZbfbnA|v$+(J^YHna!^7$Mb5!RiC-nJhKi>Ik9zJ++8wr^C5x!pzh?}xW zm?G(>;FY*V5OJdJzgHr5ZAv)&s1CBY^`)#{1+s(yI)&B?k@$xJj}H537$X>&C@J zT~MQ)Qk*s~u|w=_v6W>XMk6E`PoQ8G;L%hmK~-5bK>9pXV;oGodjQg-HX|gqn8sig zE@=+dI5-q5XS6#5#5rhN!Z8`*fw;j&GD~crmXg9Aa-$dJ3FKuIX+KjBVDyi4qay^v z)L9|@p)Hm=8J0Tmv4$!@qpo zBh&zEGEQS}^d{ZJL!b@>YN}hW;k5mM;9z|R?C{Gz!XU;(ke?r>(iHwNzq+;KiGu$o z6ecJAGJo1JFmK1az^m!@km1o8s_ zu5M$gD`zi_?YmH?2pf-Q(!4#ha-Mw=kR%pD6GpV-e!{porw9n%$G6@*1NpuGG;{PY zB|{hxfe?uZndEtT^tTpvKzatTDC3r0H?h&vOI5?tu58hMZLC5Z^=Sq+2#-*JHuz%8 zM{dXZr}P8m`5Dt5OPcmbP=O_U-<#^^T6Ac18|v(IR1-)@gv`va%QX5l3x>&jq%N8J!qRQ+`nJ18bXq4%Niz6jaHbEo?MUh#5+*-dw>f_bl%ug9# z9Q_W)-vbHnaxQCm!nkrH-x-sJr1d?71Mod(tvIK&pfr~Yh{RaL1QG8H&h0-B119nm zTrq$zrOt3Q;JBTgw>9Qj4f!BP9|g z(7pm{9DwWx&H>wjtBb~hK<@R?qFkwbPHZnX0mYBWN>ji%I~Nl9n$N~hT@-i5=N<1Q zEU0E`I;n}hS||z5!+!ASJA=w^JUABUkrE~?EAMg)jD7X)K;~1E1fV`(`HmYOTJVEg zCr3^e$64sa7KN`%Q7UO{J^yL>aqB!f)cDC@v|Dq0A5z#4^dQW+J%4C_A5r*BA-ayx z_3tN{nN(UyaH@~$9@g1v!cDkR7*kxBb2af(^JqT3x6q$UQ4teW2F5wCL5wF3W7IX` zfc<6(yyn=!`iKdZ1&(L8Lm(pz_ZT?9lf*$(6xMB2pkx`;`;Q>;Cy~y}h>;^BC6oa|l|@@8 z$I_rU!*+`%T5W|B@)!m~kGwszUh@7$2lI10{CVw)`vW6tSpcPqNDIIZpdH5Kv(b^b zWA=h|svhm9Z`WqW)6?NLY61`!XfzZF7pOuj1R6D`TY*NG2lod+Fd12D0mcS^^#sHW zXbhg9cjZrLItR$?CZg9cZD(t<>F6Dh^1ZO0tI&DtO?rVi=mC6unEx-2knntBloLIT zNawv#w7VCR^Re1qv0`HO)fE8ivLp7wCePHgM@x9N`dFKjL(FY9 z3n>v80k)};3m7}ene+QO{eAV$og*cg>voF99Qoof6^Sr(Yip+$j$yEKaws}NCnrfA zk6&m}d$XyDHUv$UDB1$k*v{it%RGS1DaxcZz{E~>KVOzS-WrE{u>kEL$sm^6XO?AE z$Lt=mk^Q%lVO$KMzz-nVNds$sB&0a-F+FCl$Q7HvO}qa5C_{3pK_Ws+o}pd{{L^((J{*+GO z=mO|$F)0Ol!*Sd?x{s>KkTftUl%JotJtHJLQ3cRS_9qiCqGt9tH*DyQjup5OxK9J^ z1IXNSiL==^xEU0Nrivh931lK00|$$8E&@kj6m2s?g7BRNrEFOtb30Xo)E(seJM4Tr zMqstEv7r0tzXJmdj94>9h&l6d5rOuyD1w48Mk6JLZ&|k3#E8$_%*qlfiYmp1q<7za z-8DD9z3;z`p$Qo zPJ5Q5TUNRfYj={J%je={r4hKapYW5fehQP8#jJ4mgK3lqU6g&2;#Hn)ciTYons z6=9_(;M-JgHvlb-RM99Dp(-)xf2DkV@H@`Vg1}RUr%aj&>4-!RptI;0dV6Z1Wh4Z* z66em~)a{NcBvGI^l%Ys9(3cUAf?d&-i%KyxS8riA<6>XN|;?}Us# zCS2-pBP9Dbd0Dqn#=1>UVS4+gD!8&h6z)%g7s2s=QLmw3hzHa{P-` zzv0lX!6PJ4=E{g}kwb^TzsiHxRUM568__8Mx39HZKA_w=k!-2351Vey!|Nj@A94Mm z{+~YbPxUOHVeD_+(czv@!wlLd`Lc~t9#YT|Kfx5QP_KkKgGX`@#0Y33B}6pl1jGw; zU>zVdB?--uG*h+&N{C$m;xwzFG$7sa_7a_RWG>JY8z1?roo0R`C0vtumVaLAMu|V_Q5!5tbSCH<>BWJJ zBAI8Fnc_&|AVd2iQaMmaCNT^PjG+uFqOpf<^4nWq;ik;;PyD6)XTSNeLltPUl>Q#L z0FeYaZ*8gilJ9{0F5g0LU$xw)gW)KtGup~6@4-SCD5O!%=Nufp6ZX5+eM$U}C=-Ph zSN(r!rSFR0HTLMwX!&AZ?py%z$T-igV)GR7s!J zze^(}2r8i=EudWJ57z)4yG@+#7&VrIS&mX{?qt>+HJZw_sxv4Vjv2T|U@1FXqCi%S z22wRQj3Xqv@aUDcJ4+h1Q3(5XA1Uxn;(le-?mb2%#mAVj&#&M6e@*}{F-I7IvLhs- zsCzbMkcFTGi6Ii8A^RiI<;P)*56koEtEbn8;m zdKBpe3vFNOIgeO-GOh&D83Hk{vUcI%U&cepqv&Pv$bFJVQA{K+5m&h9mq{@fgGL9G z#K2#5@@UR$wLF|3ixkD@r*{DHcn*k;cGsY{8OecQOas4|hdp+(le^CEJRX6SR1_pQ z=*E@8qX6-oftP?I?I07PeawT;{iCjX^vCcVnV$r15H~UeQE*=4vf1y|9HqGFW@KweH~)D_#UFe^ShhS4x`}GRyn#F zh<)qjR$w=6^-bT;SHybR;fFmT2agGx)H*5{`y(Wbr3^^kCk1A;=Q}y-8I>BjS_x(L z=wNZPTAXAR24p)NBP1gvnemBzZhM9BGIiNTo}lNtYPk9^d$E9Q=-MEld|ovaZ4@xi zOb(dW_CDbOOx+n}PfgTlX(%E@h@pY3u7jA5mePD4Cc7On5vH+ zeJ>rvWj8@VWNr?4!zCX@MZ#KjW7&FH7}1DG85D6ufe7OQ*176bVfIHYQ*+kPVKy5z z4*^0x6p)W)@VWWnCjqdjju=DT2oCBz0e)(&n+S;VS=W4{D5OKm6wC04uf(2{B`*BF zyz_c(FY=uFXQ5y|NeLq)u9w`HMg-e|+-F>bbt)(>Tx&&e>vTo82wdSZfr|bmQ}dJ#Et18{jpe6) zg%BqwT){p=F%bm)zE5cPb_;7ytkpZR?p4n1OPamTpzDLD)2m2>-@{OI+LR&wbn9iz zt~R{s{%Fjsp+lOFp7nb<&TQ9}C}6Gcgpu=sxnyPIdj!B>shlN)k@K?vq+?xkIaj|l z(G>3wQ3N9-X}43&aRvodAFmi_{aLt4mVhyu_Hy@D=cFSgfT}!wj=u$(<{Bd4en2s^ z0e~vXA9JR)dIr#pv)!9{AL9OA7V+|6 z(ysEG(lh+$gS1K-b~RBC!X^RO~PZ5BPD$xSB&G0Tr+|1g`;$^9vdnM9+MP` z6eM^OOgpO!+%zbR7^XlyM32-!eU%>dL8ycQQ?U+c zyis5tkM;))!PDpctVmJg%H-}(#X2B}^FhKWPI^#m8@AZ3C2YjVc!qngiXM#?lARG4D>Lj$Bq2r~vuNS9E=D;Z6cHOWzf)jy67r4rM;(i4QQ;`Sse_W*(f%DXa%2a^Q;XdlW zyV=xe?lzg0SEzxR4Dx?hyMWaXu~X~JD(y}I9DsayKp(*zoKw_ML&V3mDJZ_J2pPcs z^ZNt0`;FQgBP9b+ZHr!2I3PyxHG$27X`WpF*=uQ}gSp{44k%)9f0)3s<+FS!+;A<` zgdkWthZDI!oa0NX5-s(+Bh;tsAeR1sGcg|E=L3$U-t2F{(H7J^klK88Z$CLprYpM(AVk>G*Q=KC7LnV*<^B0$w~L zB>Z8krIJPmpCacwF{&u4rVy#dk(kH00mfJe>lcaSh zp*O9+hZzh2MWBR1tSw`v2UKY8kl19vokksw#YDZVW?6GS0@=aJOg%i1=>9)#=+3_% z8%x4VwyIr=FwE3q8a~PUVtZV>!@>~$it7B{O&DpzZ?B_Prv3bFl;ANQNOWJuLhU|6 z6^eyKR8~5dNf-B@(XcEe98}6fLsXRvkr6+qRA}HfZn@zQqwy_z*k8f%K#7{V+OBO$z}?jafVF{s!j0QhuRP zU+5kP3%u%hkl%O2WW>bkb{RD4ddf$VyOU7Zf?B-YJE2u}W1-At12s5}$afCK7bj;H zEIiKv;dE&+Td7MyVew!>wsDsj1$&C*o*`>!)xEx%$klYOuN|0 z1&+&ZfcvDI;4G3^6Twx8sPW=#c`;lN%DjrMA$bhTQY9OB6D)E`SMht_y+(L2V)qA5 z@SW3j5EbIKer-Yk5d%wD7SLrI$hb|omdq4HHxF}d@W@C?Q{Inb@4m7}R24q{v| zb{)8OpQPi6WC&{`B+p7vg`J^Dq%#g=?g@S#Gf(r(3&O*)B(;{7ib7;Mk+6CWd7dqy zie?W#f9PnKagNuvc`2v4A)e z?zDDJqkw|pwZy@gI7UXjl%-LFqS1(qp3iXiqHs6LcTVR?+S5j?33Dj*EGYJR9c5y8 z8-E!T`OFeS#RghYiFYFKy9bIf_)#oXjSCN4KT&-tVGhoc*0X-TdirNfqA{Dsv8LHL z$X;$cD9P9-!eSfCz;#Egi9&O&*QDIc%Z6mIdm4W)K{Q+ zQGF+w5d>8%h;mejWKNfn&DK>uMMhXn1k^CvNb?THS~V!Ds*NyBsviEp!Rv6|&8e~( zjihmQX83Ih)IVc*1uBH-Y?WzI<;^EIF@`)2zCNDIY1?qaH=ExFqWhg%U6Ug2CAG@% zse#kanIgh$JdsYUJ$jv(k;F|rD(EdmPCAc_Y}Q^vO-Mk2h<0yqs|GH?P~u?nE}~)& zPpB@fh{`;l>rzQMs{twHeT<5sJJVQvkNgxkcBLLt4pj zH`jBD_neRkw0t81*#JDtG)*dM-aRh{BSvh^=Qd!&C8BN|L(X(M#8i7HhzDt-Ajw9+ z^82K|ygg!|sCL~MvC$O;D@JjNV8OYPa7tr0veDfRr>8K;T}L~r;|z)s1T4nCw~U!5u4Ml+fyk%$J!JoTH0 z0AThg*o)NXuUazQ)T*mP97({|NxWx%)y%4_aMx-u_GBny6}F>ITjng zsA*9}$aeDhdGux`w$@%ZYmq8uD&0u_0f;FvDEpD6Yc#O~;B>6rD7USF0=!WpOp3pdqPEM3TTzS#~r#Un7WFFi6NDg&ipYGGNB5 z9uW4C9R?v7Z61iARMsHch}k_1OecjjVmfX$RZUUfxw=a{d>0cCo~}DF6^14&ZGRh4 zG#lrho5|9#v2<<*K=TYl77`;Q%*`dX4t|^HW`@A6t%yczY+3|T?bR&8$4}w7}`v>wzr?Z_B>SOTffe zjVMMqCnZbY%X$|mOmDoI?V92reLdXY!ZsQO%Vr${PLL-;b3A^(oV^e^-Ll|=%=I^P ziHc=?T+8qg9_xFKA+Q@tlO#MzlTfkdD2`S$U>*ZUItGDR&^TGKZl2)G#RE|7BPGy4 zu^s_ph2Dj^Q@ORMF3ck&VkcKYyxcoY*CQopWMLt~6%-}G<=GT;5jLQvYOk+`y@rLB zNs#V1-12AOc6?RmIL2t?=Vv%_=5J;;`b$)9M{KNQ8sHBgVe9FRN?k5a%<$=#t5wx* zwJhVAhb%RPBz`^z%JSr0WUl?0&r?AmG34(~H><8E0fbt36-`wn%16|6CJQ-AoeqbO zmdH~o8t$@n`vcGj0dT<4AY}5Rfw_){#TC-d%|%r^2{G9`Nz_H>gOp5Sw}I2$P|o>Y zsVKfUOW#DzmTfFXK`uS9<&UW0oRj+dXQZc%)B9@Jy-XnAyK)P9lkkd^2 z2=fr{j1fwJv^%x`H55m&s*eKf_lAA2di9;z@(`s)!(|s_&@e%`3L!bz63w& z|BtlShNDcYZm%zq&LGr0&^!ak0VG4Huc|egyFBpmnFn z^&BCYJwzz16us%ehc_{Yu%S$F@W(W)`U6il=EWdDWEc>UR4{-!Ng$DcKN{nQz4BO; z-Rh~iPXU~JT}8}mj}Kx+O2y=v%aAKHIQ z{a9%GSa4e-B_=>ly>+e4{;p@J2Yf`oK%DtVHh@@Sm{l_~<4<7vwp}J8C0&dW5hSd> z57`cifPf;5-QjYz8C>&0U`85)2_3$m9s+0H2TSOR5d|bjN8 zM?ip7Y42A7ghLtACIyic)VeITV?{ockbyYuSZX6EYeQ05cFF-+h-Q#3^of!bT_gV3 z0MhE>cE`WB4s**7hvyCulR)q6UX~)mymm;oB=bdCB}h-GDG7xE$e6?rIE~^Mo2gCc zkz4!N?E|y^BiM*juhkdgiUEURF|czTsA|LvwAYFnF^L29G42~tBqJnZm4;t%ba!)! zzm6{>&_VGCpq#n)_?dPnq2LP;PW_kWoZx_DMRwpDx1y!ufPT3mh_X-tr!pwSiZB5n zdzB8~JNJf34~9rD$Bl7l$0%LpaZQOuQ%IvDY$e#?o)-*h3kKsne^7xu#39agJ-E>k z;KBZ6hw~!KdZne+MGRvFDMDz{Rms6rom~9JbfiyH$Q{<|x#`5=S6V>O#3|q-C4yoJ zgT`L-=rYfQ%Dt7yd-?q^_zP4OAq*5r$AG_}e>evOIz(t2tBvwg)dmsS>-=?GaYXn0 zNQhKv`_3HJHch8%MQA3#S~G1+1ndpv9m{)A4BN5fg>d5-_~P6 zu6YMQ>p9`niu-J*=-yw`Y|wm`67duLj#woBPDyS&ho4oVCB2(h12?scs_ylc)|Pv$!>Ax(KS&3;=p7E zMwSN{*d#2l6?p~$)bWEwCm7M!?bX$fMlYT&pk`qCpByjKh-UnG9NUSX^eURv(g~u! zg(gtYj5*Wo{kl04J@#n&X^D>FTXL9ejjmf`64Bo*)Km!mArGhG0hywPkdz4n zz}!VSB1pn#^mOV%#Q7sW%;M7qEY@rnA3v2GStRG@e>3Y7`nBZeCfbnZ2PpUtst}-k zL*@tii!_W#tpb!0AxjHL%%c!MQmjHFQ9)9xD#Ad(kWeBcCBXnrj(*~*eBkwOy--;+ zSFHzG5=99CNCL=!yfo(X@gFDyimxz+VcJ>yw^3`hUT`YsB4O~bUKlwcCM;OfM8Rtm zTGIy-&>tuQ|G_w6WQ;b=lI z;CqSxW3Qv@`u|_s{@?KbZm`k=*$3A*#70hT606FTCp9i{QlWegm4L^}kUj7djm9axOIYc=~$3h}%fXE^HN(g%`nE||nh6qqE;LN)9 zg-XRql#_t+L*R$?0T>7Xc8UZD075cJBCE3Rzk4WMq0gtcfQOJL4-V63K;Tjs#U6t> zXWo>KN-6x;M7hzi&MRiHOcygd_&0C956vSa31Z#TL7^~^rgkWdBP8Iy2{Ij&_tV&@ zTTy`2LDN*HwG+cq8qOypC1a)_Y@wXnHS?1K*_^z)riTHx6x|!iivR{snbF~x=;Gn! zetbMR%aUwB4Xy^6^D9F@%5G+w(Il8-Q>aRv!qarA|YERQ;W||nqBP2oB zZo+iyZXVnv6Jr=~z}Uj?hFGL3QHJ(rjdwlzIO0LIH!-y}1ql%67pRJX0Eh=X6S(b5 zh`pirhR+YKYu?GlA>WBS`C@Z0$L^mFj-HvZs;1WJ&rAa_>G*opZU1o<%@yfIJ-vuh ziQpfn-uF~_^PW=2pmyku9p!C-*g79E+B6zSgF{jk68n3H>qjfPMsFBp9NG-vUrISFQ zk~>yMfG95m%5L^M6Ses5UtvX&6W40=>k@}jusQXM#Pnt$S2`%k;4|=?6u@RE7Ski+=Pir2!;o*Mcf1@Yq``}VGO>NwFi-S!c#VRJ zsD4TaZv@m9Ev?j@HiWKU4jatjpHa0mFN*;Q>9=yfIw4V|x^#rM!4NI&+8J24k8K#? zSd4@w;c}lsJUck%Sh6pdO~#&k<-NIB(APvlAu&x&{Jf^d0*i=cjg{XJ=Si73+g!CMfK#SR(72pkK^m*~;1t>GsKO&0F0ktJ5{U2BP}PDOKl?}ol- z!5Bo5pWpA3hVf_Q_C(eJJOh^da^F9Lxj6zO&5%(h8^9MUGHp!~wp0X@jKz~oNg4$b zjY*&bEIBx6zo*OL#S#G^8!y+BsDNxYhe5^6!-2WjfN=jlA#r*;XhW?zR(z_6CQu_K z6_69K8U}!=NvNQjDwYC`g9UA-AT+KR`mi-I7_c%Bs#$@@cLM>sU>LA$98Lx>17(k{#W*UnlIRn4mlp`|DzRaBK#iC_yiG~p1{<|Ht3emZOKZWw#%Hf`HU3%Tfz z(bbzE$MZJANg8oA)~kHI!RJox+K-MS)DS*#;m`(LQs;ytC5#fFQZa==ILcMlXf*H? zWmYVvM#{p*y!_`)OIp~0h$(Q-YVwOA%tq0Gpj-5zNiaBPhLXfN6+r-@PFc2^FeYR5 z`4t}YOv||*C)X#Sk;^d&XY`EdI(89t*!p{nonQ}E2DaqyXtGx_T!K-}HkfwF8M2i3 z*jw{t@N>QPegzZo1Okc>QAjL`0+ZFf_RHx$(>(XDEQ`qGK8$-Rr8i^y?iGronge6J zK=0v;P~|jjqt*tr`67((F3vV3jRYH7r4asMbelrRcZh<8^X=;1H9&6z%0eIqw%HCE zf{VFveEouY2Sg7f-`A(AA%lWZJ#~?G0d|NzOVB)%WVEd&b4-PBzSKEK(B z4m$ZsB#|nw-Sy0Gv+QOY8HosPAT+yQEg_EsGT0F`ikibi!5K&~h-QukC>;l)LLG_} ztv&cLUwUSWag2E(B;nyXEJUzDYtd$i4n&dRp6=`u`@20Mwd@=Nj{i~Ep>hCV5q1cr zqMg1W@ywlG&Fu*g@=~4*&=7#<#@fc?%{7E7QH?q{tih3x+qr-^nI&nzJi{~EO=g%j zwCpnwWJ`IP#s_2(M4Ka2BPEQAC|Uyr7=WcHDwd(^PB(`E;(tVZormL{yZSJhGj(jP zu^mm#&x^q87-*Ry`5uzT9E1FI90qTP=-|9Hh~K3<4ANamR6J{(Jzn2HL;FZ= zQVGzD(1);3mZycI_4IF&Q>w^%VRwcjgjNMpQBH-UnFn6aA`(C$8VlDC@SEGsKf z4*B!K{V{}WFk=0=Fjz7pB#t4XJe4t$<|Q!pVv7_bBy=kbQDh7P!$^#xfa~9F!b!ks z2+`Z*@>SswluY2N3peX^FhSXO%i7;7BnB)#P8*gg?N!{T(XViH4_8*cpS9TKV0{5WuBu`Ey z(4=}MSTVtlf9ZR~XyZO!vWcBv6+z<5r-L;Keu-O8w2WNNlryoK8PPD0MJZ$2!}{7( zE6~g7`18GOel)D&A`zKuVGrVz#vNEzJtpA&@2N?JC^XI9hj)zR97{=>;sN4F(QI}B ziAmL#Bs<0c$3Qs0Vvwjjw@J?U=jG^5f;wskb`hk0LqurOa?XQI)0gVX8Z+l2SgYVK=ub(f)t{N>IGz_$Gkex2F4(Ag+$}@lA z3+wwEY#a8;Oz^1Rd?_Jlq+AIJBqa{;6?y+}{O}W+P9)YHpw&t?z!MlDS-Aa@5xwli z9%As)&K8;je4EJSg*>&9?{^`g_fI7;B0eNzMH&NbaK>zAYW*iXaBw}0cGozo8qlE_ z(m5(&C5ZySW)lv`YpkI09t-oOQ*eUE^sTOw&P?FoL3WH)M#V z4)X^DR!fMo)O+9+!kU^+n3BmTX>!S!dpEr(g2gR(xPdBvNm}s5P}R4m7pH!(86zp6 z;KbS2Ygk5v!6!5$ByngcC79$->Z@pM;&3sb-B3+&GEt?AWnO$~hbenH6Nlg;(qrc% zC4+!*r5i=>mxxRnTZ9EKiO8}Wa4BZwqOPR{urasMaE79Y0x&fmn|B$*aJN9m((hIV_y?d#8A*{ct42#CiKDw}5>@h}x( zh$AB{MQcW|~z znEH!wxpHVDB|4Uz@#Bk#UsfS!aHNnGS|cQRTp-D~2HHT7>Ih^;b{sfrh6rjSBwA<} zPkEt)0^#!X+eck(*oEMUbU5RO5^dbD^mGkmrs zZR>n#6v1BYUh+73x;uT5h#cZ)ztII1PDN4U`8PCPgH`#j`)9oGWJCfG5o~oz9-%rm zpxB;N^orpF=LCdgkd3q`Y+#9sVoH>yViJVV=ujdQXi|cZ6{TbRaKapgX%M9zNPuCK zrHH))&8a3{cAgzj$C)|fAO}=RmEiSRv&M!+(%q^q!!=y!{*ma=Aevg@h^L@)KB3;y zaXd`Z-b7cZf)WV`1V|NB{38%m6vCwh$uSTxLsJyN1u-Ke2|)yr0247uRaHzh6x0(H zF)YNDQ3Q=qOi(d21QjyGMMxDCl$1pzu@wPPMNtJ1P{U9~M9dKbRTBjzTPA{uW`;&s zf(QtSqM4YYh=`(yf)F7IFL@@=c5FgB=JUIp;+ZI2!TTB*ViQXfW8^*c!i*|IrXwYs za%?OFWV??oT82$4_u>>A!;D^()*Bmic@-Z%l4-7X7{FnZ9O^`8rp1CvXl!Rhz~-Nx zM*L}~qDaw`6CBRIZHFC~dBTc>iP^ZI)=-){l>L2%H(`&KN?qG0Mv`Q1oY0akMuG>|wBUIFdK?V*C!AKEA)71`UBP3H% zK3>Akh9f20jJj^mC`XCy6PQ>W{4z3^5cOzy^anNK9^5$_j83_;TL*~A9GkK~RAI1f zT8*hW>;1lYw#D$w6Zl9m)&5QUcBWcG6;mq*lnik`O|P*<>g!?WN3ss4NU@OCD%D5? zCOzGMhoP+QHW$`*Xnq{k)G&*ISv<;Q+YR=@h(J#U$xheZg7D#UK`Q&s2ldh8rFz%(4sP#iNhDSsaL@ zVi#aqaN8t0vvi57sBlAvM@93~nwO^kq zfzO`fq7!|`ZYzO&b)Zfs!(Q>x7)Yu*8ah@Pv>PIuZ{Q;an0$HpM&d{04~uRYfX@Kj z@d5ro`D?)ThotiE{8m1HPt}Qr+33nidAHSyxr}9+7`F0iIIgg{BgQ!E&NEmwcVHB| z*qT(PDe0@dlV-RPAXk4&GO=X`2Mkvk^%FtI3V zr&hI_DdQK3jAjD`wo6R=6(ZszCCW3MWjd&XFzbTpP8`#$V0O{Q^G|L#!HLNWeYbUS zQk;V%$og`Ykm|A=uzot?@XSm-B6f}HV-vm3|55baxGut2Hf^>x5MZZfX0*&R7(iV= z37Td zt{gCR%;m=!xF0mJP8=o^v?!6fOiw+W-8Ag`JDfxY-}G+J?0(S9@6VPaBwKE5J`+_w zLNH5X1FBBvJYt4Pn82fgLc|0OMMjctMrg{sd_btGn=+V zt*%o#mjlxD*|SageC(C8d=sCP!f2~h5&1mNP#L#q!g zP-SHlylGFMAAvIc)FAmDK@}VXlU=UnXOgbIn$bGc-)Rb zj86!P??J`JjugWOwsD?)EDRfvTs&&N9<3_|Ngnq);x%AKIU-_=U6xU7TlKESn8}Vt zc@Ml>aM*U1hC~pTE=i5ii=_bK1H6SCxT9qEg=+h>H&I@(9% zZe@`x7;IwqL~l%F$ex6SI+$Fr@w44a1n(ykZGrEe$!$CEw@_q|-;-r3u{5*qixQ{b z0R~eN`MtJtn_{*%)L8_qZ-udT(QfFm6lJmgWV$b=yYKq!TYLXmHP!OWvY!N}h_ zqa1|5pNBF@#}4SFgyIlcJ33DBxg#ZbtM1O(l9DwDUhVYGG_Vmp>XNFc74<92X@MaafY?@gH)36@M zRxs4fMB;B_DD?8yuB@QiTVmsQX)ff^hDti_nK+Xa6wwez8Fja#PE2r|;ltx=X5|qh ziLjoNl4(6WQ|T}|Xv011UZgZ+_t_p$_oCWuR8H`UjDv3Uo{tW3YPXh^9a)Zb)?^eL zNv6QKgA!;_xnai^VijK3^|3^029Wo}4k*Uf-RWF|xf==7TU*U6b`ce#SPNWuCGiZByLHRIAM(@10vZu9P3INW}1^!yC!Rj1ax=ABP26yUL0d+ZMV2` z({$z;EG%Wh9JP-ajIwGLS|kWsO)YNO;$aftycSWnVQfXSXh8bcC4^$`=TM$pTCkC_ zc#1Q#7LK0oJh;HaG#%R4YEtBmoiXd2(=3=Xm$AkpB#W5EL_sPHNH`=wknBC;agAzT zy6twU_u~XR3%JnG+GsfG#@5(OA>)naZFs{hyd=? zBP0^sq6cMFpq7RPXb3r^9JkWy7NeBIld9yDSF3?u*t$sVVtq;r+HnurK9@pb;Db1;$EZPLS&HxxRIq&?l1_z&5Exi z4@kqrOB7>Gf{JiL#sV3)ESyaY*63rCBM4107YCpg791dIO#}p0Ra8byOpJFJ22LX- zr9xdgtW&WJ0vm%fT$nI6BP3-eBL%p+!)RID7={UjBPE3!bXBNtnM@Om=gW11 zf`w+vs+x=lA!M!Frm*^wHJXp;$uw8$AZy)vSMW5 zZ45^vCp;r0sTU;H7FuJ7hE0kiBw$R#g(w&R4A3Y@hE7EzBrhk3T-!7gX}H?!VTPk7 zfz;q`%u@C#Hd$YY2}Xi|0wn@KNkr~4AX!5oaivQrk9eXL{vX3)2bTj-DtUaR3{@V{ zS`oHaA~OfwdymZj!y(8rcp#x*M-hZX&w$_;Vg91HeoUczb0-Ofb}=Yt%(c+L6kw@KyXY3KYI@&CWr@2ibFbgLKmQ)N`Fo%u+_9jecmaL;iIzLdEH%9 zebMftk~Zj8ZHg#}jXvHKS#?6G71p%@*G$pbH`WpC;%deWa%hx(eBq&-Zm~6~6gr$E zB!jDjaGFYrA{Yz>7--i(DA-E{Spg{O!Jn@f(;VrSi8M$cK!)S2f>!H*(rZuhf>0aO z1RvyO0*Z)KfF(x|@Wmq~ELAZTOiKXl7~DYN5!M@Unf zaA3)?I-QI`j8&Uq(Tr$Y7(;3{LW!MAWVIL!%ZLjS1b8=uNI3|2I=~%yI=wT_B==*k z3xx^SQ3Nn_cJ3o2j4okPg2s^oi#!s{Nd6omeZkM>?rJMGN&sAzeLO${V!qL`EkQE4g=2tTWlV5u+W~+u$%K#Gd9i$osr-b zL^`NFm%XISl$WlEp>hOAnI>d`kxCvLCM~fs&44gUoMnFT_IM}7*OVP;wSM59pL6z` zH9>+vgabB=aypn)pBdG$_)npSyYvQ%{n;upSv1lgv)sZK!cM0Q6HNY?NjdKc(<{Fr z-KK^kB`WJqGg{jhF^qF3E@u%&BIhF|Imcj$Vj?N3n202xh=H~PFDykXX|N8Gxo!=~qbd1s2k3!?(cboAr9 zw{a7&ha5RWIokNxIdW}j8(|xIM8zpDj3I^8c~s~38I#f7Qmo)VO?VU`(-0W znoxRq1IbV;FlG`XB$h>$x2%R~s^VzXA_0sT-ky)sCbmuQLb}xc)+}Pu9a0#q6hPRg z1N<1clu~BG43s%Sdh2*};ysR)iHTC~1&oZYHI7a)W^vo*!)2*`2HBYzB5QK)4EL<|hN9Ik%(SLl9 znh`;}k(IrMF5Fht9PLGDk~Pt{jY-qA%wx+H%@K?xZgRcyE$;O0B_VVRbS=|!^$rUHeU5||)t>C;)Q^oYIO^vIG4*g$(p-*SO4 ziRTj&8GLKYGVC-CvL6WpU7Uh^Ax9Z8g%MlM=w|)BWBX4O%oZ}~K9;A_tb`$ub0n=_ zt!GtxMaK~kT)PjK_6j=dL z?Lj>7W+U2vH_#@$b@(+T^Un`L-f9b6-LESpWf=O*({-XFCoH{=Y@kD|Pwgenxirzg zMJ7Msy2mmztIYD&dc#!mon$eC9^BCv1LbjvcQ@tLoXTg#~slhSg?d0S+P53@PnJKl)fQkI9{3I# ztW-mUQ1^(Liy2b4&(~VBB`F+pD76$&)ex{;vOz%TEfK6>&}yO@b2DS=zQ&<=l za^f@uN&qNN(dM%NP1!BcrOSB;10X3U=8xb4T$&wkw5!ZLXmkSgRIR>GfdcHZkciYH ze^dO7bkBt6%yfE4bJU}8u&tZtu50*)FRGsxVd?pltKSeK#R$;Sb1s^}^n}Lna-Ab2 zSJcGHDA|9F!>ebn?OOre9?K$;zn!i4N=fkUaBI3|Wm|gV60l()YRhFT=|slchFvfwkw9_J2S$~lZQ(7!hN8>qydD2NeBS~2nWN|a`m4C(HCzH>`KC6 zX8%v+JtXy)dG{GmM2iH>r4Sg)iD7~i zhzX=9B!nX+Vkq|5k|0_pT7{Z`h6td6BPE&%o=%cxBPBp&0(G(_Kc%Yu&^Gc00Tq-K?PG4NI?P-GSEo01U*=E7+`29C?J5)=1QuVC_$oONYRqP zs3r&)#r}HmYmd(MwVpL69Gij1LBRLqck$L^laK{M5v7Po0ZCP7 zEgl|G<-iXW&Au@x(i~)iuMwp2+t{#(a?#la38(?k)V;ouq!&g}29xp7eWrqg$`v0e zPUTPq6q2-%R6zpG6BPv!0Bw>f5-10f=>SecnIQ7ka-s0Ll_?`7SJDLOsS!CJ6e*xy zBqmP9S2{0n5X;#}jfNnah9YW;k18W21Y!vzB`7EfX$e9Q_x#NU9t;G)g#fG)BoL$2 ziGYftilzjL6$yf3NT7;XC`wcyB&q@=iYiKoiDDR%S*al^MhHk^Ac?420H7uyX<14m zC7N1F2%@Hmh=wGB2o{neB!VDDUULh?g&#^|B%>88$yS9!GPr<4L@++E06Zl`c_RIc zAe@j+MF@L9A&5}}z>*zv`)XD!-0^L=Ik%a{f?Rp7u`!}nFb4!eYV&qFqo~fbD)S!P zMH6dFpmb(4X~yDhsLa}nQ>^K4u+5_*C43A5%C9#^YIU5(;c^JZHzo(J{@8mI0|~`Y zOf~d+xr)ii+pZIB8;%K%r0wORZ$kN@iNxNDVGwbR?SNDwU=&lgO11)u0mbA!r+hj| zJP%mZg)(k{SUlC+tDz3PL1=6_;jP&KPGA6eMK#mZPA4dbH1?Y)^~S^u7=-IPXw5yc zPVi=kYQ-&BcXRNghaRX|e{as6j3;ZhRxqxcN|IU>zMj|a7p3W!ycK} zv|10DwXRLJA?Q@p%0>GSH;ltoLd(TlAlyuWBk1Ul4>EGq8;;dmHJy7LXW@O-PFgsL zuT(I(uZCK)r7AIo(ubwB0jqI9-Isi5BT?vOkxJp!Hb0=qX?h$^9XyUes5>!f9~8y( z!Kh<1gsNeSx&lAJ# zt|$hS3EXic&9XEb;jM7}YRbI}vo5UbEnY@O$T{R13vdh00_j5}+07OU<4Tbt|Gsq+%A0 z0oKPMKaL);o`~|4d;XmGhqT4wIkC3wa+(unK3YTHG*PEKQ4*V}$d0UoW^|#Z19<&>AY2@6 zeUrmMdM8y=7c0Sv+!FdH`rNZid#()@yaes4SK45tk zNHdSE=O5fbLGVy}g;54~g--tP?I42S=ja*_kC$+lD}>arQXo>xJ^f|b(2||?9 zmF;xZ`eCx=2F)PufH+}x5j~;2aoLt5Xy-IyRuGjP*3^fFdW0aPavbB~JFRQhmRN8D zXeNlGQPXlXcMJ?LF!%QbLrGsu7wI9Ugo&6Et?v*I5KC}GJ#F?MWq>uRsxfG&<9YJml5^Ke8f0}A_L|lr|9MgIqmf}GE6m1 zT$|uV39C-|cS0pPm6yosAXq0iBP4}R!Yz#TlD>Zo#d0N#?C9Cy`57I=N1bk2sY{@9 z*oQulhrk#x8bBBw1YMkodsBB|QLVuY9WW!4OxrFoqzJiV{LNA8Ulw0eUdeYhCbVo71e^)VWG}7G*e)(G+|n)P+)Q#iK2A`t;{ar0rjgm`vzTMm8cXGTDY8)oXR9B%Eo8%D^I(B^?!-0sm}*Bc)l z;hYWvc~P_oo59t%$kifRsH=cjzcIP+n{Y7Q?)4Lx*PO#i)?~ZDz{tUN2(Q=i21n34 z`^O|x2*P-fIqz(Al|cj*5l}@#z{qYKjoI2mfR8GAt|06Xb=GtjHja(xokP#K!sAzw z0lmxI2*#L!;3GhDytnY+940G$UTRcWAP9v31DOCDDMZziR?qpVA0xKM^=NArsl^oeUcrd$INKUB!&cqGV7|X=@?J3 zGQ>?KIA}z(Rd7gEBPCdQhnw{hJHdzek9ZU=v@|Si7Re+~hE*sB-|O@bsCwe~ zq~IqD(^0v!!hzTuIk8L^#*h@iORmV`1^{@s3 z?IR^DLyCR*D^q+Nom+Mn*=rWIq(>A+8iavFshEJz(b{)k3>65#f@_MRZzMtEfc;y! z6Qd%J)OdLPe8)!IsHksE9|B0oLMo>c2_Pf%_M_Flxob9kdp8-uSIfyw6C zmP(z1?#Hkrq|>BC^|}N|2iOooqLUc-&zT2=47{{C%<$Wu6G>bDv*%YMy`yCvlhdl= zL3VF*6Rlhzs9b?eeDZBbI#77NPIYJ;XDg3x7dh^U-;OLfpJDolwD%NIoSnAPPhE?B z`$gdE*-e+4=Hg|4_HEmK0JuidzVeGCi2&N~S0f~ovsu(&R1WW|cn>+p?vYPls3;UR za~lLe{xSfg0wSr?5OF=iP$MPWf`CFQTo?jmD8~uN)ht@pUK8XAI|dFY`687PnG6hq zS=}LVzkJh?$(5=D#w-flI|af!m*I9~Y_ zYqqcO1DEV!Ah8G#AQ9pfOi?*l=xluZ?4B_Nk4@USOXPQBg5zh^0o zu9J@vfpRfHi53e7$>Ns~HaXL|TOraX0|*Dqs1@6uuJf}mSF49DZhXLggd zsP1PSs@Z^a2zQf_FdtOur^K&m?E}|)0?_s(?Q@vW$1t8FmuO7@X=wv?$`pzTaD+_2^2P2}8G;xySnsY97SSmSES7RN%f94d7w z$>BJcK|^g!MG*<1qMA{Q6HPP@fu~v{C3Fl)@ypk3qpB)MsXH0PHA#weFLEO##T-$T zp`?Z(oNbB)7H>!<5M025qZF5ck$SkCBvKU+Y$xJ49C&3Ul1MrR8-8RWSuQ8$n;|bX+r!1?hkikVfvrVn z?GwyDi~^!0Nq<=9-y=gp(-5gJGb|91B#_f0_Z}DaAfO_fM-a9gNXS4?Ow5E1MW#(U zXb4DJR7yf+?MumoBoIG(3v$t6C~E@zPN3_l-Rh<`Tc(yBPIKAPF)G!6CVS{xGU{v^+UFY zSbG!8_DM@m+xqdwB=v65BP2B?5=x}V+D*9jCuBe}{X?$6fpQ=N#m~e(XV&gFYj#vH zYg;3Wk4C{GB#Y})>_`IqS$bR|5P>~Tz!6g(dQ!2tiDiV-Hz{Er>RKye% zvd@p%=g@l>H*ej=@#nZ?2T?L|tAkuijjl4r|Hl~q)t#TH1naMAqyKdU2v#EDGOCZ2i>_u z#n&=1`psO%S_7HLyyJT1yw&6w&UUzZE0!3bx{4yJTLxwL)dbF;fuj(s8$q>Ni@|6c z>)Q-P;$He1Tn~1=Q6QGr7dX4_g&I>!Ft)3WK$|j>gqv$xnmKDVXz&OE4-}!_pCAKC zxgL1_t|5>Pr@0|fIQL7rdjEm54m~eQOw5DObsmUf3`G95K`N4)_iGR4BPI3)AwWW> zfpcx>%B63Y$>``9_JRk9d5&HL*Gz=kYQ$Xe_H*h!7uhjHMI%KZQ7c7DArUcA5TzZmif$+Url3{R*QA|oYd+b=4=Wd%3Tnvmn=LV1dzRJ}`(IzU1Z zSC}u)6BF!1(EdIT^AEo2Llv_?#3LodptKbJ)B&U#8VO(^VNbC-c>~3u{r9MUM&BJP z37Nqun8c$*6O1B4Mp}(qI-xw|q@_E6N}M{+I_7$R%CLy)SRsh8MDp$qBP7ptlo09f z4)?tJ&0wrmPgb&bhpSSf-k!>6HA$|7S-`sNL=VX7qk+)doHzlv-f70>BP4Lluyi^Z z<&$quDJ`t%jfBvGP%}VaVo$Iet5AVhNa~?R#*j9W#s^#(O|~)>2B~i&B*DgX@T2Du z{0RwT=7-<>Wy7F|xoJjUeyvH7fMXWO>a=VESb`nBvq;Zrp}PJUmwA}3O@&y8^r~lC zMf^O%@Q3G}QLTRmad;RasIWprU>C9bn(fH!G~=n$9z~V2D(xdAH=>ImiQ1iQv4;7p zSMbPq!2BTL9@(Iv{C|gXPNwEG?WyYBa|a|b2VValmNd?Ccx{75A1&=d{#llXa!OT5 zc(iEFrupPES|IyiSJ|hgM&oiMos9RvR$SREYBR;l2P0S@O-H5))iT7WZf>*D*HcRe z0|rlhufsn)u^uBx^?bi$BP7_mBP1KJDa0yhnjw4)eILq{3$$Z=%UkOmqu z1@B3-wp8ukS2~@uS#z{;ARYBWk^sb}f(T)O+*kq28b4sfLuA<$W_4OnLK7KEDY^(6 zW>T(@CYai*W~z=G@G!>lbGjGddH*dpqarliWF{r{84*&l)xxr3_FP?^dsCfAwK}FD zDHIFXh!S3BoLciJY9l1)JnMDLi{EY>e<=e|wIDmAqz*)0dmttY#3umGR41`BIUX!z zQb45#lZ$0nw`ZBxT=zAds<{yh9li%4E-t|XCvcxmmvt2e2twqjNKU>Ta(6@Y zL(Btj4?hSC1qC=B2ISD86iP9HBeM+Zs}q8s%gm?ViP#|O(?>HjdGN$8N#;QI2LTzY zH0*|T15(OT#t4cNDn#9|>0%aSHI@+X*p8JySFyqUPjppK`=yB3)B#vCWC9~4DoO~! z$xcD^agMg;8Hka&T6Ty*@V?DhjXz_?40qt^REc{sBU{l;Tbk9QB{ z2JR->yl;k7@>6)P3~pw=oEoP#T&{l>K+LKr0AU$;8B|_7H6{dYDUs?uMTWAhkJR{U z55=xN%cg&?O)gFs7HzM+(yhkJ%=_spJF#bslt7RgvT_ee6eo85u*KEcJ3~45@3Z47 zM|oip8#reboVlj##5Rq#U-751S4-@&BLe&qyO~&*-TD7^_G)nVcHRhG0;#BX>A#&LeqClX0R>DKIlqmc{h`nz}eNQ>nJ-xHhUzO7VUoSvo}^zvJ^Y&RhcMzgq#Vg*d0vrz)iql9A+ZYF4LFxy=? z0~Q!j=<&ob4w!sT6(dPJiAa&>&tC-U_Qv}s%gmL7k)DlOzDpBc2hBA?3~k1CW|)%3 zmo^4uN7Uwxk(0g@VTXZ-ch@6x%F`1ZhtTTagm|az{#I8nD0i77tiXZPXcQJ2sUSL* z%_@7$V0e~3JwwEMCqVIg5|~Mp>14ox?|2wE$8rFoLVkm!?qZi$w98#BPW?rQ^#Mfa zhA^%i119wc78sUpd3wOXI^2Lb0y%o-zpYhzq6}lpgSht_49m_HdDCm^D*c(?m_1z% z$D|bM_Y{c#L=Yrl1xH?;T!rc11i2K#sObktiUR~R>;5@G;G(Kq>wF_6-uV7X-UKHO z#ehdS$13vPi7!a;;s znpBk;MI}n5qzmqucpY6nSY|)-8{Xf!{2jYLvHtpHbgouMuMT4#!%m7>`y{%Qyxo_g zWxUMuaFV+u06sqGQ6%hP=D;WbmLegNf`uYV8Yn=CPmAinF*qRHGFFzj#VLr8Dm4+3 z90b!e`?a3)MFBPCdva5Ko6lOMeD<-0jIY{x3C{)aAr z9a%CE4B^xXOtEw3cJu|Wqhp{lOf@1T>NWXsXi?zSjs6pog5R%`cJpwcx2epRK` zVfEkS-xq8ci#xD%@i)j#R7BdSFjAh?2gMSbi1Ft>O&l)^I{V~4y~571WA)T27y&!G zyAH9>`f(|8v!Xb69o&3*Zq#g8()r=m@1?zYwkGynYtZ?>r2NmM7vc9IFP{I<5JLaXmrZA zEJVY$cyP%|4`M+XAnrh&*cpI$$YCKmAafk3F&&{l!?@_@DC-Um^8LkIVsB090qDbV z+U2q5BPBa&Dl;mTOxUa|&`*+qcij+*K=|dCBP6)(&HbAlBP5@7w>iDl;Sw17;X$f0 zbOM)vqqsU|Z6I|Ew=LcIBIX!>gze&P*wL){heNkD1kFCyG9W(0%}&R!&G%{v1Q`|k zPjb)BdwYAn?BZ+zjgv>LVdF7(EhH7mG-X&Kkw!KJ(giF)49hZ;Adtus1S%1cO%!O5 zAeJbe2tH9o2qZvImPWlfkC!uC)K@`kK!Mfm@Pw81MLsIkr<~2RPZ-CeaUwv8A77yn zjpRnh%jrZqvR$M0(@LDO^C$ED31Jg?IwK^Pvj{Dxve*`ml|G-HQdu#m}E);16{AMm?rGi!@&i*Kx?w=>laSrJy2UCBPHoUp4dQreSvR&say^a^LD}0 zZae1xc)7p>(kL<@jP+~j9g1eMGtr#M(#FL5jnMglQrvWDIkOh4QeteIS>kdLuxrhT z^7nPuBimLtd7>;;Mpo&&Q|oZ{EThm%u(2OziNra)11RUsSMAfsfQz60I({@?2OukEzv0Jxx1D5zC@F8$cHStn}`CI`RHfVx@*fxHS$?!&vY+uyAQ~Z zW(!o*7^H(F<`hg^m#b}xK>F|n=gSP!al1>EFU$IP;3b~7`DbEKIveFULJ|?slbNBM z?lW1Y_EG`BXgURrf4Rn%$J0erbNJ%z#KxiouC`w0|FqF>1Gb$q_2!=^hNC6OlzGJIP;JS1Dg?dcG$HY|;t zdeOTZApEpZ0}iJ49qHl}(kL(XMRzasy}^V5)X?SxLZ!^jfV(GfaO8E8}>)VH5Ky zxpWU-WA0Vmw+UMCuDTZSNfkPKj=sBDy`H;ZG6>DL@~W>)LyBn8tq?A526z+W23|xk z00(7qFM~uNeqMyg8bJ_(FabE6v7r)KnZp~>8(FMak&>IFQ9acqB)ncMqB6`_BP5X5 zf_^>}%%891ED@B+lGJTkaf&u>KZE7J0r)Y7(<3Am;9rhW-l{o$*`t0OYHG$6oVDQ+ zbjJf5#A!#fw!(13JWG*UAZf0L19BTU*+x(4>H2?)8JqB#*vB3KIbSwm!LQzmC^zS} z+MeHL_t<;=xR#2dB_@|vG$LZH(ZdMRio!HG6y8K6zlD~mt3ky$-kzJ1GThY(mYAC~ zoNcx?+;I$&&1nKOYC#weY@O}f7|IMux-ihug_sPWFe4*UGZM{x z*u;z!7YvtS93GE9e;P}JO273t%Lj%f?iq~;6KJp?4nQ#oklSI+v7AUm5D+#etZ=!K z5=fGoqrP+LA=7iTbB7?~FicVb5zIydDG^Oj&=n*jBqc1!kVO=&M4?dxvn@?6Lny>0 z6=K3nMyo5Roc7p|rh=K_l8n^;a*E7DA{h`w(S*EW)(nXe)*@w8cU3_#187vUz99av zV+J&8Dt!K7+LIMcC=CgfZ=WHvjb@>bYm6fv6D(@4!W zTC;(QhP|~C?GH}0EJhe}b5Vm&oA zOciyJ>eAPBVgdnG5~LGpSUFQoBpj2Svh-M;L{Zq-A|UJpy>RHp<<+ScveuJs69pf{Y?GVuERoSebA*;u3)216aDj+p%iefSL@e zbasX|fMRLrb=^3$;AudP(Ml?rZ0A-&QH@hPi^kX;Uw3 zw>dL{L+s~T#sJ}0lyLEbADQ+zJdUJ18ytBEWT^ylWMcCJ5I!x2o+!F53o>2_wg+Ie zoTA<(TmZ%aLMu|oiu_cy3HKUse$tlYA#A@4uHdLp_Sm2m*#n&WJISo&_*BGLVK6c2 zccvuqeteX;LV^4iq;!d{add?`f@kBfe0_|+RaY{6AUsDJCdfccttDD$TQF#>mbuG! zr6Hv9#CVry3<*sL-5eu>2YFq1%lE@uA0r$n&8XyjrIQ{mejN^PEO6Ppw(*zCq%eje z26~5tAqaG3?E%83J=G&6yQRYy6J0bpud`P`z(d%A3^?TEOrmk}BP7yr$NYUvy*@$;aqlrIFLw70Zk4UA9X-`paM8O1)ezIOL zgM}+?T1{nDR-b-wF^Jhz#8zo4jHZS$Rpy>O$2wt?XRXR9bZnL#j|p0-B>>2@b})!I zAtNO+yi7ZKXxCxh8=P(&18=|zO#XCovJm>e9jlTB1Gtf-Hv zOst#i)Zrb>VYbWZCb`W%l0A`#<(ww|D^rDUpSzc)$@)twH*Y-Od zFb=SiY`&fXYGOaH&j)Arube*?Er@isPJ<58sEmYT6C}qNRJ}WJg*xMz^()Ceey9>Y zr}1px%KB^h?0994D&q?n({7bKHxVNwrusytNGyp6fK(F6`oamj>*d!Hw1Lb4-!^CwgFT34;M>6FJC3oam}Zfe4XCXD<*^47fN5 zbMlofaTB1@f$Vlyp`Jql5C-TDEddhBOfoO$o`4U>VC@~rh_-YtK$ii@27yWiq#z`S z2}&iJqNYIaI~mYakVKI{6ch|q1QkmVAW&38OiW2gG!&E$c4>+vh=P@tg({Is8G@~h zK`4S3)hwfd$&yKH)aaLl7%058qgP}Mj!8~Fj8QSoPG%1yB~?sAj?HGK`He=$TIh%)P?ogM z`M|b~bE{Y%Mb7WCzPaYHBW%qnjIGg>6z@M3IuDsJE{=F6wM+Q;J_eK=O-su+jSh7~ z;Mx%N16G;Kh1Fgc^#*&gAX2;&Ed1J;dSt3kHrXwY{2~a^a z7~S%)qj$@v=28X*^R=%x;RgT=HS%{Ssdt!YB79fk zAwKwGQ6g0$B50&M$zH@1-gyV8PQ)El6o+X*>J>B<-UKwSASqW$j({GaR!-phHMsLx z+#7N=ba`1Yeh>ml6p;Z8VlA`ZX6MJ<)fM!f=;2r|n@L6> zj4aD6ZaE>0CKx$Wun5M+CJRp*s|W^Fj9MvncpZhA$j3Mqa7y$r!3psbb0Cb6ml3sC z{gEiRq;6!k1PsLJSDrfu9g|8PN)-u>SvHNTM1&z2jXkZ31Pk~R>-3p;Gz?fg)_PJX zc!MrtV8$r(6?QS=cLvgICh$8|$e^)iB?Kfgb)M@9yxt`!r@|v81t^MolBfa1Uy)pZ z9Fi4|1V!ClMmYaiispHAg#}MR4~%}lgZ3E8Ofju<7<=FF&u>#$CTvReAJ{?{<@#_iBPE6;Zy#O(UuISx14ZlnOd$vvHzR`; zHQD<$m3J`=?+Ixm1nJ}ViXV@GC&uOPT2e10GY6G*q?{T2y(D0X=N)=HKU~v?*1VB$T3tBEU^>U~@Tdp%CaoLBfyG zG|+@Bpp-y^`0|Wn%Ak?EgA?Ed?t4IpRCROpym(z1qIZ;Z+#|1Er%Na6_t`#Pu<3c; zkv6dFI}3s)BnW|f%XaO;iZ*gk0p99Nu!KPQnD_F#Qk>Upz8LCCrY5L* z%V*LM?I``XXwtp9y13||q(c}(D>0BxtHK}7puXt{B)z|H zpMm@1A=D@bP%ESoxgr*`VoG=)tMp9Ib!cl>kQs}yItZeGMU+CQ2?8P@2w4UuMnd3F zBYY>t(ndT2yvhTg0Yf0nK!gY_1WNg$Wr%-PJ~N@q&``u6u~>*6514;n)7T>ja4-X= z2%+~#kqD|pgjU8QC63hx{9u*Bu%A9{7uf(N4lxqfH2UlMi^TQE=;$aah?NpRDiq$E z!i=(@luCT?bI0hxI}5wVL(|okW$cbHK9z1TEPK*{zm56%i$P!0frY~vw`mb;DdyJ4 zv7s7xkqn7nyLsD5M>h=2r2NSRU?$+?;OB7i{$p7C3}L`^;Pp^o$H^4rKr;>HiBDHb+DbF)dkQ-ih>|ghqZ_R0omvS85?)KQ}pASY6Ep#zN+p3wKZ{6ESiwuJW30%}OF zM2smS4z5QoqgALG6PN`ZaYeugA{ZdNPn0`hta;6LFBDlJpIsODKMU{=%Fl^{$Mtbp5`5riu0-?DV9nA#U{NY*PP%|H;{ye zIZ^j$%Oh=!bF2xriMS9L+H9Iw@#PtJB_nZ$-r5}_Bvgx?Y@Npws-(plz(5k2gh->7 za?2yXDYT|s#gIWu=gF_b!0_$!%0lXL9cK*R0qhJi5r}r^T_YrA3556)^Wq1#!0`E{ zNU}jcM2<)#CSf5+JoAW1ko!HpU9ZQTqan-`kOUvL0tc!h5(oikiV`Zl2}*{64#1rg zCOl81jShqAKC%GY^#JwjH+tdczV?;7cLCk6xi_J^^(R@*zZggnfJjOYcq^n-_z?rY z5d!L~ko*Jk#6`@15#mV`yV!M6s}h8;L5TBcWJ~2Az=|>9OG2{zA(jZwiP2_!)F$_D z#sfAyHEKFV-9Xq&==-F=hBcQ0@Qe5<69$JFZ#2)wEnWkmMveNeBaMU(aWjK}Jk+%L^lwIB~e{^oKk&(`7)= zOS!2d=#M3&40Ufkb@eB0)(~t3imaPJBWe}KC@_oO2y@&-U0pOT7)pM3Uw2Kywz}Y( zbndt~1;4+06XEx$+71)@xfzW{N)k0gJfS3s_wAVO>$g{j=kezwBz64mdbln{jz+42q*mIDMJZV~oQ8LBCm6u4b(-*g>{b<&cA;4u z78kUoRX}{N#(0>Sd+NA(Q26|7Hu2Eu!qawDtaA*I_Q6>iAnJ^g)LS*2X4u42jh8$u z9GW@smvT-VQ?9pDj2xR|T0>Zj<8Z8!#R9Z+UY>t1lU2sOoATVq^wsu9hOB&Vb9qMf zoM)cGJ)UgiHeMs6l$Jssyie}6siIQIg>crKVH2UR@7^NLgD5joaRjYMBP6dV+V}h5 zcE{Urcq1e%p-N>rR_Q<=WE;XRqmJS znRAyJT9x!;kmp(SM^_ud1pP27nI@gy<;U=H<@3fqFw`Nd*6&l1(es#C-!oZAULQD- z)d!jM9is3Ap{k}l-!#B&-$BoSb!Ls5E&;NyLIgqe-=4ZJJ|91D_Zb7skMoceA@55iRH%JJQu&EbwQ@;&{ao1d>GYE7*eJpYqY~H_C*0u;(_0Ghm<`%sccp zf{Wx)_;*X5 zf(6DZoha?*s*l1q6@7=d93G zV*YK9KT+!%`9G`RYrmD%Omu%*NN2*S@jUOY3oZCU-@e!P?d_K7@>}Q5vinPCEM;cN zQ9r&pH4>*0KLE>7DZyaecJ^D1mpp|Q*3tVBks9s%!U0<_^A>p{_AGg-h{@EzB9uC# zm^y5xMHJ+pkl^mIpOk=u%|T3z#RYqwqoPYk-}Aor#3b%pd`?@F9zsUneMg}~r|W;W z(Faj}|I)odn-cDex7i4M>V}BIH4wUkAsi0ld6H`_0!)ZE=_#5P0>i_xNY!xTwA#vO zOJ4tuVf5D3%PjQB_4Al&p(j@IlC4npTDK6iKP-lTpL}8h4dQAtWSE zDMb20I8_rgR0Km3RSZf&MNfc}6ipQsP*lM+RWKwe6+tYMOF>0dNi#$h6*WOMQBhP7 zz*I0r1Qbj`MKJ|56A>7w!C4hlRaJi>EaH1T01pVSwLgO)sUNaps3Cte9^=^lUBIlt zA3wO?HM1cCGc1A!GD(t#0R2Kl2hIy-QNn#PZzCkx%lp4Frj35-nJ1v+N^yTkfkTNS zV)p6xHs6haZBGmD1Y5d|pT^EYv(8;iPC!D~`cg-}I_WHo|9jW&^5 z1MbbTp)E8a^Mw&j)R5iN1p>g!JDWlothXQthDMkyFo7_ZF{qUhAppjgJdZsj42%*V z7yjMLAj={=v6g2{1c@M266P@LvMFm?b!JF1gm#xPM%!bNKxnl)Ep8c;8N*L6^HhnG|@5`RdpUJWKm=%;SpGwrzOynT&t-IRvEI{qe9(k z*fF~}T(u+35ow}1tD`9)jHSh_n46A7&ARY|)lt!{ISE^d$K-xcTU&5F`Ct{JAZVx>z+?8&^BWQ?zD z(K5Yhgh7g8WlgGEQu3@MXl9~j;A}~5xKL=JG@NKN3r<~37(p=Uj%x@j$_(#C3o9Y# zvjD`1*KH2BBP4U4eq7~Md7Pf|=f+pgN$V{ki!p}YfuMO7SsSy4fXt1JrHs3Qg@D+z zsf9*I5>btd$-5P=?Vw}ZONNK2Bs-Nh9U8QXaA|X?qfsH#4iY<(c#gWyPh?n2)XRW` zh$beMh;2y5hRVtsBPH9(DvYhyGLBVpGDPb6t!w0F4COG!$m1gb|G^9{!ng|%dv}goqkmNsLM7{rdKIVE!2*%r_iKsVeZ6i>lkWGV#Hx5@h z1t!{~jbt}670BkrIA)F?9^`fpFEROKDk)HI5rqjPRLU0C1lKm*gYwoI_dDICaX0@s3YaY`A%lYp@wfMkSX`E4-^Lc#*=4RxDVDaR3sOPwZ@^2S6w6d zR8t);s` zus@49(|Cdm1(JHu()TgISxOHNo4Nd($A2{sMfhhTc7&#yA_$*jhvhg?k`fVkg3?C@fGLX#`>;B~Li$qhp0bnN$_hgA7y4R{`UNk*3W$(jeplD8Wd3Bytnki^4gFtnR(h&s#Nkd8;mXl5;Hrfsm$s#yM z?$jEmmMW;0N`%Q0-=czU$jx@t^?Ghz67Pfu+zJC$-57~5i+%HBBAqw@C6_V@)R~?A8LXTbEg;A z4`5su0DwX1BPD1bpX55@+3Y^B^U=y?A&X;djWY<_8wNl=YXmFuf^ZIx9iS5q$|^A; zm{L@r9{l1@7EVUy9E=_S}+AXDsjkNO2b4#Jp=%K5v zqp{n!4yv7Nf@3C#uAX3`AqK|C^uoGoRwE>$$h1U;(C$Z3)V+4xi$>%c1|zUYaDnTg zFuj8*vrQ}mhy|1*Bm$sFbg#}GeGqs=9`dZfyDNtL`}e%JP=gQ)+BKPMEfQ0ZJBevP z=U5Ezuf!i0NOJY82=-z(F88Vs2@)cmf^9R0PfbD`;ftRe!Hj#GFDPz@?&I>_^HT+t z1Y;T;i6hxfqL54HO^fgF7UpCOlVxWX@;Cf9)}G1oKPZP4ZBKBVKW zw=7kBZX+d*GBgy+jb_|!{}ka^^v@iSe2rdT&$WY#)#1A1W~4YWGBSZ;rB*jOM$wGi zerGaQYWaw!3y8f$LaHi?1|MbUC!xZ0(7}=bjNqaYTN~b20v397o);CfZn2@#OhVci z-bbbb2{M#SgT(TT>}XO${fufOXE%ogqP*ay8ZsJPXd&}@B;mPt;+kTz%3-+4>O%6M zm0UF%j#Qgt!qjdBcGIDqA$aL&!%g_)Jw{}QJf10d?QzXL&PA#0B%;zEWcjiPEBo#3b(=i;P5$aKi+w_Z`R;Zi$hT(mcERc!T!%hm_rn~{ zW969MZHyjII7Tr2&bL9czb)gFnN79UtD^lf*nkuOP=J__fw0t%vdJA)zI35S8|dOe zue6on6wn}G_0w&%y*N-Q*GFwxP`o1~kOQVUCKx>sbWCI%*}u!_Fy8#UTYJUU2d@ah z>101#T)sK-2!g~O;%5?ALvvRCPB=_hY^!O?JDe3}v&QARAc`w;aU&#<7P=ULkSGqQ z>{Ulq-v>>z*{_WtPw{iQ`FU#uo2NA{LPsR$f~?hUT@ourQtct0bpu()ea>a9477zB z8i+H=*;aRaFl`mo*y>s(tkH0&Y$GL2;a~=cu)HIMG~G;0ocGWAwTf$)49XJK+V*4`u^Upieq#mP%i!h*WqQ1g7V zuUU1%WrmHho7CJxBMc-qV4@X74pT6hmKaPK2O1EX!z-X(gxG=Hx#`a571OLq%J(7G zD(lAMd~+|Xb&WtB6XD($QF4*Ry*Z4IQzIooxh)dLBPHIDg3~ySBMJEJyJc$G(7P?- zA;|dOtI=OH@;RPaFM8)*5z7X)s-=`J5HYRKY$GHzX04%Zk42#OoNa@!$7G(W9yMPa zuQwRyrigiU2z8!sKFg%K@o~;P;TrLZFp0s`>vP;Jq;W+LRT8Q9SzD8|S$gTktVmC?1Y zOcsxzGWdu#>%+a=$;R|URX%z3h?|N38)%1acI;f7u|)nax|@7;9w(#0ay$V0%yw@H z?crEbX_87EZ?GxqPFbYIN|g^9p<-h~uPO*D;5bE-0FeWxXYnkaC~ES;_3Ec{lPc+jqFgR70W@!)6M-@W8J}&MX_hUgp}wARNM<|Ut6N?R;4K_> z9U5Iq(_@hp+*%kY(;>PRaLr7^F+KM?WH+&6VZC3UBP4__6P|p8b*C9FR@dWR60t~H zGYqFnpgP%i5qs~y8cjx&G+3q`M-kbn#;I9@6kEiUvEyS!_18q0U~%GDH~|boov;H! z$U6|h0=61AS%^6xqy@rg`ydNTnW1d#90d_DVC**8G~1oBKs6ePzzgm+$&11l9m|w# zhe%5)I|Ql3HNLk=9tW*CS-{ALMM@(ih-#8a0)+Qj40+p|oLnHqwop{Ed;1-cBP9h` zl_?IO&Xl5xP8_Ehw=okCGrvC_mhQ(b*wvyNSfuDe8=x7&?+Agyz$H>(7-xxG_^(E4 zR`9 z#vSJ+`R$~{cH_qbsvY`J=v8<2QJ*8$EsD5@^l=(72JK#}8Y^g+FHX*vr9rgZ$#J+y zxU3wiuB@3QgTpQA9#vl_CKaP0y>-fY%slreZoILn%Z@`kVvbvJcjoWB*GDUD3Ghk~ zo1%rsTZ2luyV*E-P-CmhbHG1{+2#(%-XgNy8-;IV+S0CX7Px9`Lxh@1K=|kjfOyjV zErex)D@Eg+ObI*ACPB)IE~76!ro80wR#7^M>A4BJaUA<2B(=%MCxB5gjj7*!UHtap z0BdWIQFT>Eow}Mf+F9`B4u*GhqVq{*Bb(jbF6+V``P>l;MjS~??uSsg;v!b)LPE>A z#&o#diym~Nx@%0nQkvy#w<~D4HWDr}jq8(1Mg^G1S1G8-O-!+|7gttC>cfE|ZMpolq;BoO>DYKLVig@egLUD!QpPThr6?rJ|aa zQ=mxt`N3by4%r0N(ie*$i<(5~Im!Y(f^9T)$V?1Ui%3mH+6$)l7rnqck=B^8HJ3GD zu;OUw9TwGE#Lk#Bg{>+E*LE|s9P;)q<__Bk&bdqsBP1>tJsTdr4~X27PMK#AlGo7a z8Zm*rF$WW!T;0ovawBtYvr&khH>)q0F^`55<2_7wC3^4a@xswme@esvi~=n#tXdA9 z1rZXB+ME?c{r%97-nfp*5IfW;@jm)8NZc~meLr?&GEAKtwK-qSKLa^B<34`X=Ds2J zmfHh*<&V67Xaq)$dLN4`UuN5M?(!X-B6jULw=W%>uyyC>5=cms*Fs38KqNu+BP5Ca zMF2r>%`OfTYIOaNydZ<|~nfBP9^ErU{jZE+no54nnNT zAwm=(K(s-S7}N&>=oEx3BP55C9NQx#nO(L<8enDOJOfa0P64RkM^X@BnKpOP2|bXZ zPa}Kd1#DpCIwK|I1WF?QazIh(d6yB}n4^rxkzc#%j-Jn#hn0qKupugyAC!+AVPvm{ zplBwtVjCkQ>!FiSoFyY9k{ILDjBHn=Rj0W)cZmP9BRS@Av6@7Y(gYSf#InW^;K~k? zFVj}w)3rMl)8j#eVHrmodP$IMXe&5rvt?Mf6&rVYD{pEf)K%h8C%+<-mXU@QSLiV8p4^|n;h0KV6@OWIyOyJ zC85zEQWTchi4GTrma{HA4qIblD{BC{Ha<LouPW zQk`m!HCkskC8HQxEKuCd9Y>u}UB2?h0YGUG2NhKD}0&HE%E|@CJUpRX}fYu;~MslK3 zOo?}+B(yn~&YxU3(_DzmDH(B{T`GXn)hit8>o9DpfSiippxI*fP@Ja2B0~tZnIk2@ zqGiTfq>3(;=V%aUYnB+dy;)ZVigUf=tR2`c*@HRt!?~hipsvPrP+J%wmL@q~QQ|Kn zB#y5uGy-I`g3Z{HEOFj!l1<==V4B>LnUGDIOf$B-GGgNDw%)gG?QUwfvn-{@%Jc$B z;SVnfuc6@~_k+!sbU;-trFSl)`2F59Z>;;zZA3*SB2eYtz(1^oF*bx(!!bSDrylz^ za9bSX-7g*7*cMDK7=2ofkS(TmrZ2de&PuK_nIeriL;z7OcrHGsM--q^G?9+U?w_Ev z9PxAvvZrnACAJ>iTcxL(9b?G!QC#xfQW~bcF@9b>E|cA=m$79;Oy3F7-mXS5dk3eK znwbvH_4Nh=zMujow?p1^KR4jPRb-ewAkbkw7@~rZqLvf8!h zL!@DhRH&ptBP1-L0}>|*Ov+3GYCr^{0-kO^&D^Iku7lP0LEk5K^gfsaAyAT-CW0Ck zq5`O;m;@k(N+e*4m?8p*B8Z@pSf~kTDI+CfNP?oELWHVBi78-(f?6V=C?WuYsDgw7 zNJ;{dq7r1JBPFPbsRa}89=~rD2h?x}is+id(he#&C)c~vx2E;N-Ln5a9jQiueFAnk zX*Qv!Y7;;)!Vvdbj}yu`Aa+GxBE*3E#R4O{JEaaok?*eo7i&h(5>8t==f1_e>i8Jj zj`j$wLOyPzv^kB!i)pCY2|yed5PiNp`kjQ5_R}yh=HbhObGCfk?m@z;Z%qO)SUSy3 z@s}m|zck3GnA2TtKjQKb|B(-ex1t+!)~~=$la%7e=`E?!r@(l(J9Bol( z)6Uqx|us)95{bw6D zAwFR}b0Z{V9JR{xp6kPKbq*Q`^PDp) zb+VcqgfqxGkU2F&ZPy*jk$QwGz#V4S83ewm7pz5fjBYVaH_sS5t><=%e8@Tokhv!D zWSF4w^GXw5jl}wtkX2oh*nfm0mhF%9}ws^u#SD7kh%$e z#tWsVn09i>|2xkoUk+=8F;mly^15pSQyD&;u^}WXG}2Nn z0kSOHzf$a@WX#w?b%;-Y)CF=)1t9g2!utgz7_-aQZLn9>4TJA+PCj!PU^i@Qrku zp;RY6PAF=s1DWhy{T+d?&s99R7AxR6+uz;3W9j3y;tbSe+TX2TFLaSD-mcYH?eV2Y~jU4Yv+QZFQ%|wjv%U!xP zm8J^@haj5_JZ;R1%X6(6nZPtHL;EWi?Dw`$T)Zr3A4b2MaP>eG#tZbELvdvG@%D&7 zAc+M;W^wb7d*`PQ9qUkUwx6fY$S@Iqe}P`MVgiD~s5N3D(f93yCEy}o)uw*b%+NGs zrWB4ZA9-$cddWG?toL=yNs_qm`G>*?`+SS`T74{|>PmiSdt6|}V8QaEIgoZpZAxxU zYu&PaTKUh$W8`Mqy(1;U+=ibQe@-p4_n+f=b+RKQ5_hx?I?8npgOM~bnwzEtXRF{_ z9Aq&(wpNWB8nK`$sYoZT94vX|N&sveoG10O9hqCx=DE4~bnG?I|_fbbU)sEY5-E++i9;exp-l_Mk!Ela62 z!e1!idKW`hbWtQ}u0f$=5rK?wiJV^<+~?uJ-gu6N*{j~IkEA0dtnU)}m|`?Ean}QF zroseBj(^BNvBbNsE22xrB$G&EV5Ck#1@c)*Nxi`#<3wvCvobmo z_(oFy0$S)lI;70T;wy*M562jhPIJ$Z8N^wto&~*fD0h4iw9M?=%bnu)(f;l65>c93n2cMvqM8=)5g)FUOK%#3fI zqY>Dl&AeD!GKa%OmgYlt*4mLJAx{QifnhwHWR0ISoNa=aXdV%X%RCnwL^dU2D0+rj z8QX9SMz>cZBraOpM5M(-a$Xt^qs4>;&^3zVyR{xH*A-r-HB@Hu7~x{&be9`TPqVK+ z4@AcnQrVe)cOGYb$D;>UV&Z6dXLO<6w#}SQnF}sj%H1|2C6@^t&3SX%IccW)!|#1_ zMUShwl%pMEoMt@A!MT>UUlzSRU7fW}F|m`1af&|^9%HqCQV>$aO=q@LRjsIJ48M9vV>x37>w2pg2Qb-UBy*tf7+1aW)Uj zCpzVO@cx6x7wkRSLSEhbcA@4>eb!o&m~@1tSgng3$Yw&h@S*Z%Gu-%V9|?tFwxhcU z-w&6Xb9KeGY>l`P;|rrMoFUyKB}S#3;pQV4#s@U-kbKnAWvMX2m*(?wa6vAGIT@Lq zQALdwJYlBTGE?QEs4GC)G~MaVHDrLuLPilpXkSicha~HUWZBqn91*_zM(o|ocOuys za@M7sIMjU8aN^=+jHVDEvPX$ zW;1(YQB&~*fr)rohc8at!eDL93w>~JAq5_aMjC;QS4r2|*ISDaVS-X@3#F3+rw3)I zbL5@3)`&9$RI+TuxMHa2$r!NI$p1BDb4>UFE-Hbl$1z;-yd92HG* z2o7!oKv;-fCD%&eLEV8 ztxnXz5at#mByF^z8Og^9B_kv#>?ZVI-#eb|qoz*F1drJ?rtR9`CY`znFqOVnWU{+r zRw*-he|zQQj|j_>c#)D)Zi(%z^TjPIM!FsFbOcCV%oz}r)x8N{(lHk{;lQC_wGOU* z^(k}8HF`ZqPu{HTG)139Or?peD9dW;s5S<)Newf!!5L58F*6B*eF@_|@OsBtRZOAOYBm=ExsnSRf)XP>`R5o(C}S zhRk@vhmUzxL&!+nglQPUa^Mj33zlS}Dq@O?h-O%rSZXXANl3*E#@LwQ!Byr!NK zhJ-HfO(set%rzB85g;dDP#*6OA4lI#1KH3J#P&*;?K`z>+64#FsnHb<0yKM;{=hQ{ z?`Q?b%MO6;9I3Hc7#7->kq~K0PZvYL;&|VfAjeU&BxRcW=ULB7%GRUYYD*ntF*Pta*G|b{v+d0+J!AvC2rc|zgOMMj z(K)Iy5lW{v218tZZQ#}>qZKNHz=w1gkE&RocfD1DgCAbG7kJZY+@4jH0uxi%{vU<; zDi4uCNWJOft>M@J-S~s{EFn!L57#Ief>x1a5`;pPLXdw5O2nVckpmIl9KcYJG)ctV zpbVgCGpS?%3?wH^2Y`X>M;ZM{N1O~I^h4c%A%L#24v>iTL~0=QPb^*8K_U>pPL^yx z@W&ScJe5S*bJD$X8}@LA@4LzHd;{SCP?8eJO3>1UEfF<$_3k*B0uI}7 z=)uSr^P)tGAd!Fp8)NnUGswas+WNa%Y&dLwT*M2X*b|Sz<>#C_N0f|5Ab{Z0O^?AO zff%+jMykS&*aM%95 zj}FG+mY4zho%i{7ji6*nL;WmXqvF zb251{W|j~bh7<%b9F7i1t~i*>9uI9scpF}+*o3lhKJrpRpLFLVxy%uz!pG_lvl|s! zTg~jAkj;pMAS8^=0U{~X+4dJvB-1w%k`XbC0l(kht9^?OUxKPcJ$`OpUAUGG6dzUk zk>Tu$KsdCAXh8Xu5Ix>FMJf_WMM6Y`v_SzSH9$&$RZ%h#ODO?K{OLnL1|}p3l7zxa zv>Ofy+Vc?Jc4L%;7hipsk2{~gOY%OPeN$lXlXn!{?e6*dh7ijsz&Bcr_NgsNz}3;v zi0s@!f=Vp zz^PVKZbBoABokr7U8Y`|FyUxt7(+ty zQb8|jH2KaNVVbj5OJv=egTa_DQMNGID==QEw4s|hb0}e<2&&XhY2sQ;%S8y|u~(fkSM=qZ4*osp`9zFuViqXpTT9U)M!n15tT9ZZ#-1!J6eX1* zV?cTPW=7;LZ)1W1tl}0otgJW^lxzjVu5li?RpscakWIW#NN}VQnO1pslUeSK zd!Ue;%P3KEz^?Iw)FULAB)q|}$L`rC;i>X$kof(6?fG%i#RmmR-A|BWIl4yeJ;7An z)%@x)KnV3;pzfj|aMUPUO8{xwQFCvN?iZPCuz3B2ui3(J?6z2@HeKhhJaU_<;`}EmIQEl+{wCKm@@+ki<{Y_F4}A zoFa*!S|T8!2?&Z(2&AD&Ac9m6roi<=e!L?k=tS;E^1&YeRl6M$Om;&fCHeYA5KuI9 zV;VHYRLfG55dlL4#UW6|L4BJjz#$BdiWM+mAqQCeZgb$cZ&V-lb#!Iv>nFeX@7AYa zM0ks}>pWD%*fV48wOEPZB1CB|K3vy8`9miHR$6^>#=#%pq+!yw&D@wkdQ=Qn*DzVn zD4BVHi`>;Bmgav#`^(;Z&-%Ni)mah(K9BC@IDtvc+5Pth^%#Qb8e%#E7j!8N2PL zYbJ@q-&_W8{wu$o)U_K?Aryj;)qr&Y)UhQ8I_CsAD(Or><$!&Qsl6O$#zzjY2Xahz z#r}2yJN7f_B0hwZBtUdX`9N&dX$)lrV;T{J1;5;86#eh*VVD~%BS5Q7l5rRpoh{8N4h2er^nzJ( zg%C(6d5lLRTMim|&MU$ufRlrRk2!LQrh`R|tV6lMIK(tT5hVo9+&GSgDdFRX7GXKE z?T1@npv09))=UKk!-8%;Pg&0q>Qbp8lcL0dQBg=8T;aP|BP9!>uDF}5JDD;%$s;5Y z6r{{SArglrGcP2-b?Ws81v+GTv+O;sFUgnGW_m?({{vos$AbOw#4bSEe6(wxHkKl8 zz8I!Figs}h=oe|6pQc2$BP6GG{68}{y`KNY6Xa2Qe5E;;1wMcM3@xl^`dP9*9S)f;z5gABpXZIb$y8amrCVjlJC&aYp*9;Tb>z$oD;Fy ze{7x1oc!`qT;1R2v7YOqk)k01eszeTmbQgXnI`9ppqIHGWguQ72NwuXm2k zfWfhzvjkMq#-xc99+#ynF=;A_h#-?fio_xh?d|x&>idVYDv$5qZgA#l-gA2YWA6Lr zvTfTZ7Xp`Xc993E=ksthkK~3OE<5%ZPs8(aUlJZN8h+npJZMz+bjc2!@){#0!CPiw z-;Cg>g1DD()M#Nv(F4!a{PxO9i4gl(+e~r6b6?@q#vdHmF{IBBi{aaag{$y|{2Z){ z>?LJP+&O=r#P8<&`IMi2uU(vm)ljzQ(2~#*hh#Blclb~%Eb_fxyWBqgT)Io0ig(*1 z*LyBVgF)VX&#W}(;AC^293+53h(;V-v2i^PG>cD$8a(>?bNb`W_}*jXKZjM^v9aLR zzgjConpsPTMOgY?yg{Fiy^l zocIGkf4lu(@c93;|8Af6_x*qOf9Sqn?z{iL|9ih@`+wj65A}bq`!fFT{y+KtfA0T> z{J-x1`}_aD{r3Am-Toin{r(T||4;tEtNZ`M{M!G+xBNNzzq|E(-v5*jdi<&f^O0fx zhx9g2@c%Lf25s{G>OY>WmW(YbLh0v7XB0)hR!6p0A07fmNGDj?s*!Rr7P7q+C0 zz$qhwX;*5JN~WqM5h!Zz?k0I_>HPTdcN3(7!U^Nugz@vUU1Bk5XPaF4{CXIAkp8>= zUS@xWYfmsvtd0e$J|Ew9)BDfwozbGGDVV|{7dX~*d;S0UDwxZ;+ZkkHsiOb) zzRGDhnEaE))EZ32n7_pcGp940QXDHK#KH-R^Ih6m1~5is+wl&UAf;lO&A;$vGKF2c@rC0#V3s#^sG zc)Zpi{e#{~B%56Nhhcsgr@y7yTq+bWx5b2{igNMLoMdD~f^<3OW#X|{Op<0fg)s}H ziGx7^?4dJ&0v$mJApkBc44^!sH;N%3EwVM5vI7J|5RE8n=kfpb9fp^BI*O7d>yJhj zFC!#qn}Ps;_y#8Fd==NZ=zW|kNndRm^3I#U??8}MU?9XIiBv@_Q7thm5d;*m>Pi#{ z2Pla4dbE!>s)X1>{-}xnL{{b$BP3Njh^3;3L>t(WN>zvu#en-ddp+o{m%;yqsIP4W zPTA*Xi4T;)@TvZ~Kjn#yvBsW~3{%uK8beFz>z8>=aBe;trp$ zSERIA&R3>_^@fDC^1|pIZ*H!cIJW)-eEfd6i1Ixq#>W{_$sH6NhG>E>D_*-KOUc87 z@%OK_Z|e4)`G&;fxt;He^w zfRv%WxRpB*s6apFLC`%9*CQhgBI)eR@xm|21oa3VL~vLu0FOYyF(MAa1CO4d!>$mA zp1w9tTIfE`Jgf=4Ho6b|h!6Z<#rB`^m9sN)AB)`a62KE`ZUdj`I)wxOTtFZYL4*MG zeNQAGrxq=;ri%dS6eN&}9VH2+qE`?ee^&mClED&V>qY%|>?-|)R6#5uN+IS-9p`!M zn3>n$zaSogm6thj73cKyz?e72?WffpY3#TchoXGQI*3noABW&i`o$HrLeO5_kUggp zLJ;y`f8F@XKi=E?1^>c7sXzAo$N0S#CwKiUA+KKYOrP)h@A6ll#64gBVWUMGBOP{P zZ~GDCx6f8#;q>qF4yI-Q!@u4-prQ^_@9_Ab`Fz2nIdkkxC;CEl2P%A1@nnmJWI}nc z{3h)Gd;E=Z=y0pcU6*6^xa0b{9qjfG_I?mXBrsJk4=et+F=r_1QUAjNe|`~pfQbKO zTP3`X__z5!$~2hYIfML4u=t_GB!!JuT496 z!SQ0_omZFrxgY~EWS)hoEUpaF(|2OCw#fpL2n8b~>t)qK@3YfQROwTR`s1Wg6$BV5 l$4wd@-;hlo=lQ=+zytsf|Ha&qP81{}fgt>V3L`u{Jqk~96_x-1 literal 0 HcmV?d00001 diff --git a/wscript b/wscript new file mode 100644 index 0000000..157c771 --- /dev/null +++ b/wscript @@ -0,0 +1,70 @@ +#! /usr/bin/env python +# encoding: utf-8 + +""" + * weighttp - a lightweight and simple webserver benchmarking tool + * + * Author: + * Copyright (c) 2009 Thomas Porzelt + * + * License: + * MIT, see COPYING file +""" + +import Options + +# the following two variables are used by the target "waf dist" +VERSION='0.0.1' +APPNAME='weighttp' + +# these variables are mandatory ('/' are converted automatically) +srcdir = '.' +blddir = 'build' + + +def set_options(opt): + opt.tool_options('compiler_cc') + + # ./waf configure options + #opt.add_option('--with-xyz', action='store_true', help='with xyz', dest = 'xyz', default = False) + + +def configure(conf): + conf.env['CCFLAGS'] += [ + '-std=gnu99', '-Wall', '-Wshadow', '-W', '-pedantic', '-g', '-g2', '-O2', '-Wmissing-declarations', + '-Wdeclaration-after-statement', '-Wno-pointer-sign', '-Wcast-align', '-Winline', '-Wsign-compare', + '-Wnested-externs', '-Wpointer-arith', '-Werror', '-Wbad-function-cast', '-Wmissing-prototypes', + '-fPIC', '-D_GNU_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE_SOURCE', + '-D_LARGE_FILES', '-fno-strict-aliasing', + ] + + conf.check_tool('compiler_cc') + + # check for libev + conf.check(lib='ev', uselib_store='ev', mandatory=True) + conf.check(header_name='ev.h', uselib='ev', mandatory=True) + + # check for libpthread + conf.check(lib='pthread', uselib_store='pthread', mandatory=True) + conf.check(header_name='pthread.h', uselib='pthread', mandatory=True) + + # check for needed headers + conf.check(header_name='unistd.h') + conf.check(header_name='stdint.h') + conf.check(header_name='fcntl.h') + conf.check(header_name='inttypes.h') + + # check for needed functions + #conf.check(function_name='writev', header_name='sys/uio.h', define_name='HAVE_WRITEV') + + +def build(bld): + bld.new_task_gen( + features = 'cc cprogram', + source = ['src/client.c', 'src/weighttp.c', 'src/worker.c'], + defines = ['HAVE_CONFIG_H=1', 'VERSION=' % VERSION], + includes = '.', + uselib = 'ev pthread', + target = 'weighttp' + ) +