From b6140f5887fbec2842858d934c99618b1bf447d2 Mon Sep 17 00:00:00 2001 From: Roman Bazalevsky Date: Fri, 13 Dec 2019 15:42:03 +0300 Subject: [PATCH] Squid report generator (MySQL storage, reports/graphs online). --- fetch/fetch.pl | 126 ++++++++++ mysql/squid.sql | 317 ++++++++++++++++++++++++ web/api.php | 196 +++++++++++++++ web/index.html | 42 ++++ web/squid.css | 216 ++++++++++++++++ web/squid.js | 638 ++++++++++++++++++++++++++++++++++++++++++++++++ web/squid.png | Bin 0 -> 62643 bytes 7 files changed, 1535 insertions(+) create mode 100755 fetch/fetch.pl create mode 100644 mysql/squid.sql create mode 100644 web/api.php create mode 100644 web/index.html create mode 100644 web/squid.css create mode 100644 web/squid.js create mode 100644 web/squid.png diff --git a/fetch/fetch.pl b/fetch/fetch.pl new file mode 100755 index 0000000..a3159ef --- /dev/null +++ b/fetch/fetch.pl @@ -0,0 +1,126 @@ +#!/usr/bin/perl + +#build 20191105 + +use DBI; # DBI Perl!!! +use URI; + +#=======================CONFIGURATION BEGIN============================ + +#mysql default config +$host = "localhost"; # host s DB +$port = "3306"; # port DB +$user = "squid"; # username k DB +$pass = "ASxjC7Gftx8IvRfF"; # pasword k DB +$db = "squid"; # name DB + +#========================================================== +#Path to access.log. It could be full path, e.g. /var/log/squid/access.log +#Put k access.log. Eto mozhet bit polnii put. Naprimer, /var/log/squid/access.log +#Путь к файлу access.log(имя может другим). Это может быть и полный путь, например, /var/log/squid/access.log + +my $filetoparse="/var/log/squid/access.log"; +#========================================================== + +#How older data must be deleted. In example, older than 100 days from max date. +#Period, starshe kotorogo dannie budut udaliatsia. Ukazivaetsia v dniah. +#Период, старше которого данные будут удаляться. Указывается в днях. + +my $deleteperiod=120; #days +#========================================================== +#min bytes of traffic in one record to write into DB. By default - all data stored. + +my $minbytestoparse=-1; #bytes, default -1 + +#=======================CONFIGURATION END============================== + +$count=0; +$lastdate=0; +$sqltext=""; +$sql_getlastdate=""; + +$sqlbatch=100; +$overlap=300; + +#datetime when parse started +print $now=localtime; +$startnow=time; + +$dbh = DBI->connect("DBI:mysql:$db:$host:$port",$user,$pass); + +$sth = $dbh->prepare("SELECT ifnull(unix_timestamp(max(access_date))-$overlap,0) from access_log"); +$sth->execute; +@row=$sth->fetchrow_array; +$lastdate=$row[0]; + +if ($deleteperiod) { + $sth = $dbh->prepare("delete from access_log where access_date < date_sub(now(), interval $deleteperiod day)"); + $sth->execute; +} + +#open log file for reading +open(IN, "<$filetoparse"); + +$countlines=0; +$countadded=0; + +print "\n"; + +$sqlspool = 0; +$sqltext = ""; + +#loop for get strings from file one by one. +while (my $line=) { + + if(time > $seconds+1) { + $seconds=time; + $insertspeed=$countinsert; + } + $countinsert++; + + @item = split " ", $line; + + $bytes = $item[4]; + $time = $item[0]; + if (($bytes>0) && ($time>$lastdate)) { + $ms = $item[1]; + $client_ip = $item[2]; + $http_code = $item[3]; + $method = $item[5]; + $url = $item[6]; + @matches = ($url=~ /(?:^[a-z][a-z0-9+\-.]*:\/\/)?(?:[a-z0-9\-._~%!$&'()*+,;=]+(?::.*)?@)?([a-z0-9\-._~%]+|\[[a-z0-9\-._~%!$&'()*+,;=:]+\])/i); + $host=$matches[0]; + $user = $item[7]; + $mime = $item[9]; + if ($sqltext) { + $sqltext=$sqltext.",($time,$ms,'$client_ip','$http_code',$bytes,'$method','$host','$user','$mime')"; + } else { + $sqltext="($time,$ms,'$client_ip','$http_code',$bytes,'$method','$host','$user','$mime')"; + } + $sqlspool++; + if ($sqlspool > $sqlbatch) { + $sqltext = "insert into tmp_traffic(timestamp,process_time,client_host,http_code,bytes,http_method,server_host,username,mime_type) values".$sqltext; + $sth = $dbh->prepare($sqltext); + $sth->execute; + $sqlspool = 0; + $sqltext = ""; + } + print "Completed: ".$countlines." ".$insertspeed." lines/sec\r"; + $countlines++; + } + +} + +if ($sqltext) { + $sqltext = "insert into tmp_traffic(timestamp,process_time,client_host,http_code,bytes,http_method,server_host,username,mime_type) values".$sqltext; + $sth = $dbh->prepare($sqltext); + $sth->execute; +} + +print "\n"; +close(IN); + +$sth = $dbh->prepare("CALL Process_Traffic();"); +$sth->execute; + +$rc = $dbh->disconnect; diff --git a/mysql/squid.sql b/mysql/squid.sql new file mode 100644 index 0000000..ac8861c --- /dev/null +++ b/mysql/squid.sql @@ -0,0 +1,317 @@ +-- MySQL dump 10.13 Distrib 5.7.28, for Linux (x86_64) +-- +-- Host: localhost Database: squid +-- ------------------------------------------------------ +-- Server version 5.7.28-0ubuntu0.18.04.4 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `access_log` +-- + +DROP TABLE IF EXISTS `access_log`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `access_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `access_date` datetime NOT NULL, + `process_time` int(11) DEFAULT NULL, + `host_id` int(11) NOT NULL, + `code_id` int(11) NOT NULL, + `bytes` int(11) DEFAULT NULL, + `method_id` int(11) NOT NULL, + `site` varchar(1024) DEFAULT NULL, + `user_id` int(11) NOT NULL, + `mime_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `KEY` (`access_date`,`host_id`,`bytes`,`user_id`) +) ENGINE=InnoDB AUTO_INCREMENT=112422 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `column_names` +-- + +DROP TABLE IF EXISTS `column_names`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `column_names` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(45) NOT NULL, + `alias` varchar(45) NOT NULL, + `template` varchar(1024) DEFAULT NULL, + `template_name` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `column_names` +-- + +LOCK TABLES `column_names` WRITE; +/*!40000 ALTER TABLE `column_names` DISABLE KEYS */; +INSERT INTO `column_names` VALUES (1,'username','Логин',NULL,''),(2,'useralias','Пользователь',NULL,NULL),(3,'mb','Трафик, Мб',NULL,'column-right'),(4,'avg_kbits','Средняя скорость, Кбит/c',NULL,'column-right'),(5,'hostname','Адрес',NULL,NULL),(6,'hostalias','Устройство','',NULL),(7,'site','Сайт',NULL,NULL),(8,'requests','Количество обращений','',NULL),(9,'_user_id','Пользователь',NULL,NULL),(10,'_host_id','Хост','',NULL),(11,'hosts','Хосты','$hosts;',''),(12,'users','Пользователи','$users;',''),(13,'hosts_s','Хосты','$hosts_s;',''),(14,'users_s','Пользователи','$users_s;',''),(15,'sites_u','Сайты','$sites_u;',NULL),(16,'sites_h','Сайты','$sites_h;',NULL),(17,'username_hh','Логин','$username_hh;',''),(18,'ip','Хост-клиент',NULL,''),(19,'uri','Запрос',NULL,''),(20,'bytes','Байт передано',NULL,NULL),(21,'seconds','Активен, с','',''),(22,'host','Хост-клиент','$host;($_ip;)',''),(23,'user','Логин','',''),(24,'hour','Час',NULL,NULL),(25,'hostname_hh','Хост','$hostname_hh;',''); +/*!40000 ALTER TABLE `column_names` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `hosts` +-- + +DROP TABLE IF EXISTS `hosts`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `hosts` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `hostname` varchar(45) NOT NULL, + `alias` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `hostname_UNIQUE` (`hostname`), + UNIQUE KEY `alias_UNIQUE` (`alias`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `http_codes` +-- + +DROP TABLE IF EXISTS `http_codes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `http_codes` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `http_code` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `http_code_UNIQUE` (`http_code`) +) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `http_methods` +-- + +DROP TABLE IF EXISTS `http_methods`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `http_methods` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `method` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `method_UNIQUE` (`method`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `mime_types` +-- + +DROP TABLE IF EXISTS `mime_types`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mime_types` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mime_type` varchar(45) NOT NULL, + `alias` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `mime_type_UNIQUE` (`mime_type`), + UNIQUE KEY `alias_UNIQUE` (`alias`) +) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `rep` +-- + +DROP TABLE IF EXISTS `rep`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rep` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cat_mnemo` varchar(45) NOT NULL, + `mnemo` varchar(16) DEFAULT NULL, + `name` varchar(45) DEFAULT NULL, + `description` varchar(1024) DEFAULT NULL, + `query` varchar(1024) DEFAULT NULL, + `has_total` varchar(45) DEFAULT NULL, + `graph_x` varchar(45) DEFAULT NULL, + `graph_series` varchar(45) DEFAULT NULL, + `graph_y` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name_UNIQUE` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rep` +-- + +LOCK TABLES `rep` WRITE; +/*!40000 ALTER TABLE `rep` DISABLE KEYS */; +INSERT INTO `rep` VALUES (1,'user','by-user','Трафик по пользователям','Распределение трафика по авторизованным пользователям','select 0 as _ordr,t.user_id as _user_id,u.username,u.alias as useralias,round(t.bytes/(1024*1024),2) mb,hosts,sites_u,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select user_id,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct host_id) hosts,count(distinct site) sites_u from access_log where (1=1) $FILTER; group by user_id) t left join users u on t.user_id=u.id union all select 1,null,\'ИТОГО:\',\'\',round(SUM(bytes)/(1024*1024),2) mb,\'\',\'\',round((SUM(bytes)*8/SUM(process_time/1000))/1024) avg_kbits from access_log where (1=1) $FILTER; order by _ordr,mb desc\n','1',NULL,NULL,NULL),(2,'host','by-host','Трафик по хостам','Распределение трафика по клиентским хостам','select 0 as _ordr,t.host_id as _host_id,h.hostname,h.alias as hostalias,round(t.bytes/(1024*1024),2) mb,sites_h,users,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select host_id,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct user_id) users, count(distinct site) sites_h from access_log where (1=1) $FILTER; group by host_id) t left join hosts h on t.host_id=h.id union all select 1,null,\'ИТОГО:\',\'\',round(SUM(bytes)/(1024*1024),2) mb,\'\',\'\',round((SUM(bytes)*8/SUM(process_time/1000))/1024) avg_kbits from access_log where (1=1) $FILTER; order by _ordr,mb desc','1',NULL,NULL,NULL),(3,'site','top-sites','Сайты с наибольшим трафиком','Сайты с нибольшим объемом трафика за интервал времени','select site,round(sum(bytes)/(1024*1024),2) mb,count(*) requests,count(distinct user_id) as users_s,count(distinct host_id) as hosts_s from access_log where (1=1) $FILTER; group by site order by mb desc limit 20 ','0',NULL,NULL,NULL),(4,'site','top-requests','Часто используемые сайты','Сайты с наибольшим количеством запросов','select site,round(sum(bytes)/(1024*1024),2) mb,count(*) requests,count(distinct user_id) as users_s,count(distinct host_id) as hosts_s from access_log where (1=1) $FILTER; group by site order by requests desc limit 20 ','0',NULL,NULL,NULL),(7,'site','by-site','Трафик по сайтам','Распределение трафика по сайтам','select 0 as _ordr,site,round(t.bytes/(1024*1024),2) mb,hosts as hosts_s,users as users_s,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select site,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct host_id) hosts,count(distinct user_id) users from access_log where (1=1) $FILTER; group by site) t union all select 1,\'ИТОГО:\',round(SUM(bytes)/(1024*1024),2) mb,\'\',\'\',round((SUM(bytes)*8/SUM(process_time/1000))/1024) avg_kbits from access_log where (1=1) $FILTER; order by _ordr,mb desc','1',NULL,NULL,NULL),(8,'user','big-files','Большие файлы','Кто скачивает большие файлы','select 0 as _ordr,t.user_id as _user_id,u.username,u.alias as useralias,site,round(t.bytes/(1024*1024),2) mb,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select user_id,site,sum(bytes) bytes,sum(process_time/1000) seconds from access_log where bytes>10*1024*1024 $FILTER; group by user_id,site) t left join users u on t.user_id=u.id order by mb desc limit 20\n','0',NULL,NULL,NULL),(9,'user','by-hour','Трафик по времени суток','Распределеение трафика по пользователям в различные часы','select hour,t.user_id as _user_id,u.username as username_hh,u.alias as useralias,round(t.bytes/(1024*1024),2) mb,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select user_id,date_format(access_date,\'%H\') hour,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct site) sites from access_log where (1=1) $FILTER; group by user_id,date_format(access_date,\'%H\')) t left join users u on t.user_id=u.id order by hour,mb desc','','hour','useralias','mb'),(10,'host','by-hour-hosts','Трафик по хостам по времени cуток','Распределение трафика по хостам по времени суток','select hour,t.host_id as _host_id,h.hostname as hostname_hh,h.alias as hostalias,round(t.bytes/(1024*1024),2) mb,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select host_id,date_format(access_date,\'%H\') hour,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct site) sites from access_log where (1=1) $FILTER; group by host_id,date_format(access_date,\'%H\')) t left join hosts h on t.host_id=h.id order by hour,mb desc',NULL,'hour','hostalias','mb'),(11,'user','by-time','Трафик по времени','Распределеение трафика по пользователям в различные часы','select hour,t.user_id as _user_id,u.username as username_hh,u.alias as useralias,round(t.bytes/(1024*1024),2) mb,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select user_id,date_format(access_date,\'%Y%m%d%H\') hour,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct site) sites from access_log where (1=1) $FILTER; group by user_id,date_format(access_date,\'%Y%m%d%H\')) t left join users u on t.user_id=u.id order by hour,mb desc','','hour','useralias','mb'),(12,'host','by-time-hosts','Трафик по хостам по времени','Распределение трафика по хостам по времени суток','select hour,t.host_id as _host_id,h.hostname as hostname_hh,h.alias as hostalias,round(t.bytes/(1024*1024),2) mb,round((t.bytes*8/t.seconds)/(1024)) avg_kbits from (select host_id,date_format(access_date,\'%Y%m%d%H\') hour,sum(bytes) bytes,sum(process_time)/1000 seconds,count(distinct site) sites from access_log where (1=1) $FILTER; group by host_id,date_format(access_date,\'%Y%m%d%H\')) t left join hosts h on t.host_id=h.id order by hour,mb desc','','hour','hostalias','mb'); +/*!40000 ALTER TABLE `rep` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rep_cat` +-- + +DROP TABLE IF EXISTS `rep_cat`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `rep_cat` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mnemo` varchar(45) DEFAULT NULL, + `name` varchar(45) DEFAULT NULL, + `description` varchar(128) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `name_UNIQUE` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `rep_cat` +-- + +LOCK TABLES `rep_cat` WRITE; +/*!40000 ALTER TABLE `rep_cat` DISABLE KEYS */; +INSERT INTO `rep_cat` VALUES (1,'user','Пользователи','Отчеты по авторизованным пользователям'),(2,'host','Хосты','Отчеты по клиентским подключениям'),(3,'site','Сайты','Отчеты по посещаемым сайтам'); +/*!40000 ALTER TABLE `rep_cat` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tmp_traffic` +-- + +DROP TABLE IF EXISTS `tmp_traffic`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `tmp_traffic` ( + `timestamp` decimal(38,3) DEFAULT NULL, + `process_time` int(11) DEFAULT NULL, + `client_host` varchar(128) DEFAULT NULL, + `http_code` varchar(45) DEFAULT NULL, + `bytes` int(11) DEFAULT NULL, + `http_method` varchar(45) DEFAULT NULL, + `server_host` varchar(128) DEFAULT NULL, + `username` varchar(45) DEFAULT NULL, + `mime_type` varchar(45) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(45) NOT NULL, + `alias` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `username_UNIQUE` (`username`), + UNIQUE KEY `alias_UNIQUE` (`alias`) +) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `web_templates` +-- + +DROP TABLE IF EXISTS `web_templates`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `web_templates` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mnemo` varchar(32) DEFAULT NULL, + `description` varchar(128) DEFAULT NULL, + `body` varchar(8192) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `mnemo_UNIQUE` (`mnemo`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `web_templates` +-- + +LOCK TABLES `web_templates` WRITE; +/*!40000 ALTER TABLE `web_templates` DISABLE KEYS */; +INSERT INTO `web_templates` VALUES (3,'menuitem','Вложенные пункты меню','
  • $NAME;
  • '),(4,'menugroup','Подменю','
    $NAME;
    • $MENUITEM;
  • '),(6,'menu','Верхний уровень меню',''),(9,'report-table','Общий шаблон таблицы','$HEADER;$LINES;
    '),(11,'report-table-total','Общий шаблон таблицы с итогом','$HEADER;$LINES;$TOTAL;
    '),(15,'column','Отображение столбца по умолчанию','$VALUE;'),(16,'header-column','Отображение заголовка по умолчанию','$VALUE;'),(17,'table-row','Строка таблицы','$DATA;'),(18,'header-row',NULL,'$DATA;'),(19,'total-row',NULL,'$DATA;'),(20,'column-right','','$VALUE;'),(21,'filter-display','','$NAME; : $VALUE;'),(22,'clear-filter','',''),(23,'menuonline','','
    Онлайн
    '); +/*!40000 ALTER TABLE `web_templates` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +CREATE DEFINER=`admin`@`%` PROCEDURE `Process_Traffic`() +BEGIN + + insert into users(username,alias) + select username,username from ( + select distinct username from tmp_traffic + left join users using(username) + where users.username is null) t; + + insert into hosts(hostname,alias) + select client_host,client_host from ( + select distinct client_host from tmp_traffic + left join hosts on hosts.hostname=tmp_traffic.client_host + where hosts.hostname is null) t; + + insert into http_methods(method) + select distinct http_method from tmp_traffic + left join http_methods on http_methods.method=tmp_traffic.http_method + where http_methods.method is null; + + insert into http_codes(http_code) + select distinct http_code from tmp_traffic + left join http_codes using(http_code) + where http_codes.http_code is null; + + insert into mime_types(mime_type,alias) + select mime_type,mime_type from ( + select distinct mime_type from tmp_traffic + left join mime_types using(mime_type) + where mime_types.mime_type is null) t; + + insert into access_log(access_date,process_time,host_id,code_id,bytes,method_id,site,user_id,mime_id) + select t.access_date,t.process_time,t.host_id,t.code_id,t.bytes,t.method,t.server_host,t.user_id,t.mime_id + from + ( + select from_unixtime(round(timestamp)) access_date,process_time,h.id host_id,c.id code_id,bytes,m.id method,t.server_host,u.id user_id,mt.id mime_id + from tmp_traffic t, users u,hosts h,http_methods m,http_codes c,mime_types mt + where + t.username=u.username and + t.client_host=h.hostname and + t.http_method=m.method and + t.http_code=c.http_code and + t.mime_type=mt.mime_type + ) t + left join access_log a + on t.access_date=a.access_date and t.host_id=a.host_id and t.code_id=a.code_id and t.bytes=a.bytes and t.method=a.method_id and t.server_host=a.site and t.user_id=a.user_id + where a.id is null; + + delete from tmp_traffic; + +END; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2019-12-13 15:39:51 diff --git a/web/api.php b/web/api.php new file mode 100644 index 0000000..2b700e2 --- /dev/null +++ b/web/api.php @@ -0,0 +1,196 @@ + 'OK', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 500 => 'Internal Server Error', + ); + return ($status[$code])?$status[$code]:$status[500]; + } + + function response($data, $status = 500) { + header("HTTP/1.1 " . $status . " " . requestStatus($status)); + print json_encode($data); + } + + function connect_db() { + + global $db,$mysql_host,$mysql_port,$mysql_schema,$mysql_user,$mysql_pwd; + + if (! ($db = new PDO("mysql:host=$mysql_host;port=$mysql_port;dbname=$mysql_schema",$mysql_user,$mysql_pwd,array( PDO::ATTR_PERSISTENT => false)))) { + die($err); + } + $db -> exec('SET CHARACTER SET utf8'); + + return $db; + + } + + function exec_query($sql) { + + global $db; + + $q = $db -> prepare( $sql ); + $q -> bindParam(':s',$auth_token,PDO::PARAM_INT); + $q -> execute(); + + return $q -> fetchall(PDO::FETCH_ASSOC); + + } + + $api = $requestParams["method"]; + + $data = Array(); + $code = 200; + switch ($api) { + case "get-base-config": + + $data["site-header"] = $site_header; + + connect_db(); + + $cats = exec_query("select mnemo,name,description from rep_cat"); + + foreach ($cats as $cat => $value) { + + $cmnemo = $cats[$cat]["mnemo"]; + $reps = exec_query("select mnemo,name,description,graph_x,graph_y,graph_series from rep where cat_mnemo='$cmnemo'"); + $cats[$cat]["reps"] = $reps; + + } + + $data["cats"] = $cats; + $data["templates"] = exec_query("select mnemo,body from web_templates"); + $data["columns"] = exec_query("select * from column_names"); + $users = exec_query("select id,username as name,alias from users"); + $hosts = exec_query("select id,hostname as name,alias from hosts"); + $data["dictionaries"] = Array( "user_id" => $users, "host_id" => $hosts); + + break; + + case "report": + + $mnemo = $requestParams["mnemo"]; + + connect_db(); + + $rec = exec_query("select has_total,query from rep where mnemo='$mnemo'")[0]; + $sql = $rec["query"]; + $data["has_total"] = $rec["has_total"]; + + $filter_str = ""; + $filter = Array(); + + foreach ($requestParams as $name => $value) { + + if (($name == "mnemo") || ($name == "method")) { continue; } + if ($name == "date_from") { $filter_str = $filter_str." and access_date>='$value'"; } + elseif ($name == "date_to") { $filter_str = $filter_str." and access_date true, // return web page + CURLOPT_HEADER => false, // don't return headers + CURLOPT_FOLLOWLOCATION => false, // follow redirects + CURLOPT_MAXREDIRS => 0, // stop after 10 redirects + CURLOPT_ENCODING => "", // handle compressed + CURLOPT_USERAGENT => "web", // name of client + CURLOPT_AUTOREFERER => true, // set referrer on redirect + CURLOPT_CONNECTTIMEOUT => 3, // time-out on connect + CURLOPT_TIMEOUT => 5, // time-out on response + ); + + curl_setopt_array($ch, $options); + + $reply = curl_exec($ch); + $retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + // 400 means not found, 200 means found. + curl_close($ch); + + if($retcode == 200) { + + $data["active"] = Array(); + + if(preg_match("/HTTP/1.0 200 OK/",$ptmp)){ + $code = 500; + $data=Array("error" => "No connection to Squid"); + } else { + preg_match_all("/username(.+)/",$reply,$user); + preg_match_all("/(peer|remote):(.+)/",$reply,$remote); + preg_match_all("/uri(.+)/",$reply,$uri); + preg_match_all("/out\.size(.+)/",$reply,$size); + preg_match_all("/\((.+)seconds/",$reply,$sec); + $sess = Array(); + for ($i=0; $i< count($user[1]); $i++) { + $ip=trim($remote[2][$i]); + $reversedParts = explode(':', strrev($ip), 2); + $ip = strrev($reversedParts[1]); + $port = strrev($reversedParts[0]); + if (preg_match('/\[(.*)\]/',$ip,$matches)) { + $ip = $matches[1]; + } + $host = gethostbyaddr($ip); + if (!$host) { $host = $ip; } + $username=trim($user[1][$i]); + $site=trim($uri[1][$i]); + $datasize=trim($size[1][$i]); + $seconds = trim($sec[1][$i]); + $record = Array("_user" => $username, "_ip" => $ip, "_port"=> $port, "host" => $host, "uri" => $site, "bytes" => $datasize, "seconds" => $seconds); + $sess[] = $record; + } + $data["data"] = $sess; + $data["dictionary"] = Array("_user","_ip","_port","host","uri","bytes","seconds"); + } + + } + + break; + + default: + $data["error"] = "Method not found"; + $data["method"] = $api; + $code = 404; + } + + response($data,$code); + +?> \ No newline at end of file diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..39266c4 --- /dev/null +++ b/web/index.html @@ -0,0 +1,42 @@ + + + + + Squid reports + + + + + + + +
    +
    +
    + + +
    +
    +
    +
    + +
    +
    +
    +Отчет с: +по: + +Фильтр: + + +
    +
    +
    Статистика
    График
    +
    +
    Выберите отчет из списка слева...
    +
    +
    +
    + + diff --git a/web/squid.css b/web/squid.css new file mode 100644 index 0000000..fa2e0cb --- /dev/null +++ b/web/squid.css @@ -0,0 +1,216 @@ +body { + font-size:.8rem; + background-color:#eee +} + +html, body { + height:100%; + margin:0; + padding:0 +} + +header, .main { + position:absolute; + width:100% +} + +header { + position:fixed; + z-index:2000; + float:left; + height:5rem; + transition:box-shadow .2s; + box-shadow:0 2px 5px rgba(0,0,0,.26); + color:white; + background:deepskyblue +} + +footer { + font-size:.8rem; + overflow:hidden; + text-align:right; + white-space:nowrap; + color:#aaa; + text-shadow:0 0 2px #bbb; + padding:1rem +} + +footer > a { + text-decoration:none; + color:#aaa +} + +.main { + position:relative; + top:5rem; + bottom:0; + overflow-y:auto; + height:calc(100% - 5rem) +} + +#menu { + position:fixed; + top:5rem; + float:left; + overflow-x:auto; + width:calc(0% + 15rem); + height:calc(100% - 4rem); + background-color:white +} + +.main-right { + float:right; + width:calc(100% - 15rem); + height:calc(100% - 1rem); + background-color:#eee +} + +header > .fill > .container { + margin-top:.5rem; + -webkit-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; + padding:.5rem 1rem 0 +} + +header > .fill > .container > #logo { + margin:0 3.5rem 0 1.5rem +} + +header > .fill > .container > #logo > img { + width: 3rem; + margin-top:-.1rem +} + +header > .fill > .container > #brand { + font-size:1.4rem; + position:absolute; + cursor:default; + vertical-align:text-bottom; + text-decoration:none; + color:white; + padding-top: 0.5rem; +} + +.nav { + font-size: 1.15rem; + margin-top: 0.5rem; + padding: 0; +} + +.slide { + list-style-type: none; + padding: 0; + user-select: none; + display: none; +} + +.category { + padding: 0.4rem 1rem; + cursor: pointer; +} + +.slide-menu { + padding: 0.4rem 2rem; + list-style-type: none; + cursor: pointer; + user-select: none; +} + +.menu-item { + padding: 0.2rem; + list-style-type: none; + cursor: pointer; + user-select: none; +} + +.menu-item:hover, .category:hover { + background-color: lightgray; +} + +#report-name { + padding: 1rem; + font-size: 2rem; +} + +.selector { + display: inline-block; + cursor: pointer; + font-size: 1rem; + margin: 0 0.5rem 0 0.5rem; + padding: 0.5rem 2rem 0.5rem 2rem; +} + +.selector:hover { + background-color: lightgray; +} + +.report-block, #report-dates, #filter, #page-selector { + margin: 0 1rem 0 1rem; + background-color: white; +} + +.report-block { + min-height: 50%; + padding: 0.2rem 1rem 1rem 1rem; +} + +#report-dates { + font-size: 1rem; + padding: 0.5rem 1rem 0.5rem 1rem; + display: none; +} + +#report-button { + float: right; +} + +#filter { + display: none; + margin: 0; + padding: 0 2rem 0 2rem; +} + +.fllter-button { + padding-right: 2rem; +} + +#report { + width: 100%; +} + +#report th { + font-size: 1.4rem +} + +#report tr { + font-size: 1rem +} + +#report tr:nth-child(2n+1) { + background-color: lightgray; +} + +#report tr:nth-child(2n) { + background-color: white; +} + +#report-graph { + display: none; + height: calc(100% - 10rem); +} + +.numeric, .clickable-numeric { + text-align: right; +} + +.total td { + font-size: 1.2rem; + padding: 0.4rem 0 0.4rem 2rem; +} + +.clickable, .clickable-numeric { + cursor: pointer; + text-decoration: underline; +} diff --git a/web/squid.js b/web/squid.js new file mode 100644 index 0000000..dbcf25b --- /dev/null +++ b/web/squid.js @@ -0,0 +1,638 @@ +urlbase="./api.php" + +refresh = 500 +online_history = 60 + +graph_colors = [ +"salmon", "lightcoral", "crimson", "red", "darkred", "orangered", +"gold", "orange", "yellow", "darkkhaki", "lime", "green", "greenyellow", +"springgreen", "olive", "cyan", "turquoise", "teal", "lightskyblue", +"dodgerblue", "royalblue", "blue", "navy", "violet", "fuchsia", +"darkviolet", "purple", "deeppink", "gray", "darkslategray", "sandybrown", +"goldenrod", "chocolate", "saddlebrown", "maroon", "rosybrown", "sienna", +"brown", "dimgray", "mediumvioletred", "indigo", "orchid", "mediumpurple", +"steelblue", "powderblue", "lightseagreen", "cadetblue", "aquamarine", +"olivedrab", "chartreuse", "darkolivegreen", "tomato", "firebrick" +] + +currentState="" + +templates = {} +columns = {} + +cats = {} +reps = {} + +data = [] + +current_filter = {} + +dictionaries = {} + +current_rep = '' + +online_traffic = null +online_connections = null +online_hosts = [] + +timer = null + +assigned_colors = [] + +var d = new Date(); +var curr_day = d.getDate(); +var curr_month = d.getMonth() + 1; +var curr_year = d.getFullYear(); +today = curr_year + "-" + curr_month + "-" + curr_day; + +date_from = today +date_to = today + +function UrlParams(params) { + + var out = []; + + for (var key in params) { + if (params.hasOwnProperty(key)) { + out.push(key + '=' + encodeURIComponent(params[key])); + } + } + + return out.join('&'); + +} + +function Macro(template, values) { + return templates[template].replace(/\$(\w+)\;/g,function (s,name) { + return values[name] + }) +} + +function ColumnMacro(column, values, macro = "column"){ + var columnrec = columns[column] + var templatestr + if (columnrec) { + if (columnrec.template_name) { + macro = columnrec.template_name + } + templatestr = columnrec.template + } + if (templatestr) { + return templatestr.replace(/\$(\w+)\;/g,function (s,name) { + return values[name] + }) + } else { + return Macro(macro,{VALUE:values[column]}) + } +} + +function HeaderMacro(column,macro = "header-column"){ + var columnrec = columns[column] + if (columnrec) { + var alias = columns[column].alias; + } else { + var alias = '' + } + if (!(alias)) { alias = column } + return Macro(macro,{VALUE:alias}) +} + +function GetApi(onfinish,method,params) { + + var req = new XMLHttpRequest(); + + req.onreadystatechange = function () { + if (this.readyState != 4) return; + if (this.status != 200) { + setTimeout(OnLoad,30000); + return; + } + res = JSON.parse(this.responseText); + onfinish(res); + }; + + var url = urlbase+"?method="+method; + + if (params) { + + url = url + '&' + UrlParams(params) + + } + + req.open("GET", url, true); + req.withCredentials = true; + req.send(); + +} + +function UpdatePageProps(props) { + + var logo = document.getElementById("brand"); + logo.innerText = props["site-header"]; + + cats = props["cats"] + + for (var i in res["columns"]) { + columns[res["columns"][i]["name"]] = {alias:res["columns"][i]["alias"],template:res["columns"][i]["template"],template_name:res["columns"][i]["template_name"]} + } + + for (var i in res["templates"]) { + var mnemo = res["templates"][i]["mnemo"] + var body = res["templates"][i]["body"] + templates[mnemo] = body + } + + dictionaries = res["dictionaries"] + + menuInnerHTML = "" + for (var cat in cats) { + category = cats[cat] + innerHTML = "" + for (rep in category["reps"]) { + report = category["reps"][rep] + reps[report["mnemo"]] = report + reptext = Macro("menuitem",{ MNEMO:report["mnemo"], NAME:report["name"], DESCR:report["description"] }) + innerHTML = innerHTML + reptext + } + grouptxt = Macro("menugroup",{ MNEMO:category["mnemo"], NAME:category["name"], DESCR:category["description"], MENUITEM: innerHTML}) + menuInnerHTML = menuInnerHTML + grouptxt + } + menuInnerHTML = Macro("menuonline",{}) + menuInnerHTML + menuHTML = Macro("menu", { MENUGROUP: menuInnerHTML} ) + var Left = document.getElementById("menu"); + Left.innerHTML = menuHTML + + Online(); + +} + +function SetDates() { + var inp = document.getElementById("date-from") + inp.value = date_from + inp.max = date_to + + var inp = document.getElementById("date-to") + inp.value = date_to + inp.min = date_from + + var inp = document.getElementById("report-button") + if (current_rep) { + inp.disabled = false + } else { + inp.disabled = true + } +} + +function OnLoad() { + + GetApi(UpdatePageProps,"get-base-config",null) + SetDates(); + +} + +function ShowHide(id) { + var content = document.getElementById(id); + if (content.style.display === "block") { + content.style.display = "none"; + } else { + content.style.display = "block"; + } +} + +function MergeTR(tr,th, macro = "column") { + var str = "" + for (i in th) { + if (!(th[i].startsWith('_'))) { + str = str + ColumnMacro(th[i],tr,macro) + } + } + return str +} + +function MergeTH(th, macro = "header-column") { + var str = "" + for (i in th) { + if (!(th[i].startsWith('_'))) { + str = str + HeaderMacro(th[i]) + } + } + return str +} + +function ProduceRep(res) { + + current_filter = res["filter"] + if (!current_filter) { current_filter = {} } + dictionary = res["dictionary"] + + header_template = res["header"] + has_total = res["has_total"] + + innerHTML = "" + data = res["data"] + ii=0 + + if (has_total == "1") { + total = data.pop() + } + + for (i in data) { + row_data = data[i] + table_row = Macro("table-row",{DATA:MergeTR(row_data,dictionary)}) + innerHTML = innerHTML + table_row + } + + headerHTML = Macro("header-row",{DATA:MergeTH(dictionary)}) + + if (has_total == "1") { + totalHTML = Macro("total-row",{DATA:MergeTR(total,dictionary)}) + reportHTML = Macro("report-table-total",{HEADER:headerHTML,LINES:innerHTML,TOTAL:totalHTML}) + } else { + reportHTML = Macro("report-table",{HEADER:headerHTML,LINES:innerHTML}) + } + var body = document.getElementById("report-body") + body.innerHTML = reportHTML; + + if (reps[current_rep].graph_x) { + DisplayGraph(true) + var config = PrepareGraphDataset(data,reps[current_rep].graph_x,reps[current_rep].graph_y,reps[current_rep].graph_series) + config.options.responsive = true + + config.options.scales = { + xAxes: [{ + scaleLabel: { + display: true, + } + }], + yAxes: [{ + stacked: true, + scaleLabel: { + display: true, + }, + ticks: { + suggestedMin: 0, // minimum will be 0, unless there is a lower value. + } + }] + } + DrawGraph(config) + } else { + DisplayGraph(false) + } + +} + +function DrawGraph(config) { + var ctx = document.getElementById('canvas').getContext('2d') + var div = document.getElementById("report-graph"); + canvas.width = div.style.width; + canvas.height = div.style.height; + window.Graph = new Chart(ctx, config); +} + +function AssignColor(key) { + if (assigned_colors[key]) { + return assigned_colors[key] + } + var rand_color + if (graph_colors.length) { + var idx = Math.floor(Math.random() * graph_colors.length) + rand_color = graph_colors[idx] + graph_colors.splice(idx,1) + } else { + rand_color = "darkgray" + } + assigned_colors[key] = rand_color + return rand_color +} + +function PrepareGraphDataset(data,graph_x,graph_y,graph_series) { + + var xvals = [] + var series = [] + + var values = [] + + for (i in data) { + rec = data[i] + for (key in rec) { + if (key == graph_x) { + if (!xvals.includes(Number(rec[key]))) { + xvals.push(Number(rec[key])) + } + } + if (key == graph_series) { + if (!series.includes(rec[key])) { + series.push(rec[key]) + } + } + } + } + + xvals.sort(function(a,b) { return a-b; }) + series.sort() + + for (var i in series) { + values[i] = {} + values[i].data = [] + values[i].label = series[i] + values[i].fill = true + values[i].borderColor = AssignColor(values[i].label) + values[i].backgroundColor = AssignColor(values[i].label) + for (var j in xvals) { + values[i].data[j] = 0 + } + } + + for (var k in data) { + rec = data[k] + xval = null + yval = null + dataset = null + for (key in rec) { + if (key == graph_x) { + xval = Number(rec[key]) + } + if (key == graph_y) { + yval = Number(rec[key]) + } + if (key == graph_series) { + dataset = rec[key] + } + } + var j = xvals.indexOf(xval) + var i = series.indexOf(dataset) + values[i].data[j] = yval + } + + return { + type: 'line', + data: { + labels: xvals, + datasets: values, + }, + options: { + } + } + + +} + +function AliasByName(dict,name) { + for (i in dict) { + if (dict[i].name == name) { return dict[i].alias } + } + return name +} + +function AddTraffic(label,b) { + var rec + for (i in online_traffic) { + if (online_traffic[i].label == label) { + rec = online_traffic[i] + break + } + } + if (!rec) { + rec = { label: label, borderColor: AssignColor(label), backgroundColor: AssignColor(label), data: new Array(online_history).fill(0) } + online_traffic.push(rec) + } + rec.data[rec.data.length-1] += b +} + +function ProduceOnline(res) { + + if (!online_traffic) { + online_traffic = [] + config = { + type: 'line', + data: { + labels: new Array(online_history).fill('*'), + datasets: online_traffic, + }, + options: { + animation: { + duration: 0 + }, + responsive: true, + scales: { + xAxes: [{ + scaleLabel: { + display: true, + } + }], + yAxes: [{ + stacked: true, + ticks: { + suggestedMin: 0, // minimum will be 0, unless there is a lower value. + }, + scaleLabel: { + display: true, + } + }] + } + } + } + DrawGraph(config) + } + + for (i = online_traffic.length-1; i>=0; i--) { + online_traffic[i].data.shift() + online_traffic[i].data.push(0) + if (Math.max.apply(null,online_traffic[i].data) == 0) { + online_traffic.splice(i,1) + } + } + + dictionary = res["dictionary"] + + header_template = res["header"] + + innerHTML = "" + data = res["data"] + ii=0 + + var new_online_connections = [] + + dictionary.unshift("useralias") + for (i in data) { + row_data = data[i] + user = row_data["_user"] + username = AliasByName(dictionaries['user_id'],user) + row_data["useralias"] = username + + host = row_data["host"] + hostname = AliasByName(dictionaries['host_id'],host) + row_data["host"] = hostname + + table_row = Macro("table-row",{DATA:MergeTR(row_data,dictionary)}) + innerHTML = innerHTML + table_row + + var bytes = Number(row_data['bytes']) + + var idx = row_data["_ip"]+':'+row_data["_port"] + var last_bytes + + if (online_connections) { + last_bytes = online_connections[idx] + if (!last_bytes) { + last_bytes = 0 + } + } else { + last_bytes = bytes + } + + new_online_connections[idx] = bytes + + AddTraffic(username,bytes-last_bytes) + } + + online_connections = new_online_connections + + headerHTML = Macro("header-row",{DATA:MergeTH(dictionary)}) + + reportHTML = Macro("report-table",{HEADER:headerHTML,LINES:innerHTML}) + + var body = document.getElementById("report-body") + body.innerHTML = reportHTML; + + timer = setTimeout(Online,refresh) + + window.Graph.update() + +} + +function CancelRefresh() { + if (timer) { + clearTimeout(timer) + timer = null + } +} + +function ShowRep(id) { + CancelRefresh() + current_filter = {} + var header = document.getElementById("report-name") + header.innerText = reps[id]["name"] + var body = document.getElementById("report-body") + body.innerText = "Отчет загружается..." + current_rep = id + UpdateDates() + Rerun() +} + +function ShowFilteredRep(id,filter) { + CancelRefresh() + for (i in filter) { + current_filter[i] = filter[i] + } + var header = document.getElementById("report-name") + header.innerText = reps[id]["name"] + var body = document.getElementById("report-body") + body.innerText = "Отчет загружается..." + current_rep = id + UpdateDates() + Rerun() +} + +function FilterSelect(name,dict,value) { + var str = '" + Macro("clear-filter",{NAME:name}) + return str +} + +function Filter() { + var str = "" + for (key in current_filter) { + var dict = dictionaries[key] + if(dict) { + str = str + FilterSelect(key,dict,current_filter[key]) + } else { + str = str + Macro("filter-display",{NAME:HeaderMacro(key),VALUE:current_filter[key]}) + Macro("clear-filter",{NAME:key}) + } + } + return str +} + +function RefreshFilterPane() { + var filter = document.getElementById("report-dates") + if (current_rep) { + filter.style.display = "block"; + } else { + filter.style.display = "none"; + } + var filter = document.getElementById("filter") + if (Object.keys(current_filter).length === 0) { + filter.style.display = "none"; + filter.innerHTML = '' + } else { + filter.style.display = "inline-block"; + filter.innerHTML = Filter() + } +} + +function Rerun() { + online_traffic = null + var parameters = JSON.parse(JSON.stringify(current_filter)) + parameters["mnemo"] = current_rep + parameters["date_from"] = date_from + parameters["date_to"] = date_to + GetApi(ProduceRep,"report",parameters); + var filter = document.getElementById("filter") + RefreshFilterPane(); +} + +function Online() { + timer = null + RefreshFilterPane() + var header = document.getElementById("report-name") + header.innerText = "Активные соединения" + GetApi(ProduceOnline,"online",{}); + DisplayGraph(true) +} + +function UpdateDates() { + var inp = document.getElementById("date-from") + date_from = inp.value + var inp = document.getElementById("date-to") + date_to = inp.value + + SetDates(); + +} + +function SetFilter(name,select) { + current_filter[name] = select.value; +} + +function ClearFilter(name) { + delete current_filter[name]; + RefreshFilterPane(); +} + +function DisplayGraph(on) { + var selector = document.getElementById("page-selector") + if (on) { + selector.style.display="block" + } else { + selector.style.display="none" + Display('report-body') + } +} + +function Display(id) { + var elements = document.getElementsByClassName('report-block'); + for (i=0; i91NmjD5cUE@7 z739R>VR2wVKtSLnB}9}!KtTUhK|!D){}nn;rDh-?KS(Wwg%u=)g?}kH*_&C~n1X~F;t_ftlfr-Q#A}JnOJlsg;8|2N=1~2* zhwFsrL~lccPv5dB16wsLrJ_1}hBP^`1S2U&He$YEQ5t-);!KV%eqsuRz7HKZeX)lh z0X=aQfBhx*Ow!{Sxj7e3EZ=K~j_-s0@>6kg(Yje0tq1D;#j*u*^8xR6f&B+q1z4(2 z7K+E*2nC-UkpN80EcFF?6?7*gZ|ABRLyMt4IM!(5o~j*gJF!`OLsf#I)65=2tYZt) zHzIwe>*J+vpvHSvQJZlqV)!=Avr2ckz)I62-mP@4eodRCp&!Ic?AyFImR9XXimak*Rb zmoAW4fK`D`ZiZt>ybaw&C8OrTUhz{A5fV8JI-{jBDW1OyIm}6eU1IFKWXz*M!2=V9 zOvLi@C^lOFuGoW-ps0GxF1iB6BA$^Nhn}%I4FTmf&<{eRhD%0VbJV}J9IKg^(9(U} zeFzY+PPW|W)C)e8PY<2)t|}PZatik!fEoBLl@YwGAeY?Z)x3_K%J z^2cx8`e8gs@cDE=7s%i*>~}S1*Ok`m3X9HP|ICt*_X&*hPtLdP&6a-^e3jXi>X%|J z?(kRzVe=G|`cV7Od{X*Q_%M9RM7U_S6MvHGCU?ivLvVH6bmfw*de!I~qHaa#S}a-T zvQa3@je8wp9wmKre$?~g)}poP6C{=#cHLgWJWu`n#P7m#fo-soZStbK`+>!ZNCue= zxiYLW6jb4Yp}CQpSggc8I=uQwQsSnQb(9j}!JQL9ArXEPDL*)}&jQwx)A^$JLS9=8 z{`8fI%E-;VYfCFbHp;S}&F!cr`UvZiIXk863%P?(AX(wI%s!5;zE)FSLj~hK-pZ`I zBp!-B#fm<2M9J>n+SMOfNZK7p9CP}6`@LJ#ZR@A)wYEs;cR$aCnuT^Ls?QbDQxDF1 z$gQ0BF-t)t)Kh!c{z;+4A!NKVckRwQ{+aatmP^Z=hd)qthC+mgkOSwtngfSNpZFVN z&h$Y*6U5QO2A2jE1mspqQslRa$NJ@`d6JE$+YZ#%GZ%0>Y&7aIeI~`{$VXM(%l?lY zn2m?eC9Ku&I4v5CY|N#zbI7~$H!CCk=;ky>OQ}2xU&VvH$^6=OzM?C)x_i|#=n1tx%B)16~yL`McZk*;b4Bm#rGWg zvL2gNeeyrCy8E76G41!7kH7In+p?T)&%OTFZ*c__Z_5MbCu--2{fZ_}O-4p;C)86O z?78BNQye_9T-i!uz(*a{Xa3rhKF>P`q0K+chP&c-K6SkgC#w)Wk1%_^AwRNF$jG8# zIMzBG0t1h)d=!RGn7m`=ezJe?V82PYen0$BSo_WjxCPM#RRqQU_#|y7v6S<)CpnEV zzx-Uu@>rg>huvbkt5iQAaKBkV&r&tn?ULoaxaF$eC6ISs_PMEhX$kui6R(5_SXYZb zQTS{}?XCq(MaG^pd?t8_gMx^ET`Pxnp4NoL>mwiXiAV-;JJ4G!#cO$>k&N6H{>-$(^{9PYpsv7S}F>nm%VQDML5H6Sc>B{X!SxBuou zg&Ct-xFXI1?eIR6x2v-&;@?s2>+`WB}4Z~A^e7$L3iAqwds zW#{@s-HN9&!o1ll|BmJP(q=zwizlxxZuwz&eAy2Ao^F7*RW{9?QcZB0L5OG7+17Ba zoHReTqV5}8!ef2XrtYu|9yMsvzHqBNvye7?a6!pv^OM*jr>ngDyYTp$u=0BZG3#9* z2rTaVIW(Cq`;*RiQh#K4rEDg!=|*egQ_CHN1)gO>BT|`hz-7|8c2}lg1KH**1CD%f znmYs^v6$zs()dhot3giu!D==+es7z!-998YMA+Z*`tHknAj!N5L*@rP&r#QRwrkn9 z-&2dg?8iS%mg(BPadu_nJn7hKITHvfQ(4~aug0mee*LCMJ!(q9lUtYKUAHpvU z`a}Zh&`cOQZ%F4~HJD%P;C_!iG!PDlH~efBA>TrSANsZIbG-N!nov3$l7y=YV3xmF zJp7Y!WFN-SdM(=DQRSf)x|omg@+xFZivn60*F_0s-8n11-F6PBrnPu&Ga6zZK&np( zL1Mvw~dBa4-pxBKokMcN^R!{ice&SPx=6aR?pey`aE3-o9Y(qlmAp7*K@l(O9C zQ-d7)hcd!Kc1$k$3E4K905&-LAKuUAmyaER?-fFi>m7~%o!%Xb)z!B_!C~plI+WE` zU?P=|TJ!96fA2SWyYazL>St&ps=J)p%f(s2r;wZ6p8>lIz6zEbD6M$%2c-Wr*;Gsb@}WJD@I1_O_6ud< z^kc4@b>?r6>|dVZO1ALpzYX1F?e;*;&{H|*Wq~s<-f%O9eHJWZ1ttSy(um)ac@Bs) z;Z)MCf)u0{o=<*9^ZFe(-$47QfBo~we>H18?D%Wk`PRR)O@kw$UMEk?RfacTSad*I z;yxiX2BIopIff`^cxfFk*7Xf|gka_V$%(0!bFnEYKU6q{iRVCQK3+F{icOmNqh)apzeel-GuZE8NLBeG}@wTmU~?{LayP z_jUjuHPT5Rx~ig`#+ysx!&bz7nve9*-afcH>%qKN1t2_6-+`;nJE84_={!rqB}hNs z5|?0w6~{!{)tx?lxeK7Ok~!SBX#n!zE<40ifm}_qPr8_I=UGou*JG_-mDxxo0zW8? z08}%^W~p)aHiD1^qF-th>hh2%t?avyI&U2GUr$iJC-VO|_6W>*ku^T}Ml6Tfj*WsB zrx1y_+1|t5INj!6xBKDVqX27v5z1F)^X|r+)(iTpqe5JLIP1h}j!&X5Ca>`AnR>kC zs#19;vY&?yG6DN?6NkA0de{wp_~pk1l83}kVscmd&xzEp^-sTV`D`$acYA_&OI(WY zA8AF_uSW)zz9%h@TdZ>v1Wl-nj3X1lH?VkzcU6*5+q|IvKLYW$*`|K42(()Gbt)C}i>!25PQ@+mM{2r?r zzRMIrRzA8Y?5763m81Bo>2X^@jfs*__9=Gkc3Wl&pRV>H%+3*|tNkr0v_e`2M6*(= zZ&P%hER9@Yk^Y|c95-}tv3|SGbrEL-TV`nv(i4bEvHWgT71y)Yw=ghX>}aTalh1jz z26nyF=z{9J?|juJysa@vE4}?StE#*E><&Q?w9aguFz+*W;i)Y_52M;@1C{k;)9DM} z3qb4o8My96yk%+sjaHK#ajjyG58GJMI^x78oDp7wA3&+Qr&)xE$rXRi`oVhKMhpR; z?cly7jAo1xYkZFL7{dm>_jqf`F{(D{PE0bK3zf9B12uf|_ zqZIa>&+dX&YlHI349dO^ZxV+4@c8Q8K&(^EROS^bdv_puFUZkF+#*BLMfI7ZNG=I0 z{krnt>>Tv#Jm`K+wPyq>w<$Cw4phfqr;l&jPp$f%F9lTZae!zPNx*Vs!IkUlo{H5L ziH;Dw&REzqp8uCh4zc7}qUP}z`EBl(^#cgPcNYaeCHWh9dC?brx1+8qF{CTD-GOUk z+s0JH^Tn~9{AZpN{uQ@=d_@Tq+_-8<1r&3vOPej&lus%rB^kSvA;#^tU-W;W!%ucg zN5L#Q5|WZTmzuEL?S4QLV)|S0%NUJP`arc_?CRfMu}8M>aD=WBIi87Mgs3sA(_w{*WKO zxetrWjtcfIb@o!;OMk!DU!E}OZ`K{-Y-)QxF83k=<#Ho+dy#^_sd!mGY-3Qpm*1v6 zbv`9OD>zzqCfl|j6=sD2pA1Mtge3AE9D1T~SC|ErNEc8Sh4dq~-G7=d!0G*<#OFG? zM12hwX9DF3TtOjgSf#pRJ;yxSjoU0qb+KWmjs)A)U6%KO)XYPgN3uJ{0A--Y_6Hw* zj*WuMN_8kOpV;Hgi{`LA$Mw>j2VDTY-*TH?o0A^a+nI4I5U!L_k&!E2uL$08*>m(b@kZ~)P2 zzV8A)Ed+)&J>gnoia+8yj?1&b{2v*hX0wkgp&+qHP9a;8%dQLzAEnfU=ep^T;K}0ZsYppup%F?TG}IT5)tOI{OOamZ2T*EHNBh;FhLUi!;6eBx`6_-~WOOKT*kI z-}U{Z{*!MGuYVwzad1j-h!9)i)ilj5(Bs(GbxY-f&$=qr7wQFY0(lmyx)&w8dB7Iajuuha-zPZn$4>BBHdE0dJ@Bdvp+PXlukqz@h0Q2Ddp^lR zEUr)&X;I$K*xXo=cdvBj*&~Q#tpEB{yKz*FeZwCbSKgEBFtlktDNU)WE)d;0#jlkwnraM#tlc|M#oy1IVF!UBQRe ztkS$|U^`CjJ9^CCGkw5B?EZnGSC>D| z4xpkFveAWAOI-i`aD6>U`9(+FL*5hVv%%{>aFW|DT=m)uvgy8ydS;;zXl+wCb!EiP z&G&28fxg9W6O|deW}QPtFtoAyGSCJdG;Vk{tK4J}*S+DUYm{HXLmb6*U(+iU3mgiM zAa9mX8*y`N?!UR?X=2{+A8tRG{`2qYKq+sqQIu;^_CHl7|Bm;4d$u0 zvwg~iD@P=}xBxX~kJ;CCe#(l7S~~a<{O&yoOGd=w|6as*xM8u61XHm0{k?Be4E}1G zhTf5`5xb*}7(mUujz2#qGi#3yoG~E08Nb>fCL!6Ztz$*Z_~hUA!ONp5gz}Lq=JDLG z!rP_3_-&3~K*LNcl{mxQ#@?8F?P88Es}AXe?lWfQ89*;c8i8dPkMW=+z8GI&D(cRa zp-*bvWWk>Kmw&&tC#cwVy$a(=EK#iL_c_VBRroFEO7D~DBQBlzH553!DkX(bLRxjF zT9oOO3W({jnFzU&p=Asy6>_SSP84Dx#_>3E(f!ZNIp&iq*ln83YANZ2@V!xfU!~X$ zZE@-c5`U4;Q>oxq)0u11IV7BV^hJkcvZoz89BG02d6s8)a4{3GEuXoqRfI|oarbpezE8TtL<@pPz3M{(d9UR^j#>kbH>#Z@ zdVSD`8fblC31Pxfwc`X6m%pYRyE+6HTPN+RhJ?Ds^>&Pm3y1A!#5+s2rc2paaHiCt z#Z_)`7=LVgb*hV?E5>5HM#Qwh1~3V?MSnS16Nah0zkLVZvj+#aa4zCdv!EZFqew|Y z^Ii8i#z#`{_YtnS8+PErm+Y48+lp3j{7MdvAFywik3?ma_VciO501Uq`6zlU_XH8g zu;V%o_F6nabv%S^T{l}K)~hJ%U{jPSR*nkdM3XhJV9_ILD3D zL@wjL?BfzySBN^z?M($hHNP4>V;Bj_{yooB>c`RAgwH(0lkTct>D4Xxv{SOA5fWPS^574vy;}*S|fo<~$Q; zTkYJIW2`{X`hbPI(wQk_a^gH9MW}Ga ziDL?{@j~mRH`jT`j*kh}w&_#p?QWI$%sckVT9}=RGCQFE;tzXOvL#8uOl#DV9jmER z*3c%Vn2nuaYI3@SdDwyKXPb9u4W-ho{tX&L=8sS?W^{}Kck{0MUU@gtNflR7yb1IQ zKy2(nG(Po?4^)~tG7>X|YL0A5n$8{Ie?XH9aw6^g1_wIcH|Op(R_9Nn=ZqxZCBptL zt|w2JymZHX69}a&vr6&ZEvEr7ekm1U$~Zzzpl+u`L3%gs3a!cX8St=cQiey z?g~RWJxwQsO#JGpnTE}F|26KJ;WzfFDc9}Q)%~?e1^c65Q3j`j;95~Z6>8zEI9l3z zheOVKH!QCg$|67^Vd zM_8^L86x%A3!K8dAMKxSdVvMEza@imb=_GQ%S8mfKz$ET+M-`(@k6`C}=?bl((r{W`2*1$}|;R~c;wZf6$lj#Ro&FUQlr zNS#Kdu~r<&gu5OK!Bn#QSyp`Ls~G85_}!l0q1&MV$Kcu8fv>k`|6L`C+7tizboHpS z2P;TajL%4!5&>&JNt&cSB;lb$+H~&FEmI6!bE+F1e>jG^wz`SJOg1Z93sWxY;;=Cm z5k4`t*0W?yvsgUiuZ)YmmnT}ht`L(eBs#svFe0tB1WPjWwuma0-FPD zyD?BFx7~?)@B}GPiy8fKJe>h7kR^~MQq@w$Le)~`LdVHyWaxdFd2x%@0;l=vshCK- zdO@oIsZ<7K%zVAl6l%O;C&hEc?C^r(X!kaJg8AL_14D-`wzobuCyq ztD|+K0+YUBlY9DHst&hp}w& zMPzK#1Es_jKW}8mb^I;^nYjCfnPpDLgP+!+C{8t$5L!))^m^#_g?S*0ds%LDJ<8I> zQq?&sytcu7h_+X~rV;dh4EgURNX>t|sCMB*FBS!zQ@Iw*7AUYjGWSamT5!Sn<>z=s z6JWbw%7iswZ;3k2^l}Uf3^}P!~ITlyfhfLutDk5prKBv z$mdtY-dXLz_#fr@EXqkKLIvYSQ{M)c60QqIUF=iVj(V?3pC3=KGv%VR3}6rBM>zCO z+83l|542ScHMeiC+ydR3c{!2}eGr4DBIRkE#qHi<<98RF-W$53Y%TTi^bLh@S&=Bm z2&$S~il&a+1)2nd)bbs1M#jJD`>ipxT6OA>yFPo=^pweG&{YFVki3_+ zdq7J9SO`vnSD_ewDHWXsqvfCRl>vz$cF}b#e$C2}{J|K{t0|+3C8!Iid&^^^Q4~{maY3DO~Uku8w$`Ke@V8Q4CVR+XHGmen3%y zX3uSVS@RI1-N4HVUR6lzBID-wcX0d*!~sqb*xq+L13bywJ| z6qfOgz+IU7OxuWSNE0g54nms2NQ0R!rmio3{bJI-dvLmp!{fXkA=PcYF$+cwA+|M3 zf|dnNTBU}sZ#^5x?EdaEsq2TDOfs@sMz!;KOvOHP>AwRf^ZvnIBcQlnNXR!n#W7XL z-wOQnmBNETN3H}VfkY2e5aBI|!;#m-cNUX~4*5jp z<$)5ek>M<#_OhE;GSW5geE!!D6FiwznEhyXj3~ z4eSm*xBUm%A!jjjB>GS(NmUErw1T0|$1XN~6-k?@Kg3;m!sBb>q}8`>@H`$n>p=sr z00F%g%pH$KM@kDif@XRJ^Z>={T7Y-LyIGt^Ju7@Png}7DDJ`zWS#M0mvVy{OJg4Q7 z+muKBd>XZcPHG$Zy>s-F%9icWs*YcLaSu8tfWbpx;Meqm9^c@m{1@x7`?tEn%eFL+ zx8OH=?tASCO%Y;z2UBt~)eBWCcGcL^vO+ZD@cU7PI)s8*9i-C^?g6U~IFReb8)>Ji zzDB7|KrWeStmF5Jv%ZmtX`WbBlv{)N$l-zIKV_49Zu!PczfaRNq9LY;=eRNqd%KvE zn2P7TQYeN9<0!-;QoDX7O~5^&YQg^YvMe%dZF-b9e>tWk$S46elH&UKG?38bDF?{p z{8^QhlENg$$UpLeSApFe_O9<~i%Y-Qnr{-0Y;-3AhEasZ<;`Py^9r}={YWVlV-%UC zF0rla^$7;taSuu*&=((!iy(UtI#0^H)-~B1B+5ct*6y<^Q7JKjwXI>zGG|bKUTio> zrmI=Zq5yVlaHOKSPdqVG;-F~+oqhexNia)d9m==az#cqWB=BHZ5(|7m?D@gz`*M%a z!qGh`&VT%R-9Iv#Ju+$lx5fIgxR(8go6(InLZb3FeuKI^s0ItkasmHMrZf9r&`vnP zAL*NoObATu8B`R>jL-w&U<$w4rYLrbmylfW2h65064w7Wl@WF$t7vs0C{mV=LFBUB?8=_N~!H9d;&n z(V!L;g^QrrqEjvkFsSO{>A;{50-AD&rotGAi2{cvJ)$wCVtm_JppE zZ}M3BwBgR8#Kr33Yfs{cxF*erLW%vV1fqHExt7iySY^AiZrzz*?PH3~UIkf$W|4$p z#iZ-X{jI6@c%y38;~!%&x4vY3*ze+rnvtYNPqFWe)H=ezDZ*XT?2O?p`$c(ogu&qb zjy<1P^13U(-FLso6-6zUB*BLqBe9Y6fH9FV7xRl9qtB%RWvf{QoCVgDM5K;t+`e0T z%z;{=e)F?Wc=Mwd1yF53L=A-Dje|L)UUW942))8B__JK3z-7sq|g?bSJ{b6EsB}{1QRvqy=-}9^b#?h`K_-pRwZd;xT zvBo>AQXWR;@Zf6)u#;`q)B~^I?oWDicuobvCSo+XS||MomoSpmYn+%?_kp2smTA%reZ<&9FnZjuJSZ9Eoq$% zZ5}&k(_+p^O2y=+DmqQTmv4md1A0W@12t=A+2b|8A%Skzg{;`>HZ7Z6XcN+CNsfX7adjS?)DA;DuW zm?gP2bIpDGK-EDC>5UcoOARuW#gy;i@>puavemA7c8%fU^eSzs4|#hY^i7(A!lYNQ zfNNUpQW6g(7e7h{>i7oTHD=uh5k>VR{QLD=%mt9>oT`lBdyCHhfJ*lD>s7(w^+0Hrr+S z>thUk@OQBW_uNh%^Aw*N%*#6<(ikf-^{Ht0 zF*xIJ`h}>Z$rB;%Oz=e^V8CU~M2I~OhMq?&HRfS9h)f~m;uv@wY0mZdm3eE$M2v-8 zNx9tnDWTmLu^d`W>pMkn*QOqk##t!c7&G z|6NKWPm%#;TM-E(_DcY`${ZfQmHl@pS`dXucqOPLp$~V~5j3%OBz_qEksu~!!ZNnZwMNZM zTSXgIhLr(f^s)%);P)Y^@p~e>*NR{wKWui29ZWeO><$s;VAzi+kIv_io{7wZj8b3M zvossGtF|c`KayFKNR}=$CjnlX<+xQ_T=)Gs1l`g9%D_Z)i%n2ycu8Kkg#L8#GxkY>%gIs!N0 zJzS75e|x^Y{Mok8yP8bpzb}lF>5}keSF^``j|Ft6t=1XlcOUdkM)u1T0UBhyXI1)) ziQzxwykT)(A|bpXlvoo-|t=3)v*Cnj=vp z-FWyP5Pmo4e1FZiG_KK9j=QIC!s_>#2hqgO7M~$+-eEc4hDmrQi756%kY>k zQ!1JuT}^gfQ2nvK;TpV`N{=34Q0UMY;F0fCF?{M~!;quh_pw-cYBq=9i{rB3TAhGa z>%LmEph;yu5-Qi3#+%Y{1YIQDH!b1IUm+-{A$i=AR4ER-i~cRE_=S$jiwX1klZNPH zRCTOYg?XmZT8X6ZrBClq4$m)L`8>B7@X78s>Sw5({5=wS{!h{y0Z&Z*RH!gk!kLkI zLS2ho+HntK+sUP85V5wd&xUnVN^@p%^4wZ@sSyCa@K`129+%)Mc;Tb; zco)~&#uDYrp~OABfzpO&P&v=-rPBthKR7%DS9jab%A^be({MB0!`7)8ja?|=O2na3 z$!qTd(|0o;#49^MMKz2Rs#m-X%l`17RYB1W6%i^jZ0&H0gkLZ5R6*O6Oj5K$DuXO= zM`7us1~#XVZ1X4C80jB}>i~?JYzphY9yP1=5G1X%GPh@wqZ3ODN~_YzS1SMD!nK_l zN;&a9)|5})noKk$m_mc$+yNm~I+NYHvdO15@?_eJE`zyl)aZjA#6TfQ5)Hp46%C)S z=*w@+s;}t7-6$Lk*f5oIer6T(o)axC#3>rssYmpSdRZ$8b8`pW*+k3RcTHZN>o#`c z3%QMI5L_dy;^u%9*{4Fyex435twu(`FcTXPzz59vME~UW7s-6didW_kgF54${o>9! zmbl`v0zV{eXU0;HabC{ZJqO`tv>9bG-sHx=TMNp^Ngll``;e>#+-359JzC1?S?tI4 zP69%*wFd-lL1X-`G23poat(@Tbs$oBuIPhZI#IRJBRl_U@zGyF~^B8 z$jG6)sdQ8v9ZuIp&BmF~p6t$~-7HQT`Lov4_QA@vUDh=Fyd=7mW>`(GwZ}cRxptnj z?7is!=3Ff9fK% zb(ZYqm&KJsrtScm%NTQ4N=pm#-3TkKe=XkTxVR=CrfAn83JmJu#AkDlHH9{Fo*|+K z3b_O+r4k5O+NT)RWUyLf{$zH|upUS9_Yo!$4_Ioy7ZB2L@rX)_qVtY%&8D!8!{S)< z^{c0|Y&hSqIlpejgoC%ATxA8a5oYtt!zs^O`Hq zq&J&)U6mCPq>rN=Ei@!8qH9c4jlx2KYrrTMOPB8NK^2nKUv%dI zIx#e6?Jh1nkLNtFc8WV=_DAw2y}MB=ySkdO7Shk9Np|pAS5esg5hoN=ZL7`3kX3zu z9dnuN=l8|QvagF(<>rd6I0G%cbdQHJK5_)fV+t?lNRP`E6C0W9qOLfgn8&XR2HO6; zU?df56P9;gSi5oF8>8@eiMG{3Ag&+(EVi^l_ge}J>kJvA8Q^VzR zPquP9!<%q1eiIkW<0M1ej@4hNrh{PS0)FbSV&Oqiu91gJ8a~1jtwU z!`yHUbqL*NBX&VvsNGZf24heM1Q3{aHcC z#$)e4P;G_K`xE-L8#J~U8q`GT$Y!&6@spkv>hVNBUE_)G#{aBAJ-1rU)kkqFmSgtL zRXq0Bu!9ggVD}zz&GUZ5`@6{1%95xu!^lj1clLd)>ln55m1J^1Z6ykD1|49omb8{F zE9X-+w9nv^c64!EyPb#@K!_`Ba$4|I&=$1ed*|y$;2SvXd}3G=eizf4q`=KRa~~?F zz*QG8gP;A`y!=zkM+VxCnXs30qpV&J`tvO0L}kLU{Yb;!E2C_mMfAS^h~D!a9frxf zgs>+}V9|;r9a9`MSD~raAQ%AG07)$-DFZ_3^WBjOxO>&26aXvHv%Afgr!$nEo%Erk z^K8xHIx>IBf&O~uJ**Pg$8vQgl0U=-JmDw4BYEKM*D>qA1ECUwaojxu*Bi~iM(5U=i-Wm z=Lj-dn7GBEyc4KHjA1iAa=tUd|IX)o`>4ro9kVJ_iBRr5>HShNTJw&UIy1vUFnx*yLz85Kj zRBpF9-k@83#88YT%w4BQ999tu#6`D-0YB{ZrwsB*s*K?4NW8;a6M0Ry1{_2+QeZ8h zcxo&W-mbG_((Za~j4w62P*dY0W}*h4*Oy{rXX_Ad!z@HosTPBc2NUFL(pO?(ekkhf${)ijO z!t!5ELH5Q`$;aO;EEI6y5krI9{YK~GpmJyT+%Ogqk+`hLM^3EM7Q?5hUH6p_?`u&B z)w?SO@j#X$hV6KQrE$2TSt(YLO`cI6ispVp=4v$lvAxbvJ1?{^Q_%|SY79!;tWWCX z$mqUP%XL+7@bcFYvFQ9b=#p_-=*v?!>xe zG8?lTx|2~S%uSz@UkpET5%5|_J_wo=)7q0v51*2jwjwWWZuS<~ySK;{!W<-G4C!xfyu^*cSttZWk?P$Qo9J@v7E`uC>n2w z17&A7IWXLD+7oBiHwZ|ea@e2~_B`7rt1x{Br%85>q3kc?%8<~D$h=0j@Ltz;4xfSF z*wxxvg#h2g^ecQdVvSm=NJS};s3Ixiln6yBFcvXNxTNU(L%g{mTQhr2I8@h2NP-P) zfGyerzUcfIf4dJKc6O7N9?UYoD!bB5Tlv1uQyH1Z^FT7yD#eg-rdZjgXd?3_Y4G#{VTF%fY5(kOr}e}DEy z(cC#iI^CS-p|$@={iL^Tx;FZ@Eh6Lrmr;ZIWZFQ_8x(Lvc0UC#vrSsY=Ge^v))~DU zO*FAL7_Vt2@S*H2&`ly(Y%1k@PK@y`bkt%XQ-TOeZk6Jw98fZ9mhRJ4Y0u0;z90aU zvcMUR0;b=t>pA+}t`w(&WX92A*S<9@-~AaLNXmWVj^%X?nUIyY>1{{zy2MEl_&#ZS zUFeyNrdeT(B%yjciIs|Us!Sp!CdwyP()ds~FPEtOGDVg`see0i6I*km^^=E5+iOnz zVqdfiLt9K=0a;$N8+a{tYQOfV+Vg0;1{CeJECEk&dj;5Y3zhCVEn@9g$x7|KLGph7sMZq}9bK9Y6S9cs zj--N234?|+o#^7AH{AZT>~6X>T$c;+?hSk`>%dSM{sj_=baqY-YT7>>`NjVST=?Em zvYN_7BQzmcIhg^=WZ9DW(*BuiV4nA1x~ei&U@u|aKgFN-sMVKg=*$7t5u-d_^nm$t6hf)~}3rnUa}1ho*l z;()O(XK9+#4)+P#!rv^5hvz((;ob|(_ zDc&E-bcBa1z$bv+3^X9>fxyMP-zO>4MPXUzaopmcSZR7>pi<+z^SBvqzQh=3OzyO) z>6I`)&@`CN-Y5LDpk zSk$bvJytD{K1Go-nZVNJ9VM9)ZWw4MZwPdX@jWd*WN8&II*CtlB{YT2M-;_#%`ZZ9 zI+`zX5X~TQ??sXt=c(8hNgzP$(#TEW3!j~F3`+4wva34 zdKK84mP^qJf_f%pzp^&i0L-a?wW4jA0ND9HX?H#jgnHN&{=p)`7@0gLvio}N84b_< zf}@?PGI(IGJ5-4>R?AF+n7pKBkI+oVT<4%y_G=%uF)5Q$05b)boTI=YA%#RiCay_Z zE?241A9fQ$zk>D&8(M<;6+u_OZj0Da=G1)#@R_+&n!2;0^X^%F{9A>zanMNV?AE-B z5!MNo76=hds^JAU;plMpkLN_NDcv}IHilO;YE+t(*ktsO!QCH=kcxbPqq9mDg{(Sh z=N+~`Yxp{Z&x)y&gTuO1%8t5u@D81>%eX=(e3-sEM&C6=i33G~J93XKa`O4bqse?9 zM_O0(hs2p8O$WUAUwxP5y~7wLTrb~(BAS`b%Pb)-Jaf>%;$LVE5BPo0El&c4?<;g6 z@o*0&W>rxT)ab+#afYT3}Iz~clGvZRMA{>Yzg*qWF>RT8k8KeXxwae^^ zgXp;O`P<-K9u1(wm~dB)vuD@P-1$%KGV>X(X6F&p6HCkn&_Mv&&Xbr_ooF=0l(U2~ z>x2U4aOALM=IIco1re5O=Sd*&K2X~?SXwg}I&{cTn9%Hn-t*~2vZVIWUK-m$1zR?R zv3Gz-u;+qT6~O?9!BFIs>71+Zv|J8zel*Qwg|+6l7k(Dh5eSk~osO})$MqjXY*GC!%3q%I`_U8*3d zM%U=8aTeMjF>cH>%2xvu^1MJp36WikRWjeO#|s;jsr` z=I&B&+PNu9xhW=d2l+$jRJ5JmmvRT2mDwPfG9Vo*g~V_z%f=XOy z2sRu>mMcEqPP%fzs4!MpYkJ{UN;e1}Dz(e0Z{VoF+n$$|W#(wHA)Bi?+nfey0ujM* z`11#`FjYt}7H>=yYp7d9u_Xg7Qr}-H#lk=0n(1^zBl5LpW?^F;{te`khTo5L4+|22 zL>TnCmZG1lJ$y@1&q~jh<-RRmm7)YqKzrB;uAj5mJ;!d`8BlY4(7cNRG14xR0Lau* zPvh4-fw6pwuQI!qdQm*4ACW+;CzC*UX9&Ju7cjv3NaL>W=yuwC-;rw`B@S%U@e-kurqxli%tcECJy8_LQr>L7n$LHBLZ2;(Rk;q zq&Kbl?v@+DvlTVS22FS@!q`aH7|m@_NqYN3@mzooHr5#(c*x|SXEmnq(qU)Iv+-oC zZ?1snF^b%e17@=nwc3_X&1Q805i0t+0&F-)wL%QI{W_(58`_4tgdUfiE5b>KQ)lAjoy(v`WJ$4bYV;udYY!7u?cd@L)IaSUQQ zc03u=h1p#GLqhRuBAj}#dZVVP&UMKNY}$QKK!ARSE|U@+ed5&QpME_Ovb7BZGcvk% z&>aL{9CcSOIMpf+WysAIK6gQq@vz?z+<9d0pd`kiY^WulGBQiCAAq=juRMv{6TewT zA-}iJc5z&nb!a1-r%tAQ;xW6QbaOgpN!h^w<7~k0RBONE7Qlz4_R(V}q?plHCJ=j^W?fUjy6kW2g>hU$V&})ckCnacDNuw^(hgvnOb5T6c z_{wCR%QsG}K)qZFz%%H(NaJ+(@Dqp4EpKQIiog{R zufkt1UIGRUd*Oq|jGLbgJ!79ePq~iwYqI4{<{DD}B3?6M;-m^+P{q?hz+TjD~I~6XlX}&-<}Y|=sS*{&J2U**1iv@Tk?KzJ7y@- zhd6Pn(&uiOeWpK5{?o*kVz)%dg;;=%PVx;eRwg-O*A|>J;ZSN4n8tb@j;Wq>1KJX5 z6G_!IvogOXA~vH!#)aAH@n~>kl7mSDqMHwz)Dp!C|1@sokCntS5xZjX#&fTu?Af=2 ze|{mBw&0!6v(0YqMZ@!ba#z)5Tywp@T0TZh{{i6Jn=|+$M7PHqk-4}N&)y<*O6o<( z?e#}Vq5c#&s+!MAxb9B1m}{m=td$7hU~+GfbGj7&4kP6If@}+Cq&IZ~L<2vT{f46j zUTH+sW}{Oz*>cz}O4Gt*Qq$RlmVS79sRrDt7b>j8@}*@%GD(>TConKWTzAC|}@FZ(r>T1#8 zB7<*dM*8N}Nlc4R=V>THwr)D11-#RfM}L_{DvxrHb*;`jjSmZ#tlD_Rc;B04q|cAy zMay&q?2LN9T=UY5n6;fKq-V35uTXWIm+@e7!*-3pk;WU6VN}!MBB=iyro6Bmuc*Rk z5(8hqDp)HqucOJ>7a6T>BokvAj0`PJs))Ouw=%`E%{_WezYxO(^6SlkzgSZ9Uu$>s zl!889!GM0$3Z-lKC3V-2l*$~%VG;=^ewv^NIecgs#0M_Z#uReN!kEpno#}g?i|hRb z>Vz5&u>%Y)ymVfc3GY8w82*IMHV(~g+?;%V_xTN-Z{75@v%}PyFxTePCs7)guFv-H zYr8zC!jbA12|kgfFxF4Fq}W*4LlVxT`f>;I1XT2Bx4to4a}(@1@pfiAJI&N-&*bCJ zdg`*%2=Wvoy-g3<(5jFavV|;ZXhd@hG0>9s?az#W77E}(;0cu>eSK`Q^Tg&D(bsY2 zuTEC{g_T8=ty$z_9dvlEYhXp3QS7oz);hO5%w`ZTga)^oUKma0I|;bOlmew|zmxG` z7?J9`uSo%`(X}e+oVTdgt@vG`YVv;8%p=12Lq5~VQ2-2$GlFE_DgAgFq3uDVo**-- zw+h;~)QVk;pg0j9G6UQTW|gS)b_oI0MW;?(8731kZ)<(p#qi(tn4V574!$0)k5HETlvIKg|H`o&^~fKN7#n>1J_ zn0ZuBl$-`2nZz<(mO9!fz^}ci6c59{|`u zC%;7+si&Sh>ba-sg7DY#u%;v2&gW+>tj3n>%Z5W`!&1rMajd5quQpp; zsyEP9I|%Dza_tLW z;XB{@7MqPcaJa_DRK(&dfNK<6+LGSl_ElhyY;vF-TrR?ag!IXiVzp~$*oY&LJpwrJoUUl_Bl^Om70UL@0IsvBEyl`a822AtYVl? zgiIY9?VQ(}ZO+ykXsZd`Qr{rEcpbryMlgH3xON*=At^N<{0FsVyfRr-X5Rh z>gT6X)?dcV+Z2(h+svmA0c1k++&%|jV0`bGjOb97p1#4IQ%>zw)%^**NpwfhJg7|5 zT`4AEA*L2F|0ueh6=}{y+^J`{>5+fJ4}b6s4QDVuqq?-l`~JPZ$@QQ9d5lkqG-t*) zsM1DemaxWh{N^QEN9WN?yUfLw*}~G74M7P=r-M(3y`y||k;+Z080QC)e6|=G+4ivB zbi7*gJhkok(N@k=JC4n|N1HyB^0aRYa*@dw+lld^RFv-y$A&|RVI{UKb_74^b>+>) zLM191kE~FN0$jH@DpPSlmgcmY87&RM-|$fPL3sB%3P54UdA2=lI%PZc+_;mH%*E6) zrICk)o^=;2f6XfmucThPa|V}V%kji;v|>11iI`6W=N(&_<8-Ud8?`#F*?>G7n=JBT zh|~}6@e`qP=>nO{K@8>U3>Tx>P(K~wC#BapG0ab+d2tjU?@thlk?tg;eM@JjcL1gj z0d(Y$OC6a6>?J&O{6LVA)d3yd<~VK(>c{~qI_8h#D-wc^z4-$l7J?s_@6%%FrHS}Z z{w%9M`e%IekyBydW8P-<`dj(XU;D3Fz3=^)yhUu3`Fxv1Kq`wNHWtUse8QcdzL|4h ze3~T7sl>$=p2GDnNx<`4=P{+2h0olEolU@nnBR7qbiCnmTX}6S=b0VH!&^Cz?_`|c zbNE(Rl+g*dq<_LrRJ7nmN~uWZ9gc;y$go;6EG34;L|9A=)kuTIFB)_zkx;QpVge2! zOa#_q>Tk&I=N@tqT9IWpSDHqsyWr~Yd1cSTo>O)dwj8Xha;aF%lSPJR=Ba0%T3!gh z_cRL6ArHH{saV6I*l;v494;FU%~<9VgY%9ZmvOGu=H+^wX0w3|3x9u!si^yVg#h|cG>YzEZ<6fmSL*lGoQ=7w^&;hO z|0BNo^m&Z6SeJ6`gCFHRfAw!Mf5Qo4Z4(*CTzZ*O96@D?ig-#!!q_TxEZ(xr!Y|y- z<~Lu)Y}BY&s9;Dm^v~dxc&*CvPu@=X=G8EUO9U&P%p0~+Ya+%NdXDWSpye z@}?r0$M|B~O$VwQ^|JcJLOB+eBRG->Yq78r2f<%T42u=ZLLyW}nKho-ilrP0W#dUy zgWwzOj?{L=j*i@Ua<8PhCo_h0WsdDvHmO?^+P~5RPg9kqD!GQz=YoO5iQ!1ua=2_+t5{|d!KtI>axP^lFSY9IH5y3T?rrfI z)q_%e$gV&lDu6M>o9md@Un4b!rJ0Dv;hWiD4iPutn(vS6WnbvJFY7;okN1_YhmwG! z@CH}c17O7B$pJq@`eK#dl>15eo$kSh=JpRN$T3*@QO`LjZjjM52f;#vK7nY+s{8&8 zu_Neu1Y->+8n5EN_P_A`m(F3M2%EMjU-v$?@A@si|IjwG5B-=MudQ|JatW5>!s5?FRP!8p?L2yR z6IW}7S^jeg@v#MFZaYMBbPfu{p3|_%(|O3eBh58T+jX8yAiDJs+mD=LFZ0wq?0RKK zm2IzV_+a&$-G(Az?fPZ*oU&Ua|C;J)dZkr(7&As#vBIH_)vs7qE0&oUa+Hm|j6Z&C zi&JNt)S?`7C_~Bzg_|S9If{s%dzO568z&Lh9h&9L((O16z^i_K>g;js=i}j0^cC@O zKMrVMEVy*N?#}c4lvv;?Ljc=bn8=9rTQX)P_~?^PaDAk^z-3f&qj&ug4#9}T%f1+W zoS`?v153jPZ;Dy={WIBzFX6;6Z&H40_nSQPm2dFMsZDHTF|8Jr;~!?@?mrKg9rGLO zh|Rcs?o}Rr`8eYF+x;{v9ZOf zA}%!8*K*-fGt}}Q*~)o%JLjc6N2BSHw)Xn)`w|3F^xhL&O0lq-z@ezH_=&JwSp0=V zSSVRIb&2MWUL-lc&8#SMR+x*Rgusgzs6X^7*}caoedK1CNpPtrQzdml=+it*l`(gUlwO zBBx+-hltQtVWXwIvgdhfC+FcU$Fn<*-G)O_#pHcqQc(|-kd8-VA&!Kll5jK<4kyBD z66*NNCCfq#3yEQ&Y{{QFMeUECVJ**Ds935Zl#4-|B7#@Q+8K@SzlNOMrTY21(YbPA z^}~|Rw)3=drBx_^ruQtr?*`^l&#ORxH&&?b}% za}Cps=B!~YHXJEg)+&b8vSp=Wsl>%xf9E;9-sHs>Yb23D#b89Jo_-Ct{vz|GT^i+C zxbXz((c__m$oJ3aR$|R*nF?YprH8(cJ9m~`EH|$tY~J)fF6lg0@_n8|PncyOw4VyB zHj0n?ZQ7Mg&bulKU{Y*OKQ?)=J}Gh~gE$BG^zJKj3@z`H39i#REEhuRh3!;%qvm;fC)Dzv-gR8Ad$d(F=@dy=>CV`b zkl>328w>M^;bZ-g)p#4)2P1;Y`C z7Wsk^<+y!il|H(YX^y7b844`gE46qDpq39@{1y-W;Wv2kLQ2VkHHN!?<*)L%dpFs3 zop~dy*ftf3X#07p#s>tS2$k5-IK2(cjAS+rqq$5`z8f0&(mB4@0Np)Phv#=4k8V32 z+i_g1d0eYAN59Vv?FfI^?t#R@Yz#*d%h5Pk&ef6>2|i(|WLPLrd)35HaT)a=y~vz+ zDsdPnZi+-!NAPontU&HH6&lu1e{r4W#X{4-Wt|$ljDU^z;&mB~HXlodYjKE` zR|>&jED4Ko(V`m*l}MN=8+c}&Xmgh&u~-R%KV2b+xk9SY^3YNZU>+CBcr^!`kDcM# z6RV^K8d=BsE3G`VT9>LieqH383?>@xxvBO+Gzrj;4 zUL> z7&+H-3{8XLkbU>F7Y!QbY{su`{~nM1tFQ6Wg*2?&u2gvMzyF_e-DiJ+-HmN##j{}A zl&~~)t~-;jQ^QY+v0SCdkR-+U?ZHT~=+8H_owC_hUaKijZ99Iv<9KP;(`qV`YA>_j znY_~}>)BA!>!A0JB*Kv-Vy$G01YdCVml9#V!0lHfVI~fB^dy4zsg00_DEbHTLikg{ z=@B~!?X zn_n@)eBtu1mO`w*S~jfCL@bpJu@Q1Sne)`LjO|vN^UXG|G@7(pDYK7!jrPVf_>~pP z5&Y!GZ|Al9evWU&C%7d$#fOjo9zXcjW3;WszVrgo|M)*py6y(%@;Z&zPLro88HUvg z{F%?(%@+@S5a&8DYw6Cv85Mqx;$s;hD+lrMKBI3YRm%$DdMCz8LE@uvr^RZL!-`OWH^=xM-t0gDPk!$tds(XXR(O)tFeUk z+$dQ7auiCD#(C1cCQgcBxOCQJhw@y@hfI9K6-_%XfN}PUX*@fvoY}1w^D9;AsV^+Q z_HqHfNCrAjtHAEJypn48$_j;JMW`5MA+oH*hSjoRr5v$VHmp`G3l&Qe3z;fes?=T1 zPMWdaN_n->WFyOoUwj_E^+#YMP~}7Kzl|p!{0*MbYlvOWBj#pS-u;)k)_j2r-~A@r zO>ldA#LqlI7DF?)cr{$N6!V!+-oqc?{0p4+i$vnP2uDH2x4e(!C*238o1Tx01d*Qt zFLSk!fCo+mmcbo(2XE|?5jSOWhyUO<;$g(E90)WTMf0GaJE|r(F}F2d0XVG?@NHUhGam$@Yc;@^YR3xn5N~HG{2ap|+z~TE2VG|o_UZ&?p zc5wSI?s*>DaXhi@xm5S~mSS=Vn|AvfbqvLDf5F57@4glZM-$<2DPlRXtdtCku?d;| z!qpGLUkH8&gHSYnc@1;)Glf)@b_cVs+EoA@_-?0judV^bS97qHDNCutq>fse7jeH9 zU*X?PA2#&_%O8?_d13XHfO?#@hJ{#IOAO1U;Px+CQ`!ORO~Ft7spbLYFoBPCOxkeb;E}hZ z47jh1wr>_;Z#9@6n3otlx%PPh-O|UtWL?jt(lOco$#nPA9Q+VQPjFGO+?~FJ|LQ;B z+1EEoqL7h);5Ys%*L?OD@M(isJd5p%XsN=@_pFd_)LDOegD4VWD`5sd1%wwk^4_B? z-?@V3F6_MnQcnTj^*p)jd34utYR{2170E)gkBSz{Gy34WaY*pZM4>ycgWy{&MJyM| zy`?y~`tyB)AG-7mi46)#B+L!*J{XtOn9y89uSK`%ePQhbe!uRZ?xCgxOumC1g&h@+ zDI}SrmIZ6yDq{VXFRZ@rtl(BMw3}NH!s3#uH7rGj<&t5w9I;X|tW-kGUyb1MqZc{z z_yyKC+gxmUP8-9S*@%VPN^Bjyv=Y23tBYlxTfC2_&GqCeUCZA!Myi8Z|FQhkGjqCcX6<-BmZ=l+ zGE~*Nsv*E+B;dY@CHvqE!>-PV+PiQ-8L+=J!eE2O*aTl6(r}1or%6LaM*@-+#fjl# z`O}oY`H%SSi)S$+;2ih=h2Q4-U;GQG&xpt<`J6^&jX1JYtmj>yzJ?2HWj3DK#O$TT zrd>m2p~Us?KEm;L9|>qYdc!x*)*VmpDv$2C0OV;Xl7ex4E3vyVe)#kx5=yaQH4%

    $?i=O`B{9>Pwrd0SptI6T3+S%*9%l`$l`1>=dD?_=;Ehg?zAFS@drds` zVjOqP!?sr%aYR0ou-kStI<3(F1Tb9a} zYQ?ho=s7Mueu2yw>K-<8IF-Y?BTPK@(0)l+yYLF}xmVb6mTMLa)%)JVCRGfcQ8O#F z&(qAb*pAW%>+R>L!CoENSEk;_PsKkDa`{K`@xbr;mxGSmRwWW7z;R_dWt1j5 z0HYw|pFgZoM=kIfcm0WUWhl1V2W%9)2y-^$=tKXKum0!_tTh;)GJp3^uyNDRv;Mu) z96nm%-lHidDS>!8$@eHsP=MS~nz78?JRe4NiC_VrJ5&t2sdBmjPwj>z-`QGd*fBZ1 zW~X9|Pba~rkzgZXE)kBza3l#Mu9lKQ@H+{RT|m`f}(kzpq4ECE%F`eL77u=uKB z+;(1!+RjzUoF_jtM}E^G)*nAZJF>ye_Y^I-u&2S|*BtD4Wm5yDKQ)H;+<7SE39`b) z*O2i~z2b@_pCk0!o1(?JYQsR0rNkDNKVr3FSgJ%UmWA0QLbIHWC)Y`V2C$vOd8eGp zwL7^=4U~OO>5sq1=3a(Z!!;+ao$-jC9{4_K%Y6L%Z_;}nB zs!4o2AoBwrw@h%>uli6>8SA$6wgL@KMA3m{-RN~(!g$=jju}9pG6Hj`V=4#(s(L?7 zWq(VuQ(?w>?tJcxJpRXzkc%PmIq};4oIm#SG#_0@z2kJLO@2q2`#ydL6$v$bE1?^% zGj|WCs3_hjUIc3lO|PuC952_DM|V9ZcRlrvyYKrFshxVhE$W65REjA)M`FWTVp&Nj zhH@B|5?Cx7=1YdsUW4e>9oTDv0bhyX_!1mnz$Xzt_xP^hdotf?+<~@pw6hSGm*00I ztuwopUc%Sx%w0 zZud_G9>DgEN>GdmA9SCdoUpo&{g!_s&0)GDXbyi+9>a=l@snr1#P|N_>ojsOnq!u3 zVf*giB()W+I+DoK)`;&srBsh@^T54JSPe+IPEWq+C>`%X3=Y_7dETfiPwjf1-c#1= z9&Hh;EU$#aj5EVsVvD7W5ogj()t=RTD5ypmCD^C_xVmVk+vwZdE!suRnJWu;tvRV<4o z!+hCNj!Z~Us*+}odg|Hnu5u*pP}8jOr9)p!?6X<9=V^)2L-%C z73o<25ms2H<)?n0lF|IMpO0n0)18Ko_fN_iY?>Rtu;Z!&f%XIcx)}Z|+}1r3`K0}L z>FHlPE!}++*+K zPXXT*7RrWl?x}y}Ipl>4R1-@nHrOI`OFej}q0PJ8iGzb7ijkGk4K?{45*KUF7_Bi;di~=Yty`$A&{k<~VW3Vb+e#(Z~yhQq=Wb zXEs1_-xGndu~egwqgaT8@UK=Z%Vo=QIe>erB}*v^1@GJ`8J;{gG?IwTdde9OXPgd{ z;39F%XdQp*al*iLIC9f9e7|%J#`%Ff`9a9NE9K+ywfwin$DO^*I>va8@3*AC- zAHyL)e>|kaV2Gj2XxHV@?zrQ9F3nIDbzo!anA>Jfdgrjq zKFWm}IfQ*c!wY`G^2A&s?(}E4{(FC)Z@#=98gq={#$W&UnR(Z{Nj6`{s^d_!%f)vP*_j@0TRL;QV=z%b=^c%Q)!48c z8x*->g=*b&TNxEeU2nCJ&RumMNY>WhZw)5(Aa9S``uSL@>6%w%6+i@ zK6nCc-xK_HQNjzuJ3VP+m^)OZv^Gncds+%)yq%y0Qq&6rq+W=bOsYb>;b*r&bF| zK2h7ZS*LLO`>cK?4j`URl5a7RFp(z?qqw@b{n${A!?4g&By7KM5!cGl$lzTN{$PcL zRC|fImWQT7ONH#^P3(FdswLW)3qtHWoIMWsMHAR-rFzReVSB;lqHFLCNSmvK!+ zOhL;C@!mRm>LL6>m2$~&==NKAD82#feAjT8p@~&GhA$@ZlMd;INz?2_#-mZE;$zwW zE0x~VqalVxqJ=3G19B>D6ao_Vst?s^*m4jr1|qwim0 zX*DSZL82-+`8}*FJnH?5xUZauvuI2Bb_R@Yq zcLBK5`MKYt=xp}VABV5Sl3_kEtdwGw%BHaTmidyUTryZ|@aoCM zZr{&6z1hl^rvJ~YD{H-3a2 zEfY)D>+*!rh&dUt?{Nw~)&qF)t@81{5V+HQC}SpKT=g7)p*tFD91=-JuIe72dDjsI zQDszYKO)PiW8hCi>af$^>pMzd6isV+*UrP7{Mt9URCidPvwY*Nto_--g>G$S5r>bJhcW$3V11mzmw!ECV<#b*Pn@D zEeiPkPOQIJWcU}7uxMj8>MYs_xcx}N%)(qjGe@hD()2+Axgz{Xl`e+AGlIKScmZ{< zG%{tbo?&uFBkg7WJBlE6MOR)P>iAh9@M&S~!)EYMPV@v^fogDO5+hWMVKx#LV#|CI zdJ&dN5sM{Zsj&R>iD9lBQK>{|y-oY_9zV>~56lND(ckkVNyLuOq%e$Ys(H=jHkerG9G@g$K_gX4r0W&?; z)d?`ZA-bxAWh|93Z@>SNZ)Y#S@Nkb&^8n~tD-g5D4*GV2m% z!#jmW9I=~woH1k?#%8tpEPuNY{-zH&{-#1hg*Ajq+l5(uo%r8tSixOb`pkD)bHiBg z)Q4dpoy@-1UPoNXK*M2Tai{MbY6UA%-7%PmLBT)yKY z>}iRJyf;*3WQqF95b$IFe$aqVd8^m$Pr1p2c>3)q10v&Ld?P{t?e0n2hkc|!WvJsy zD2#Y*-_K)5BKNR-0n4p}#gxu7y%?@BJKXsA7x>Oo7l^FEDjfag-^AT<51KYfG$ZyY zjZ&2a*G)BfRn&*gyH1tMZRN!Vyi|u;0qE&yzmBVqq38w*ZvSj7ti*6QhNZX={76_R zb#VJ(qi&~ZCouuPu0>`)cr+g8!&KsQvBJ(Pm&q&z@~+dbAK=C3v)yX-w)jSt z`O~k_`u>klV@O1~?cI0tjfJ~0x$hSJy2CX`@Y8<29=DE8M+BD>czEcw``!ZwDUH#q z#zq@hd7DCjVj|GkI;Tj#&)t^?m;?^mUn&tD69R}FfF~YCC3HTT5jzVz2e-mUUjKc5 z^u0%MVljEf>L)*k|HS9W(*|YDsrUx1l-BC7D<@pAjsT10DUD2-F zxfix@`-{51iC{5?V+kz9uowwTg_}Pg6SnLmVbjiRBqTQI4^_n#7GG6E$6hgZTaCfq zxWd+B=V@i0jKcL-`mBD~z|+vsxpz79tR0?5W)gNYN9Kw|q4Py--)qgy3NNEmRqzTb z9#n`4@3Cx6$nZzO^3Nxx5PVx$f6HPy3W>hNP>u~2*!spv>d#!jN2c&rLT|yYgKYQX=XfK`yEgH+zfP@IBNxkEH!bnn9iL^(m$A6MDwVz| zewqx_kv`PN0SV~7p*ho54rB~X?NbagB1w3aCjy1draDG2MHs9CXr~ULW1W)yjXuTo zRmZzYIzma0P@Llc9$H`&G86Nu+C#kZN8jOM4I(lYZ@Hc17k`764|#x!uhF(K#faLT zHz9$Q>bd7kTX?YvJ2izO)~A!5?I8J#7BJqhhkiAN!$p06p)-Ut7Uq%=a@`?}T)Mp;sqgsv0+D*vP@TTH~na3Yu z@41txwJapC{K1d&_1QZyx!>QgHWeyu|KBF^u?~C46I}m;R?|;IcevsudkAfP!mcww9zew`^-{ZN{H6jD0(hM`d`tPti zHy@UHNJc6Km57q}s4)Yc%2uwt(lVT>dD0e;Nm0Bg-n%se+jgW#-W`sG)ne<;QVa_T zR13>L8^c`5PzK!PCOf++aXF&0Tqc@{ak=8Mpp5cD_;Xi)WW16gtbE{lUSDr=@$@dK zHMBHz@YOu*YFNJ6$~|HX?|T0=EFYO;x9!M^_S_C|s56bn7YQ?8;M}E{&=U!iOtAR< zF8^F%^%oMuVku&=i1X)4hS|hYi44|C(SEEno;pw3cC;fyvsewb?ZQg1%>w8Dasl;? z479f$axTZrr>J_ojaXPehkWxJ>e5^W{1cU>o1iuYcfRTgy843Xge%2uqEeF3zIUqAS*8Gq9F!$3{gxSdR?&rS9 zcOH8gv4V9uvp@YyY~Fe&rrn@IC_yz$Lb{`9 zF+_!%e<%vVzZkJOeO7-ivQ(2^tUsTaZk#_~wxJs_wv-|X+ksWdQG7e2v0kGk5*myO zmwzjV&0M=pKIift)K?t%tsI%n!5E@ei`lP!k?o6{VG z(-(JjdxC{h468+XZ?V|0yAX%rmem5nTd_(t5o)jR^3w0ULSD}>Mb5?NkYA{C{>!g$ zY_r8RA2?2yYj??J5d5MRU;LcMh7%vUmf4$^dF9L=mo{6pa!0uovvhct)gx7G$+FkZ zi{xH^Yi=ph6)br;`LGY`kVD%Ft7}MDm zsHk}IJX9VUs?=53_R4myY~*k;S5D<{IuB6d0Y9?cL*1&jx60Vuf}s<)v?)rdG=^ zQ7_KVRd8a+oU-x5bL49?EMB)jmK8nqu22Gf%AjM>lcfr`ELONa?+n-sR=%Bk8f_Om zh+?rvH^%St+xi8+Yz;Fu^y|+?mTDZf?N;O9?k^-k;O9$*YAIqiHq69^Qe=q4U_`?n zK~-Eaxi=G`Z47%k?4oQr*l=N}$0-M|0d>pg%;~!uj`ePbuG2U_42j9hy zZuvP{&US})1h}u6j-LkjdkVfC=5ZMVYdt7=C0rSuY2@+h_X61N=O+iyZaw+B<1VkT3`{2A_B3LTi{iR4)=ve)jt`N=GP}UPs)WXIaHP+8J zz(`oENhcOBw(fXnv~uLx%iMi`vwx$+XHq5;6G|S)qJubFAS+0EI-b3uX@2A+*St9aoNalx^ zR!-ulVV;`6PhbK zBJSCJl$ZYahtzT<_Kw;2eT3Z)d=%eqBBCt09WF=n&}m)uo-Hg}8MIm;?ar{$qHECx zi3uBa!x9b~3CjhrXDOmr){BG1uS8I`V2jBx&I_6=84@lX*|>J*o4w)MM{hW#^F#thXHNUOAJ) zOL@oz>}&M&Acuw73(s-v5C0iEyDb`-aQpR3q@Ve>c&L0Ak?*eKlAfsBH%r9zD`X_v?M0M<1lQwFwV-i1<3^UCJ4Nd-gg_O_Naw83c#LK z3(GMqL?OW!EWT2*LTrK?=e&m8p?Zue4Hb4=NZfSbwi%(a*eL4wHK(k3sOMphURGf9 z^Nz6lpg6+sdcyB~$J&S1Qb#Yr*O@&Mixh3TrYrcfR)VV^8>)riFLZ=Iwp7bDSp3LR zjt!+aSbd@AQFvEWE7Xzspa9yrr|BHcJVy?fiSJ$G!uQT{K@G3uaM|r&p^XQvMl41r znf?8L%HGZnn=QkQYbBD;{|4V)`cNPyeOQt!<)?Arn|-CjQO_Oa<{v=!AbFT5JM?w~ zjChS+fex5T0a!DIDjTOg^?)G-GO8itz`aQWLarnG2f}qqv2xc-U+1ZZU&KZh>vH(? zPtiPl6w)@aWO((|;wnZRP7F1t!S)E1a6S88VXXae76vWZY9ko2CmS!xyXNAgci27o9rLcnPBe>n7lv*+B`eIY=7r1O8SqyCdn5|TJ~dE|U@d~>C|LdZ2xhG^ zV};lh3nTk#_noFB?O5Ur%4-$$=nSu)s-ux~EqGV)J18X)$4)Fz%RH@2yK#MIM_<-g z$M>D@#b?vWf}5h8mq-{8TDHPW6oh>?3Nd|ug0C7I7LuRj z?NYy-65eubKguy_ohN zB(6BVeG~F9PC3bho|&r+1$KBWGGYW#@8|BkfX*A!F@Op^;O9}|Ji@&X%NV3j1fE$`4-I3ccdxD(%nyELjvo)@DZ9v`s{gK~y0J%{2Jmu7hRjfO{C4+5 zogNIrkSSaz(UES~;Lw91^p&xEZ2hae@X+Jr7-E;>-}fQf*WLhW6N4inXP4Qa+I+D1 zn)?v%cSa9)I`}#pd7`kOqa*x_kuq z!^}d=Cq8qGr=Gmb#WM}sna2vuEtRYnU-1v){4y)lN(wnds)g(nsd3;X0w%Yv7PdIvC7N&7E(>I-ckAPACrIW z4~a>s<-*Z9!)HJLUcPYKuXD~X5Rr#U3ga;LSHMsEUONWOH|n|5BJxBh0N5tc9SR#{ zGVH(@d7FShW7>gb(yAgkI4l~k9mkh%RL$6%?!<627x6#(8n17(NsJO7J5K9EA4OdT z>WRo{h(*;S&Z17y+=DN!+bQpLzFQAAO!KK&Sc#MctISywl6)qNp!CH~f%EGrPdv8E z*5#DAWV!8*Ic~nG8oKuiVeQ1{xd)dC@r>oZ_ph;2bJSZNH849H;l!|$x`C{|^F@qb zWb##eBTp=0$wo;G6%*Y2p2fET!54>^e!imsI&ObA#xFoT))3jS)1dRIJLlQ^?n|_` znrLi#eFWNDAy)Ur$}lXK*PCqq@fnVM_F8t^DZ6RLPMWdNPPy1_^G37HnO2*;*+89x zW|Nt({Q>z8zejAL>4j@n%6#}d^_8LW&h3CH-xaW9eC7KwXsO23GS1O$6Komt{>~4O^{gSo>#uc z51u$5w)q$#{fR$Ax^@WT6bm?8CKD4j^tdA4_Y^U|FKYZnz28bV1SnZ$*$RuMNb;Ew zS1X|g?^W5_%J|A3uCud|Vu}SbXHPe2eo{Gc^DJqu-8SC5PzX+?J4DkbLXudVhuz$h zs_(}2oq-?0%@5&(6v7!53pUCIW=x3f19C4c2MN|bxcjqFNbt?a0jED38)l*){G~$h zLrE{Vp54lUHDnj}*n4?{RHR#8>@*%VycS!7!m^NE2fGNnFK&_FzlfU=E;myyrzz`2 zYw!7HldRQ3y=Uh98RYl=1?kH#Vv~q=uH1dY0_M;DI{)y<2WdJ>Ty*$(W3J=S^#-wBI#QEN-Tw& zZ%C{qGGSW}>cc2+rMm`O6>8^qsMT|F2~&C7XtC|Lw;_1f!H$C+r))XlQrjVCYRq4s zu-vW(=hA0uD;19WGLs1$*7yz5;z;Xm^${BZ8wc<+myezI@O z)?4MLVIGxfal@TZcOoEY8oHBYXLzW6C*P*you8}f0R-vq^F)SMDap`S@Lue)-(#8r z&bV(k`j}E*_pgGJh$Y+L=IkX7J@#dO@X98!4du7?<~rsJ|1>oIlnOVwr4UEBa)qQ^ zrgZ#z+9z(q+;S)FW7p#181cTF_%jyfj52G2do4wR5AVC`M-Vb^XthFOs>^%@!mi$O zY_}XqWD2Dr-T8gKPw+E3xOwSL*6m>RJNG{pLPF1kNxM~Rn6b7Gyc4GDRtxBEHSW0h z;cu15GE)eC5?NvsfIyv3&G(I~4f_K-UVzeUWz?LfEkaAfV9=(9m0>l7-9iCu7x3PT zPC1<`w$|ow%X6mL=2W}QRy)NzN3wmHJPKP>;ixJ` z!7f=$Wa#f?QK!tW#-tWnxg!UhN^jhjmtvZ(6awFwH!t1B96?9~Dh6hxDBoFO&IW+a zOcda|9RN=!nKxS~fSEXi0+po5=37H#BrMb{Ht(2$&r7>~3BFKDUX>`a zwpVNk-YNR|FF82t;6mXYth<~>)AL5NNiEBfc1r2Fr%1l~ugK55!QxyD4wjc@x#uT7 z!nf}DRW9m0kNw3NG6=xvn;azL`l&}O8R<3=i(u8`M^5z#ul0a85jVSYJn-D_bN;*E=ixVM zq(0oVJkPKuV)f7p*Bv{|?KfY`^4c*f^Q*MdjE#*AE?v05>C>mUc;O=3TbILn>UtgX z*hAQ-AESEreek)Tp?%A3l+8840ukw{Qd2zes~r3cf)Kz)|M~YQp zJ2{;9a3&9V0Pi7+pgxmxuHk5Bj^x65N`LfK@<$$`ouwp6M4ow0+ zmCt>i{L?>4D=CrtfQb+hMEh4vO3_#otmXV2Wz6A-e9xni5Us>CBFHjdxb-r)*hTxW z6U9G`2}3rkMwm5Wn@%+{A;ynPH*q%?*=}NQw(taI3X5Ng!uYM&*kb)ah#ggg+Dq#+ zo<2vqUPCj7RAQ2Amzcf(7|}`rwvSmQm& zPx2=D=}kk>rYZ4V0ZnDf*`OjLglj+kW@Jj?YI^{^MBljT#_(d0ez$2@qYdB2Nt$;5 zd?b${j+D=x{SueH^aUP!t$~d#-nCdga)e*_go4)>qmS_q|KUI6i~sUp(8@Ek-XQzkf6U^k*Wg!wgWbg?OqOE?+ByqI zO{E9FRmIO+bitw;ns+pFeR%=tdJY5E5ycooS%RR?Sz*42?PqN0$g4&{$Y0O$3z zy~7zu-nGW1m$%t&diDe^d$^P@}K^v+;!KT;A;SaKz+ZEXTYEWXt&#(K7EGMXU@=WwbwlS@wIi53V_;NL0q#+x zH%&wPGQ@GDWLW-kGyR{(Z8F?^09 z#h_B7u<`9z*!FSi`3#k>e1rVqhiNvO5JglY$FZd{*S-HiUb^q+d9HK= z-YGFzG0I)XE|a-h{50HkG_dSrOjdppU75mL5E=BB_ix!6an=#>|ES_dKTzl@djLa7 zzym-%A~LDMG9FPm2Kgw(+UHUPpL*j6^XSV1u6Oab|EvFsfB5(RXT-+rKKl&S|LMP{@_+gdY0NJnd7nk^Qv|(#_Z@2g zMhLW+u@D)d62XG8EJQ*0I~o1ixDa+5-1O_7WQmO-Hd3_V_Rs0>REomC zO=PLRvBeudc(n+p!&vcL`=G#pQ3k!p*;U7fz(u7Myn*dRpF5zPZ8;c9l~P zZaKRx@fNQYOslm3P$t-$Z)!{gN5G* zTF|a*Ck)j#`wr@D#Ai0Y#`!OOf!8)#7{GGqeHP>9j-}zgA3zCG!OD8G)I~=Tx%aU(p=ZDZqIr>jaJgWujzm-n%DLw*uu*SAY)~JN zgn7|R5PA#3Cg7GT+379p>zA25K1VanX}QqJ*UUphPt!Tfs&e+-KEef-Fg_;=<4C%rwPgf=X22fmWPTcO z%|)jNqYcm<4j0Dru@2Sa4<0!v2ZM$B=xS%ifsB5SI(2#TErbA*wvq1d29$1#q>k_o z_Ju{=^3LF9*3MHMmV43{+4@&s;OSF!toi@9_ug@qU00p&ckdH!s+>CKoD^EJl9g;( z&XyC#m|z%_XBZpa%wW=t&6_uXXYlZVVFoaGuz_c=F*wOVmV;zvsU@{K=TMz0*R7k+ zIeYK-$GKH?)4BInceUup>+|`v<*vSUe`l?|_u4BjLq~THfA~NCga=;#y0U!`hKh)F z0x&T#$?yEm@9@}TkJH)J#ilJ=2z;MHAx|!wLu4d{LLOy&EX%^OEMl=3`COJi{geN} zp68$E_y7BU=Y|`0@sW>w7^5}6_h0@C+Hvsr?xFM1hnarx-C?JV*@Y_K{PR`uvzt|h zo5T_b85ZJnS&}ZxqNAL!leDZbUDpxw;W|qapS9;@sMgjs#*LVz_g!^(jexuQotP~=ot%##fQ z(t%=1DJHe1)Me-_j^RA}1m>Bi@kU3&8Vt)~MJKFU)1h&$5>}x=rr?oRicFxG3IZmTV#XK(Kft|s zp42l>qF#KS;@BukhLccIwr1PP1WRwZnR7cHcnKd#;Fb9KU;H=x_>cd1MLe$rb^?S%DaG%9@{=4pcAT4b@20D( z8_Tlre4l(SM=TacNQu^A$WW;OucT|nIT_;dI46!B<-`B>-}3n{e4ZssmhkJp`5PQM zbdV<=e;kw|@y##ceCWgYb_`*3IX){fGORxkmcX&XxP52&(9fpnCT)v^71q_qt*~Ox zkrLY~_X-r0s|6KO2z(*Jk_1bVy-?!pixbRT%43wlj!6bLbhG-VKAeP&QD$y`%y#0{ z#vm<8I_YpO2n9m1Z2RYoA)~_vB!$`Dea4`qVZzo}**sGvpBbf?4itHSViEV`F;Y)I zfjPLJTsn=G5@}iV#xxt3$63Dn2F`DL1K;f2HD~8bbj6_A8kN7rOudEfCsDJXqVw$= z)eX>cpSJ%_jd0tib@ukJn#d(+J&SNrO@L;pjb%x$t8A|};+wUvUK6^}NQT4=>V+pb zKT*UO&GsET`Q=~vsQzp6B8D9zmc`fnVowi6;{5efcH+`zQZ^-}}Vx($(3?ul>ev@?)>;BbUwMA3H?i zz>D~|-VH&3up~%{w7|8X!;*AKId|w2<-;DgWH{Peg!KfLC6E?qbUAiz@U%dRu&P_m z7W-I|>2o>uJba$qw1>3BTz9FXXL1}pIm4}QTaFXA=9_(%)&D@75Mx=Aqk9Z_Pf=vH ziHJra2wNYOH<8xFyBwyIa4D0cpu-78c6y5B;RDDQp20tMlu{v&lHqjUo)|1!+C|Sz zH#4*KPQKA~15-MQrTwsOU(EaVO%rEZU0Cfh_mimEPp0Pko8byt+@_ViDX2Dgqay`v z(psBl5LIO;nwSq)vm;QIs>^&akeI6mY$U~6H~SY-RE!A^)0s9*?&sv*!NV3@+pZmMNW69E`tX#E<6)RWJ)!7LMa=9F?>xSKVf-pVUE0yql zpTP4eC{>>OSM8)p#NzzJ7yh32zyJO0zU5|azwI@==ZAiXzx>pnBQ1;gb59W4eH)%@ zL-{7}DBJi+DM(piqfNKm6HtoT#G0^@Czn@@Uh+X1dV5`#4!KpH1TiZB1n7d{+uymw z*rbPLi*P<*I0h9X1P702$viX0?XT@aDKl3*6qGdp4KNr(uShX^athm?4YyTR)X&B) zHP(h6#w-m*A9v&useLcQp63WIoI@#%l3^Rd-olF=o5?8~sWcWr z-NtV<*~Ua9x-4`*QL~@g9t#k$hof;@(9tGlYkvH7QrIkB*B)Of8cCi9g9?3202Fh02(xJb?G?|K3om1axKULe# zq9JDWhoW&SF=@4rYeIN!;kH3*l@FjYoLSouOe{d+T($sc;1P|iSr+q3QEeeZbus6B z2*s2)!mQIqVR3V5ANt@PJR>ni@y>U>o9^!Jc^u_q#k;@?Z}umC@C3_zU}NuU)4BMB5Z#^9iE%W-~7l=JU}2#0Psf+PD2TsmFC zaYfmcq1f~MG|8os&Q1%X%kdEbj+UGmD-tNMEvk4qt0qbyo6{Vd%+oI|v=MlEcJQah z(`ZJpNdr>NVuDXwTd#=a5m ztdq7Wtu?sKXpO=(RQmcVLY$(0()Ozw1`J_2Fk9KxC{$AZj3rok=>Sih z&m+jG7+AJY&Oe@6DJwyAE3Ldo1U&Ny1F{)>g+^Hf$i7?T2sj9nVCtG zNG6EKW5nWdTsMa6IC#=RD_zGz%eFXoc9@f=PIL23H)2W2o8S6Y9{%cA0YmY~A?$3H zqU}&ZhZ%PwOw0+pGYK3aa75T(Ljp1oOiy@KMH^BIyb_$6C@~nbF)AFvEkrnTAZvn1 z>vdMw6%t03$7Dgw%?eOuA)vJmw`rgNjlDLGwZg>|6mlj*?BZ$UkyntXj-e)}C=m`* zb!?lZU6QS9J4tNY!KF?2@>JIrE{MLc&_@M0=($;f&DOQnr)*3`v1_vny2*ZObW26H z(Q9Cni|7lwmCLRw)Yz2P8eGv_8EJ}Z=6*jyc+5thu9gWPqB@jR%q*KNXlrc0H4c-^ zs(2bfwNj9X1=7{Zn=dVo8KjxT7PuhxWsveW>&2QJ#k zQ6#OVJz8sVMOAV#_5C?p%`aUn0bn8uFXo$tl-*atG-=Ol8rn;<5;W{>CmAr)sPm`s zj6@s7&Ye3+CK3_cf?O_-(wbPz#j$NHX(7uQcS4ly;UK{CywLF%gzCOA<)ULL!#}nC zmMWg0!aP{AWC@$MZe{fG5sKLvyo(oLXbHv-<_)xRZor&V$+p4}Wck*!)=B(vfl2E* zTi9N0P;rl-&>%t-1AB!bI4P<_L9=cPX|PuMn3BQ-y4*`4Y$aqw7*Z7i?0gpI%xUcX zd(lS@;b${p#6W}tK88|~6)U<~cf(rFZ@iD^d$uwxmzLH1Fo7p(Z5yp?r1MP7s>7zK zNBm0nQ&dyXX1GE`snhkiwX~UL%}B+3uZ$>K>v5}7N=35)JhLXvVm1W9s+|iEks~md z4&N-o8eP&@=@|};TfscB|rX2|FBlu9LhFF+|Bs>c=aTT`32Zw%?_^xWSa$6@1!4SfH*-z8>QbWDts z@qO_9xke^c#XgpWGkliBzLzKrpTSKg(Ob3>U%H-r?;si%*)Nbo8ts`duR!Z6PpJXy zH3n0%Q6tXWX!1}vXzaBmWN(1+!dux$i4YRdxP=_@(k0xZhcQPFp++v^1qvlYq15Rb z)+~*&dh-g@)|)xD{4Nf}mN9NR!`oh)vV9+|o{9#cFw?|~Y@)r(HJ=kL)p*llKQ+w0 zX@YAIE!FtS7=0^R=Wq>8N02qct?j`XS;w>6C2S z+|S_F^<3O=7f;BH?~a*e6D zkr$iRXtT-C()PLbhQnqX#nnrt>hK9{9b zED{6(M(aA#wbt|x46=OrimIQdIy=j0#b5%z;R+bb!hPxoh_8P+tf{vgTuTrHIxNG@ z$w#CL?XeK z&71hncfZHT$OuX);_*0IYx4O#nQWF!I?eR-G}F`5%*>?8W@gA|a}R^tZ& zT1yNXOXV=>EFx_vT^z<&VX;rF0mEh+KPUtlF@Jk`Lg3f}VM}5b^mSSc^tlYISxRE# zX3njA4NrD#VpR0tDTxTeq@C*U9Brw#m8!pKH6pu4WQfS29*uG54Xf(CXqt_er@14q z@#k7(3tlO18?;7Y&ij9w)HKMesR7Wq(793rnDtwlhz_E)4G>Jl;0b9A7wlyu%7t1(1U;fHhI5&Kjd_ITcI0S(Ti-2-jGBX*n*$mlChFms7saV7- zd1$SOp4Jfl{GoTglSGXZGGFxPXcd+fde*fJrMr~4Q&aGbuM&7A0wa0N&OTy4`m=ng zYd0Ff5^t35{CPHv9ml(LmeP2hVDvm=;~8wg^9+Gf=pYOi8YCqX!w(GEqMqMaM$_pU zVlj)3m>}*-EJu*&NV0TUFJhn%f8|y#^{?mU#0ExWA0=&pHb`Nxgsz^kXlj#H8sARF zP@mY+U|p+tYN|uWqRHs4O58a=xT)!m)dY9$*wkn9MCkF+8i0vxzEfdhG@+HscM;8L zt;4OCSXFJo8>bpui>U!vRZ?rtStdmbiCLe+E$2o#H6G3|n<+kJ_mC*(x@&D18=t6K zEm`xsyKcCFTXyf}*=L_4pD)bi{TB)a^7$P3T#kG$PqA3QFO@JxmlrlFm?ZFhkG1R8 z@wT_Uwd!9=28J(OLInZ1F|5umgdO$=5P*;t@h85IKXQpcI&4^Cv;KW==C3>NMf(Z? zOv$yF&UGZZZ^zke=u~-@2IsL#0loPN24~Jt%x1{vie!Q~jw-QiW*Ara=<V_S-awm>467+dhLGp~;{Ek5ea4HV`gW)i1h^!%zRrPxI81PjTk- zDdLGZDhTjOVdkIjmGC_ut#w;o6H`v%{m8HU3M*Hxocnn}!TFr#^y$-BmW9Dk?CwHX z5@Sh>v~bUyM!)z1+OmiX#nv~ymah)H8|^8qGBYF!W58DeKM-U^C+Fo3L;^(0;0&3$ z%1>=17K%xI3EKp7VIUz4qhf$*(Sb!M(1P-$p;-n?Kb%uwi=blT)~J=H#sl6o)wO1i znnpH%ltx=)`&Z)DZfH}#pKAJYw22!{YZPuXTI+oct!bUbt?Yc=jMhqAfv8txnrU5E z%Ly3S4}j{pbR(~4R6|ijC=__;UGL_1 zfA4p3%R!^ zXpLLr{A!Ndn$}3%CbZV!2wKug-AFTWMLaeY4)c0C7Fz(!+7wcRe?)_1hN_8RqH=m? zm3Mz$XjK1wF1ty9W5L#w-{qO7Plb8>w#DgFC)u-SPub;NLRfLIVhvx{vMm1HzxzM< zFTeYH^z`(Q&*#c&f1~LIqRPZ67K;G<>@WNxfA~j#L~m~|5RUCSpHrO5Xo?#4KKU5= zTo!2z_R7^1x_iP=VnSf;c>$G~AyBY!^8m-z+)plW<{YVW8$(n!4i*(Xz3Tt2%Tte) zuuz15Ol7KZOCHZ-wvAiMrpk4#E&ghb(>~a#7CsBXhkp8B@poVN0`Gm_`$=_lP$-1ie?btSltQVnBarWVbiArM z-hd7i!g8>V9wwL=CoqyNE8`S4-$X{m!cbd-*!WyhNK|(h)2w@JZQ@C59!Hj;RT;po zI@UJAZGstrYZgT7W$dT9Mir*1lddstGg=$qausA)e)bC4Ay89^D<~{ zwx1S**64q4ai}gE*U-G9PYWJ5a$`06`=TcTwG=Ut-3+TuoQQ-9Ed)a{!_do*^1``% z=(BvGuH@@q{R(e>+e5tL?QgrRH%}&$B$LUOpPTUwr!$%(X~nrh zIIE^3X7kwJe41nX_hMNViS8bpyYEA35LlQ}k;1vN7$NCO+H`JN$C&8~=leG6;L>DI z8q>r>9kuxy;k23BUfF>ra=9Dfw(3rEnY1>Lmd#6H8zd)P5pFv?UJ$Kf0kl?ViM1gD z(S~4K)F^;x^rwMSB~n_Od6i7m8Fm<9aYyEPPCUIIUxQ`YsJreZux(14cOZA(L{j*a zJfHvk+rQ1JQ>VEak1{Y`FdUrLyga2inbr6jdQx%DJo`N!{>=YES~fx{1|NJ2X5|{B zGHB_L$mOw%1vJo+G+gZ4N=Z8v_F28RRz&b}K4rSrQ6;K{ZOx22(S*mf;o8=?jlL%W zx2jitgl9Sew=G)hNN+}KWfY@bT1DM#%l3J^5L#IB{_|<>^@0ppI zS+s+1fP4UFvYI`U0edC_PGuCHHgqQ9WKZnpbHDphGU;iI4p_4DMta};5Ym7YHsE3h z2C2ig*D=dSCj`1OC2KZ{QWNrQ7|MwZ!8X(lnayWw7#@<%LS79bB2gPU;&2-(=R-!* z8jah8R&g1$%0_}%|JbbY&NKYNVT#Hig(SG;HiCEzj7F${VC8CpxBMuM6vX3kzW3el@X=rWC^Ive zD?a=s4VUtU1JjD<#sXfPP@Kyt0s~#C1m4+0eC9WPp5YV6kW$du*Uyc=@GEo-3=+3& zq#Xm{g0Sn{B%+N(m#WZoRCq{4^SB+UFY3Zg(YOZD;$7Our5)Twrj-TI8j1VQN^3+o zww3(4jK{u`Ulwh+1`M^SrS(}+uC3XA=DR$7d<0v792}y!bvq&m=Ds9W$}w~2Tj-fg zGxOEI#dTc1@b`bm)YKHe`-xAmZta={y}LG0REBBKaH(K8oz)EI6k|nAQGshqdOPFf z4n4yc|MRafeC#lmZR0u)Z~W!|L~(E%Ctf%~rc}gB#bBrxENAY0jSvL0?5*XCY~Ur1 zoFr)?jMoN6x-gMEHZsC9-D+}XJ3BxaBD3Av!4(Usy>CtH9PZrkfmXC$Dei1Pw|00e zD)Rd;gU5?>@E1h@G>xN1I%%qzuZ(0Zm$3Fd&vahnqA=TcqB^_6?mE)K5k5}&rp~?V zry0_QOJ56xz@v|Ri*x7B@$Y`?W8CxLgE$t504!mU<;KeW> zK9NN2xG|j0QvM3ZC`u-d&<0;RB!2AQvnihB*cbm2$F@0o=pY~Y*$;95JKx6x@Bb-Q zZn*(11S(LNaz|Wa!c^XzGL#f#d_!It@`0hK0BMm(I3$cm=9M4t#OMA8hoAZ$x}2k* zNOf`NFMW*Fx4e}TUwE3O$}sFY6m)1s>GLz>tQ1|TZlo9?lQXOu-$QEPZt~ix?tkB~ zRkB!cz@=4)s_x%K8wazUP1z(2*btLNz-@OwEf$Yi0FP@Maa>IvFYftYYyr@ySz$!H zqbxOJwx;9keqOv(!V(&5`6`M_mm!pzv!5h}oJcU+30O;ul(vT0oAz$oMrKG<@=G(^c4)mU+}cE- z1@O3~neZy|*i>jU*R%i-jcnBDgb;;fITI9)9wX;z907XM7E~;b2)uHIoS}$|!kWvP z(@GO)!}@pqEE{*-#0&rXlk9)$I|w1k%}n$CfA|c~e&dTQTeq2YJ9o2e%MGMfti?`t zVkc4<70w69r6(B^SP+i{F4y~=HkX=J2Kt<=Dx?bjW{1kK) z(p)$>8ve+2(Hl0-HP%Gb&a4wol6c_sL98F~d|?yP!0}QwZBe z#$zA^v7sgCja$*X?9Slpx;mJey2$iY8h4-<^Ufb8w`C_r8HDnnXfRG3gdi_{ro19cdg5$+^LDJ~PZJxR zW_ciaO?Q$l+ty&#En{D?fO^dX*e^Ye(y;%9bKH8*_c^)xgD9USp7IvC=O!Yg)adrB z`I2x_kxkqR=#g2L`xjUl3?uy_QV6siXTQ6h5!oLWE*TZ(ZkU?h`gQGbB5tdOwtpjk z(L!i#zMtB|T>y{UqBY`xHtWz)7nx{6Yn4o0{KJ360w8KQs1eoEOdBysSZ*j9=XR)Gh{h*Cz2d^>a$F|_(jy1L62O(Y}kxY8iXCbg!VxT zd}T4EJSGbThPu1h@X$^4`vI2kvom3F-Z&gf8zuwIsU3Hb+O&h<&|W4o7SoSB#+DD= z!#=SAtFq6JxIAXhW`(uN!_WwfwCS~SY$+UM&FSaK9y~;TB+d9#hD;`pZCP}5Bv?Dx z&CV?w8QJ*&2Rm*c9mFa$mWp+yz5I{1yxyk0C`UW{X+gN{@OVMA);PPxT$;h;eT0l7gd`y# zAq5?_g*!cx(VAZ2FxXugN@1a?kfU z`^;g!KRih$KcAKmA_oXO%%N%GPn~7$>gRdG8*k_NTmBWpW(aGx{~+_DtD~<@>Kn(l z?KCE`L{=D6-4Vz%*iQ{{TT}!!<8eE*mOmR=_1h|>8AU5C&dwr60~SXBM5!o|Dnd9n zZzyw;Bjb6b04tur@98TKw5%MosOQWplMl+Kqre6_B%}m%*@Bek6BJ6MZ40|^h`ynv zjGjGBa%_wsn?)zOn9O-xn8+fup+jjrJwdoiYpF1e&jrzJ_*k|lAQk~VnSqM(z!wEIEyYoEgU&X@6|!;4>ff!o%7 zlW#76A3+fI4GisXQ{8AHvQE5)eGw(Bv)a;beS}TV{sYG!d5&YJa|Gon!`cK$AxI=r zBvKt1W60-c@QNjT1BXv#IQ1|d*Tq*BF z^l_`lZGjnuy8v3t^LpE&wdu&R1>;_eQGhuCC8A%sJT|*HQ($T;7kb}&`>>KJf(qsd z!Zuz8fv_a9BaR@85fWDzx`ZGlp<6ZM=#yWmNRNe9ET@10 zOERf79U4kT(-rTfcli#|>GP0YNbQqPCh=pjITgqla794aj!b|8du1Qq={#y$ zlZZx7g-99@L7A2kfs~B-He)51(R`8R371aSAz=vy69P{g zPCk8%i?5t#)Dv{A{UPG#{s3e995|Mt<1atMJAOv-wa$kKd|4K9H0dH!quPpUKF)qZ z35z98ntS&B1xG&jD90}N*f!{(#OgI`dFV%fg4f*hHgeN3ri6`Ly%gWE$!1ENnx3Fz z%UgM1%LAC?S)P93iyYd2l<$A#0QdEOmgze_!n7YpmfzLXOtPIFkR?n5RlFTjrVU!> zaD}O^S**Ejo8m5n$Hqj`T8BG(v$rs17EJ3LZdBufYe)c8SzB{W3`|4stU=O20Y=YI z^1%^ccXr`f79yB$ZY^iSOXbj&)0JTDJ=++6;R2oMEFC~^%3=9k>u_&f!-Yb?WJxhq zR9Ne`VA(cGDa7gH*nvmESFG5vjQpt2$as#DE%7{$p8l;Qx|Wj(Ceg#EanGEhuyG3n z;jmDlRVav5fKWbZzr@8-k-@yns#Kibm`%zObjKvaj~>80eT=n%AmhVW$5!H--iLee zZ^0Ejw=csD|MRoF?k5F5SoRRPz{ak;T_bJ}(WoyRCTs|9+1x4jvF3Z9<*_fk$V?HW z)Y#JDy+8HSyzl2fjObm(H$MF|`;J^-Qp4cR)!g*vn<(Txjs-dLzQ>Yco)u_}(}@s* ztY_H&PmgiKy4^fJ^yaWxLbKp?W!K!cZpFr9)f&?}KOv~u_lnxk>H;(X(I~xl(P*V@ zTI+FJbrHG-!hmybfQo$OO1r4mED{JN#%9o3BP>a>e~^5oXV`?&Z%*1viERWcR`hfG znpO1Y@~k0X*ZK~Yu5iiwipfGi+6$O07SStKk?bENH#UMibsRZ8L1{3B?y$N2%{v+1 zH^S)oN%Bgua@{66%@48nk-tQhN;uCyjoh$_xd5bAq2SU2;d>}4x#&3z6di_hF_t78 zy5e!{@eIj>!)!`g!~#f^4EuwC;f)W_8xz=vKM&gHl_ObJ{?T9YruU!W&`m$Y5xokd zG?vhj`>j5!Gz{$xxij24{WS97&-3l?oW?@{J}XwO;TM17+Zirc96C16SB{P_ zDQpTDVy7lpF+IaTuV&@0LH2y+Z%7}0lozrWFb4X%;&cqUbf#jgI`I_!Lw7Pk2eR@I ziUvLj(?W}FmOv9_LbtJ>8V{ltjn8m9JT{Ge3QaS0X@O%J)NwVVb(Td&T&*;K#R~&g z_NgKi$m z7FMAGn<~}1(M4G?V#~A&jWuW>I;%`KDMgRMog3@bs&$vBoNpLS>+F|_c4)1|741b& zuL&ohs5`y01kJac)o<0C>&BI^ay`03V2c1Fz$?Z{OpK8^ zevEU+XE=90OGyhXX^`5df5jR$zxk&)J++QUv}7_{r2FtimhDD^Yg^YRgT}M(s@oZg znx$@|-+#@1YKAMyeIO96EPyM+ZHHDW(ieni-?MMZ^8~9hzpvRSKpT#a*=%7)7YKr2 zep+fgQC+uTD%*`)2+P8e7LJs}9Eod%jxHmhXbgqGP%2jmDh#Fld(nZ9aAP1PYGRDo zzC8r@EhFRQnRJrj2C>SMS4$o}E4Q%gp%3!ZU;bAD-^cyVH*nXi#Y=S{jV_NzQsJc> zgfBN)vN&zqbf;}PVh&qhzZLI$he?g4NlEBU*{r^O4f1uHnNX5**?^v{TUh$BKjp+@ zUt#Y*{S_AvzKHMnOlAyYd#15oOygRwAjQ0aX%P5Y;46u=3_@!xqe*oSuFUB zfuM6GKltqTm`>*r#?aN3Am&^#4<4a@)^8KEY`o{L!5c$5zZZW znc&~QVTQ)tmO~<57e6Wk{@7ax=&eItv5`77*W!(fo zZve{@g0X_(e9C3$?LW+t4R>(pyALz`(zls9v!CqL1S;?;sxbR;ZqpP?h@wx-63Ff@ z`Zn)m#T^f_^8R;{T)hA|- z?OICj2j0&!8{f{T*MY49EULp)_4O#_`F6(Cor&3qkBA6wMJmNrU2a6fTfJ&O)%@Jl zsLqwRO)(n)iH4J^P2-%NO5B<-U^CqLGtq?B2wZa&(gGGw18A7993k(ez?6z)vjv2- z%DJhgE^{-$nj3U(i?CGp`6rLy96ZZyt{@!~aB__NkqMkPZN^yTnt}8*!PG?9pFb5R z5wjQ>&k~$FgLV8M{*684y)2W`K^f4-l((*j?C59N-9OIA^Dht>jq~_pbgW)WX7_Cf z-@@1-OLX400?V@T zrzXhFq)`SouIuE^n-cub&lXUgkNwnRh)vs2!eQEqp)n|&x%Yhe+ebNnagf1H4=}Uu zO9Z77*57>&r@I$_{l>6SsWIVvZUZO}5KI&$C#1v`0#^!*HWa-CD^f1quEdoBD~x6$ zb0w^=?`8dkX;!BsuMHHZi-yyqHeCv@Qartv$AACVIJW0G;*Mm;n{Hw9eIMjm_h#^e@?meV zW}=xxuReSxB1XqYC%Qx(@>aOzjDV;xUILTC;sZyBuqf4b4d!j}K5>TAXLZHyDjZfGl)D@tFBz+-E%GcPI#L3NoRtN)r zXE)<_Kgi}Ee1?N36!O?1;`?7Df9t)dQie1F-)NA63x~!y{n8nXV-vgKhv}LcCVlQD z)c7c|zy1vJ7ydP+p{3<^WwSW~Wre^KTqqxYOGuO^bV@42l7vf_BXKN&;|RRNqvXy_ z<2n{`0V`a=iWuBd3<%DhM(pk-opQ+qE_q*L^(2_c6evoCHVQ2?YgczL)M;Z>=$+RF zf^y^2d;lfsFtz{teE+}xDrb)#CmFNZ{f^gg=p7$r*jkFCy~Yl#xp1zjyW688V%5Da zP0hcFwr=0b@L6MAQ{^_S@9P{; z$`a+uM(E5J>2hF6vfRfIi=}t2S#8J#8f*O^OLwn8$H5B(o`Rx=e4z2Pq9g?u zp7|#p|AXJ+;@MFWF^AjUbt?zo@vEF?2)BIr8{IC(R7PHEe^#$0)ZdIEB5|p~-)ma- zRgP+}#T60eM>E`NuY2@6HOFn0G$bN<*!=I&n6Y?(T2VBTq5(%4w1%Pe-8inq_61VNIr}P(&zNs9 zddpkbv3V~qAITzyPZNLU2V~#yc8u>LEJ5B2PJVhz);_h07>U1f1A)kGtCg|5RcD&oL7-u3dyVQUsuNrqu5Co0eiM=K zQkl~~e+Z&+t0xIpW+O)9&c9dV&o;wtN^4ylur;k!?=HlGcwCFQn3ljIM**sB_{vwE z&yEUzb~3h!cy|(Grod>_XQ96GP=QE$eeb@UaY~P7d3ZnyrG@uk{jnayXflt~i zFsB#2rHNxmScG1G3G7&f zy?rH08M3~nSoF#HimV@y3w&k*MaD03{0o1|)1Ub?`JyIf!R~k6#({@^m2+kY+XQ8` z)KpzdqRx9>mzP@eS5c?V)~5nj?|@kqofV_7UgpA(}q7RS7H zHD@JEoX;Q)^baK2a@z(@baZlR)F)vHV$y^o(uKj6;i2`7##ahoEAoL)!S~4Gc%Y%9xtAlYYIwe z{gcuK3c5%pD3S4s^bPhfu&S5AgeECVlvECkhbs)W7IZFMLEqXM9PE`2Y9fXjE{0>CMCjzp<_e_leGB*g z`0IJ%4?oKJBd=hjKz{RUq)wio_~y6cuU>-*0)$qfHzZI9?PCIutY0KojB(M8k+NMn zZHG?B!M?4ZzI+chHeIO%({YE%$tf)9Acci1!4U#SXl%JwZ+zoQj=uZfGAx#08=tuz&7yTO%zT!fiCouuq2G9iM#rv2gJc-d z&_Pyv*lG=eW+tg=(iXTGZZleIac6neoYs1GW@}oTPieolOaQ@rr`ZPH$~l{-ta4^a z5?j52m~$MB#GjZzr_+c;vTA=A1A#I0s41rXUZ(vbeO`$eFvJ3=iYpdMEzfcT?)` zpA!V3Nf4G0;}gtU=X_{Xs<9LvJWWsx}>A#Ge?BZNiFvaylGEP-84%@rm9 z~K9T0N!sS8yCO5tB!{k&0JHFyW<$sevQO4PshId{)#QUViJ-3i%ngNewys_|zUu5Ha{P0hMDig#CL&PC0T63sAM z;MS?@G#8f5l>L3+I?d8bp2Bg%TF)oN?U!FLH6hLmG{+ZS>9?L$%0MhgK5kbhZnA@uPd$c^aQ1ADJH%lIcdg_JeGAJs^|58_MUI~?VwnK@*dZ7gL@!+q zfi52y&_a{f3g3V&B+`JiTvpz4FU!{5$ixf#D5cM%0iDfa_V2|#un#wz!Ad4ksZNaJ zgbS~ASr7ze&7iCus1gJvL{NgD2toLF;}^n|BCI=Bh@eP(Y7F<-K@yKYg8bSS37&rnKbA#T3mCX(Mh zjb|)WHiNT&FW!T1smQf27h4#E7bxOPkry_n%Id$N8)9*0#&hg>_yEOAGe{{YYQxF1 zd2WB-PmrA$W&fj(V7W2A^^LRaJo9_J^GELI(2jSp;un6A4gc*=IdOa%w^+dW{AZAX zN3i=YwDJ(X24m1@MzzK_n!topjV@(#oY9h{8y=u<)vffNd79~?-yuD6g1{(rp@2Mg z7;*dvZmI*-KZv_#4TaTfv3mQFu8VQpIoFW%N@&lgl*`~`G9<@GDO@;@J28$wJ%y(N zw3HajA@E`4@&vcMWh;~SypylS@1^KTY=Svu$e7kjZFK8A(Vzug^x8%x*EGcywYZ{T zQcUFmn~P%7JgKK$TBC8>+sBvB<0iD${HKv)@S1E0QmKZ`R9U8<6$w)42EN93W3iW*~^Jn&awC0G@UVqU;cG)5*+;2*RX7heTUMV`^1;I?R76B9()V;{_>lM|Iybtcs!4j&tw1H zXGl&@F>}uw(9$4-S=C)JWfY!PcxdR2<4ehT&m&`Z(7*XD46eVM{^6JKr(a=m<|OHf zF|^XCYzC3dP&{!QN+m4YK_n8;*@>{jszu=k$iPPz@&FXdLbWJGSTyCh7;WfGI{fHE zDg4*Hna_9sIK!nr+@Odf)VwgkpdxJkh9RZO4Og>hCc?GfaBW*m;BGb`sJ4#2t~{Lj z65m$xMzo-{6>d{nE8fMlNh>v3eeLkLvcu+LM*|ks1Ta(6vAP*D_!I>PZ9VY zzE{G}X9=bz2?9k>D&Uohc%FwchCr*Z5YqD@Tfme`A;)YRDFu07qA~@xh_kqzani9t zJe-Q6N>SxnnpH6)?cU0jlC^p5b&FZIwx+6#rP|9Kg)3@)rzx(WUcD#!9cR^l(}LD$ z+-O>(#`U(tQ_RH{;c0}bo9u3&K400A+&cihU* z4Y#7EC&*nqi%~uW4^AFW^U9$-exUJvRqjFz=GikuFJ zFY6-Jl|o=)rQ$4GGsq41Y@utY8@s!o*&}ox zc$%&LahCRKW;&OWCtjaiBB+?wG`}v@p4=LLLEWYl(Q8{1{;FN~hPahisAzIf+uToe zxMg*r8Lg4H&1kLL$8FFmqMVGac|4~Hlp_eDcku+kA`b^`l)w<75Y6&gDb6gpkvs3* z!SLsw2ir#FayZ}kDy5(J5I8Q(3V{k+YSNF|eu zOcgy`X=58n*OoiE%^uvG4$ScoL%I7E+G^LUi&J>(AJ6xB-xwAN*{WCi5 zyqDrVZ@}vrK$MewwDQR~9`2eB2G*})$WE{I2Ej@y{=!$F^oOxtGjD-Dghx;9trg=p{l zO{;iYOC7iQeyUAQGA(Fb4BWP8jW8G5;jy_Iy}%Yf3>aXhrz^7mYCN8GX%oy94`)ON ztCl)+9C(gPQ$Ch$qsK-_luGzpwnZ3rf|9m~i4s!#XkoC1Bvwjd_1M^J#&ENICqwmlz8hmqD7-t$pYV4xWXqX3P|ChyCkCDVD&(tJ#wWY(|(aj zzrd(hV8YKcnagtGnKNYfoFkb}k==MJiMKw8yKxInXD31hScN>QR0>TH6Amxc*(~PJ zKHO8sa2y-m+khzP|714l$Z`YW|U7!YkVCx=LifWdpbCO^aAv)8sHWp|zo)X%BaUL4cW>o|jlnha6Vh zMM6NqxJ<0v$u0QwuR6s!~>{Nnf8<&EC zWM_iqYnSl)ci+L#x*;+pLta5aNeaG!js#~Xi|jvm0iz98ph+6T9q-)6*8A2I(}t8K zS+cYrUoGQ>gZ(7jK15**70eL$nv+ewF8z<#R3ZHHE|5L#>P`NgKSxfvq*dJ)bwsR5+xs>)hQ+w#vOnrYF+vQ2%g zAKA;PGg&OVJRalZajeNnVwVge2(gqqu4f#ho``cE1L*bvI6TC(hIaDw{3O8@ly^%+gGyYmJO`AaUJoVB%W8m(@+RB z`9P6ZkPi&KTb7dRPBAJZ@fE%7c=ru#d&dqe%f^uwG0PztcewP_IsBI=ST?ko{()WC z+K`?(2QiDW2@h-E3*5hYl9?5om{y%gq3b-?4OQL9H4_ciw$Zv)9u!fR17DYr!$NRr zAGay35x7lht@+&r(aM$43W(mGYgGVDS7c??NUd7t*Tr>0A#mDV%hD~&Sb1?D!{@SC zw!laU=ZA@%JdWMfjT#(6TUMB7U#o~9$r~2|I6~pb00%$JDKKG6Ej4MAPfOAQCNx|O zAlnC4Ul4}-bbwGE1U{x{C?0T77dz2|JK(Ne#Jgfx)6?i&Hk{Uz&!SHpL%y;H_vk^K z>2VwkDrO_Ca3r@1@)Z3X=~9k~Vvf;Lj&ZL<(VwB91EvFqyn>?E6qF$s81h;&v}uqv zuUX5g*RG{wV;@DW(8|Z?utYfK3j7OGXI>ejZpb&hE5X|KAmYu=$DZhZ(bdOwMpvo9iP zjlyk4Yb0(vv{q^jZSuIfN5i!&0MgU-H-ezOKeJz@HD^0EvTDZ?)?RvcX8E^*fT zNXHAyd3Cv(Pii<1_F11L(qkxJB-fpQdp6_l+D)u?5GR*~+zf%zXrob6Q<$TN5&QNK zKky39g|oQ%3`QC(sX-_Lk*~Ug5E6wZq##`c7W=!|&ku;S-!YbCSGoap|Qq z+`FN`ndP@qQg#@z7EMCr5ofF6+9H~+YvlL0`b-_BSkQio#9T0L3#^6EDq3OInhiB6 z&OM7K0EB5{Vj3V|3asDa)nP zvde!gI&DeHf^J99=R#jXkkUS-qnGILimcf+NZ)dogbX-8Hp9n${r7nIuRntc6l<3z zSoNPi%6GQ?7}E0^hxDj!6IPXuSD6-9<>YE(U8`ba&4z2WgWJY_YKlp7+@`eFe8+-l zZIR5|ipRzv*RDY%6VWqRQed+D>f{>!+f@|+Rpr3>0{YCE>gmAczHj<6lNYtL*rHFf z(I-dh_SF4tDekf+jw zlYi&>(^c4Zresk%?4V~PB4u#52FOkYrtIvrV~BW)gtkc>7-Px)J=mH3jE*{B4O^Qo&qZ7R(2L>V4MWLgcQmO}$>?D@zA{Or?mgpdr z=q8rzqT6=qv~7BAn?6U-=V%5Jf}yyf&(;jMlAf5L%dt85e}9YL{{4^h^u)6iOR#DE z0NtPX9iHraJyHejCwg3sT-0k7_gbaZ804D8699`g9k_8K#H`(98s8`_9;p=v#X80x z{7rUj{vJ!e@&%4ObDT_3g@?*^2s{sSZn8Utjpa??_u4Rd&%F{ zM>2DmfBM5uGJNVHw&NfyiIIk)7mgga{D6G^Jd-ovC`F+t$Xn&I-SQw5%W-i#I}ouX zrC6M7Jc-}gNB__=I{TM#c4!Tq%hxhExSYnw*M&V zsLk^uPjY^EoK>IyGdBPH29Ai;SVpzCz*qY)w1FGZcxdr)uK`+Ljc1XEgNpgSc;&y( z8UYQ}hDx<5;%ANtnDA3PzWSZ4{KebYbkDc(zx@r)?mfkH&LC`wZHIjU{A?EX??vq2 ziG2YiQ+bpE zX*-m(2sM{E2bLxXiWKwtFzhTqluMMyrC?kLjF7}TIyu=lL~7M0`gh#M;I7+PwP7=B z20BTgZnUpu%9;&Bb;VjkH=^#Pnc8`+&vV$fGO*jOQvw#7RC z47-ngiQEsK;_Uv5oV!$_6d0r}kWwON%dIN>0hVoJCzIgB@NFC4vdYCZ7D%gVVPdI{ zP@6CyQz^W7f@~s*)!9X&x0ga!4=R-c$3|-th89n`_$M5+0k;$S?@sah^~<%VYMN*qnVHZzhdD>eDxMf|=1#rY1dd#Uvu1M|eKDoR3z9 zAW&qp1(XU0g!%#az6sMrg+UsFAZ%n3@9L#{?G{$w^&mT5|3*@7H>Ww7=v8B`r0r7+E;PJydR)tU22n% zh0qXaPRLc9-u_|MZG8_rrk~-aLwgu~#b$S!bK`3zc<#AOkqBqiTvd2o(?F~Kr_ z3TXngQUt|3*<6zT>=^dsMbe`e$&D*Y7pEAxm?ob$2oxOVVT<74n*QE`gTT}E4+pR45ySv(D(P(Ys@j#inX-nyB}(_$4A5@T8P$SnPOn&s&u^pBl} zQwNzoH-Wh{#l*-onVg4E2H!XM0jSwwq-A^GvBQyF!j%YNuw*cYrL_eblxHZEG^LV< z4okDJjK)dCkOM>LZQIc|-9%~m$~ln{@95-#p+Pndt>n^?Lp=KLe-^Je!wvUr;><7n zE+>N3g!73hPxPzsnFy<{XXdPfGA2BdvOr9D!~(^d;$ci?n&gE`1V>(C`uHT1r_M1s z6;SlT{Do!tK3_pp5JN*?*+KjGV-{xp3ZHgEcm@8EOWewAWL)+}F3k5t75 zAbJ>N!{4d2=ohkQuHJsSY~0!rL``uQcs^?RGphk4;@6r65J6Zgi5Ha*-AYOdu+X41 z85L(nEaPPNN~|7DYD<9_0n1D0={9mJofovoM)dRweu#5_r4Cb zay7ozT*~KJmrqk%w}p*&y^d$U^p8xOy1+nwnB(!a^ESV!sarEaW6!h!4~a(#LkbX_ za+e?m1ny8kYIlk5;yCNl``C5hX-Y4>!qI(WTpCOB`2YSiM<4$lcl^YUv+<#~b7ap8 zoP6PBE`IY_wrxJf^Ku7{3EEhP25T#7HfrR608xEtXm|au@_xD!T-hjWM|5v*!{zb# zT5|$6DhG}nrp5xo9Sc!)1alK{XUm4ODn{1C7?s;0ArMIr{RUeYBpNBJn~rM2q#>ot z_phm}FAr7JmzLg#Efo^Mpc!Yif1GU>&*C21!`O32Ielo1>6twC(@zjTb{O&CTk!9H zfD#~-Pu_vf``<|F+uvYn%;S!!SJ<=aE|gz?cG{tLo;~3#L(2UR(#B=VTE*#sH6&mE zCN|%9jP2)NV)qM=aqRJ9oH%}#hkxf2?0Cx?S$ogDj2t`8%g>MTz_D+zf6Eqvpq+3} z8=GCUvuVTv?vz()KV5CysI_j3$JdwuXgt9@B2ZI12}RV-K&zU^v;ZTm{xhPij@blN zeWdh!k?&c{vA!YBoj*(F*umiHx3TN>&$02@Z*%Nx&#~_-57WPXEy?aK#?Oy3`RFrj+y!_G()8BoR3E!vq z;r~E#-xTX73M_YqI9WW77#^peNir-6zpEK$9lfT;@zjXNvqCT&P%@@Ed9>qA^uOsY zcHjC0D<1v__CCCq=>j-0i-RwYaN~t1IlN*61Y+SluFHZGZDlZaLl8CcyZL)4@`{ zy5qwn|Ko4)rXSx)G8yCa4<6^4KllTt&rWf2NiVTgn-IPtf8heF-#T4P3S645@7 zr7+mWXWCEjXzyEi>4X23TmIv}V)N!6bf6g-FOhuVahBU-XdxHQ<7Vp`$z#z5t*_F4 z5|^=`Uafsx)e>2}`U1cR{Psd6qTyf=(GKHie83v_TNh0+BXL_TOoM+n3&6Ed_@3aK z;tf3af&az>AGw$A4wr*ZeUB3_{}TrXQ^Z%TC7w(%H8O!46tIPE{7zAwVlJD<^DU|^ z zXFrLB@8hVl=_bxOBO*)p7A^oJrPQ9 z*i2^o&~hGARD}BKg>XIY!gy?|I@U;GP`={v)O}3+;(y|;@7=`kkqMTadKTB#3+M5y zzhnVC7KjDYTBmWewV&$OwIyyl`>Bkxu>E8fzK=x(kA(=&TC+!$&+MXU0Fs4$+aIcH9glv`KGL7;DVH)mYD5@mD*Cm1UM)zmil@8?qB1!pL-)EufW+a ze}k1)7tIN140)kj(N)#}bcMRvXxwsS z{KQl^5KV;>zTDEfydh0R>*{tQ6VhBZ-n)Zo(M$Ctnl?(-+FI9$wQWXgm5{l5`zd;Do96*k z=8UvMt7y58qj8Ne2+Io3nrSKklz{O?GXaFhX#s_%s)rO{+w=Uc?a)-&wAD0ls+2D% zQ{@4z7&lh;eKkWDq6RXGO7p266RJl}RpM$P%R?aN6N2h-ThIy!rP(`hHyhu5H>FG( z-}k~|1ly`|h?%C}Igi^8k4bx<=yC?%H1c{d7gR zH3y>^kFNw%7{W`onYj`EQ$cu~UNiv^PcbRrVyjQj+P1Z!(8?(@MpTDPE1ex;&gs^; z*ZV@+w>H9!a=gs@glcCN%<2HL>V_4w z?w+j}U(vf_83ns*ma?X_R(q0}&m3$*YZSevLh-D}rKYWW`#f&Gt`R(*6*o<3p+}N&JA5k0o$pG zH?&a%^+OUP;ZX4?w$>XN9M&Y*JPvSE6)0ObJ z9a>Er`>7Up?z>{K@QgLH|4V@3v3AdO+qD3;#q&xrg+*_(@@kPxVG4yvTSwGou~phS zrmDxhX>v=51~JuUUfWtVv0+H39oz^^Ev&hKkcf!+T4-k69&UX7T3%XxGsVEc5<8e0BFzv$buxpDIFpi?g4qap&~1WU6^n zL;)zKY>VgHJ=bk(0OKbZHSjV{Bge@64`d>Vv8ZYJQiZX zJic1{sTQ}L{d8G87MHcMr$o@TeMyQkDIM)6s|F%GIgpg9xrS^l^wNh&{~Vz&VITq z9xrG=&C;O}sZ}z>LD3ky;R+04TM^SXt#!Djwy%U~$zwCu zey=sH7*m~ibG3QgjMiFQVd|2g7Gpov;DNvo?IDsitCt+VusnvLC@$D%Fwim9_xFOSEfl|5X^A0ryd zn}62*MD=F(-UXK}xTj6o9rFC{bf~>gmL>uF_o8dO2wf?iBHLVqK z&V};0mF?dgcLB7DtGk~ri^mNdk&CjQW=-nO?$%9=6vn{cm<4tZTyR5>^lBb99xvjw zuq|8%+1WKOf}?7&Yr{5`o|4+cigHLq2vHY4i(1@9VVdZ$P$OJ3kJ(23b|q$QGE8ll zscl+Y;)<3$u1o}Kg&QU~wMpwD@OUA#iZ*DytotQ5_1q$~6(3TxA|NrPYL0f3ml) zb@LAw@Y(0&`QqiA<;xNPql09H;{U>+o7z~j4#Do81|5Bx_fc%M5zGP?DhgAGMs{8W zu2|S&)^0v+<}<@;?QqlJ;9SloYKPvoXr-dm;8o!9{OriZrS)?56AKism(AlA`)PJa zjO^|~xNhr)*aoc?|JUetvX^s~7Ze7p!InK|_`FQ;UQ=xSVLg*Zr>84yQc)FxnKPeF zv=lc@4qM&ND+YheJA@iwvao4WO>t)nH_ZHE&h`@s=M6N#tqAM2MOT}&M)7#jXsy9* zhS>_Y9a`r;J6n9z2CWO(PuC2OjX`$zAiLUd{Kdf(_~P^$e%R1n?*F0*0DyrrY||D` zA?ax+^+2bm(3zR)kV#ZnrAgRkL7TM24NaT43)!T#KbJIa`m<14uapPkRiO29c--Fi z3o3(gi$!aspjn7eTCDwK45G6O+1=avFj;_RT59eZU&EoxJ;PVj7JPgShm7X8+tt-% zcTX4@s4Pc~U|K`NE@DyIu^$_$W_2N#HgFeWqt6v{M2PZ*(i+uGyAiF8OpJDE6*X1! z?b3QRc`W9dv$dvmQFu)IJYEc14U`XmPkW9B3C8f-S918TSO5S_Kg%C$kG~_j>1X-lD?PtgWCF}S9j969 zT6{;iY&WI$90(?tL#L-PDyV28x^UHYp{g@n-tetfIL&^iDQf#^C@c& zu`uo5vMn(qaIZv@Su|Q-Z605yCUdRvxVF`IQyv?Gux&(VHzJh^&Bb<(pbZ$(TJgT= z)qH!g&g`NJ0DzuT{IGQR43c=;MTr7T5MZ(ybUruNTAbR#js>W5jVs9-{EX)P6&8eB z)`N{{<6Rb@lD9mVQI%wsb5R$Y)kJ37P8 zKJ6Yo8_*QB&reRTel!d_iq{Cle(be9BvI=JU0Vbct6!M`)(4cEfJDao} ze?i+DeF49-;G0G?zNM}f?qburP@8!nK9WXZz{RFD>fhTHl+AI&l5b<%$aoTw>OeU5 zg35J-14c2UeST(o9bZ`NvwBqo06@<$Z?xdE#$^emg}xP_G{!4o3VF0wf*`07!J>Ve znd%AFm*W&#s7hGzif!RuN&LJW+^a=vr4OK8TCdc<@@nw7o&8jWTWQKj88+~AW8uM% z#lVsatkVNxAUsACd~kXdk6ev&desB~K=&}Ok%GSvE;p2$6)s#5P!3e%{~VatY5o5Rk6l2aQG6j#d~9YNM_x6#^J)r! z*{Amm?-mvxMRGe5@ULqG*Ps9Y-S{|!HGG<9jp7qiYxt*E{WbnM1OUK_JtPbLJY+2X zjS$=|TrfVMuJ4WO&%fZuDj$3gFg$_cPZAS+<@_z=|5@bFKbHWQdx3+vy&b#}!3PXH zC>#cbEDHmDT{F1;{0q40WjUU&LmOYfw=sNfD$65g`{f$K|3U;n<&!+lN;kpVgywC+ za4Ui(B96p>Q56Eg)EH9NpX<**_aUGCZ~4Gum2*#uXbdAp@Pd&%>=k%8zmap-%&T8Z z0-*BgK1ZJv+$enRz~V+UTYwb^IuOJVNbK@BWVtwwoOZrrL3!|tgc*hV|210wzr^FV zen*!trT{Q#3?&R%;5?EeTCrC+JfjVJ(<_<0CS}*PDgf$UbPrBvC*3l}Y6QI!l0uNw zilnr$qI?Ic!t{!I+WE{vo_4?Qp96QXF|TDFUsYNy&;d$X(BM)`g2_XTz{@V*PrVG;QDj@ vx&B-i0N0=E&-LfJ0J#2Kf383O(w_ep0g6pEog0Lw00000NkvXXu0mjf8`>5> literal 0 HcmV?d00001 -- 2.34.1