From 5f2c175958d679ca53e02588b75a13df34a9ace3 Mon Sep 17 00:00:00 2001 From: Sascha Leib Date: Sat, 13 Sep 2025 23:20:43 +0200 Subject: [PATCH 1/3] New release 13.09 --- action.php | 73 +++++--- admin.php | 2 - client.js | 2 +- conf/default.php | 8 + conf/metadata.php | 9 + config/default-config.json | 115 +++++++++++++ {conf => config}/known-bots.json | 24 +-- {conf => config}/known-clients.json | 0 config/known-ipranges.json | 160 ++++++++++++++++++ {conf => config}/known-platforms.json | 0 .../user-config.json | 4 + lang/en/settings.php | 10 ++ plugin.info.txt | 2 +- script.js | 93 ++++------ style.less | 14 +- 15 files changed, 410 insertions(+), 106 deletions(-) create mode 100644 conf/default.php create mode 100644 conf/metadata.php create mode 100644 config/default-config.json rename {conf => config}/known-bots.json (94%) rename {conf => config}/known-clients.json (100%) create mode 100644 config/known-ipranges.json rename {conf => config}/known-platforms.json (100%) rename conf/botmon-config.json => config/user-config.json (96%) create mode 100644 lang/en/settings.php diff --git a/action.php b/action.php index a1aab74..0535472 100644 --- a/action.php +++ b/action.php @@ -20,12 +20,19 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { * @return void */ public function register(EventHandler $controller) { + + // insert header data into the page: $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'insertHeader'); + + // write to the log after the page content was displayed: + $controller->register_hook('TPL_CONTENT_DISPLAY', 'AFTER', $this, 'writeServerLog'); + } /* session information */ private $sessionId = null; private $sessionType = ''; + private $ipAddress = null; /** * Inserts tracking code to the page header @@ -41,28 +48,23 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { $this->getSessionInfo(); // is there a user logged in? - $username = ( !empty($INFO['userinfo']) && !empty($INFO['userinfo']['name']) - ? $INFO['userinfo']['name'] : ''); + $username = ( !empty($INFO['userinfo']) && !empty($INFO['userinfo']['name']) ? $INFO['userinfo']['name'] : ''); // build the tracker code: $code = NL . DOKU_TAB . "document._botmon = {'t0': Date.now(), 'session': '" . json_encode($this->sessionId) . "'};" . NL; if ($username) { $code .= DOKU_TAB . 'document._botmon.user = "' . $username . '";'. NL; } - $code .= DOKU_TAB . "addEventListener('load',function(){" . NL; + // add the deferred script loader:: + $code .= DOKU_TAB . "addEventListener('load', function(){" . NL; $code .= DOKU_TAB . DOKU_TAB . "const e=document.createElement('script');" . NL; $code .= DOKU_TAB . DOKU_TAB . "e.async=true;e.defer=true;" . NL; $code .= DOKU_TAB . DOKU_TAB . "e.src='".DOKU_BASE."lib/plugins/botmon/client.js';" . NL; $code .= DOKU_TAB . DOKU_TAB . "document.getElementsByTagName('head')[0].appendChild(e);" . NL; $code .= DOKU_TAB . "});" . NL . DOKU_TAB; - $event->data['script'][] = [ - '_data' => $code - ]; - - /* Write out server-side info to a server log: */ - $this->writeServerLog($username); + $event->data['script'][] = ['_data' => $code]; } /** @@ -70,38 +72,32 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { * * @return void */ - private function writeServerLog($username) { + public function writeServerLog(Event $event, $param) { global $conf; global $INFO; + // is there a user logged in? + $username = ( !empty($INFO['userinfo']) && !empty($INFO['userinfo']['name']) + ? $INFO['userinfo']['name'] : ''); + + + // clean the page ID $pageId = preg_replace('/[\x00-\x1F]/', "\u{FFFD}", $INFO['id'] ?? ''); - // collect GeoIP information (if available): - $geoIp = ( $this->sessionId == 'localhost' ? 'local' : 'ZZ' ); /* User-defined code for unknown country */ - try { - if (extension_loaded('geoip') && geoip_db_avail(GEOIP_COUNTRY_EDITION)) { - $geoIp = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']); - } else { - Logger::debug('BotMon Plugin: GeoIP module not available'); - } - } catch (Exception $e) { - Logger::error('BotMon Plugin: GeoIP Error', $e->getMessage()); - } - // create the log array: $logArr = Array( - $_SERVER['REMOTE_ADDR'] ?? '', /* remote IP */ + $this->ipAddress, /* remote IP */ $pageId, /* page ID */ $this->sessionId, /* Session ID */ $this->sessionType, /* session ID type */ - $username, + $username, /* user name */ $_SERVER['HTTP_USER_AGENT'] ?? '', /* User agent */ $_SERVER['HTTP_REFERER'] ?? '', /* HTTP Referrer */ substr($conf['lang'],0,2), /* page language */ implode(',', array_unique(array_map( function($it) { return substr($it,0,2); }, explode(',',trim($_SERVER['HTTP_ACCEPT_LANGUAGE'], " \t;,*"))))), /* accepted client languages */ - $geoIp /* GeoIP country code */ + $this->getCountryCode() /* GeoIP country code */ ); //* create the log line */ @@ -123,8 +119,31 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { fclose($logfile); } + private function getCountryCode() { + + $country = ( $this->ipAddress == 'localhost' ? 'AA' : 'ZZ' ); // default if no geoip is available! + + $lib = $this->getConf('geoiplib'); /* which library to use? (can only be phpgeoip or disabled) */ + + try { + + // use GeoIP module? + if ($lib == 'phpgeoip' && extension_loaded('geoip') && geoip_db_avail(GEOIP_COUNTRY_EDITION)) { // Use PHP GeoIP module + $result = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']); + $country = ($result ? $result : $country); + } + } catch (Exception $e) { + Logger::error('BotMon Plugin: GeoIP Error', $e->getMessage()); + } + + return $country; + } + private function getSessionInfo() { + $this->ipAddress = $_SERVER['REMOTE_ADDR'] ?? null; + if ($this->ipAddress == '127.0.0.1' || $this->ipAddress == '::1') $this->ipAddress = 'localhost'; + // what is the session identifier? if (isset($_SESSION)) { $sesKeys = array_keys($_SESSION); /* DokuWiki Session ID preferred */ @@ -140,8 +159,8 @@ class action_plugin_botmon extends DokuWiki_Action_Plugin { $this->sessionId = session_id(); $this->sessionType = 'php'; } - if (!$this->sessionId) { /* no PHP session ID, try IP address */ - $this->sessionId = $_SERVER['REMOTE_ADDR'] ?? ''; + if (!$this->sessionId && $this->ipAddress) { /* no PHP session ID, try IP address */ + $this->sessionId = $this->ipAddress; $this->sessionType = 'ip'; } if (!$this->sessionId) { /* if everything else fails, just us a random ID */ diff --git a/admin.php b/admin.php index aae7228..ade38a3 100644 --- a/admin.php +++ b/admin.php @@ -59,7 +59,6 @@ class admin_plugin_botmon extends AdminPlugin {
-
@@ -69,7 +68,6 @@ class admin_plugin_botmon extends AdminPlugin {
-
diff --git a/client.js b/client.js index 91b7c7b..d1f8018 100644 --- a/client.js +++ b/client.js @@ -73,7 +73,7 @@ botmon_client = { console.error(err); } finally { /* send the next heartbeat signal after x seconds: */ - setTimeout(this._onHeartbeat.bind(this, this._src.replace( this._scriptName, '/tick.php')),this._heartbeat * 1000); + // setTimeout(this._onHeartbeat.bind(this, this._src.replace( this._scriptName, '/tick.php')),this._heartbeat * 1000); } } } diff --git a/conf/default.php b/conf/default.php new file mode 100644 index 0000000..1ba3fbd --- /dev/null +++ b/conf/default.php @@ -0,0 +1,8 @@ + + */ + +$conf['geoiplib'] = 'disabled'; diff --git a/conf/metadata.php b/conf/metadata.php new file mode 100644 index 0000000..409716f --- /dev/null +++ b/conf/metadata.php @@ -0,0 +1,9 @@ + + */ + +$meta['geoiplib'] = array('multichoice', + '_choices' => array ('disabled', 'phpgeoip')); diff --git a/config/default-config.json b/config/default-config.json new file mode 100644 index 0000000..d0b79c9 --- /dev/null +++ b/config/default-config.json @@ -0,0 +1,115 @@ +{ + "threshold": 100, + "rules": [ + {"func": "fromKnownBotIP", + "id": "botIpRange", "desc": "Common Bot IP range", + "bot": 50 + }, + {"func": "matchesClient", "params": ["aol", "msie", "chromeold","oldedge"], + "id": "oldClient", "desc": "Obsolete browser version", + "bot": 40 + }, + {"func": "matchesPlatform", "params": ["winold", "macosold"], + "id": "oldOS", "desc": "Obsolete platform version", + "bot": 40 + }, + {"func": "matchesPlatform", "params": ["winsrvr", "bsd"], + "id": "serverOS", "desc": "Server OS", + "bot": 40 + }, + {"func": "smallPageCount", "params": [1], + "id": "onePage", "desc": "Visiter viewed only a single page", + "bot": 40 + }, + {"func": "noRecord", "params": ["log"], + "id": "noClient", "desc": "No client-side JS log was recorded", + "bot": 50 + }, + {"func": "noRecord", "params": ["tck"], + "id": "noTicks", "desc": "No client ticks were recorded", + "bot": 10 + }, + {"func": "noReferrer", + "id": "noRefs", "desc": "No referer field", + "bot": 30 + }, + {"func": "matchLang", "params": [], + "id": "langMatch", "desc": "Client’s ‘Accept-Language’ header does not match the page language", + "bot": 30 + }, + {"func": "matchesClient", "params": ["brave"], + "id": "susClient", "desc": "Client identifier that is popular with bot networks", + "bot": 10 + }, + {"func": "combinationTest", "params": [["macos", "chrome"]], + "id": "unusualPC", "desc": "Unusual combination of platform and client", + "bot": 10 + }, + {"func": "combinationTest", "params": [["macos", "chromeold"],["macosold", "brave"],["winold", "edge"],["winold", "brave"]], + "id": "suspPC", "desc": "Suspicious combination of platform and client", + "bot": 30 + }, + {"func": "combinationTest", "params": [["macos", "msie"], ["win10", "safari"]], + "id": "impPC", "desc": "Impossible combination of platform and client", + "bot": 80 + }, + {"func": "loadSpeed", "params": [3, 20], + "id": "speedRun", "desc": "Average time between page loads is less than 20 seconds", + "bot": 80 + }, + {"func": "noAcceptLang", + "id": "noAcc", "desc": "No “Accept-Language” header", + "bot": 40 + }, + {"func": "matchesCountry", "params": ["BR", "CN", "RU", "US", "MX", "SG", "IN", "UY"], + "id": "isFrom", "desc": "Location is in a known bot-spamming country.", + "bot": 50 + }, + {"func": "matchesCountry", "params": ["ZZ"], + "id": "zzCtry", "desc": "Location could not be determined", + "bot": 20 + } + ], + "ipRanges": [ + {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, + {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, + {"from": "24.240.0.0", "to": "24.247.255.255", "mask": 13, "label": "Charter [US]"}, + {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, + {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, + {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, + {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, + {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, + {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, + {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, + {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, + {"from": "110.238.96.0", "to": "110.238.127.254", "label": "Huawei [SG]"}, + {"from": "111.119.192.0", "to": "111.119.255.254", "label": "Huawei [SG]"}, + {"from": "119.0.0.0", "to": "101.207.255.254", "label": "Unicom [CN]"}, + {"from": "121.91.168.", "to": "121.91.175.254", "label": "Huawei [HK]"}, + {"from": "122.8.0.0", "to": "122.8.255.254", "label": "CN-ISP [CN]"}, + {"from": "122.9.0.0", "to": "122.9.255.254", "label": "Huawei [CN]"}, + {"from": "124.243.128.0", "to": "124.243.191.254", "label": "Huawei [SG]"}, + {"from": "142.147.128.0", "to": "1142.147.255.254", "label": "Web2Objects LLC [US]"}, + {"from": "150.40.128.0", "to": "150.40.255.254", "label": "Huawei [HK]"}, + {"from": "159.138.0.0", "to": "159.138.225.254", "label": "Huawei [TH]"}, + {"from": "162.128.0.0", "to": "162.128.255.254", "label": "Zenlayer [SG]"}, + {"from": "166.108.192.0", "to": "166.108.255.254", "label": "Huawei [SG]"}, + {"from": "177.0.0.0", "to": "177.255.255.254", "label": "BrasilNET [BR]"}, + {"from": "179.0.0.0", "to": "179.255.255.254", "label": "BrasilNET [BR]"}, + {"from": "183.87.32.0", "to": "183.87.159.254", "label": "Huawei [HK]"}, + {"from": "186.0.0.0", "to": "186.255.255.254", "label": "South-American ISPs (186.x)"}, + {"from": "187.0.0.0", "to": "187.255.255.254", "label": "South-American ISPs (187.x)"}, + {"from": "188.0.0.0", "to": "188.255.255.254", "label": "South-American ISPs (188.x)"}, + {"from": "189.0.0.0", "to": "189.255.255.254", "label": "South-American ISPs (189.x)"}, + {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, + {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, + {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, + {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, + {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 30, "label": "VNPT [VN]"}, + {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Amazon Cloud [US]"}, + {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 32, "label": "Charter [US]"}, + {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 24, "label": "Charter [US]"}, + {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "mask": 16, "label": "Inspire [BR]"}, + {"from": "2a0a:4cc0::::::", "to": "2a0a:4cc0:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Netcup [DE]"} + ] +} \ No newline at end of file diff --git a/conf/known-bots.json b/config/known-bots.json similarity index 94% rename from conf/known-bots.json rename to config/known-bots.json index 40ab292..ededd49 100644 --- a/conf/known-bots.json +++ b/config/known-bots.json @@ -1,35 +1,35 @@ [ {"id": "bingbot", - "n": "BingBot", + "n": "BingBot", "geo": "US", "r": ["bingbot"], "rx": ["\\sbingbot\\/(\\d+\\.\\d+);"], "url": "http://www.bing.com/bingbot.htm" }, {"id": "googlebot", - "n": "GoogleBot", + "n": "GoogleBot", "geo": "US", "r": ["Googlebot"], "rx": ["Googlebot\\/(\\d+\\.\\d+)", "Googlebot-Image\\/(\\d+\\.\\d+)"], "url": "http://www.google.com/bot.html" }, {"id": "googleads", - "n": "Google Ads", + "n": "Google Ads", "geo": "US", "r": ["AdsBot-Google", "AdsBot-Google-Mobile", "Mediapartners-Google"], "rx": ["AdsBot-Google;","AdsBot-Google-Mobile;", "Mediapartners-Google\\/(\\d+\\.\\d+);"], "url": "https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers" }, {"id": "googleapi", - "n": "Google API Crawler", + "n": "Google API Crawler", "geo": "US", "r": ["APIs-Google"], "rx": ["APIs-Google"], "url": "https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers" }, {"id": "applebot", - "n": "Applebot", + "n": "Applebot", "geo": "US", "r": ["Applebot"], "rx": ["Applebot\\/(\\d+\\.\\d+);"], "url": "http://www.apple.com/go/applebot" }, {"id": "slurp", - "n": "Slurp (Yahoo!)", + "n": "Slurp (Yahoo!)", "geo": "US", "r": ["Slurp"], "rx": ["Slurp[\\s;\\)]"], "url": "http://help.yahoo.com/help/us/ysearch/slurp" @@ -41,25 +41,25 @@ "url": "https://duckduckgo.com/duckduckbot.html" }, {"id": "openai", - "n": "OpenAI/ChatGPT", + "n": "OpenAI/ChatGPT", "geo": "US", "r": ["OAI-SearchBot", "ChatGPT-User", "GPTBot"], "rx": ["OAI-SearchBot\\/(\\d+\\.\\d+);", "ChatGPT-User\\/(\\d+\\.\\d+);", "GPTBot\\/(\\d+\\.\\d+);"], "url": "https://platform.openai.com/docs/bots/" }, {"id": "claude", - "n": "Anthropic Claude", + "n": "Anthropic Claude", "geo": "US", "r": ["ClaudeBot", "Claude-User", "Claude-SearchBot"], "rx": ["ClaudeBot\\/(\\d+\\.\\d+);"], "url": "https://darkvisitors.com/agents/claudebot" }, {"id": "perplexity", - "n": "Perplexity", + "n": "Perplexity", "geo": "US", "r": ["PerplexityBot", "Perplexity‑User"], "rx": ["PerplexityBot\\/(\\d+\\.\\d+);", "Perplexity‑User\\/(\\d+\\.\\d+);"], "url": "https://perplexity.ai/perplexitybot" }, {"id": "metabots", - "n": "Meta/Facebook", + "n": "Meta/Facebook", "geo": "US", "r": ["facebookexternalhit", "facebookcatalog","meta-webindexer","meta-externalads","meta-externalagent","meta-externalfetcher"], "rx": ["facebook\\w+\\/(\\d+\\.\\d+)", "meta-\\w+\\/(\\d+\\.\\d+)"], "url": "https://developers.facebook.com/docs/sharing/webmasters/crawler" @@ -89,7 +89,7 @@ "url": "https://ahrefs.com/robot/" }, {"id": "ccbot", - "n": "CommonCrawl Bot", + "n": "CommonCrawl Bot", "geo": "US", "r": ["CCBot"], "rx": ["CCBot\\/(\\d+\\.\\d+)[\\s\\.;]*"], "url": "https://commoncrawl.org/bot.html" @@ -185,7 +185,7 @@ "url": "http://www.sogou.com/docs/help/webmasters.htm#07" }, {"id": "amazon", - "n": "Amazonbot", + "n": "Amazonbot", "geo": "US", "r": ["Amazonbot"], "rx": ["Amazonbot\\/(\\d+\\.\\d+)[;\\s\\(\\.]"], "url": "https://developer.amazon.com/amazonbot" diff --git a/conf/known-clients.json b/config/known-clients.json similarity index 100% rename from conf/known-clients.json rename to config/known-clients.json diff --git a/config/known-ipranges.json b/config/known-ipranges.json new file mode 100644 index 0000000..2542329 --- /dev/null +++ b/config/known-ipranges.json @@ -0,0 +1,160 @@ +{ + "isps": [ + {"i": "hetzner", "n": "Hetzner Online GmbH", "g": "DE"}, + {"i": "huawei", "n": "Huawei Cloud", "g": "HK"} + ], + "5": [ + {"9": {"i": "hetzner", "g": "FI"}}, + {"75": [ + {"128": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "23": [ + {"88": [ + {"0": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "37": [ + {"27": {"i": "hetzner", "g": "FI"}} + ], + "46": [ + {"4": {"i": "hetzner", "g": "DE"}}, + {"62": [ + {"128": {"m": 17, "i": "hetzner", "g": "FI"}} + ]} + ], + "49": [ + {"12": {"i": "hetzner", "g": "DE"}}, + {"13": {"i": "hetzner", "g": "DE"}} + ], + "65": [ + {"108": {"i": "hetzner", "g": "FI"}}, + {"109": {"i": "hetzner", "g": "FI"}}, + {"210": {"i": "hetzner", "g": "FI"}} + ], + "77": [ + {"42": [ + {"0": {"m": 17, "i": "hetzner", "g": "FI"}} + ]} + ], + "78": [ + {"46": {"i": "hetzner", "g": "DE"}}, + {"47": {"i": "hetzner", "g": "DE"}} + ], + "85": [ + {"10": [ + {"192": {"m": 18, "i": "hetzner", "g": "FI"}} + ]} + ], + "88": [ + {"99": {"i": "hetzner", "g": "DE"}}, + {"198": {"i": "hetzner", "g": "DE"}} + ], + "91": [ + {"98": {"i": "hetzner", "g": "DE"}}, + {"99": {"i": "hetzner", "g": "DE"}}, + {"107": [ + {"128": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "94": [ + {"130": {"i": "hetzner", "g": "DE"}} + ], + "95": [ + {"216": {"i": "hetzner", "g": "FI"}}, + {"217": {"i": "hetzner", "g": "FI"}} + ], + "110": [ + {"239": [ + {"64": {"m": 19, "i": "huawei", "g": "SG"}}, + {"96": {"m": 19, "i": "huawei", "g": "SG"}} + ]} + ], + "114": [ + {"119": [ + {"128": {"m": 19, "i": "huawei", "g": "SG"}} + ]} + ], + "116": [ + {"202": {"i": "hetzner", "g": "DE"}}, + {"203": {"i": "hetzner", "g": "DE"}} + ], + "119": [ + {"8": [ + {"32": {"m": 19, "i": "huawei", "g": "HK"}}, + {"96": {"m": 19, "i": "huawei", "g": "HK"}}, + {"160": {"m": 19, "i": "huawei", "g": "SG"}} + ]} + ], + "124": [ + {"243": [ + {"128": {"m": 18, "i": "huawei", "g": "SG"}} + ]} + ], + "128": [ + {"140": [ + {"0": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "135": [ + {"181": {"i": "hetzner", "g": "FI"}} + ], + "138": [ + {"199": [ + {"128": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "142": [ + {"132": [ + {"128": {"m": 17, "i": "hetzner", "g": "DE"}} + ]} + ], + "154": [ + {"220": [ + {"192": {"m": 19, "i": "huawei", "g": "HK"}} + ]} + ], + "157": [ + {"90": {"i": "hetzner", "g": "DE"}}, + {"180": [ + {"0": {"m": 17, "i": "hetzner", "g": "FI"}} + ]} + ], + "159": [ + {"69": {"i": "hetzner", "g": "DE"}} + ], + "162": [ + {"55": {"i": "hetzner", "g": "DE"}} + ], + "167": [ + {"233": {"i": "hetzner", "g": "DE"}}, + {"235": {"i": "hetzner", "g": "DE"}} + ], + "168": [ + {"119": {"i": "hetzner", "g": "DE"}} + ], + "176": [ + {"9": {"i": "hetzner", "g": "DE"}} + ], + "178": [ + {"63": {"i": "hetzner", "g": "DE"}} + ], + "188": [ + {"34": [ + {"128": {"m": 17, "i": "hetzner", "g": "DE"}} + ]}, + {"40": {"i": "hetzner", "g": "DE"}}, + {"245": {"i": "hetzner", "g": "DE"}} + ], + "195": [ + {"201": {"i": "hetzner", "g": "DE"}} + ], + "213": [ + {"133": [ + {"69": {"m": 19, "i": "hetzner", "g": "DE"}} + ]}, + {"239": [ + {"192": {"m": 18, "i": "hetzner", "g": "DE"}} + ]} + ] +} \ No newline at end of file diff --git a/conf/known-platforms.json b/config/known-platforms.json similarity index 100% rename from conf/known-platforms.json rename to config/known-platforms.json diff --git a/conf/botmon-config.json b/config/user-config.json similarity index 96% rename from conf/botmon-config.json rename to config/user-config.json index c17bd77..739dc64 100644 --- a/conf/botmon-config.json +++ b/config/user-config.json @@ -65,6 +65,10 @@ "id": "isFrom", "desc": "Location is in a known bot-spamming country.", "bot": 50 }, + {"func": "notFromCountry", "params": ["DE", "AT", "CH", "LI", "LU", "BE"], + "id": "notFromHere", "desc": "Location is not among the site’s main target countries.", + "bot": 20 + }, {"func": "matchesCountry", "params": ["ZZ"], "id": "zzCtry", "desc": "Location could not be determined", "bot": 20 diff --git a/lang/en/settings.php b/lang/en/settings.php new file mode 100644 index 0000000..388f996 --- /dev/null +++ b/lang/en/settings.php @@ -0,0 +1,10 @@ + + */ + +$lang['geoiplib'] = 'Add GeoIP Information
(requires PHP module to be installed)'; + $lang['geoiplib_o_disabled'] = 'Disabled'; + $lang['geoiplib_o_phpgeoip'] = 'Use GeoIP Module'; \ No newline at end of file diff --git a/plugin.info.txt b/plugin.info.txt index 8ababe2..b2bf384 100644 --- a/plugin.info.txt +++ b/plugin.info.txt @@ -1,7 +1,7 @@ base botmon author Sascha Leib email ad@hominem.com -date 2025-09-12 +date 2025-09-13 name Bot Monitoring desc A tool for monitoring and analysing bot traffic to your wiki (under development) url https://www.dokuwiki.org/plugin:botmon diff --git a/script.js b/script.js index f17eb69..c902300 100644 --- a/script.js +++ b/script.js @@ -21,7 +21,6 @@ const BotMon = { // find the plugin basedir: this._baseDir = document.currentScript.src.substring(0, document.currentScript.src.indexOf('/exe/')) + '/plugins/botmon/'; - this._DWBaseDir = document.currentScript.src.substring(0, document.currentScript.src.indexOf('/lib/')) + '/'; // read the page language from the DOM: this._lang = document.getRootNode().documentElement.lang || this._lang; @@ -34,7 +33,6 @@ const BotMon = { }, _baseDir: null, - _DWBaseDir: null, _lang: 'en', _today: (new Date()).toISOString().slice(0, 10), _timeDiff: '', @@ -320,7 +318,7 @@ BotMon.live = { nv._country = ( nv.geo == 'local' ? "localhost" : "Unknown" ); if (nv.geo && nv.geo !== '' && nv.geo !== 'ZZ' && nv.geo !== 'local') { const countryName = new Intl.DisplayNames(['en', BotMon._lang], {type: 'region'}); - nv._country = countryName.of(nv.geo) ?? nv.geo; + nv._country = countryName.of(nv.geo.substring(0,2)) ?? nv.geo; } } catch (err) { console.error(err); @@ -553,9 +551,9 @@ BotMon.live = { if (v._type == BM_USERTYPE.KNOWN_BOT || v._type == BM_USERTYPE.LIKELY_BOT) { /* bots only */ // add bot views to IP range information: - v._pageViews.forEach( pv => { + /*v._pageViews.forEach( pv => { me.addToIPRanges(pv.ip); - }); + });*/ // add to the country lists: me.addToCountries(v.geo, v._country, v._type); @@ -572,10 +570,10 @@ BotMon.live = { }, // visits from IP ranges: - _ipRange: { + /*_ipRange: { ip4: [], ip6: [] - }, + },*/ /** * Adds a visit to the IP range statistics. * @@ -583,7 +581,7 @@ BotMon.live = { * * @param {string} ip The IP address to add. */ - addToIPRanges: function(ip) { + /*addToIPRanges: function(ip) { // #TODO: handle nestled ranges! const me = BotMon.live.data.analytics; @@ -615,8 +613,8 @@ BotMon.live = { it.count += 1; } - }, - getTopBotIPRanges: function(max) { + },*/ + /*getTopBotIPRanges: function(max) { const me = BotMon.live.data.analytics; @@ -649,7 +647,7 @@ BotMon.live = { } return rList; - }, + },*/ /* countries of visits */ _countries: { @@ -885,7 +883,7 @@ BotMon.live = { // Load the list of known bots: BotMon.live.gui.status.showBusy("Loading known bots …"); - const url = BotMon._baseDir + 'conf/known-bots.json'; + const url = BotMon._baseDir + 'config/known-bots.json'; try { const response = await fetch(url); if (!response.ok) { @@ -896,7 +894,7 @@ BotMon.live = { this._ready = true; } catch (error) { - BotMon.live.gui.status.setError("Error while loading the ‘known bots’ file: " + error.message); + BotMon.live.gui.status.setError("Error while loading the known bots file:", error.message); } finally { BotMon.live.gui.status.hideBusy("Status: Done."); BotMon.live.data._dispatch('bots') @@ -961,7 +959,7 @@ BotMon.live = { // Load the list of known bots: BotMon.live.gui.status.showBusy("Loading known clients"); - const url = BotMon._baseDir + 'conf/known-clients.json'; + const url = BotMon._baseDir + 'config/known-clients.json'; try { const response = await fetch(url); if (!response.ok) { @@ -1009,7 +1007,7 @@ BotMon.live = { // return the browser name for a browser ID: getName: function(id) { const it = BotMon.live.data.clients._list.find(client => client.id == id); - return it.n; + return ( it && it.n ? it.n : "Unknown"); //it.n; }, // indicates if the list is loaded and ready to use: @@ -1027,7 +1025,7 @@ BotMon.live = { // Load the list of known bots: BotMon.live.gui.status.showBusy("Loading known platforms"); - const url = BotMon._baseDir + 'conf/known-platforms.json'; + const url = BotMon._baseDir + 'config/known-platforms.json'; try { const response = await fetch(url); if (!response.ok) { @@ -1095,13 +1093,10 @@ BotMon.live = { BotMon.live.gui.status.showBusy("Loading list of rules …"); // relative file path to the rules file: - const filePath = 'conf/botmon-config.json'; + const filePath = 'config/default-config.json'; - // check if the user has a configuration file in their DokuWiki installation, - // then load the appropriate file: - this._checkForUserConfig( filePath, (hasUserConfig) => { - this._loadrulesFile(( hasUserConfig ? BotMon._DWBaseDir : BotMon._baseDir ) + filePath); - }); + // load the rules file: + this._loadrulesFile(BotMon._baseDir + filePath); }, /** @@ -1146,35 +1141,13 @@ BotMon.live = { me._ready = true; } catch (error) { - BotMon.live.gui.status.setError("Error while loading the ‘rules’ file: " + error.message); + BotMon.live.gui.status.setError("Error while loading the config file: " + error.message); } finally { BotMon.live.gui.status.hideBusy("Status: Done."); BotMon.live.data._dispatch('rules') } }, - /** - * Checks if the user has a configuration file in their DokuWiki installation. - * @param {function} whenDone - an optional callback function to call when the check is finished. - */ - _checkForUserConfig: async function(filePath, whenDone = undefined) { - //console.info('BotMon.live.data.rules._checkForUserConfig()'); - - let hasUserConfig = false; - try { - const response = await fetch(BotMon._DWBaseDir + '/' + filePath, { - method: 'HEAD' - }); - hasUserConfig = response.ok; - } catch (err) { - console.info("An error occured while trying to check for a user configuration file:", err); - } finally { - if (whenDone) { - whenDone(hasUserConfig); - } - } - }, - _rulesList: [], // list of rules to find out if a visitor is a bot _threshold: 100, // above this, it is considered a bot. @@ -1476,7 +1449,7 @@ BotMon.live = { } } catch (error) { - BotMon.live.gui.status.setError(`Error while loading the ${typeName} log file: ${error.message}.`); + BotMon.live.gui.status.setError(`Error while loading the ${typeName} log file: ${error.message} – data may be incomplete.`); } finally { BotMon.live.gui.status.hideBusy("Status: Done."); if (onLoaded) { @@ -1557,7 +1530,7 @@ BotMon.live = { } // update the suspected bot IP ranges list: - const botIps = document.getElementById('botmon__today__botips'); + /*const botIps = document.getElementById('botmon__today__botips'); if (botIps) { botIps.appendChild(makeElement('dt', {}, "Bot IP ranges (top 5)")); @@ -1568,7 +1541,7 @@ BotMon.live = { li.appendChild(makeElement('span', {'class': 'count' }, ipInfo.num)); botIps.append(li) }); - } + }*/ // update the top bot countries list: const botCountries = document.getElementById('botmon__today__countries'); @@ -1678,7 +1651,7 @@ BotMon.live = { BotMon.live.gui.status._errorCount += 1; const el = document.getElementById('botmon__today__status'); if (el) { - el.innerText = "An error occurred. Data may be incomplete! See browser console for details"; + el.innerText = "Data may be incomplete."; el.classList.add('error'); } }, @@ -1792,20 +1765,17 @@ BotMon.live = { const platformName = (data._platform ? data._platform.n : 'Unknown'); const clientName = (data._client ? data._client.n: 'Unknown'); + const sumClass = ( data._seenBy.indexOf('srv') < 0 ? 'noServer' : 'hasServer'); + const li = make('li'); // root list item const details = make('details'); - const summary = make('summary'); + const summary = make('summary', { + 'class': sumClass + }); details.appendChild(summary); const span1 = make('span'); /* left-hand group */ - // country flag: - span1.appendChild(make('span', { - 'class': 'icon_only country ctry_' + data.geo.toLowerCase(), - 'data-ctry': (data.geo | 'ZZ'), - 'title': "Country: " + ( data._country || "Unknown") - }, ( data._country || "Unknown") )); - if (data._type !== BM_USERTYPE.KNOWN_BOT) { /* No platform/client for bots */ span1.appendChild(make('span', { /* Platform */ 'class': 'icon_only platform pf_' + (data._platform ? data._platform.id : 'unknown'), @@ -1848,6 +1818,15 @@ BotMon.live = { }, data.id)); } + // country flag: + if (data.geo && data.geo !== 'ZZ') { + span1.appendChild(make('span', { + 'class': 'icon_only country ctry_' + data.geo.toLowerCase(), + 'data-ctry': data.geo, + 'title': "Country: " + ( data._country || "Unknown") + }, ( data._country || "Unknown") )); + } + summary.appendChild(span1); const span2 = make('span'); /* right-hand group */ diff --git a/style.less b/style.less index 627b13e..9e1cd61 100644 --- a/style.less +++ b/style.less @@ -335,7 +335,7 @@ .botmon_overview_grid { & { display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-columns: 1fr 1fr 1fr; grid-gap: 0 .33em; } dl { @@ -354,7 +354,7 @@ header { background-color: #F0F0F0; color: #333; - border: #666 solid 1px; + border: #999 solid 1px; border-radius: .5rem .5rem 0 0; margin: .5rem 0 1pt 0; padding: .25rem .5rem; @@ -432,7 +432,7 @@ } & > div { padding: .5rem; - border: #CCC solid 1px; + border: #999 solid 1px; border-top-width: 0; border-radius: 0 0 .25rem .25rem; } @@ -448,7 +448,7 @@ } & > details > summary { background-color: #F0F0F0; - border: #CCC solid 1px; + border: #999 solid 1px; } } @@ -483,7 +483,9 @@ border-bottom: #CCC solid 1px; border-radius: .7em; } - + details ul > li > details > summary.noServer { + opacity: 67%; + } details ul > li > details > summary > span { display: flex; align-items: center; @@ -587,7 +589,7 @@ column-gap: .25rem; background-color: #F0F0F0; color: #333; - border: #666 solid 1px; + border: #999 solid 1px; border-radius: 0 0 .5rem .5rem; margin: 1pt 0 0 0; padding: .25rem .5rem; From 7884ded35be081b050496da37cdb501e4a5cc4a2 Mon Sep 17 00:00:00 2001 From: Sascha Leib Date: Sun, 14 Sep 2025 11:58:40 +0200 Subject: [PATCH 2/3] Added platforms and clients --- config/default-config.json | 23 ++++++++++++++--------- config/known-clients.json | 10 +++++++++- config/known-platforms.json | 10 +++++++++- img/clients.png | Bin 15217 -> 19544 bytes img/platforms.png | Bin 12169 -> 11840 bytes script.js | 7 +++++-- style.less | 9 ++++++--- 7 files changed, 43 insertions(+), 16 deletions(-) diff --git a/config/default-config.json b/config/default-config.json index d0b79c9..f220192 100644 --- a/config/default-config.json +++ b/config/default-config.json @@ -9,7 +9,7 @@ "id": "oldClient", "desc": "Obsolete browser version", "bot": 40 }, - {"func": "matchesPlatform", "params": ["winold", "macosold"], + {"func": "matchesPlatform", "params": ["winold", "macosold", "androidold"], "id": "oldOS", "desc": "Obsolete platform version", "bot": 40 }, @@ -17,6 +17,10 @@ "id": "serverOS", "desc": "Server OS", "bot": 40 }, + {"func": "matchesPlatform", "params": ["null"], + "id": "noOS", "desc": "Unknown or missing OS information", + "bot": 40 + }, {"func": "smallPageCount", "params": [1], "id": "onePage", "desc": "Visiter viewed only a single page", "bot": 40 @@ -71,14 +75,15 @@ } ], "ipRanges": [ - {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, + {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]", "g": "US"}, {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, - {"from": "24.240.0.0", "to": "24.247.255.255", "mask": 13, "label": "Charter [US]"}, + {"from": "24.240.0.0", "to": "24.247.255.255", "m": 13, "label": "Charter [US]"}, {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, + {"from": "66.249.64.0", "to": "66.249.95.255", "m": 19, "label": "Google LLC [US]"}, {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, @@ -102,14 +107,14 @@ {"from": "188.0.0.0", "to": "188.255.255.254", "label": "South-American ISPs (188.x)"}, {"from": "189.0.0.0", "to": "189.255.255.254", "label": "South-American ISPs (189.x)"}, {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, - {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, + {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, - {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 30, "label": "VNPT [VN]"}, - {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Amazon Cloud [US]"}, - {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 32, "label": "Charter [US]"}, - {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 24, "label": "Charter [US]"}, - {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "mask": 16, "label": "Inspire [BR]"}, + {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "VNPT [VN]"}, + {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "m": "Amazon Cloud [US]"}, + {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Charter [US]"}, + {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "m": 24, "label": "Charter [US]"}, + {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "m": 16, "label": "Inspire [BR]"}, {"from": "2a0a:4cc0::::::", "to": "2a0a:4cc0:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Netcup [DE]"} ] } \ No newline at end of file diff --git a/config/known-clients.json b/config/known-clients.json index 813f5b1..d650d9f 100644 --- a/config/known-clients.json +++ b/config/known-clients.json @@ -23,6 +23,10 @@ "id": "huawei", "rx": [ "\\sHuaweiBrowser\\/(\\d+\\.\\d+)[\\s\\.]", "\\/harmony360Browser\\/(\\d+\\.\\d+)[\\s\\.]"] }, + {"n": "Silk", + "id": "silk", + "rx": [ "\\Silk\\/(\\d+)\\." ] + }, {"n": "DuckDuckGo", "id": "ddg", "rx": [ "\\sDdg\\/(\\S+)" ] @@ -59,8 +63,12 @@ "id": "safari", "rx": [ "\\sSafari\\/(\\d+)" ] }, + {"n": "Firefox Old", + "id": "ffold", + "rx": [ "\\sFirefox\\/(\\d\\d)\\.", "\\sFirefox\\s" ] + }, {"n": "Firefox", "id": "firefox", - "rx": [ "\\sFirefox\\/(\\S+)" ] + "rx": [ "\\sFirefox\\/(\\d\\d\\d)\\." ] } ] diff --git a/config/known-platforms.json b/config/known-platforms.json index 7dd452e..a4a9ed5 100644 --- a/config/known-platforms.json +++ b/config/known-platforms.json @@ -15,9 +15,17 @@ "id": "ios", "rx": [ "\\sFxiOS\\/(\\d+\\.\\d+)\\s", "\\siPhone\\sOS\\s([\\d\\._]+)\\s", "\\siPadOS\\s([\\d\\._]+)\\s", "iPad; CPU OS (\\d+)[_\\.\\s]", "\\sCriOS\\/(\\d+\\.\\d+)\\." ] }, + {"n": "FireOS", + "id": "fire", + "rx": [ "\\sKFFOWI[\\)\\s]]", "\\sKFTHWI[\\)\\s]]" , "\\sSilk\\/"] + }, + {"n": "Old Android", + "id": "androidold", + "rx": [ "Android[\\s;\\/](\\d)\\." ] + }, {"n": "Android", "id": "android", - "rx": [ "[\\(\\s]Android\\s([^;]+);" ] + "rx": [ " Android[\\s;\\/](\\d\\d)\\.;\\s" ] }, {"n": "Old MacOS", "id": "macosold", diff --git a/img/clients.png b/img/clients.png index fc6a01d06805e4c4f9087de476cdb8134148b5b7..fd9d06bba32f300d41da7c5218228db878ccf44d 100644 GIT binary patch delta 19446 zcmV(?K-a(VcG#E!kQWM=2nGNE09ddhl#wAQ3L^jj79#=4QDAG4Q&s^3k*XgHXWak* z=mP)%XWami)LnlsWDTGiK*xaq080l+L_t(|UbTG%fLzt}_jxk5GwUAN&2HSCC=i1H z2^yT@T3Vnj#Yzj5;&r4g#UaIuQ=Awf2{A}QJR4j0aeMOp&V4hpGrJq1{eQpY?0tI9 zz2}~L?z#8f_eP?_;I`XtD?u_DG$}z7L5y{2^v%N$Kiq%H2YW-W0>IdY?TfcYpSFMuY91DR+`q=ktz9p8X1g^=ymt_3-f3V``lNY;ar%-;vy zYi$br1@u>IQ{XPpht?(?1KJ24msq1J!?moS-McYZy`iApi$h&#V?^?guTvjZ1KRAhu_N7*F6>Clj{+W*wpvaZP_5 z`vTi6C;(z1FW|U>G*yCMfmkgD=mOlZnGXW2GOni(=udng0p8|geE;Qq0QY={d@*IDcco!c?U?|89V(aS50v2H71JM5u zoTAK}IrBnn%mVELy#d;gpau}JB`A50X)kC5h{4vj9F#oAW}FAw!6o36TtWYU z9)FBf0LS?lpJPS)K#OkDR2U40O&3ja0)h374(0MQ&>gp1-Vf$xS^$+A~!Gw zr|HMj&v8RbKh8WD%yX>_^I{8O6){|(yK#SPA``aRxiL5+C#4-fIdP2fhqUAOfS3p4 z9vo{;Ui2`COTzoFKy73AAn-KE1Z9DK&Ic0UZ9c|+=Q%!rd&VJo8N@u+fF1#LbvU?y zUF=2>dqeh3mmvpV;5d8AIUsh?+_?Cj{h(~n$GGNXT*H;hg8G6Ypz$~^I-ZOk4HtiM zXYnM6g)q4CxdUQLV{pp%Bvs1$(?F~;1~b0~%wMv0y9r<u;oZF+fGr)G`Em$Y?XgXKUtJG+$(;t0Q10Xg`D>2D`?$$WiyW^@JM=s#ayRIn=8uhpFPY|Ip}jU&lW3pdv6-IINP$@apYSj+rOv(Hv>iS3x;2 z=ZtYmw!ey^xG0K?I1NB(=Ai3{lik@uC!BXR&0KIj z>7E!x?KX<2ZgSfE512!q~$?fD#)mavipjp5-EWjF+TQ$kI4i zYgHeV0;CpF(bxl2JZOIv`CJYPIqdZ9r`J-`$|1-xRO&)K_@OE;4TOkZLUQ6p2$154 zBUwPiMoPUz+P9@-v_Su&A?f66FQ(dq6X}EZe@`15&J+T|C`AzT)f?z{!l*YD+2;~? z*@Ga}Sc1)pu4U6ym^llPA~LD15i-9;X*z85#N&6-eeXO@kFS4zkk)lhpiZX_#wz(7 zDn(_JyrEn$hS>(AWJ((8e(+J*gi)e^<%H#ETS12qz!bvp0D_dTNvl@OqAiU@=*Ikl zI+Or)sv+vIhtR8N6egXbMx0DP7Cs7Zq!SqQeP z9s4L`1X0gmuXTTtUq@;%1;lnxkC3D^k<^0gJ5(~-9HitUG=eqh^?XdU4wS&3vsLq< zdkvye{qR|w1{_q{+DU`T50W1Akrwb$INVMlP&k4#(m}y+2hAFeM%#+(TVb}&c9H_n zJu2C3w!@`s9KxWIP4!)0BgP;wQ>(H;D3O9L{ual-X;Oc|Zjw5@B)54f?(d+eznvn% zcAAp+4h^?qP}70Zn^EKx8TO)~bt)wJprT0pmn?uSmJWD+(VEw%sW3YqJ)RvEq#`FW z2-_yE*rE@iZ>0fen&?x4xiPU@r7BVvV#=D=*SkU1A9OQL9F8KM3I_CLJKQHLd< zHv88T;!=O>x|05#k}C`CK!Fe&h=tfdDz;fLhe#$EIl!0!PUHd$SQZbOVmexTXE7;x z&3D=#`{DtuOvbqPY3K5MRssKfe8y?`{sQK8_bxAw++rcG#mGj z<|`pvQQJGtH~w>`U<#xJFb;ZtxnEPf6>3(Tii&^2WP?evAc;%D5?BD&6_-xIF%7!L zzOOZh3=J-*II!Kl>b2n(Hwzg87_}&gCV4N>)Uf1+ZXHgIoX!~89U<7b4l>cl$fWBE z`MoZR_&g|}ot&P?H)>w+Soh}Fl7X~94*?9+$yCz}eFV3hr@@yPXr-(U1%6D|;LgyE zC?bmPNG&!;{QUgJe|(v^Jp;W8NTSyB8w{+q)6jGf4{3d&4>S}NPFZP|WN90m z^801pM|f)CkT|S>&d$z$4u|6yS(e8mfS6#IG{J;7Q)Eeu1$15C7>!21$;->*V7XWH zDxjgE!I7JrduMw@zJ1L>$+i=58`G{fR5X7uxKN@Yi1~&TnKZRRis#w2hkQQY{pIE5 z9ByWyhXCYyylS&O^}%+U`20qhTu_S5Zjy#N;6}$H*h0}>NsFRkMI^dpyh#g&>g#n) zyBek8AwUWl0y;W6uI-4ak3Ofk*x4!33RI{8M$A~KhW{l>VHh#^`5=uuu#uMk=V7{N>zB0DQ0XsIE@DmO{yTyl4cgmWy2l^u(a>T9CktbCQe zT=F#Kwbj#R#HkNXy_li}rO-2aHC3iDur|JV7e;f2VN8(G8Yk4i65zgQRW1JVdA@}0 z9yuq|fEmVUfWLvhdjB!HZTC0S7z)#_V33|2JCF7Z8cmV|odIG~uBCq!b!;~h?M5IV z1jIFC0`G7rQ|7j~i@$sw%#$>D)3A?Tm|j7RXPrX_!(plk1!+~Eq4eIwQ_&aa!kycM z>2g8)L6(er_jI7=)r^T;0t8DM0$aE+@RM}dxNx4hLBjzsynnEZ2Ipl_`Jn#v=9FWp zIV*?$IOlSb-34IIGogRDma`8bTnqyyj#}dqurOmoWo{hZokj;y7ZTjD1b-<udS)0ts)0K+i7Gtc#R4=<`({i*H10>^8B}1<^nP*V zUZdMbK}D_m=*@p^Ub6r_ zjMKmZh1S)Xbo>B~8UtuFu=`xaPge}?j1@S|8>UU0mKw@t2w<#SxpKT=m`^Qja8CTF zp^&njHgdwp=xBIw8nAH=Teu;a6vZgWj}gwvecFF%R#|wREK66*kSub{oOIDz>v3JR+L8NMdHZygQ}`NFn#*;BX|1g zSg~S7KbYENgev2)J3%wdi9G*-@yvRJG90>WM7s94KuAYFj z3i^MkloZ7<4P&<%({>?UV`}=piWa}eBjsMvtAOT3C+A6u^nj!)7fZ72L1%%G9+x8b zVg?5=p?@%kH#gc)^G}*_{V&CD{O8D1YE7q|Fb84b3t-+41V4|kBtZh~$=IK>$BeTl zM#{4;x>;}P`spQaf0CSR7f9S?q4DH77vg`8&%vM{=N7pWeS(S3Lgbjo&ghXiH4@Cl zc$%*<%|51KE^j<#?)eFJ0;v)-%spfvqthim3kFcyPtY$FpU zcY~br)DDZ&^yA7tUc!%LtP;$BbAJAYQvDHJ#=VDiG3SgKC2mZX!id4O^FHS~?Ye(d zs_8PeUuc+jJU@xDN^tT!C;i5y8RtFlcyL6H-6qMbbJle-Mb44?h~aeXHVYylrLa+w zWY!fj00`z>G2)PQj9k%=N`Aff9_hr_=eyM`X}_#Uh4ViSte*d!F*OGff@o1pvh0s9 zJaf0})YC_JH8skIJZi{cG~K(y9(sRe7+SAYYJfG!+Eid0vTTMVQz?~BdTahws#AVS z=vXrvfBR=|PPVCLWn<)MN|HbR+lONtjQs4C2Q|BD!!fAFK=*q50DE+F&PH#6|Kb8w zMNM(_fJZl6tPDDT@D;L6vgWB}$A zf;tFA&GAI1r69qpXllw~xA<9f((`dPzXS=V3> zp!@WPBjgQ)$R7+*0C7Yef2+xgMrp-{yu}9#bQz9m{k)N0+NDw-$Z2> zyUAfwVq*HN7pz62pp9%9-C;W9VV}2szV6cL{UajBtRg`P0m%JzvnqeX+2IHI35jam zl?l_3*Fk`}(Lk>!99TDe)bZ}1@k7kc8|Ds-#N$>;yik#j80yxO28W0BZ*I*uUmuyc zya$Z9ZJjjtr4w=#r@U8nNChz0#HkFl%*r`&_sK;kPiXSSA_`iQCrfj_-}LVKvz&i3 zM!0>+XZ{(`V-Bwov!j0}2j;ze;uVTRdIoL|F@Em`4fySn{eW)ju4p(~HQ4Uk{pX5J z{LEkYvve35f`gdja_7|6=TqDunobN1KQ=OkICT(IZgr=OYykW9*am9 zmM&=gByl)X0AtqE^U6^VuYiu1c&x?(5{`yTbv@NApOzgsE-?`=02c)ZNbf_yHI<7H z=cl1pWgqvCxe9*-{2DpG7X3ka@~Wa(_`p53nle=-dzt_*nE!0>MfJ~%y>94LKst{7 z``j@QG9Nw3{F{6=MqhipRJGAM^h0YU$y|pZf765?*B;7M9A3ca72AtZq=&`URX^2g^Q`d15 zXE+KKMbL$W$*%a zq8!^=Et~5CSBPz%N0q@;PNYJJqLJGfsmyjo#Djl3k=2RIn(u)M?hZ9I>n-1HSE7L^ zoSsd@AlzX{7}YrQ?BuG*BWG19-vV(lRIX1vH+9&&0K#6lvV@ zefeZ44fV@6*+cDdNp|Ouk_AhI07O^F0W1dtYYAg9GvXzCE>YgpN;pJ=R5bvVvpWKx@%3j+XTya{cPPbG%JTfm(!Ixw3Hq zUj$-r%CROAT{9wDFnXVqS6)q^cqH$U@cw^RoQnz}Jeh(~2?7AL9uznZ0WqFpkc@oE zb;q(#$z67W@R~3SVHx#Kj_vbV#cD2T2M*9Xx+0 z!4xA59Fcn+>d{dGjiNE_Th6!2Dq)7qoP|IoLQUGHRp?P*`wow=>2%}{*t<{SWi6&9 zL^Glw77~L1rZ~^Ke8_Q89W!N}Gh;4*(7Ue#j<^HjUFdimy!;^p68Wy=XJ%XqLkJ0j zc?gUl3|1G_!kY~v{Dh30?iEZSgkgW6&lRd_K8SXJwxEhoe!e)F1_a*ca0z6B5Mlv7 zRB#Zb2qNdc4Y63@*e}N|?&OyIz9>PW6b6rCkV-K`ln}se0XRGRoM(Q-8%apyJxM0t zT`0kN2OsGwS6JlHJQDPA@R?LUf} zct#4xAV2~`ah`=GnOjG2jT|?%$oWa;j4lC;heo}KzsI0X#GH?jT_S%+E5=}89cG8b z^*|=aD}Z1O>kxvtRFZVSj0Vp0es)*JinlHmrQ`N3HVjX12a8{`rsP0d$WgmBOGZi9 zftw1CTw%&A(9pe7Jo2y^3;xCT`8~)<}=J#WPzebi`B;6Epj*z zr+9Qb>5*?`Lx0Kt@tuD?W?7OrynrL1;it~r^<_NSm>A|3IJ1H&3r%TI1n#V?F}54UX2_J3uNFv zUde_4{}8|hT-@J*t_JmR*S!E?B>faZmhlemXV>#krkN&yle~XYll6EV=xCTTxTH&Q z?+w?% zA6dV=2DSS_RtEEgpQ5v&uC*B@K<>HcS_0w@p6A}g3LAi3_06Dv;3m$Y0IuiN$-K9ba}A!0PGI!T%4a zNmtRiNZ5k@FA)_2z?}UruM_2^%-z8~Ov-Y8AUcx*u0VhC3~%>>CsE1VqW>$%V9pIg zyo_)N@RHmA8WIHXtjN0{LnfaBbf`F))k-N=Vb)o=+u!p=#c1vu~@>~p8V&Z;+j1!70Yk5s0E=7QMs zb_eHvJotZo#{&437;ad_I1t4?&!c_~VlVpN;y2*MY7?Fh!6)rx=6nDtFHYs$ao_si zAjO=)0{HEeG03@??`I^0Oa-L^sG|VCKEOR%iaCP?@Vf&X9oz#U+}Uu&af7=F#QvUN zRmylS(+#|OpP5#HIlqaN0j>jXY!89X1M!MQUNV2O8?*#Bi2jv<>v$5KJ0gs8#nN?N z+s+-(E?k#bRn`+3&aOMmzN7gy3~m>^pqrQfGjV6mp(SU8)8$g#=6a;PqE`W6%qnBs z=2w__I|U53wWe5TS9?6{)etup*<7w1)$wY!YX2()^_cnUApp#|bK#ziJN*>EEVQ(< zc5Q!sEXXhS6m#^=A$}q?oU-y+wqn2Ul(3)MN(vbQz?@&MO1?6df^HfO%lr+0Z^6hB z4ESH&pFHI6HBUv05Io@lx%+y z3*g4n8#X1yaq7z=`+g)AWX+C@6p627-Kj}FNFE>Vg^34}1az3NaU z*aQ9dc>HxZpi*~nu9Fol)TOF@SwN~*{udzEW-8|ifQkaFTzqP?fd4R}SmOhOn+v2*hcUBD#@$;p&Kp&7a>F zIxk782D(oQ`2Yg+)esT`LkO`5`xMmmj9JFR0XBcLswkYM2>S-ox8%Z>?G4EN{UM_( z_gos#)B^>BxtBXE%moWL`rub2yW@H3!w;Ld4w%`4Ax+;DhL8mFq_Br}sMcExOD3KD4rd7fRlIaxkMk#(;(=n95o{{r*JPScx?-07#|RVw0WZ#r^( z9O~kDlhW0Ldt=C8PwhhrZ~nzL@6LVn(97ymgQs! z;ekpQAfOIp3OZLZ&97fK%~-@V*L-4{?>uRm0WUP3fFIj0K5m*zKQhfIuKD0K)2zZh z18}cJJu4lIpH2yQ?xqB%AAsNDo-P4TCD>-DXepB8sjxrMUl4zp^K9>Xj}Yxg-=Bka zH64C$95-NK`NtSlyarXZ5DkM@zZRole(pAJI8g(S$Y?24l>C5zU|t5&Mee_PC6T2B zc6@D`zdzG7uNjay0L-W~&1-RNJ&&W7yE`eg7edy{>(h{dVdFUZTwi z%CE#dk<`?+#S2KUWFESTrE3D&=%~1|vkMU=t;IIKS)6}wjpFJsp#1%d7@JPU*s=}7 z@nJ|aUXPuQ5(tf?mw>}}_VpG57+{K3HNZeHx*uMc8yUCUSFz2^8SFZ|8IzC9139vg z5`cPOZe7aHE5rETdbBIx!gyUlC+0x7!wlDD66;WypOZXPG5ne4a?*CK@q7 zO^m~vYEXXy==i%O$lI4hSEDmKz)xg>jku9^8KM`_*AK(x-$5GzVUbCUMhSQxTcEoD-skE0t}&IvhQRLwl7o%Qyf~*H-paeV>ltK>y3<$X!34b-93*3exxSZ!yIw6FID4Dn$ z%+tT|BGBE61fVLOUFX@}ZmW>FV*#-uyTI4{yf@~IUQ3V!O2Q#LPX?YywW z62gD} zm^V5q99Bhp&Y8%A^sWy9$g(veH4L89NYdJYZ>;atq!_&l0An7Q|4PX#`n7BHF{)$W zaB@@)CCO$zZ876fitgP((LLKJy!jhV?`(hNDYXY6h*g(?9sXWm&9 z`08UY+Dfr~JIRP}zl4f&W|4is5ONG0L7tf>k?-@j$p6JVJOg$qge1SaBak5g%&%4o zivL!8&7Eqzem`}7{x}m7JJ#{WccW))Vy=R?jt&J3~ z+e?KP{!|XE{AB7)Bl|r2=+*`Vwg7*2egmCfz(XeJQrv)H4Hf+KUMe~3aXf#+|SH@D=;Y>I3xrih*`*hU{it=9o+xj@qB(`%l#dH{UC*^sZG<#xIcTLc&30359U{nuv z^oD57HgZ&pg=z@_Xhdx1>4>#7Vze&PyUVxJ&3{QPz7*KJyNMoqeGNG(y9SwxCr(P1 z)z?G+5FkE;HA&^>FCn+dMwEYqfeOF+(56h{~DqV*#EAW^2feMIb&KW z-tMH94+l{F;-RR7Oy|Jw)vd!oLp1*k)LH^E(2g#%^(hMPGpOaGN@{<2Z7}V7bSyQ! zJ&^oc3engt=FE$EGH))yI(A&_TQX1&ONn%wRm(Yn;{HCQLf>Yb-$_8wQSBqoh<0)f z=n7rzsMBbT__9qx09q?Mt_)!86>AiOi7wa&P~*GPsr9o8au4aGyy^8+FuPW4oBR=h z1lWSuk^muKExTOyitK;5(h=L8il0)jaVy@RO-=7sL+8Wj;FF`M>78nd)LN4=5<*Mn z72dp-O=_LYodx@IcDd{o(_!x0fuV7xi%(aj&%2v#2TVB_sv2%a;c(RrCC;yl4@;sn5 zcg=qoJ>0eMs4C?@{vl$?TKen8`+2Hg+`vvTiE}<`r0Rnq!Mq6Wy5XUl*jH<@4+vFOM-voh3q+}k7uvwZE2>Gsk3P5!B1#vpX11>xP+T-dFla@9WJZOgw7Lc zxr{R^7$wj{03*=>-N7!`HRc%AGh;q<+t2Fs#cYdCu>*Su9gDCQu25Y6AebMy(@zKc zb0k*C!qj`%vJQ-YSlDvi%$9tKB!0#}+9b0amC7-H8Nz?XGTfozrbbkF1FmVr`9>UH zjceZh`&UJo9uvqAaLx3VY#0bHIk^-!*~MAz3ldjZ{X*AM4vg(_3ftCoJ{jFz~S=&C7A!*S<(xM&dH$fr^#8Q9^&$zv>omq#XKS+H(fiS+EJR+orH_Tu!F zQ<`|#xDJ0Oh9nuuX$%D8wByVt{a8u}w)q_P`5EZEXV#Qj9!l5EUxSA5l3Jv=2`MkG zOc3uUQa$~+0S~XuRw;CclY+N9C_0qciF3z;kC^+GE}huG9RWXuO08eyTroIjvO*1W z&&k?7VV0wC;As0GEpEoQt&i@0_kfmlV30gW&ys&6Lq>++mgEnkWP2qh?n6E8grMQl zkH*)Z3Zblf0l}QNkyZ{*5qaFRGv= z%q~&r){zbxk*7*`Jy)1Z>tdSGn0S>BndJO~XO+x7w?2^{2f(ky2x zPT5*#()$}(CH$(ML_ZmCqZxgBE?gTw!>Qs{Q34i}5N4HtPb3ebbdjnN_G-SVwiQG7 z)d}Xv?hVsa8d#9Xb~lVW*4c+Mn8uuWp#+@q<_8^nGhv8?-~NhUL0Cd(__Dp@19cwUGdpB1)PDUWHnL+9zwWXe;?Um}y4<6WRv z0ZCl4(yUtLr_*=EX)YNw0_Ckf8Ij}ka;j;M($+ukr7up;rw`wqBOQP8qlLW+xN5c8 z@98GGgEYDXj6Eq+VQ?OEiS8OebT1pXpQ0l?^#1I8y7P${QunVJ_Y^St6Z5pqL3$F* zIf}DtsrywBaybOpaqdYTit%}cd}BRy<97=rUYnFcrX%>kykfJT-WANbPhsLKx)Y8+ z*N$Md05zJNgw`qNy8wSZf613-#wxW`-XwI9&>PRx?vq?&V&m)F@5M9!(H0iB7GUOZPZt#tjYI`U zPzO!~02gB56GnOlg7_WD$yzo74t+iJCM}ZAk=|)B`z^1fEq~et+hC^Y0{8}$=!{~b zDbRNmx%;|}=u>9KlK^}Ty9Q>OWS$ftnfm!<(j@umEws>Oquc^sPRSQ>t`jQZ*U^46 z&|ML!^UFALU5dDTm&%OAARtet4s*YfvmS^qo; zLM~<%65U@()D}e@)xf}b48s{<#%YX7IC@GhJ4+rHz($mgDwME@Fv z5Cl123KhJHJzx!Or1d1in8`zE3*ppFZN5xvguKOk&b z$4{>^as?#!nZTU24FmA5-?>TZC~CUp{-n5 z{b7P{9U%IAKLRe;^*t46FkJDR#pDf~rf(+@OkUIdyhDn~sHmD#;Dqx~QRiYPeZp$A zi|>i{K}CPp!Okz`%4Z!XO_3?d5GCTxE$Qcy#4ybD@`612Vl>QfF;^zfYO*EauII7O zRE_TWUbuxBJpSPu*~U3#&d|M3KN~^vSWCVWIPxK%`7*Aw+xWP7o}5%H{^ZeT(s!d#38O!7R_gw z((Qko1w!!O;Z3g_gH7ze3>UH?Xt`@veYu;i`uSiFdr^aQ+Rwiwp)6-i10B{&b3 z<$-BG!&6V((o{1#E}L%o_6#NCD~aia7g&F}P=4v!el)2p2mV|#V?qb~MY4DzWs8A> zL$5_|alnFsFx%pkvy!K}dM*7O(1H17v5+UWwD>HiI9X^4t(pa+`xNeo24m zz5G?HcwxAJ5CFzprM$+PKkd!o{Qm-O5j@5A00i-Dg8(zXxda|ZKZUe-Fhgj)FV zN3YD)@#D!hb0(=1Cz9N!51HXGnSlUlYu8fjx_k@~uG5^`A? zxqkLDvK_~7FC7{zD0J_=WN`EDiC=%Pin^BRB%ll$MAYSt zr|9Cv&>1=d2#mh<7HQvpn{iEV;4|#31dM|mT6BSnYd?j5WWz%EZ+|22!iD5L`D64+G1*B%o^*udb9&*7d(k;mB>?AXUTWmIR{q%pQiKAW6cVzs& zLZ*P|+nFD#XK*8OUUpexuM5ue&liodJG5^yen>zFNU4aWce_Bqao%|(_vH}J0^7Z# z7ojn<1#NT26P9pB2^gVA9_i`0SRKEBPfS#%^QN0fa%D!xMpIL7mKNfcocukU6xj4U zsL<~INYoK5NEs%c6{mk-wzpI8w%bVizQ-#I?{k*8o6CT{dpG$nxrE}&Qm;Y@a6|0Q zoK@<>wY@NBEIIlP2jP!~Iv^st2~J#=BP;;;!#H?#+r9gNP9jLdo7x3v6iRM#&j-5JuF_F$Xrkp%({yuw8 z^m>pP2ST5aH#m_Z;W<=T;3m7GkZO~~%4i0EsJ^2!Lc0&_r|);hXzuj>y_TrQ0cNi0 zzn~8{-bqFB2=agXog%0HV1%;W){8Ag#Xicid#I==O8Hq8RFLDOXW!aI73Dd!aCUVD z&y1ZU^Orulni}h@g);}5yB4b2s+wqgp7n91tf5^#XJ+0UD$PAb2pKuVPRCCgk>Z=$ z;EL4E^J(S!A@u4e*83$J8_?GRIkv6^oLByIGmRM7<#m4}Mk%~UF`3&QrLv+@di|qX zI``y$DRm{=0Rs--$MiXIOvP7yE-l*fK`*_d`#s2(@inKc+L8LR8($xkAZ!7dXZ@E2~ipz zJDH|Ao*;j>n_t_vFxGI=#(EdM^_gGP)y7?IRM#BDXeA+lEr#*0b>-CB(AAiWi?eCu z^imo&Igg(EbulgIn@bASmnKQC5vg`*JIDec(g}Fo}7C#y~ z2`2!yIL;iWNyw(r6&bJ@rdRTVKAte@Vw?msE`#gY)NG0jv~}pzx`&sPTi}w6A8ai! zlWpoyDIB)OAQz5&FQxz5h)lI`z|4GbIf;K9b2_q2qGn_;nfr8T<&#qPvu|Pu6`9f~ zsyz^+Lgzl3JKHkZ@9OO-=A7GIJm^lKF>DGUZHYz8h4~5<4dhpLEFmR>vxI|W2myJX zhf*%%%%K}dZCEFY&0xkWYDAk640)SV7SfJxhBJ}8mNB;KAl)!cqoN#VrmLtLeJg*} z)f?2$^A$aQ-Gf4>`&T96|1^XWE3H@vZzuQpdamp<2d}1i$5?g8NC|Le{gPaL&r1pU z$LWj6wqt`3l4Qc*9COZ@7)HI7d%-;CMmljyF>$?$gFtG7!Hw?YC0CQ=TTXrZ$kY}Y zKrerP8m*6u-wa8aYZ6K3RsFxE3*CQzqKTubGStn;*kRN+x0%~&uBUL_YeGm8Uo~7! z+XDP9kcDX9fi$Pz^K_!e^1>nYB`WkR?9p|KomOAOj7D_vLDWD1X{42Q)-R>($TQ?o z)(b)XDl&7QTdD~6vU=+=6wx0hPmUsbIghi5JRXHSSx#~|`HOx)Qb1#~)mVR6Ky#~Q zgPpOB6w$t;V$JeHj23kgIn~7Q3dpltuQrzy<@PQh315(Boe(+cI>jPEGRY}QbtEt| zMy^{X!*bA+v4njxS&wB!5pBcSBEYhGtzEnu=1F7dK-PS>i-4raVUk&a#kfH5mP z`Ma?^mvlI=De>or?uVcr4X1yH05E4?%TJKf7Tg^b`1QR@AS7dm(`APMnDe)axY$3G zIfL(6pWu-~ssxFgGjq!w_68LdScqy#9~blM8kvu7+22o0mP80h=$v1(>zQ-6hvf5r zOw!!b;Z`vaOnk>H34LBQ81Q6u26&nJ6bOkYv%;0xlX-3dDbIaQ(#3x_5cR1*c5wN= zU1&ImG@2y1VK7gUk$W~pvC|#$O}|6yL665v82)%W>1RzO{j#}ay!CA2io@bg=FKHw zJMU?V(6cnf>gmi?pOg9i%Lu14UZ^?}xW!q^qQ!1^c;M5ae}?%@=4kT=;4lLCqlI=2bL!@3 zzyf-Gr&VD8Zqk2tuJw9kPCm(xzDd#|@oUCM3u{@lwS5S{?v0lduMKcZK5`pK$ND1+ zz^FyO)C$$jB_EKvj9;HUYFO*8L0y4OIwXnYn;#N&z;$8#l?Q+DM-BEL>*Pdd!T!7l zr1^_Tn#NxcLWTbcjh!p}=)wJi^`1WOfY_gRp{R`H8^oh9GQWJE%;i5wHSFv}rqkUu zuU2M@vfMSdVpxscDVg&ml68oiqTXc%gy0FjkxhN#ZyptaG(v?^~&+WWM<;E)1BZ>XbHRl65m@JUj? z-#eu~Xb&!oyG)79Sb$7#9hr?A_iKCac`9&8=r6_Ad%u52hsaCvsqt4S05Y|W&zgsX zp__WkUNiR9Q{Vb;LeX{7$|3d(yy|znQ8<6bjY6Puk}gLWR=?YKMU= zE4N2uvD6pkQUVaS+=`;AI$|-MnF|3rg@P)DH~)dOw{IY$F*O}}NU(=j73KECt|cHE zjaI^5Pmvs1WEM<-s-XL*3;`0w!y2`>sbm~{k+grsgGpPl7`2}mf%gJbIfO_jp%gsH zYY9*kWjX|8vv_svDWszgL`mWj8Av-@bn^PpUBW47pI=PTXU-#S%L;HyF23O4&)|$A zOx0M3OO_<@!wW(HB&OzHoFk@?GUg`IeHs~>9mKzBpokDD8nKaSbCS{e2}KtlN0Ha> zC)0n|CLZS5jc-CW;%p#+N_7VG%A8?|i2!IUTm*K2&<+b7UKE2AQ29lHnd~ zDu%6XGIg}e#J`bg##IQ(C9U>dqL;2Esri2(O2P~4`PcUnLV%=-dc1|==u=7kZ+nJv z7T!lvXOxt97(#3akt9(XetV18!kcmdnXRiydhby(!y&Pln1z7ETH&OMdi@}k4da7~ ztM8zG_pKo3fCZ#HCk-6zu8_!@sj z>ivUY7tw)NUb@UtW}@PfJTn z#AC%&CD+y0|9;o5U0PF96Gb8sVQPO#aO2@(2ZKQhWapFZ@?VoY@kY{ojVJ+1B1++e z%3z$jZkVbq_2G()4rl%P^}j`h-=*@Wn)owWAQ>Ya7LXLkKcFM?ale=3fBuT3y7y4g z7#v0q5{5e*leX@ev|P7SN}?01d>9A07m{pQ?GOE-LcC=t29u-f+4p|W}YaCXsJ2~ z(VxWuS1E3v{>}40&*9&FO+ya>m2Xo^?wRME;#v0oI<GnS*~^{_y@*o5S_| zrVpMyX0@Ho2p^3zd|GTGd2a^~fKksad$)tN;H+vDW*JE%|#yRyuh8_AJl;h>T*Gt>Tps^OB;Q$rI~_8K8-9y`!K^& zJQy9{ylefar~m!Mr$R+~*q2jS=psApBZxtFN9_R$G&fM#+d+|atEkZJfHGyM#VG{Y zT>PU8D%o9GOZ-1 zXY;-%BHjQ=4s__kW1`WEa0Dp?Rt>MBnTyV(Y3E!_&E7D@`De6$nwu!<_ff}zedKRy zBzBJM0Ed+4kOw`bgz+J}#dst*T{&^s!0Qzm4jp~8Y(wmm=Bn(TY$_-%r7dy=J@ff@ zmKWuI0cIL%Z$oevL12bbxZD)(Y$ulyqp{_PJ6)_Q3GtSrT2>sz2W>7psp!!8x9L)l zRZ^VrJvd(G&;+A@II9NaaA&g$#C|LgAb%qUBM_XGk4S|z%>e~idFyK`Hp6wGMh?$ zK$cUbtSkqAIU%H@BSek6cF<&L4^5T#P^`6%n)d7`Ux$}+2xc1ai#l*-Wzqae1HnWh zdzJ@n1jWF1e$jxZT)pF%r6eF-S3U47m3%VHh^^Y_nvOD66u7JVkw|ebXMa71Q(#ojL!Q`Db-~-2cU2-tz38mCHsr z^Z5~@lY17*6K^kYi9oD7{tx2l0xT)7IEN73ldVWaUy+Nkf=rRdPO?>wUwr&IS3k~t z6PhP_bH%dvc5c{oMn}!TtY{#H!G?zM8A6kPIHKj4PH_TXYf;}-*jh>Y57Ak_~0K;x_0c?eTUuOIiqvu4tMu&SEw-KoU$Ur(XV35(8&{T zntSn;X>)E}IHZ7dEPd{o+@LQoY5(2>QzPwd**R|4(okF5vKwE2y;r8`IIMt=Uw=KP zy}9{{U?4Ev@AZz1hQs~g`(e$t?M|0}Yl$a2`>WzUeZD^Zl1qNrgw&dkKK5+izU{uI zy1L6^;cymOtcnxfgS?poPNS0 z3dCleGmg*Z9T(HEAN6I4S%pO2dB>MS7;rlVBiRaFQ< zNpAbm4L9`s-u2D*{_;EwQ~y~~Q0zARnqoFJQ?$LEva_>k{PD+&fe4S}HIS;RR19G| z*R7-a{Rr_PM1uf+$SSF7+mu;x27A^U*pI=@rOY-9C%IebU$}0I_Z7q!+ zHHI{=mqt#TM(Z|iq;*@j(w@c^s;R4|oi%%?0VNnSemr`&D1{+hv`RqNw5-m~&Y`uT z)vvcT5yqjw?33m^2|Z8ep9+d_Sb_+^`%=|Jc?q5ZJj+_FjZTC`B zM+bGZHdAFq1sM>+eRLABSgf+LVr=2+_1}J^OgnvgQB_6NKf*llMU}CO$jQl}wpOSo zC!ap~dM))GHk!tb8chQ#`cr91F z7lhF7;*bSwu-USK@^yS~RaGSo8&N@3gYsy=&^*fTn~Qp?^Xr;_euAtj>Oj7Te?X1x znzz|noQOAD+gjnCq3e!zYG`hu=GIPXh5j3xTgitAJK*(E82Y#4T2;|0H(RArIKi?K z2hEv3w%n8L%H?j$4*e6Wh(7`o19SeRRZU0e0ypgUwvxB4nYN=eo3?JJ&D(Z}Z6BgL zUq>rN!%=b|$_|Hr{9-K4#$-ny(XVf5UO_=_mQp=x;H`?PWOMG>z7>UkU=Yy(a#h*C zl2(1S3c;*N0YnguEzQ)}SWoSUyuHnJu%b4)gg9ah4I$j+@=tx4rV&u8 zM-IHkVRsZok!!949;UJ-1;araR6U3a3kqrb)@>9*>>2WZby8<*3)P|>gabi3chN$c zH+Lo-*uRxxQN%|Opz9dG^Q$%J(_?Y%du7n*LF4Q;`viZGf9nht%@v6H;0X~way@wP zAnH?IN>Q{A{>kJqBL>o}S<`6#{5dps%n-EfAR65sVFZFXa?ioJ^+Gy*q>P+2%0SL9 zv5yTp;CP`cI051I&}h#8aadp4XmWjj(XZ#^F7q6A_K`1 zutP+!j#QS_ze%^;duwjZftrIjn%#zwoa=#SS)BZdOTeMH$c9k7FZ4Wf#zeI4T zCcm$P!jT|KEF&{<1PRIMG}b@=j-%=|O=-09^^%o;(do0M_ec0HzA3;Z;UBPz#^6Cs zC-uuKrh;sVh72yDNZ3p5ZHI0z#gn~M;I(?$>RoeBnk%7YPl9`JhLB@D9H;yo zhcI8bVNr<;-WFEF76axg#?Y=TH#7Iag8qJg)sKJ8Kbj$s>Tr@kr7yDCY)`;U3wGD+ zw-v|=jT~BNqUf+-W+>bdi~z$cZj^{;VdffQ_7+&-udlrJR~fNU4*`r{{`Qt(xaoJ$ zlKcFkQa$NXB3cCOTmZwy}+g25hhh0s|%}fIvbCNq}-bUC;&H-R^Ckng9EG zX7+aPRub6n|De<}Ju_9+)!o(AJw1Dx90s@Ca!U^+Q$T-{9hw9pR%g(s4?g%{6Ekxm zrvNbaA-UZlFY^wA1n6fV$a&CEIT`3C0L;fCc^WiPWn`n-Nh_Q*6Q6=EgOJVksSVvp z6~O#ENY;Q{=8Hgg+lLAdgMMotD%=Tr(>|1AKQOMKC_aIG|;Kv}E#ROf52R1SjpvhQI5zw!h;ef}?p(1`u~B`JjWk@{6#pJ3EB;M3AEOsIuNxaUIr}(xz|X$K%+qfTiY^_dyUPw6tsmU z;6+x@A7RJuB2_>>^LULIfNOi5V+C9vfP_jB3vk_SuDtd~Bv*r8XC=AapBiPN%t?t{ zuAqO>Nr`eNb>Z@wobCtzzd!+WSi~SFb#c&1iApEUM3s{gEl%pf<+Yl1!0t|GMSH%> zTnE)4)&s#x&J;+{gx|CeRbAEFhYBZw27>OSfYWf0uAu*8oJJGT3$jxX>}Z)yksXX+ znwg(@jU6pBpF9ZiT&1IVv4zk?L>}m;$eVve!ZDp2K}Al@$e-ur5x>mHzY9bj#9hd1 za&LMN#FFs*1(@w9W&(c!S)hE-51HYB$IPSOd6F4;W;~MTLFBO#^bn|Xz`+f4vFkwe zhV)I}f(Gv+pPq6yh%TC)i_h!<6@lKyJ@ar6E0u!!fMTEt$X5eT)`*51IaoXnq7Z+A zmCpf)EsbExXIzu=d@6`0Bgp(JFn`uQ?IM71O2V;$F1IT-UJ88;>JNIfHLo)-Q7xb!PasI=n62;bRP=cN{|VZhCMhlY#|YuVaqBoK4jSP zAH!;0aIw{LTF7de$HC>0aGUAZf>nQe(rsc|&x)oMBHiF*=fu|*U~Qh>Up)HHaj2;t z;`I!MK(_y!=qAAW^U#2Em>Z_`7BttzL?5#tf#mgEXziVIrE^CXvIJQ74nGaUc!P5) z*7Ku>S+9=D9C*lZxWtnb)JYoJibwmSwPVIG=dLu;0?hA?Jyv>mED~R`*m{3-WWaiG z;-%s(-6T;h{gCyqAt#7odL@DuoPZFw1a>LNYk6YTf(KF?Pfz!ubTc*Y7|^B->?oFe zL@#^GKNWw;6e;#<5^tTp;p6kRCC##%JVoZYRpYk|tQfULf<53gOVEJ4j*gHamMLaa z{8h_aa)y@D%01&=Z&Lzd7ao6qZQ!Wwk4YZ1D#V?IsD>bdJTp%kH;h`o=KVXTT1J)b zL4i$hN}4J0SL~7LKl-&44u`i^%7Yb45>1$?Sdpn)+9uD~MMo*|dST>tNua}$BDg7n z&KZRnw1`wq-Z*{q+$Z%E1R4RK_%x6Bb*~gwhGo;DQzc#l7KxNd3Xy+11q6J$UJ&=7 zzcbbqt!>UZGm0jxTdL(l`+y;)Q4H-pq6Jf;l_EMUfM!9T7|}vmxAaD-|6+lpkQMON z%dDT?B!Q|3>KKe^3zkH;$x6ZsZPCkhT{ADzQqVl^l~j9`=;I=ykB*8q3J(n|f%n1K zZkCFtDj>s;UnuQ)0qK7T2IOF>hrIgZ2gHg(djs0D6fWUWJOm-ht8^=&50wOhYmgT% zKly2e7`qX2(uJYesi;Sq>xRnaPfwMnU-_rB|E?F7r4Tqn}tjPQ*ozHB@d?0%B;MF}ox@kJS{&A3nNN4jLh8)k1R6OA5^K*^1PmM5{WFMnh8Uho^2u>042`tP4CRQA4aYm^dVRb=3YpJNEW6 z72^m?0gC#?mkP_t70V@cuvtt{vb{y3;UgUQ0H{$IE}Owx5O0h0=Mwq8XOt#Vm}O zNx6O6!%|X=SfCutt5651d{Q!8BwB|S@_lc4F>(-tcxRVI+q}~YE83Oc5)1#B&;re^ zr?+0_7H^Ppe?p3VVHsPnM`o3OCYMybDg`DKDu>JPLZK8)Wa?r>Jd&zKvrfeRdG`nV z7pf8vdy0Q<*ypdR@7rtmerSQB`k)mbbW<-<4~SBEtRp4CI^qNK06Lf7BcVN2^fGa8 zL2I?=fwc#5#fGls&**3_FzdEfi`jv3opr&AkAip{fp1a`0E9YH$E0@9L64XXK51HB zDSCt7^hDyb$(($ZiHP6CKWzP9|6D5+kIt-ZPHBGuvrzJa^!scb4#8}a#3Sk)X%fOg z(fWMZ|5=d)%%J4!#x?$zm%Qq*?R3{J_7vYdC#oNKz1>@v9|%}dS>lr-c-Z`+n0Nx{ zP#z0S9d?Gz!y#R24#dR|#%2DzRB=H6asK*6zi?P7bQ3_-$vWk1*C4snnGy4W|HUWC=KU@Zi-46W&K2`cU)NhS7gg ze3n#|Sn~b>k%>Jm*@;P$1@43MHCfl7$?P7MG`GW@B{UgOWXX??Hxd;=^9LwBrvM6R z0ZmO!6I+wMPrmu0=0Cc(S4xX5c^Q_iDm7&vj8DI0p@|Y2`hyOpeSMl7fEPUv(~jmg zU3TtmlV>i@OBDMO$5mBTsgfuGd-i|q2^16-F2DVK-=u`;lkIS3HK@!~o+%xEx(8cx zQ#VCt$0Hz1!=(aPy|6tZ*KS@UJBQDdj`ALI-&}J|I24*baNxkWx;rl~@5gU!)h5-3 zys{O}(Vu5Y2mB40E5`6a2K^EFDnaNAS_pWQAENs1tl)*?&b+fxMyq9BB(q2^?)OoS0j$FLaa2+3`0Uzh*c zv_zgL8z#S=e4Wg!E)#zuDD@q2`Q53BWPuhNtfPG&v$95fjJ3A5YVsi})C40kR;J;9 zPANO9K2eJg?#KXs4C{|&CeAMETEg?;c177(QJUt%I6q;zl z_7-?xbosH>mgv-yE)WSdRzzbbV&ZLYkUN&YC?72Tizi8^}Y#GPmf7%JowL}?hX6fCxTXwG<3OC)4qs7`-ATJ$@)W&5X6 zABoDgjt=?j(Q{?T&~cTkm$;2`qhezqG;wqqnv0+K0nB2Q9KvR8r4UH!}Z7@DV2 z5{$OX)6@D({n_WrzGzf-Mmpq^-XrAoNvDe*ED=rjsiw<<_Ju4R&+foz0N#^W0)&() z1j!mbF~(f9aSUi0x~+efLIxP#J1kFzmF7$J(0=mru_wrZ{9^gl>~D)+P!8r?3B|os zpW_8m6HOeo#u8ANxpqKFQW8c=_Mt8ic8ivTkhmopf~RxJ4LN^Ex$N4tOKNIrq-@e8 zxog4o5-aP65EOm{aj1^_`5e=_R=Wg)OCZTI*02O?2NtFv(U5-=23i=7$sB|zdoZHw zdnZ=NjvYH>e_g%2gZSshrk=8|$0*o64*`PLW=@4-Isy?*ruVlHMaHFnQ3CzMSW5xx z`WMC#P9|jSeguRFnmiab@({j1I=Mjh@7f`s*EGmI`-1XhyuX-5z2L43(4&1YrOntA z1;OcAQTV7j2DN{h^e+T23P`0=pB_~nPlnKWh9bV1);9_5Q*!HAn5b#Dyu7JRZravE zwt5DNCs+>V(A@Hh2jPjQ!z11Zn1ggUg=zhgGPJ^wwpd(_E>9#OV3j^$!i1Vqzj6QR z{ad9qmXtlMNx1|ed|#_pe*A&R)4ThL=Itx~RH^u)dE$RV6ybvh^@cO3Lzj`|DLk8! zg9zuztJs&iZ~XZ2oSvu-ao?=!=$cYbhfM4pM?lpoH!aSWU6Ec0c|eIGm>?it_!(at zw1zA9g_!D+kHO!kM-jtDWk6|MN)a>8td6b*&-=++379;2a@;hHD=#13l32FAL)IQF zl-Z+-5z&7aNOci=F{~Og6hmbWj0;-KlwOzxh2vp4b*LeIiVaz{uR|^$(V76StH_hQ z*`3n(_~VbSJ{b2r^4G1!{uZMEn)#(ip;wmffj{Y`$=)_E+IUiilzU|LeoIaqn3DQ1 zIt|)=i6y;H0%n;)04rLiQmzTfNh-ZyR9v?CAtnfUO-5Bs92O+lzK0jCpF zrZs;F?j03ptwAWm&}ALcRWoMH_3=tFVH;t`I_H*64F7i&j8KiF)h>FZY5IN zkgl{+#@{NRd!27Xaw4aI1Lw>u)jZmLn%8rQrt5_mEClDc8*YI%0xZ}c%;C*VOo6P& zt)%gA)l2_6@{(G^87IxwbnR&{?+b#TM_7O2kODm!{W(2mlAahTr>%xnYZ=CwJzjao zU2Ioyp0ZItZ}vra;yp0vOKqW@8WSuG7D{6fMYQ3<+?P&MhK}Q>>*k)Q77JAg=Dm9A9eFA9 z{QDm57+vi5X*z9ATe~SVhxRcu7}#!=$0DAJdQH=5D<}Xc=ByZ%W#>s={H-28*>#t8 z@;^=~@aAiKbdOeX%G==;r>r-RD@K2Wpn4QZ*F(t#-`Jja`kABKQrLw3 zf8>Rc=)HES0a}pO^q_6%x)sqZPfzXCg{OSS8`S@-Y@9OdfA*WU;v&nNU*z{9vd}`w zpFNmZYnBx)-by=mw1L=FzkPF-KW`W zY`RuhUnDEWZb}R=5UwQ8IA`lUGB>`g)heir!?f7_0gme37mQM$QM@E`NJ4KL(!PDg(DK`h)5W5Q3Rvb zGb?L@$&y?7YVlAQz*dyC6p4SH8vN_I1+``%xOaDRB-Yjul`xoxkhX)dBIY5gYYs)E zE)~w*GHZk8EJ1rXDj`P@^IWw6!pIH@q?{)wg%4KQEDpLt~mIssy-#cy6Jxs|qCG^CWsZk9B{=Ds&22$Cl9* zRzM&5Uh{jaFPqjcrZlFB6gdK*{WUWOM2n*L^9>26{M})h`f3QU)|nXflmqL6w+_BG zbi#0}^}0DjV#%akk~WygKn!*Bsl%cp`yFU1v;Hy0xxE|Aq;Iu0=h>5rJwbh!H=vcH zxjL7!&^WXB;f%Tl1Z&45z{W}IlulLCp%jJG4n5Tt5FXx zfKJpnSEB&O(XfA1*UHXiQ;WhgbX;@&4_7lyLl!~6RRhjJoS%W5#-8!VIUWf32{gYN z<3Y81S7jo)_b%VgUS6;GGX%7O`3=J^u6;_KbwN%6nK8DAnzb51{)UO)tvQsdIJ|&yA8xKfl^=`SCLw>Fj3{`LCdmR!JNIZ31I0gw zM}B6*@!#C!Jkkw01x#30gZW_U7PO_Gf-y!c9BC=UrX17_JVb@#Fi{LcNL2iu&>F8N z^4KR+zN23KW}=&bNlP2YSdx4S^JHiY#$ad@26!!LrywOjqVRO>;`g>;S|1jV7JD1_ zUbtlZ54nHAMxnEv0h5;=ybQ7P8eIaDJysA?B`!PBk73Z~^q=Pz=EUkT53~nivd-bs zi!ulNsZ;X;u`MTUd|;Gf2&4r}S=u@h#rXpY7050a+1bvLDSC#=qX4!d9_hLXA(%XZ z@_fl2`N7y*v)A9pMs5p$=3H*#OJ?;d*GwfP*4%$6;oUV7t*w_-oUyIlvso9oLmg|F zed}PVJE;=lNl8I4HlQdkwou)}eo8L0=eViXvs@8`98PaI7|d+3qqiJ$1FqHuxhg zNlkw*C>BpXS|SASm8Hg(gNe02U+#5KZxV!!SvUVjl2?kaj2m0bd*y zpOohI;9@=A5jnAb&9;tEJA8F{f6*)Yi{w{|1WPcg6~ky{qL)^SUWIFAeI*eNNbAa- zC{1OVtgC~y)25?o@?%rY(Swx$1;f?g*n zuZd=%S_b~1H}zofF?ShFxPcMA8ct~unk7n^kU=o@phW?O1lTClA z3O7t6s;B%_N86Dy6lTiC0wD}yjY!x^t^Po_Vo9|LBNLj}`%6s=!yH_bASDD7M`&-r zJO)aTl6WHZ8TIzkBxFeD6atedGo?0sf)NF6KTxRJbS6p$?%J(!TZ?52NttmFg(M(= zl;o<*n~aP0lPPUZ#w>ucd;38+;)8z>pND}b!0iuN(4_qeO>2WW!>~VvM8P})#t?>9 z7f(eunr8Gd9h&Y^Od*6YG3F{$9oUC{fWF{Wq5LW8Vg?X+pUV>H0wF>H?Wo`ml%fNg zx35hk!Y6z%{yDx~lSQfoPAN>zVvuSHM3fM~z5sl)=-em%hX*b+X**Sy_B(%3f;AA< zs%!1FrrG{nG8w)sWu#_)H033}s>AcQeNhe`4QM&a;iy)G(ZsXkQ}KqNU7*Oe8M+z% znHhTN3T`p^%FwO*$F!gXkE*GUV#EX{3KY_AAT_aryD)>AWi2Z{=kZ^aeB%$<8wt9g z^yHtX_r54!B)5JZfaWWpIro1Ep%mx`?e*f{xmGP(qL$Td8vPQ&2TRjiAn*l9{~X$U zfxH7a9u0-YL5T@wB65tC2#;@H`e36ifVlPZQQ*r-bUsZ)A^xq)#gj~m=0i(jTtfTV z9R|Xb*;F{8j@3D?rIKMY6+5Z@-8)y1t*SwV2gYu~J>Lb&u@G8&a548ohHh}t)KfaJ-rnyenLy>;pRx7=F5B?C7}biJe;|r zDN~?nv}wuMgI1#B;r4&`?)rM~(IBW40;XbOKHW;h=6j5ImA8I-qaF<>B^lo=M(i`) zG@cE;eS5c678i#Xa0K*!w*_5Y?e{$w#EoR!@U#QO#`4R(CzXHxwFH1+KO_vH>u_VHrtHQWF^QG zeoDRxbFIoM0knVT$h8>60iJ7bYcv=8%gkM%o5z&@B$2@XDO0uguCUeiN?`?9&sJrf^v6+rWJ8{mKc3+&7^(RoPNg8nZNR|3GC z{+Ihixs|yqIKre`&eue%E8ub@Pw+Sg9!Dj!NB>9A!JHjKeT;AjaLes~3=IOfD)Jf# zk%8Jho@*=aWhe!Q)0_Yg?%w1l2ASYseHpcPno2RHlLEfarO;WXg1~f5PZs3GG_)-elSAqIJW*LNHZrWfM2H^1Bqfzkog zR{(cJaYRcqCn$j54lp{n3qm;9u;SR^t_RWI^HYDNtoJfqz}@>~Ita}9B~lhx2kdMQ zfX)YTYd^P)YzHmI18RIFa32@ZIS^rViN|SRvYl#3M7Fggqird~jg`KZeKW*&QZuM~-YxR@e|}mt z#J-Y7mH;s4$5rkpV`&(cS+_J)_lHKz9KkRIhU}PUpf{z5MD{G_`05Ly(eAH%9nINV zvY5jppJ7IER!RM4e$av*8QL)3vX6baHacsFvpbEftoK^tr$RtFKBLVWIrHSpo)hKx-?l zxkC`BmQuL8peu%;b-5q=d?kSSaFl;SF{U6#nA+QtO8{pzhkSjN3t&FXWvonPAMetm zhPgIs7!m<7btz_;?gv*#MBWhN*}ys= zv-=|{V?z`|9OkaD2ey<9R^xOofH|Ec-8;XL$^@6w?7fcshgerQfE|ueM0(olxZm~u zfd8y9&D-3MJQcv4lf$&T&Hy9vbD@3b>br}N^ZQ)^fAuK%2GweflMg|4qs9;VLrGa7 zXFrT0)PMuZdYkUx8Zhs^q1AuIyZ+u|kof|HjH3`2x~@mY9X)VWMMd#w2+aH@lQ0vB z+W;kJ_E{C1B=H`>}d@;ai4 zzk&Jh&M+E|Jm_cQMX6-8Hw_xkKwX@OQXK=KtvLS-=bz!6Vatc-TTOpl5y*+d3b0No zJ4@Pw3q|*9TvC%H*Y42pxP%ssAceR@{A_K9k>2ax6^9gH&8wIsv7(idFuA2mt=UNu z0bB~?fz@1rh>gTBj@7m$`RctJvIJOX`;V1m(VY_UO%lUfE(ZEN`h(J#HJ)Gqjz_ri z$bBX(1%)MINrWFQl1hI;h;_HNTYZ42kQQK_D<>lP7bssXBgK1Tj);eOOij5%Du8nx z)Y1y3$fFQd3J8yh^VYo8PuoH724#_=zo5}DW~F58*@YLycb^?M3RfcBEA`A>K( zuVS*ZDZ2s4hkwIl)%_$N7>?stk(Y^2@ys9j6|%x7Fp*kjc1u9;GhsA8DuN6WL7e#u4;elnnDo&((Y1Zel(@+9sk<1b>e5bFs5yk{l?WzHWfYH71!t7-1 zxi8|F%n7=VwyecR@_0buvo>F6zNNYxRF6%S5OL>ZhWCG$LTYX4{Nl78>XWKTnb8~n*ahreu{*@8qf*$ zp%`xGno28#aEg+RpMrVjZ@egUZAA(&6<61}+S_FpG6xnA4cQ6a^TS-siJT>Hfs!zU z=VE{0M8$@Ug=Xi*5?cuU$)#YPYu#EQX9--OB%G)5We`i0QtDusKyXQKNfRD-IObmq z)&e=&nk9>@qd_Cpy3tp{VNJB-+)13Icm5E7uG=$G)8v|lORI*wv?gbhB611?y7MN#3|)yn!L3Brs@%Xg>RGi^2r zT~8IwIcq}k+_NS8(c573r6hK56*I}`JX7ZTgDUJ8EnYpFa6W{1y@to%TlpZl$t9i2l)CW0f! zOU1WulKKa4ppc1fNz`n{vH6=lufMO)!54oovCRmYF{w*#+bB`k*;`g2MN{WW!EtjW zzWqxvTDsS1s;OR*`*%sjMc>!M%in)F?)ovk|N6+6bqH($oZJDMU&tvFY^ff=v_{Im zf4B5F``hC0*;i$G3QMGT_L<_Xs+Q=wk6^a!E=?hUp<~2b(W5%CYfB0Omg>;H2U`m( zv<2F`@XfneN+)s=y$c{Xc)|iHyMS|(?r3@8F)2Rj90AWe$eTTR3Y#KZi=}^}XB)n8 z$4FCKL>8~vB?<27$-t7e$UFXQFzNndSmZ%odE=&F@V0-PXENJ4n_?zRe^5#bgEDK< zpstpXnG**|Ab?pt%#jQ6otq>uSZ!2u1fUbKoo6D^SdZDdF0U=yEI)cUz4=mM`YI_q`gJKjs!5V9L1}z*pwvD$0+o>M9Qa+`YD_d#_s>F&Eg*jjEf_MJ{w&em zrZm1aKMdT_ z+e-4A1Oy#}+of=Hi{uUL3|;)F)A&yH%QlVx^j12qEMV@Hs8^GTPWT5({cF>t>D~TP zFuYYtr`1aNtQvJ}@hg9K2W&xXNq`ctiY}L4k&Y`9iS6n5DGeWc@tz`Scx^CjK2r8Q zK2{oD9W1dLdr?M1Xh~ktjjPzCR_h!r=+EhL=@m0!?cRc^akh)kG-Z1s`%*T@qy61~ z3V7Z_-fp?>qd%w1rB_U2zg^MI(MI{}=f9I}2RBJ%(s*ep@yUOuN0rE5&g&=5rJak$ z!BG>$*Q=j|K6s7mfcDxo{~@}$YvobBQugSZh$U;}x9jfZQonkDPSM4=Z`I4-eG$dH z67IV0f$Qn6CqR2;-*nB;e{-;)KQBG&TT*e^jiSM2CmL#`y1@3P0Z&kh{XJxiHc+On zYn7^&gp@}$b#H&^8JD`uIpE|DehHQY$%9kYCkiYi79x(Ohh0q8cm+`OZX@fJ=$1-9*L5Bh4g#gN3_9fE;H zwH8(=?!O<*k38sSg8m$d9kP&ehb^nY`0Ir&*Bswirip*Xcl_flv8qw2jQM*ZT z_^T@QsPH=6Q;+NQ$X|hbUi-sGmDwH>$P#eXw8kPd5NWd>uCp<%7JGzDVGN*=`d7)H8S%}c=*&TuS9MOO2@4MiH{&Vb?rp(QET7YWs~YS5b!Nj zdjBG|BB+_}k-9nO=5L=kGf**PoPTI4X(czUiEn>@ZEq@n?@)cHk*{f{4u#;B^f%+; zdm*8oLp^PUpi$cYOsG8_LTP&i#hk}T2aNQ7blaaQ#upUn>GkUaQA?iQk(8|+hW#TP z9&UsMQO&n70=^IhXm}Rkf0sjvg?fvlQFH{|$$$SUqX1`pMke#ij z=!SnL!}4^wd9dFK{-}MU2Xi<5-MGDTIb|w-D8UdN%m>n*u5HzBSuywD_IO3s%cBkT zraZnnDKU(q9`uA+Jv?&rn1GBf^=fxMSy3XZ6DhOa`IHYzQh)Fqr1Kv#R~AApg)I1X z;jX+wJv~UT++)h$)*5PU#EU`w!eL&y08xJh7b1y%L;d}SY)pRQDyoz<`*h#9Heq_ui$_%nD990Jmw*@COq4D* zXtaMYAF64>)P04+9O_;-)hk2F9ksh){0YI{R4{`%d7%VU+`V86(oLMUVjA$$VibQf zp@|RS$i>Haq=G;9bO@vpR*LO|jMG94)6ntH&WsGE{%srLJKp-pk~rcl544{@L6?D* zhh|Q!SsJZ(6{R2&6y0U-yLL?Eri+)Ep4wV8J2b_~!!(46hi6W#d@rJ!KB-fXwOdEJ zlf_~t$rI2d;tviX^M25J?vx`l-?D!$wr%se*s)~l*dDyd)3Qs@sl7;#QHA35)1`@= zfZ>Jf--kmIw!ihlI%@ADA6E!Jvm|de({1hr_TuVscE?Rb47v5p-K(1FQit3P%ewmJ z*j?KrVRN|qyvs`|Y+2j2xxKe>{M`lWLw_{wJN=}jH^yGv(9x2V16w=d<$8Z~<#BTh z@+Qv68xW6LiPcLZH6OkiPJF&Hb{u-BpUk=ftiC|@IAw}C)mv}EP3jwi9>WTx$M6DG zTYFZwN$3E)Bl5|_b%>d8dApZ*ZjX4@ciyiX{)Eb()pLsv43;2&8tZ{}ve=5?l| z^xRx=$;i{xZ`Pi<ORxLYQ;_~HhcFFr^mdSscug%sne@HkB zIR$)Yh1K^j4RV{LNBz_@p; zGd6a}<6zDx&aS1dcR|RvA;6Dok8>)<>mF%8x=?Mnmm8&bSJEKgnfft9sOEv?&RXui4~%xMmnF|WGhg4Yp4-;W{b z<_RJ(96z-KZUbXA{G_@*q*%Un)gZeh>e1WQSbgu`jg~;oIqhEcR} zF{t1e>L7>!;37+QXA&B4NF4nRUF!U{ym*pJoTwoh{V9Atx?)@t1b}{TPwI zjYS9o&6mIgFCrgxV+(Z|X95B>&=_9JgnOS?rs#u%GKPOE>t8g8Tn=+wG*aXr{Qd!9 z%WA&8%F+sO&q-iTYZcHWxsb4m`Q4_vk$ZjIueZy1;@UM6nSva!1f(ovoa@_T@+B*) zADZC8y&~`JLBNG}eOG^U7*;%0bRS@vdF-IWy{GH-fR@lvQ9DnA6D~zXorkIPNh{DV zz7W|B6J39Uc77QvpEh=zBFSZl67lf!%xf+YrnN?&Un=j9Lod! zL>9oQ-HtXtDN_(iz~72gin)y4=XEj0=gTYlH>-cOT}@$mI_siK1Rj1Kb#vQxkp{%7 z=U`l`K&i%nHekHFkmDRHpQWHMnv1DdUj1x=zFw8EUl5aTuN+htyAlNxVUfRJfcY`} ze=|z;B&>6?T;l0N7S(c2GVbJl_R>w^PHT8?q>4rCak$E0^^xst$E0v;om6X}e zDG+~x{{U}#%~3eS`SWlgYddUrP19Ew$aj7?OjDcn(*hL!W?qis;esP1lX>QyG#?_& z7h$50P^w4wfGh7qbDvov4=tIe-=gjVvIPLs-!Ly(-Y$>9TNbHlJ@0VI1xj!}T2>*N z_7hxsVo&p0@$p4+(`RRS_y-u$$Sl0V@&$kTvsd?($-Ro<&owKdY`|Y6OFAiA3>+Lr zEm_Eb1ruSoftN3=){pJVoak19Oq}|*Ici%>&f5`_6JW9_C{^*`LQO8{FZCE3w*6{{ zwfNWqS-5h(&Ofe@6IlWdPMtaw3HNSsR|gv)oiV)wQt5dEGk=$bjVf;ww^|F6Y zKH(J%USY_dyU>8x+W#Z&UwU<^*|=m%Y!`TdZhQtZ-OTt5!+k?YG6)tQNs@fur^q3b+vmTt>@+-m917-Ef2W zX7KB!LxX}Mci$~0yLWfoNE3B#({X>`89G#oo_Xeo%n9$5DN^+G)8ZYge!ICVW>ElJ zOByso!Eb&eT48z>=ZMhC%O(Gwdqm4;L(4)h3dqXMzxig-D=NgqOg#R=3u4xAF)TOC z0|zAj;)`PL-79*}o|5;2A2?Ui$Y&jJi-+2J;~6nRik`H85h8T)#bWH*C3=5Vl@vix z4(%j##T8;~+N2aJe*JY6MU(I~*GOtZdhf^1tP%vi@eSvw6J}$h#GcCeYaM7OY$!m0 zOU`zmWu0UoKTCjT2!H3rM(}ce9%Uo`_rEKXb%pn6`^|gsl1o%d&P*ym=D+7|lfn*J0@fgQ0cbDFdr_vTR66sRYAGzp%gHNeCK-n#??_w6 zB#A|5OGSBs_&px+`gFB3n&2M?IM^DK?R)pg7h4lDXIj6UCF+(z<|*Swd2`+EQmK!Y zP$;N04Ryq%sK9^zu%)u9UGn{fQdt?7vi$y1UL2IaF5D*ltBYm9tif44vrb&*&%Sk~ z)bF=9&g?zVxlz?Os6i%_+CQ$8Kcds;9A7$HdX}7~gp3*PmlG$CPV-G4up$lX0$ILh zxV-p|{e8*0I*heIv9EIj=M~@ID5HmTdfk}W6W*grtWAH9NUzGC@{hM_JEc*|1V7B52V2dICwz^uH>N-1fRaKFUnbuQAPAQcq ze^Mp$`;^F=``hG``1fR0ii^A=E8I9u?^QW=baIhtL7e*o8Fr&AAI4FQA7BK9ll_T{Vg*1n(Q$qsWdonnv5JbSw@T-CR?m?rFrnTlu3#9 zWaoc2_H-+9LG4Q?PL=tCW3s<7A{*i7$ehT>%(5?B;3?xZsVEWYVe^v_lW_rHi=%Q( zUFeqC85yt{W>)h3?OZVGWbA^Bd%^W=IAAFSnhzS%w1Zp9ZLlO0hS?j;bf0&G7LD3- zkc-B=p0EvbUUbzT1rT>vuU}a%p;XU_{okfq{py)8(q1Y@j^<#Tl|D$(R7G z!)dNAT;_xNeI^$b{8}cB9h7BmBI|#Is6EhZZQ6OQMECz)332gJ-IcN_%x{5g#QO}9 z*?pgqlM8Jx9PvIY6@?4B4V~(wsXb=JV}|-c)NmMStVy=kE|H?x6H@3|qXhNspRIjK zPmgjhE51BNV#b3~SnN@wTw$-k?|F#itb_LWQusaI{9B8uJU~7M3oy1b> zr7C6nA)?VcS%O|?dIgmF?N6I~RF>ox;G(^Qt4@fV3_}vJ4zVPtN_8ZV8BtQezZ+#o z1;qvSFMwtV=!(>d{rC#V-FMA>7WM`vd*c$fr88aSUAiyp6N*ga6adCFxchfwxt4S| zuqpB9hwg=-ZXKta05GSoae|7FSEN&-nmVoWNdsBp+wPWp( z&idp%u@*g#a60RQsw06t&fXTSPP?KIJ{|TatWUFNn_mNm5x^fU+;4v|tc}fm%U8f8 z3OLj+4Wu>Kj+-sguXBH~>TBRI`>p}=Rdnc9#F|AV;(2VLXrr^2ZoUdAAm=x&3VXJT zal?7`=aI!_qCfJoXy>TEX8cuQZ;Q5%4*|4$^Lgj90ruo0_km2TIkEuETJ+28P~BSm zhFDAa`RrGQz3&>-8Q5e((?tK#1F8;K7v^s{f&a>&|5&X%g9U&6c{gaMoFm#){(=xH z{MYF0tnjZ6jt};C`aA*ApLe3Nm+052S7Bm(ut=cFY)QSp-OA#wtcd^%zHIyhb2pvjDJS3&3`54|h|C`boeLsrK;w~%T>okJ!5r-HA1d?$y#e|X6l6}6 zgO2(Sdj{qp4&f7^_dyFmEE9qZ?*dH*y@}L+%8LY^Nk(u4WLFnN8bO(eQ|CWDj*b;= zCV~(BXYyM-zWk zNC%NQF#>c$cLdxP2s?s};u6q}pq;!B0k?NYMPm`X4(g*W`0+9HJ0oz+ION0fo2V}M zaeo+e*-3K%Mq3el-+vauQ-M$cadZT~^Ph!q5w7p(j*5tr<}?D-Gba^*?2kk6mj5h- zn**UjKt*g~+T$HuAKjfYC_s?qKMTWl&>ule-j*6ZPgdM@|^;r;wL}E@n z(H#No&Gz~aRYfcFA4UW#8siW&-9MdF0DmmOjeu2u8HlZIUl3E>5l@47F9XE#Scqr6 zr(zu}mu@$9-BD2_u=`}A7X*961OCHsoKg8 z|4a@}Rz_Xoze7c@fVO}*k~|SkDSrpyx?R369{<~Sm8AY4+CK+`9Om`}?fT@CVfjAh zmcmHv?1RT7I$W&P9nk{;C&Kc5Y%b^^cN83SBg0??rTPy~ACa=fl%#;zfVF_wI-W8* znQ6my!`Z5GjC?(a_fN}|!^!~6c}_iYYM{aK!tOsH{0hVYHV1VP{m&DjqkjO-a(xcE z0K~dc4c{FMn&2PfMxQ5dH)DDd>y#1<1Jt9Vs2e5X3?zGp6PssAl1Z z1(^t!#+VE#Kg@|g>&HWq36ug-^|p*xu|hRbn~)bFmUI^;bJ`Kr~M> zE`X4}px@${6M@VP9RufQW@z9+*j zXBt&s{g@K4;oecSkX;bMSuPIp7|w=}oat{L+JNJA4{j@Cw(o#W$9%81^CBE8{Ov%s z7>t?>{GNZN!Du#!)e)Qzkry>EWz9VYv<^fUo|aJyp|mIt`sRR!fjICRH7(sR!=i>18*`%^Qonj(=&H#hX{Ms2Z>${MR3hu{W~Sv$(4~y@ z6VT@DbC;4Sn`innhd@4yBPj>h@2fq$d0Sg;*&vHEWzC3NUVopRIpcam*32JCL%|L` z$z0;|HnjP+{QZ#DR`1sGHx^4nsTv=0M3l!eU}0Vlm2d)y6@`Ot4!-GZarSXReg2M7 z2(5k2TSkXU<=Rz$OltGCXm>3%8V|f?G~KhvpzU9MP%qi0=6G4AYVI#+rZ0k8AmrAP z&tIkO{~W|{TYvfXHPaE!2H%R5Q5T+vV}-IUtHo>*-xYHVVuwHX;8LU9c7-9Ra!xTQ z53qej;|QGv%(?4oTSCS&QHj~kn!GJ3;&snW9&!HO!Sf$hGb*~*BU^ucuJ`h@8;sB0 z=PwEm+T6YuyFKMq%GAm0n7Yvcv@co=XC4`mE+YroEq~Ez1IkebdTgK3di4IYdzCmdP(MY}((A+~N{NIIB zF7c1#fo@I_?&l%wgiZp$gx(wb1E!X}8*3;#A%DL9B2zlXmx9>hG64jgWX@&(3WC_} zh7cwI%&$Pe&WE1$sp38e`DNhvco~5C7zBR-oepy%Y)H_)kXL}{!ki9nL+T$494jal zA@%f!Xnt%NPZgWMd`jRrgkTQXO`Z;OqT^c0lm=g>S6F&|W~qs@?;z+5R60;m|7tB>?8d=79ds>4MJlmk@H9 z|1`Xi{{{-qD4q^Dh6)YdLjsTsdTtSIxrd;i6zYW9=YZfKBW$>M3b-GM?VJMwH|YA^ z=|4LqJPsaom_z880}A;Qg05aKa)841E`O20vGj8P;c=X(N28y~x801xu`+uxHi*nV z=YnV{bX{nk9FP41iK8`!p-TZL!qtzs)A|iGKH%|bmp3)ZIZrIq+AsbHLnjrT40rrZ zADo$E`mCl=TUyg7T710Dp;njZk$~kd>(OpaUahQ`z9uLpB}w1#vkMI;Y{z;epns-C zuFy;}d;sceuViuiTJ^BrD-wDnATv|W8;ristm`fHmEMIb<{3GsbV8hEpMU4S_0jYCzb0OLX6Cqw&dX!tAdOZI$jw&&TfvyIMVXmd0k0W)i9v<5^%;eX}L6SE?Si#wa8pI^KNmfHUneQHaPC zHG^>z9Kt3rXaJ*HG=Wukl*Hpk++!RUa^OKWW9@oHPOAH=8>bpLmJUG)n76DbDK^nI zCpO+Ft$2tG8^E9u%qc(-g@1usaKAO67B^DPYt&%Onzf%Z4u|D z3PVKCPzkU)&804nCiN)1V<@7UdI$kSS_`Uy;$jRiG=qX6$p&{B=GuGn4vpSru^ znpwV=mIjN!pomPU27e7PbmW3W@Bt0iIk&~ohZ?8K4!N(Zk=Kd~F_V&U9xFezJLTOH{di770{Zp#yz7k7 ztC>=!J{m>l1Oql1BqzuLW(>)c#}uLjL0}xNtDIYL=`GpV?K=g`tJz}%yd5lOQHsmA*50WW~ z4DC=~6og072yj0bhbC+?=&wI=xiM_jPMClnO|n(lH1D#eCS6$*&5=`V8sY)jfxSsJ5IC-=ZZG#d^8EitB-5r zeyO|VSurFz#Sj}Uo_&R4zGuF~Et-M^drI-38?9?NeCuD9)vMHTdz9^{(u+Q;Py+mo-Ftt5H{~CC zc|Q8LcsYT5rD@kyrmEZOQj(qCC?oYXW>fTj#$zz?$Ik`K<6-sh%CSw*WXxpSke`rFr1=klps z8lZR49lg;cqvs%7N4mH+A3prvi-2UP)jUOPTRaQ7)UZp=q3Q}W}NB-^fNyc2h^@SDh zs*t?=I&?%{@%r2mmPsh4Kh77L*nWF0Z?73R$Eg zlzzQ*rvWqkMj!O z4(H}3M_H}QVDG^f4?T8UK&3Fv_gdQ8p3dpt|C^ZX{a=aYn=bb^m8Sqa8{QNE{w6dW z|3t*Wf#Yri&#)8W%wrfL34h@Gdv3n!DIN#?+JAT)5zQW{;l7&}e?9rtwK(Q(FD^&n zOF6b#e1;49xI*Vc#HmFbPH*0f
Dx)i__3F|>z;lY(U{^qeWTp+%c5Wx6h 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 qIGbWROZ=S5Auv4d&ixld3x`C`q0}@q$y27 zV-GeIP>cpKme_;QM2MO%QKKemG?paB@>z)}pd@HiKqGAgWRNyYV;a-@+;+bA-S?i$ zT;|TeVDdfx|2=tm*6dUES!?gL*Is+=efGH+qz9HRU4J?r$#&nFta$$U=U4iVPZ43pT{tW31->Fi|tspXg7<3khXat>xS{(G9o;+BCLf@gnAkaIYuRuC; zq6SpvI~*8TgBYZbgFXZ;2C+>DGQ1l!9rP|r|2Z!bcqS3aVUR;z5NQLYBTuvM^cars zXmgN!>^qa+;sN%HUO+yol&bBC$;iLOe;k0>pMUDu3_90$D7*bB8ID6jrmutAL05r} z$71B8F+_qEfO^p4aYZUT`xVFmTY zoJa+cIWZP=!^sG^-Jc#0I>n`+8$n<5LI~V(GAf#g>h9iZnxEaWl}`^xb+bTTS>!k-=w4zJIHC?phf z;_;Iaz|m}v?@)ELYTscf`Y=i1*S!Y>&lw z)^jS>!FD-mXLm9x3Iz_Ibb2~CBJT4Y2IG`!5QODLiBMp|JCq0AESyDRV(N{!}OS1r9#6l7RpMmKU*?>P*9VH3T@yEdmW#02}!t(0?dU zU(CM~PSuJ|8vhY+Lj33O|B^7J@vWDUan#D1V3>ty#6 zBS7|aH;4}sJg56$9K?8u`S?r(C<;XP5ycwtffM;8&fhrI>N#gP8K|E8Z^b|auq_6R z|7U7&qBiOi|2I_h252jYGs*sNN`Ey7*6s45Sp4ldRFd*Qw0}+rIn5midW^{@!tx^4 zmcmFJ?Db<311|RJ<1qjM{b6|#-30^W;|1$sWDsniWZ&U;N2qGCBuOATuuc%Y<0+$; znYLaxhF+C(u$>^UD1=421SQ1#sSb5JFfwj$G`y6`c8UEX{sUX*d_UN=$$zl{+q`n>^e>Q+Ad+wQ_k3bCJX&FrrN{iy8?;Ox*5GQ^GGg2MZ(^4X? z85C}jK@PLrvZ=xoIe#PFH0x)RaT_Y|YVz9r54;^mI~h!51R5EF82_&YQGc8VT-R2$ z@0r5iEufilK1S;ZOU|3n)>yV@u+!NU@B&Gr;$`OYNfMhKEoGZ4<)eF8X?YiPDKq^T zv?cSbWn@bC%y{Mi$ZL&E$i?;hnhtH*-rZC^)EbqvX6&tR&wopweZ4Vb&JU%vv`|a1 zRC+zF-QKOQ9WZpaxC|wmj!0{jnjdmTRLnMDV_pxHZ~=)Og_CYhz8P$B^>I;4Nnrs} zTh`e(GoVtncD5XqrsA!JyBC{G``$8{e{!|auy@sdt#Z3s<7JzwwLjfV{|xGcklQN1 ze3Q2Sa}d+*HGezS%tSg5d~1^m&OaN+3e{UziN!45E6*{C1M%F0%S>|nl}26VTw+iW zV9$=m89E!7Yu63-xU^@&;xnTfi?=3;$8|yC*mL&`Tkx=2QPDhZ+4ifmJXg$WHN9}3 zuPNN{x!D)F+%@&e)XD3px^Wz6U$hvmJTfCgMozLj!+%rqYtRN-bk=w+cIb58)7C#_ z)|_8j6s>y1q^^Pf8+1Z&X_AIb|3mZTGBbS=UjgWhw8R+EetV}$Yu{+m=1nnBCA?0R zekZVR&_cK_p#xuB+yf^3e+#GF z;!i*QG=DuX{n*Z%Z@!r?l|n*y6$1j8KZaxji2a0=sDZyXO;T8?h)p&W$x`hSZ|85my*qQ_+c2nNYq%llvJyWn<|{z3n-f>IGm z&v=ODN6&bw*bL^U`;P1mvF5nz0FnJFMKrI-#g|y`Xf^kw{5b9Y2f|HD(>EbEieiXKM4G7#|=y#Xz z?3C~u@L<3k!0|PpkUt>l>-8chDBSN73V)nSFZUfDLw_S0<4nHoW**L!If~ICvie*L zqNOl&p?PvX_6rn_))<671@wn&9&x4Q3^6_6_8P8eZCQfo#qA|}jLV=ukd0_cXjUH*JcZ)5|B9YNX zMx%L>*w< zj)1To3|hgc2`;c6kCJ%YhI`E8L=D`iX0$`A%}sVKyzvYp=h6Wv0rPLJNQjQNpA#Kx zk}f<%hOJ=G2Idr?h{8afxPRZ}SBncJ=QZjv!mi!BWU95-9xx@Kz1uRx5oJrFUKC?L zGo7dgmX?gEE;44x+ffkag^KFpqvd_Y@i-^}n!%Q0G+R{Z^it}iN=wH6w3EWXm??Gd zg#mPTO3gVr8k)H`d;&~iZkNX-9bis|EODR)V5W$Iah)}wWzoXSW`CbCbahJ9=2~OO z$WRHeMOmtxZiBR-@s6U28e1R)3~4Rs28xTx&(H$WQ<5FwGR$@GmO=xg^IlK_hK}&^ zU1eQ$t*`O;pbZb&5y;y>R*=QwXNuHH;&tQ+4@VwYUTu>+w5?e~j$i~j+M*}5bq0%k zFC_&Qfk_dWPz?s;(0@=162S)yxX!gLre5?o)pn?TbECXpcYoo6QL`t%@ z8tp7bOds@;IUvZvvYqGUYLaC_xYygX^m1HmMk7Frf8(2!9Cp(dpJoxQG{7Z4!0Q z(z2A%EG393h4NYi3P1{n{_P;9>>nvfUat8C5D-8Nigi9>w`#@ANFjFABmxhTDTxdn zP+u5?htUXdU(Z7mHXF6KAGyL5v}-3wzz?U{>+J^5&F$@)vL>1%mn=y%Q+iddE)oGt z19ifro13IABY(l8@4gKnU`0Lg(|6o=ipBI;CZ^)?F|Z(53VSa)oQB@4L9mf(p%9iF z9Ze$bo=dKuX6Eca2q6U!KYz=4rNwUgd2Ey+(`wQ_^SI?rSGRW;%+lTNG-P@VGT&}B zo(`3^*)84`OJ`U@E{X&MR8&+X#>K_mY&M(EH5d$>!G8zMcTWNyP1CB}Zuh!|hK8rp z)635p|k2OS9T6L-K_}Hxgyyzqz40q1`N5r+K3>^hM z^cai=G=D~=x%8*0lJ+CfY?+j*?r85lE3y@n6%(vAEJ9qa7%@yfOAK?*g-bZreVm*2 zO7pGHi!mWejM3rZE-DwxPZmhb)u*Gt?kYU!f_Dvucm1oH_kjhPr?tg@1=kwtw2nKL zY2EL?t9iXBH^^1jq}Ajv)0~Be{JAvE-PEqVHGlVSTJ5d|T2iG?z?W+^t+i1-;8mj$~X0L zfAV+nxWmN~2?u{13{laTaYTu0bCIu2hGfe6vf)y{H+aK%^0+ujo661Qes9`s%@r@A z3V*_Tq(Y1%`9dl*oM)dQr6nA&GzrU&lkv91{#AFyNMkDn7?eTee?LPm*>IK&J}X74YrACWU7O^|zkDmrPOqw^ z5qcLbaxh#nMh>!#Ocm#r!x+rL&f`VRj(-vOD|JK;#^}Sm%5*ghlSY{~F-3lS{YZK3 z_cP_g!Rhk+AvbtzUzG2Xg~`RLP=?l)mdc$!+nze& z=5Z367vrn8N0SXJcgofJ-yUe|a7*FtdW7^I$;*n8>`rCqjEABIYeGBY_%Vj2DcP+gUwsiC35WHRy9Ac8IvoCiwhcNb)Ydq|B+ zzaECufCX`*7kYPM`r{L%3-k%q0Rcx04Rv)}!GsIq|8hXUHY3MSmge6<D;`$6EF5I-+aX&P|)_0p1{3@AOw$nLO?A&hUljsYWq zB!v$at4XP!ujcuMQAmVT5d?(V{@)*Hok>ttuO-jE1n^x9H^^|+Mt^rQCpvx|0{Dej z5CQ_glrM_7G|yFd?u6;}!si6|D~PXI_|4812;=S$p8&tkX$kQle*47q7odTFpI*{1 z_->i|k8&Wyqc<{boJ@%^{`6F!fBDFFoS38bW2XNq{71kE@xLa3yZ`j>J9>SrGXU_T zH-f9c>Q#*r0DI-Mgntn)zlh^IT>b8+Qs8hEmI_vtFwSq9wEz_iy=LSJpb4Pc$V z!;=CRWBI{!FN73;k}xxSH{aFh;7&nq9wzZ!4#Ag3JWt0nAwMGvsUjUv6$gHO^=ciM zsPP%s`BINd1$DUQo67Wo|1~r13$z5i20iCSPJbFaUkZVK1%IIW984Ys(Uo&^o(_JO z$zA09?6_a_+Xgq>a6?9AW#zf8t*x^VJ?A6Z=C{m@q?-_+9f*jC_%uB|eciLqKHKNV z(IExgdh4x&_V3?+Kjyg$v$C?Ha&mGcAt6D+!hG|G&dyG$tE-dZ;$kT&DQU6UY_AR- zI`p9@o_M0y*MDBU1T0**@IsXO4Z⪼OpcK-S2N6eZvOJZZWnIFd9*eEEaI@ZzA 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 diff --git a/script.js b/script.js index c902300..1062364 100644 --- a/script.js +++ b/script.js @@ -981,7 +981,7 @@ BotMon.live = { match: function(agent) { //console.info('BotMon.live.data.clients.match(',agent,')'); - let match = {"n": "Unknown", "v": -1, "id": null}; + let match = {"n": "Unknown", "v": -1, "id": 'null'}; if (agent) { BotMon.live.data.clients._list.find(client => { @@ -1047,7 +1047,7 @@ BotMon.live = { match: function(cid) { //console.info('BotMon.live.data.platforms.match(',cid,')'); - let match = {"n": "Unknown", "id": null}; + let match = {"n": "Unknown", "id": 'null'}; if (cid) { BotMon.live.data.platforms._list.find(platform => { @@ -1216,6 +1216,9 @@ BotMon.live = { matchesPlatform: function(visitor, ...platforms) { const pId = ( visitor._platform ? visitor._platform.id : ''); + + if (visitor._platform.id == null) console.log(visitor._platform); + return platforms.includes(pId); }, diff --git a/style.less b/style.less index 9e1cd61..4108677 100644 --- a/style.less +++ b/style.less @@ -49,8 +49,7 @@ &.bot_seznambot::before { background-position-y: -140px } &.bot_claude::before { background-position-y: -160px } - /* platform icons */ - + /* platform icons */ &.platform::before { background-image: url('img/platforms.png') } &.pf_win10::before { background-position-y: -20px } &.pf_winold::before, dd.platform_winold::before, @@ -59,18 +58,19 @@ &.pf_macosold::before { background-position-y: -80px } &.pf_ios::before { background-position-y: -100px } &.pf_android::before { background-position-y: -120px } + &.pf_androidold::before { background-position-y: -140px } &.pf_linux::before { background-position-y: -160px } &.pf_bsd::before { background-position-y: -180px } &.pf_chromium::before { background-position-y: -200px } &.pf_hmos::before { background-position-y: -220px } &.pf_tizen::before { background-position-y: -240px } + &.pf_fire::before { background-position-y: -260px } /* browser icons */ &.client::before { background-image: url('img/clients.png') } &.cl_firefox::before { background-position-y: -20px } &.cl_safari::before { background-position-y: -40px } &.cl_chrome::before { background-position-y: -60px } - &.cl_chromeold::before { background-position-y: -60px; opacity: 75%; filter: ~"saturate(25%)"; } &.cl_msedge::before { background-position-y: -80px } &.cl_msie::before { background-position-y: -100px } &.cl_opera::before { background-position-y: -120px } @@ -81,6 +81,9 @@ &.cl_vivaldi::before { background-position-y: -220px } &.cl_aol::before { background-position-y: -240px } &.cl_ya::before { background-position-y: -260px } + &.cl_silk::before { background-position-y: -280px } + &.cl_ffold::before { background-position-y: -300px } + &.cl_chromeold::before { background-position-y: -320px } /* Country flags */ /* Note: flag images and CSS adapted from: https://github.com/lafeber/world-flags-sprite/ */ From f40be0ac64886d480c33cd63aa2483508f26606e Mon Sep 17 00:00:00 2001 From: Sascha Leib Date: Sun, 14 Sep 2025 19:32:48 +0200 Subject: [PATCH 3/3] Multiple updates --- .gitignore | 1 + config/default-config.json | 32 +++++------ config/known-bots.json | 6 ++ config/known-clients.json | 4 ++ config/known-platforms.json | 4 +- config/user-config.json | 21 ++++--- img/clients.png | Bin 19544 -> 20706 bytes img/links.png | Bin 0 -> 2299 bytes script.js | 107 +++++++++++++++++++++++++----------- style.less | 63 +++++++++++++++------ tick.php | 6 ++ 11 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 img/links.png diff --git a/.gitignore b/.gitignore index d0f2f3e..cbf6a5e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ logs/*.log.txt logs/*.srv.txt logs/*.tck.txt +config/user-config.json php_errors.log diff --git a/config/default-config.json b/config/default-config.json index f220192..a3c1e72 100644 --- a/config/default-config.json +++ b/config/default-config.json @@ -23,11 +23,11 @@ }, {"func": "smallPageCount", "params": [1], "id": "onePage", "desc": "Visiter viewed only a single page", - "bot": 40 + "bot": 30 }, {"func": "noRecord", "params": ["log"], "id": "noClient", "desc": "No client-side JS log was recorded", - "bot": 50 + "bot": 40 }, {"func": "noRecord", "params": ["tck"], "id": "noTicks", "desc": "No client ticks were recorded", @@ -45,17 +45,13 @@ "id": "susClient", "desc": "Client identifier that is popular with bot networks", "bot": 10 }, - {"func": "combinationTest", "params": [["macos", "chrome"]], - "id": "unusualPC", "desc": "Unusual combination of platform and client", - "bot": 10 - }, - {"func": "combinationTest", "params": [["macos", "chromeold"],["macosold", "brave"],["winold", "edge"],["winold", "brave"]], + {"func": "combinationTest", "params": [["macos","chromeold"],["macos","msie"],["winold","edge"],["winold","brave"]], "id": "suspPC", "desc": "Suspicious combination of platform and client", "bot": 30 }, - {"func": "combinationTest", "params": [["macos", "msie"], ["win10", "safari"]], + {"func": "combinationTest", "params": [["macos","msie"],["win10","safari"],["macosold","brave"]], "id": "impPC", "desc": "Impossible combination of platform and client", - "bot": 80 + "bot": 70 }, {"func": "loadSpeed", "params": [3, 20], "id": "speedRun", "desc": "Average time between page loads is less than 20 seconds", @@ -65,31 +61,32 @@ "id": "noAcc", "desc": "No “Accept-Language” header", "bot": 40 }, + {"func": "clientAccepts", "params": ["zh"], + "id": "zhLang", "desc": "Client accepts Chinese language", + "bot": 60 + }, {"func": "matchesCountry", "params": ["BR", "CN", "RU", "US", "MX", "SG", "IN", "UY"], "id": "isFrom", "desc": "Location is in a known bot-spamming country.", "bot": 50 - }, - {"func": "matchesCountry", "params": ["ZZ"], - "id": "zzCtry", "desc": "Location could not be determined", - "bot": 20 } ], "ipRanges": [ - {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]", "g": "US"}, + {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, {"from": "24.240.0.0", "to": "24.247.255.255", "m": 13, "label": "Charter [US]"}, {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, + {"from": "47.200.0.0", "to": "47.203.255.255", "m": 14, "label": "Frontier Communications [US]"}, {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, {"from": "66.249.64.0", "to": "66.249.95.255", "m": 19, "label": "Google LLC [US]"}, {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, - {"from": "110.238.96.0", "to": "110.238.127.254", "label": "Huawei [SG]"}, + {"from": "110.238.80.0", "to": "110.238.127.254", "label": "Huawei [SG]"}, {"from": "111.119.192.0", "to": "111.119.255.254", "label": "Huawei [SG]"}, - {"from": "119.0.0.0", "to": "101.207.255.254", "label": "Unicom [CN]"}, + {"from": "119.0.0.0", "to": "119.207.255.254", "label": "Unicom [CN]"}, {"from": "121.91.168.", "to": "121.91.175.254", "label": "Huawei [HK]"}, {"from": "122.8.0.0", "to": "122.8.255.254", "label": "CN-ISP [CN]"}, {"from": "122.9.0.0", "to": "122.9.255.254", "label": "Huawei [CN]"}, @@ -109,8 +106,9 @@ {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, - {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, + {"from": "2001:4860::::::", "to": "2001:4860:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Google LLC [US]"}, {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "VNPT [VN]"}, + {"from": "2408:8210::::::", "to": "2408:8210:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "China Unicom [CN]"}, {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "m": "Amazon Cloud [US]"}, {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Charter [US]"}, {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "m": 24, "label": "Charter [US]"}, diff --git a/config/known-bots.json b/config/known-bots.json index ededd49..646823c 100644 --- a/config/known-bots.json +++ b/config/known-bots.json @@ -22,6 +22,12 @@ "rx": ["APIs-Google"], "url": "https://developers.google.com/search/docs/crawling-indexing/google-special-case-crawlers" }, + {"id": "googleother", + "n": "GoogleOther", "geo": "US", + "r": ["GoogleOther"], + "rx": ["\\sGoogleOther(\\-\\w+)?[\\)\\/]"], + "url": "https://developers.google.com/search/docs/crawling-indexing/google-common-crawlers#googleother" + }, {"id": "applebot", "n": "Applebot", "geo": "US", "r": ["Applebot"], diff --git a/config/known-clients.json b/config/known-clients.json index d650d9f..f5bca20 100644 --- a/config/known-clients.json +++ b/config/known-clients.json @@ -23,6 +23,10 @@ "id": "huawei", "rx": [ "\\sHuaweiBrowser\\/(\\d+\\.\\d+)[\\s\\.]", "\\/harmony360Browser\\/(\\d+\\.\\d+)[\\s\\.]"] }, + {"n": "Ecosia Browser", + "id": "ecosia", + "rx": [ "\\(Ecosia ios@(\\d+)\\." ] + }, {"n": "Silk", "id": "silk", "rx": [ "\\Silk\\/(\\d+)\\." ] diff --git a/config/known-platforms.json b/config/known-platforms.json index a4a9ed5..817432e 100644 --- a/config/known-platforms.json +++ b/config/known-platforms.json @@ -25,11 +25,11 @@ }, {"n": "Android", "id": "android", - "rx": [ " Android[\\s;\\/](\\d\\d)\\.;\\s" ] + "rx": [ "Android[\\s;\\/](\\d\\d)[\\.;\\s]" ] }, {"n": "Old MacOS", "id": "macosold", - "rx": [ "\\sMac OS X 10[\\._](\\d|1[0-3])[\\._;\\s\\)]", "\\sMac OS X (1[123])[\\._]" ] + "rx": [ "\\sMac OS X 10[\\._](\\d|1[0-3])[\\._;\\s\\)]", "\\sMac OS X (1[123])[\\.;_\\s]" ] }, {"n": "MacOS", "id": "macos", diff --git a/config/user-config.json b/config/user-config.json index 739dc64..3f87f02 100644 --- a/config/user-config.json +++ b/config/user-config.json @@ -9,7 +9,7 @@ "id": "oldClient", "desc": "Obsolete browser version", "bot": 40 }, - {"func": "matchesPlatform", "params": ["winold", "macosold"], + {"func": "matchesPlatform", "params": ["winold", "macosold", "androidold"], "id": "oldOS", "desc": "Obsolete platform version", "bot": 40 }, @@ -17,6 +17,10 @@ "id": "serverOS", "desc": "Server OS", "bot": 40 }, + {"func": "matchesPlatform", "params": ["null"], + "id": "noOS", "desc": "Unknown or missing OS information", + "bot": 40 + }, {"func": "smallPageCount", "params": [1], "id": "onePage", "desc": "Visiter viewed only a single page", "bot": 40 @@ -77,12 +81,13 @@ "ipRanges": [ {"from": "3.0.0.0", "to": "3.255.255.254", "label": "Amazon Data Services [US]"}, {"from": "8.127.0.0", "to": "8.223.255.254", "label": "Alibaba [CN]"}, - {"from": "24.240.0.0", "to": "24.243.255.254", "label": "Charter [US]"}, + {"from": "24.240.0.0", "to": "24.247.255.255", "m": 13, "label": "Charter [US]"}, {"from": "27.106.0.0", "to": "27.106.127.254", "label": "Huawei [US]"}, {"from": "34.0.0.0", "to": "34.191.255.254", "label": "Google LLC"}, {"from": "45.0.0.0", "to": "45.255.255.254", "label": "Various small ISPs, mostly BR"}, {"from": "46.250.160.0", "to": "46.250.191.254", "label": "Huawei [MX]"}, {"from": "49.0.200.0", "to": "49.0.255.254", "label": "Huawei [SG]"}, + {"from": "66.249.64.0", "to": "66.249.95.255", "m": 19, "label": "Google LLC [US]"}, {"from": "84.37.35.0", "to": "84.37.255.254", "label": "GTT.net [US]"}, {"from": "94.74.64.0", "to": "94.74.127.254", "label": "Huawei [HK]"}, {"from": "101.0.0.0", "to": "101.255.255.254", "label": "ChinaNet [CN]"}, @@ -106,12 +111,14 @@ {"from": "188.0.0.0", "to": "188.255.255.254", "label": "South-American ISPs (188.x)"}, {"from": "189.0.0.0", "to": "189.255.255.254", "label": "South-American ISPs (189.x)"}, {"from": "190.0.0.0", "to": "190.255.255.254", "label": "South-American ISPs (190.x)"}, - {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, + {"from": "192.124.170.0", "to": "192.124.182.254", "label": "Relcom [CZ]"}, {"from": "195.37.0.0", "to": "195.37.255.255", "label": "DFN [DE]"}, - {"from": "2001:4800::::::", "to": "2001:4fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Rackspace/Google [US]"}, - {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "mask": 30, "label": "VNPT [VN]"}, - {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "label": "Amazon Cloud [US]"}, - {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Inspire [BR]"}, + {"from": "2001:4860::::::", "to": "2001:4860:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Google LLC [US]"}, + {"from": "2001:0ee0::::::", "to": "2001:ee3:ffff:ffff:ffff:ffff:ffff:ffff", "m": 30, "label": "VNPT [VN]"}, + {"from": "2600:1f00::::::", "to": "2600:1fff:ffff:ffff:ffff:ffff:ffff:ffff", "m": "Amazon Cloud [US]"}, + {"from": "2603:6010::::::", "to": "2603:6010:ffff:ffff:ffff:ffff:ffff:ffff", "m": 32, "label": "Charter [US]"}, + {"from": "2603:8000::::::", "to": "2603:80ff:ffff:ffff:ffff:ffff:ffff:ffff", "m": 24, "label": "Charter [US]"}, + {"from": "2804:::::::", "to": "2804:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "m": 16, "label": "Inspire [BR]"}, {"from": "2a0a:4cc0::::::", "to": "2a0a:4cc0:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", "label": "Netcup [DE]"} ] } \ No newline at end of file diff --git a/img/clients.png b/img/clients.png index fd9d06bba32f300d41da7c5218228db878ccf44d..b087ff6eeec789e500771e1fad1b4935c57a20b5 100644 GIT binary patch delta 20611 zcmV)OK(@cwm;vIU0gx98um}bK006U3rO%NeC<-C~02U$v8y13(kyCaFUEKfx=mP)% zU6ImXe}f^@40*G|K>z?xkx4{BRCr#sy$66C#qm8{Gn+3*NvCwmStx=MK>-jTvdEYm zjSV=Fj196)HjaR8Ob!MNn2gCF0YVZ=APHri(&c=+dz)wGd#`7AZ};vb;OGDMq`Jvf z-PP6A)ji#_nj8c--E>nQYz_rYPtr6Hu_lAQf4ukJdz*Q(H}on1j9u8=nj|OB9RxAZ zZ$OZ9uc6Llpoai3pMcF%psDIaHd>O~(&RQ1UxF@zkgfKi4L!M40Q1YSSqn-re-rdu zdspGlpugC=3b%pYws++)(0cH=&_1-07LZK&Lm)S3KWIKub27Gvg9tz9LC^!qePTB5 ze>oA`qe0amFX&3c5K~FK3|bCKT_f!VjRO(1wogH+Yc%5`&^G3P7g<36fF6H{ ztpd*T9Ip|TxVA63uYl{7*f3GViMXCJS6=%EHdle(U?HWdKU0*6;^da-%@s5yf44+Q za+^Ym*YtEf`2PzOK!-&PO>R?YOKyp>P}}xeSW~RNmPJX z4g?E1Qy@VVo?-8*vZ}Xt6^;Q70o_IcCtxRCK>v?%0#!sW$Vx%5qGg&QD;U9T=K0KP ztZ13%$%7!z)jG_J7D5#fKG5wre>aVUeL6RS2{|s~{PD?i#QhoPmw?EFSb}rSshjQv zF(*8J9%?&;CxJ&n7AObwQ=UkI`#eX#^8`=enaS8Z2O^JEp!+~w4GwOgi(L<*H>7X6 z7%BJ&=jkcugXp4Jx%kXpP(J8g+;cqcVWCpc08j)p1?N@6lhvZ(Mm81?e}gE5VBxa? zqNNes@|l!Mc{~e5l@VlqC73^BA9fQ!By+;HfiAZ@*ktmV?lqU7TG(V}dSg+ILME0k zU)~G{$m~WzM}RW#q25!4m;$Zk*PzS5JkxzB^vFRbkQ>(E%&>(-WQHxP!T9@yE#C&K z{!riu58R6Y3ah#Q}X zt`{KnNS=lSYM)x$4o_KK5A+aVJvz*j-0cDD%PIYl@*^NbBmpuZ#O3gaX=S#_S;!J# z-Cg;b#Ee&yhhn`rHaohD8@Ed|0sD%BuuTcc^$xVw&3GkwR~FI&f6Qyfyd)*TQzT-Q zTh~u>Sbv$iLgK!(FolG1f`m|)La^W%g@BkF3*ICz=QMNWk;j@_Px@!_ZUrSEcGm2( zrJ~~u73mnU@selmlW5LNX>q9QU!Hm2smm8X{@Rvz&g$2?X{eZfFpVJx5m1ck!c7jR zXqNVp6_1~1ZeI8Ye?CVjD~ew{y~;VTaj4{=&iIh3d}P~$`V{qbeDK`u{&xS2K^~~u zsiV%JTrE8;gOB{LOg!sF93u@*1cnZVRhpO`Mypm}6=_DaK%4M+ryiVt>SRZLV5mfK zQxrFG8-(0w7{WRWk2>$ZK}AD$OCmQ{OpjMQnnOIgTXfAUf4e`NW8cf1hoGjoCYsY# zEFOn$#S9fB>$)@kfEGi_3|%Y;Fgr`d3iU%PTY#n`E^cp=9CP*+a`>Wa#K?r^T6h;pV0gl*2mFlodj2xfnhjfTG0ZEz+YaQAjxd1s! zrEJnZDIc*yfBZg=ggkEf>iw&vVfiSe7%KIl90E`ka|0o&mC(F+5CXI~;z$aJxWrMb zN#d)%Vm3klsv;TUZ!MSV{nO;FH-9hd>rPVw!pKD@=<}D*?u1cpP9&c>=%5F|HbDt4 zJG#~_%R%N8qD6FZHb=zz3b|=>$wLp`CU?B{pgg$pe{NaRK2_Si1{gcV?{P|0x1=Lf z2*xnm&Zt;gLW}_TIBCMjQP6h6dbFjaO$i`{&^>@4N7#}TpUss`^<`+r0*cxkL1}k} zq|F^dtCEng7!oz(Vgb+_uSXvQW@;BU2sv_~iNC?~e;=7%vQxCS4$)gWBpzs!XrNUhovkvX z=rtMZLZ_w;xwoQ7DH7a)iq`HB%?}kt;=iB(TCD8L`&n~Q|Ax~1VzhW}6p#}s(Lva^ zaK|QNlzgQPL8Rr8{(74ns%@A4j#@;lFwp{-O%4+01LbHEt?wr&|DgN+*BN!#0;=F9(HLvM2s9p2rpdL6N#08=d7s!cy3TB98fsqG{32+i0SirK_X^I)B?d|2_C~Cab z{lG_e@fIb3*q?v%lcuxfqM|+#$;)el{UXaAmJ^sz2<@B48g|H-#C?;ghi2n>lJNHt zS6Rzz-k1J+nqms11rYo5ez7;<=oswGe~C+3Sy)^!Nea@K6H1@}mKAg7z_|o;jbndv zftU%npz`3>+!g;GYjd-aC4i_#P7+$jg$ZX^%Y|+|-h_C)F>!lBuyF%qp^eeSFdP!- z@JYm+1n z;;`UaEGHa-*5vZU&nd3|$H&RXv(T%66sq%njgEEVWKDm@J zQPgXLb) ztAM(?I!|F?;jOI^{pMBsHP?2;e{G~4EhuPUWT_^j5c7>Hvt;IAEnehK+~fEA@2se( zV7Qru9s-c+DNdK`k+-(Wv?tf=;)7CLZc7p<16DeUpoOBoN+ODi7189vDV8i6ZLBpC zi7SvBb^+4J642Jxc2!%<`PchC)7-Uiw+WXe<%O1f)F?8wuO(IJG+E$2e+)HteS;?R z`&iQA*F}qIQkieb&kr|ZrC#$o-Xwbw=BzZ!ggo8`ubiBmTX?^=Z{NOw0mEH&-MemAf4_V$QZ2GHU?NO0 z#e@*5hAAgwr6Poidejh4XFzUQ_lEpn%Tjr)c%=Ms`n58*qFCH9uhgRnec-rQJXebh z(_!C-t*RDR9@>rV?V5as0yV*ijFoEmFPRI|jKR-$%H)0P<}*B-bogXKg(W&u$>tOrrdSb`9gB$5-ypwU z{(^k`$)i%#QY#w~r`|pD0*RLNg`Ux>IdwS%*2af-pf_il=2RWEacUJT0q#pyRO2tN z^A_4YQZAMWGmOcQK%IR4<^yum&M&1t6qX&Go$~mkqh;5Ke~F@b&=?>#Whs4DL%Y#r zCjtQ_Af7O%@_?aCzg(NU`pf%Zo|1q!4g2M(*@LD2^fP6DI4o76PFc}^w7fCxB(%ka zaOW;%y3FW6$kOrbt~Rv133D2AfM6+sz!okH{4@hLuACS`&THcghCc)di52ca>7AJL&+2EBNW+q!l;2g3>>$uib5 z2kVC9B_Pp|BZgSw;*IbzI^vsQT1f7kS}MDC?UI_he|mWj5yQ`#`^x@4W1)8+8Xu?4 zoC!iy=tA!247Sj9h|1vn80v|!jsn&X&Wob+5|ec`5i!CBB0CsGI4TcL&y||pyJS;! zgZys4SDuIt7Bjye+;uK$vXsN}}-qD$j@# zQ)Um0et1Fc&5B^tq}_6$OZK2Y3= zB5{R%;_|yd2$F*t)Tzsuk_4VjNLx4|5n^jWA?Dfg!8+cgm%s+hgE$C3%uJt5X_ZeDTFqZBfTxAKzZ!Zbg*lf{pjdbIP*4 z@F)E=+1G(6+KS8Y5{Im*vE-;B38@dF(!lNu9Ray?WP7Z{Yh62Q)~s|_HcJ4peEISz zrfEI0w9Y&2ow`!V_qxOjA7h~6!D+z8e;Ky0B3TkeFDQT>&hhTQi3is8%hrf?%cgd(t2*S7{pdIB4Z30bB7<^cG8kRnfjLo`P!x$H)pt9c z&bwyMp8f5OekMNq?6ZL|wL=lAOu^yQglSFV_y_tkYZ1yYbXkw>>LZUl^81A?ee39nR?$Vr& z3p8ENLt}xE9=9U(Y6J(cpnoujH#b{Q@(){a`7NG2`^a*mBgxuxc&Ce>kPjtM8=-+ZB>e*{DB${&{%fLogV~)FO4NO|Z~d zs1&pBj24MoGs#@_r+JTM^|wsx)A|z@oRegykj_Eff+Oc@PW?TE&~9w)6jLQiJ>18C zxMpq@W7XNlJ`!QE8RV8jI~12Nj_mjDCwwJi=V0N>3yatFHSWW0Y(4Cof0;5eN zGYb$Qs2WAm^+5c@({}n!e>!DcN5UE9sXS-MV>bMDn>+OU7}Q=n*8nw0Z8~5Zx^9Iu z%h6Xm?v;g?JH7fNO2-Ma{x^T>D9E>*Ir->0TACJ!|K{GB2dv#zgaa z)DU-cV!`^3lE4KePA5u=#RDGQaDijQIU_ICU79^kt!sJp`Lc4tf0kIKfp8^$^5U(_ zi$@Q50A5u!kmcGccos&DQuqTJ+vXm ztPjVHkmr=s$2`BL&K*Sa83;$DBN&oEXGnsGi$Z9%o?cb!jThd`SBnQiC9PA0G z)%*CFxwWRpyKhfRe<;$?8I~ZJ2e9>nu_B&BRM!#+NnOAjO_CgxQq4AbgF>dCAFDQ6D+!LS69f_NUPgW>2|UDphB=qR*xPf05f4 zi$#%QswS)iqy+KULSdKZipS-Mso}F;uo{&@*3&Y&!}923e?DyaaLq-t2SrqhsUk&5 z0Z9GTb1TF7;k)^U#A!d34a?NmK!CO0M60J9SU0@W_WFn^qpbF87YvWY<91Fupdte? z)Q!iD438Pq*j#MAI6irM514V+8g0Qd#}qic`fjI3D}lKtFJ+-=Zo#oTk1soZYC}gX z;y`W6%Sm|Oe{6Vt?djgXnd5T(sdxTaFk+q#Gv-E14jld5v6nhL+GB8Yi1B+jXdvL$ z-1`j6@I}MXp(EY?oqrmx+)R1eiXiNT%40=g`NCxLdntK zpaaZ*GV=V|C)H6m^eP||NBn)kArP_`{Z-}wcf7CDC2PjkhHJ zB>KrnF&KlPO=#e?xV;4_0TPC%^NZWrfo^?J99raE+&%>n&NZ@p^{d`+~W#h+o=S2Tu~H!Tw46zPxNSK=&1U&J30e?`0A3u zqL&U9$te@@7NS)vfYORZFRBo|9M_5mN-XG+_ElBL1DZ@ThCtL%WTD;V7zKPGTnB1P z0{v*+7^T;)+&#ae!BOHYL#llFf4G4+f#^*cYhq(0%t)d$dWTk2F-$=5NYQ=az0J55 zRYEwJf?f#%0Ms62I1T|Z4l!tEvF5vF+53{)?-=DZVHV0V@Q2>ifyT#ZZ!(RID<2E~ z=O<|wObmVMl@AJrM~-$;EzS^BLe)f2A7U`sgeq{uG{SnqT|UW*kTkH%>&mMtVYR+30i}0;8ys;P z#QV_jcsTtb3!3;Z<2y6vf5KEk!eAZ(V+e!QMHAtTrWt-nM@n}qrVv7yXmgdS8uz0f zpe{I7D8Eo$%m4!KGnoTjAVes@j{@#QE;^BN|GHQ#c*Mt(pKWJNepBTjnG2J>7;Lo| zB1#BgT>#F=Kl8C4a3=*#I*!xDe;abJ7Q)(f&0lMp{%7Oy;6(`|e=+y-LtpAp_i49$ zQvx0hupH%Zlog>haqRk1oB^cHlW*$`)eL{;241?1Q%t@ybnEW%t;oTHs_UZ|aRU{3 z@~AhE>e#_um|o4YJ}p@M@E;0K`+MdLwjL-t_Kx)27v+oO=1m@?d?ixOIYP(<>Vdyr z+*Rw;uq8@a-KNnme<6IZG`$r9pNI5KNX<7m*NFXbNYF$iVu~3H9cIOXll{x?ZL$Rr zH*XpXzU)NjP(>8t-o9KM@wjL%SQ6tB>d&q)5T?|o!U?snj&Us!51NU{G5!y3TS>O6 z1QqU?um$)05JZ2h)D-VG0`)(Nhd3gIa}c0`p}J0CDdzSWf83+TtwiLU6mz0W0CCTR zr}6hNl!+SiG4uQA(ZPqHV;!bLVmXM#cm+_5VI4{kbERqftZ4A;jt_3jn(@}9qDYDy2bggn)ob9Cf{4%~9E=L%D%K-1{Z;*oo;Sm&SpA1*;kveCPM6mH&B z1OccPnDByDD;qT6#%B3 z&3q^5NDwEf_6EkKS0Kg80tr0FnQRE~4*=Z2?EVgPe+8(AyY2-DBjv{svWy3Kp04Mf zY%@&)7dcatdb}F+U6>Qh=~6sjFfB(QkOrZkq=j>!o^EqFg$i^4AcTRT!oPzi+h=S5Hn1QQtbNU5nCh!b-uuqms zOeRL91>i>bWo3$pw&Yo!OJWn4XLVP*1J5#=-fSOb;oj~!UX`pf6VEBIZu>RnY)86Oxkk3C)!g2F2&|C z?)QR+QOK;(|0n2R&WfQHBOCyna{GUV1_2xuc^!nvK+PWSZ7S|X$OW6zUI89=V8bN_ znP6jm5mTRvJKq4QNk_flK``O+iypvv)?}{NnbVE@NK_Sb@D2`+11-Xd|Kga92Ax%J zfA}0kN61$yvq1|$^t|1{)K3AwuPJ~_Vpy@taUzOij-!47q8I(Y;@99swJFbs;8V7f zIZt5A$*D{o+t&XJ(##18;Odk^ka9KNPb7uR1f>J0?*J|zV2hS!PEY{X4lp`c0wHW{ zSa7Ux*MsQqxl}3Zy-YW7_CA>o1#_-Mf64;OfR*hY(Agl)SmczEouE(ffNEa}+{Zz5 zHbm&>s;TRo+s+1P2kuMGD(i_XXV)FpfQej&!Fs_7-JJeUVq?zGk_qAVQ>|uWEw;U) zR{>y5mC?4jgo*oUptGH5h=q2v#={*6#EoSxpRd5_c_H8F{tE>482RcU0LNqi=@z$*t+t9UtU7+;^N14zRAIktG1kxwtB|WGoHCGV7KF z>i*t@o+B6rz>pR5WYnf~lgOHt+`sCaaJc8|-ek&YEm_Q=lCRLCIJK~TD;G7S@oHhA z2g!dCyK01239xfS_kQN-e!rShf2{<7ISY>S*R#|D(D_Y-Zc__Nvha3kDMz}W19Nm~ zlTiHys~ru4pc998M!Z-HrcLP$tL**iw10~Gu z9(tf0?1KJ#y#6{EP^deY>Qq51bvc~_C?H)b{|k_6E1mKrL7*B+QL~G?VK}Ud9`ic` z%ts*?iZKNxg{iqMy$N8if98O%uX+QRk4!OEstVxO7d8wDfw)ak#4u9}uD%tq zg$oBj=Y3MDf$md6-hu#QC4|Jl5JGIiv2+?n)+pn_0Gt20)8XJYO*l5OeMK*A+FFOy z-x)HyQqSCgX6`E)$yV;5uof+1^uZ;P-SMRM_S+3C12VfilrT1ge<38vJSFU&ZH2>B zJKY<=oKBMNool2r!QnJ}t|R{t>+>pE;TT1vyRAw0`?cHSK6QM{j?^Mg1u$plFzv20 zz)1W|q`qtPJ%ulF23-b!^&t3q)o4xfJOtH^ojmmKg~fU7{VjdKMkCYEBvDe7x1+Ei$M10HMn^}duQMF`7nnbAveEGEjeaIxkTOPl zvytK>Q5HubSBF7pJC47?@mDxz*z(!gRx?Kgdc{EnSPP3!e-*#?717b(cD1X!oLXGlE%HVL_=iQy~}1N9#DL8X`_9%BHGM>z7xc_z#Sg~cLqgdeSvNI;17 zTWyb8fT)lbe_)*{M`80{P>vc#iuOkz5f5{pDdh|)4~}(EYde_Y9EGS{KzKCWd~lTI zcnD!fr3(;H1F{sIrCHV&FIrYCVp*%+v#i%1wya))0& z6weI7vo`fCbTEE2E#QgklbpT>euHPa1U!;to28HwnvKMWC z0qWIk_`S)jz`&>PqF3>6sH#b147~bP=mqn=+tFi1>ewTbrBG4o0|JV9KainP|M~OD zBqg!!3(NZbX_j^6kmLzqPNijCg>!3hEfa6xSvv;?NWIZh-W1@%T6@H>uG@P5QHZ^+ zc|v4Ze@6Q=4*T~%DKfQNTvnA{waN~O`ksOkpuMC@eg*gCHFS2iWE+5d_Ahi+Q%mxJ zQP_VC=Q8mnp7{q?AuFtaiqtT3DhC9Y3B&ww{+^SNnv8n$*|Q@3GS;XM!v3r21-v2~ z5tLtsXCmpLYnvC4S;*|Vs;O%V`DmzE*!iW1f09;XpDT-t?Ot3BI+VYE8hz74(YI_t zcYF-CS<7Q*BL_+&nK@wiPG4^$hz_QjRRatMqdVb+S;<&)U%)<@6LcLNS%Z({ffU(D z3qU!LTbJ^S`l0`CzuHysp}+1xBj!Q4l*_(*66LtBEaN_rWk`K8W!X6(K1^=mChE~a ze@*to8>)~4==keTkhYISu0Uh9k8fmw^|+^*!>eg@@c`0gK%gAhjp~Z3eFY*Tpo)EH zDUU(hGygK&g!9ioCh|1e`Z2iuYiJ{=EHZ_O$N|T(6}k)HF^A{7@|;sB@&NkfEc8sU zP>&h`jjQ)@Db#~`*62%?ick(rU-lx}e-IeZY+Ew?S3NpJm!8<2IniSQZdMM69_E@t z0eV_LM16=N4L`d8<-!579+-n1a40B^9s&pmxg8sRHJ}TuLlNB0F_m@*VHYJEw}W}+ zH(nIFTaf}(#nE++_I8_v%!UO-MRtMr{IoabM6WqW0Xbm^&%wZ{iVcm0YUjife_IIs z$%SCv+qkttuQ^BoIblDIFN2t)gh~#Y2?Uq)mQ>-)gE9YJuuhao);xLBngkl7#*Mxc z4yvMEXHH`$z3W2&x^DMKO_O69DOx@JrM1196w#{yFlNX6myV*cU->2;=JX67E1sdF zMRVD2Tda6gqPw?Abk`OMZ~QW0f3!DqNbN2NqUy5HLjahw>3TAM!KqUUjy_$2pT7%6 zn`4x_m^1qc| zd8;#CyI0yjd=-ACLk!kf24B5Eb9wGv$Lzo$b@&yWGTJm2C2XICloR@l@ryQ zN$ULVzSrM1pzVdfNn|U6W_0S}J2pxfdUh6^B+#- zbvSqU>0r|HV_4)tUcQNkqVcvr&NH2MPE*W;>Gn!do>%5g8`@nHGI#1w@p#ayhdO#g zv}%iZhN+2aNdc%twDU~Fn(EP8*X8w3x604|oSuBCuyJRDJn-Tw@lO)x5ovi*Ee^Q&OL@AgkFaw>BMRP{UAtMkuWMJx;3Yj{>C2ddtK}wI_FTP5@ zxXU6Et;>~~XGSYt@AyWJ7XcR)WbKttVHRx!l>Ys&bTR;|C(PTD1BH=xze>A;QDRuuIDSQ4pNg7@q zE`d#@sO&a#@*+?2W)9ZSanZMAp%#`B={BlXaE!zQ{ly7=TXC*QK+rMFFL~oy#W$oY zbaA6hqgCq5Hc0`ft#n*jK;J7?uR0T5a1W9C*Jn%f2ZJSdRJ#<-u9cE`)oS13M+B0f z1<{fKC15pOe=fZu9akn|JJaz~8ZOr2z4_Ac`Y`BxjO>4Sf;7A~Od{3xpp1sllDxtj zSJR}{=xi+L&*^gM6*FP&*@muhwu{eHr9Y2#DI4VB|KL9Yp1&jSRKD(_Kc~y3S4^YE zF6fqUlRUoZ0ol>EMMBdiOKYJ^zC5H*9zAQ2v=ns>e;RwoP7znXK@#}*b&dntW7qsc z^l;b8qdKMd!M71hR?A=3-^rnV^#Gk>3TM7kFT?hS6!S8;>$-ccr@Nkl)GPg_ONRcN zjRpOA(Ww_p=|w*i4K6#@P%Ra?wm0=Syi(xqBjdFpGHZRil()vDB&?}>i%z~U#heXJ z@4+v@f1F_RRQ~)^rqC;PG&M?}nR8|7{`X{N|0Big@F_Rl^vGSJdwh1237sd^axoLC z7$wm|0Fi8fZlTNd9dej6Z_YyKcA(wptI-xiV*7Rp8Wv?OEKuBkH<*8Wqn`=-b8PI8 zh17f4vIdO5U)XZ>;Z4PwXne;%(Gsfyh02(}e;>ldet05*hw4$_b-1S<*Xwb9CGL6s z@1K`tdrTlpz?HL`@?jvHa&i$Ka;vLs3zB!)?LyaE4)pDD3H$baew_ZZY02;Y`9*oU zkCuE?6*J!;D#b|8V4xUhoF|{mb7>*i=QSMj9q7@It?FxgD8sOR1scUEwb2E%J%5p@BA7DWA$1GR%-K10 zuBUYPME8h9+=_2m8{PT(zC_Nx5&8%te@D|y9SMS4(%+7X>-m^^4&}5Rg2rk;m{NNZ zgi`kkiaGbOtsLY0{FZ-~PR`BO)8p5TVN0Ic6_@RuhWhvhSHv4!7s6z|gBI}l2$`!~ z1JiWVu!bv@aK=gFgZU8ZGo@QKTUN}PTOKaWdU>>=-js*e#3h1O)Pb5Xua84+ z9Pg2FMNaLuCrS%tO)O#7CztXekxV~$4%PXG%$0_4mO@UvByYDbPfs_}tM;1muXTnR z8*!phKX;^4&Oubcfk0OOe;eZ~QVCUwH8@St8pcV*Lnu{Uz)5bW&-JF`l+87k zyt$q#;Zi+Kel*1;a|ZOBxHe^u*NI0}4k#!o%+3KXq)sAtk)h+lt%cda6sM2W5GEd+IkD=)kTQKzmmq78j%^jQ#gin5N0X4-JDki1 zA=O78`t8iOt&i;3x;`?4e@v6Q2QTup>>PBZUZl_1JaM||(nO9x^TP4(gCP#x-+XQz zQ|}_5ln^enByXDOj?@L#;);oO#f^mwx%remtDEZ*2b>MdvN~hJ?wz5aIV$yhikC{T zW$o0C?!SZW?{3fl`lH#G50b+EXnS!(XKP#gN9X#ce;(WUllXm8(i?@0tz?G{QULJei~% zVkT0&Q>it!Uike`PS{keYpSFG9Wp-o>-$Eo&OXv9Yem?$hQmFaGT^S1h+aG)L?HHRGNFCcbB#ys=Xr26IMnb}4ng z3qme|05`5Z%&r)(JH$UJPp9kEp%Gdb8oa#t1=G7FX!0U*i??#h!;}m`%OytR3a2sf= z;V0Gg;RSN>l|${Es7G&EYYn`64=jNxXSXZGoLeIKpaSe`D&oMW&?%je?4N&tsOkz7 zvj$2;#S;25V^q41M$DWm&A9slC=@4g9oPHvMr2Y=cZQ1@Hmn=+ttN8PInWsr#Zu z7Yar7U^OOM1GS2CzP1hgYBq#b@Qdq+2l)Q4B94mm}Ct4Zc=N5#I1-?ydy*$F}_=9Y@wSt-&I zMHyAWz}Saj0?0UnQ6EN6scC1a^9tCB$`M@BG2tb&ztrpB#*6%G0zwd^d?{4$0?wms zY@sQ}nSekIG@jQok-E<*hw8(;GM*#r-!zC^e+qS+H%8<|u75z-vW9Q3vQh=4j!9rn zZRJuWy&+~5aNVZ5k#l`gtGA1JkkV@=G6f~U9FVe*ajfr*$YvJSAei7Q`$Rt6i+~Gu zy<{*d3=5t~Og+GD=6({Lse8I#_h>O41yywdoNy5e>MV4nk6DR&@r}qHsOW0g`9&;z zf9g18ilh`nZ5IGS}?N-?Qv`j(B zL5N!>EX6qWye`J%9C=kgqe9!=9F(WBe=eqoz{Ag>Y;M^p(tucXG1|3KnF|V|y0~@9YhRtHf30#j$cxUmQ`*$U?nJ>vP~=fGFu#QVZ$ZxfFcNJCD&u%K zyw^EC%bc+@3_85R>bzlyroJehHoQ@9nrER#|6846p;9!jk}~a_0wMVC@TONEe}Y{c zKL;1GuG4ncRDDIRT>jIMnwqSi7NGDi^HO9F7m`9UnP=Wf^&!H10V?_&xq5Ifxbi-j z``kjgZ|U*+P3k@%TL3WUE%Soqet8JqGGBG;c}I#;Kn~7^W#z%NALGyyYns!FPR^Gb zzB<*B^_9fT%quKEQGe#Dfik^ce*yftX2p~a_(igKa!ZSWgF~w&uP|UiM;LD4<#Q|a z8Qqx^J#vtVi^1|AP@4g=h-FI!q*?YGIvgyBCf*^7w5ETqWAAF zRyZtHFer)Dt0ngCyJBorgW$b^t@d~d_!)N6Uw2MH@7GU!KlzEcj^yg41A~G>zx}P4 ztlmBGGpeX-nobgq5hEo3f9a>cl{w)&^iauv>M3zf;Ci#|f2oteWtWMuWs6Es z!5eQNE1CqazFHC+(sMtmvU1=#E&XxZG|Z+Zi9Ffs*E(P)G!($YA!obJvP?3-F93H5 za17^nUTk z`d52D14dPqvN-oie~dM+OF!74H>$ZBsFD}+Z}F7f^N$H}u@Ft%m=zCyNuf9R{(AF3x3*&}TEHpCO#tnJkyi3A5oU6Z}Ae`w^;LK!`z^jn`l=nV<;6RW1F zS%Tpavai%kQ)IM6V~wI2d|QIy$FGBs^bAOLE2S zaEQ~TtC`URKUCk=9+92<_R2TgW3piOpk8y-;{=%}jGxKd>u;4ZeVhaWUX{{7XGHRI z?S(C6f8~D3apy@{SyYO121`kSR~~<5hYYSLkQ3((%i@`JkYfJKJ6A}3jXiN@Ut`xq zRoBo4nNnnbTq$RCm(Mx8Xuk9lf0ce^e|_b}cdF&A;|HeIm8u8Q8L^`YGAH9* z&D&(lhE{263dpWnd%o|G(c5L%&@Utqogl-)(`CE_WSVYU-DbrZqV*EvVar4==DGJV64jDU~Z`k1rw%Kc;DXgBqej+OsV_OKztE*ksHN9s*MKujS zX}i~LuSjEiPL5D#F4ViI#XJPU940}_~TvE*wa>&e*#lq zGFnCUL(Xe}JJ`yl6yeWD7Y zaKL0fvO-jfxgFn6lSU*kmHJF1e=4S@pQmpkl!`2Ef>iH|NvU^_ESP7T?ANvKG;^kQ z2Rq$K)Q2r4q$N3NxwP0JWy85-#}?9OWR7x>gc4AccTd`7oHlx$IP2D^Y!hVsS(U0Y ziXr#8rI1!MGfYJ4USiVF{c`QBgp?I{vt7l|i8o43ttkWZK9>itzFX;ZfA5N9{GWkP za;6o9a6fg-`&rnhja(^5A7+;wkrv?1`GxofoShc(k5d+lYuh>{B*lbaikWf}Vbf3>CR8VT3@TM0?w^SUc!OOR`UY(xhPm-z#qlw|OyyZhL8SpR&T<1*G8be}R z2Jsb8YTh;HS=bYp?1@X9md@>J=d%4-ODHnYs{k;j!c)H+%dw<`fu_XI58VktJt|HQ z0bovF%Qr|F6Yjnff4F?_LI}y~;&j;|0OtHw5wrb$nG<|wZIVYC=^P|ePUf~d>F=kda-swzb9ar!hdE?yw!D~~7dI4Eu}fYHgmqn zpsvBH?}3BNf4c_E*HEF`5o_ibisPYIL>reqbn{(60lltiRoJ^zjGvrkFOMuJ7X7a; zi?&$(n(=pqJuTYaKLB9&=5xtq1FXs4UI#L<_S*%Z*P>r!hw9cRZ;7>x%V)nc?0MIq zuD~V}nkM?s?@?vIvM~R`4*Yip{l^+T*;vq@_kgx=f3aw@_yr*p_#aW(S>WFtY#;1( z`aA&9pLe0GpXk@BS7Bm({H9o+elOL~*{MWlx@*o>rbXHAnza~~qd*tYwW!m+mWv3C zXhLlHZSFb+2w`KvF9#gBO*lBn{6}EkbD>WP$(*ps?Cmov2ZLIwluCIDsWM0-c|+G4 zv~LIRf8o7sV6vDKJ#vtVWLrT`M>O}nkw=Z}09xDGk|E(rWphQ*$A zv`3#3EA$8i)NM_2I|z(~6|Y)X)%K^J9}VkaMecr={=p0zg$ZOh2JIRxSwDc@JD^AB z&?!R;e%Q%hK+i&!fJ7*;1fK0wGLNH+6h~kk{qg}6NP1S=L7{tcPEI5eS$-`oAZA%p zf6*(y)oA=i5@5`4rY0f|301u*i4W0*3TJfG4gy_w+#HR?(qEKI3qag*BeLo=5Q`aP zt^^no>U2tY#!Q1}Z0U zO-yXtn+)mjqq&4rNPKvKL?1g_5}Q5)x76ed27e|KiZC@nAwFHx)DJHx0g#v;fANl+ zA&x_?7sH7`py$G7(pVrkV2PeNSE4b)M7YfBv1*8uewb_4__w1?HeR+ za*i)QzF`w?Qft1`g`5djd4K79-4o&(a;jMEA<^L;TuyXbTXbn_)rG&2X~mroQYeY) z*F~PWO0>rP$O$Lb^Vj#1LV%Qte|oG!@$|2hK{q`n1t;DiT6jVDJlMsrL_pq0>=3{cst6f5&su=lbW6 z3!lU~+R;QqMFxaGkTL|Ap|$Q~Bp{ALwnDLJOntOX2`DNm+FMgo^ES=wKyc<2NWYWL zmBIIJ6wlZnNVK^LCXD)_R0WlxJ789C5{ru$b?yDWefy}_is?eGsjdC}jvYG^4Gj$v ziA0pCrNGL=Y-dDqaa2=7II@27K=IWeAE?Ge=3@-R?d}-Z}|pQ zauP@ySptaSduCqk*}ZLtg<5H%fE7d5OfpaAMAcLSgy_%afV&*Ie&fq0e_Fubea%1* z0hO;xQ{ic6pOClg%{9*2z0fTx4%Eb7o}iNWeQOg9jA`P`=5>lUG|i#*3kH9zzNVOk z12+1wSzr6v!>)}_e?H?XqjJnJi#`0DTvaBHPQN%dtrq>WyCasf@4KQoZXfvKo?h$H z0R^OhDxPZ;$xL$wy1Rvg2WrTV)m+np7-FkAuzb~^|1^DjBk^4^dfu7&Q%?Wk_ljE& znuBpipL>WAkNp68;TJ>8aJLI)4Bw?Q$mNIkH@iH(CpWzHfA|4EXOI@K>EoAXOqhSB z`tHz>DaRB$b93*p67fk6w@2B1PEoPsmX=Eb<{M-`4UNsPetB}-S~6_Lq7zKZeA|rM%+EUUNcs6Cr=T2lapmTUx2QhQA*_i=U!Oy+oKq_K zMlBqcDS9NwDym=OKCXqEOq%_w9W$I9iR|#_Y_@fI>ar<&4uTLML zDp&0D%ftNfnt!-MV!;kiXJftkG?4!3lXngXckCLiA_SzatK99a8ETfpc7G@n>Q+jj zj)o)}LCh3JNE4A*C?sx_MPbDN$t~+6ad)nCy80SJn6i6Og zN)7!(y2W^;bGGByF~hHM=y2$0qjeWzpA1*!&dZmQzI|nrK3E?6@N3(PvR#0ghFV(? zoJA0rAs4<}3AeY3&y2~W3dEg0s!Bt=d_g2;GAMaD%3Os3b5*^ts1PyqW%FUS|ZJbrZ1+J7s>uQ zziixGC+}2y(vP>)zbrR+=CTSP5{!R()QV8sJ;H8qwLbKY(zB%CqZ% z8vze*mXzAK)qRF{$?p1KUyN~ZE781 zhm@-pP8IE&zrXM7uik&nLGi%ij(-_b zAY;&N=4i9#(j=#{MDoh|OY4SRs4JG0H~R2}hb=t4>*M}U|Kf(ncP(Ew&Rfh^j9#`Z zQlwTdFh?Njj{iZ7F2GWX$_oV1y|~JpXe$cQSI{L=-!87oDbF5t<`oZ;Z&LFjFMqb| zjqU3;oZ42kKPMWDp|g=d{|uo?9DmVr%#b*UKfD&~h)JNuKyZs5jTuJ>kD$?m{6c7~ z0bygGF;(-=yQcSP(XamfAMS=NTb`*~wX%}S@9fkjFJ^!YbK!jp`sPY*d5#np7l_M5 zXVFnsd)-s37Vr7`{q$2=0#bN($#1UOzv7FFLv3xnUMKR(e3B0<%P-1-nSbV5?*1bm zIpz9Wdko7TkilF3c-XgX+s<3uf%ZA=+qdO*|8|8FW?ay(%=8Q#ylM2I)2?4|!DSg^ zZe2K_fJ`iX;<3U`e{lNV-TP)nT3hl9a(zofEiKEgd-26ynP%dk0^WV`#e&wx#!EYc z!P$Y1j`7iOco2L)tl72I>woiol9!+Vd3pc-Uz~E`h2L*LYSlaM=55`&<&K7$nu}xM za1Ls$j=mSmoC~H=_!`1fR99U`3}7V6`}KQz?9{2hId<`4&XUSP4*~N}IcBj0V{?z2 zH0{cYfdk#UHf|(C)h}R+#|PA}%D_P;`@=krL45nTDN`;#_eVeCynnqkvILy>qw{Zx zMPiGKt^ARb2Mj3aXl~|bKT#Lr;z2`ST2UcTjdc3`(pXbt3xO~Lxl&72Ap|+O=?B+d z+w*(ZKmYA7&PF%&pM6TobIm})VKp>Lw6#_8^YdlOQAeqc2z&AgkkjduatPbLW{uSD zMTid}2?*dzR?X>bnSU{N?#z=exIhKPswQ9j(@Tcwn*Qvt%3*znRSwnnS69o#35Q6c zqeI5enk8%2ua`BOH_NX2CaJ2amF-o#qz*YaWXcq@ZczzCxT=+akx1mUx3`b34y}B# zr9sdS1?C+$|6%BPHh(H8!mtDpK%O^W3XuBGkjibf4Pq7dlYjC-L&Z~2BGs)O($Ll> zZOx5RIe4&`5W+S(g;*?BSvh!8>B_ZVz2lg5%IvbCgNObj%#JULj4q;}pg>xhp`LiE~`t~V@YbcYZKuGr2)<`52l$|@Oq#X?p`*j9-KCm>0)9V~j zS=r}bj(Nwx=4x#6n~WI7W9moWpq&e?X0P z&3#&n7x89uOEcUvbluh}b&XBZ*xWA7(0_env-lBV2Rr-{hW_2S*Xb~%FyASC;RO5j z@yPszlPdD^eT8hc+|a*JMf?a%49xjUs|f?43*2y^qggsy8f7bTvtjdA*|=q!+V>;6 z^S3oiG=Cfw52EaFD4_b%G$uFNh=Bw87L}9~<~W8;7=EL}>Bwj5Y2OY9e_#;N0a8^t zs8UvZz5>ClB|$_G^-YaZUtcS&h`c)*YhXn!a^Vk7lRjwK8WG~CJ~V`|$>mRdS(X`e z3>!cEN{`!97DcLA2JEKNk~+hkGGf>WDJ?0Lt$&-hNC>fK$losQ%}r8`dJqnF%2|s~ zl%p3MF8lUwmRJ<=5d;_pI`CXtgEl=DPkiGTF>%CXx63^>(8=FALqW3uQ63x+2_V%Y zM~;yG6@4X&`oW(}K4jc*nLBruEL=EWCLJ;gHM=6+bv-!K2+ulS=G3h4$X1r+*Xm&^4K%(P@@ z)m~SL?vU}LOD$v_7EFf99l;3Dy<(+AJPR{VAZBlZ75?h7tA3dk8}$%C{Ngt^jKM>{ zgB};{udYSF8Sx)>$jFksTrcth?vSDBE;Pj&v}8n}ruR_LKfm&tU-x)j(toRf6mI<8 zO%vj=_)V~og{^HJv3$3~-LE7+IJkcWUtrdvQhg0~@Xt%Hyyg3SzbK6*UanW@a zfV2kNx+u^p{!YJ49X?t5dj^Vds+0u|b)R0z3fs z$HI-I`y}Lf3I)tphkzXw!6xzl^VZL$4eDSM${>KaecZ3*?|-u%l;6*}M~0OTRViiD z7=zm`$jO&V&mh~3yD*Qln9}di_?n=|1|l2Ie+fCGG)YM8Bp3^1pq4jxbw}g z-;yVmJ|#8HHGeAlP^ZyO>}}X5zkc^OD)mmaAU}qs_%2^}%F&X~$E&y?$q`;p2)dypf`b_7C0_|<}&<*0(A&`&^nlK~3o`Zf-d%D}5TR1TobAOH8K za>i5V%J4_V$wwPL7DsZcDCdE;NBNrAp=dn?H~_<7SB)1OZ^gp$z+r!uGiNWBe3%|nMO7%11Vg5p z$Ej2k&3_1xAN}|Vxnt{HqPx@1PgOKKk4wD#=|ldqA%JWmayY&GG&yO^A{o|asN`^T zH@86gmGpyG2uV##tzynpZ?4%Q&u@KERs>dv1I!T{+HCj(5KAKGrUYa;JCzgl-W>;2 zD?bLX=xI4^)~T|;sai%oHqLG%2y$TCknOg+Ie$C5C9)@S0jg>_V9)fDUJxq%pwdCg z_R9)O<=k>)mb&IO-lKannGm{$y_HLNzdP0)DkkMXts2QLQ>aKCtK^c z$@<_|U~Ct9H?YA;e+@U=9tpeQVc3^;-%k8X#DliV_yls~fJ!p-O;9aA0rRYdv^{Ip z(ow|M$O%{S@Rd1Noj6qXX`(I==i0INq6$ZW*76eQ2VkE5=6(u2bC8Lyu!SC%PBAlV iVFhI!I!M?e^8W$X_&B)OrpWaG0000{003C9B9xIKC<-G002U(w$x&cykyCaFXWak*=mP)% zXOYrhe=lSWpc+8OfdBwY2T4RhRCr#seFcDA)%EvzGPX189@))q+?^;8g8&H{oZ?zq zpe@Bp3zXt@q%FlE#fwv%7$FHUNJ2atTlaB$^8LXiKDpi8LMGfG&lQ?bfaZIgtv0`Bg~PgObeO2i{ed=3{*S<$M75e23%$5c6Pl-3lTJ zlGqfvcx*XA&<;=%LqHx7=WHh*NJH`*f0uX{A4p&*$PHra>dOKaVB-VO{|}s^%$zy% zLTtXatDC*0vm!JjZ672in0U;FDZI|9~EUj8p)} z`52#LRN~x$#I^v=S0dp|F&5%{(p>r6KagAtdXFn9+59<2>Bvu{jNV*9OCn_yeFD$!i_g0XKJcR;Q2CMLFYg5!!qqQk;0%!o}E*5YKHc}Pze~eRDMeGH+Q82inrJEu*Fb1dT$J5Vo zLrXu-JQ&P#tqk*G3t<&8T%fyge{3QXw%NHcI3p*e9X~m7jPZxG#N4WB4HOG{^*Hfqu>h65wq<#(w8HK7f11A$b|ZJl2370d;jaxPV>kMi6^L z_Dz=|2VdYgd&)T=cG29p_@4csY|zKJ=44#MmCAzpf+C>tI4(M#j2;aae{yH>B#4DD zxbnFJVoPIi%J(Ey%KOtmtTF~OzXr@-vUa-(U?fVyeFMAP?%*zy@9Exh8LSrWGSj^= ziB2IMD_5>;g#+Z`MnT7d(yw8?Co3@twwB+3t_1UR_aV@u1nEF&xCN(&EliB`uw^Y6 z|FE#-NHE(@QOGp6kZx?1e@Z`DlsMcgey{-Zz-)z__I9$VITY7Tio~W$6<@N6_ljgY zIC{kOB_zu^$UU+rA%oI#bH~i2)%8FR0p`=yj>KjUnBR==gPb1=Aw(L;fDoJFAj3@W zlQWPZzD74xqXR#DuQ5+Fp-TrD63 z#Lk_59+i8~7Lkq~8%ZAH07bK=Qkx>qe{;?wXRKWG>^s{&I=8HSOBESDFpZ%E5m1cP zg^LuGBvX3BjK?oDf40v5Bj3jmRusQ%QjOZLxr(yTW?aZsHj3>)dy2ZepS^syuhTcB zzXPgPWwbfet0{-6;<*3N=yPAkKJuU#a)e8 zR9ikd6xodFB1o2HHU5|sL(X)WOb9T7g=B`x(97na>xh%x*+M6rcQwsia6Rds7)9+i zil}aK<+Ra&(^iwou^o3Yf*^nt{=>r9!$N=(8!d7jwvnFYB6*CLq*2JyI9O{{ACv;5 z7E;mJ15`X{e--&$4hlK!^zEnDQq#&I$T3vvLOuAQDlQF#h+aZ+;zkIN;)o+zK*UB$ zy+qo#rDU`~|Dqx3UUo5cJg>=y$@XHx=3E5_s8zAk|oc z&5EvN(^Qx_3y~r+sjU$*zeQ;}Z1lwAchPad5S(f5C2&I=m#ec`5Gips2r{BEfc=lJ^b` zw_#Azfzq2%yvB>AACNc@*9fGw5|cz)5E*Qcp4J0Crs9TlV^Co%}zCa&0` z520_R0f@95)JN{1$wZ8{dq%eyELyPLLN^C>=#9La6N$u3t{`_eF+=Pn2EOy&OJ06_mJi*AzM+~ zJI*)$bEaSlqy#VydVaZIQ@j;wR-B58f5K#gNwOe`OTrRZ0M`|lPQft^y2ie*HHQoh zE~q%L-M#9y;TAUw83Gu!D2XO{FVWPnk9e3E{ga( zD4?C3p2#<9Uhr7==GT&ev_KC54AjX~(+qtCx16WJml$ZJtPTZ!OxNJf(2Xc2e_V^H z!XZd4Hb?yY{KkKLnYcXzy$VR8*7F+-thLk7bPx||eW4FD6ctWcX_jPZ8=Ug{W!^`4 zYT=MLtboqW&VCMu;}}_%$0LB4V3;()gf~-UNsI+_UEdguM!(6+%j00VSM(~Np`pQ% zo11%Qdqlo{%|Xew6LA~Ut~OLOe=xXEq9KU+h7_4JwL*&L*|mp!KHvT2<>ef1W}t@v z;lKbn{F-R_HWtMCo}5AdnK!+S)pyGj3aT_N$V8Y#){K-~!%+W{dL-Itb;PDoC+Z zBpDLPVA{_nQFEtE=VI8==9Q`DfR|pp$Q8@6#ikY)7mJbz0sHswcep*Cm3Mw&n;0`} zv^!!_EhELSF4wO<*eOk{_p7uMUexX~DF}zh%mrh#TAlq7^A&>F38Dwn!!)#cBfa$b zZL}X@&T6BGn8%0Um6ers2VXB8IB=k!U$@uX__5tqmhD8YiI(~ee}pLp84$v%;hZyL zp(2Eea#SZr&`)=4c#nRxZ7DsIKbZbB=?0oro=^6elN!;5K6X+p?v^6eGVJ@9HML~( zpx@ZpDbWg4r~yXISg3~oB}!o!G5Gl)jXSWBmjCBrx@hZ{wA4`PFH~FwRQIyH7f1>fb+tEH17mX@6N#zb_GOi+_40IDMw9`(2*}H(CNH^ z1+;hXUaGCFrTmE#>7Io*Q6#@VIwSZI8S3Sr7x!`6&}o&RIv0{meLa_8!vK#4i8>uS zz$6=A2p=OOzNwZ%bpM1x+Oua5)ipHICx{q+(OOCee@li#?=Eycs>Pf$gs9Ml($AQfDMi`#a-w@#qlsGwbPB=mcNb*B>EzKeB6iWDC2<=CgqiBnQ$c zDATY44fkr)5!Q%#<=C_b#*G^X!{^F3j0a|ye}~uSDM6ahCrWOklWtj(MSC$2vB{uV zHdKHi6#R@0fvpNxZbNX(%(D>B+AyRF#==yY7o|J|zq882>%j9t<}CzFnlveD82Z&$ z3~7%o-yNh49Uhu9JcnY6o657f6+^3jT`&~tK))bG3@Ss!5r_upq(M6M&CzM?!602R zf3!0OUe_>B=FQD1g|EN<`r3}D^60ZWbL{Pi(rmEt5|2vD_QRi)Np!%ADB6tEzygKV z)tPks0F4?0Xf&|!>Rpo17U><`#s`$YZSF{;3jw_jG2M&(7~$n}G&sy;A%`t&1r`srA)Vnsig z+GK<(XsDwJjt$}fV2wwf2oud z#V`$Hw;9uRAzfo?`oD@6zsDoxUeT+7=0zvxNs9D`0_@4ypR>n|vnNK%vo5+> zZ|eH#C2xO{oNO0J+-0Hh42N8m3QB1Pzk1srPx9il? zM|d?g%7;8^$YC_yyTcxOe`Oe2uT^S*HOSgjU>mY*h9pxdl}>tV{#B||eoE+AGa7&U zXKzlnsb*zkU{PbcfH|o9@y6wig<%z3V^vE zsSk_=@i9boZT=87fB2nI%}~=H5T&C+My2zde+In$oD(*T_S9;+VFrpES;m8?7*ED!#RN4lpy9eH$t@Z1ZXLrS7QRJ9a6BYuJf_UFVWf!~2VN+sa z`m7hMMWdjNY#H5QI^H+a^2Q?%Vz6icS2?U-+|h z7#f0unB#Ki)Yj)y+#uvjlwvlQ;t(YfFcER7J$yd+=gq^_raW3 zG;~QfV&=74)Qo^g2MHJ43pgY{)m^tbS20JMh%`)He@W!nj{7jii`d)40p*&+#sU(KhD&ul)hwTu9XKvA5ibB21qVp)L%=naixB6hp;u)e z_m8;>e+2v*IlmVDL3#43qFDIAJ+_)MRV90x056#TZ16?(&x^fo=v6>Ej{W=GF%U8z zJ<0r=d^JX2d%RS&(K_@)YbD8Chai8`gdf))%2ga*z~~j*i&5oMaM?s_QYto4qPQEw z&ixWaK+!Gm$S-c1dG@x%Ej`eyfbq*~F&@-ze}gUE4aVrPuqA1TO}SIoaT8}a3Kd1r zg@nnj_}8mS=!sR6uM&@b)6qk~#APibO^QE{aWZlY#$ad>I(R8=r63`I!tiuHva4PU z>jR`nk&kih1xv^MoEO*#blDj&X<5gmh@IEVS?=hf-6UDFKt0bq+&u{*FR9G7HA+EN96nT822r0@#Xp zOO_1?!Qc_(vc*fXoRN>_eD?qwxg`KO=jkSX$SfY^8d{tpZ7meoS4-jgM$)1j+gdG~ z>jGDZZJtM!!BkG9LWrV~+Zn0Mc16U4e>;)YiOZVrfeP*pH8txk-)&c-fhe4wO~fGF zVMrL&IP>h}s>mZ}RVm*BaWPb`Pdqnu*u3OKT{vw4s40w;D_^IkPWKdP-12?-WGD^w z%Qx9W?QuzV=a7;GON0PKSI7Y@2Lo#fV=*)0C3`MW-qcDsM1xc{0F|^0<_?=5e`!z% zaM+@#_&BxsoJ-_rFm!z5`dvZ455Bsfg5<&qqO2k!XD)iR94IZHReNUGN8*eVhBWaK_>cLo}+*-gzG?S(J+pd^&xWo>b-NkO-g}Ugj~6@aRFZhVsFZ^ zCK6pUB3dwdpOjZ#O`v!r?~(BSe^#7}3L!k1f>8+q0JI(yI1T|Zo??)Ue93jkvQNof zc7pJlFbiQB_`}{*LFc1)wix>6)z1X}{j-z{W>mfK)@L~bBlB#m7BvKwuxcV`4>6dm zCMsMv^subii^p1#GBV658w-SR5UYm*rnc@&*^I=+B8+rMs`>{>3P2q^e<#5dBMcmo zdmZZ0Q38#kG3{H4I})7jGXQjOd*6}f1uA5s%k!nc7V2^ico&OIGF|n-sf-$WP%W40X|f45Tytr z=e`ZGSm4+%$1U#Umi)dbL824}k7AHYF+`LQz-<9IJNukxe#9F|NaQ_9Cf{8s!FmYm zlqFxiVfYruj!f;BaxjbjllYh)T^Y7^^*m@xE z#QRcfUxY8B+qXE7^VP^XuMt8i&<=c!WUtvErY%v+;xdW-62b>llG`Eh6-eKL+e@83EU|=0)hs5#@#J)I1s0JbUW#h zZ)HP&$^Y@4e?4Ydk~qA8BcS55b~JUd-uE03FLU4pPkTUYEPps~Lcx|FBmfNiBjJ#p zQv_sm1}NDkcp2|IAYP}+i*8uxm?H`RQ(nz{Kj=6RFH-Fd9G6~=919C%;67f-h5-K% zzy(~~-+`_M^>Ej{0AVEk6hfBq4(?~y^H8RlCV-Q?e^Qh6cpd0ym@~MfOL6ZF)~;v* zz8)pO1-x2?*YEO7V;zV~f?({Zfkr{6gE*Mt1t~r78fYwt*9bL%(wTD<&Fddozq|&u z`$AR*^Ms$Gv!SlF86`mOx#wB};trnY-oy$UfL-;?pnu>d&Y=LV=hex)%;zF;AQNBX z+8NyifAA8-k3lRbwSpPA4i~2$fTjcYFb^J+B{P$bAt?d45Pn&hBBCu?%*PVg0_GXR z)$YK(98GVv_A>Br_Y!ae;s(RQl0d|rvDWlZ;C0!&%sm}nb{D|v>CwUe52#63(YZ+2 zg8nZN6#~GV{V%T*<)zHs!97gMa(*B>lLD?lfAS1(_kt%;$=ss-fyof+N8hfLLQ2|mKkNuUKd@E`1Rr@_vuH+%(RN63#~xLSj9LH#XirYehp$T`rqO=;Kgbao)5t%?PTVB04Xm{<=k=K`rjbMoWTP4 z?UXUdxtQ-~B!o-_r2?p<0KY!KJz9!6g9Y%r0~{UP10memaK&+hy9vbpo?lhUcrMco zyn3IRR)IOciIf4Z18!^&fzAW*ibY;Bf3h321UHEOm4WMc5}i9DjB~}(bza-f9ndaZ zmsnNS6B*8~JIubL`85n~7rdaGm;WOBw6k_?e|;>- zFZUF4^vxlDA~l?{@>#ZGzweZ=pW8|b83MqZU#?2NGM0jF8V$?*4S#RJ$Po3N;c(B#y@{N&wPY}dO1{O2;*8wJ?fgu_ltbRf7tnrhHjHDlw{z;!a|kFOs$o(!+ibM&7FuT3#P$k#{{r7nM zbvU3>cX6(h6)n`Is(o2Ns#g9NAlGIp=Lv#9F_j`#7k9%zSQmTDqXw7{K`8`d7L*Vs z*0%H}fJZfle0&Aw#u2TraX_6wkk$mCmh=|Rf-xoSBNva0A zPYU?}0`%1o5(7gBu?YJV)b)&6#=`+Nf3vD6oTdo-2GY0W!j|m~$o>5xqbv7Z8qm}O z1%tVlJ1oov3po1VS0uaRdFjIso45{`*@GcX-xP+B1oNb@hj!#ve~W&)H-I@iNp|o2 zj#N5$I?Y<^$bT3cJ(b+xIEqLOTNCd0JG;Yv#>lo^$(K9@z?=t%DR-R)j>OMF?z?8+ zllVHT|CR7pkAtsM%+@51Lr}x;aaDiM&G+!=hocD5;eaxprYCS6nD<=Jn#5=JJ|l7P z6$ly4LXwbWIW&6ge}J`xg*hW2F#VlOh7pU!KMRGT_vf!%wjyy%poaj)yGp4;mgr#! z_z8B!Y-9=&X$5(nUAZ|~K1GpruQ%ulhGYK%^T$rpn~vP+r{h&B;%IL=a(o=>;&_zm z7zpje{=X{G~J1-e0e~R-{PJw0Z%2^W~gW>lH;kcKha+hf0^@a?|Y9B?ML6AgLX9?es3H% zU|{*j7*)ImRkaWegIB*6qhNmSHg7ml1CPjPDO8mFfPi3L2GT|Dzj`H+r37|-ZJNJ7 z(=@LckT?L$s5H%Macn)#rQ9<6Tvn5MYn2Bi;(H20fb@o_`Bl74?_jXAEz&348it0IF^oY zaL+&ZEo6aJP?4BsPL_bduL;BaaQvZDk(;!3vtlt(S=u}5{jvRa>IGh+%?Qe`#66MJ z)V0M6NUvlbx{9T10@>)OxU#bg5hbm~HosY%e{YTA>M)@E{fiizPR7`>4a4zaNHboK zosJR+jii@=!*}-e76KSxid8khKrp%=UYHvhx7=5;&CD6>I=mT^kIVx(vXByhdSGr{ z%Fipq_}_Z8E8xO-T|p=2K)B@Qv3ml=xUMMeI-+IBeIjR>C18A>NZ}?LF+fd>!<%YQ ze*)G`fQXXO$-hH*JpdOEmLj~@h$ zi|27kG=h1?>`R7NTA3wr7XqcEcIw~Ai zMSISf$b}1$t(J`YxFUyW8iRdR1GD` zW<6~&<57z4-9gbk+bF#G8%^(Qf8{B)2Ox-5mw_Gvz?{3T=deZUZM3>-n8nJ1C&^S8+V#XCF$b}57;zq=!lApp#;Rtk#$R(#E! zYP^0wb$@WJ%sd(D!_a+f0%D5yX`M( z+jGCC$d2#Gee<8FXbjX2pC4NDCABU7D;dGAE+ZYzVdJRq@>{6!;h(XP3CWU((M&?; zAC}(qK;Mp6|3;DR2%0gdi|^V@Vdz=SFQn{g^T<7QE=6~5CB408oocO(6tCM$g%|!* z4y^oS>P;j2Jp1U@1_ZVMe|CNYonOF1Cg@V!fME?4{PbQbIqPz=m-Z8f6i+VY%sHLZ z;&KXa{0eHzY|<>mF=!;Ig(c;&y*o4rSSBO)C2TERq3y_h61I~sqPz(_iQWwm>^ycM z<)6=Elb&dQoITx5-A7e}sVw(=qs1Fk=Xf8HC6o4HJfy(}Y1b>Ui;wR5T7=~r^;9ssR&1O65rG8Qg4mJ( zAz&@LT=t6Wf4I^S+ntJ^Qm}C=-k(iP?^Z+S!|33Xqp0bfYKqialQI%QOXd~cyp~OB zoy?sD`*U`=>=n~t?%RQ(ai)t;SEbLxZ7CDX!}r<02|Rztyp!d6fc-hUT=t47)L9kX z7H*+uw>(C>I<`@0;y7y0wb3_Ya_Q-F`%_z9*QBv?fB1N^mGvk8m+$gCpfz{Re;7U7 zweYAa&E+es$bl|PBDpdK5C@ugCW7Z2=2P!p_|xUk4Nr>ep5BW{+l}s z_UCzLTta9>{wGRmAfr(>QJ1NV=tkR(g2#av6G71V^k29#I<>+U6N$Z9Zv7T zFM~^hf8>SiIj4_jujp-Qrjn_%Xz9UEXlkG1$f>x5n{IjP0g@dqtILGW6Kc7PGb$J* z&_e(t(E;7TF4r~Y7}YalK6Km9>h#5Ii%zivdk7tiuokXRT>l`LAGy;{2m5m*R>;EC zd)TrLjDJ|za^1|9e2FA}#y{F5vmBMmF@G7tf5kG~q2Z=RRCoifX~g+P9AAxV-u?Sm zMVTHG$PjSN^ph%qRU=N(i?39QOGc=)7mvlv*B2*UevphVYVFq__zwFRn}w?v00l-Y@M$AgcU`<5=9*uWhDKZQ!IU*uddIA^j#4Rg=Q+C5>G zqj2D8`yefD#<#7H?tb@xmUUo|JV?)yeV-5W-dw% zOq31X94J)6D`vUad;N*eS0ok8$ZLT;#N@t7L*WXm4Htq52AFDsuA{TzNxkqL-*AQ=E&|1 z(^MK*kjQp7j62rZhclSQoOz)HobludOOR|}w-dvFHf1yHm@5~um z%+%OEm~l#oZs;=p)TABY)V^y|bk9d$nc_QD{FR#p<7FC9bZF*`^~=JI$&9ifCS-K4 zweC8hqGY;cxuMk8!|Y&+lLku&6A#avvF7uTFny*jLFPUgX$=>P4>BnZi9&YgKxW<_ zxt=%q$jok_~!t>vULmaxl{elM0 zy^Z-Kh45>Z%$v=0SMmh6;_}f}!;OV>y8ZNhYg-$%L#~G9x;lH*-rb>qF(i3^l9$M^ zY3`Qh_1VS!?_N+}_D9pN>QA|S(D&kkV0)aJcLt*ca(KkhE`9*0K@Rm?5lc?&KQ?--N}c2mg^x2UcC>%8P|hIhnqW|DM> z=}7WUp5lG0$1|_`qG8B0;`r>+9X2pnisRF{9$4?a<_cHyc}|&9V{^eJ?U*FKS$q1@ z=Ansz9yqROJ34oIe-n&(O3k{s7a>Q1k8$sX%UXu<+*ns+x4d;2OhK$P<9VRg|AINs z8vYElAjzDODnU9>8eV?FPa}9Ca@!Q^{WX^+y@Kkub4PS2+g-<=~JfAXV+y$ZN$wb}3KCc1+( zx&(|pDN|u^9&?HA8bEX}8@HdLBRur}?0mZOi5XJ&uNn6gF!~eow9P?!63jV@vudgP zRS_`tkkv!C7-%(+it;w!onjz8CqV6^}> znw*5zDd)QYe?5Q6muAK)wN&0FA?NFSV9x4DGUl^MN`lWLhJFxT(yin917SqZ?}6Ju zUkyJg&JWC?%dV-iN+NE(W4+n$!F{j<&N&aelFT_}ByJRdeN8|d_yPu{qY~ru&k$8z zjcS%4j2qen2h^2Elkb@z?Gys8Uu8b=w}W)OV3e*Fe{mLI=5S9J6%ma@1xHW^P6PlK zV&D@-dIo~{9m&aBHUbWPJ@h6mlFpIdX)*gPuca-2+6CKSrs)Fs29)TGVxlR~cNDq% zx{c^lX2z2Md=0w>W}0N46d;-U`DM~1`ROgR&}F0C0$xtZ7jdo=D&g1BelyTwz7mys z4|M%0e}4p)nQ}(phi~GCQ{qKGAbBqf)=7EQOQ*{pw9u@bXxP{C_ib7KJP1NAW)%|M zUrE#!MIF_^z<3P98DPd~j7m6qN-jG~9v8qyl#bTv`2Lf^Qul z`g}hEF4*-w6=*PA@tnov4V|7T=aR%Q%=PkuJo;iZ%y2PRCeLcJCE>2;vCmYE?)hH0 zg&92l;Tze;Ic3h!y-+_JLGoBqfYoDtDqlX5-i>P%*w6OO;ENI$eve~!!v$>j5-o&N zyAw7)Fe_bx^Z4J;187Gs(z|AkCZtmDk)Pz`d5&E@4 zlxies6Z*RgxS!+7=TfjRRu`u#z4Prt`8!d<{!R?ORq7BYyAum$1c;tS2lFfV|2CBD zkAu;7pfQew!+V$KXSrlN7zWKOH-onfki-|IQ-(L>edAoT=-0#{u2dGyXPMINf1CwE z@ZaH0uN#9+?7s{bvLR@>YgT=^o38r#U`Z_2PYDqCmvIG(hZ6}Q>CDrwWc4A!d=)DC z3Z;5{Ke+OBF!x!x^vKea<=ez{K&Aj-#s|j5D}D3?yk)i+*7FrfN&+P~50>SDX+OhL zPu$W}GdeDtZu#~MCF3iJ>4g_qf4NY8>DqoYsVoQnTry)q2mD2{cp_zsfrCS@MQ?Gy zf`KsHz?&D8%Tu~DXY?pRI!^l77``h)=kAHnu~6A$lq#p%BhmR4)QG-e*B|$oOQyK# ztu+f|{&9s~ks+XC+O$DPcRMZ z$u@H)sS_uX+@}wj;V_wj0BLL2Qtac8N#8Ce!FvPu+9O%OFR+pNx^oh8SsA&0_A{~_ z$8Rqk8Z0Pu@4aMj^X`dXf3S+Wmgyv*3>rk)FTQw0<_vZ6WXgWw1yV=x`))ljn+347 zq`+!$|M|}(c~Y}DM}$;RKv}>09Z6YiXc;JD0U1ZLZoQS{!a_1I5|6&}3K_LL8P+?D z=4Oh%`YIU*4v<`0O0FAkOq@v}i|c@wc!;Gp%Fv;d{hakh2>(SFf04d-FUiHllnp_> zf^R47%eRndA`@Lb-+&8Pyh!{ zIa_U(>m&{Q1>i0L%0T|kiv{Nu{Cbpy=xeVDm34=kBP`B->Zyq%5HLLTsS1V=a7b`FNKRJ7moKO2;>FMz zIs*udzV#Mq-+r5MO>f{c?5qTggB)6Pfs1QDg@0tjLilfgBk#h6va7GCjp+_F+>9|-Ozkp9nRHpN$n@DnHM#n}|Q*V|Q;+CBJJ)9KS^gO80?*2&B z5iCd%L6LJ4p~?9QB3>ch3Y zFlQ_|`VI%?$o0S$WCnwRaqN>%j@;q!7KCtL-0K3Q{{g>2pM0NHYv`asEQCAk{}r5b z=9T#@laWvtJC^jYg(*FBVX);frH3!cu;u+8Vat&af7f=HJ8MG}3G}6g7VE{L!Bx35 zbU@(|??3DXnz6*JYiXrGcn}?^x3m}V=@g0PQ+|$}I(#va&N`-?JZ}Czdr$OwkQoO; zpO7~=ks{$aR9N69yP}Y4lf}wt27jo&qccLg5A3J!cgAS$^!~k;sK)_juIay^4>#UP zMe+#pfBT&xr~Y7svfb8;Ek(sX%CdW?s3=PLSrt@}%RIka$gbq3Fjoh0*@ zKDwG3>#T({2b#MUs@kfWXndaaaiy%GT|Q@K-W)2;Jw*r^ImAxKPa2Wpo7&)t)Xnp0 z<@zD?>L=FwB^w*i*8(}Vt_7S|{&X{q7}(`?emUqo_JOiAIv2Cd!sYZaVN+ zs;S>Y1Nu1Vi?6#nE+K$bljVF&*aMH$l7rphFU)0scU2Rm?9K>iPA%HE0@vn8|)Y{P1n2U?EY2@@$8a6qP zp8It%E$Ev|AJ%zkRrDvcR^v%tqSeu9^x|iIY2OZOIRrCjY}#!(KVfu|X+7glUc}(s zH>gADit;+T=KOMccU>F3(Rd1S?w~p1f9ny0sfMQ07oR!AeXPbk^)XS}fki`U-FH^~ zsa&}xO(1U*4~i`$RdeoXPP%4Z2i@}dB>M7ug@zC0C+zSAJFIu1Sy&_g`U$NTj4dHt zUtRsOEXh3sDpu3LQ|Hj{W~eFV#Ut(1>YPsd^@$>N4wz2EMo*%lqX*Lt^Biicf4)qp zl;MkaEn`nvQ4*Z{yb052L3M=cT0*oLevX+lvM{pj2NyVhoJ57WL?sqK8afFl0Jb>J z9H&XhrqLA{uo)F(7iVU=M=+wH0my}!Jl8hg0EijX9>QE^h zw#FbAj(jhr|JsO5wQ#`9d~i95e;jin-L6on^P9jj&6oCk-U~Mw(20=FioSP9A~Dhs2Y7Mf7R6+)X(!3 zJ$~JTLZ|yzCF1`ygc2*QSO{+?_xXCR>@x?irg_I$b;n2vaAy6ITz$_=3HitAi^#TP zgAkHr!r&Zp&Y2iSy_I{xJm*F_aY`|9y^4cCYJNvoFA3A0|(ZB6>NGvxqz%g*;hKaya>men3({W3$y*e^@|st7U_ov5geb zzN2Ez@=>$yh4$VUIlV{IsX%sc`MzCfIEOTv zB)DNPPm+;)Hbt@19r8`TL+e40$4eOgcsuE5O(gxYxn#WcY~qT;;!ftxC15-6X^POZ zG{x%a%vGP0`TolYr!!utIuf|WS<9luZg+U#)1iNc`Az0%^9SHC0{Ekab=Dih(x~1q zISNc<0f+k1e?Thd($qOb{ktZsegF=$?iw)OL4)o@teKrl$`fyqG$M2A=4ikIdVQx= zVE=B?e|E0*dSp&M$&bEC(jxI|#zzZlS+uo%2*B=*mlLlIa7#XN8%W3cBMZQ&MZVMu z)y*XzkhzRspFL_=>#jjvflWFjiR7Cf5_Q0JVf>W`fAB{Q_8;ryL}$VNya%NDi%6Qr zUl2lt{|SwqEBxre{e$(MKJS3opLe0CjN}`{qcAeRe4otaKS(v~>_n#1-8HXPW{a}i zHMe3|jsUxeu9rHkb8bXnj26U}M{?ImKnQmh{N;c{_X&pwGye&g_k7VOi9|`b%k1ql zD~E%4e^n`&^CXgWkV4{uu6NLm48Df11;s~sx-#ms2Nv&!- ze=KB2)@hoiW%#v}fS74cz^MFAz4?36z?i?8sznqE)x1yI=NLkT(*|mXfh;SxM`N+n z7v)j{5VzclqN+M#F`bzU0Xl_(Dup-yfwZ@8Afqug9ePNxhgTKl_Qb9wAR3KU!d_32 z99d)*On|DO`=|^762-$BwYRBc9DI?qf5n4ITd^3mpBRDn0#rGKNGG8bJjrVbP!wf4 z1Z1;#b?hmmqYgw#;u0B1J6m+}`p{j%DQKTxOwnh~BW=qHa7!+};NZ{Tj3P|cScprO zB=N%wLI5PD=3ks6rjRn`CenQx8JZo$ziFU|5Gfk5k!f?1(fSER7avEF*Y79Of7d1+ z_51yP@lp`KV#dO7NDShH07y)I@KLhaDgRtlN9k-b0uf}AU!;&J8j`8L7OfZ#85tCU z;%n}r(34kEVCN=^8@$GsKfYlRE)ws2rz$xew&FfidgF6s8*m1hogtFp9&9Rxt!*-O zw9CZ5k!i+N2+1X__FbZvt|h7Ye;`W23+wsU_Yy*Yq>6gHh2rQ_N&RnohH@6(M^a~$ zlz13IYzUDgQ5t@Gi`T-NasipGt4VtAQ8L3Jv6z^JfW%tiq>6g|Ae9Z{gNm!~pnmtQ zAm@Muq;#NZqZN8P_-7#$@lKi$q7;$2>1m>^>)>o9OMtG6r4T|uAQ1Q(e?{v3gJ2kR zVt`mv!AO;WF>&I=yXAQ7EdwTorY>^K#HwSnV?i7Nf0-zak(*D(?2FJ= z(5TpKrDA@Q@dH=?N?rt#LWTfF{zFr*bL`!*%S5X*P{D#Bw@hZ9D2ZsPItbC9#Q|3- zZlC_m^FPnw-+fI(4*`{LQ%mld=bhqN_WnAxem``Jh66S6FHf+N`1{rdIvB&ik*ym9 zZ)lpQ+Aps7QhZG@e*=f?^kK8E&hx5oh>tt_TD@{uwaFv=EVrl=CFmn%%UY6GJQy+6 z(vL|}?(X;czFynXAq6CXChperXsR&P zr{ZigY*%xiKJB7gyL~MtVMQB1dO3gB>Lq{Nvwmqo^^^st7^d-|5x1D1yYM)=`2orc zHT3e+QI9g&+-`E_<$sYK;{(;1MF-pC#cY9ZTNK_z59Vf~7C~ z^``ABKDi)g*yO!WeYv&jxT#~Q)gPe?W(}ttmyK?DWj%#dCpmI+VYWI&d|vpW7{Zze zmAVwVW=0`p>-BJ02FZ~uv#@g5qa#nc{8dG{&B@)PJ(Crmrp3nm>D30aa$j zs7m!wVE+!<&}pY_VF$U8bCDm^feY$#L73`rQcFu4eX*sPf<``#EJXV-!%{pL9pAib z{ivt^{l%w3MS9qmQ&{LCJM1HfL3c;(0SYuXP}ti+k#(!6(CvUSWvIm|1le5tqYEn8 zU0LKQDIr$ns(%AMdXj&8^x!AxTd5IhrDOJf zPNN!DQ?87TBpN}?6h=rBp;#zHcGN{~d0%oDl~CO7rl74%xDnK$T(jywxpHUoz9%By z07(vX=)z;7(Ti{dDFjvxucDcY&ZKGQTuja0Fva<2w11kLDC+l7$ANw1Z)zlVj_d%3 zl;@BKJ*9;4A-lzRBsg6;aoE7?6&Vg4eY9*t?33oI?4E2YC@rNeas@r}`FEBV<$eKX z8ftGta27#ehEllP6z*&%ml30}<%m07tSSldmZMr$9K{E1E<35{(D}FNQjk?robWw3 zUgppQqklN72IO#OvkJt1ED#`nBL*W7oRyDAg*D9q1z36OYbxYe)YsQQPbAsU^~J>N zMRc&iN1L}c&_}fndSFe2KKk|m7;|o+B9I=1i9-MJP>^E50CmDBq(BGFt#%`_fD$y+ z9}9A;h8*+jrg--*QMW#SltPF{vvZs@w^Ah^>VIe5_xlj9GQ$Kxn9YvB3j*R0fLu{t zZZ;K#;P;phk2}!-lq_dlcDnQ1*#u$0LVyjn>T=r1<8e}~X&>D+Gl%96E26nWi|DRt zZhBy*i+;aoIC=mtat{G0krCG@FAE{1%bL0tKZoHoVfJ|qvO71gHjZEdos~eAQ>Cmd z2Y)#sq@yE5jk|WxWN8mgmG@ArwT_zh>?dD`mvRVZ8t{ucaAsxE{7D1BL?U~Z2Wc9F>?&K_b=r6H{P^5um7N6%RxWF6;__r z4(t$UQze=*Wgtm|N6-VGZl(L)SxdFPINXHwD;yq_^qCuvr+#uP#eA()IC3aOIy=OB zgkCBZJ)Ef8_kaJ$dEb8e*3VVNMis*mEucR5=hTHTTq1s2F}s-7HJbF@!2mg6aepTa z%b{TyHuG$=WRobXvVc5AeW-oY9<&wH^bDOj|Csq_b$#6b#b4g??4Fg&MmY2N5u=lP z7RnQEFK~%KtULY>;^+b_DX%z(5Z#llNJU?fi?M=Ck;YE4RgPbL{5e-Y&U_P^Cwgd*UX6T0Z%_()0yEu#T^K-~% zV6dnZ)!+ESnnnA*`!sb|hJYj%-}BpR53c(9vQS4yujd(_A{S-D%ChsaV1K4=)81$B zQ>Wi_XOC(5Lo)c_A5Xe=?AU#W-QPK*bLS3s_itCIFyoxEBE!+IV$0CU6K|S(@s(+F zZe2K}fOITPHgbBYranT}PC6$350_L24!XgU9W}P&4 z;x*;{`q}qv-pmZexPW^+zCrw|3>;))Jk0wsi0>RRe*9Gz{NyLRZhtR@3;`GZ1&Q zp}_2u<~#{KPv@Tsif~wh2*BgarX1vc1#-EgzKP8IGAiz0MSqT*0;+BIQd36r#h&zvgBXN z>=S2S2%Vl4Lw~I4bhyx)WeKXRsG@y)4^U@Br?Ni%sT$17OAEz0_R+2A)pR{djSY3Q z;GB~Q@dkwviL?cy6hS6iTASJmN^*+ja5Q`tkAYDKxX=281lxKEa=LTZF3}f+(C^}q z1#Ga{vVrn-d~a1%B@G)(J41urBXP-vJwZ)nLoDN zlkLjoZp#k+6RU_n0uuvs{-sq-N9Y1K?Dw{kx2>7BqcoegZl}%Lc8F~sqB~zlD@DUm zav;hMhkyKHEX~GbM<3CzZ)sjZL2i~(J!;^simGID?%BQ-g@0fW(E)N**}sxjeYFa~ ztVsbx5REO()Yw>0?TEa+&2_M%HoD|TXHp4zwq}GlVhjx-+~x95eVL{aP^w1`yvAX7 z6h)D1t^*#XvLyw>K^jy&hzbh|Y5Ue~6hiD7@_%(wXKM@9q8)?-K{|KQLYg;sCLP$n zm10rEM-ZUv7{K$ZHR#i0aqW9$(C9(q>^A!Ze~^Fc3>D24i2C3O5kGQ0c<>%BL za(_-RRO&>I8=>oQqsF09eKdCDV46C00*x9uga!?)q|T0d+FSEI)T$x_$r7+bM6ixj zmes#Wx7>ScZq0$3gE*SqhLD`=foEBq{E17zp}5F~P`oenJafiGwC-H$>})2#uY}uKKmU%S>NQPiwDR?mm4DIcv!?e)_%6OFz$M`yu#3jvK}{$1%PXdW zY>9>pE}=-+OYLoqh&KGV25~6Vq9N|oa6PvP>+1rtD3RUnUVPIpA70F6%C6y8sw{6W zEGVKJPY$VQkKwp<|@X}t}Hh*_rZexet*@Ef6YIdA&}~Dl0c;|ve|4;z)TBv*X*|y$O?@d zT4otmSMQ*chKX4gSGVt zI3vDe#tbg-xSc2qxI=~{+t3wD(2^d3nm$2A-+ayWzv=O~q*nn+-1@uQMn1)3@!Mb_ z^V>VTv243yFDu9nRP-t52blF}RNuiJ{PT)y?l{Evi-`UopcQ+^;bP8R00000NkvXX Hu0mjf#xkN= diff --git a/img/links.png b/img/links.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd986976a4773454046605a468c987634eed49c GIT binary patch literal 2299 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 literal 0 HcmV?d00001 diff --git a/script.js b/script.js index 1062364..b6e1592 100644 --- a/script.js +++ b/script.js @@ -107,7 +107,7 @@ const BotMon = { _formatTime: function(date) { if (date) { - return ('0'+date.getHours()).slice(-2) + ':' + ('0'+date.getMinutes()).slice(-2) + ':' + ('0'+date.getSeconds()).slice(-2); + return date.getHours() + ':' + ('0'+date.getMinutes()).slice(-2) + ':' + ('0'+date.getSeconds()).slice(-2); } else { return null; } @@ -433,7 +433,7 @@ BotMon.live = { // get the page view info: let pv = model._getPageView(visitor, dat); if (!pv) { - console.warn(`No page view for visit ID “${dat.id}”, page “${dat.pg}”, registering a new one.`); + console.info(`No page view for visit ID “${dat.id}”, page “${dat.pg}”, registering a new one.`); pv = model._makePageView(dat, type); visitor._pageViews.push(pv); } @@ -448,19 +448,21 @@ BotMon.live = { // helper function to create a new "page view" item: _makePageView: function(data, type) { + // console.info('_makePageView', data); // try to parse the referrer: let rUrl = null; try { rUrl = ( data.ref && data.ref !== '' ? new URL(data.ref) : null ); } catch (e) { - console.info(`Invalid referer: “${data.ref}”.`); + console.warn(`Invalid referer: “${data.ref}”.`); } return { _by: type, ip: data.ip, pg: data.pg, + lang: data.lang || '??', _ref: rUrl, _firstSeen: data.ts, _lastSeen: data.ts, @@ -1293,6 +1295,16 @@ BotMon.live = { return false; }, + // the "Accept language" header contains certain entries: + clientAccepts: function(visitor, ...languages) { + //console.info('clientAccepts', visitor.accept, languages); + + if (visitor.accept && languages) {; + return ( visitor.accept.split(',').filter(lang => languages.includes(lang)).length > 0 ); + } + return false; + }, + // Is there an accept-language field defined at all? noAcceptLang: function(visitor) { @@ -1886,7 +1898,21 @@ BotMon.live = { platformName + ( data._platform.v > 0 ? ' (' + data._platform.v + ')' : '' ) )); dl.appendChild(make('dt', {}, "IP-Address:")); - dl.appendChild(make('dd', {'class': 'has_icon ipaddr ip' + ipType}, data.ip)); + const ipItem = make('dd', {'class': 'has_icon ipaddr ip' + ipType}); + ipItem.appendChild(make('span', {'class': 'address'} , data.ip)); + ipItem.appendChild(make('a', { + 'class': 'icon_only extlink dnscheck', + 'href': `https://dnschecker.org/ip-location.php?ip=${encodeURIComponent(data.ip)}`, + 'target': 'dnscheck', + 'title': "View this address on DNSChecker.org" + } , "Check Address")); + ipItem.appendChild(make('a', { + 'class': 'icon_only extlink ipinfo', + 'href': `https://ipinfo.io/${encodeURIComponent(data.ip)}`, + 'target': 'ipinfo', + 'title': "View this address on IPInfo.io" + } , "DNS Info")); + dl.appendChild(ipItem); /*dl.appendChild(make('dt', {}, "ID:")); dl.appendChild(make('dd', {'class': 'has_icon ip' + data.typ}, data.id));*/ @@ -1906,7 +1932,7 @@ BotMon.live = { dl.appendChild(make('dd', {'class': 'agent'}, data.agent)); dl.appendChild(make('dt', {}, "Languages:")); - dl.appendChild(make('dd', {'class': 'langs'}, "Client accepts: [" + data.accept + "]; Page: [" + data.lang + ']')); + dl.appendChild(make('dd', {'class': 'langs'}, ` [${data.accept}]`)); if (data.geo && data.geo !=='') { dl.appendChild(make('dt', {}, "Location:")); @@ -1931,37 +1957,56 @@ BotMon.live = { const pageList = make('ul'); /* list all page views */ + data._pageViews.sort( (a, b) => a._firstSeen - b._firstSeen ); data._pageViews.forEach( (page) => { + //console.log("page:",page); + const pgLi = make('li'); - let visitTimeStr = "Bounce"; - const visitDuration = page._lastSeen.getTime() - page._firstSeen.getTime(); - if (visitDuration > 0) { - visitTimeStr = Math.floor(visitDuration / 1000) + "s"; - } + const lGroup = make('span'); // left group: - pgLi.appendChild(make('span', {}, page.pg)); /* DW Page ID */ - if (page._ref) { - pgLi.appendChild(make('span', { - 'data-ref': page._ref.host, - 'title': "Referrer: " + page._ref.full - }, page._ref.site)); - } else { - pgLi.appendChild(make('span', { - }, "No referer")); - } - pgLi.appendChild(make('span', {}, ( page._seenBy ? page._seenBy.join(', ') : '—') + '; ' + page._tickCount)); - pgLi.appendChild(make('span', {}, BotMon.t._formatTime(page._firstSeen))); + lGroup.appendChild(make('span', { + 'data-lang': page.lang, + 'title': "PageID: " + page.pg + }, page.pg)); /* DW Page ID */ + + pgLi.appendChild(lGroup); // end of left group + + const rGroup = make('span'); // right group: + + let visitTimeStr = "Bounce"; + const visitDuration = page._lastSeen.getTime() - page._firstSeen.getTime(); + if (visitDuration > 0) { + visitTimeStr = Math.floor(visitDuration / 1000) + "s"; + } + + /*if (page._ref) { + rGroup.appendChild(make('span', { + 'data-ref': page._ref.host, + 'title': "Referrer: " + page._ref.full + }, page._ref.site)); + } else { + rGroup.appendChild(make('span', { + }, "No referer")); + }*/ + //rGroup.appendChild(make('span', {}, ( page._seenBy ? page._seenBy.join(', ') : '—') + '; ' + page._tickCount)); + + // get the time difference: + const tDiff = BotMon.t._formatTimeDiff(page._firstSeen, page._lastSeen); + if (tDiff) { + rGroup.appendChild(make('span', {'class': 'visit-length', 'title': 'Last seen: ' + page._lastSeen.toLocaleString()}, tDiff)); + } else { + rGroup.appendChild(make('span', { + 'class': 'bounce', + 'title': "Visitor bounced"}, "Bounce")); + } + rGroup.appendChild(make('span', { + 'class': 'first-seen', + 'title': "First visited: " + page._firstSeen.toLocaleString() + }, BotMon.t._formatTime(page._firstSeen))); + + pgLi.appendChild(rGroup); // end of right group - // get the time difference: - const tDiff = BotMon.t._formatTimeDiff(page._firstSeen, page._lastSeen); - if (tDiff) { - pgLi.appendChild(make('span', {'class': 'visit-length', 'title': 'Last seen: ' + page._lastSeen.toLocaleString()}, tDiff)); - } else { - pgLi.appendChild(make('span', { - 'class': 'bounce', - 'title': "Visitor bounced"}, "Bounce")); - } pageList.appendChild(pgLi); }); diff --git a/style.less b/style.less index 4108677..4f5fede 100644 --- a/style.less +++ b/style.less @@ -40,7 +40,7 @@ /* Bot icons */ &.bot::before { background-image: url('img/bots.png') } - &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before { background-position-y: -20px } + &.bot_googlebot::before, &.bot_googleads::before, &.bot_googleapi::before, &.bot_googleother::before { background-position-y: -20px } &.bot_bingbot::before { background-position-y: -40px } &.bot_applebot::before { background-position-y: -60px } &.bot_openai::before { background-position-y: -80px } @@ -84,6 +84,7 @@ &.cl_silk::before { background-position-y: -280px } &.cl_ffold::before { background-position-y: -300px } &.cl_chromeold::before { background-position-y: -320px } + &.cl_ecosia::before { background-position-y: -340px } /* Country flags */ /* Note: flag images and CSS adapted from: https://github.com/lafeber/world-flags-sprite/ */ @@ -332,6 +333,11 @@ &.typ_php::before { background-position-y: -40px } &.typ_ip::before { background-position-y: -60px } &.typ_usr::before { background-position-y: -80px } + + /* External link icons */ + &.extlink::before { background-image: url('img/links.png') } + &.extlink.dnscheck::before { background-position-y: -20px } + &.extlink.ipinfo::before { background-position-y: -40px } } /* grid layout for the overview: */ @@ -524,26 +530,49 @@ & { display: flex; justify-content: space-between; - align-items: center; + align-items: baseline; + white-space: nowrap; + line-height: 1.2rem; + margin: 0; + padding: 0 .25em; + } + &:nth-child(odd) { + background-color: #DFDFDF; } span { - &.visit-length { - min-width: min-content; - } - &.bounce { - width: 1.25em; height: 1.25em; - overflow: hidden; - } - &.bounce::before { - display: inline-block; - content: ''; - width: 1.25em; height: 1.25em; - background: transparent url('img/bounce.svg') center no-repeat; - background-size: 1.25em; - } + display: inline-block; } } } + span[data-lang] { + overflow: hidden; + text-overflow: ellipsis; + } + span[data-lang]::after { + content: attr(data-lang); + font-size: smaller; + color: #555; + border: #555 solid 1px; + line-height: 1.25; + border-radius: 2pt; + padding: 0 1pt; + margin-left: .2em; + } + span.first-seen { + min-width: 4.2em; + text-align: right;; + } + span.bounce { + width: 1.25em; height: 1.25em; + overflow: hidden; + } + span.bounce::before { + display: inline-block; + content: ''; + width: 1.25em; height: 1.25em; + background: transparent url('img/bounce.svg') center no-repeat; + background-size: 1.25em; + } } } @@ -554,7 +583,7 @@ align-items: center; } li:nth-child(odd) { - background-color: #EEE; + background-color: #DFDFDF; } li.total { border-top: #333 solid 1px; diff --git a/tick.php b/tick.php index 1d46b1e..67b4550 100644 --- a/tick.php +++ b/tick.php @@ -2,6 +2,12 @@ // Note: this script is normally called in HEAD mode, therefore it can not return any payload. + // quit out if it is called without athe right parameters: + if (!isset($_GET['id']) || !isset($_GET['p'])) { + http_response_code(400); + die("Parameter error."); + } + // what is the session identifier? $sessionId = preg_replace('/[\x00-\x1F{};\"\']/', "\u{FFFD}", $_GET['id']) /* clean json parameter */ ?? session_id()